From cf099d11218cb6f6c5cce947d6738e347f07fb12 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sun, 20 Feb 2011 12:57:14 +0000 Subject: Vendor import of llvm trunk r126079: http://llvm.org/svn/llvm-project/llvm/trunk@126079 --- .gitignore | 37 + CMakeLists.txt | 301 +- CREDITS.TXT | 4 +- Makefile | 19 +- Makefile.config.in | 15 +- Makefile.rules | 138 +- ModuleInfo.txt | 2 +- README.txt | 2 +- autoconf/configure.ac | 198 +- bindings/ada/analysis/llvm_analysis-binding.ads | 32 - bindings/ada/analysis/llvm_analysis.ads | 30 - bindings/ada/analysis/llvm_analysis_wrap.cxx | 369 - bindings/ada/bitreader/llvm_bit_reader-binding.ads | 52 - bindings/ada/bitreader/llvm_bit_reader.ads | 6 - bindings/ada/bitreader/llvm_bitreader_wrap.cxx | 423 - bindings/ada/bitwriter/llvm_bit_writer-binding.ads | 28 - bindings/ada/bitwriter/llvm_bit_writer.ads | 6 - bindings/ada/bitwriter/llvm_bitwriter_wrap.cxx | 335 - .../llvm_execution_engine-binding.ads | 192 - .../ada/executionengine/llvm_execution_engine.ads | 90 - .../executionengine/llvm_executionengine_wrap.cxx | 924 - bindings/ada/llvm.gpr | 34 - bindings/ada/llvm/llvm-binding.ads | 1974 -- bindings/ada/llvm/llvm.ads | 497 - .../ada/llvm/llvm_link_time_optimizer-binding.ads | 207 - bindings/ada/llvm/llvm_link_time_optimizer.ads | 184 - bindings/ada/llvm/llvm_linktimeoptimizer_wrap.cxx | 923 - bindings/ada/llvm/llvm_wrap.cxx | 8817 --------- bindings/ada/target/llvm_target-binding.ads | 138 - bindings/ada/target/llvm_target.ads | 72 - bindings/ada/target/llvm_target_wrap.cxx | 720 - .../ada/transforms/llvm_transforms-binding.ads | 206 - bindings/ada/transforms/llvm_transforms.ads | 6 - bindings/ada/transforms/llvm_transforms_wrap.cxx | 828 - bindings/ocaml/Makefile.ocaml | 9 +- bindings/ocaml/bitreader/llvm_bitreader.mli | 8 +- .../ocaml/executionengine/llvm_executionengine.mli | 68 +- bindings/ocaml/llvm/llvm.mli | 962 +- bindings/ocaml/llvm/llvm_ocaml.c | 5 + .../ocaml/transforms/scalar/llvm_scalar_opts.ml | 3 - .../ocaml/transforms/scalar/llvm_scalar_opts.mli | 5 - .../ocaml/transforms/scalar/scalar_opts_ocaml.c | 6 - cmake/config-ix.cmake | 162 +- cmake/modules/AddLLVM.cmake | 34 +- cmake/modules/AddLLVMDefinitions.cmake | 24 +- cmake/modules/CMakeLists.txt | 21 + cmake/modules/CrossCompileLLVM.cmake | 52 +- cmake/modules/GetTargetTriple.cmake | 6 +- cmake/modules/HandleLLVMOptions.cmake | 161 + cmake/modules/LLVM.cmake | 11 + cmake/modules/LLVMConfig.cmake | 76 +- cmake/modules/LLVMLibDeps.cmake | 121 +- cmake/modules/LLVMParseArguments.cmake | 80 + cmake/modules/LLVMProcessSources.cmake | 38 +- cmake/modules/TableGen.cmake | 26 +- cmake/modules/VersionFromVCS.cmake | 31 +- configure | 3439 +++- docs/AliasAnalysis.html | 81 +- docs/BitCodeFormat.html | 9 +- docs/CMake.html | 53 +- docs/CodeGenerator.html | 724 +- docs/CodingStandards.html | 538 +- docs/CommandGuide/FileCheck.pod | 4 +- docs/CommandGuide/index.html | 2 +- docs/CommandGuide/llc.pod | 8 + docs/CommandGuide/lli.pod | 9 +- docs/DeveloperPolicy.html | 85 +- docs/ExceptionHandling.html | 22 +- docs/GetElementPtr.html | 30 +- docs/GettingStarted.html | 74 +- docs/GettingStartedVS.html | 322 +- docs/GoldPlugin.html | 2 +- docs/LangRef.html | 260 +- docs/LinkTimeOptimization.html | 4 +- docs/Makefile | 15 +- docs/MakefileGuide.html | 8 +- docs/Passes.html | 10 +- docs/ProgrammersManual.html | 28 +- docs/ReleaseNotes.html | 26 +- docs/SourceLevelDebugging.html | 54 +- docs/TableGenFundamentals.html | 24 +- docs/TestingGuide.html | 69 +- docs/UsingLibraries.html | 8 +- docs/WritingAnLLVMBackend.html | 4 +- docs/WritingAnLLVMPass.html | 130 +- docs/tutorial/LangImpl3.html | 6 +- docs/tutorial/LangImpl4.html | 7 +- docs/tutorial/LangImpl5.html | 5 +- docs/tutorial/LangImpl6.html | 5 +- docs/tutorial/LangImpl7.html | 5 +- docs/tutorial/OCamlLangImpl7.html | 4 +- docs/tutorial/OCamlLangImpl8.html | 365 + docs/tutorial/index.html | 2 +- examples/CMakeLists.txt | 3 - examples/ExceptionDemo/CMakeLists.txt | 1 + examples/ExceptionDemo/ExceptionDemo.cpp | 3 + examples/Kaleidoscope/Chapter4/toy.cpp | 3 + examples/Kaleidoscope/Chapter5/toy.cpp | 3 + examples/Kaleidoscope/Chapter6/toy.cpp | 3 + examples/Kaleidoscope/Chapter7/CMakeLists.txt | 1 + examples/Kaleidoscope/Chapter7/toy.cpp | 3 + examples/Makefile | 3 +- examples/ModuleMaker/README.txt | 2 +- examples/OCaml-Kaleidoscope/Chapter6/Makefile | 9 + examples/OCaml-Kaleidoscope/Chapter7/Makefile | 9 + include/llvm-c/Core.h | 24 +- include/llvm-c/EnhancedDisassembly.h | 2 +- include/llvm-c/Initialization.h | 40 + include/llvm-c/LinkTimeOptimizer.h | 2 +- include/llvm-c/Transforms/Scalar.h | 3 - include/llvm-c/lto.h | 50 +- include/llvm/ADT/APFloat.h | 7 + include/llvm/ADT/APInt.h | 142 +- include/llvm/ADT/APSInt.h | 18 +- include/llvm/ADT/ArrayRef.h | 121 + include/llvm/ADT/BitVector.h | 36 +- include/llvm/ADT/DenseMap.h | 3 +- include/llvm/ADT/DenseMapInfo.h | 14 + include/llvm/ADT/DenseSet.h | 3 + include/llvm/ADT/EquivalenceClasses.h | 2 +- include/llvm/ADT/FoldingSet.h | 2 +- include/llvm/ADT/ImmutableIntervalMap.h | 54 +- include/llvm/ADT/ImmutableList.h | 14 +- include/llvm/ADT/ImmutableMap.h | 53 +- include/llvm/ADT/ImmutableSet.h | 553 +- include/llvm/ADT/InMemoryStruct.h | 77 + include/llvm/ADT/IndexedMap.h | 14 +- include/llvm/ADT/IntEqClasses.h | 88 + include/llvm/ADT/IntervalMap.h | 2139 ++ include/llvm/ADT/Optional.h | 54 + include/llvm/ADT/PointerIntPair.h | 7 + include/llvm/ADT/PointerUnion.h | 12 + include/llvm/ADT/PostOrderIterator.h | 6 +- include/llvm/ADT/SCCIterator.h | 2 +- include/llvm/ADT/ScopedHashTable.h | 103 +- include/llvm/ADT/SetVector.h | 4 +- include/llvm/ADT/SmallBitVector.h | 7 + include/llvm/ADT/SmallPtrSet.h | 5 +- include/llvm/ADT/SmallString.h | 12 +- include/llvm/ADT/SmallVector.h | 26 +- include/llvm/ADT/SparseBitVector.h | 2 +- include/llvm/ADT/Statistic.h | 2 +- include/llvm/ADT/StringExtras.h | 9 +- include/llvm/ADT/StringMap.h | 21 +- include/llvm/ADT/StringRef.h | 25 +- include/llvm/ADT/Triple.h | 77 +- include/llvm/ADT/Twine.h | 30 +- include/llvm/ADT/ValueMap.h | 2 +- include/llvm/ADT/ilist.h | 1 + include/llvm/Analysis/AliasAnalysis.h | 368 +- include/llvm/Analysis/AliasSetTracker.h | 60 +- include/llvm/Analysis/CallGraph.h | 13 +- include/llvm/Analysis/CodeMetrics.h | 31 +- include/llvm/Analysis/ConstantFolding.h | 13 +- include/llvm/Analysis/DIBuilder.h | 459 + include/llvm/Analysis/DOTGraphTraitsPass.h | 2 +- include/llvm/Analysis/DebugInfo.h | 196 +- include/llvm/Analysis/DominanceFrontier.h | 189 + include/llvm/Analysis/DominatorInternals.h | 189 +- include/llvm/Analysis/Dominators.h | 265 +- include/llvm/Analysis/FindUsedTypes.h | 4 +- include/llvm/Analysis/InlineCost.h | 32 +- include/llvm/Analysis/InstructionSimplify.h | 111 +- include/llvm/Analysis/IntervalPartition.h | 4 +- include/llvm/Analysis/LazyValueInfo.h | 4 +- include/llvm/Analysis/LibCallAliasAnalysis.h | 10 +- include/llvm/Analysis/LibCallSemantics.h | 2 +- include/llvm/Analysis/LoopDependenceAnalysis.h | 4 +- include/llvm/Analysis/LoopInfo.h | 43 +- include/llvm/Analysis/MemoryBuiltins.h | 4 + include/llvm/Analysis/MemoryDependenceAnalysis.h | 109 +- include/llvm/Analysis/Passes.h | 35 +- include/llvm/Analysis/PathNumbering.h | 304 + include/llvm/Analysis/PathProfileInfo.h | 113 + include/llvm/Analysis/PointerTracking.h | 132 - include/llvm/Analysis/PostDominators.h | 7 +- include/llvm/Analysis/ProfileInfoTypes.h | 33 +- include/llvm/Analysis/RegionInfo.h | 57 +- include/llvm/Analysis/RegionPass.h | 126 + include/llvm/Analysis/ScalarEvolution.h | 146 +- include/llvm/Analysis/ScalarEvolutionExpander.h | 6 + include/llvm/Analysis/ScalarEvolutionExpressions.h | 138 +- include/llvm/Analysis/ValueTracking.h | 52 +- include/llvm/Attributes.h | 7 +- include/llvm/BasicBlock.h | 32 +- include/llvm/Bitcode/Archive.h | 13 +- include/llvm/Bitcode/BitCodes.h | 2 +- include/llvm/Bitcode/LLVMBitCodes.h | 12 +- include/llvm/Bitcode/ReaderWriter.h | 9 + include/llvm/CallingConv.h | 27 +- include/llvm/CodeGen/Analysis.h | 11 +- include/llvm/CodeGen/AsmPrinter.h | 7 +- include/llvm/CodeGen/BinaryObject.h | 2 +- include/llvm/CodeGen/CalcSpillWeights.h | 24 +- include/llvm/CodeGen/CallingConvLower.h | 42 +- include/llvm/CodeGen/EdgeBundles.h | 61 + include/llvm/CodeGen/FastISel.h | 15 +- include/llvm/CodeGen/FunctionLoweringInfo.h | 7 +- include/llvm/CodeGen/GCMetadata.h | 9 +- include/llvm/CodeGen/ISDOpcodes.h | 52 +- include/llvm/CodeGen/IntrinsicLowering.h | 5 + include/llvm/CodeGen/JITCodeEmitter.h | 2 +- include/llvm/CodeGen/LatencyPriorityQueue.h | 22 +- include/llvm/CodeGen/LinkAllCodegenComponents.h | 4 +- include/llvm/CodeGen/LiveInterval.h | 193 +- include/llvm/CodeGen/LiveIntervalAnalysis.h | 45 +- include/llvm/CodeGen/LiveStackAnalysis.h | 18 +- include/llvm/CodeGen/LiveVariables.h | 11 +- include/llvm/CodeGen/MachORelocation.h | 2 +- include/llvm/CodeGen/MachineBasicBlock.h | 19 +- include/llvm/CodeGen/MachineCodeEmitter.h | 2 +- include/llvm/CodeGen/MachineCodeInfo.h | 2 +- include/llvm/CodeGen/MachineDominators.h | 2 +- include/llvm/CodeGen/MachineFrameInfo.h | 14 +- include/llvm/CodeGen/MachineFunction.h | 26 +- include/llvm/CodeGen/MachineFunctionAnalysis.h | 4 + include/llvm/CodeGen/MachineInstr.h | 36 +- include/llvm/CodeGen/MachineInstrBuilder.h | 21 + include/llvm/CodeGen/MachineLocation.h | 7 +- include/llvm/CodeGen/MachineLoopInfo.h | 4 +- include/llvm/CodeGen/MachineLoopRanges.h | 112 + include/llvm/CodeGen/MachineMemOperand.h | 72 +- include/llvm/CodeGen/MachineModuleInfo.h | 73 +- include/llvm/CodeGen/MachineOperand.h | 134 +- include/llvm/CodeGen/MachineRegisterInfo.h | 58 +- include/llvm/CodeGen/MachineRelocation.h | 2 +- include/llvm/CodeGen/PBQP/Graph.h | 425 + include/llvm/CodeGen/PBQP/HeuristicBase.h | 246 + include/llvm/CodeGen/PBQP/HeuristicSolver.h | 616 + include/llvm/CodeGen/PBQP/Heuristics/Briggs.h | 464 + include/llvm/CodeGen/PBQP/Math.h | 288 + include/llvm/CodeGen/PBQP/Solution.h | 94 + include/llvm/CodeGen/Passes.h | 35 +- include/llvm/CodeGen/PostRAHazardRecognizer.h | 94 - include/llvm/CodeGen/ProcessImplicitDefs.h | 4 +- include/llvm/CodeGen/RegAllocPBQP.h | 167 + include/llvm/CodeGen/RegisterCoalescer.h | 2 +- include/llvm/CodeGen/ScheduleDAG.h | 85 +- include/llvm/CodeGen/ScheduleHazardRecognizer.h | 28 +- include/llvm/CodeGen/ScoreboardHazardRecognizer.h | 129 + include/llvm/CodeGen/SelectionDAG.h | 106 +- include/llvm/CodeGen/SelectionDAGISel.h | 102 +- include/llvm/CodeGen/SelectionDAGNodes.h | 37 +- include/llvm/CodeGen/SlotIndexes.h | 118 +- .../llvm/CodeGen/TargetLoweringObjectFileImpl.h | 6 + include/llvm/CodeGen/ValueTypes.h | 59 +- include/llvm/CodeGen/ValueTypes.td | 11 +- include/llvm/CompilerDriver/CompilationGraph.h | 2 +- include/llvm/CompilerDriver/Tool.h | 4 +- include/llvm/Config/config.h.cmake | 340 +- include/llvm/Config/config.h.in | 76 +- include/llvm/Config/llvm-config.h.cmake | 6 +- include/llvm/Constant.h | 13 +- include/llvm/Constants.h | 130 +- include/llvm/DerivedTypes.h | 3 +- include/llvm/ExecutionEngine/ExecutionEngine.h | 164 +- include/llvm/ExecutionEngine/GenericValue.h | 2 +- include/llvm/ExecutionEngine/JITEventListener.h | 52 +- include/llvm/ExecutionEngine/JITMemoryManager.h | 12 +- include/llvm/ExecutionEngine/MCJIT.h | 38 + include/llvm/Function.h | 2 +- include/llvm/GlobalAlias.h | 3 +- include/llvm/GlobalValue.h | 17 +- include/llvm/GlobalVariable.h | 34 +- include/llvm/InitializePasses.h | 235 + include/llvm/InlineAsm.h | 59 +- include/llvm/InstrTypes.h | 193 +- include/llvm/Instruction.h | 7 +- include/llvm/Instructions.h | 422 +- include/llvm/IntrinsicInst.h | 29 +- include/llvm/Intrinsics.td | 8 +- include/llvm/IntrinsicsARM.td | 6 + include/llvm/IntrinsicsX86.td | 314 +- include/llvm/IntrinsicsXCore.td | 22 + include/llvm/LLVMContext.h | 39 +- include/llvm/LinkAllPasses.h | 18 +- include/llvm/LinkAllVMCore.h | 17 +- include/llvm/MC/EDInstInfo.h | 2 +- include/llvm/MC/ELFObjectWriter.h | 46 - include/llvm/MC/MCAsmInfo.h | 102 +- include/llvm/MC/MCAsmLayout.h | 43 +- include/llvm/MC/MCAssembler.h | 189 +- include/llvm/MC/MCCodeEmitter.h | 38 - include/llvm/MC/MCContext.h | 82 +- include/llvm/MC/MCDirectives.h | 9 +- include/llvm/MC/MCDisassembler.h | 2 +- include/llvm/MC/MCDwarf.h | 133 +- include/llvm/MC/MCELFObjectWriter.h | 47 + include/llvm/MC/MCELFSymbolFlags.h | 11 +- include/llvm/MC/MCExpr.h | 44 +- include/llvm/MC/MCFixup.h | 16 +- include/llvm/MC/MCFixupKindInfo.h | 43 + include/llvm/MC/MCInst.h | 54 +- include/llvm/MC/MCInstPrinter.h | 8 +- include/llvm/MC/MCMachOSymbolFlags.h | 4 +- include/llvm/MC/MCMachObjectWriter.h | 65 + include/llvm/MC/MCObjectStreamer.h | 18 +- include/llvm/MC/MCObjectWriter.h | 35 +- include/llvm/MC/MCParser/AsmLexer.h | 16 +- include/llvm/MC/MCParser/MCAsmLexer.h | 33 +- include/llvm/MC/MCParser/MCAsmParser.h | 6 +- include/llvm/MC/MCParser/MCParsedAsmOperand.h | 4 +- include/llvm/MC/MCSection.h | 11 +- include/llvm/MC/MCSectionCOFF.h | 8 +- include/llvm/MC/MCSectionELF.h | 151 +- include/llvm/MC/MCSectionMachO.h | 22 +- include/llvm/MC/MCStreamer.h | 232 +- include/llvm/MC/MCSymbol.h | 19 +- include/llvm/MC/MCValue.h | 2 +- include/llvm/MC/MachObjectWriter.h | 44 - include/llvm/Metadata.h | 3 - include/llvm/Module.h | 2 +- include/llvm/Object/MachOFormat.h | 367 + include/llvm/Object/MachOObject.h | 180 + include/llvm/Object/ObjectFile.h | 262 + include/llvm/OperandTraits.h | 28 +- include/llvm/Operator.h | 159 +- include/llvm/Pass.h | 4 +- include/llvm/PassManagers.h | 11 +- include/llvm/PassRegistry.h | 75 +- include/llvm/PassSupport.h | 105 +- include/llvm/Support/AIXDataTypesFix.h | 25 + include/llvm/Support/AlignOf.h | 6 +- include/llvm/Support/Allocator.h | 10 +- include/llvm/Support/Atomic.h | 39 + include/llvm/Support/COFF.h | 12 +- include/llvm/Support/CallSite.h | 19 +- include/llvm/Support/Casting.h | 4 +- include/llvm/Support/Compiler.h | 86 +- include/llvm/Support/ConstantFolder.h | 72 +- include/llvm/Support/ConstantRange.h | 17 +- include/llvm/Support/CrashRecoveryContext.h | 8 + include/llvm/Support/DataTypes.h.cmake | 189 + include/llvm/Support/DataTypes.h.in | 111 + include/llvm/Support/Disassembler.h | 35 + include/llvm/Support/Dwarf.h | 7 +- include/llvm/Support/DynamicLibrary.h | 86 + include/llvm/Support/DynamicLinker.h | 40 - include/llvm/Support/ELF.h | 299 +- include/llvm/Support/Endian.h | 213 + include/llvm/Support/Errno.h | 34 + include/llvm/Support/ErrorHandling.h | 13 +- include/llvm/Support/FEnv.h | 56 + include/llvm/Support/FileSystem.h | 690 + include/llvm/Support/FileUtilities.h | 2 +- include/llvm/Support/GraphWriter.h | 45 +- include/llvm/Support/Host.h | 66 + include/llvm/Support/IRBuilder.h | 479 +- include/llvm/Support/IRReader.h | 24 +- include/llvm/Support/IncludeFile.h | 79 + include/llvm/Support/LICENSE.TXT | 6 + include/llvm/Support/MachO.h | 38 +- include/llvm/Support/ManagedStatic.h | 10 +- include/llvm/Support/MathExtras.h | 48 +- include/llvm/Support/Memory.h | 96 + include/llvm/Support/MemoryBuffer.h | 58 +- include/llvm/Support/MemoryObject.h | 2 +- include/llvm/Support/Mutex.h | 154 + include/llvm/Support/MutexGuard.h | 2 +- include/llvm/Support/NoFolder.h | 138 +- include/llvm/Support/Path.h | 16 + include/llvm/Support/PathV1.h | 755 + include/llvm/Support/PathV2.h | 347 + include/llvm/Support/PatternMatch.h | 339 +- include/llvm/Support/PointerLikeTypeTraits.h | 2 +- include/llvm/Support/Process.h | 146 + include/llvm/Support/Program.h | 157 + include/llvm/Support/RWMutex.h | 173 + include/llvm/Support/Signals.h | 59 + include/llvm/Support/Solaris.h | 40 + include/llvm/Support/SourceMgr.h | 15 +- include/llvm/Support/StableBasicBlockNumbering.h | 59 - include/llvm/Support/StandardPasses.h | 75 +- include/llvm/Support/SwapByteOrder.h | 101 + include/llvm/Support/SystemUtils.h | 13 +- include/llvm/Support/TargetFolder.h | 68 +- include/llvm/Support/ThreadLocal.h | 54 + include/llvm/Support/Threading.h | 59 + include/llvm/Support/TimeValue.h | 382 + include/llvm/Support/Timer.h | 2 +- include/llvm/Support/ToolOutputFile.h | 62 + include/llvm/Support/TypeBuilder.h | 6 + include/llvm/Support/Valgrind.h | 32 + include/llvm/Support/raw_ostream.h | 66 +- include/llvm/Support/system_error.h | 910 + include/llvm/System/AIXDataTypesFix.h | 25 - include/llvm/System/Alarm.h | 51 - include/llvm/System/Atomic.h | 39 - include/llvm/System/DataTypes.h.cmake | 189 - include/llvm/System/DataTypes.h.in | 111 - include/llvm/System/Disassembler.h | 35 - include/llvm/System/DynamicLibrary.h | 86 - include/llvm/System/Errno.h | 34 - include/llvm/System/Host.h | 66 - include/llvm/System/IncludeFile.h | 79 - include/llvm/System/LICENSE.TXT | 6 - include/llvm/System/Memory.h | 96 - include/llvm/System/Mutex.h | 154 - include/llvm/System/Path.h | 716 - include/llvm/System/Process.h | 146 - include/llvm/System/Program.h | 155 - include/llvm/System/RWMutex.h | 173 - include/llvm/System/Signals.h | 59 - include/llvm/System/Solaris.h | 40 - include/llvm/System/ThreadLocal.h | 54 - include/llvm/System/Threading.h | 45 - include/llvm/System/TimeValue.h | 382 - include/llvm/System/Valgrind.h | 32 - include/llvm/Target/Mangler.h | 7 - include/llvm/Target/SubtargetFeature.h | 2 +- include/llvm/Target/Target.td | 129 +- include/llvm/Target/TargetAsmBackend.h | 67 +- include/llvm/Target/TargetAsmInfo.h | 75 + include/llvm/Target/TargetAsmParser.h | 16 +- include/llvm/Target/TargetCallingConv.h | 14 +- include/llvm/Target/TargetData.h | 3 +- include/llvm/Target/TargetELFWriterInfo.h | 3 +- include/llvm/Target/TargetFrameInfo.h | 97 - include/llvm/Target/TargetFrameLowering.h | 196 + include/llvm/Target/TargetInstrDesc.h | 13 +- include/llvm/Target/TargetInstrInfo.h | 187 +- include/llvm/Target/TargetInstrItineraries.h | 88 +- include/llvm/Target/TargetJITInfo.h | 2 +- include/llvm/Target/TargetLibraryInfo.h | 66 + include/llvm/Target/TargetLowering.h | 171 +- include/llvm/Target/TargetLoweringObjectFile.h | 15 +- include/llvm/Target/TargetMachine.h | 56 +- include/llvm/Target/TargetRegisterInfo.h | 214 +- include/llvm/Target/TargetRegistry.h | 66 +- include/llvm/Target/TargetSchedule.td | 43 +- include/llvm/Target/TargetSelectionDAG.td | 122 +- include/llvm/Target/TargetSelectionDAGInfo.h | 10 +- include/llvm/Transforms/IPO.h | 8 +- include/llvm/Transforms/Instrumentation.h | 3 + include/llvm/Transforms/RSProfiling.h | 42 - include/llvm/Transforms/Scalar.h | 30 +- include/llvm/Transforms/Utils/AddrModeMatcher.h | 8 +- include/llvm/Transforms/Utils/BasicBlockUtils.h | 26 +- include/llvm/Transforms/Utils/BuildLibCalls.h | 14 - include/llvm/Transforms/Utils/Cloning.h | 15 +- include/llvm/Transforms/Utils/Local.h | 16 + include/llvm/Transforms/Utils/PromoteMemToReg.h | 3 +- include/llvm/Transforms/Utils/SSAUpdater.h | 49 + .../llvm/Transforms/Utils/UnifyFunctionExitNodes.h | 4 +- include/llvm/Transforms/Utils/ValueMapper.h | 25 +- include/llvm/Type.h | 26 +- include/llvm/TypeSymbolTable.h | 3 +- include/llvm/Use.h | 37 +- include/llvm/User.h | 41 +- include/llvm/Value.h | 18 +- include/llvm/ValueSymbolTable.h | 2 +- lib/Analysis/AliasAnalysis.cpp | 187 +- lib/Analysis/AliasAnalysisCounter.cpp | 45 +- lib/Analysis/AliasAnalysisEvaluator.cpp | 36 +- lib/Analysis/AliasDebugger.cpp | 29 +- lib/Analysis/AliasSetTracker.cpp | 105 +- lib/Analysis/Analysis.cpp | 67 +- lib/Analysis/BasicAliasAnalysis.cpp | 459 +- lib/Analysis/CFGPrinter.cpp | 27 +- lib/Analysis/CMakeLists.txt | 11 +- lib/Analysis/CaptureTracking.cpp | 3 + lib/Analysis/ConstantFolding.cpp | 298 +- lib/Analysis/DIBuilder.cpp | 801 + lib/Analysis/DbgInfoPrinter.cpp | 129 +- lib/Analysis/DebugInfo.cpp | 244 +- lib/Analysis/DomPrinter.cpp | 50 +- lib/Analysis/DominanceFrontier.cpp | 137 + lib/Analysis/IPA/CMakeLists.txt | 1 + lib/Analysis/IPA/CallGraph.cpp | 24 +- lib/Analysis/IPA/CallGraphSCCPass.cpp | 1 - lib/Analysis/IPA/FindUsedTypes.cpp | 2 +- lib/Analysis/IPA/GlobalsModRef.cpp | 77 +- lib/Analysis/IPA/IPA.cpp | 29 + lib/Analysis/IVUsers.cpp | 12 +- lib/Analysis/InlineCost.cpp | 486 +- lib/Analysis/InstCount.cpp | 6 +- lib/Analysis/InstructionSimplify.cpp | 1904 +- lib/Analysis/IntervalPartition.cpp | 2 +- lib/Analysis/LazyValueInfo.cpp | 844 +- lib/Analysis/LibCallAliasAnalysis.cpp | 20 +- lib/Analysis/Lint.cpp | 110 +- lib/Analysis/LiveValues.cpp | 15 +- lib/Analysis/Loads.cpp | 4 +- lib/Analysis/LoopDependenceAnalysis.cpp | 17 +- lib/Analysis/LoopInfo.cpp | 22 +- lib/Analysis/LoopPass.cpp | 1 - lib/Analysis/MemDepPrinter.cpp | 167 + lib/Analysis/MemoryDependenceAnalysis.cpp | 373 +- lib/Analysis/ModuleDebugInfoPrinter.cpp | 6 +- lib/Analysis/NoAliasAnalysis.cpp | 88 + lib/Analysis/PHITransAddr.cpp | 154 +- lib/Analysis/PathNumbering.cpp | 525 + lib/Analysis/PathProfileInfo.cpp | 434 + lib/Analysis/PathProfileVerifier.cpp | 207 + lib/Analysis/PointerTracking.cpp | 316 - lib/Analysis/PostDominators.cpp | 10 +- lib/Analysis/ProfileEstimatorPass.cpp | 11 +- lib/Analysis/ProfileInfo.cpp | 17 +- lib/Analysis/ProfileInfoLoaderPass.cpp | 3 +- lib/Analysis/ProfileVerifierPass.cpp | 11 +- lib/Analysis/RegionInfo.cpp | 168 +- lib/Analysis/RegionPass.cpp | 275 + lib/Analysis/RegionPrinter.cpp | 36 +- lib/Analysis/ScalarEvolution.cpp | 1170 +- lib/Analysis/ScalarEvolutionAliasAnalysis.cpp | 41 +- lib/Analysis/ScalarEvolutionExpander.cpp | 51 +- lib/Analysis/TypeBasedAliasAnalysis.cpp | 232 +- lib/Analysis/ValueTracking.cpp | 369 +- lib/Archive/Archive.cpp | 54 +- lib/Archive/ArchiveInternals.h | 2 +- lib/Archive/ArchiveWriter.cpp | 117 +- lib/AsmParser/LLLexer.cpp | 21 +- lib/AsmParser/LLLexer.h | 4 +- lib/AsmParser/LLParser.cpp | 151 +- lib/AsmParser/LLParser.h | 8 +- lib/AsmParser/LLToken.h | 3 + lib/AsmParser/Parser.cpp | 10 +- lib/Bitcode/CMakeLists.txt | 2 + lib/Bitcode/Reader/BitcodeReader.cpp | 181 +- lib/Bitcode/Reader/BitcodeReader.h | 5 + lib/Bitcode/Writer/BitcodeWriter.cpp | 32 +- lib/CMakeLists.txt | 14 + lib/CodeGen/AggressiveAntiDepBreaker.cpp | 45 +- lib/CodeGen/AllocationOrder.cpp | 68 + lib/CodeGen/AllocationOrder.h | 54 + lib/CodeGen/Analysis.cpp | 30 +- lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 64 +- lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp | 61 +- lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp | 122 +- lib/CodeGen/AsmPrinter/CMakeLists.txt | 3 +- lib/CodeGen/AsmPrinter/DwarfCFIException.cpp | 138 + lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 681 +- lib/CodeGen/AsmPrinter/DwarfDebug.h | 139 +- lib/CodeGen/AsmPrinter/DwarfException.cpp | 338 +- lib/CodeGen/AsmPrinter/DwarfException.h | 155 +- lib/CodeGen/AsmPrinter/DwarfTableException.cpp | 349 + lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp | 1 + lib/CodeGen/CMakeLists.txt | 17 +- lib/CodeGen/CalcSpillWeights.cpp | 15 +- lib/CodeGen/CallingConvLower.cpp | 40 +- lib/CodeGen/CodeGen.cpp | 61 + lib/CodeGen/CriticalAntiDepBreaker.cpp | 99 +- lib/CodeGen/CriticalAntiDepBreaker.h | 12 +- lib/CodeGen/DeadMachineInstructionElim.cpp | 16 +- lib/CodeGen/DwarfEHPrepare.cpp | 30 +- lib/CodeGen/ELF.h | 2 +- lib/CodeGen/ELFWriter.cpp | 17 +- lib/CodeGen/EdgeBundles.cpp | 86 + lib/CodeGen/ExpandISelPseudos.cpp | 82 + lib/CodeGen/GCMetadata.cpp | 7 +- lib/CodeGen/GCStrategy.cpp | 44 +- lib/CodeGen/IfConversion.cpp | 247 +- lib/CodeGen/InlineSpiller.cpp | 287 +- lib/CodeGen/IntrinsicLowering.cpp | 32 +- lib/CodeGen/LLVMTargetMachine.cpp | 43 +- lib/CodeGen/LatencyPriorityQueue.cpp | 26 +- lib/CodeGen/LiveDebugVariables.cpp | 711 + lib/CodeGen/LiveDebugVariables.h | 63 + lib/CodeGen/LiveInterval.cpp | 312 +- lib/CodeGen/LiveIntervalAnalysis.cpp | 357 +- lib/CodeGen/LiveIntervalUnion.cpp | 315 + lib/CodeGen/LiveIntervalUnion.h | 258 + lib/CodeGen/LiveRangeEdit.cpp | 129 + lib/CodeGen/LiveRangeEdit.h | 135 + lib/CodeGen/LiveStackAnalysis.cpp | 20 +- lib/CodeGen/LiveVariables.cpp | 42 +- lib/CodeGen/LocalStackSlotAllocation.cpp | 29 +- lib/CodeGen/MachineBasicBlock.cpp | 79 +- lib/CodeGen/MachineCSE.cpp | 162 +- lib/CodeGen/MachineDominators.cpp | 3 +- lib/CodeGen/MachineFunction.cpp | 69 +- lib/CodeGen/MachineFunctionAnalysis.cpp | 12 +- lib/CodeGen/MachineInstr.cpp | 171 +- lib/CodeGen/MachineLICM.cpp | 506 +- lib/CodeGen/MachineLoopInfo.cpp | 7 +- lib/CodeGen/MachineLoopRanges.cpp | 116 + lib/CodeGen/MachineModuleInfo.cpp | 76 +- lib/CodeGen/MachineRegisterInfo.cpp | 64 +- lib/CodeGen/MachineSink.cpp | 312 +- lib/CodeGen/MachineVerifier.cpp | 377 +- lib/CodeGen/OptimizePHIs.cpp | 6 +- lib/CodeGen/PBQP/Graph.h | 425 - lib/CodeGen/PBQP/HeuristicBase.h | 246 - lib/CodeGen/PBQP/HeuristicSolver.h | 616 - lib/CodeGen/PBQP/Heuristics/Briggs.h | 460 - lib/CodeGen/PBQP/Math.h | 288 - lib/CodeGen/PBQP/Solution.h | 89 - lib/CodeGen/PHIElimination.cpp | 143 +- lib/CodeGen/PHIElimination.h | 115 - lib/CodeGen/PHIEliminationUtils.cpp | 61 + lib/CodeGen/PHIEliminationUtils.h | 25 + lib/CodeGen/PeepholeOptimizer.cpp | 131 +- lib/CodeGen/PostRAHazardRecognizer.cpp | 180 - lib/CodeGen/PostRASchedulerList.cpp | 74 +- lib/CodeGen/PreAllocSplitting.cpp | 43 +- lib/CodeGen/ProcessImplicitDefs.cpp | 7 +- lib/CodeGen/PrologEpilogInserter.cpp | 62 +- lib/CodeGen/PrologEpilogInserter.h | 4 +- lib/CodeGen/PseudoSourceValue.cpp | 2 +- lib/CodeGen/RegAllocBase.h | 181 + lib/CodeGen/RegAllocBasic.cpp | 523 + lib/CodeGen/RegAllocFast.cpp | 68 +- lib/CodeGen/RegAllocGreedy.cpp | 1285 ++ lib/CodeGen/RegAllocLinearScan.cpp | 109 +- lib/CodeGen/RegAllocPBQP.cpp | 994 +- lib/CodeGen/RegisterCoalescer.cpp | 3 +- lib/CodeGen/RenderMachineFunction.cpp | 14 +- lib/CodeGen/RenderMachineFunction.h | 4 +- lib/CodeGen/ScheduleDAG.cpp | 15 +- lib/CodeGen/ScheduleDAGEmit.cpp | 2 +- lib/CodeGen/ScheduleDAGInstrs.cpp | 137 +- lib/CodeGen/ScheduleDAGInstrs.h | 10 + lib/CodeGen/ScoreboardHazardRecognizer.cpp | 243 + lib/CodeGen/SelectionDAG/CMakeLists.txt | 2 - lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 1211 +- lib/CodeGen/SelectionDAG/FastISel.cpp | 84 +- lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp | 1 - lib/CodeGen/SelectionDAG/InstrEmitter.cpp | 141 +- lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 1056 +- lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp | 33 +- lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp | 426 +- lib/CodeGen/SelectionDAG/LegalizeTypes.cpp | 49 +- lib/CodeGen/SelectionDAG/LegalizeTypes.h | 34 +- lib/CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp | 66 +- lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp | 4 +- lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp | 325 +- lib/CodeGen/SelectionDAG/SDNodeDbgValue.h | 2 +- lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp | 12 +- lib/CodeGen/SelectionDAG/ScheduleDAGList.cpp | 51 +- lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp | 1969 +- lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp | 333 +- lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.h | 35 +- lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 684 +- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 850 +- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h | 14 +- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 791 +- lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp | 16 +- lib/CodeGen/SelectionDAG/TargetLowering.cpp | 669 +- lib/CodeGen/ShrinkWrapping.cpp | 4 +- lib/CodeGen/SimpleRegisterCoalescing.cpp | 247 +- lib/CodeGen/SimpleRegisterCoalescing.h | 13 +- lib/CodeGen/SjLjEHPrepare.cpp | 446 +- lib/CodeGen/SlotIndexes.cpp | 33 +- lib/CodeGen/SpillPlacement.cpp | 330 + lib/CodeGen/SpillPlacement.h | 108 + lib/CodeGen/Spiller.cpp | 316 +- lib/CodeGen/Spiller.h | 12 +- lib/CodeGen/SplitKit.cpp | 1491 +- lib/CodeGen/SplitKit.h | 419 +- lib/CodeGen/Splitter.cpp | 32 +- lib/CodeGen/Splitter.h | 4 +- lib/CodeGen/StackProtector.cpp | 28 +- lib/CodeGen/StackSlotColoring.cpp | 30 +- lib/CodeGen/StrongPHIElimination.cpp | 1694 +- lib/CodeGen/TailDuplication.cpp | 21 +- lib/CodeGen/TargetInstrInfoImpl.cpp | 50 +- lib/CodeGen/TargetLoweringObjectFileImpl.cpp | 253 +- lib/CodeGen/TwoAddressInstructionPass.cpp | 54 +- lib/CodeGen/UnreachableBlockElim.cpp | 15 +- lib/CodeGen/VirtRegMap.cpp | 165 +- lib/CodeGen/VirtRegMap.h | 33 +- lib/CodeGen/VirtRegRewriter.cpp | 896 +- lib/CompilerDriver/Action.cpp | 26 +- lib/CompilerDriver/CMakeLists.txt | 2 +- lib/CompilerDriver/CompilationGraph.cpp | 66 +- lib/CompilerDriver/Main.cpp | 9 +- lib/CompilerDriver/Makefile | 2 +- lib/CompilerDriver/Tool.cpp | 6 +- lib/ExecutionEngine/CMakeLists.txt | 4 + lib/ExecutionEngine/ExecutionEngine.cpp | 378 +- lib/ExecutionEngine/Interpreter/CMakeLists.txt | 12 + lib/ExecutionEngine/Interpreter/Execution.cpp | 6 +- .../Interpreter/ExternalFunctions.cpp | 4 +- lib/ExecutionEngine/Interpreter/Interpreter.h | 2 +- lib/ExecutionEngine/JIT/Intercept.cpp | 2 +- lib/ExecutionEngine/JIT/JIT.cpp | 23 +- lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp | 4 +- lib/ExecutionEngine/JIT/JITDebugRegisterer.h | 2 +- lib/ExecutionEngine/JIT/JITDwarfEmitter.cpp | 11 +- lib/ExecutionEngine/JIT/JITDwarfEmitter.h | 2 + lib/ExecutionEngine/JIT/JITEmitter.cpp | 4 +- lib/ExecutionEngine/JIT/JITMemoryManager.cpp | 2 +- .../JIT/OProfileJITEventListener.cpp | 2 +- lib/ExecutionEngine/JIT/TargetSelect.cpp | 2 +- lib/ExecutionEngine/MCJIT/CMakeLists.txt | 4 + lib/ExecutionEngine/MCJIT/MCJIT.cpp | 92 + lib/ExecutionEngine/MCJIT/MCJIT.h | 68 + lib/ExecutionEngine/MCJIT/Makefile | 13 + lib/ExecutionEngine/MCJIT/TargetSelect.cpp | 91 + lib/ExecutionEngine/Makefile | 2 +- lib/Linker/LinkItems.cpp | 13 +- lib/Linker/LinkModules.cpp | 100 +- lib/Linker/Linker.cpp | 18 +- lib/MC/CMakeLists.txt | 6 + lib/MC/ELFObjectWriter.cpp | 1858 +- lib/MC/MCAsmInfo.cpp | 7 +- lib/MC/MCAsmInfoDarwin.cpp | 9 +- lib/MC/MCAsmStreamer.cpp | 382 +- lib/MC/MCAssembler.cpp | 794 +- lib/MC/MCCodeEmitter.cpp | 12 - lib/MC/MCContext.cpp | 117 +- lib/MC/MCDisassembler/EDDisassembler.cpp | 2 +- lib/MC/MCDisassembler/EDDisassembler.h | 8 +- lib/MC/MCDisassembler/EDInst.cpp | 2 + lib/MC/MCDisassembler/EDInst.h | 2 +- lib/MC/MCDisassembler/EDOperand.cpp | 23 +- lib/MC/MCDisassembler/EDOperand.h | 2 +- lib/MC/MCDisassembler/EDToken.h | 2 +- lib/MC/MCDwarf.cpp | 793 + lib/MC/MCELFObjectTargetWriter.cpp | 23 + lib/MC/MCELFStreamer.cpp | 350 +- lib/MC/MCExpr.cpp | 284 +- lib/MC/MCLoggingStreamer.cpp | 60 +- lib/MC/MCMachOStreamer.cpp | 355 +- lib/MC/MCMachObjectTargetWriter.cpp | 22 + lib/MC/MCNullStreamer.cpp | 31 +- lib/MC/MCObjectStreamer.cpp | 187 +- lib/MC/MCObjectWriter.cpp | 65 + lib/MC/MCParser/AsmLexer.cpp | 182 +- lib/MC/MCParser/AsmParser.cpp | 889 +- lib/MC/MCParser/CMakeLists.txt | 1 + lib/MC/MCParser/COFFAsmParser.cpp | 144 + lib/MC/MCParser/DarwinAsmParser.cpp | 2 +- lib/MC/MCParser/ELFAsmParser.cpp | 460 +- lib/MC/MCPureStreamer.cpp | 234 + lib/MC/MCSectionCOFF.cpp | 8 + lib/MC/MCSectionELF.cpp | 121 +- lib/MC/MCSectionMachO.cpp | 62 +- lib/MC/MCStreamer.cpp | 218 +- lib/MC/MCSymbol.cpp | 13 + lib/MC/MachObjectWriter.cpp | 935 +- lib/MC/TargetAsmBackend.cpp | 25 +- lib/MC/WinCOFFObjectWriter.cpp | 371 +- lib/MC/WinCOFFStreamer.cpp | 180 +- lib/Makefile | 2 +- lib/Object/CMakeLists.txt | 6 + lib/Object/COFFObjectFile.cpp | 375 + lib/Object/ELFObjectFile.cpp | 686 + lib/Object/MachOObject.cpp | 342 + lib/Object/Makefile | 14 + lib/Object/ObjectFile.cpp | 71 + lib/Support/APFloat.cpp | 28 +- lib/Support/APInt.cpp | 234 +- lib/Support/Allocator.cpp | 10 +- lib/Support/Atomic.cpp | 112 + lib/Support/CMakeLists.txt | 58 +- lib/Support/CommandLine.cpp | 84 +- lib/Support/ConstantRange.cpp | 94 +- lib/Support/CrashRecoveryContext.cpp | 30 +- lib/Support/Debug.cpp | 2 +- lib/Support/Disassembler.cpp | 75 + lib/Support/Dwarf.cpp | 4 + lib/Support/DynamicLibrary.cpp | 170 + lib/Support/Errno.cpp | 74 + lib/Support/ErrorHandling.cpp | 11 +- lib/Support/FileUtilities.cpp | 26 +- lib/Support/FoldingSet.cpp | 29 +- lib/Support/FormattedStream.cpp | 1 + lib/Support/GraphWriter.cpp | 48 +- lib/Support/Host.cpp | 307 + lib/Support/IncludeFile.cpp | 20 + lib/Support/IntEqClasses.cpp | 70 + lib/Support/IntervalMap.cpp | 161 + lib/Support/Makefile | 5 + lib/Support/ManagedStatic.cpp | 2 +- lib/Support/Memory.cpp | 74 + lib/Support/MemoryBuffer.cpp | 113 +- lib/Support/Mutex.cpp | 157 + lib/Support/Path.cpp | 283 + lib/Support/PathV2.cpp | 774 + lib/Support/PluginLoader.cpp | 4 +- lib/Support/PrettyStackTrace.cpp | 17 +- lib/Support/Process.cpp | 33 + lib/Support/Program.cpp | 56 + lib/Support/README.txt.system | 43 + lib/Support/RWMutex.cpp | 157 + lib/Support/SearchForAddressOfSpecialSymbol.cpp | 73 + lib/Support/Signals.cpp | 34 + lib/Support/SourceMgr.cpp | 31 +- lib/Support/Statistic.cpp | 2 +- lib/Support/StringMap.cpp | 2 +- lib/Support/StringRef.cpp | 73 +- lib/Support/SystemUtils.cpp | 40 +- lib/Support/TargetRegistry.cpp | 2 +- lib/Support/ThreadLocal.cpp | 84 + lib/Support/Threading.cpp | 116 + lib/Support/TimeValue.cpp | 57 + lib/Support/Timer.cpp | 4 +- lib/Support/ToolOutputFile.cpp | 43 + lib/Support/Triple.cpp | 106 +- lib/Support/Twine.cpp | 34 +- lib/Support/Unix/Host.inc | 97 + lib/Support/Unix/Memory.inc | 151 + lib/Support/Unix/Mutex.inc | 43 + lib/Support/Unix/Path.inc | 887 + lib/Support/Unix/PathV2.inc | 507 + lib/Support/Unix/Process.inc | 295 + lib/Support/Unix/Program.inc | 424 + lib/Support/Unix/README.txt | 16 + lib/Support/Unix/RWMutex.inc | 43 + lib/Support/Unix/Signals.inc | 303 + lib/Support/Unix/ThreadLocal.inc | 26 + lib/Support/Unix/TimeValue.inc | 56 + lib/Support/Unix/Unix.h | 87 + lib/Support/Unix/system_error.inc | 34 + lib/Support/Valgrind.cpp | 54 + lib/Support/Windows/DynamicLibrary.inc | 166 + lib/Support/Windows/Host.inc | 23 + lib/Support/Windows/Memory.inc | 73 + lib/Support/Windows/Mutex.inc | 58 + lib/Support/Windows/Path.inc | 921 + lib/Support/Windows/PathV2.inc | 750 + lib/Support/Windows/Process.inc | 222 + lib/Support/Windows/Program.inc | 403 + lib/Support/Windows/RWMutex.inc | 58 + lib/Support/Windows/Signals.inc | 328 + lib/Support/Windows/ThreadLocal.inc | 54 + lib/Support/Windows/TimeValue.inc | 51 + lib/Support/Windows/Windows.h | 120 + lib/Support/Windows/explicit_symbols.inc | 66 + lib/Support/Windows/system_error.inc | 142 + lib/Support/raw_ostream.cpp | 103 +- lib/Support/regexec.c | 5 +- lib/Support/system_error.cpp | 130 + lib/System/Alarm.cpp | 33 - lib/System/Atomic.cpp | 112 - lib/System/CMakeLists.txt | 48 - lib/System/Disassembler.cpp | 75 - lib/System/DynamicLibrary.cpp | 161 - lib/System/Errno.cpp | 74 - lib/System/Host.cpp | 305 - lib/System/IncludeFile.cpp | 20 - lib/System/Makefile | 25 - lib/System/Memory.cpp | 74 - lib/System/Mutex.cpp | 157 - lib/System/Path.cpp | 264 - lib/System/Process.cpp | 33 - lib/System/Program.cpp | 56 - lib/System/README.txt | 43 - lib/System/RWMutex.cpp | 157 - lib/System/SearchForAddressOfSpecialSymbol.cpp | 64 - lib/System/Signals.cpp | 34 - lib/System/ThreadLocal.cpp | 85 - lib/System/Threading.cpp | 64 - lib/System/TimeValue.cpp | 58 - lib/System/Unix/Alarm.inc | 72 - lib/System/Unix/Host.inc | 96 - lib/System/Unix/Memory.inc | 151 - lib/System/Unix/Mutex.inc | 43 - lib/System/Unix/Path.inc | 923 - lib/System/Unix/Process.inc | 295 - lib/System/Unix/Program.inc | 402 - lib/System/Unix/README.txt | 16 - lib/System/Unix/RWMutex.inc | 43 - lib/System/Unix/Signals.inc | 299 - lib/System/Unix/ThreadLocal.inc | 26 - lib/System/Unix/TimeValue.inc | 56 - lib/System/Unix/Unix.h | 87 - lib/System/Valgrind.cpp | 54 - lib/System/Win32/Alarm.inc | 43 - lib/System/Win32/DynamicLibrary.inc | 200 - lib/System/Win32/Host.inc | 23 - lib/System/Win32/Memory.inc | 73 - lib/System/Win32/Mutex.inc | 58 - lib/System/Win32/Path.inc | 872 - lib/System/Win32/Process.inc | 221 - lib/System/Win32/Program.inc | 409 - lib/System/Win32/RWMutex.inc | 58 - lib/System/Win32/Signals.inc | 332 - lib/System/Win32/ThreadLocal.inc | 53 - lib/System/Win32/TimeValue.inc | 51 - lib/System/Win32/Win32.h | 57 - lib/Target/ARM/ARM.h | 114 +- lib/Target/ARM/ARM.td | 58 +- lib/Target/ARM/ARMAddressingModes.h | 12 + lib/Target/ARM/ARMAsmBackend.cpp | 512 + lib/Target/ARM/ARMAsmPrinter.cpp | 2225 ++- lib/Target/ARM/ARMAsmPrinter.h | 112 + lib/Target/ARM/ARMBaseInfo.h | 249 + lib/Target/ARM/ARMBaseInstrInfo.cpp | 1305 +- lib/Target/ARM/ARMBaseInstrInfo.h | 171 +- lib/Target/ARM/ARMBaseRegisterInfo.cpp | 948 +- lib/Target/ARM/ARMBaseRegisterInfo.h | 65 +- lib/Target/ARM/ARMBuildAttrs.h | 73 +- lib/Target/ARM/ARMCallingConv.h | 160 + lib/Target/ARM/ARMCallingConv.td | 29 + lib/Target/ARM/ARMCodeEmitter.cpp | 368 +- lib/Target/ARM/ARMConstantIslandPass.cpp | 27 +- lib/Target/ARM/ARMConstantPoolValue.cpp | 26 +- lib/Target/ARM/ARMConstantPoolValue.h | 43 +- lib/Target/ARM/ARMELFWriterInfo.cpp | 83 + lib/Target/ARM/ARMELFWriterInfo.h | 58 + lib/Target/ARM/ARMExpandPseudoInsts.cpp | 1227 +- lib/Target/ARM/ARMFastISel.cpp | 1670 +- lib/Target/ARM/ARMFixupKinds.h | 97 + lib/Target/ARM/ARMFrameInfo.h | 32 - lib/Target/ARM/ARMFrameLowering.cpp | 1021 + lib/Target/ARM/ARMFrameLowering.h | 74 + lib/Target/ARM/ARMGlobalMerge.cpp | 69 +- lib/Target/ARM/ARMHazardRecognizer.cpp | 121 + lib/Target/ARM/ARMHazardRecognizer.h | 54 + lib/Target/ARM/ARMISelDAGToDAG.cpp | 1823 +- lib/Target/ARM/ARMISelLowering.cpp | 2278 ++- lib/Target/ARM/ARMISelLowering.h | 88 +- lib/Target/ARM/ARMInstrFormats.td | 1191 +- lib/Target/ARM/ARMInstrInfo.cpp | 33 +- lib/Target/ARM/ARMInstrInfo.h | 5 - lib/Target/ARM/ARMInstrInfo.td | 3554 ++-- lib/Target/ARM/ARMInstrNEON.td | 3650 ++-- lib/Target/ARM/ARMInstrThumb.td | 1661 +- lib/Target/ARM/ARMInstrThumb2.td | 2725 ++- lib/Target/ARM/ARMInstrVFP.td | 1146 +- lib/Target/ARM/ARMJITInfo.cpp | 13 +- lib/Target/ARM/ARMJITInfo.h | 2 +- lib/Target/ARM/ARMLoadStoreOptimizer.cpp | 519 +- lib/Target/ARM/ARMMCCodeEmitter.cpp | 1230 ++ lib/Target/ARM/ARMMCExpr.cpp | 73 + lib/Target/ARM/ARMMCExpr.h | 73 + lib/Target/ARM/ARMMCInstLower.cpp | 147 +- lib/Target/ARM/ARMMCInstLower.h | 56 - lib/Target/ARM/ARMMachineFunctionInfo.h | 60 +- lib/Target/ARM/ARMPerfectShuffle.h | 13122 ++++++------- lib/Target/ARM/ARMRegisterInfo.cpp | 1 - lib/Target/ARM/ARMRegisterInfo.td | 90 +- lib/Target/ARM/ARMSchedule.td | 140 +- lib/Target/ARM/ARMScheduleA8.td | 862 +- lib/Target/ARM/ARMScheduleA9.td | 1799 +- lib/Target/ARM/ARMScheduleV6.td | 130 +- lib/Target/ARM/ARMSelectionDAGInfo.cpp | 16 +- lib/Target/ARM/ARMSelectionDAGInfo.h | 6 +- lib/Target/ARM/ARMSubtarget.cpp | 119 +- lib/Target/ARM/ARMSubtarget.h | 48 +- lib/Target/ARM/ARMTargetMachine.cpp | 62 +- lib/Target/ARM/ARMTargetMachine.h | 36 +- lib/Target/ARM/ARMTargetObjectFile.cpp | 19 +- lib/Target/ARM/ARMTargetObjectFile.h | 11 +- lib/Target/ARM/AsmParser/ARMAsmLexer.cpp | 192 +- lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 1530 +- lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp | 800 - lib/Target/ARM/AsmPrinter/ARMInstPrinter.h | 118 - lib/Target/ARM/AsmPrinter/CMakeLists.txt | 6 - lib/Target/ARM/AsmPrinter/Makefile | 15 - lib/Target/ARM/CMakeLists.txt | 25 +- lib/Target/ARM/Disassembler/ARMDisassembler.cpp | 49 +- .../ARM/Disassembler/ARMDisassemblerCore.cpp | 259 +- lib/Target/ARM/Disassembler/CMakeLists.txt | 14 + .../ARM/Disassembler/ThumbDisassemblerCore.h | 298 +- lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp | 711 + lib/Target/ARM/InstPrinter/ARMInstPrinter.h | 111 + lib/Target/ARM/InstPrinter/CMakeLists.txt | 6 + lib/Target/ARM/InstPrinter/Makefile | 15 + lib/Target/ARM/MLxExpansionPass.cpp | 321 + lib/Target/ARM/Makefile | 4 +- lib/Target/ARM/NEONPreAllocPass.cpp | 406 - lib/Target/ARM/README-Thumb.txt | 21 +- lib/Target/ARM/Thumb1FrameLowering.cpp | 352 + lib/Target/ARM/Thumb1FrameLowering.h | 52 + lib/Target/ARM/Thumb1InstrInfo.cpp | 84 +- lib/Target/ARM/Thumb1InstrInfo.h | 17 +- lib/Target/ARM/Thumb1RegisterInfo.cpp | 332 +- lib/Target/ARM/Thumb1RegisterInfo.h | 5 - lib/Target/ARM/Thumb2HazardRecognizer.cpp | 53 - lib/Target/ARM/Thumb2HazardRecognizer.h | 40 - lib/Target/ARM/Thumb2InstrInfo.cpp | 44 +- lib/Target/ARM/Thumb2InstrInfo.h | 8 - lib/Target/ARM/Thumb2RegisterInfo.cpp | 1 - lib/Target/ARM/Thumb2SizeReduction.cpp | 133 +- lib/Target/Alpha/Alpha.h | 7 + lib/Target/Alpha/AlphaAsmPrinter.cpp | 166 + lib/Target/Alpha/AlphaCodeEmitter.cpp | 222 - lib/Target/Alpha/AlphaFrameLowering.cpp | 143 + lib/Target/Alpha/AlphaFrameLowering.h | 43 + lib/Target/Alpha/AlphaISelDAGToDAG.cpp | 19 +- lib/Target/Alpha/AlphaISelLowering.cpp | 87 +- lib/Target/Alpha/AlphaISelLowering.h | 5 + lib/Target/Alpha/AlphaInstrInfo.td | 6 +- lib/Target/Alpha/AlphaJITInfo.cpp | 310 - lib/Target/Alpha/AlphaJITInfo.h | 53 - lib/Target/Alpha/AlphaRegisterInfo.cpp | 152 +- lib/Target/Alpha/AlphaRegisterInfo.h | 10 - lib/Target/Alpha/AlphaSchedule.td | 4 +- lib/Target/Alpha/AlphaTargetMachine.cpp | 10 +- lib/Target/Alpha/AlphaTargetMachine.h | 20 +- lib/Target/Alpha/AsmPrinter/AlphaAsmPrinter.cpp | 166 - lib/Target/Alpha/AsmPrinter/CMakeLists.txt | 6 - lib/Target/Alpha/AsmPrinter/Makefile | 15 - lib/Target/Alpha/CMakeLists.txt | 7 +- lib/Target/Alpha/Makefile | 4 +- .../Blackfin/AsmPrinter/BlackfinAsmPrinter.cpp | 156 - lib/Target/Blackfin/AsmPrinter/CMakeLists.txt | 6 - lib/Target/Blackfin/AsmPrinter/Makefile | 16 - lib/Target/Blackfin/BlackfinAsmPrinter.cpp | 156 + lib/Target/Blackfin/BlackfinFrameLowering.cpp | 124 + lib/Target/Blackfin/BlackfinFrameLowering.h | 46 + lib/Target/Blackfin/BlackfinISelDAGToDAG.cpp | 6 +- lib/Target/Blackfin/BlackfinISelLowering.cpp | 61 +- lib/Target/Blackfin/BlackfinISelLowering.h | 6 + lib/Target/Blackfin/BlackfinInstrInfo.td | 8 +- lib/Target/Blackfin/BlackfinRegisterInfo.cpp | 106 +- lib/Target/Blackfin/BlackfinRegisterInfo.h | 8 - lib/Target/Blackfin/BlackfinRegisterInfo.td | 20 +- lib/Target/Blackfin/BlackfinTargetMachine.cpp | 2 +- lib/Target/Blackfin/BlackfinTargetMachine.h | 17 +- lib/Target/Blackfin/CMakeLists.txt | 4 + lib/Target/Blackfin/Makefile | 2 +- lib/Target/CBackend/CBackend.cpp | 337 +- lib/Target/CBackend/CMakeLists.txt | 2 + lib/Target/CMakeLists.txt | 44 +- lib/Target/CellSPU/AsmPrinter/CMakeLists.txt | 9 - lib/Target/CellSPU/AsmPrinter/Makefile | 17 - lib/Target/CellSPU/AsmPrinter/SPUAsmPrinter.cpp | 364 - lib/Target/CellSPU/CMakeLists.txt | 6 +- lib/Target/CellSPU/Makefile | 2 +- lib/Target/CellSPU/README.txt | 2 +- lib/Target/CellSPU/SPU.h | 1 + lib/Target/CellSPU/SPU64InstrInfo.td | 79 +- lib/Target/CellSPU/SPUAsmPrinter.cpp | 327 + lib/Target/CellSPU/SPUFrameInfo.cpp | 29 - lib/Target/CellSPU/SPUFrameInfo.h | 75 - lib/Target/CellSPU/SPUFrameLowering.cpp | 276 + lib/Target/CellSPU/SPUFrameLowering.h | 94 + lib/Target/CellSPU/SPUHazardRecognizers.cpp | 4 +- lib/Target/CellSPU/SPUHazardRecognizers.h | 4 +- lib/Target/CellSPU/SPUISelDAGToDAG.cpp | 223 +- lib/Target/CellSPU/SPUISelLowering.cpp | 787 +- lib/Target/CellSPU/SPUISelLowering.h | 23 +- lib/Target/CellSPU/SPUInstrInfo.cpp | 15 +- lib/Target/CellSPU/SPUInstrInfo.h | 4 + lib/Target/CellSPU/SPUInstrInfo.td | 396 +- lib/Target/CellSPU/SPUMCAsmInfo.cpp | 3 +- lib/Target/CellSPU/SPUNodes.td | 18 +- lib/Target/CellSPU/SPUNopFiller.cpp | 153 + lib/Target/CellSPU/SPUOperands.td | 18 +- lib/Target/CellSPU/SPURegisterInfo.cpp | 264 +- lib/Target/CellSPU/SPURegisterInfo.h | 16 +- lib/Target/CellSPU/SPUSchedule.td | 8 +- lib/Target/CellSPU/SPUSubtarget.cpp | 21 + lib/Target/CellSPU/SPUSubtarget.h | 6 +- lib/Target/CellSPU/SPUTargetMachine.cpp | 13 +- lib/Target/CellSPU/SPUTargetMachine.h | 15 +- lib/Target/CppBackend/CMakeLists.txt | 2 + lib/Target/CppBackend/CPPBackend.cpp | 37 +- lib/Target/MBlaze/AsmParser/CMakeLists.txt | 8 + lib/Target/MBlaze/AsmParser/MBlazeAsmLexer.cpp | 127 + lib/Target/MBlaze/AsmParser/MBlazeAsmParser.cpp | 568 + lib/Target/MBlaze/AsmParser/Makefile | 15 + lib/Target/MBlaze/AsmPrinter/CMakeLists.txt | 9 - lib/Target/MBlaze/AsmPrinter/MBlazeAsmPrinter.cpp | 295 - lib/Target/MBlaze/AsmPrinter/Makefile | 17 - lib/Target/MBlaze/CMakeLists.txt | 14 +- lib/Target/MBlaze/Disassembler/CMakeLists.txt | 16 + .../MBlaze/Disassembler/MBlazeDisassembler.cpp | 647 + .../MBlaze/Disassembler/MBlazeDisassembler.h | 55 + lib/Target/MBlaze/Disassembler/Makefile | 16 + lib/Target/MBlaze/InstPrinter/CMakeLists.txt | 8 + .../MBlaze/InstPrinter/MBlazeInstPrinter.cpp | 69 + lib/Target/MBlaze/InstPrinter/MBlazeInstPrinter.h | 43 + lib/Target/MBlaze/InstPrinter/Makefile | 16 + lib/Target/MBlaze/MBlaze.h | 8 + lib/Target/MBlaze/MBlaze.td | 41 +- lib/Target/MBlaze/MBlazeAsmBackend.cpp | 163 + lib/Target/MBlaze/MBlazeAsmPrinter.cpp | 335 + lib/Target/MBlaze/MBlazeCallingConv.td | 14 +- lib/Target/MBlaze/MBlazeDelaySlotFiller.cpp | 191 +- lib/Target/MBlaze/MBlazeELFWriterInfo.cpp | 111 + lib/Target/MBlaze/MBlazeELFWriterInfo.h | 58 + lib/Target/MBlaze/MBlazeFrameLowering.cpp | 450 + lib/Target/MBlaze/MBlazeFrameLowering.h | 53 + lib/Target/MBlaze/MBlazeISelDAGToDAG.cpp | 87 +- lib/Target/MBlaze/MBlazeISelLowering.cpp | 720 +- lib/Target/MBlaze/MBlazeISelLowering.h | 46 +- lib/Target/MBlaze/MBlazeInstrFPU.td | 253 +- lib/Target/MBlaze/MBlazeInstrFSL.td | 326 +- lib/Target/MBlaze/MBlazeInstrFormats.td | 272 +- lib/Target/MBlaze/MBlazeInstrInfo.cpp | 179 +- lib/Target/MBlaze/MBlazeInstrInfo.h | 166 +- lib/Target/MBlaze/MBlazeInstrInfo.td | 927 +- lib/Target/MBlaze/MBlazeIntrinsicInfo.cpp | 6 +- lib/Target/MBlaze/MBlazeIntrinsics.td | 6 +- lib/Target/MBlaze/MBlazeMCAsmInfo.cpp | 9 +- lib/Target/MBlaze/MBlazeMCAsmInfo.h | 4 +- lib/Target/MBlaze/MBlazeMCCodeEmitter.cpp | 223 + lib/Target/MBlaze/MBlazeMCInstLower.cpp | 166 + lib/Target/MBlaze/MBlazeMCInstLower.h | 50 + lib/Target/MBlaze/MBlazeMachineFunction.h | 86 +- lib/Target/MBlaze/MBlazeRegisterInfo.cpp | 343 +- lib/Target/MBlaze/MBlazeRegisterInfo.h | 20 +- lib/Target/MBlaze/MBlazeRegisterInfo.td | 140 +- lib/Target/MBlaze/MBlazeRelocations.h | 47 + lib/Target/MBlaze/MBlazeSchedule.td | 4 +- lib/Target/MBlaze/MBlazeTargetMachine.cpp | 66 +- lib/Target/MBlaze/MBlazeTargetMachine.h | 33 +- lib/Target/MBlaze/MBlazeTargetObjectFile.cpp | 9 +- lib/Target/MBlaze/MBlazeTargetObjectFile.h | 7 +- lib/Target/MBlaze/Makefile | 12 +- lib/Target/MBlaze/TODO | 26 + lib/Target/MBlaze/TargetInfo/CMakeLists.txt | 3 +- lib/Target/MSP430/AsmPrinter/CMakeLists.txt | 8 - lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp | 179 - lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.cpp | 116 - lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.h | 43 - lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.cpp | 150 - lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.h | 50 - lib/Target/MSP430/AsmPrinter/Makefile | 15 - lib/Target/MSP430/CMakeLists.txt | 6 +- lib/Target/MSP430/InstPrinter/CMakeLists.txt | 6 + .../MSP430/InstPrinter/MSP430InstPrinter.cpp | 113 + lib/Target/MSP430/InstPrinter/MSP430InstPrinter.h | 43 + lib/Target/MSP430/InstPrinter/Makefile | 15 + lib/Target/MSP430/MSP430.td | 1 + lib/Target/MSP430/MSP430AsmPrinter.cpp | 179 + lib/Target/MSP430/MSP430FrameLowering.cpp | 223 + lib/Target/MSP430/MSP430FrameLowering.h | 53 + lib/Target/MSP430/MSP430ISelDAGToDAG.cpp | 17 +- lib/Target/MSP430/MSP430ISelLowering.cpp | 22 +- lib/Target/MSP430/MSP430InstrInfo.cpp | 52 +- lib/Target/MSP430/MSP430InstrInfo.h | 9 - lib/Target/MSP430/MSP430InstrInfo.td | 16 +- lib/Target/MSP430/MSP430MCInstLower.cpp | 150 + lib/Target/MSP430/MSP430MCInstLower.h | 50 + lib/Target/MSP430/MSP430RegisterInfo.cpp | 170 +- lib/Target/MSP430/MSP430RegisterInfo.h | 6 - lib/Target/MSP430/MSP430RegisterInfo.td | 8 +- lib/Target/MSP430/MSP430TargetMachine.cpp | 14 +- lib/Target/MSP430/MSP430TargetMachine.h | 12 +- lib/Target/MSP430/Makefile | 2 +- lib/Target/MSP430/TargetInfo/CMakeLists.txt | 2 +- lib/Target/Mangler.cpp | 10 - lib/Target/Mips/AsmPrinter/CMakeLists.txt | 9 - lib/Target/Mips/AsmPrinter/Makefile | 17 - lib/Target/Mips/AsmPrinter/MipsAsmPrinter.cpp | 386 - lib/Target/Mips/CMakeLists.txt | 4 +- lib/Target/Mips/Makefile | 2 +- lib/Target/Mips/Mips.td | 30 +- lib/Target/Mips/MipsAsmPrinter.cpp | 393 + lib/Target/Mips/MipsDelaySlotFiller.cpp | 13 +- lib/Target/Mips/MipsFrameLowering.cpp | 314 + lib/Target/Mips/MipsFrameLowering.h | 48 + lib/Target/Mips/MipsISelDAGToDAG.cpp | 28 +- lib/Target/Mips/MipsISelLowering.cpp | 620 +- lib/Target/Mips/MipsISelLowering.h | 18 +- lib/Target/Mips/MipsInstrFPU.td | 2 +- lib/Target/Mips/MipsInstrInfo.td | 355 +- lib/Target/Mips/MipsMachineFunction.h | 34 +- lib/Target/Mips/MipsRegisterInfo.cpp | 287 +- lib/Target/Mips/MipsRegisterInfo.h | 5 - lib/Target/Mips/MipsSchedule.td | 2 +- lib/Target/Mips/MipsSubtarget.h | 4 +- lib/Target/Mips/MipsTargetMachine.cpp | 20 +- lib/Target/Mips/MipsTargetMachine.h | 21 +- lib/Target/Mips/MipsTargetObjectFile.cpp | 29 +- lib/Target/PIC16/AsmPrinter/CMakeLists.txt | 9 - lib/Target/PIC16/AsmPrinter/Makefile | 15 - lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.cpp | 512 - lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.h | 88 - lib/Target/PIC16/CMakeLists.txt | 26 - lib/Target/PIC16/Makefile | 24 - lib/Target/PIC16/PIC16.h | 134 - lib/Target/PIC16/PIC16.td | 40 - lib/Target/PIC16/PIC16ABINames.h | 399 - lib/Target/PIC16/PIC16DebugInfo.cpp | 490 - lib/Target/PIC16/PIC16DebugInfo.h | 156 - lib/Target/PIC16/PIC16ISelDAGToDAG.cpp | 50 - lib/Target/PIC16/PIC16ISelDAGToDAG.h | 60 - lib/Target/PIC16/PIC16ISelLowering.cpp | 2000 -- lib/Target/PIC16/PIC16ISelLowering.h | 253 - lib/Target/PIC16/PIC16InstrFormats.td | 117 - lib/Target/PIC16/PIC16InstrInfo.cpp | 224 - lib/Target/PIC16/PIC16InstrInfo.h | 76 - lib/Target/PIC16/PIC16InstrInfo.td | 540 - lib/Target/PIC16/PIC16MCAsmInfo.cpp | 59 - lib/Target/PIC16/PIC16MCAsmInfo.h | 35 - lib/Target/PIC16/PIC16MachineFunctionInfo.h | 52 - lib/Target/PIC16/PIC16MemSelOpt.cpp | 254 - lib/Target/PIC16/PIC16Passes/Makefile | 15 - lib/Target/PIC16/PIC16Passes/PIC16Cloner.cpp | 299 - lib/Target/PIC16/PIC16Passes/PIC16Cloner.h | 83 - lib/Target/PIC16/PIC16Passes/PIC16Overlay.cpp | 182 - lib/Target/PIC16/PIC16Passes/PIC16Overlay.h | 60 - lib/Target/PIC16/PIC16RegisterInfo.cpp | 84 - lib/Target/PIC16/PIC16RegisterInfo.h | 64 - lib/Target/PIC16/PIC16RegisterInfo.td | 33 - lib/Target/PIC16/PIC16Section.cpp | 104 - lib/Target/PIC16/PIC16Section.h | 99 - lib/Target/PIC16/PIC16SelectionDAGInfo.cpp | 23 - lib/Target/PIC16/PIC16SelectionDAGInfo.h | 31 - lib/Target/PIC16/PIC16Subtarget.cpp | 27 - lib/Target/PIC16/PIC16Subtarget.h | 44 - lib/Target/PIC16/PIC16TargetMachine.cpp | 55 - lib/Target/PIC16/PIC16TargetMachine.h | 70 - lib/Target/PIC16/PIC16TargetObjectFile.cpp | 384 - lib/Target/PIC16/PIC16TargetObjectFile.h | 168 - lib/Target/PIC16/TargetInfo/CMakeLists.txt | 7 - lib/Target/PIC16/TargetInfo/Makefile | 15 - lib/Target/PIC16/TargetInfo/PIC16TargetInfo.cpp | 22 - lib/Target/PTX/CMakeLists.txt | 26 + lib/Target/PTX/Makefile | 26 + lib/Target/PTX/PTX.h | 49 + lib/Target/PTX/PTX.td | 54 + lib/Target/PTX/PTXAsmPrinter.cpp | 347 + lib/Target/PTX/PTXFrameLowering.cpp | 24 + lib/Target/PTX/PTXFrameLowering.h | 43 + lib/Target/PTX/PTXISelDAGToDAG.cpp | 151 + lib/Target/PTX/PTXISelLowering.cpp | 210 + lib/Target/PTX/PTXISelLowering.h | 67 + lib/Target/PTX/PTXInstrFormats.td | 24 + lib/Target/PTX/PTXInstrInfo.cpp | 87 + lib/Target/PTX/PTXInstrInfo.h | 75 + lib/Target/PTX/PTXInstrInfo.td | 257 + lib/Target/PTX/PTXMCAsmInfo.cpp | 30 + lib/Target/PTX/PTXMCAsmInfo.h | 28 + lib/Target/PTX/PTXMCAsmStreamer.cpp | 542 + lib/Target/PTX/PTXMFInfoExtract.cpp | 96 + lib/Target/PTX/PTXMachineFunctionInfo.h | 79 + lib/Target/PTX/PTXRegisterInfo.cpp | 19 + lib/Target/PTX/PTXRegisterInfo.h | 63 + lib/Target/PTX/PTXRegisterInfo.td | 102 + lib/Target/PTX/PTXSubtarget.cpp | 23 + lib/Target/PTX/PTXSubtarget.h | 32 + lib/Target/PTX/PTXTargetMachine.cpp | 60 + lib/Target/PTX/PTXTargetMachine.h | 60 + lib/Target/PTX/TargetInfo/CMakeLists.txt | 7 + lib/Target/PTX/TargetInfo/Makefile | 15 + lib/Target/PTX/TargetInfo/PTXTargetInfo.cpp | 21 + lib/Target/PowerPC/AsmPrinter/CMakeLists.txt | 6 - lib/Target/PowerPC/AsmPrinter/Makefile | 15 - lib/Target/PowerPC/AsmPrinter/PPCAsmPrinter.cpp | 922 - lib/Target/PowerPC/CMakeLists.txt | 9 +- lib/Target/PowerPC/InstPrinter/CMakeLists.txt | 6 + lib/Target/PowerPC/InstPrinter/Makefile | 16 + lib/Target/PowerPC/InstPrinter/PPCInstPrinter.cpp | 292 + lib/Target/PowerPC/InstPrinter/PPCInstPrinter.h | 69 + lib/Target/PowerPC/Makefile | 5 +- lib/Target/PowerPC/PPC.h | 62 +- lib/Target/PowerPC/PPC.td | 6 + lib/Target/PowerPC/PPCAsmBackend.cpp | 119 + lib/Target/PowerPC/PPCAsmPrinter.cpp | 696 + lib/Target/PowerPC/PPCCodeEmitter.cpp | 253 +- lib/Target/PowerPC/PPCFixupKinds.h | 45 + lib/Target/PowerPC/PPCFrameInfo.h | 300 - lib/Target/PowerPC/PPCFrameLowering.cpp | 971 + lib/Target/PowerPC/PPCFrameLowering.h | 322 + lib/Target/PowerPC/PPCHazardRecognizers.cpp | 56 +- lib/Target/PowerPC/PPCHazardRecognizers.h | 20 +- lib/Target/PowerPC/PPCISelDAGToDAG.cpp | 210 +- lib/Target/PowerPC/PPCISelLowering.cpp | 731 +- lib/Target/PowerPC/PPCISelLowering.h | 7 +- lib/Target/PowerPC/PPCInstr64Bit.td | 57 +- lib/Target/PowerPC/PPCInstrFormats.td | 39 +- lib/Target/PowerPC/PPCInstrInfo.cpp | 81 +- lib/Target/PowerPC/PPCInstrInfo.h | 26 +- lib/Target/PowerPC/PPCInstrInfo.td | 177 +- lib/Target/PowerPC/PPCJITInfo.cpp | 2 +- lib/Target/PowerPC/PPCMCAsmInfo.cpp | 5 +- lib/Target/PowerPC/PPCMCCodeEmitter.cpp | 195 + lib/Target/PowerPC/PPCMCInstLower.cpp | 172 + lib/Target/PowerPC/PPCRegisterInfo.cpp | 975 +- lib/Target/PowerPC/PPCRegisterInfo.h | 19 - lib/Target/PowerPC/PPCRegisterInfo.td | 13 +- lib/Target/PowerPC/PPCScheduleG3.td | 2 +- lib/Target/PowerPC/PPCScheduleG4.td | 2 +- lib/Target/PowerPC/PPCScheduleG4Plus.td | 2 +- lib/Target/PowerPC/PPCScheduleG5.td | 2 +- lib/Target/PowerPC/PPCSubtarget.cpp | 2 +- lib/Target/PowerPC/PPCTargetMachine.cpp | 31 +- lib/Target/PowerPC/PPCTargetMachine.h | 18 +- lib/Target/PowerPC/README.txt | 29 +- lib/Target/README.txt | 979 +- lib/Target/Sparc/AsmPrinter/CMakeLists.txt | 6 - lib/Target/Sparc/AsmPrinter/Makefile | 15 - lib/Target/Sparc/AsmPrinter/SparcAsmPrinter.cpp | 249 - lib/Target/Sparc/CMakeLists.txt | 4 +- lib/Target/Sparc/DelaySlotFiller.cpp | 230 +- lib/Target/Sparc/Makefile | 2 +- lib/Target/Sparc/SparcAsmPrinter.cpp | 251 + lib/Target/Sparc/SparcCallingConv.td | 10 +- lib/Target/Sparc/SparcFrameLowering.cpp | 80 + lib/Target/Sparc/SparcFrameLowering.h | 41 + lib/Target/Sparc/SparcISelDAGToDAG.cpp | 18 +- lib/Target/Sparc/SparcISelLowering.cpp | 721 +- lib/Target/Sparc/SparcISelLowering.h | 3 +- lib/Target/Sparc/SparcInstrInfo.cpp | 195 +- lib/Target/Sparc/SparcInstrInfo.h | 11 +- lib/Target/Sparc/SparcInstrInfo.td | 221 +- lib/Target/Sparc/SparcMachineFunctionInfo.h | 11 +- lib/Target/Sparc/SparcRegisterInfo.cpp | 53 - lib/Target/Sparc/SparcRegisterInfo.h | 9 +- lib/Target/Sparc/SparcRegisterInfo.td | 3 + lib/Target/Sparc/SparcTargetMachine.cpp | 6 +- lib/Target/Sparc/SparcTargetMachine.h | 15 +- lib/Target/SubtargetFeature.cpp | 3 +- lib/Target/SystemZ/AsmPrinter/CMakeLists.txt | 6 - lib/Target/SystemZ/AsmPrinter/Makefile | 15 - .../SystemZ/AsmPrinter/SystemZAsmPrinter.cpp | 217 - lib/Target/SystemZ/CMakeLists.txt | 4 +- lib/Target/SystemZ/Makefile | 2 +- lib/Target/SystemZ/SystemZAsmPrinter.cpp | 223 + lib/Target/SystemZ/SystemZFrameLowering.cpp | 386 + lib/Target/SystemZ/SystemZFrameLowering.h | 57 + lib/Target/SystemZ/SystemZISelDAGToDAG.cpp | 31 +- lib/Target/SystemZ/SystemZISelLowering.cpp | 18 +- lib/Target/SystemZ/SystemZInstrBuilder.h | 6 +- lib/Target/SystemZ/SystemZInstrInfo.cpp | 150 - lib/Target/SystemZ/SystemZInstrInfo.h | 10 - lib/Target/SystemZ/SystemZInstrInfo.td | 56 +- lib/Target/SystemZ/SystemZMCAsmInfo.cpp | 5 +- lib/Target/SystemZ/SystemZOperands.td | 15 + lib/Target/SystemZ/SystemZRegisterInfo.cpp | 214 +- lib/Target/SystemZ/SystemZRegisterInfo.h | 12 - lib/Target/SystemZ/SystemZRegisterInfo.td | 48 +- lib/Target/SystemZ/SystemZTargetMachine.cpp | 2 +- lib/Target/SystemZ/SystemZTargetMachine.h | 12 +- lib/Target/Target.cpp | 15 +- lib/Target/TargetAsmInfo.cpp | 27 + lib/Target/TargetData.cpp | 58 +- lib/Target/TargetELFWriterInfo.cpp | 5 +- lib/Target/TargetFrameInfo.cpp | 19 - lib/Target/TargetFrameLowering.cpp | 53 + lib/Target/TargetInstrInfo.cpp | 93 +- lib/Target/TargetLibraryInfo.cpp | 55 + lib/Target/TargetLoweringObjectFile.cpp | 8 +- lib/Target/TargetMachine.cpp | 4 +- lib/Target/TargetRegisterInfo.cpp | 43 +- lib/Target/X86/AsmParser/X86AsmLexer.cpp | 9 +- lib/Target/X86/AsmParser/X86AsmParser.cpp | 437 +- lib/Target/X86/AsmPrinter/CMakeLists.txt | 8 - lib/Target/X86/AsmPrinter/Makefile | 15 - lib/Target/X86/AsmPrinter/X86ATTInstPrinter.cpp | 129 - lib/Target/X86/AsmPrinter/X86ATTInstPrinter.h | 81 - lib/Target/X86/AsmPrinter/X86InstComments.cpp | 232 - lib/Target/X86/AsmPrinter/X86InstComments.h | 25 - lib/Target/X86/AsmPrinter/X86IntelInstPrinter.cpp | 140 - lib/Target/X86/AsmPrinter/X86IntelInstPrinter.h | 95 - lib/Target/X86/CMakeLists.txt | 14 +- lib/Target/X86/Disassembler/CMakeLists.txt | 2 +- lib/Target/X86/Disassembler/X86Disassembler.cpp | 15 +- lib/Target/X86/Disassembler/X86Disassembler.h | 2 +- .../X86/Disassembler/X86DisassemblerDecoder.c | 31 +- .../X86/Disassembler/X86DisassemblerDecoder.h | 4 +- .../Disassembler/X86DisassemblerDecoderCommon.h | 3 +- lib/Target/X86/InstPrinter/CMakeLists.txt | 8 + lib/Target/X86/InstPrinter/Makefile | 15 + lib/Target/X86/InstPrinter/X86ATTInstPrinter.cpp | 127 + lib/Target/X86/InstPrinter/X86ATTInstPrinter.h | 81 + lib/Target/X86/InstPrinter/X86InstComments.cpp | 232 + lib/Target/X86/InstPrinter/X86InstComments.h | 25 + lib/Target/X86/InstPrinter/X86IntelInstPrinter.cpp | 139 + lib/Target/X86/InstPrinter/X86IntelInstPrinter.h | 95 + lib/Target/X86/Makefile | 2 +- lib/Target/X86/README-SSE.txt | 50 +- lib/Target/X86/README-X86-64.txt | 44 - lib/Target/X86/README.txt | 335 +- lib/Target/X86/Utils/CMakeLists.txt | 6 + lib/Target/X86/Utils/Makefile | 15 + lib/Target/X86/Utils/X86ShuffleDecode.cpp | 148 + lib/Target/X86/Utils/X86ShuffleDecode.h | 69 + lib/Target/X86/X86.h | 10 + lib/Target/X86/X86.td | 28 +- lib/Target/X86/X86AsmBackend.cpp | 270 +- lib/Target/X86/X86AsmPrinter.cpp | 97 +- lib/Target/X86/X86AsmPrinter.h | 2 - lib/Target/X86/X86CallingConv.td | 67 +- lib/Target/X86/X86CodeEmitter.cpp | 21 +- lib/Target/X86/X86ELFWriterInfo.cpp | 55 +- lib/Target/X86/X86ELFWriterInfo.h | 19 +- lib/Target/X86/X86FastISel.cpp | 300 +- lib/Target/X86/X86FixupKinds.h | 16 +- lib/Target/X86/X86FloatingPoint.cpp | 129 +- lib/Target/X86/X86FrameLowering.cpp | 994 + lib/Target/X86/X86FrameLowering.h | 65 + lib/Target/X86/X86ISelDAGToDAG.cpp | 200 +- lib/Target/X86/X86ISelLowering.cpp | 3194 ++- lib/Target/X86/X86ISelLowering.h | 243 +- lib/Target/X86/X86Instr3DNow.td | 77 + lib/Target/X86/X86Instr64bit.td | 2250 --- lib/Target/X86/X86InstrArithmetic.td | 1125 ++ lib/Target/X86/X86InstrBuilder.h | 37 +- lib/Target/X86/X86InstrCMovSetCC.td | 104 + lib/Target/X86/X86InstrCompiler.td | 1626 ++ lib/Target/X86/X86InstrControl.td | 294 + lib/Target/X86/X86InstrExtension.td | 172 + lib/Target/X86/X86InstrFPStack.td | 82 +- lib/Target/X86/X86InstrFormats.td | 24 +- lib/Target/X86/X86InstrFragmentsSIMD.td | 107 +- lib/Target/X86/X86InstrInfo.cpp | 448 +- lib/Target/X86/X86InstrInfo.h | 84 +- lib/Target/X86/X86InstrInfo.td | 4842 +---- lib/Target/X86/X86InstrMMX.td | 607 +- lib/Target/X86/X86InstrSSE.td | 571 +- lib/Target/X86/X86InstrShiftRotate.td | 746 + lib/Target/X86/X86InstrSystem.td | 390 + lib/Target/X86/X86InstrVMX.td | 54 + lib/Target/X86/X86JITInfo.cpp | 16 +- lib/Target/X86/X86MCAsmInfo.cpp | 15 +- lib/Target/X86/X86MCCodeEmitter.cpp | 149 +- lib/Target/X86/X86MCInstLower.cpp | 117 +- lib/Target/X86/X86MCInstLower.h | 2 - lib/Target/X86/X86MachObjectWriter.cpp | 32 + lib/Target/X86/X86RegisterInfo.cpp | 955 +- lib/Target/X86/X86RegisterInfo.h | 17 +- lib/Target/X86/X86RegisterInfo.td | 100 +- lib/Target/X86/X86SelectionDAGInfo.cpp | 52 +- lib/Target/X86/X86SelectionDAGInfo.h | 9 +- lib/Target/X86/X86ShuffleDecode.h | 155 - lib/Target/X86/X86Subtarget.cpp | 18 +- lib/Target/X86/X86Subtarget.h | 36 +- lib/Target/X86/X86TargetMachine.cpp | 55 +- lib/Target/X86/X86TargetMachine.h | 75 +- lib/Target/XCore/AsmPrinter/CMakeLists.txt | 6 - lib/Target/XCore/AsmPrinter/Makefile | 16 - lib/Target/XCore/AsmPrinter/XCoreAsmPrinter.cpp | 280 - lib/Target/XCore/CMakeLists.txt | 5 +- lib/Target/XCore/Makefile | 2 +- lib/Target/XCore/TargetInfo/CMakeLists.txt | 2 +- lib/Target/XCore/XCoreAsmPrinter.cpp | 280 + lib/Target/XCore/XCoreCallingConv.td | 3 + lib/Target/XCore/XCoreFrameInfo.cpp | 27 - lib/Target/XCore/XCoreFrameInfo.h | 34 - lib/Target/XCore/XCoreFrameLowering.cpp | 387 + lib/Target/XCore/XCoreFrameLowering.h | 59 + lib/Target/XCore/XCoreISelDAGToDAG.cpp | 21 +- lib/Target/XCore/XCoreISelLowering.cpp | 172 +- lib/Target/XCore/XCoreISelLowering.h | 1 + lib/Target/XCore/XCoreInstrInfo.cpp | 66 +- lib/Target/XCore/XCoreInstrInfo.h | 9 - lib/Target/XCore/XCoreInstrInfo.td | 76 +- lib/Target/XCore/XCoreRegisterInfo.cpp | 284 +- lib/Target/XCore/XCoreRegisterInfo.h | 11 - lib/Target/XCore/XCoreRegisterInfo.td | 4 +- lib/Target/XCore/XCoreTargetMachine.cpp | 2 +- lib/Target/XCore/XCoreTargetMachine.h | 8 +- lib/Target/XCore/XCoreTargetObjectFile.cpp | 49 +- lib/Transforms/CMakeLists.txt | 6 + lib/Transforms/Hello/Hello.cpp | 7 +- lib/Transforms/IPO/ArgumentPromotion.cpp | 117 +- lib/Transforms/IPO/CMakeLists.txt | 3 - lib/Transforms/IPO/ConstantMerge.cpp | 86 +- lib/Transforms/IPO/DeadArgumentElimination.cpp | 76 +- lib/Transforms/IPO/DeadTypeElimination.cpp | 9 +- lib/Transforms/IPO/ExtractGV.cpp | 30 +- lib/Transforms/IPO/FunctionAttrs.cpp | 141 +- lib/Transforms/IPO/GlobalDCE.cpp | 6 +- lib/Transforms/IPO/GlobalOpt.cpp | 830 +- lib/Transforms/IPO/IPConstantPropagation.cpp | 6 +- lib/Transforms/IPO/IPO.cpp | 38 +- lib/Transforms/IPO/InlineAlways.cpp | 11 +- lib/Transforms/IPO/InlineSimple.cpp | 15 +- lib/Transforms/IPO/Inliner.cpp | 56 +- lib/Transforms/IPO/Internalize.cpp | 4 +- lib/Transforms/IPO/LoopExtractor.cpp | 17 +- lib/Transforms/IPO/LowerSetJmp.cpp | 6 +- lib/Transforms/IPO/MergeFunctions.cpp | 646 +- lib/Transforms/IPO/PartialInlining.cpp | 8 +- lib/Transforms/IPO/PartialSpecialization.cpp | 216 - lib/Transforms/IPO/PruneEH.cpp | 11 +- lib/Transforms/IPO/StripDeadPrototypes.cpp | 6 +- lib/Transforms/IPO/StripSymbols.cpp | 24 +- lib/Transforms/IPO/StructRetPromotion.cpp | 11 +- lib/Transforms/InstCombine/CMakeLists.txt | 2 - lib/Transforms/InstCombine/InstCombine.h | 28 +- lib/Transforms/InstCombine/InstCombineAddSub.cpp | 350 +- lib/Transforms/InstCombine/InstCombineAndOrXor.cpp | 597 +- lib/Transforms/InstCombine/InstCombineCalls.cpp | 288 +- lib/Transforms/InstCombine/InstCombineCasts.cpp | 35 +- lib/Transforms/InstCombine/InstCombineCompares.cpp | 772 +- .../InstCombine/InstCombineLoadStoreAlloca.cpp | 11 +- .../InstCombine/InstCombineMulDivRem.cpp | 315 +- lib/Transforms/InstCombine/InstCombinePHI.cpp | 79 +- lib/Transforms/InstCombine/InstCombineSelect.cpp | 294 +- lib/Transforms/InstCombine/InstCombineShifts.cpp | 116 +- .../InstCombine/InstCombineSimplifyDemanded.cpp | 100 +- .../InstCombine/InstCombineVectorOps.cpp | 272 +- .../InstCombine/InstructionCombining.cpp | 604 +- lib/Transforms/Instrumentation/CMakeLists.txt | 2 + lib/Transforms/Instrumentation/EdgeProfiling.cpp | 9 +- lib/Transforms/Instrumentation/Instrumentation.cpp | 32 + .../Instrumentation/OptimalEdgeProfiling.cpp | 17 +- lib/Transforms/Instrumentation/PathProfiling.cpp | 1423 ++ lib/Transforms/Instrumentation/ProfilingUtils.cpp | 22 +- lib/Transforms/Instrumentation/ProfilingUtils.h | 7 +- lib/Transforms/Scalar/ADCE.cpp | 6 +- lib/Transforms/Scalar/BasicBlockPlacement.cpp | 11 +- lib/Transforms/Scalar/CMakeLists.txt | 6 +- lib/Transforms/Scalar/CodeGenPrepare.cpp | 369 +- lib/Transforms/Scalar/ConstantProp.cpp | 6 +- .../Scalar/CorrelatedValuePropagation.cpp | 86 +- lib/Transforms/Scalar/DCE.cpp | 12 +- lib/Transforms/Scalar/DeadStoreElimination.cpp | 847 +- lib/Transforms/Scalar/EarlyCSE.cpp | 470 + lib/Transforms/Scalar/GEPSplitter.cpp | 6 +- lib/Transforms/Scalar/GVN.cpp | 813 +- lib/Transforms/Scalar/IndVarSimplify.cpp | 49 +- lib/Transforms/Scalar/JumpThreading.cpp | 998 +- lib/Transforms/Scalar/LICM.cpp | 324 +- lib/Transforms/Scalar/LoopDeletion.cpp | 26 +- lib/Transforms/Scalar/LoopIdiomRecognize.cpp | 594 + lib/Transforms/Scalar/LoopIndexSplit.cpp | 1270 -- lib/Transforms/Scalar/LoopInstSimplify.cpp | 170 + lib/Transforms/Scalar/LoopRotation.cpp | 491 +- lib/Transforms/Scalar/LoopStrengthReduce.cpp | 200 +- lib/Transforms/Scalar/LoopUnrollPass.cpp | 57 +- lib/Transforms/Scalar/LoopUnswitch.cpp | 60 +- lib/Transforms/Scalar/LowerAtomic.cpp | 146 +- lib/Transforms/Scalar/MemCpyOptimizer.cpp | 729 +- lib/Transforms/Scalar/Reassociate.cpp | 38 +- lib/Transforms/Scalar/Reg2Mem.cpp | 12 +- lib/Transforms/Scalar/SCCP.cpp | 39 +- lib/Transforms/Scalar/Scalar.cpp | 55 +- lib/Transforms/Scalar/ScalarReplAggregates.cpp | 1155 +- lib/Transforms/Scalar/SimplifyCFGPass.cpp | 6 +- lib/Transforms/Scalar/SimplifyHalfPowrLibCalls.cpp | 9 +- lib/Transforms/Scalar/SimplifyLibCalls.cpp | 342 +- lib/Transforms/Scalar/Sink.cpp | 20 +- lib/Transforms/Scalar/TailDuplication.cpp | 18 +- lib/Transforms/Scalar/TailRecursionElimination.cpp | 139 +- lib/Transforms/Utils/AddrModeMatcher.cpp | 28 +- lib/Transforms/Utils/BasicBlockUtils.cpp | 157 +- lib/Transforms/Utils/BreakCriticalEdges.cpp | 56 +- lib/Transforms/Utils/BuildLibCalls.cpp | 54 +- lib/Transforms/Utils/CMakeLists.txt | 3 +- lib/Transforms/Utils/CloneFunction.cpp | 40 +- lib/Transforms/Utils/CloneLoop.cpp | 45 +- lib/Transforms/Utils/CloneModule.cpp | 8 +- lib/Transforms/Utils/CodeExtractor.cpp | 4 +- lib/Transforms/Utils/DemoteRegToStack.cpp | 2 +- lib/Transforms/Utils/InlineFunction.cpp | 173 +- lib/Transforms/Utils/InstructionNamer.cpp | 9 +- lib/Transforms/Utils/LCSSA.cpp | 12 +- lib/Transforms/Utils/Local.cpp | 148 +- lib/Transforms/Utils/LoopSimplify.cpp | 69 +- lib/Transforms/Utils/LoopUnroll.cpp | 38 +- lib/Transforms/Utils/LowerInvoke.cpp | 27 +- lib/Transforms/Utils/LowerSwitch.cpp | 9 +- lib/Transforms/Utils/Mem2Reg.cpp | 17 +- lib/Transforms/Utils/PromoteMemoryToRegister.cpp | 209 +- lib/Transforms/Utils/SSAUpdater.cpp | 171 +- lib/Transforms/Utils/SimplifyCFG.cpp | 2003 +- lib/Transforms/Utils/SimplifyInstructions.cpp | 94 + lib/Transforms/Utils/UnifyFunctionExitNodes.cpp | 2 +- lib/Transforms/Utils/Utils.cpp | 37 + lib/Transforms/Utils/ValueMapper.cpp | 178 +- lib/VMCore/AsmWriter.cpp | 40 +- lib/VMCore/Attributes.cpp | 33 +- lib/VMCore/AutoUpgrade.cpp | 569 +- lib/VMCore/BasicBlock.cpp | 9 +- lib/VMCore/CMakeLists.txt | 3 + lib/VMCore/ConstantFold.cpp | 159 +- lib/VMCore/ConstantFold.h | 2 + lib/VMCore/Constants.cpp | 382 +- lib/VMCore/ConstantsContext.h | 30 +- lib/VMCore/Core.cpp | 234 +- lib/VMCore/Dominators.cpp | 275 +- lib/VMCore/Function.cpp | 21 +- lib/VMCore/Globals.cpp | 49 - lib/VMCore/IRBuilder.cpp | 81 + lib/VMCore/InlineAsm.cpp | 79 +- lib/VMCore/Instruction.cpp | 36 +- lib/VMCore/Instructions.cpp | 212 +- lib/VMCore/LLVMContext.cpp | 42 +- lib/VMCore/LLVMContextImpl.cpp | 13 +- lib/VMCore/LLVMContextImpl.h | 8 +- lib/VMCore/LeakDetector.cpp | 4 +- lib/VMCore/Metadata.cpp | 13 +- lib/VMCore/Module.cpp | 2 + lib/VMCore/Pass.cpp | 1 - lib/VMCore/PassManager.cpp | 128 +- lib/VMCore/PassRegistry.cpp | 173 +- lib/VMCore/PrintModulePass.cpp | 4 +- lib/VMCore/Type.cpp | 30 +- lib/VMCore/TypesContext.h | 2 +- lib/VMCore/Use.cpp | 122 +- lib/VMCore/User.cpp | 81 + lib/VMCore/Value.cpp | 97 +- lib/VMCore/ValueTypes.cpp | 5 +- lib/VMCore/Verifier.cpp | 32 +- projects/Makefile | 5 +- projects/sample/autoconf/AutoRegen.sh | 8 +- projects/sample/autoconf/configure.ac | 10 +- projects/sample/configure | 2371 ++- projects/sample/lib/sample/sample.c | 2 +- runtime/libprofile/CommonProfiling.c | 53 +- runtime/libprofile/PathProfiling.c | 266 + runtime/libprofile/Profiling.h | 11 +- runtime/libprofile/libprofile.exports | 3 + test/Analysis/BasicAA/2003-02-26-AccessSizeTest.ll | 2 +- test/Analysis/BasicAA/2003-04-22-GEPProblem.ll | 2 +- test/Analysis/BasicAA/2003-05-21-GEP-Problem.ll | 2 +- test/Analysis/BasicAA/2003-09-19-LocalArgument.ll | 2 +- test/Analysis/BasicAA/2003-11-04-SimpleCases.ll | 2 +- test/Analysis/BasicAA/2003-12-11-ConstExprGEP.ll | 2 +- test/Analysis/BasicAA/2004-07-28-MustAliasbug.ll | 2 +- test/Analysis/BasicAA/2004-12-08-BasicAACrash.ll | 2 +- test/Analysis/BasicAA/2004-12-08-BasicAACrash2.ll | 2 +- .../BasicAA/2006-03-03-BadArraySubscript.ll | 2 +- .../BasicAA/2006-11-03-BasicAAVectorCrash.ll | 2 +- test/Analysis/BasicAA/2007-11-05-SizeCrash.ll | 2 +- .../BasicAA/2007-12-08-OutOfBoundsCrash.ll | 2 +- test/Analysis/BasicAA/2008-06-02-GEPTailCrash.ll | 2 +- test/Analysis/BasicAA/2008-11-23-NoaliasRet.ll | 2 +- test/Analysis/BasicAA/2009-10-13-AtomicModRef.ll | 2 +- .../Analysis/BasicAA/2009-10-13-GEP-BaseNoAlias.ll | 4 +- .../BasicAA/2010-09-15-GEP-SignedArithmetic.ll | 15 + test/Analysis/BasicAA/args-rets-allocas-loads.ll | 2 +- test/Analysis/BasicAA/byval.ll | 2 +- test/Analysis/BasicAA/constant-over-index.ll | 2 +- test/Analysis/BasicAA/empty.ll | 2 +- test/Analysis/BasicAA/full-store-partial-alias.ll | 33 + test/Analysis/BasicAA/gep-alias.ll | 2 +- test/Analysis/BasicAA/getmodrefinfo-cs-cs.ll | 2 +- test/Analysis/BasicAA/global-size.ll | 36 +- test/Analysis/BasicAA/modref.ll | 10 +- test/Analysis/BasicAA/phi-aa.ll | 2 +- test/Analysis/BasicAA/phi-and-select.ll | 2 +- test/Analysis/BasicAA/unreachable-block.ll | 2 +- test/Analysis/GlobalsModRef/aliastest.ll | 2 +- test/Analysis/GlobalsModRef/chaining-analysis.ll | 2 +- test/Analysis/GlobalsModRef/indirect-global.ll | 2 +- test/Analysis/GlobalsModRef/modreftest.ll | 2 +- test/Analysis/LoopDependenceAnalysis/alias.ll | 2 +- test/Analysis/LoopDependenceAnalysis/siv-strong.ll | 2 +- .../LoopDependenceAnalysis/siv-weak-crossing.ll | 2 +- .../LoopDependenceAnalysis/siv-weak-zero.ll | 2 +- test/Analysis/LoopDependenceAnalysis/ziv.ll | 2 +- test/Analysis/PointerTracking/dg.exp | 3 - test/Analysis/PointerTracking/sizes.ll | 86 - test/Analysis/Profiling/profiling-tool-chain.ll | 4 +- .../2010-09-03-RequiredTransitive.ll | 24 + test/Analysis/ScalarEvolution/fold.ll | 62 + test/Analysis/ScalarEvolution/nsw.ll | 70 +- test/Analysis/ScalarEvolution/scev-aa.ll | 7 +- test/Analysis/TypeBasedAliasAnalysis/aliastest.ll | 62 + .../TypeBasedAliasAnalysis/argument-promotion.ll | 31 + test/Analysis/TypeBasedAliasAnalysis/dg.exp | 3 + test/Analysis/TypeBasedAliasAnalysis/dse.ll | 66 + .../TypeBasedAliasAnalysis/functionattrs.ll | 81 + .../gvn-nonlocal-type-mismatch.ll | 91 + test/Analysis/TypeBasedAliasAnalysis/licm.ll | 61 + test/Analysis/TypeBasedAliasAnalysis/memcpyopt.ll | 23 + test/Analysis/TypeBasedAliasAnalysis/precedence.ll | 46 + test/Analysis/TypeBasedAliasAnalysis/sink.ll | 20 + test/Archive/GNU.toc | 4 - test/Archive/MacOSX.toc | 5 - test/Archive/SVR4.toc | 4 - test/Archive/extract.ll | 8 +- test/Archive/toc_GNU.ll | 7 +- test/Archive/toc_MacOSX.ll | 8 +- test/Archive/toc_SVR4.ll | 7 +- test/Archive/toc_xpg4.ll | 7 +- test/Archive/xpg4.toc | 4 - test/Assembler/2003-05-21-MalformedShiftCrash.ll | 2 +- test/Assembler/AutoUpgradeIntrinsics.ll | 2 +- test/Assembler/AutoUpgradeMMXIntrinsics.ll | 223 + test/Assembler/extractvalue-invalid-idx.ll | 8 + test/Assembler/flags.ll | 64 + test/Assembler/insertvalue-invalid-idx.ll | 7 + test/Assembler/unnamed-addr.ll | 18 + test/Assembler/x86mmx.ll | 8 + test/Bindings/Ocaml/analysis.ml | 1 + test/Bindings/Ocaml/bitreader.ml | 1 + test/Bindings/Ocaml/bitwriter.ml | 1 + test/Bindings/Ocaml/executionengine.ml | 1 + test/Bindings/Ocaml/ext_exc.ml | 17 + test/Bindings/Ocaml/scalar_opts.ml | 4 +- test/Bindings/Ocaml/target.ml | 1 + test/Bindings/Ocaml/vmcore.ml | 1 + test/Bitcode/null-type.ll | 2 + test/Bitcode/null-type.ll.bc | Bin 0 -> 312 bytes test/Bitcode/ssse3_palignr.ll.bc | Bin 1280 -> 1504 bytes test/BugPoint/crash-narrowfunctiontest.ll | 5 +- test/BugPoint/metadata.ll | 4 +- test/BugPoint/remove_arguments_test.ll | 5 +- test/CMakeLists.txt | 57 +- test/CodeGen/ARM/2007-01-19-InfiniteLoop.ll | 5 +- test/CodeGen/ARM/2009-08-21-PostRAKill4.ll | 26 - test/CodeGen/ARM/2009-09-01-PostRAProlog.ll | 106 - test/CodeGen/ARM/2009-09-28-LdStOptiBug.ll | 2 +- test/CodeGen/ARM/2009-11-02-NegativeLane.ll | 3 +- test/CodeGen/ARM/2010-03-18-ldm-rtrn.ll | 4 +- .../CodeGen/ARM/2010-04-07-DbgValueOtherTargets.ll | 43 +- test/CodeGen/ARM/2010-05-17-DAGCombineAssert.ll | 17 - test/CodeGen/ARM/2010-06-28-DAGCombineUndef.ll | 10 - .../ARM/2010-06-29-PartialRedefFastAlloc.ll | 6 +- test/CodeGen/ARM/2010-09-21-OptCmpBug.ll | 84 + test/CodeGen/ARM/2010-09-29-mc-asm-header-test.ll | 13 + test/CodeGen/ARM/2010-10-19-mc-elf-objheader.ll | 37 + test/CodeGen/ARM/2010-10-25-ifcvt-ldm.ll | 31 + test/CodeGen/ARM/2010-11-15-SpillEarlyClobber.ll | 85 + test/CodeGen/ARM/2010-11-29-PrologueBug.ll | 28 + test/CodeGen/ARM/2010-11-30-reloc-movt.ll | 42 + test/CodeGen/ARM/2010-12-07-PEIBug.ll | 40 + test/CodeGen/ARM/2010-12-08-tpsoft.ll | 52 + test/CodeGen/ARM/2010-12-13-reloc-pic.ll | 100 + test/CodeGen/ARM/2010-12-15-elf-lcomm.ll | 35 + test/CodeGen/ARM/2010-12-17-LocalStackSlotCrash.ll | 15 + test/CodeGen/ARM/2011-01-19-MergedGlobalDbg.ll | 127 + test/CodeGen/ARM/2011-02-04-AntidepMultidef.ll | 128 + test/CodeGen/ARM/2011-02-07-AntidepClobber.ll | 89 + test/CodeGen/ARM/align.ll | 4 +- test/CodeGen/ARM/arguments.ll | 4 +- test/CodeGen/ARM/arm-and-tst-peephole.ll | 112 + test/CodeGen/ARM/atomic-cmp.ll | 17 + test/CodeGen/ARM/bfi.ll | 32 +- test/CodeGen/ARM/bits.ll | 17 +- test/CodeGen/ARM/bswap-inline-asm.ll | 9 + test/CodeGen/ARM/bx_fold.ll | 5 +- test/CodeGen/ARM/call-tc.ll | 96 +- test/CodeGen/ARM/clz.ll | 6 +- test/CodeGen/ARM/code-placement.ll | 54 +- test/CodeGen/ARM/constants.ll | 13 +- test/CodeGen/ARM/crash.ll | 29 + test/CodeGen/ARM/div.ll | 2 +- test/CodeGen/ARM/fabss.ll | 2 +- test/CodeGen/ARM/fadds.ll | 2 +- test/CodeGen/ARM/fast-isel-crash.ll | 21 + test/CodeGen/ARM/fast-isel-static.ll | 30 + test/CodeGen/ARM/fast-isel.ll | 31 +- test/CodeGen/ARM/fcopysign.ll | 53 +- test/CodeGen/ARM/fdivs.ll | 2 +- test/CodeGen/ARM/fmacs.ll | 55 +- test/CodeGen/ARM/fmscs.ll | 39 +- test/CodeGen/ARM/fmuls.ll | 2 +- test/CodeGen/ARM/fnegs.ll | 20 +- test/CodeGen/ARM/fnmacs.ll | 31 +- test/CodeGen/ARM/fnmscs.ll | 64 +- test/CodeGen/ARM/fp.ll | 2 +- test/CodeGen/ARM/fpcmp-opt.ll | 1 + test/CodeGen/ARM/fpcmp_ueq.ll | 10 +- test/CodeGen/ARM/fpconsts.ll | 8 +- test/CodeGen/ARM/fpconv.ll | 2 +- test/CodeGen/ARM/global-merge.ll | 23 + test/CodeGen/ARM/hello.ll | 2 +- test/CodeGen/ARM/ifcvt10.ll | 43 + test/CodeGen/ARM/ifcvt11.ll | 59 + test/CodeGen/ARM/ifcvt6.ll | 7 +- test/CodeGen/ARM/ifcvt7.ll | 10 +- test/CodeGen/ARM/ifcvt8.ll | 4 +- test/CodeGen/ARM/inlineasm3.ll | 4 +- test/CodeGen/ARM/ispositive.ll | 2 +- test/CodeGen/ARM/ldm.ll | 11 +- test/CodeGen/ARM/ldst-f32-2-i32.ll | 28 + test/CodeGen/ARM/load-global.ll | 50 + test/CodeGen/ARM/long.ll | 8 +- test/CodeGen/ARM/long_shift.ll | 10 +- test/CodeGen/ARM/lsr-code-insertion.ll | 2 +- test/CodeGen/ARM/lsr-on-unrolled-loops.ll | 23 +- test/CodeGen/ARM/machine-licm.ll | 66 + test/CodeGen/ARM/mul_const.ll | 2 +- test/CodeGen/ARM/mult-alt-generic-arm.ll | 323 + test/CodeGen/ARM/neon_div.ll | 48 + test/CodeGen/ARM/pack.ll | 69 +- test/CodeGen/ARM/phi.ll | 23 + test/CodeGen/ARM/prefetch.ll | 61 + test/CodeGen/ARM/reg_sequence.ll | 39 +- test/CodeGen/ARM/remat.ll | 65 - test/CodeGen/ARM/rev.ll | 41 +- test/CodeGen/ARM/select-imm.ll | 58 +- test/CodeGen/ARM/select.ll | 4 +- test/CodeGen/ARM/select_xform.ll | 63 +- test/CodeGen/ARM/shifter_operand.ll | 72 +- test/CodeGen/ARM/spill-q.ll | 36 +- test/CodeGen/ARM/stm.ll | 5 +- test/CodeGen/ARM/str_pre-2.ll | 5 +- test/CodeGen/ARM/tail-opts.ll | 9 +- test/CodeGen/ARM/thumb1-varalloc.ll | 40 + test/CodeGen/ARM/umulo-32.ll | 14 + test/CodeGen/ARM/unaligned_load_store.ll | 3 +- test/CodeGen/ARM/vbits.ll | 42 +- test/CodeGen/ARM/vceq.ll | 11 + test/CodeGen/ARM/vcge.ll | 41 + test/CodeGen/ARM/vcgt.ll | 28 +- test/CodeGen/ARM/vcombine.ll | 38 +- test/CodeGen/ARM/vcvt.ll | 20 +- test/CodeGen/ARM/vdup.ll | 18 - test/CodeGen/ARM/vector-DAGCombine.ll | 107 + test/CodeGen/ARM/vext.ll | 59 + test/CodeGen/ARM/vget_lane.ll | 37 +- test/CodeGen/ARM/vld1.ll | 50 +- test/CodeGen/ARM/vld2.ll | 59 +- test/CodeGen/ARM/vld3.ll | 48 +- test/CodeGen/ARM/vld4.ll | 62 +- test/CodeGen/ARM/vlddup.ll | 212 + test/CodeGen/ARM/vldlane.ll | 204 +- test/CodeGen/ARM/vmov.ll | 70 +- test/CodeGen/ARM/vmul.ll | 72 + test/CodeGen/ARM/vrev.ll | 18 + test/CodeGen/ARM/vst1.ll | 41 +- test/CodeGen/ARM/vst2.ll | 55 +- test/CodeGen/ARM/vst3.ll | 47 +- test/CodeGen/ARM/vst4.ll | 58 +- test/CodeGen/ARM/vstlane.ll | 161 +- .../Alpha/2010-04-07-DbgValueOtherTargets.ll | 43 +- .../CellSPU/2010-04-07-DbgValueOtherTargets.ll | 43 +- test/CodeGen/CellSPU/arg_ret.ll | 3 +- test/CodeGen/CellSPU/div_ops.ll | 22 + test/CodeGen/CellSPU/fcmp32.ll | 25 +- test/CodeGen/CellSPU/immed32.ll | 15 +- test/CodeGen/CellSPU/loads.ll | 12 + test/CodeGen/CellSPU/rotate_ops.ll | 14 +- test/CodeGen/CellSPU/sext128.ll | 30 +- test/CodeGen/CellSPU/shift_ops.ll | 18 +- test/CodeGen/CellSPU/shuffles.ll | 28 +- test/CodeGen/CellSPU/stores.ll | 22 + test/CodeGen/CellSPU/v2f32.ll | 3 +- test/CodeGen/CellSPU/v2i32.ll | 19 +- test/CodeGen/Generic/2010-11-04-BigByval.ll | 11 + test/CodeGen/Generic/2011-01-06-BigNumberCrash.ll | 15 + test/CodeGen/Generic/2011-02-12-shuffle.ll | 32 + test/CodeGen/Generic/add-with-overflow-128.ll | 24 +- test/CodeGen/Generic/crash.ll | 32 + test/CodeGen/Generic/overflow.ll | 220 + .../MBlaze/2010-04-07-DbgValueOtherTargets.ll | 43 +- test/CodeGen/MBlaze/brind.ll | 13 +- test/CodeGen/MBlaze/cc.ll | 85 +- test/CodeGen/MBlaze/fpu.ll | 16 +- test/CodeGen/MBlaze/imm.ll | 24 +- test/CodeGen/MBlaze/intr.ll | 48 + test/CodeGen/MBlaze/jumptable.ll | 4 +- test/CodeGen/MBlaze/loop.ll | 3 +- test/CodeGen/MBlaze/mul.ll | 6 +- test/CodeGen/MBlaze/shift.ll | 26 +- test/CodeGen/MBlaze/svol.ll | 80 + .../MSP430/2010-04-07-DbgValueOtherTargets.ll | 43 +- test/CodeGen/MSP430/mult-alt-generic-msp430.ll | 323 + test/CodeGen/Mips/2008-07-15-InternalConstant.ll | 4 +- .../Mips/2010-04-07-DbgValueOtherTargets.ll | 43 +- test/CodeGen/Mips/2010-07-20-Select.ll | 6 +- test/CodeGen/Mips/2010-11-09-CountLeading.ll | 33 + test/CodeGen/Mips/2010-11-09-Mul.ll | 15 + test/CodeGen/Mips/cmov.ll | 15 + test/CodeGen/Mips/madd-msub.ll | 65 + test/CodeGen/Mips/o32_cc.ll | 325 + test/CodeGen/Mips/rotate.ll | 40 + test/CodeGen/PIC16/2009-07-17-PR4566-pic16.ll | 32 - test/CodeGen/PIC16/2009-11-20-NewNode.ll | 36 - test/CodeGen/PIC16/C16-11.ll | 40 - test/CodeGen/PIC16/C16-15.ll | 45 - test/CodeGen/PIC16/C16-49.ll | 15 - test/CodeGen/PIC16/check_inc_files.ll | 9 - test/CodeGen/PIC16/dg.exp | 5 - test/CodeGen/PIC16/global-in-user-section.ll | 6 - test/CodeGen/PIC16/globals.ll | 18 - test/CodeGen/PIC16/result_direction.ll | 13 - test/CodeGen/PIC16/sext.ll | 11 - test/CodeGen/PIC16/test_indf_name.ll | 12 - test/CodeGen/PTX/add.ll | 15 + test/CodeGen/PTX/dg.exp | 5 + test/CodeGen/PTX/exit.ll | 14 + test/CodeGen/PTX/ld.ll | 78 + test/CodeGen/PTX/mov.ll | 13 + test/CodeGen/PTX/options.ll | 6 + test/CodeGen/PTX/ret.ll | 7 + test/CodeGen/PTX/shl.ll | 22 + test/CodeGen/PTX/shr.ll | 43 + test/CodeGen/PTX/st.ll | 71 + test/CodeGen/PTX/sub.ll | 15 + test/CodeGen/PowerPC/2007-03-24-cntlzd.ll | 2 +- .../PowerPC/2010-04-07-DbgValueOtherTargets.ll | 43 +- test/CodeGen/PowerPC/2010-10-11-Fast-Varargs.ll | 16 + test/CodeGen/PowerPC/2010-12-18-PPCStackRefs.ll | 22 + test/CodeGen/PowerPC/align.ll | 4 + test/CodeGen/PowerPC/compare-simm.ll | 2 +- test/CodeGen/PowerPC/indirectbr.ll | 4 +- test/CodeGen/PowerPC/mult-alt-generic-powerpc.ll | 321 + test/CodeGen/PowerPC/mult-alt-generic-powerpc64.ll | 321 + test/CodeGen/PowerPC/rlwimi2.ll | 2 +- test/CodeGen/PowerPC/stfiwx.ll | 4 +- test/CodeGen/PowerPC/tango.net.ftp.FtpClient.ll | 585 - test/CodeGen/PowerPC/unsafe-math.ll | 2 +- test/CodeGen/PowerPC/varargs.ll | 22 + .../SPARC/2010-04-07-DbgValueOtherTargets.ll | 43 +- test/CodeGen/SPARC/2011-01-11-CC.ll | 105 + test/CodeGen/SPARC/2011-01-11-Call.ll | 13 + test/CodeGen/SPARC/2011-01-11-FrameAddr.ll | 64 + test/CodeGen/SPARC/2011-01-19-DelaySlot.ll | 90 + test/CodeGen/SPARC/2011-01-21-ByValArgs.ll | 18 + test/CodeGen/SPARC/2011-01-22-SRet.ll | 36 + test/CodeGen/SPARC/basictest.ll | 24 +- test/CodeGen/SPARC/mult-alt-generic-sparc.ll | 323 + test/CodeGen/SPARC/xnor.ll | 15 - .../SystemZ/2010-04-07-DbgValueOtherTargets.ll | 43 +- .../Thumb/2010-04-07-DbgValueOtherTargets.ll | 43 +- test/CodeGen/Thumb/2010-07-15-debugOrdering.ll | 2 +- test/CodeGen/Thumb/2011-EpilogueBug.ll | 17 + test/CodeGen/Thumb/barrier.ll | 11 +- test/CodeGen/Thumb/dyn-stackalloc.ll | 23 +- test/CodeGen/Thumb/large-stack.ll | 14 +- test/CodeGen/Thumb/long.ll | 2 +- test/CodeGen/Thumb/machine-licm.ll | 41 - test/CodeGen/Thumb/select.ll | 2 +- test/CodeGen/Thumb2/2009-08-06-SpDecBug.ll | 9 +- test/CodeGen/Thumb2/2009-08-21-PostRAKill4.ll | 26 + test/CodeGen/Thumb2/2009-09-01-PostRAProlog.ll | 106 + test/CodeGen/Thumb2/2010-03-15-AsmCCClobber.ll | 13 +- test/CodeGen/Thumb2/2010-06-14-NEONCoalescer.ll | 5 +- test/CodeGen/Thumb2/2010-06-21-TailMergeBug.ll | 2 +- .../CodeGen/Thumb2/2010-08-10-VarSizedAllocaBug.ll | 12 +- test/CodeGen/Thumb2/2010-11-22-EpilogueBug.ll | 34 + test/CodeGen/Thumb2/2010-12-03-AddSPNarrowing.ll | 11 + test/CodeGen/Thumb2/bfi.ll | 11 + test/CodeGen/Thumb2/buildvector-crash.ll | 17 + test/CodeGen/Thumb2/cortex-fp.ll | 2 +- test/CodeGen/Thumb2/cross-rc-coalescing-2.ll | 10 +- test/CodeGen/Thumb2/div.ll | 2 +- test/CodeGen/Thumb2/large-stack.ll | 2 +- test/CodeGen/Thumb2/load-global.ll | 23 - test/CodeGen/Thumb2/machine-licm-vdup.ll | 38 - test/CodeGen/Thumb2/machine-licm.ll | 62 +- test/CodeGen/Thumb2/thumb2-badreg-operands.ll | 15 - test/CodeGen/Thumb2/thumb2-barrier.ll | 32 +- test/CodeGen/Thumb2/thumb2-ifcvt3.ll | 1 - test/CodeGen/Thumb2/thumb2-ldrd.ll | 2 +- test/CodeGen/Thumb2/thumb2-mov.ll | 6 +- test/CodeGen/Thumb2/thumb2-mul.ll | 18 + test/CodeGen/Thumb2/thumb2-select_xform.ll | 4 +- test/CodeGen/Thumb2/thumb2-spill-q.ll | 36 +- test/CodeGen/X86/2007-04-25-MMX-PADDQ.ll | 41 +- test/CodeGen/X86/2007-05-15-maskmovq.ll | 8 +- test/CodeGen/X86/2007-06-15-IntToMMX.ll | 13 +- test/CodeGen/X86/2007-07-03-GR64ToVR64.ll | 14 +- test/CodeGen/X86/2007-10-16-fp80_select.ll | 19 - test/CodeGen/X86/2008-02-18-TailMergingBug.ll | 2 +- test/CodeGen/X86/2008-04-08-CoalescerCrash.ll | 8 +- test/CodeGen/X86/2008-06-13-VolatileLoadStore.ll | 4 +- test/CodeGen/X86/2008-07-19-movups-spills.ll | 3 +- test/CodeGen/X86/2008-08-23-64Bit-maskmovq.ll | 6 +- test/CodeGen/X86/2008-09-05-sinttofp-2xi32.ll | 22 +- test/CodeGen/X86/2008-09-17-inline-asm-1.ll | 16 +- test/CodeGen/X86/2008-10-27-CoalescerBug.ll | 10 +- test/CodeGen/X86/2008-10-27-StackRealignment.ll | 4 +- test/CodeGen/X86/2008-11-29-DivideConstant16bit.ll | 9 - .../X86/2008-11-29-DivideConstant16bitSigned.ll | 9 - test/CodeGen/X86/2009-01-13-DoubleUpdate.ll | 2 +- test/CodeGen/X86/2009-01-27-NullStrings.ll | 2 +- test/CodeGen/X86/2009-02-26-MachineLICMBug.ll | 2 +- test/CodeGen/X86/2009-04-24.ll | 3 +- test/CodeGen/X86/2009-06-03-Win64DisableRedZone.ll | 9 +- test/CodeGen/X86/2009-06-03-Win64SpillXMM.ll | 14 +- .../X86/2009-06-05-ScalarToVectorByteMMX.ll | 2 +- test/CodeGen/X86/2009-07-07-SplitICmp.ll | 2 +- .../CodeGen/X86/2009-08-02-mmx-scalar-to-vector.ll | 8 +- test/CodeGen/X86/2009-08-06-inlineasm.ll | 6 +- test/CodeGen/X86/2009-09-10-SpillComments.ll | 4 +- test/CodeGen/X86/2009-12-11-TLSNoRedZone.ll | 2 +- .../CodeGen/X86/2010-04-07-DbgValueOtherTargets.ll | 42 +- test/CodeGen/X86/2010-04-23-mmx-movdq2q.ll | 64 +- .../X86/2010-04-30-LocalAlloc-LandingPad.ll | 2 +- test/CodeGen/X86/2010-05-25-DotDebugLoc.ll | 7 +- test/CodeGen/X86/2010-05-26-DotDebugLoc.ll | 2 +- test/CodeGen/X86/2010-05-28-Crash.ll | 6 +- .../X86/2010-06-25-CoalescerSubRegDefDead.ll | 8 +- test/CodeGen/X86/2010-07-02-asm-alignstack.ll | 4 +- test/CodeGen/X86/2010-09-16-EmptyFilename.ll | 29 + test/CodeGen/X86/2010-09-16-asmcrash.ll | 56 + test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll | 26 + test/CodeGen/X86/2010-09-30-CMOV-JumpTable-PHI.ll | 71 + test/CodeGen/X86/2010-10-08-cmpxchg8b.ll | 28 + test/CodeGen/X86/2010-11-02-DbgParameter.ll | 35 + test/CodeGen/X86/2010-11-09-MOVLPS.ll | 66 + test/CodeGen/X86/2010-11-18-SelectOfExtload.ll | 15 + test/CodeGen/X86/2010-12-02-MC-Set.ll | 22 + test/CodeGen/X86/2011-01-07-LegalizeTypesCrash.ll | 19 + test/CodeGen/X86/2011-01-10-DagCombineHang.ll | 15 + test/CodeGen/X86/2011-01-24-DbgValue-Before-Use.ll | 103 + test/CodeGen/X86/2011-02-04-FastRegallocNoFP.ll | 14 + test/CodeGen/X86/3addr-or.ll | 38 +- test/CodeGen/X86/abi-isel.ll | 942 +- test/CodeGen/X86/add-of-carry.ll | 34 + test/CodeGen/X86/add.ll | 40 + test/CodeGen/X86/addr-label-difference.ll | 2 +- test/CodeGen/X86/alldiv-divdi3.ll | 17 + test/CodeGen/X86/andimm8.ll | 19 + test/CodeGen/X86/apm.ll | 26 + test/CodeGen/X86/atomic_op.ll | 71 +- test/CodeGen/X86/avx-128.ll | 2 +- test/CodeGen/X86/avx-intrinsics-x86.ll | 33 +- test/CodeGen/X86/avx-intrinsics-x86_64.ll | 2 +- test/CodeGen/X86/bc-extract.ll | 27 + test/CodeGen/X86/bit-test-shift.ll | 13 + test/CodeGen/X86/bswap-inline-asm.ll | 11 +- test/CodeGen/X86/byval.ll | 11 +- test/CodeGen/X86/cmp-test.ll | 27 - test/CodeGen/X86/cmp.ll | 92 + test/CodeGen/X86/cmp0.ll | 24 - test/CodeGen/X86/cmp2.ll | 18 - test/CodeGen/X86/commute-two-addr.ll | 48 +- test/CodeGen/X86/compare-inf.ll | 16 +- test/CodeGen/X86/complex-asm.ll | 17 + test/CodeGen/X86/conditional-indecrement.ll | 89 + test/CodeGen/X86/const-select.ll | 22 - test/CodeGen/X86/crash.ll | 58 + test/CodeGen/X86/critical-edge-split-2.ll | 29 + test/CodeGen/X86/critical-edge-split.ll | 50 - test/CodeGen/X86/ctpop-combine.ll | 40 + test/CodeGen/X86/dagcombine-buildvector.ll | 2 +- test/CodeGen/X86/dbg-live-in-location.ll | 84 + test/CodeGen/X86/dbg-merge-loc-entry.ll | 71 + test/CodeGen/X86/dbg-value-inlined-parameter.ll | 86 + test/CodeGen/X86/dbg-value-location.ll | 70 + test/CodeGen/X86/dbg-value-range.ll | 56 + test/CodeGen/X86/div_const.ll | 7 - test/CodeGen/X86/divide-by-constant.ll | 62 + test/CodeGen/X86/dll-linkage.ll | 2 +- test/CodeGen/X86/dollar-name.ll | 2 +- .../X86/fast-isel-avoid-unnecessary-pic-base.ll | 23 + test/CodeGen/X86/fast-isel-bc.ll | 16 +- test/CodeGen/X86/fast-isel-gep.ll | 17 + test/CodeGen/X86/fast-isel-mem.ll | 18 +- test/CodeGen/X86/fltused.ll | 19 + test/CodeGen/X86/fp-in-intregs.ll | 3 +- test/CodeGen/X86/fp-stack-compare.ll | 3 +- test/CodeGen/X86/ghc-cc.ll | 4 +- test/CodeGen/X86/global-sections.ll | 18 +- test/CodeGen/X86/inline-asm-h.ll | 12 + test/CodeGen/X86/inline-asm-ptr-cast.ll | 27 + test/CodeGen/X86/insertelement-legalize.ll | 2 +- test/CodeGen/X86/legalize-sub-zero-2.ll | 41 + test/CodeGen/X86/legalize-sub-zero.ll | 35 + test/CodeGen/X86/legalizedag_vec.ll | 8 +- test/CodeGen/X86/licm-symbol.ll | 2 +- test/CodeGen/X86/loop-blocks.ll | 11 +- test/CodeGen/X86/lsr-reuse.ll | 15 +- test/CodeGen/X86/machine-cse.ll | 40 + test/CodeGen/X86/memcmp.ll | 12 +- test/CodeGen/X86/memcpy.ll | 64 +- test/CodeGen/X86/memmove-0.ll | 9 - test/CodeGen/X86/memmove-1.ll | 9 - test/CodeGen/X86/memmove-2.ll | 9 - test/CodeGen/X86/memmove-3.ll | 9 - test/CodeGen/X86/memset-2.ll | 26 +- test/CodeGen/X86/memset64-on-x86-32.ll | 2 +- test/CodeGen/X86/mingw-alloca.ll | 4 +- test/CodeGen/X86/misaligned-memset.ll | 15 + test/CodeGen/X86/mmx-arg-passing.ll | 19 +- test/CodeGen/X86/mmx-arg-passing2.ll | 14 +- test/CodeGen/X86/mmx-arith.ll | 380 +- test/CodeGen/X86/mmx-bitcast-to-i64.ll | 37 +- test/CodeGen/X86/mmx-builtins.ll | 1324 ++ test/CodeGen/X86/mmx-insert-element.ll | 10 +- test/CodeGen/X86/mmx-pinsrw.ll | 2 +- test/CodeGen/X86/mmx-punpckhdq.ll | 19 +- test/CodeGen/X86/mmx-shift.ll | 24 +- test/CodeGen/X86/mmx-shuffle.ll | 6 +- test/CodeGen/X86/mmx-vzmovl-2.ll | 24 +- test/CodeGen/X86/mmx-vzmovl.ll | 4 +- test/CodeGen/X86/movgs.ll | 53 +- test/CodeGen/X86/mult-alt-generic-i686.ll | 321 + test/CodeGen/X86/mult-alt-generic-x86_64.ll | 321 + test/CodeGen/X86/mult-alt-x86.ll | 358 + test/CodeGen/X86/narrow-shl-load.ll | 83 + test/CodeGen/X86/negative-sin.ll | 4 +- test/CodeGen/X86/non-globl-eh-frame.ll | 24 + test/CodeGen/X86/phi-immediate-factoring.ll | 2 +- test/CodeGen/X86/phys_subreg_coalesce-2.ll | 2 +- test/CodeGen/X86/pic.ll | 24 +- test/CodeGen/X86/pic_jumptable.ll | 2 +- test/CodeGen/X86/popcnt.ll | 38 + test/CodeGen/X86/postra-licm.ll | 2 +- test/CodeGen/X86/pr2659.ll | 7 +- test/CodeGen/X86/pr3522.ll | 2 +- test/CodeGen/X86/pr9127.ll | 12 + test/CodeGen/X86/prefetch.ll | 10 +- test/CodeGen/X86/rodata-relocs.ll | 16 +- test/CodeGen/X86/scalar_widen_div.ll | 2 +- test/CodeGen/X86/select-aggregate.ll | 15 - test/CodeGen/X86/select-zero-one.ll | 25 - test/CodeGen/X86/select.ll | 239 +- test/CodeGen/X86/sext-select.ll | 23 - test/CodeGen/X86/shift-folding.ll | 6 +- test/CodeGen/X86/sibcall-3.ll | 2 +- test/CodeGen/X86/sibcall-5.ll | 31 + test/CodeGen/X86/sibcall.ll | 30 +- test/CodeGen/X86/sink-hoist.ll | 29 +- test/CodeGen/X86/split-select.ll | 7 - test/CodeGen/X86/sse-align-11.ll | 3 +- test/CodeGen/X86/sse2.ll | 30 + test/CodeGen/X86/sse3.ll | 17 +- test/CodeGen/X86/sse41.ll | 4 +- test/CodeGen/X86/stack-align.ll | 17 +- test/CodeGen/X86/stdcall-notailcall.ll | 13 + test/CodeGen/X86/store-narrow.ll | 14 + test/CodeGen/X86/store_op_load_fold2.ll | 2 +- test/CodeGen/X86/switch-bt.ll | 30 + test/CodeGen/X86/switch-or.ll | 22 + test/CodeGen/X86/tail-opts.ll | 23 +- test/CodeGen/X86/tailcall-largecode.ll | 8 +- test/CodeGen/X86/tailcall-ri64.ll | 24 + test/CodeGen/X86/tailcall-stackalign.ll | 2 +- test/CodeGen/X86/tailcallfp2.ll | 4 +- test/CodeGen/X86/tailcallstack64.ll | 17 +- test/CodeGen/X86/tls-1.ll | 19 - test/CodeGen/X86/tls-pic.ll | 16 +- test/CodeGen/X86/tls9.ll | 2 +- test/CodeGen/X86/tlv-1.ll | 35 + test/CodeGen/X86/tlv-2.ll | 32 + test/CodeGen/X86/twoaddr-lea.ll | 32 +- test/CodeGen/X86/uint64-to-float.ll | 21 + test/CodeGen/X86/umul-with-overflow.ll | 8 +- test/CodeGen/X86/umulo-64.ll | 28 + test/CodeGen/X86/unaligned-load.ll | 2 +- test/CodeGen/X86/unknown-location.ll | 10 +- test/CodeGen/X86/vec-sign.ll | 30 + test/CodeGen/X86/vec-trunc-store.ll | 2 +- test/CodeGen/X86/vec_cast.ll | 1 - test/CodeGen/X86/vec_compare-2.ll | 2 +- test/CodeGen/X86/vec_ext_inreg.ll | 1 - test/CodeGen/X86/vec_insert-5.ll | 9 +- test/CodeGen/X86/vec_insert-7.ll | 15 +- test/CodeGen/X86/vec_select.ll | 12 - test/CodeGen/X86/vec_set-F.ll | 6 +- test/CodeGen/X86/vec_shuffle-27.ll | 29 +- test/CodeGen/X86/vec_shuffle-30.ll | 2 +- test/CodeGen/X86/vec_shuffle-37.ll | 10 + test/CodeGen/X86/vec_zero_cse.ll | 5 +- test/CodeGen/X86/visibility.ll | 11 + test/CodeGen/X86/vshift-1.ll | 2 +- test/CodeGen/X86/vshift-2.ll | 2 +- test/CodeGen/X86/vshift-3.ll | 2 +- test/CodeGen/X86/vshift-4.ll | 2 +- test/CodeGen/X86/vshift-5.ll | 2 +- test/CodeGen/X86/vsplit-and.ll | 2 +- test/CodeGen/X86/widen_arith-1.ll | 2 +- test/CodeGen/X86/widen_arith-2.ll | 2 +- test/CodeGen/X86/widen_arith-3.ll | 2 +- test/CodeGen/X86/widen_arith-4.ll | 2 +- test/CodeGen/X86/widen_arith-5.ll | 2 +- test/CodeGen/X86/widen_arith-6.ll | 2 +- test/CodeGen/X86/widen_cast-1.ll | 2 +- test/CodeGen/X86/widen_cast-2.ll | 2 +- test/CodeGen/X86/widen_cast-3.ll | 2 +- test/CodeGen/X86/widen_cast-4.ll | 2 +- test/CodeGen/X86/widen_cast-5.ll | 2 +- test/CodeGen/X86/widen_cast-6.ll | 2 +- test/CodeGen/X86/widen_conv-1.ll | 2 +- test/CodeGen/X86/widen_conv-2.ll | 2 +- test/CodeGen/X86/widen_conv-3.ll | 2 +- test/CodeGen/X86/widen_conv-4.ll | 2 +- test/CodeGen/X86/widen_extract-1.ll | 2 +- test/CodeGen/X86/widen_load-1.ll | 2 +- test/CodeGen/X86/widen_load-2.ll | 2 +- test/CodeGen/X86/widen_select-1.ll | 12 - test/CodeGen/X86/widen_shuffle-1.ll | 2 +- test/CodeGen/X86/win64_params.ll | 11 + test/CodeGen/X86/win64_vararg.ll | 20 + test/CodeGen/X86/win_chkstk.ll | 15 +- test/CodeGen/X86/x86-64-extend-shift.ll | 10 + test/CodeGen/X86/x86_64-mul-by-const.ll | 9 + test/CodeGen/X86/zext-extract_subreg.ll | 60 + .../XCore/2010-04-07-DbgValueOtherTargets.ll | 43 +- test/CodeGen/XCore/2011-01-31-DAGCombineBug.ll | 10 + test/CodeGen/XCore/ashr.ll | 8 +- test/CodeGen/XCore/globals.ll | 6 +- test/CodeGen/XCore/resources.ll | 111 + test/CodeGen/XCore/trampoline.ll | 37 + test/DebugInfo/2009-10-16-Scope.ll | 3 +- test/DebugInfo/2010-05-10-MultipleCU.ll | 18 +- test/DebugInfo/2010-08-04-StackVariable.ll | 3 +- test/DebugInfo/2010-10-01-crash.ll | 21 + test/ExecutionEngine/2002-12-16-ArgTest.ll | 3 +- test/ExecutionEngine/2003-01-04-ArgumentBug.ll | 3 +- test/ExecutionEngine/2003-01-04-LoopTest.ll | 3 +- test/ExecutionEngine/2003-01-04-PhiTest.ll | 3 +- test/ExecutionEngine/2003-01-09-SARTest.ll | 3 +- test/ExecutionEngine/2003-01-10-FUCOM.ll | 3 +- test/ExecutionEngine/2003-01-15-AlignmentTest.ll | 3 +- test/ExecutionEngine/2003-05-06-LivenessClobber.ll | 4 +- test/ExecutionEngine/2003-05-07-ArgumentTest.ll | 2 +- test/ExecutionEngine/2003-05-11-PHIRegAllocBug.ll | 3 +- test/ExecutionEngine/2003-06-04-bzip2-bug.ll | 3 +- test/ExecutionEngine/2003-06-05-PHIBug.ll | 3 +- test/ExecutionEngine/2003-08-15-AllocaAssertion.ll | 3 +- test/ExecutionEngine/2003-08-21-EnvironmentTest.ll | 3 +- .../2003-08-23-RegisterAllocatePhysReg.ll | 3 +- ...-10-18-PHINode-ConstantExpr-CondCode-Failure.ll | 3 +- test/ExecutionEngine/2005-12-02-TailCallBug.ll | 3 +- test/ExecutionEngine/2007-12-10-APIntLoadStore.ll | 2 +- test/ExecutionEngine/2008-06-05-APInt-OverAShr.ll | 3 +- test/ExecutionEngine/2010-01-15-UndefValue.ll | 3 +- test/ExecutionEngine/fpbitcast.ll | 3 +- test/ExecutionEngine/hello.ll | 3 +- test/ExecutionEngine/hello2.ll | 3 +- test/ExecutionEngine/simplesttest.ll | 3 +- test/ExecutionEngine/simpletest.ll | 3 +- test/ExecutionEngine/stubs.ll | 2 +- test/ExecutionEngine/test-arith.ll | 3 +- test/ExecutionEngine/test-branch.ll | 3 +- test/ExecutionEngine/test-call.ll | 4 +- test/ExecutionEngine/test-cast.ll | 3 +- test/ExecutionEngine/test-constantexpr.ll | 3 +- test/ExecutionEngine/test-fp.ll | 3 +- test/ExecutionEngine/test-loadstore.ll | 3 +- test/ExecutionEngine/test-logical.ll | 3 +- test/ExecutionEngine/test-loop.ll | 3 +- test/ExecutionEngine/test-malloc.ll | 3 +- test/ExecutionEngine/test-phi.ll | 3 +- test/ExecutionEngine/test-ret.ll | 3 +- test/ExecutionEngine/test-setcond-fp.ll | 3 +- test/ExecutionEngine/test-setcond-int.ll | 3 +- test/ExecutionEngine/test-shift.ll | 3 +- test/Feature/load_module.ll | 4 +- test/FrontendAda/Support/real_cst.ads | 4 + test/FrontendAda/array_constructor.adb | 2 +- test/FrontendAda/array_range_ref.adb | 2 +- test/FrontendAda/array_ref.adb | 2 +- test/FrontendAda/array_size.adb | 2 +- test/FrontendAda/asm.adb | 2 +- test/FrontendAda/debug_var_size.ads | 2 +- test/FrontendAda/element_copy.adb | 2 +- test/FrontendAda/emit_var.ads | 2 +- test/FrontendAda/fat_fields.adb | 4 +- test/FrontendAda/field_order.ads | 2 +- test/FrontendAda/global_constant.adb | 2 +- test/FrontendAda/init_size.ads | 2 +- test/FrontendAda/negative_field_offset.adb | 2 +- test/FrontendAda/non_bitfield.ads | 2 +- test/FrontendAda/non_lvalue.adb | 2 +- test/FrontendAda/placeholder.adb | 2 +- test/FrontendAda/real_cst.adb | 8 + test/FrontendAda/switch.adb | 2 +- test/FrontendAda/unc_constructor.adb | 2 +- test/FrontendAda/var_offset.adb | 2 +- test/FrontendAda/var_size.adb | 2 +- test/FrontendAda/vce.adb | 2 +- test/FrontendAda/vce_lv.adb | 2 +- test/FrontendC++/2003-08-20-ExceptionFail.cpp | 12 - test/FrontendC++/2003-08-21-EmptyClass.cpp | 9 - test/FrontendC++/2003-08-24-Cleanup.cpp | 10 - test/FrontendC++/2003-08-27-TypeNamespaces.cpp | 16 - test/FrontendC++/2003-08-28-ForwardType.cpp | 23 - test/FrontendC++/2003-08-28-SaveExprBug.cpp | 24 - test/FrontendC++/2003-08-29-ArgPassingBug.cpp | 13 - test/FrontendC++/2003-08-31-StructLayout.cpp | 16 - test/FrontendC++/2003-09-22-CompositeExprValue.cpp | 11 - .../2003-09-29-ArgumentNumberMismatch.cpp | 17 - test/FrontendC++/2003-09-30-CommaExprBug.cpp | 10 - .../FrontendC++/2003-09-30-ForIncrementExprBug.cpp | 10 - .../2003-09-30-ForIncrementExprBug2.cpp | 12 - test/FrontendC++/2003-09-30-NestedFunctionDecl.cpp | 12 - test/FrontendC++/2003-10-17-BoolBitfields.cpp | 11 - test/FrontendC++/2003-10-21-InnerClass.cpp | 12 - .../2003-10-27-VirtualBaseClassCrash.cpp | 17 - test/FrontendC++/2003-11-04-ArrayConstructors.cpp | 12 - test/FrontendC++/2003-11-04-CatchLabelName.cpp | 11 - test/FrontendC++/2003-11-08-ArrayAddress.cpp | 10 - test/FrontendC++/2003-11-18-EnumArray.cpp | 14 - .../2004-03-09-UnmangledBuiltinMethods.cpp | 2 +- test/FrontendC++/2004-09-27-DidntEmitTemplate.cpp | 2 +- test/FrontendC++/2005-07-21-VirtualBaseAccess.cpp | 2 +- test/FrontendC++/2006-09-27-Debug-Protection.cpp | 4 +- test/FrontendC++/2006-10-30-ClassBitfield.cpp | 2 +- test/FrontendC++/2006-11-20-GlobalSymbols.cpp | 2 +- test/FrontendC++/2006-11-30-ConstantExprCrash.cpp | 2 +- test/FrontendC++/2006-11-30-NoCompileUnit.cpp | 60 - test/FrontendC++/2007-01-02-UnboundedArray.cpp | 2 +- test/FrontendC++/2007-01-06-ELF-Thunk-Sections.cpp | 2 +- test/FrontendC++/2007-01-06-PtrMethodInit.cpp | 2 +- test/FrontendC++/2007-03-27-FunctionVarRename.cpp | 4 +- .../2007-04-11-InlineStorageClassC++.cpp | 14 +- test/FrontendC++/2007-05-03-VectorInit.cpp | 2 +- .../2007-05-16-ReverseBitFieldCrash.cpp | 2 +- test/FrontendC++/2007-05-23-TryFinally.cpp | 2 +- test/FrontendC++/2007-07-29-RestrictPtrArg.cpp | 2 +- test/FrontendC++/2007-07-29-RestrictRefArg.cpp | 2 +- test/FrontendC++/2007-08-01-RestrictMethod.cpp | 2 +- .../2007-09-10-RecursiveTypeResolution.cpp | 2 +- test/FrontendC++/2007-10-01-StructResize.cpp | 2 +- test/FrontendC++/2008-10-29-WrongOffset.cpp | 2 +- test/FrontendC++/2009-02-16-CtorNames-dbg.cpp | 2 +- test/FrontendC++/2009-03-17-dbg.cpp | 2 +- test/FrontendC++/2009-04-21-DtorNames-dbg.cpp | 2 +- test/FrontendC++/2009-04-23-bool2.cpp | 2 +- test/FrontendC++/2009-05-04-PureConstNounwind.cpp | 2 +- test/FrontendC++/2009-06-16-DebugInfoCrash.cpp | 2 +- test/FrontendC++/2009-06-20-DarwinPPCLayout.cpp | 14 +- test/FrontendC++/2009-08-05-ZeroInitWidth.cpp | 2 +- test/FrontendC++/2009-08-11-VectorRetTy.cpp | 2 +- test/FrontendC++/2009-09-04-modify-crash.cpp | 2 +- test/FrontendC++/2009-09-09-packed-layout.cpp | 2 +- test/FrontendC++/2009-10-27-crash.cpp | 2 +- test/FrontendC++/2010-03-22-empty-baseclass.cpp | 2 +- .../FrontendC++/2010-04-30-OptimizedMethod-Dbg.cpp | 4 +- .../2010-05-11-alwaysinlineinstantiation.cpp | 4 +- test/FrontendC++/2010-05-12-PtrToMember-Dbg.cpp | 2 +- test/FrontendC++/2010-06-22-BitfieldInit.cpp | 2 +- test/FrontendC++/2010-06-22-ZeroBitfield.cpp | 2 +- test/FrontendC++/2010-07-19-nowarn.cpp | 2 +- test/FrontendC++/2010-07-23-DeclLoc.cpp | 2 +- test/FrontendC++/member-alignment.cpp | 2 +- test/FrontendC++/ptr-to-method-devirt.cpp | 4 +- test/FrontendC++/varargs.cpp | 2 +- test/FrontendC++/weak-external.cpp | 2 +- .../x86-64-abi-sret-vs-2word-struct-param.cpp | 2 +- test/FrontendC/2003-08-06-BuiltinSetjmpLongjmp.c | 2 +- test/FrontendC/2003-08-17-DeadCodeShortCircuit.c | 2 +- test/FrontendC/2003-11-03-AddrArrayElement.c | 2 +- .../2003-11-08-PointerSubNotGetelementptr.c | 2 +- test/FrontendC/2003-11-13-TypeSafety.c | 2 +- test/FrontendC/2003-12-14-ExternInlineSupport.c | 2 +- test/FrontendC/2004-02-12-LargeAggregateCopy.c | 2 +- .../2004-02-13-BuiltinFrameReturnAddress.c | 2 +- test/FrontendC/2004-02-13-IllegalVararg.c | 2 +- test/FrontendC/2004-02-13-Memset.c | 2 +- test/FrontendC/2004-02-20-Builtins.c | 2 +- test/FrontendC/2004-03-07-ExternalConstant.c | 2 +- test/FrontendC/2004-06-17-UnorderedCompares.c | 2 +- .../FrontendC/2004-11-27-StaticFunctionRedeclare.c | 4 +- test/FrontendC/2005-01-02-PointerDifference.c | 2 +- test/FrontendC/2005-02-27-MarkGlobalConstant.c | 2 +- test/FrontendC/2005-12-04-AttributeUsed.c | 2 +- test/FrontendC/2006-03-03-MissingInitializer.c | 2 +- test/FrontendC/2007-01-06-KNR-Proto.c | 2 +- test/FrontendC/2007-02-04-AddrLValue-2.c | 2 +- test/FrontendC/2007-02-04-AddrLValue.c | 2 +- test/FrontendC/2007-02-04-EmptyStruct.c | 2 +- test/FrontendC/2007-02-04-WITH_SIZE_EXPR.c | 2 +- test/FrontendC/2007-02-05-nested.c | 2 +- test/FrontendC/2007-02-07-AddrLabel.c | 2 +- test/FrontendC/2007-02-16-VoidPtrDiff.c | 2 +- test/FrontendC/2007-02-16-WritableStrings.c | 6 +- test/FrontendC/2007-02-25-C-DotDotDot.c | 2 +- test/FrontendC/2007-03-01-VarSizeArrayIdx.c | 2 +- test/FrontendC/2007-04-11-InlineAsmStruct.c | 2 +- test/FrontendC/2007-04-11-InlineAsmUnion.c | 2 +- test/FrontendC/2007-04-11-InlineStorageClassC89.c | 14 +- test/FrontendC/2007-04-11-InlineStorageClassC99.c | 14 +- test/FrontendC/2007-04-13-InlineAsmStruct2.c | 2 +- test/FrontendC/2007-04-13-InlineAsmUnion2.c | 2 +- test/FrontendC/2007-04-24-VolatileStructCopy.c | 2 +- test/FrontendC/2007-04-24-bit-not-expr.c | 2 +- test/FrontendC/2007-04-24-str-const.c | 2 +- test/FrontendC/2007-05-07-PaddingElements.c | 4 +- test/FrontendC/2007-05-11-str-const.c | 2 +- test/FrontendC/2007-05-15-PaddingElement.c | 2 +- test/FrontendC/2007-05-16-EmptyStruct.c | 2 +- test/FrontendC/2007-05-29-UnionCopy.c | 2 +- test/FrontendC/2007-06-05-NoInlineAttribute.c | 2 +- test/FrontendC/2007-06-15-AnnotateAttribute.c | 4 +- test/FrontendC/2007-06-18-SextAttrAggregate.c | 2 +- test/FrontendC/2007-07-29-RestrictPtrArg.c | 2 +- test/FrontendC/2007-08-01-LoadStoreAlign.c | 4 +- test/FrontendC/2007-08-21-ComplexCst.c | 2 +- test/FrontendC/2007-09-05-ConstCtor.c | 2 +- test/FrontendC/2007-09-20-GcrootAttribute.c | 6 +- test/FrontendC/2007-10-01-BuildArrayRef.c | 18 +- test/FrontendC/2007-11-07-AlignedMemcpy.c | 2 +- test/FrontendC/2007-11-27-SExtZExt.c | 2 +- test/FrontendC/2008-01-25-ByValReadNone.c | 4 +- test/FrontendC/2008-01-28-PragmaMark.c | 2 +- test/FrontendC/2008-03-03-CtorAttrType.c | 2 +- test/FrontendC/2008-03-05-syncPtr.c | 2 +- test/FrontendC/2008-05-19-AlwaysInline.c | 4 +- test/FrontendC/2008-08-07-AlignPadding1.c | 2 +- test/FrontendC/2008-08-07-AlignPadding2.c | 2 +- test/FrontendC/2008-10-30-ZeroPlacement.c | 2 +- test/FrontendC/2008-11-02-WeakAlias.c | 2 +- test/FrontendC/2008-11-08-InstCombineSelect.c | 2 +- .../2008-11-11-AnnotateStructFieldAttribute.c | 2 +- test/FrontendC/2008-12-23-AsmIntPointerTie.c | 2 +- test/FrontendC/2009-01-05-BlockInlining.c | 2 +- test/FrontendC/2009-03-13-dbg.c | 2 +- test/FrontendC/2009-05-04-EnumInreg.c | 2 +- test/FrontendC/2010-01-13-MemBarrier.c | 2 +- test/FrontendC/2010-05-18-asmsched.c | 2 +- test/FrontendC/2010-05-26-AsmSideEffect.c | 2 +- test/FrontendC/2010-06-28-nowarn.c | 2 +- test/FrontendC/2010-07-14-overconservative-align.c | 2 +- test/FrontendC/2010-11-16-asmblock.c | 16 + test/FrontendC/2010-12-01-CommonGlobal.c | 7 + test/FrontendC/arrayderef.c | 17 + test/FrontendC/attribute_constructor.c | 2 +- test/FrontendC/block-copy.c | 2 +- test/FrontendC/cstring-align.c | 2 +- test/FrontendC/extern-weak.c | 4 +- test/FrontendC/func-aligned.c | 2 +- test/FrontendC/hidden-visibility.c | 2 +- test/FrontendC/implicit-arg.c | 4 +- test/FrontendC/libcalls-d.c | 8 +- test/FrontendC/libcalls-ld.c | 8 +- test/FrontendC/libcalls.c | 8 +- test/FrontendC/pr3518.c | 2 +- test/FrontendC/pr4349.c | 10 +- test/FrontendC/pr5406.c | 2 +- test/FrontendC/ptr-rotate.c | 4 +- test/FrontendC/sret.c | 2 +- test/FrontendC/sret2.c | 2 +- test/FrontendC/unaligned-memcpy.c | 2 +- test/FrontendFortran/2008-11-03-OptionOverride.f90 | 2 +- test/FrontendFortran/2009-02-09-FloorDivExpr.f90 | 2 +- test/FrontendFortran/cpow.f90 | 2 +- test/FrontendObjC++/2007-10-03-MetadataPointers.mm | 2 +- .../FrontendObjC++/2010-08-02-NonPODObjectValue.mm | 2 +- test/FrontendObjC++/2010-08-04-Template.mm | 2 +- test/FrontendObjC++/2010-08-06-X.Y-syntax.mm | 2 +- test/FrontendObjC/2007-04-03-ObjcEH.m | 2 +- test/FrontendObjC/2007-05-02-Strong.m | 2 +- test/FrontendObjC/2007-09-25-EH.m | 2 +- test/FrontendObjC/2007-10-18-ProDescriptor.m | 2 +- test/FrontendObjC/2007-10-23-GC-WriteBarrier.m | 2 +- test/FrontendObjC/2008-10-3-EhValue.m | 2 +- test/FrontendObjC/2008-11-12-Metadata.m | 2 +- test/FrontendObjC/2008-11-25-Blocks.m | 2 +- test/FrontendObjC/2009-02-05-VolatileProp.m | 2 +- test/FrontendObjC/2009-04-14-AsmSection.m | 2 +- test/FrontendObjC/2009-08-05-utf16.m | 2 +- .../FrontendObjC/2010-02-11-fwritable-stringsBug.m | 4 +- test/LLVMC/C++/dg.exp | 2 +- test/LLVMC/C++/just-compile.cpp | 10 + test/LLVMC/C++/unknown_suffix.unk | 9 + test/LLVMC/C/emit-llvm-opt.c | 9 + test/LLVMC/C/emit-llvm.c | 3 + test/LLVMC/MultipleOutputLanguages.td | 27 + test/LLVMC/OptionPreprocessor.td | 8 +- test/Linker/PR8300.ll | 13 + test/Linker/available_externally_a.ll | 5 + test/Linker/available_externally_b.ll | 4 + test/Linker/link-archive.ll | 1 + test/Linker/linkmdnode.ll | 1 + test/Linker/linkmdnode2.ll | 10 + test/Linker/unnamed-addr1-a.ll | 27 + test/Linker/unnamed-addr1-b.ll | 12 + test/MC/ARM/arm_fixups.s | 7 + test/MC/ARM/arm_instructions.s | 284 + test/MC/ARM/arm_word_directive.s | 6 + test/MC/ARM/dg.exp | 5 + test/MC/ARM/elf-eflags-eabi.s | 13 + test/MC/ARM/elf-movt.s | 39 + test/MC/ARM/elf-reloc-01.ll | 71 + test/MC/ARM/elf-reloc-02.ll | 51 + test/MC/ARM/elf-reloc-03.ll | 98 + test/MC/ARM/hilo-16bit-relocations.s | 20 + test/MC/ARM/neon-abs-encoding.s | 31 + test/MC/ARM/neon-absdiff-encoding.s | 82 + test/MC/ARM/neon-add-encoding.s | 137 + test/MC/ARM/neon-bitcount-encoding.s | 31 + test/MC/ARM/neon-bitwise-encoding.s | 47 + test/MC/ARM/neon-cmp-encoding.s | 115 + test/MC/ARM/neon-convert-encoding.s | 38 + test/MC/ARM/neon-dup-encoding.s | 27 + test/MC/ARM/neon-minmax-encoding.s | 58 + test/MC/ARM/neon-mov-encoding.s | 117 + test/MC/ARM/neon-mul-accum-encoding.s | 67 + test/MC/ARM/neon-mul-encoding.s | 56 + test/MC/ARM/neon-neg-encoding.s | 30 + test/MC/ARM/neon-pairwise-encoding.s | 86 + test/MC/ARM/neon-reciprocal-encoding.s | 26 + test/MC/ARM/neon-reverse-encoding.s | 26 + test/MC/ARM/neon-satshift-encoding.s | 150 + test/MC/ARM/neon-shift-encoding.s | 160 + test/MC/ARM/neon-shiftaccum-encoding.s | 98 + test/MC/ARM/neon-shuffle-encoding.s | 46 + test/MC/ARM/neon-sub-encoding.s | 108 + test/MC/ARM/neon-table-encoding.s | 19 + test/MC/ARM/neon-vld-encoding.s | 110 + test/MC/ARM/neon-vst-encoding.s | 101 + test/MC/ARM/neont2-abs-encoding.s | 33 + test/MC/ARM/neont2-absdiff-encoding.s | 86 + test/MC/ARM/neont2-add-encoding.s | 138 + test/MC/ARM/neont2-bitcount-encoding.s | 34 + test/MC/ARM/neont2-bitwise-encoding.s | 49 + test/MC/ARM/neont2-cmp-encoding.s | 36 + test/MC/ARM/neont2-convert-encoding.s | 40 + test/MC/ARM/neont2-dup-encoding.s | 29 + test/MC/ARM/neont2-minmax-encoding.s | 60 + test/MC/ARM/neont2-mov-encoding.s | 119 + test/MC/ARM/neont2-mul-accum-encoding.s | 69 + test/MC/ARM/neont2-mul-encoding.s | 58 + test/MC/ARM/neont2-neg-encoding.s | 32 + test/MC/ARM/neont2-pairwise-encoding.s | 89 + test/MC/ARM/neont2-reciprocal-encoding.s | 28 + test/MC/ARM/neont2-reverse-encoding.s | 26 + test/MC/ARM/neont2-satshift-encoding.s | 152 + test/MC/ARM/neont2-shift-encoding.s | 162 + test/MC/ARM/neont2-shiftaccum-encoding.s | 100 + test/MC/ARM/neont2-shuffle-encoding.s | 48 + test/MC/ARM/neont2-sub-encoding.s | 46 + test/MC/ARM/neont2-table-encoding.s | 21 + test/MC/ARM/neont2-vld-encoding.s | 112 + test/MC/ARM/neont2-vst-encoding.s | 103 + test/MC/ARM/prefetch.ll | 58 + test/MC/ARM/reg-list.s | 8 + test/MC/ARM/simple-encoding.ll | 237 + test/MC/ARM/simple-fp-encoding.s | 236 + test/MC/ARM/thumb.s | 70 + test/MC/ARM/thumb2.s | 286 + test/MC/ARM/thumb2_instructions.s | 12 + test/MC/AsmParser/ARM/arm_instructions.s | 8 - test/MC/AsmParser/ARM/arm_word_directive.s | 6 - test/MC/AsmParser/ARM/dg.exp | 5 - test/MC/AsmParser/ELF/dg.exp | 6 - test/MC/AsmParser/ELF/directive_previous.s | 13 - test/MC/AsmParser/ELF/directive_section.s | 23 - test/MC/AsmParser/X86/dg.exp | 5 - test/MC/AsmParser/X86/x86_32-avx-clmul-encoding.s | 42 - test/MC/AsmParser/X86/x86_32-avx-encoding.s | 3241 --- test/MC/AsmParser/X86/x86_32-bit.s | 1631 -- test/MC/AsmParser/X86/x86_32-bit_cat.s | 7862 -------- test/MC/AsmParser/X86/x86_32-encoding.s | 10069 ---------- test/MC/AsmParser/X86/x86_32-fma3-encoding.s | 674 - test/MC/AsmParser/X86/x86_32-mismatched-add.s | 8 - test/MC/AsmParser/X86/x86_32-new-encoder.s | 425 - test/MC/AsmParser/X86/x86_64-avx-clmul-encoding.s | 42 - test/MC/AsmParser/X86/x86_64-avx-encoding.s | 3318 ---- test/MC/AsmParser/X86/x86_64-encoding.s | 142 - test/MC/AsmParser/X86/x86_64-fma3-encoding.s | 674 - test/MC/AsmParser/X86/x86_64-imm-widths.s | 105 - test/MC/AsmParser/X86/x86_64-incl_decl.s | 26 - test/MC/AsmParser/X86/x86_64-new-encoder.s | 159 - test/MC/AsmParser/X86/x86_64-operands.s | 15 - test/MC/AsmParser/X86/x86_64-suffix-matching.s | 10 - test/MC/AsmParser/X86/x86_instruction_errors.s | 5 - test/MC/AsmParser/X86/x86_instructions.s | 175 - test/MC/AsmParser/X86/x86_operands.s | 58 - test/MC/AsmParser/X86/x86_word_directive.s | 6 - test/MC/AsmParser/dash-n.s | 7 + test/MC/AsmParser/directive_abort.s | 2 +- test/MC/AsmParser/directive_ascii.s | 7 + test/MC/AsmParser/directive_loc.s | 2 +- test/MC/AsmParser/directive_set.s | 5 + test/MC/AsmParser/directive_values.s | 20 + test/MC/AsmParser/equ.s | 9 + test/MC/AsmParser/expr_symbol_modifiers.s | 14 + test/MC/AsmParser/exprs.s | 77 +- test/MC/AsmParser/floating-literals.s | 35 + test/MC/AsmParser/full_line_comment.s | 8 + test/MC/AsmParser/ifdef.s | 29 + test/MC/AsmParser/ifndef.s | 29 + test/MC/AsmParser/paren.s | 8 + test/MC/AsmParser/rename.s | 10 + test/MC/AsmParser/section.s | 107 + test/MC/COFF/align-nops.s | 50 + test/MC/COFF/basic-coff.ll | 136 - test/MC/COFF/basic-coff.s | 133 + test/MC/COFF/bss.s | 15 + test/MC/COFF/dg.exp | 2 +- test/MC/COFF/module-asm.ll | 26 + test/MC/COFF/simple-fixups.s | 50 + test/MC/COFF/switch-relocations.ll | 3 + test/MC/COFF/symbol-alias.s | 62 + test/MC/COFF/symbol-fragment-offset.ll | 182 - test/MC/COFF/symbol-fragment-offset.s | 187 + test/MC/COFF/weak.s | 51 + test/MC/Disassembler/ARM/arm-tests.txt | 132 + test/MC/Disassembler/ARM/dg.exp | 6 + test/MC/Disassembler/ARM/neon-tests.txt | 61 + test/MC/Disassembler/ARM/thumb-tests.txt | 120 + test/MC/Disassembler/MBlaze/dg.exp | 6 + test/MC/Disassembler/MBlaze/mblaze_branch.txt | 119 + test/MC/Disassembler/MBlaze/mblaze_fpu.txt | 47 + test/MC/Disassembler/MBlaze/mblaze_fsl.txt | 338 + test/MC/Disassembler/MBlaze/mblaze_imm.txt | 121 + test/MC/Disassembler/MBlaze/mblaze_memory.txt | 65 + test/MC/Disassembler/MBlaze/mblaze_operands.txt | 197 + test/MC/Disassembler/MBlaze/mblaze_pattern.txt | 14 + test/MC/Disassembler/MBlaze/mblaze_shift.txt | 29 + test/MC/Disassembler/MBlaze/mblaze_special.txt | 105 + test/MC/Disassembler/MBlaze/mblaze_typea.txt | 74 + test/MC/Disassembler/MBlaze/mblaze_typeb.txt | 56 + test/MC/Disassembler/X86/dg.exp | 6 + test/MC/Disassembler/X86/simple-tests.txt | 68 + test/MC/Disassembler/X86/truncated-input.txt | 4 + test/MC/Disassembler/arm-tests.txt | 111 - test/MC/Disassembler/dg.exp | 6 - test/MC/Disassembler/neon-tests.txt | 51 - test/MC/Disassembler/simple-tests.txt | 62 - test/MC/Disassembler/thumb-tests.txt | 105 - test/MC/ELF/abs.s | 16 + test/MC/ELF/alias-reloc.s | 52 + test/MC/ELF/alias.s | 85 + test/MC/ELF/align-bss.s | 17 + test/MC/ELF/align-nops.s | 40 + test/MC/ELF/align-size.s | 13 + test/MC/ELF/align-text.s | 19 + test/MC/ELF/align.s | 32 + test/MC/ELF/bad-section.s | 9 + test/MC/ELF/basic-elf-32.s | 78 + test/MC/ELF/basic-elf-64.s | 82 + test/MC/ELF/call-abs.s | 24 + test/MC/ELF/cfi-advance-loc2.s | 45 + test/MC/ELF/cfi-def-cfa-offset.s | 46 + test/MC/ELF/cfi-def-cfa-register.s | 41 + test/MC/ELF/cfi-def-cfa.s | 42 + test/MC/ELF/cfi-offset.s | 42 + test/MC/ELF/cfi-remember.s | 45 + test/MC/ELF/cfi-zero-addr-delta.s | 48 + test/MC/ELF/cfi.s | 674 + test/MC/ELF/comdat.s | 86 + test/MC/ELF/common.s | 88 + test/MC/ELF/common2.s | 21 + test/MC/ELF/debug-line.s | 22 + test/MC/ELF/debug-loc.s | 32 + test/MC/ELF/dg.exp | 2 +- test/MC/ELF/diff.s | 15 + test/MC/ELF/diff2.s | 13 + test/MC/ELF/elf_directive_previous.s | 13 + test/MC/ELF/elf_directive_section.s | 23 + test/MC/ELF/empty-dwarf-lines.s | 21 + test/MC/ELF/empty.s | 70 + test/MC/ELF/entsize.ll | 44 + test/MC/ELF/entsize.s | 69 + test/MC/ELF/file.s | 23 + test/MC/ELF/global-offset.s | 18 + test/MC/ELF/got.s | 25 + test/MC/ELF/ident.s | 17 + test/MC/ELF/invalid-symver.s | 7 + test/MC/ELF/leb128.s | 19 + test/MC/ELF/local-reloc.s | 31 + test/MC/ELF/merge.s | 97 + test/MC/ELF/n_bytes.s | 20 + test/MC/ELF/no-fixup.s | 16 + test/MC/ELF/noexec.s | 24 + test/MC/ELF/norelocation.s | 18 + test/MC/ELF/pic-diff.s | 29 + test/MC/ELF/plt.s | 14 + test/MC/ELF/relax-arith.s | 75 + test/MC/ELF/relax-crash.s | 11 + test/MC/ELF/relax.s | 27 + test/MC/ELF/relocation-386.s | 226 + test/MC/ELF/relocation.s | 114 + test/MC/ELF/rename.s | 46 + test/MC/ELF/section.s | 110 + test/MC/ELF/set.s | 34 + test/MC/ELF/sleb.s | 29 + test/MC/ELF/symref.s | 165 + test/MC/ELF/tls-i386.s | 64 + test/MC/ELF/tls.s | 48 + test/MC/ELF/type.s | 32 + test/MC/ELF/uleb.s | 22 + test/MC/ELF/undef.s | 46 + test/MC/ELF/undef2.s | 10 + test/MC/ELF/weak.s | 30 + test/MC/ELF/weakref-plt.s | 8 + test/MC/ELF/weakref-reloc.s | 49 + test/MC/ELF/weakref.s | 234 + test/MC/ELF/zero.s | 16 + test/MC/MBlaze/dg.exp | 5 + test/MC/MBlaze/mblaze_branch.s | 197 + test/MC/MBlaze/mblaze_fpu.s | 77 + test/MC/MBlaze/mblaze_fsl.s | 568 + test/MC/MBlaze/mblaze_imm.s | 194 + test/MC/MBlaze/mblaze_memory.s | 107 + test/MC/MBlaze/mblaze_operands.s | 328 + test/MC/MBlaze/mblaze_pattern.s | 22 + test/MC/MBlaze/mblaze_shift.s | 47 + test/MC/MBlaze/mblaze_special.s | 167 + test/MC/MBlaze/mblaze_typea.s | 122 + test/MC/MBlaze/mblaze_typeb.s | 92 + test/MC/MachO/absolutize.s | 6 +- test/MC/MachO/comm-1.s | 2 +- test/MC/MachO/darwin-ARM-reloc.s | 171 + test/MC/MachO/darwin-Thumb-reloc.s | 139 + test/MC/MachO/darwin-complex-difference.s | 129 + test/MC/MachO/darwin-x86_64-diff-relocs.s | 2 +- test/MC/MachO/darwin-x86_64-reloc-offsets.s | 6 +- test/MC/MachO/darwin-x86_64-reloc.s | 10 +- test/MC/MachO/diff-with-two-sections.s | 64 + test/MC/MachO/direction_labels.s | 4 +- test/MC/MachO/empty-dwarf-lines.s | 25 + test/MC/MachO/indirect-symbols.s | 6 +- test/MC/MachO/jcc.s | 4 +- test/MC/MachO/lcomm-attributes.s | 2 +- test/MC/MachO/loc.s | 25 + test/MC/MachO/pcrel-to-other-section.s | 107 + test/MC/MachO/relax-jumps.s | 6 +- test/MC/MachO/reloc-pcrel-offset.s | 2 +- test/MC/MachO/reloc.s | 70 +- test/MC/MachO/section-align-1.s | 2 +- test/MC/MachO/section-align-2.s | 2 +- test/MC/MachO/string-table.s | 4 +- test/MC/MachO/symbol-diff.s | 122 + test/MC/MachO/symbol-flags.s | 59 +- test/MC/MachO/symbol-indirect.s | 2 +- test/MC/MachO/symbols-1.s | 4 +- test/MC/MachO/tbss.s | 4 +- test/MC/MachO/tdata.s | 4 +- test/MC/MachO/thread_init_func.s | 2 +- test/MC/MachO/tls.s | 8 +- test/MC/MachO/tlv-reloc.s | 8 +- test/MC/MachO/tlv.s | 4 +- test/MC/MachO/values.s | 2 +- test/MC/MachO/weakdef.s | 141 + test/MC/MachO/x86_32-optimal_nop.s | 8 +- test/MC/MachO/x86_32-symbols.s | 2 +- test/MC/MachO/x86_64-symbols.s | 2 +- test/MC/MachO/zerofill-1.s | 2 +- test/MC/MachO/zerofill-2.s | 2 +- test/MC/MachO/zerofill-3.s | 2 +- test/MC/MachO/zerofill-5.s | 6 +- test/MC/X86/3DNow.s | 92 + test/MC/X86/dg.exp | 5 + test/MC/X86/x86-32-avx.s | 3283 ++++ test/MC/X86/x86-32-coverage.s | 19564 +++++++++++++++++++ test/MC/X86/x86-32-fma3.s | 674 + test/MC/X86/x86-32.s | 810 + test/MC/X86/x86-64.s | 944 + test/MC/X86/x86_64-avx-clmul-encoding.s | 42 + test/MC/X86/x86_64-avx-encoding.s | 3318 ++++ test/MC/X86/x86_64-encoding.s | 157 + test/MC/X86/x86_64-fma3-encoding.s | 674 + test/MC/X86/x86_64-imm-widths.s | 105 + test/MC/X86/x86_directives.s | 6 + test/MC/X86/x86_errors.s | 5 + test/MC/X86/x86_operands.s | 58 + test/Makefile | 11 +- .../TestObjectFiles/trivial-object-test.coff-i386 | Bin 0 -> 346 bytes .../trivial-object-test.coff-x86-64 | Bin 0 -> 347 bytes .../TestObjectFiles/trivial-object-test.elf-i386 | Bin 0 -> 716 bytes .../TestObjectFiles/trivial-object-test.elf-x86-64 | Bin 0 -> 1024 bytes .../TestObjectFiles/trivial-object-test.macho-i386 | Bin 0 -> 552 bytes .../trivial-object-test.macho-x86-64 | Bin 0 -> 552 bytes test/Object/dg.exp | 3 + test/Object/nm-trivial-object.test-broken | 19 + test/Object/objdump-trivial-object.test-broken | 54 + test/Other/2008-08-14-PassManager.ll | 5 - test/Other/close-stderr.ll | 2 + test/Other/extract.ll | 27 + test/Other/lint.ll | 2 +- test/Scripts/coff-dump.py | 1008 +- test/Scripts/coff-dump.py.bat | 5 +- test/Scripts/common_dump.py | 46 + test/Scripts/elf-dump | 231 + test/Scripts/elf-dump.bat | 7 + test/Scripts/macho-dump | 289 - test/Scripts/macho-dump.bat | 7 - test/Scripts/macho-dumpx | 294 + test/Scripts/macho-dumpx.bat | 7 + test/TableGen/Dag.td | 71 + test/TableGen/DagDefSubst.td | 16 - test/TableGen/DagIntSubst.td | 11 - test/TableGen/FieldAccess.td | 2 + test/TableGen/ListManip.td | 4 +- test/TableGen/Slice.td | 8 +- test/TableGen/defmclass.td | 12 + test/TableGen/if.td | 34 +- test/TableGen/lisp.td | 2 +- test/TableGen/nameconcat.td | 91 - test/Transforms/ArgumentPromotion/basictest.ll | 2 +- test/Transforms/ArgumentPromotion/crash.ll | 21 + test/Transforms/CodeGenPrepare/basic.ll | 29 + test/Transforms/ConstProp/basictest.ll | 9 + test/Transforms/ConstProp/bitcast.ll | 12 +- test/Transforms/ConstProp/bitcast2.ll | 8 - test/Transforms/ConstProp/calls.ll | 58 +- test/Transforms/ConstProp/constant-expr.ll | 44 + test/Transforms/ConstProp/extractvalue.ll | 68 + test/Transforms/ConstProp/insertvalue.ll | 68 + test/Transforms/ConstProp/loads.ll | 17 + test/Transforms/ConstProp/logicaltest.ll | 4 +- test/Transforms/ConstProp/nottest.ll | 19 - test/Transforms/ConstProp/overflow-ops.ll | 11 + .../ConstantMerge/2011-01-15-EitherOrder.ll | 18 + test/Transforms/ConstantMerge/merge-both.ll | 26 + test/Transforms/ConstantMerge/unnamed-addr.ll | 40 + .../2010-09-26-MergeConstantRange.ll | 82 + .../Transforms/CorrelatedValuePropagation/basic.ll | 3 +- .../Transforms/CorrelatedValuePropagation/crash.ll | 37 + .../CorrelatedValuePropagation/non-null.ll | 103 + test/Transforms/DeadArgElim/deadexternal.ll | 28 +- .../2004-11-28-LiveStoreDeleted.ll | 14 - .../2004-12-28-PartialStore.ll | 13 - .../DeadStoreElimination/2005-11-30-vaarg.ll | 9 - .../DeadStoreElimination/2006-06-27-AST-Remove.ll | 1113 -- .../DeadStoreElimination/2008-07-28-load-store.ll | 15 - .../2008-11-28-MemDepUpdate.ll | 16 - .../2008-11-29-OffEndOfBlock.ll | 27 - .../DeadStoreElimination/2009-11-10-Trampoline.ll | 16 - .../DeadStoreElimination/PartialStore.ll | 71 +- test/Transforms/DeadStoreElimination/alloca.ll | 9 - test/Transforms/DeadStoreElimination/byval.ll | 10 - .../DeadStoreElimination/const-pointers.ll | 2 +- .../DeadStoreElimination/context-sensitive.ll | 15 - test/Transforms/DeadStoreElimination/crash.ll | 19 +- test/Transforms/DeadStoreElimination/free.ll | 27 +- test/Transforms/DeadStoreElimination/lifetime.ll | 2 +- test/Transforms/DeadStoreElimination/memcpy.ll | 52 - .../DeadStoreElimination/no-targetdata.ll | 2 +- .../DeadStoreElimination/partial-overwrite.ll | 14 - test/Transforms/DeadStoreElimination/simple.ll | 234 +- .../DeadStoreElimination/volatile-load.ll | 8 - test/Transforms/EarlyCSE/basic.ll | 121 + test/Transforms/EarlyCSE/dg.exp | 3 + .../FunctionAttrs/2008-09-03-ReadNone.ll | 2 +- .../FunctionAttrs/2008-09-03-ReadOnly.ll | 2 +- .../FunctionAttrs/2008-10-04-LocalMemory.ll | 2 +- .../FunctionAttrs/2008-12-29-Constant.ll | 2 +- .../FunctionAttrs/2010-10-30-volatile.ll | 10 + test/Transforms/GVN/2007-07-25-InfiniteLoop.ll | 2 +- .../Transforms/GVN/2007-07-26-InterlockingLoops.ll | 29 +- test/Transforms/GVN/2007-07-31-NoDomInherit.ll | 2 +- test/Transforms/GVN/2007-07-31-RedundantPhi.ll | 2 +- test/Transforms/GVN/2008-07-02-Unreachable.ll | 2 +- test/Transforms/GVN/2010-03-31-RedundantPHIs.ll | 12 +- test/Transforms/GVN/2010-11-13-Simplify.ll | 15 + test/Transforms/GVN/calls-nonlocal.ll | 2 +- test/Transforms/GVN/condprop.ll | 35 +- test/Transforms/GVN/invariant-simple.ll | 2 +- test/Transforms/GVN/lifetime-simple.ll | 2 +- test/Transforms/GVN/load-constant-mem.ll | 2 +- test/Transforms/GVN/load-pre-licm.ll | 39 + test/Transforms/GVN/lpre-call-wrap-2.ll | 2 +- test/Transforms/GVN/mixed.ll | 4 +- test/Transforms/GVN/non-local-offset.ll | 59 + test/Transforms/GVN/nonescaping-malloc.ll | 2 +- test/Transforms/GVN/null-aliases-nothing.ll | 2 +- test/Transforms/GVN/phi-translate.ll | 31 + test/Transforms/GVN/pre-load.ll | 2 +- test/Transforms/GVN/pre-single-pred.ll | 14 +- test/Transforms/GVN/preserve-tbaa.ll | 28 + test/Transforms/GVN/rle-must-alias.ll | 2 +- test/Transforms/GVN/rle-nonlocal.ll | 2 +- test/Transforms/GVN/rle-semidominated.ll | 2 +- test/Transforms/GVN/rle.ll | 2 +- .../GlobalOpt/2008-04-26-SROA-Global-Align.ll | 6 +- .../GlobalOpt/2009-03-07-PromotePtrToBool.ll | 2 +- .../2009-11-16-MallocSingleStoreToGlobalVar.ll | 2 +- test/Transforms/GlobalOpt/2010-10-19-WeakOdr.ll | 16 + test/Transforms/GlobalOpt/crash.ll | 9 + .../GlobalOpt/ctor-list-opt-constexpr.ll | 23 + test/Transforms/GlobalOpt/ctor-list-opt.ll | 19 +- .../GlobalOpt/globalsra-unknown-index.ll | 2 +- test/Transforms/GlobalOpt/memcpy.ll | 2 +- test/Transforms/GlobalOpt/unnamed-addr.ll | 54 + .../IndVarSimplify/loop-invariant-step.ll | 33 - test/Transforms/Inline/basictest.ll | 2 +- test/Transforms/Inline/byval.ll | 82 +- test/Transforms/Inline/byval2.ll | 28 - test/Transforms/Inline/devirtualize-3.ll | 2 +- test/Transforms/Inline/devirtualize.ll | 2 +- test/Transforms/Inline/gvn-inline-iteration.ll | 2 +- .../InstCombine/2003-08-12-AllocaNonNull.ll | 3 +- .../InstCombine/2006-04-28-ShiftShiftLongLong.ll | 2 +- .../InstCombine/2007-03-26-BadShiftMask.ll | 3 +- .../Transforms/InstCombine/2008-11-20-DivMulRem.ll | 43 +- .../Transforms/InstCombine/2010-11-01-lshr-mask.ll | 46 + .../InstCombine/2010-11-21-SizeZeroTypeGEP.ll | 17 + .../InstCombine/2010-11-23-Distributed.ll | 23 + test/Transforms/InstCombine/2011-02-14-InfLoop.ll | 19 + .../InstCombine/2011-02-16-InsertelementHang.ll | 11 + test/Transforms/InstCombine/add.ll | 24 + test/Transforms/InstCombine/add2.ll | 25 +- test/Transforms/InstCombine/and2.ll | 18 + test/Transforms/InstCombine/bit-checks.ll | 348 +- test/Transforms/InstCombine/bitcast-store.ll | 21 + test/Transforms/InstCombine/bitcast-vec-uniform.ll | 70 + test/Transforms/InstCombine/cast.ll | 32 +- test/Transforms/InstCombine/constant-fold-gep.ll | 19 + test/Transforms/InstCombine/crash.ll | 118 + test/Transforms/InstCombine/div-cmp-overflow.ll | 8 - test/Transforms/InstCombine/exact-sdiv.ll | 52 - test/Transforms/InstCombine/exact.ll | 154 + test/Transforms/InstCombine/extractvalue.ll | 81 +- test/Transforms/InstCombine/fold-calls.ll | 19 + test/Transforms/InstCombine/fold-vector-select.ll | 13 + test/Transforms/InstCombine/icmp.ll | 223 + test/Transforms/InstCombine/intrinsics.ll | 19 + test/Transforms/InstCombine/memcpy.ll | 19 +- test/Transforms/InstCombine/memset2.ll | 15 + test/Transforms/InstCombine/neon-intrinsics.ll | 25 + test/Transforms/InstCombine/nsw.ll | 41 +- test/Transforms/InstCombine/objsize.ll | 10 + test/Transforms/InstCombine/or-fcmp.ll | 28 +- test/Transforms/InstCombine/or.ll | 48 +- test/Transforms/InstCombine/overflow.ll | 133 + test/Transforms/InstCombine/phi.ll | 125 +- test/Transforms/InstCombine/pr8547.ll | 26 + test/Transforms/InstCombine/rem.ll | 5 + test/Transforms/InstCombine/select-crash.ll | 20 + test/Transforms/InstCombine/select.ll | 244 + test/Transforms/InstCombine/sext.ll | 2 +- test/Transforms/InstCombine/shift.ll | 50 +- test/Transforms/InstCombine/signext.ll | 12 +- test/Transforms/InstCombine/sub.ll | 28 +- test/Transforms/InstCombine/trunc.ll | 24 +- test/Transforms/InstCombine/vec_demanded_elts-2.ll | 19 - test/Transforms/InstCombine/vec_demanded_elts-3.ll | 14 - test/Transforms/InstCombine/vec_demanded_elts.ll | 129 +- test/Transforms/InstCombine/vec_sext.ll | 22 + test/Transforms/InstCombine/vec_shuffle.ll | 23 + test/Transforms/InstCombine/vector-casts.ll | 28 + test/Transforms/InstCombine/xor2.ll | 2 +- test/Transforms/InstSimplify/2010-12-20-Boolean.ll | 29 + .../InstSimplify/2010-12-20-Distribute.ll | 62 + test/Transforms/InstSimplify/2011-01-14-Thread.ll | 9 + test/Transforms/InstSimplify/2011-02-01-Vector.ll | 8 + test/Transforms/InstSimplify/compare.ll | 189 + test/Transforms/InstSimplify/dg.exp | 3 + test/Transforms/InstSimplify/exact-nsw-nuw.ll | 44 + test/Transforms/InstSimplify/fdiv.ll | 17 + test/Transforms/InstSimplify/reassociate.ll | 186 + test/Transforms/JumpThreading/2010-08-26-and.ll | 2 +- test/Transforms/JumpThreading/and-and-cond.ll | 10 +- test/Transforms/JumpThreading/and-cond.ll | 9 +- test/Transforms/JumpThreading/basic.ll | 2 +- test/Transforms/JumpThreading/crash.ll | 27 + test/Transforms/JumpThreading/degenerate-phi.ll | 24 + test/Transforms/JumpThreading/indirectbr.ll | 94 + test/Transforms/JumpThreading/lvi-load.ll | 2 +- test/Transforms/JumpThreading/select.ll | 123 + test/Transforms/JumpThreading/thread-loads.ll | 9 +- .../LCSSA/2006-06-03-IncorrectIDFPhis.ll | 4 +- .../LICM/2003-02-27-NestedLoopExitBlocks.ll | 2 +- .../LICM/2008-07-22-LoadGlobalConstant.ll | 2 +- test/Transforms/LICM/2009-03-25-AliasSetTracker.ll | 39 - test/Transforms/LICM/crash.ll | 13 + test/Transforms/LICM/scalar_promote.ll | 32 +- test/Transforms/LoopIdiom/basic.ll | 349 + test/Transforms/LoopIdiom/dg.exp | 3 + .../LoopIndexSplit/2007-09-21-LoopBound.ll | 63 - .../2007-09-24-UpdateIterationSpace.ll | 57 - .../2007-09-25-UpdateIterationSpace-2.ll | 60 - .../LoopIndexSplit/2008-01-28-IndDecrement.ll | 46 - test/Transforms/LoopIndexSplit/2008-02-08-Crash.ll | 48 - .../LoopIndexSplit/2008-02-13-ExitValueNum.ll | 67 - .../LoopIndexSplit/2008-02-13-LoopLatch.ll | 72 - .../LoopIndexSplit/2008-02-13-LoopLatchPHI.ll | 74 - test/Transforms/LoopIndexSplit/2008-02-14-Crash.ll | 464 - .../LoopIndexSplit/2008-03-24-ExitPhi.ll | 69 - .../Transforms/LoopIndexSplit/2008-05-19-IndVar.ll | 40 - .../LoopIndexSplit/2008-06-03-DomFrontier.ll | 32 - .../LoopIndexSplit/2008-07-08-MisCompilation.ll | 25 - test/Transforms/LoopIndexSplit/2008-09-17-IVUse.ll | 78 - test/Transforms/LoopIndexSplit/2008-09-20-Crash.ll | 38 - test/Transforms/LoopIndexSplit/2008-10-06-Crash.ll | 31 - .../LoopIndexSplit/2008-10-10-OneIteration.ll | 66 - test/Transforms/LoopIndexSplit/2008-11-10-Sign.ll | 69 - .../2009-03-02-UpdateIterationSpace-crash.ll | 64 - test/Transforms/LoopIndexSplit/2009-03-30-undef.ll | 24 - test/Transforms/LoopIndexSplit/Crash-2007-08-17.ll | 52 - test/Transforms/LoopIndexSplit/Crash-2007-12-03.ll | 44 - .../Transforms/LoopIndexSplit/Crash2-2007-08-17.ll | 58 - .../LoopIndexSplit/ExitCondition-2007-09-10.ll | 50 - .../LoopIndexSplit/OneIterLoop-2007-08-17.ll | 67 - .../LoopIndexSplit/OneIterLoop2-2007-08-17.ll | 69 - .../LoopIndexSplit/OneIterLoop3-2007-08-17.ll | 34 - test/Transforms/LoopIndexSplit/PR3913.ll | 24 - test/Transforms/LoopIndexSplit/PR4174-2.ll | 38 - test/Transforms/LoopIndexSplit/PR4174.ll | 23 - .../LoopIndexSplit/SaveLastValue-2007-08-17.ll | 52 - .../LoopIndexSplit/SplitValue-2007-08-24.ll | 52 - .../LoopIndexSplit/UpperBound-2007-08-24.ll | 52 - test/Transforms/LoopIndexSplit/dg.exp | 3 - .../LoopIndexSplit/non-iv-cmp-operand.ll | 195 - test/Transforms/LoopRotate/LRCrash-1.ll | 18 - test/Transforms/LoopRotate/LRCrash-2.ll | 24 - test/Transforms/LoopRotate/LRCrash-3.ll | 29 - test/Transforms/LoopRotate/LRCrash-4.ll | 18 - test/Transforms/LoopRotate/LRCrash-5.ll | 26 - test/Transforms/LoopRotate/basic.ll | 35 + test/Transforms/LoopRotate/crash.ll | 139 + test/Transforms/LoopRotate/dbgvalue.ll | 59 + test/Transforms/LoopRotate/phi-duplicate.ll | 19 +- .../LoopSimplify/2003-04-25-AssertFail.ll | 2 +- .../2003-05-12-PreheaderExitOfChild.ll | 2 +- .../2004-02-05-DominatorInfoCorruption.ll | 2 +- .../LoopSimplify/2004-03-15-IncorrectDomUpdate.ll | 2 +- .../LoopSimplify/2004-04-01-IncorrectDomUpdate.ll | 2 +- .../2004-04-12-LoopSimplify-SwitchBackedges.ll | 2 +- .../2004-04-13-LoopSimplifyUpdateDomFrontier.ll | 2 +- .../LoopSimplify/2007-10-28-InvokeCrash.ll | 2 +- .../2010-07-15-IncorrectDomFrontierUpdate.ll | 2 +- .../LoopSimplify/2010-12-26-PHIInfiniteLoop.ll | 43 + test/Transforms/LoopSimplify/basictest.ll | 2 +- test/Transforms/LoopSimplify/hardertest.ll | 2 +- .../Transforms/LoopSimplify/indirectbr-backedge.ll | 2 +- test/Transforms/LoopSimplify/indirectbr.ll | 2 +- test/Transforms/LoopSimplify/merge-exits.ll | 2 +- test/Transforms/LoopSimplify/phi-node-simplify.ll | 2 +- .../LoopSimplify/unreachable-loop-pred.ll | 2 +- .../LoopStrengthReduce/hoist-parent-preheader.ll | 32 + test/Transforms/LoopStrengthReduce/pr2570.ll | 2 +- .../LoopUnroll/2005-03-06-BadLoopInfoUpdate.ll | 2 +- test/Transforms/LoopUnroll/basic.ll | 24 + test/Transforms/LoopUnswitch/2010-11-18-LCSSA.ll | 28 + .../MemCpyOpt/2008-02-24-MultipleUseofSRet.ll | 2 +- .../MemCpyOpt/2008-03-13-ReturnSlotBitcast.ll | 2 +- .../Transforms/MemCpyOpt/2008-04-29-SRetRemoval.ll | 17 - test/Transforms/MemCpyOpt/align.ll | 4 +- test/Transforms/MemCpyOpt/crash.ll | 19 +- test/Transforms/MemCpyOpt/form-memset.ll | 175 +- test/Transforms/MemCpyOpt/form-memset2.ll | 99 - test/Transforms/MemCpyOpt/loadstore-sret.ll | 25 + test/Transforms/MemCpyOpt/memcpy-to-memset.ll | 19 + test/Transforms/MemCpyOpt/memcpy.ll | 93 +- test/Transforms/MemCpyOpt/memmove.ll | 2 +- test/Transforms/MemCpyOpt/smaller.ll | 28 + test/Transforms/MemCpyOpt/sret.ll | 6 +- .../Transforms/MergeFunc/2011-02-08-RemoveEqual.ll | 276 + test/Transforms/MergeFunc/fold-weak.ll | 4 + test/Transforms/MergeFunc/vector.ll | 76 + test/Transforms/PartialSpecialize/dg.exp | 3 - .../PartialSpecialize/two-specializations.ll | 37 - .../Reassociate/2011-01-26-UseAfterFree.ll | 35 + test/Transforms/Reassociate/optional-flags.ll | 29 + .../ScalarRepl/2003-05-30-InvalidIndices.ll | 8 - .../Transforms/ScalarRepl/2003-05-30-MultiLevel.ll | 10 - .../ScalarRepl/2005-12-14-UnionPromoteCrash.ll | 28 - .../2006-01-24-IllegalUnionPromoteCrash.ll | 12 - .../ScalarRepl/2006-04-20-PromoteCrash.ll | 18 - .../ScalarRepl/2006-10-23-PointerUnionCrash.ll | 57 - .../Transforms/ScalarRepl/2006-12-11-SROA-Crash.ll | 20 - .../ScalarRepl/2007-03-19-CanonicalizeMemcpy.ll | 44 - .../ScalarRepl/2009-01-09-scalarrepl-empty.ll | 15 - .../ScalarRepl/2009-04-21-ZeroLengthMemSet.ll | 16 - test/Transforms/ScalarRepl/2009-05-08-I1Crash.ll | 12 - .../ScalarRepl/2009-06-01-BitcastIntPadding.ll | 17 - test/Transforms/ScalarRepl/2009-08-16-VLA.ll | 23 - test/Transforms/ScalarRepl/basictest.ll | 23 +- test/Transforms/ScalarRepl/copy-aggregate.ll | 52 +- test/Transforms/ScalarRepl/crash.ll | 260 + test/Transforms/ScalarRepl/memcpy-from-global.ll | 66 +- test/Transforms/ScalarRepl/phi-select.ll | 153 + test/Transforms/ScalarRepl/vector_promote.ll | 6 +- .../SimplifyCFG/2010-10-24-OnlyUnwindInEntry.ll | 6 + test/Transforms/SimplifyCFG/MagicPointer.ll | 1 - test/Transforms/SimplifyCFG/PhiBlockMerge.ll | 7 +- test/Transforms/SimplifyCFG/PhiEliminate.ll | 14 - test/Transforms/SimplifyCFG/basictest.ll | 23 +- test/Transforms/SimplifyCFG/indirectbr.ll | 118 + test/Transforms/SimplifyCFG/invoke_unwind.ll | 5 +- .../SimplifyCFG/speculate-with-offset.ll | 94 + test/Transforms/SimplifyCFG/switch-to-icmp.ll | 39 + test/Transforms/SimplifyCFG/switch_create.ll | 436 +- .../Transforms/SimplifyCFG/switch_formation.dbg.ll | 8 +- test/Transforms/SimplifyCFG/switch_formation.ll | 30 - .../SimplifyLibCalls/2009-02-12-StrTo.ll | 2 +- test/Transforms/SimplifyLibCalls/FPuts.ll | 29 + test/Transforms/SimplifyLibCalls/Printf.ll | 29 +- test/Transforms/SimplifyLibCalls/Puts.ll | 30 +- test/Transforms/SimplifyLibCalls/StrChr.ll | 28 +- test/Transforms/SimplifyLibCalls/StrPBrk.ll | 25 + test/Transforms/SimplifyLibCalls/StrRChr.ll | 23 + test/Transforms/SimplifyLibCalls/StrSpn.ll | 41 + test/Transforms/SimplifyLibCalls/floor.ll | 2 + test/Transforms/Sink/basic.ll | 2 +- test/Transforms/TailCallElim/dup_tail.ll | 23 + test/Unit/lit.cfg | 12 +- test/Unit/lit.site.cfg.in | 10 + test/lib/llvm.exp | 6 +- test/lit.cfg | 109 +- test/lit.site.cfg.in | 10 + test/site.exp.in | 2 + tools/CMakeLists.txt | 16 +- tools/Makefile | 48 +- tools/bugpoint-passes/CMakeLists.txt | 2 + tools/bugpoint/BugDriver.cpp | 2 +- tools/bugpoint/BugDriver.h | 3 +- tools/bugpoint/CrashDebugger.cpp | 8 +- tools/bugpoint/ExecutionDriver.cpp | 44 +- tools/bugpoint/ExtractFunction.cpp | 12 +- tools/bugpoint/Miscompilation.cpp | 12 +- tools/bugpoint/OptimizerDriver.cpp | 28 +- tools/bugpoint/ToolRunner.cpp | 206 +- tools/bugpoint/ToolRunner.h | 13 +- tools/bugpoint/bugpoint.cpp | 31 +- tools/edis/CMakeLists.txt | 2 - tools/edis/Makefile | 4 +- tools/gold/Makefile | 3 +- tools/gold/gold-plugin.cpp | 139 +- tools/llc/llc.cpp | 22 +- tools/lli/CMakeLists.txt | 2 +- tools/lli/Makefile | 2 +- tools/lli/lli.cpp | 40 +- tools/llvm-ar/llvm-ar.cpp | 78 +- tools/llvm-as/llvm-as.cpp | 4 +- tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp | 30 +- tools/llvm-config/CMakeLists.txt | 19 +- tools/llvm-config/llvm-config.in.in | 5 +- tools/llvm-diff/llvm-diff.cpp | 75 +- tools/llvm-dis/llvm-dis.cpp | 37 +- tools/llvm-extract/llvm-extract.cpp | 45 +- tools/llvm-ld/CMakeLists.txt | 2 + tools/llvm-ld/Optimize.cpp | 2 +- tools/llvm-ld/llvm-ld.cpp | 62 +- tools/llvm-link/llvm-link.cpp | 6 +- tools/llvm-mc/Disassembler.cpp | 3 +- tools/llvm-mc/llvm-mc.cpp | 193 +- tools/llvm-nm/CMakeLists.txt | 2 +- tools/llvm-nm/Makefile | 2 +- tools/llvm-nm/llvm-nm.cpp | 228 +- tools/llvm-objdump/CMakeLists.txt | 11 + tools/llvm-objdump/Makefile | 17 + tools/llvm-objdump/llvm-objdump.cpp | 255 + tools/llvm-prof/llvm-prof.cpp | 14 +- tools/llvm-ranlib/llvm-ranlib.cpp | 14 +- tools/llvm-shlib/Makefile | 15 +- tools/llvm-stub/llvm-stub.c | 10 +- tools/llvmc/doc/LLVMC-Reference.rst | 71 +- tools/llvmc/examples/mcc16/Hooks.cpp | 2 +- tools/llvmc/examples/mcc16/Main.cpp | 2 +- tools/llvmc/src/Base.td.in | 227 +- tools/llvmc/src/Clang.td | 6 +- tools/llvmc/src/Hooks.cpp | 181 +- tools/lto/LTOCodeGenerator.cpp | 38 +- tools/lto/LTOModule.cpp | 83 +- tools/lto/LTOModule.h | 3 + tools/lto/Makefile | 4 + tools/lto/lto.cpp | 14 +- tools/lto/lto.exports | 1 + tools/macho-dump/CMakeLists.txt | 5 + tools/macho-dump/Makefile | 23 + tools/macho-dump/macho-dump.cpp | 391 + tools/opt/GraphPrinters.cpp | 13 +- tools/opt/opt.cpp | 223 +- unittests/ADT/APIntTest.cpp | 7 +- unittests/ADT/BitVectorTest.cpp | 7 + unittests/ADT/FoldingSet.cpp | 39 + unittests/ADT/ImmutableSetTest.cpp | 48 +- unittests/ADT/IntEqClassesTest.cpp | 107 + unittests/ADT/IntervalMapTest.cpp | 716 + unittests/ADT/Makefile | 2 +- unittests/ADT/SmallBitVectorTest.cpp | 7 + unittests/ADT/SmallVectorTest.cpp | 2 +- unittests/ADT/StringMapTest.cpp | 2 +- unittests/ADT/StringRefTest.cpp | 2 +- unittests/ADT/TripleTest.cpp | 80 +- unittests/ADT/TwineTest.cpp | 8 + unittests/ADT/ValueMapTest.cpp | 294 - unittests/CMakeLists.txt | 142 + unittests/ExecutionEngine/JIT/JITTests.def | 4 + unittests/Makefile.unittest | 10 +- unittests/Support/ConstantRangeTest.cpp | 54 +- unittests/Support/EndianTest.cpp | 72 + unittests/Support/Path.cpp | 253 + unittests/Support/SwapByteOrderTest.cpp | 128 + unittests/Support/System.cpp | 16 - unittests/Support/TimeValue.cpp | 23 + unittests/Support/ValueHandleTest.cpp | 4 +- unittests/Transforms/Utils/Local.cpp | 49 + unittests/VMCore/ConstantsTest.cpp | 9 + unittests/VMCore/InstructionsTest.cpp | 17 - unittests/VMCore/PassManagerTest.cpp | 37 +- unittests/VMCore/ValueMapTest.cpp | 294 + unittests/VMCore/VerifierTest.cpp | 19 + utils/CollectDebugInfoUsingLLDB.py | 182 + utils/CompareDebugInfo.py | 182 + utils/FileCheck/CMakeLists.txt | 2 +- utils/FileCheck/FileCheck.cpp | 65 +- utils/FileCheck/Makefile | 6 +- utils/FileUpdate/CMakeLists.txt | 2 +- utils/FileUpdate/FileUpdate.cpp | 20 +- utils/FileUpdate/Makefile | 6 +- utils/GenLibDeps.pl | 2 - utils/GetRepositoryPath | 27 + utils/GetSourceVersion | 20 +- utils/KillTheDoctor/CMakeLists.txt | 5 + utils/KillTheDoctor/KillTheDoctor.cpp | 596 + utils/Makefile | 2 +- utils/OldenDataRecover.pl | 37 - utils/PerfectShuffle/PerfectShuffle.cpp | 3 +- utils/TableGen/ARMDecoderEmitter.cpp | 313 +- utils/TableGen/ARMDecoderEmitter.h | 2 +- utils/TableGen/AsmMatcherEmitter.cpp | 2362 ++- utils/TableGen/AsmWriterEmitter.cpp | 122 +- utils/TableGen/AsmWriterInst.cpp | 112 +- utils/TableGen/AsmWriterInst.h | 36 +- utils/TableGen/CMakeLists.txt | 12 +- utils/TableGen/CallingConvEmitter.cpp | 12 +- utils/TableGen/ClangASTNodesEmitter.h | 2 +- utils/TableGen/ClangAttrEmitter.cpp | 94 +- utils/TableGen/ClangAttrEmitter.h | 13 + utils/TableGen/ClangDiagnosticsEmitter.cpp | 26 +- utils/TableGen/ClangSACheckersEmitter.cpp | 229 + utils/TableGen/ClangSACheckersEmitter.h | 31 + utils/TableGen/CodeEmitterGen.cpp | 253 +- utils/TableGen/CodeEmitterGen.h | 8 +- utils/TableGen/CodeGenDAGPatterns.cpp | 796 +- utils/TableGen/CodeGenDAGPatterns.h | 208 +- utils/TableGen/CodeGenInstruction.cpp | 519 +- utils/TableGen/CodeGenInstruction.h | 231 +- utils/TableGen/CodeGenRegisters.h | 6 + utils/TableGen/CodeGenTarget.cpp | 114 +- utils/TableGen/CodeGenTarget.h | 17 +- utils/TableGen/DAGISelMatcher.cpp | 42 +- utils/TableGen/DAGISelMatcher.h | 368 +- utils/TableGen/DAGISelMatcherEmitter.cpp | 38 +- utils/TableGen/DAGISelMatcherGen.cpp | 273 +- utils/TableGen/DAGISelMatcherOpt.cpp | 18 +- utils/TableGen/DisassemblerEmitter.cpp | 7 +- utils/TableGen/EDEmitter.cpp | 288 +- utils/TableGen/FastISelEmitter.cpp | 70 +- utils/TableGen/FixedLenDecoderEmitter.cpp | 1372 ++ utils/TableGen/FixedLenDecoderEmitter.h | 56 + utils/TableGen/InstrEnumEmitter.cpp | 2 +- utils/TableGen/InstrInfoEmitter.cpp | 33 +- utils/TableGen/IntrinsicEmitter.cpp | 204 +- utils/TableGen/LLVMCConfigurationEmitter.cpp | 335 +- utils/TableGen/LLVMCConfigurationEmitter.h | 4 +- utils/TableGen/Makefile | 2 +- utils/TableGen/NeonEmitter.cpp | 1059 +- utils/TableGen/NeonEmitter.h | 78 +- utils/TableGen/Record.cpp | 200 +- utils/TableGen/Record.h | 42 +- utils/TableGen/RegisterInfoEmitter.cpp | 24 +- utils/TableGen/StringMatcher.cpp | 149 + utils/TableGen/StringMatcher.h | 54 + utils/TableGen/SubtargetEmitter.cpp | 106 +- utils/TableGen/SubtargetEmitter.h | 7 +- utils/TableGen/TGLexer.cpp | 68 +- utils/TableGen/TGLexer.h | 15 +- utils/TableGen/TGParser.cpp | 268 +- utils/TableGen/TGParser.h | 12 +- utils/TableGen/TableGen.cpp | 49 +- utils/TableGen/X86DisassemblerTables.cpp | 16 +- utils/TableGen/X86ModRMFilters.h | 2 +- utils/TableGen/X86RecognizableInstr.cpp | 33 +- utils/TableGen/X86RecognizableInstr.h | 5 +- utils/Target/ARM/analyze-match-table.py | 61 + utils/buildit/build_llvm | 14 +- utils/emacs/llvm-mode.el | 17 +- utils/emacs/tablegen-mode.el | 14 +- utils/findmisopt | 4 +- utils/findoptdiff | 6 +- utils/fpcmp/Makefile | 6 +- utils/kate/README | 12 + utils/kate/llvm.xml | 255 + utils/lit/TODO | 10 - utils/lit/lit/LitConfig.py | 19 + utils/lit/lit/LitFormats.py | 1 + utils/lit/lit/TestFormats.py | 23 +- utils/lit/lit/TestRunner.py | 21 +- utils/lit/lit/TestingConfig.py | 2 + utils/lit/lit/Util.py | 18 +- utils/lit/lit/__init__.py | 6 +- utils/lit/lit/lit.py | 648 - utils/lit/lit/main.py | 648 + utils/lit/setup.py | 23 +- utils/llvm-lit/CMakeLists.txt | 12 + utils/llvm-lit/llvm-lit.in | 6 + utils/llvm-native-gcc | 4 +- utils/llvm-native-gxx | 4 +- utils/not/CMakeLists.txt | 2 +- utils/not/Makefile | 6 +- utils/not/not.cpp | 16 +- utils/profile.pl | 4 +- utils/release/test-release.sh | 398 + utils/test_debuginfo.pl | 61 + utils/unittest/CMakeLists.txt | 41 + utils/unittest/UnitTestMain/TestMain.cpp | 27 + utils/unittest/googletest/gtest.cc | 35 +- .../googletest/include/gtest/internal/gtest-port.h | 3 +- utils/valgrind/x86_64-pc-linux-gnu.supp | 8 +- utils/vim/llvm.vim | 3 +- utils/vim/vimrc | 9 +- 3241 files changed, 240491 insertions(+), 160008 deletions(-) create mode 100644 .gitignore delete mode 100644 bindings/ada/analysis/llvm_analysis-binding.ads delete mode 100644 bindings/ada/analysis/llvm_analysis.ads delete mode 100644 bindings/ada/analysis/llvm_analysis_wrap.cxx delete mode 100644 bindings/ada/bitreader/llvm_bit_reader-binding.ads delete mode 100644 bindings/ada/bitreader/llvm_bit_reader.ads delete mode 100644 bindings/ada/bitreader/llvm_bitreader_wrap.cxx delete mode 100644 bindings/ada/bitwriter/llvm_bit_writer-binding.ads delete mode 100644 bindings/ada/bitwriter/llvm_bit_writer.ads delete mode 100644 bindings/ada/bitwriter/llvm_bitwriter_wrap.cxx delete mode 100644 bindings/ada/executionengine/llvm_execution_engine-binding.ads delete mode 100644 bindings/ada/executionengine/llvm_execution_engine.ads delete mode 100644 bindings/ada/executionengine/llvm_executionengine_wrap.cxx delete mode 100644 bindings/ada/llvm.gpr delete mode 100644 bindings/ada/llvm/llvm-binding.ads delete mode 100644 bindings/ada/llvm/llvm.ads delete mode 100644 bindings/ada/llvm/llvm_link_time_optimizer-binding.ads delete mode 100644 bindings/ada/llvm/llvm_link_time_optimizer.ads delete mode 100644 bindings/ada/llvm/llvm_linktimeoptimizer_wrap.cxx delete mode 100644 bindings/ada/llvm/llvm_wrap.cxx delete mode 100644 bindings/ada/target/llvm_target-binding.ads delete mode 100644 bindings/ada/target/llvm_target.ads delete mode 100644 bindings/ada/target/llvm_target_wrap.cxx delete mode 100644 bindings/ada/transforms/llvm_transforms-binding.ads delete mode 100644 bindings/ada/transforms/llvm_transforms.ads delete mode 100644 bindings/ada/transforms/llvm_transforms_wrap.cxx create mode 100644 cmake/modules/HandleLLVMOptions.cmake create mode 100644 cmake/modules/LLVMParseArguments.cmake create mode 100644 docs/tutorial/OCamlLangImpl8.html create mode 100644 include/llvm-c/Initialization.h create mode 100644 include/llvm/ADT/ArrayRef.h create mode 100644 include/llvm/ADT/InMemoryStruct.h create mode 100644 include/llvm/ADT/IntEqClasses.h create mode 100644 include/llvm/ADT/IntervalMap.h create mode 100644 include/llvm/Analysis/DIBuilder.h create mode 100644 include/llvm/Analysis/DominanceFrontier.h create mode 100644 include/llvm/Analysis/PathNumbering.h create mode 100644 include/llvm/Analysis/PathProfileInfo.h delete mode 100644 include/llvm/Analysis/PointerTracking.h create mode 100644 include/llvm/Analysis/RegionPass.h create mode 100644 include/llvm/CodeGen/EdgeBundles.h create mode 100644 include/llvm/CodeGen/MachineLoopRanges.h create mode 100644 include/llvm/CodeGen/PBQP/Graph.h create mode 100644 include/llvm/CodeGen/PBQP/HeuristicBase.h create mode 100644 include/llvm/CodeGen/PBQP/HeuristicSolver.h create mode 100644 include/llvm/CodeGen/PBQP/Heuristics/Briggs.h create mode 100644 include/llvm/CodeGen/PBQP/Math.h create mode 100644 include/llvm/CodeGen/PBQP/Solution.h delete mode 100644 include/llvm/CodeGen/PostRAHazardRecognizer.h create mode 100644 include/llvm/CodeGen/RegAllocPBQP.h create mode 100644 include/llvm/CodeGen/ScoreboardHazardRecognizer.h create mode 100644 include/llvm/ExecutionEngine/MCJIT.h create mode 100644 include/llvm/InitializePasses.h delete mode 100644 include/llvm/MC/ELFObjectWriter.h create mode 100644 include/llvm/MC/MCELFObjectWriter.h create mode 100644 include/llvm/MC/MCFixupKindInfo.h create mode 100644 include/llvm/MC/MCMachObjectWriter.h delete mode 100644 include/llvm/MC/MachObjectWriter.h create mode 100644 include/llvm/Object/MachOFormat.h create mode 100644 include/llvm/Object/MachOObject.h create mode 100644 include/llvm/Object/ObjectFile.h create mode 100644 include/llvm/Support/AIXDataTypesFix.h create mode 100644 include/llvm/Support/Atomic.h create mode 100644 include/llvm/Support/DataTypes.h.cmake create mode 100644 include/llvm/Support/DataTypes.h.in create mode 100644 include/llvm/Support/Disassembler.h create mode 100644 include/llvm/Support/DynamicLibrary.h delete mode 100644 include/llvm/Support/DynamicLinker.h create mode 100644 include/llvm/Support/Endian.h create mode 100644 include/llvm/Support/Errno.h create mode 100644 include/llvm/Support/FEnv.h create mode 100644 include/llvm/Support/FileSystem.h create mode 100644 include/llvm/Support/Host.h create mode 100644 include/llvm/Support/IncludeFile.h create mode 100644 include/llvm/Support/LICENSE.TXT create mode 100644 include/llvm/Support/Memory.h create mode 100644 include/llvm/Support/Mutex.h create mode 100644 include/llvm/Support/Path.h create mode 100644 include/llvm/Support/PathV1.h create mode 100644 include/llvm/Support/PathV2.h create mode 100644 include/llvm/Support/Process.h create mode 100644 include/llvm/Support/Program.h create mode 100644 include/llvm/Support/RWMutex.h create mode 100644 include/llvm/Support/Signals.h create mode 100644 include/llvm/Support/Solaris.h delete mode 100644 include/llvm/Support/StableBasicBlockNumbering.h create mode 100644 include/llvm/Support/SwapByteOrder.h create mode 100644 include/llvm/Support/ThreadLocal.h create mode 100644 include/llvm/Support/Threading.h create mode 100644 include/llvm/Support/TimeValue.h create mode 100644 include/llvm/Support/ToolOutputFile.h create mode 100644 include/llvm/Support/Valgrind.h create mode 100644 include/llvm/Support/system_error.h delete mode 100644 include/llvm/System/AIXDataTypesFix.h delete mode 100644 include/llvm/System/Alarm.h delete mode 100644 include/llvm/System/Atomic.h delete mode 100644 include/llvm/System/DataTypes.h.cmake delete mode 100644 include/llvm/System/DataTypes.h.in delete mode 100644 include/llvm/System/Disassembler.h delete mode 100644 include/llvm/System/DynamicLibrary.h delete mode 100644 include/llvm/System/Errno.h delete mode 100644 include/llvm/System/Host.h delete mode 100644 include/llvm/System/IncludeFile.h delete mode 100644 include/llvm/System/LICENSE.TXT delete mode 100644 include/llvm/System/Memory.h delete mode 100644 include/llvm/System/Mutex.h delete mode 100644 include/llvm/System/Path.h delete mode 100644 include/llvm/System/Process.h delete mode 100644 include/llvm/System/Program.h delete mode 100644 include/llvm/System/RWMutex.h delete mode 100644 include/llvm/System/Signals.h delete mode 100644 include/llvm/System/Solaris.h delete mode 100644 include/llvm/System/ThreadLocal.h delete mode 100644 include/llvm/System/Threading.h delete mode 100644 include/llvm/System/TimeValue.h delete mode 100644 include/llvm/System/Valgrind.h create mode 100644 include/llvm/Target/TargetAsmInfo.h delete mode 100644 include/llvm/Target/TargetFrameInfo.h create mode 100644 include/llvm/Target/TargetFrameLowering.h create mode 100644 include/llvm/Target/TargetLibraryInfo.h delete mode 100644 include/llvm/Transforms/RSProfiling.h create mode 100644 lib/Analysis/DIBuilder.cpp create mode 100644 lib/Analysis/DominanceFrontier.cpp create mode 100644 lib/Analysis/IPA/IPA.cpp create mode 100644 lib/Analysis/MemDepPrinter.cpp create mode 100644 lib/Analysis/NoAliasAnalysis.cpp create mode 100644 lib/Analysis/PathNumbering.cpp create mode 100644 lib/Analysis/PathProfileInfo.cpp create mode 100644 lib/Analysis/PathProfileVerifier.cpp delete mode 100644 lib/Analysis/PointerTracking.cpp create mode 100644 lib/Analysis/RegionPass.cpp create mode 100644 lib/Bitcode/CMakeLists.txt create mode 100644 lib/CMakeLists.txt create mode 100644 lib/CodeGen/AllocationOrder.cpp create mode 100644 lib/CodeGen/AllocationOrder.h create mode 100644 lib/CodeGen/AsmPrinter/DwarfCFIException.cpp create mode 100644 lib/CodeGen/AsmPrinter/DwarfTableException.cpp create mode 100644 lib/CodeGen/CodeGen.cpp create mode 100644 lib/CodeGen/EdgeBundles.cpp create mode 100644 lib/CodeGen/ExpandISelPseudos.cpp create mode 100644 lib/CodeGen/LiveDebugVariables.cpp create mode 100644 lib/CodeGen/LiveDebugVariables.h create mode 100644 lib/CodeGen/LiveIntervalUnion.cpp create mode 100644 lib/CodeGen/LiveIntervalUnion.h create mode 100644 lib/CodeGen/LiveRangeEdit.cpp create mode 100644 lib/CodeGen/LiveRangeEdit.h create mode 100644 lib/CodeGen/MachineLoopRanges.cpp delete mode 100644 lib/CodeGen/PBQP/Graph.h delete mode 100644 lib/CodeGen/PBQP/HeuristicBase.h delete mode 100644 lib/CodeGen/PBQP/HeuristicSolver.h delete mode 100644 lib/CodeGen/PBQP/Heuristics/Briggs.h delete mode 100644 lib/CodeGen/PBQP/Math.h delete mode 100644 lib/CodeGen/PBQP/Solution.h delete mode 100644 lib/CodeGen/PHIElimination.h create mode 100644 lib/CodeGen/PHIEliminationUtils.cpp create mode 100644 lib/CodeGen/PHIEliminationUtils.h delete mode 100644 lib/CodeGen/PostRAHazardRecognizer.cpp create mode 100644 lib/CodeGen/RegAllocBase.h create mode 100644 lib/CodeGen/RegAllocBasic.cpp create mode 100644 lib/CodeGen/RegAllocGreedy.cpp create mode 100644 lib/CodeGen/ScoreboardHazardRecognizer.cpp create mode 100644 lib/CodeGen/SpillPlacement.cpp create mode 100644 lib/CodeGen/SpillPlacement.h create mode 100644 lib/ExecutionEngine/MCJIT/CMakeLists.txt create mode 100644 lib/ExecutionEngine/MCJIT/MCJIT.cpp create mode 100644 lib/ExecutionEngine/MCJIT/MCJIT.h create mode 100644 lib/ExecutionEngine/MCJIT/Makefile create mode 100644 lib/ExecutionEngine/MCJIT/TargetSelect.cpp create mode 100644 lib/MC/MCELFObjectTargetWriter.cpp create mode 100644 lib/MC/MCMachObjectTargetWriter.cpp create mode 100644 lib/MC/MCParser/COFFAsmParser.cpp create mode 100644 lib/MC/MCPureStreamer.cpp create mode 100644 lib/Object/CMakeLists.txt create mode 100644 lib/Object/COFFObjectFile.cpp create mode 100644 lib/Object/ELFObjectFile.cpp create mode 100644 lib/Object/MachOObject.cpp create mode 100644 lib/Object/Makefile create mode 100644 lib/Object/ObjectFile.cpp create mode 100644 lib/Support/Atomic.cpp create mode 100644 lib/Support/Disassembler.cpp create mode 100644 lib/Support/DynamicLibrary.cpp create mode 100644 lib/Support/Errno.cpp create mode 100644 lib/Support/Host.cpp create mode 100644 lib/Support/IncludeFile.cpp create mode 100644 lib/Support/IntEqClasses.cpp create mode 100644 lib/Support/IntervalMap.cpp create mode 100644 lib/Support/Memory.cpp create mode 100644 lib/Support/Mutex.cpp create mode 100644 lib/Support/Path.cpp create mode 100644 lib/Support/PathV2.cpp create mode 100644 lib/Support/Process.cpp create mode 100644 lib/Support/Program.cpp create mode 100644 lib/Support/README.txt.system create mode 100644 lib/Support/RWMutex.cpp create mode 100644 lib/Support/SearchForAddressOfSpecialSymbol.cpp create mode 100644 lib/Support/Signals.cpp create mode 100644 lib/Support/ThreadLocal.cpp create mode 100644 lib/Support/Threading.cpp create mode 100644 lib/Support/TimeValue.cpp create mode 100644 lib/Support/ToolOutputFile.cpp create mode 100644 lib/Support/Unix/Host.inc create mode 100644 lib/Support/Unix/Memory.inc create mode 100644 lib/Support/Unix/Mutex.inc create mode 100644 lib/Support/Unix/Path.inc create mode 100644 lib/Support/Unix/PathV2.inc create mode 100644 lib/Support/Unix/Process.inc create mode 100644 lib/Support/Unix/Program.inc create mode 100644 lib/Support/Unix/README.txt create mode 100644 lib/Support/Unix/RWMutex.inc create mode 100644 lib/Support/Unix/Signals.inc create mode 100644 lib/Support/Unix/ThreadLocal.inc create mode 100644 lib/Support/Unix/TimeValue.inc create mode 100644 lib/Support/Unix/Unix.h create mode 100644 lib/Support/Unix/system_error.inc create mode 100644 lib/Support/Valgrind.cpp create mode 100644 lib/Support/Windows/DynamicLibrary.inc create mode 100644 lib/Support/Windows/Host.inc create mode 100644 lib/Support/Windows/Memory.inc create mode 100644 lib/Support/Windows/Mutex.inc create mode 100644 lib/Support/Windows/Path.inc create mode 100644 lib/Support/Windows/PathV2.inc create mode 100644 lib/Support/Windows/Process.inc create mode 100644 lib/Support/Windows/Program.inc create mode 100644 lib/Support/Windows/RWMutex.inc create mode 100644 lib/Support/Windows/Signals.inc create mode 100644 lib/Support/Windows/ThreadLocal.inc create mode 100644 lib/Support/Windows/TimeValue.inc create mode 100644 lib/Support/Windows/Windows.h create mode 100644 lib/Support/Windows/explicit_symbols.inc create mode 100644 lib/Support/Windows/system_error.inc create mode 100644 lib/Support/system_error.cpp delete mode 100644 lib/System/Alarm.cpp delete mode 100644 lib/System/Atomic.cpp delete mode 100644 lib/System/CMakeLists.txt delete mode 100644 lib/System/Disassembler.cpp delete mode 100644 lib/System/DynamicLibrary.cpp delete mode 100644 lib/System/Errno.cpp delete mode 100644 lib/System/Host.cpp delete mode 100644 lib/System/IncludeFile.cpp delete mode 100644 lib/System/Makefile delete mode 100644 lib/System/Memory.cpp delete mode 100644 lib/System/Mutex.cpp delete mode 100644 lib/System/Path.cpp delete mode 100644 lib/System/Process.cpp delete mode 100644 lib/System/Program.cpp delete mode 100644 lib/System/README.txt delete mode 100644 lib/System/RWMutex.cpp delete mode 100644 lib/System/SearchForAddressOfSpecialSymbol.cpp delete mode 100644 lib/System/Signals.cpp delete mode 100644 lib/System/ThreadLocal.cpp delete mode 100644 lib/System/Threading.cpp delete mode 100644 lib/System/TimeValue.cpp delete mode 100644 lib/System/Unix/Alarm.inc delete mode 100644 lib/System/Unix/Host.inc delete mode 100644 lib/System/Unix/Memory.inc delete mode 100644 lib/System/Unix/Mutex.inc delete mode 100644 lib/System/Unix/Path.inc delete mode 100644 lib/System/Unix/Process.inc delete mode 100644 lib/System/Unix/Program.inc delete mode 100644 lib/System/Unix/README.txt delete mode 100644 lib/System/Unix/RWMutex.inc delete mode 100644 lib/System/Unix/Signals.inc delete mode 100644 lib/System/Unix/ThreadLocal.inc delete mode 100644 lib/System/Unix/TimeValue.inc delete mode 100644 lib/System/Unix/Unix.h delete mode 100644 lib/System/Valgrind.cpp delete mode 100644 lib/System/Win32/Alarm.inc delete mode 100644 lib/System/Win32/DynamicLibrary.inc delete mode 100644 lib/System/Win32/Host.inc delete mode 100644 lib/System/Win32/Memory.inc delete mode 100644 lib/System/Win32/Mutex.inc delete mode 100644 lib/System/Win32/Path.inc delete mode 100644 lib/System/Win32/Process.inc delete mode 100644 lib/System/Win32/Program.inc delete mode 100644 lib/System/Win32/RWMutex.inc delete mode 100644 lib/System/Win32/Signals.inc delete mode 100644 lib/System/Win32/ThreadLocal.inc delete mode 100644 lib/System/Win32/TimeValue.inc delete mode 100644 lib/System/Win32/Win32.h create mode 100644 lib/Target/ARM/ARMAsmBackend.cpp create mode 100644 lib/Target/ARM/ARMAsmPrinter.h create mode 100644 lib/Target/ARM/ARMBaseInfo.h create mode 100644 lib/Target/ARM/ARMCallingConv.h create mode 100644 lib/Target/ARM/ARMELFWriterInfo.cpp create mode 100644 lib/Target/ARM/ARMELFWriterInfo.h create mode 100644 lib/Target/ARM/ARMFixupKinds.h delete mode 100644 lib/Target/ARM/ARMFrameInfo.h create mode 100644 lib/Target/ARM/ARMFrameLowering.cpp create mode 100644 lib/Target/ARM/ARMFrameLowering.h create mode 100644 lib/Target/ARM/ARMHazardRecognizer.cpp create mode 100644 lib/Target/ARM/ARMHazardRecognizer.h create mode 100644 lib/Target/ARM/ARMMCCodeEmitter.cpp create mode 100644 lib/Target/ARM/ARMMCExpr.cpp create mode 100644 lib/Target/ARM/ARMMCExpr.h delete mode 100644 lib/Target/ARM/ARMMCInstLower.h delete mode 100644 lib/Target/ARM/AsmPrinter/ARMInstPrinter.cpp delete mode 100644 lib/Target/ARM/AsmPrinter/ARMInstPrinter.h delete mode 100644 lib/Target/ARM/AsmPrinter/CMakeLists.txt delete mode 100644 lib/Target/ARM/AsmPrinter/Makefile create mode 100644 lib/Target/ARM/Disassembler/CMakeLists.txt create mode 100644 lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp create mode 100644 lib/Target/ARM/InstPrinter/ARMInstPrinter.h create mode 100644 lib/Target/ARM/InstPrinter/CMakeLists.txt create mode 100644 lib/Target/ARM/InstPrinter/Makefile create mode 100644 lib/Target/ARM/MLxExpansionPass.cpp delete mode 100644 lib/Target/ARM/NEONPreAllocPass.cpp create mode 100644 lib/Target/ARM/Thumb1FrameLowering.cpp create mode 100644 lib/Target/ARM/Thumb1FrameLowering.h delete mode 100644 lib/Target/ARM/Thumb2HazardRecognizer.cpp delete mode 100644 lib/Target/ARM/Thumb2HazardRecognizer.h create mode 100644 lib/Target/Alpha/AlphaAsmPrinter.cpp delete mode 100644 lib/Target/Alpha/AlphaCodeEmitter.cpp create mode 100644 lib/Target/Alpha/AlphaFrameLowering.cpp create mode 100644 lib/Target/Alpha/AlphaFrameLowering.h delete mode 100644 lib/Target/Alpha/AlphaJITInfo.cpp delete mode 100644 lib/Target/Alpha/AlphaJITInfo.h delete mode 100644 lib/Target/Alpha/AsmPrinter/AlphaAsmPrinter.cpp delete mode 100644 lib/Target/Alpha/AsmPrinter/CMakeLists.txt delete mode 100644 lib/Target/Alpha/AsmPrinter/Makefile delete mode 100644 lib/Target/Blackfin/AsmPrinter/BlackfinAsmPrinter.cpp delete mode 100644 lib/Target/Blackfin/AsmPrinter/CMakeLists.txt delete mode 100644 lib/Target/Blackfin/AsmPrinter/Makefile create mode 100644 lib/Target/Blackfin/BlackfinAsmPrinter.cpp create mode 100644 lib/Target/Blackfin/BlackfinFrameLowering.cpp create mode 100644 lib/Target/Blackfin/BlackfinFrameLowering.h delete mode 100644 lib/Target/CellSPU/AsmPrinter/CMakeLists.txt delete mode 100644 lib/Target/CellSPU/AsmPrinter/Makefile delete mode 100644 lib/Target/CellSPU/AsmPrinter/SPUAsmPrinter.cpp create mode 100644 lib/Target/CellSPU/SPUAsmPrinter.cpp delete mode 100644 lib/Target/CellSPU/SPUFrameInfo.cpp delete mode 100644 lib/Target/CellSPU/SPUFrameInfo.h create mode 100644 lib/Target/CellSPU/SPUFrameLowering.cpp create mode 100644 lib/Target/CellSPU/SPUFrameLowering.h create mode 100644 lib/Target/CellSPU/SPUNopFiller.cpp create mode 100644 lib/Target/MBlaze/AsmParser/CMakeLists.txt create mode 100644 lib/Target/MBlaze/AsmParser/MBlazeAsmLexer.cpp create mode 100644 lib/Target/MBlaze/AsmParser/MBlazeAsmParser.cpp create mode 100644 lib/Target/MBlaze/AsmParser/Makefile delete mode 100644 lib/Target/MBlaze/AsmPrinter/CMakeLists.txt delete mode 100644 lib/Target/MBlaze/AsmPrinter/MBlazeAsmPrinter.cpp delete mode 100644 lib/Target/MBlaze/AsmPrinter/Makefile create mode 100644 lib/Target/MBlaze/Disassembler/CMakeLists.txt create mode 100644 lib/Target/MBlaze/Disassembler/MBlazeDisassembler.cpp create mode 100644 lib/Target/MBlaze/Disassembler/MBlazeDisassembler.h create mode 100644 lib/Target/MBlaze/Disassembler/Makefile create mode 100644 lib/Target/MBlaze/InstPrinter/CMakeLists.txt create mode 100644 lib/Target/MBlaze/InstPrinter/MBlazeInstPrinter.cpp create mode 100644 lib/Target/MBlaze/InstPrinter/MBlazeInstPrinter.h create mode 100644 lib/Target/MBlaze/InstPrinter/Makefile create mode 100644 lib/Target/MBlaze/MBlazeAsmBackend.cpp create mode 100644 lib/Target/MBlaze/MBlazeAsmPrinter.cpp create mode 100644 lib/Target/MBlaze/MBlazeELFWriterInfo.cpp create mode 100644 lib/Target/MBlaze/MBlazeELFWriterInfo.h create mode 100644 lib/Target/MBlaze/MBlazeFrameLowering.cpp create mode 100644 lib/Target/MBlaze/MBlazeFrameLowering.h create mode 100644 lib/Target/MBlaze/MBlazeMCCodeEmitter.cpp create mode 100644 lib/Target/MBlaze/MBlazeMCInstLower.cpp create mode 100644 lib/Target/MBlaze/MBlazeMCInstLower.h create mode 100644 lib/Target/MBlaze/MBlazeRelocations.h create mode 100644 lib/Target/MBlaze/TODO delete mode 100644 lib/Target/MSP430/AsmPrinter/CMakeLists.txt delete mode 100644 lib/Target/MSP430/AsmPrinter/MSP430AsmPrinter.cpp delete mode 100644 lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.cpp delete mode 100644 lib/Target/MSP430/AsmPrinter/MSP430InstPrinter.h delete mode 100644 lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.cpp delete mode 100644 lib/Target/MSP430/AsmPrinter/MSP430MCInstLower.h delete mode 100644 lib/Target/MSP430/AsmPrinter/Makefile create mode 100644 lib/Target/MSP430/InstPrinter/CMakeLists.txt create mode 100644 lib/Target/MSP430/InstPrinter/MSP430InstPrinter.cpp create mode 100644 lib/Target/MSP430/InstPrinter/MSP430InstPrinter.h create mode 100644 lib/Target/MSP430/InstPrinter/Makefile create mode 100644 lib/Target/MSP430/MSP430AsmPrinter.cpp create mode 100644 lib/Target/MSP430/MSP430FrameLowering.cpp create mode 100644 lib/Target/MSP430/MSP430FrameLowering.h create mode 100644 lib/Target/MSP430/MSP430MCInstLower.cpp create mode 100644 lib/Target/MSP430/MSP430MCInstLower.h delete mode 100644 lib/Target/Mips/AsmPrinter/CMakeLists.txt delete mode 100644 lib/Target/Mips/AsmPrinter/Makefile delete mode 100644 lib/Target/Mips/AsmPrinter/MipsAsmPrinter.cpp create mode 100644 lib/Target/Mips/MipsAsmPrinter.cpp create mode 100644 lib/Target/Mips/MipsFrameLowering.cpp create mode 100644 lib/Target/Mips/MipsFrameLowering.h delete mode 100644 lib/Target/PIC16/AsmPrinter/CMakeLists.txt delete mode 100644 lib/Target/PIC16/AsmPrinter/Makefile delete mode 100644 lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.cpp delete mode 100644 lib/Target/PIC16/AsmPrinter/PIC16AsmPrinter.h delete mode 100644 lib/Target/PIC16/CMakeLists.txt delete mode 100644 lib/Target/PIC16/Makefile delete mode 100644 lib/Target/PIC16/PIC16.h delete mode 100644 lib/Target/PIC16/PIC16.td delete mode 100644 lib/Target/PIC16/PIC16ABINames.h delete mode 100644 lib/Target/PIC16/PIC16DebugInfo.cpp delete mode 100644 lib/Target/PIC16/PIC16DebugInfo.h delete mode 100644 lib/Target/PIC16/PIC16ISelDAGToDAG.cpp delete mode 100644 lib/Target/PIC16/PIC16ISelDAGToDAG.h delete mode 100644 lib/Target/PIC16/PIC16ISelLowering.cpp delete mode 100644 lib/Target/PIC16/PIC16ISelLowering.h delete mode 100644 lib/Target/PIC16/PIC16InstrFormats.td delete mode 100644 lib/Target/PIC16/PIC16InstrInfo.cpp delete mode 100644 lib/Target/PIC16/PIC16InstrInfo.h delete mode 100644 lib/Target/PIC16/PIC16InstrInfo.td delete mode 100644 lib/Target/PIC16/PIC16MCAsmInfo.cpp delete mode 100644 lib/Target/PIC16/PIC16MCAsmInfo.h delete mode 100644 lib/Target/PIC16/PIC16MachineFunctionInfo.h delete mode 100644 lib/Target/PIC16/PIC16MemSelOpt.cpp delete mode 100644 lib/Target/PIC16/PIC16Passes/Makefile delete mode 100644 lib/Target/PIC16/PIC16Passes/PIC16Cloner.cpp delete mode 100644 lib/Target/PIC16/PIC16Passes/PIC16Cloner.h delete mode 100644 lib/Target/PIC16/PIC16Passes/PIC16Overlay.cpp delete mode 100644 lib/Target/PIC16/PIC16Passes/PIC16Overlay.h delete mode 100644 lib/Target/PIC16/PIC16RegisterInfo.cpp delete mode 100644 lib/Target/PIC16/PIC16RegisterInfo.h delete mode 100644 lib/Target/PIC16/PIC16RegisterInfo.td delete mode 100644 lib/Target/PIC16/PIC16Section.cpp delete mode 100644 lib/Target/PIC16/PIC16Section.h delete mode 100644 lib/Target/PIC16/PIC16SelectionDAGInfo.cpp delete mode 100644 lib/Target/PIC16/PIC16SelectionDAGInfo.h delete mode 100644 lib/Target/PIC16/PIC16Subtarget.cpp delete mode 100644 lib/Target/PIC16/PIC16Subtarget.h delete mode 100644 lib/Target/PIC16/PIC16TargetMachine.cpp delete mode 100644 lib/Target/PIC16/PIC16TargetMachine.h delete mode 100644 lib/Target/PIC16/PIC16TargetObjectFile.cpp delete mode 100644 lib/Target/PIC16/PIC16TargetObjectFile.h delete mode 100644 lib/Target/PIC16/TargetInfo/CMakeLists.txt delete mode 100644 lib/Target/PIC16/TargetInfo/Makefile delete mode 100644 lib/Target/PIC16/TargetInfo/PIC16TargetInfo.cpp create mode 100644 lib/Target/PTX/CMakeLists.txt create mode 100644 lib/Target/PTX/Makefile create mode 100644 lib/Target/PTX/PTX.h create mode 100644 lib/Target/PTX/PTX.td create mode 100644 lib/Target/PTX/PTXAsmPrinter.cpp create mode 100644 lib/Target/PTX/PTXFrameLowering.cpp create mode 100644 lib/Target/PTX/PTXFrameLowering.h create mode 100644 lib/Target/PTX/PTXISelDAGToDAG.cpp create mode 100644 lib/Target/PTX/PTXISelLowering.cpp create mode 100644 lib/Target/PTX/PTXISelLowering.h create mode 100644 lib/Target/PTX/PTXInstrFormats.td create mode 100644 lib/Target/PTX/PTXInstrInfo.cpp create mode 100644 lib/Target/PTX/PTXInstrInfo.h create mode 100644 lib/Target/PTX/PTXInstrInfo.td create mode 100644 lib/Target/PTX/PTXMCAsmInfo.cpp create mode 100644 lib/Target/PTX/PTXMCAsmInfo.h create mode 100644 lib/Target/PTX/PTXMCAsmStreamer.cpp create mode 100644 lib/Target/PTX/PTXMFInfoExtract.cpp create mode 100644 lib/Target/PTX/PTXMachineFunctionInfo.h create mode 100644 lib/Target/PTX/PTXRegisterInfo.cpp create mode 100644 lib/Target/PTX/PTXRegisterInfo.h create mode 100644 lib/Target/PTX/PTXRegisterInfo.td create mode 100644 lib/Target/PTX/PTXSubtarget.cpp create mode 100644 lib/Target/PTX/PTXSubtarget.h create mode 100644 lib/Target/PTX/PTXTargetMachine.cpp create mode 100644 lib/Target/PTX/PTXTargetMachine.h create mode 100644 lib/Target/PTX/TargetInfo/CMakeLists.txt create mode 100644 lib/Target/PTX/TargetInfo/Makefile create mode 100644 lib/Target/PTX/TargetInfo/PTXTargetInfo.cpp delete mode 100644 lib/Target/PowerPC/AsmPrinter/CMakeLists.txt delete mode 100644 lib/Target/PowerPC/AsmPrinter/Makefile delete mode 100644 lib/Target/PowerPC/AsmPrinter/PPCAsmPrinter.cpp create mode 100644 lib/Target/PowerPC/InstPrinter/CMakeLists.txt create mode 100644 lib/Target/PowerPC/InstPrinter/Makefile create mode 100644 lib/Target/PowerPC/InstPrinter/PPCInstPrinter.cpp create mode 100644 lib/Target/PowerPC/InstPrinter/PPCInstPrinter.h create mode 100644 lib/Target/PowerPC/PPCAsmBackend.cpp create mode 100644 lib/Target/PowerPC/PPCAsmPrinter.cpp create mode 100644 lib/Target/PowerPC/PPCFixupKinds.h delete mode 100644 lib/Target/PowerPC/PPCFrameInfo.h create mode 100644 lib/Target/PowerPC/PPCFrameLowering.cpp create mode 100644 lib/Target/PowerPC/PPCFrameLowering.h create mode 100644 lib/Target/PowerPC/PPCMCCodeEmitter.cpp create mode 100644 lib/Target/PowerPC/PPCMCInstLower.cpp delete mode 100644 lib/Target/Sparc/AsmPrinter/CMakeLists.txt delete mode 100644 lib/Target/Sparc/AsmPrinter/Makefile delete mode 100644 lib/Target/Sparc/AsmPrinter/SparcAsmPrinter.cpp create mode 100644 lib/Target/Sparc/SparcAsmPrinter.cpp create mode 100644 lib/Target/Sparc/SparcFrameLowering.cpp create mode 100644 lib/Target/Sparc/SparcFrameLowering.h delete mode 100644 lib/Target/SystemZ/AsmPrinter/CMakeLists.txt delete mode 100644 lib/Target/SystemZ/AsmPrinter/Makefile delete mode 100644 lib/Target/SystemZ/AsmPrinter/SystemZAsmPrinter.cpp create mode 100644 lib/Target/SystemZ/SystemZAsmPrinter.cpp create mode 100644 lib/Target/SystemZ/SystemZFrameLowering.cpp create mode 100644 lib/Target/SystemZ/SystemZFrameLowering.h create mode 100644 lib/Target/TargetAsmInfo.cpp delete mode 100644 lib/Target/TargetFrameInfo.cpp create mode 100644 lib/Target/TargetFrameLowering.cpp create mode 100644 lib/Target/TargetLibraryInfo.cpp delete mode 100644 lib/Target/X86/AsmPrinter/CMakeLists.txt delete mode 100644 lib/Target/X86/AsmPrinter/Makefile delete mode 100644 lib/Target/X86/AsmPrinter/X86ATTInstPrinter.cpp delete mode 100644 lib/Target/X86/AsmPrinter/X86ATTInstPrinter.h delete mode 100644 lib/Target/X86/AsmPrinter/X86InstComments.cpp delete mode 100644 lib/Target/X86/AsmPrinter/X86InstComments.h delete mode 100644 lib/Target/X86/AsmPrinter/X86IntelInstPrinter.cpp delete mode 100644 lib/Target/X86/AsmPrinter/X86IntelInstPrinter.h create mode 100644 lib/Target/X86/InstPrinter/CMakeLists.txt create mode 100644 lib/Target/X86/InstPrinter/Makefile create mode 100644 lib/Target/X86/InstPrinter/X86ATTInstPrinter.cpp create mode 100644 lib/Target/X86/InstPrinter/X86ATTInstPrinter.h create mode 100644 lib/Target/X86/InstPrinter/X86InstComments.cpp create mode 100644 lib/Target/X86/InstPrinter/X86InstComments.h create mode 100644 lib/Target/X86/InstPrinter/X86IntelInstPrinter.cpp create mode 100644 lib/Target/X86/InstPrinter/X86IntelInstPrinter.h create mode 100644 lib/Target/X86/Utils/CMakeLists.txt create mode 100644 lib/Target/X86/Utils/Makefile create mode 100644 lib/Target/X86/Utils/X86ShuffleDecode.cpp create mode 100644 lib/Target/X86/Utils/X86ShuffleDecode.h create mode 100644 lib/Target/X86/X86FrameLowering.cpp create mode 100644 lib/Target/X86/X86FrameLowering.h create mode 100644 lib/Target/X86/X86Instr3DNow.td delete mode 100644 lib/Target/X86/X86Instr64bit.td create mode 100644 lib/Target/X86/X86InstrArithmetic.td create mode 100644 lib/Target/X86/X86InstrCMovSetCC.td create mode 100644 lib/Target/X86/X86InstrCompiler.td create mode 100644 lib/Target/X86/X86InstrControl.td create mode 100644 lib/Target/X86/X86InstrExtension.td create mode 100644 lib/Target/X86/X86InstrShiftRotate.td create mode 100644 lib/Target/X86/X86InstrSystem.td create mode 100644 lib/Target/X86/X86InstrVMX.td create mode 100644 lib/Target/X86/X86MachObjectWriter.cpp delete mode 100644 lib/Target/X86/X86ShuffleDecode.h delete mode 100644 lib/Target/XCore/AsmPrinter/CMakeLists.txt delete mode 100644 lib/Target/XCore/AsmPrinter/Makefile delete mode 100644 lib/Target/XCore/AsmPrinter/XCoreAsmPrinter.cpp create mode 100644 lib/Target/XCore/XCoreAsmPrinter.cpp delete mode 100644 lib/Target/XCore/XCoreFrameInfo.cpp delete mode 100644 lib/Target/XCore/XCoreFrameInfo.h create mode 100644 lib/Target/XCore/XCoreFrameLowering.cpp create mode 100644 lib/Target/XCore/XCoreFrameLowering.h create mode 100644 lib/Transforms/CMakeLists.txt delete mode 100644 lib/Transforms/IPO/PartialSpecialization.cpp create mode 100644 lib/Transforms/Instrumentation/Instrumentation.cpp create mode 100644 lib/Transforms/Instrumentation/PathProfiling.cpp create mode 100644 lib/Transforms/Scalar/EarlyCSE.cpp create mode 100644 lib/Transforms/Scalar/LoopIdiomRecognize.cpp delete mode 100644 lib/Transforms/Scalar/LoopIndexSplit.cpp create mode 100644 lib/Transforms/Scalar/LoopInstSimplify.cpp create mode 100644 lib/Transforms/Utils/SimplifyInstructions.cpp create mode 100644 lib/Transforms/Utils/Utils.cpp create mode 100644 lib/VMCore/User.cpp create mode 100644 runtime/libprofile/PathProfiling.c create mode 100644 test/Analysis/BasicAA/2010-09-15-GEP-SignedArithmetic.ll create mode 100644 test/Analysis/BasicAA/full-store-partial-alias.ll delete mode 100644 test/Analysis/PointerTracking/dg.exp delete mode 100644 test/Analysis/PointerTracking/sizes.ll create mode 100644 test/Analysis/ScalarEvolution/2010-09-03-RequiredTransitive.ll create mode 100644 test/Analysis/ScalarEvolution/fold.ll create mode 100644 test/Analysis/TypeBasedAliasAnalysis/aliastest.ll create mode 100644 test/Analysis/TypeBasedAliasAnalysis/argument-promotion.ll create mode 100644 test/Analysis/TypeBasedAliasAnalysis/dg.exp create mode 100644 test/Analysis/TypeBasedAliasAnalysis/dse.ll create mode 100644 test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll create mode 100644 test/Analysis/TypeBasedAliasAnalysis/gvn-nonlocal-type-mismatch.ll create mode 100644 test/Analysis/TypeBasedAliasAnalysis/licm.ll create mode 100644 test/Analysis/TypeBasedAliasAnalysis/memcpyopt.ll create mode 100644 test/Analysis/TypeBasedAliasAnalysis/precedence.ll create mode 100644 test/Analysis/TypeBasedAliasAnalysis/sink.ll delete mode 100644 test/Archive/GNU.toc delete mode 100644 test/Archive/MacOSX.toc delete mode 100644 test/Archive/SVR4.toc delete mode 100644 test/Archive/xpg4.toc create mode 100644 test/Assembler/AutoUpgradeMMXIntrinsics.ll create mode 100644 test/Assembler/extractvalue-invalid-idx.ll create mode 100644 test/Assembler/insertvalue-invalid-idx.ll create mode 100644 test/Assembler/unnamed-addr.ll create mode 100644 test/Assembler/x86mmx.ll create mode 100644 test/Bindings/Ocaml/ext_exc.ml create mode 100644 test/Bitcode/null-type.ll create mode 100644 test/Bitcode/null-type.ll.bc delete mode 100644 test/CodeGen/ARM/2009-08-21-PostRAKill4.ll delete mode 100644 test/CodeGen/ARM/2009-09-01-PostRAProlog.ll delete mode 100644 test/CodeGen/ARM/2010-05-17-DAGCombineAssert.ll delete mode 100644 test/CodeGen/ARM/2010-06-28-DAGCombineUndef.ll create mode 100644 test/CodeGen/ARM/2010-09-21-OptCmpBug.ll create mode 100644 test/CodeGen/ARM/2010-09-29-mc-asm-header-test.ll create mode 100644 test/CodeGen/ARM/2010-10-19-mc-elf-objheader.ll create mode 100644 test/CodeGen/ARM/2010-10-25-ifcvt-ldm.ll create mode 100644 test/CodeGen/ARM/2010-11-15-SpillEarlyClobber.ll create mode 100644 test/CodeGen/ARM/2010-11-29-PrologueBug.ll create mode 100644 test/CodeGen/ARM/2010-11-30-reloc-movt.ll create mode 100644 test/CodeGen/ARM/2010-12-07-PEIBug.ll create mode 100644 test/CodeGen/ARM/2010-12-08-tpsoft.ll create mode 100644 test/CodeGen/ARM/2010-12-13-reloc-pic.ll create mode 100644 test/CodeGen/ARM/2010-12-15-elf-lcomm.ll create mode 100644 test/CodeGen/ARM/2010-12-17-LocalStackSlotCrash.ll create mode 100644 test/CodeGen/ARM/2011-01-19-MergedGlobalDbg.ll create mode 100644 test/CodeGen/ARM/2011-02-04-AntidepMultidef.ll create mode 100644 test/CodeGen/ARM/2011-02-07-AntidepClobber.ll create mode 100644 test/CodeGen/ARM/arm-and-tst-peephole.ll create mode 100644 test/CodeGen/ARM/atomic-cmp.ll create mode 100644 test/CodeGen/ARM/bswap-inline-asm.ll create mode 100644 test/CodeGen/ARM/crash.ll create mode 100644 test/CodeGen/ARM/fast-isel-crash.ll create mode 100644 test/CodeGen/ARM/fast-isel-static.ll create mode 100644 test/CodeGen/ARM/global-merge.ll create mode 100644 test/CodeGen/ARM/ifcvt10.ll create mode 100644 test/CodeGen/ARM/ifcvt11.ll create mode 100644 test/CodeGen/ARM/ldst-f32-2-i32.ll create mode 100644 test/CodeGen/ARM/load-global.ll create mode 100644 test/CodeGen/ARM/machine-licm.ll create mode 100644 test/CodeGen/ARM/mult-alt-generic-arm.ll create mode 100644 test/CodeGen/ARM/neon_div.ll create mode 100644 test/CodeGen/ARM/phi.ll create mode 100644 test/CodeGen/ARM/prefetch.ll delete mode 100644 test/CodeGen/ARM/remat.ll create mode 100644 test/CodeGen/ARM/thumb1-varalloc.ll create mode 100644 test/CodeGen/ARM/umulo-32.ll create mode 100644 test/CodeGen/ARM/vector-DAGCombine.ll create mode 100644 test/CodeGen/ARM/vlddup.ll create mode 100644 test/CodeGen/CellSPU/div_ops.ll create mode 100644 test/CodeGen/Generic/2010-11-04-BigByval.ll create mode 100644 test/CodeGen/Generic/2011-01-06-BigNumberCrash.ll create mode 100644 test/CodeGen/Generic/2011-02-12-shuffle.ll create mode 100644 test/CodeGen/Generic/overflow.ll create mode 100644 test/CodeGen/MBlaze/intr.ll create mode 100644 test/CodeGen/MBlaze/svol.ll create mode 100644 test/CodeGen/MSP430/mult-alt-generic-msp430.ll create mode 100644 test/CodeGen/Mips/2010-11-09-CountLeading.ll create mode 100644 test/CodeGen/Mips/2010-11-09-Mul.ll create mode 100755 test/CodeGen/Mips/cmov.ll create mode 100644 test/CodeGen/Mips/madd-msub.ll create mode 100644 test/CodeGen/Mips/o32_cc.ll create mode 100644 test/CodeGen/Mips/rotate.ll delete mode 100644 test/CodeGen/PIC16/2009-07-17-PR4566-pic16.ll delete mode 100644 test/CodeGen/PIC16/2009-11-20-NewNode.ll delete mode 100644 test/CodeGen/PIC16/C16-11.ll delete mode 100644 test/CodeGen/PIC16/C16-15.ll delete mode 100644 test/CodeGen/PIC16/C16-49.ll delete mode 100644 test/CodeGen/PIC16/check_inc_files.ll delete mode 100644 test/CodeGen/PIC16/dg.exp delete mode 100644 test/CodeGen/PIC16/global-in-user-section.ll delete mode 100644 test/CodeGen/PIC16/globals.ll delete mode 100644 test/CodeGen/PIC16/result_direction.ll delete mode 100644 test/CodeGen/PIC16/sext.ll delete mode 100644 test/CodeGen/PIC16/test_indf_name.ll create mode 100644 test/CodeGen/PTX/add.ll create mode 100644 test/CodeGen/PTX/dg.exp create mode 100644 test/CodeGen/PTX/exit.ll create mode 100644 test/CodeGen/PTX/ld.ll create mode 100644 test/CodeGen/PTX/mov.ll create mode 100644 test/CodeGen/PTX/options.ll create mode 100644 test/CodeGen/PTX/ret.ll create mode 100644 test/CodeGen/PTX/shl.ll create mode 100644 test/CodeGen/PTX/shr.ll create mode 100644 test/CodeGen/PTX/st.ll create mode 100644 test/CodeGen/PTX/sub.ll create mode 100644 test/CodeGen/PowerPC/2010-10-11-Fast-Varargs.ll create mode 100644 test/CodeGen/PowerPC/2010-12-18-PPCStackRefs.ll create mode 100644 test/CodeGen/PowerPC/mult-alt-generic-powerpc.ll create mode 100644 test/CodeGen/PowerPC/mult-alt-generic-powerpc64.ll delete mode 100644 test/CodeGen/PowerPC/tango.net.ftp.FtpClient.ll create mode 100644 test/CodeGen/PowerPC/varargs.ll create mode 100755 test/CodeGen/SPARC/2011-01-11-CC.ll create mode 100644 test/CodeGen/SPARC/2011-01-11-Call.ll create mode 100644 test/CodeGen/SPARC/2011-01-11-FrameAddr.ll create mode 100644 test/CodeGen/SPARC/2011-01-19-DelaySlot.ll create mode 100644 test/CodeGen/SPARC/2011-01-21-ByValArgs.ll create mode 100644 test/CodeGen/SPARC/2011-01-22-SRet.ll create mode 100644 test/CodeGen/SPARC/mult-alt-generic-sparc.ll delete mode 100644 test/CodeGen/SPARC/xnor.ll create mode 100644 test/CodeGen/Thumb/2011-EpilogueBug.ll delete mode 100644 test/CodeGen/Thumb/machine-licm.ll create mode 100644 test/CodeGen/Thumb2/2009-08-21-PostRAKill4.ll create mode 100644 test/CodeGen/Thumb2/2009-09-01-PostRAProlog.ll create mode 100644 test/CodeGen/Thumb2/2010-11-22-EpilogueBug.ll create mode 100644 test/CodeGen/Thumb2/2010-12-03-AddSPNarrowing.ll create mode 100644 test/CodeGen/Thumb2/buildvector-crash.ll delete mode 100644 test/CodeGen/Thumb2/load-global.ll delete mode 100644 test/CodeGen/Thumb2/machine-licm-vdup.ll delete mode 100644 test/CodeGen/Thumb2/thumb2-badreg-operands.ll delete mode 100644 test/CodeGen/X86/2007-10-16-fp80_select.ll delete mode 100644 test/CodeGen/X86/2008-11-29-DivideConstant16bit.ll delete mode 100644 test/CodeGen/X86/2008-11-29-DivideConstant16bitSigned.ll create mode 100644 test/CodeGen/X86/2010-09-16-EmptyFilename.ll create mode 100644 test/CodeGen/X86/2010-09-16-asmcrash.ll create mode 100644 test/CodeGen/X86/2010-09-17-SideEffectsInChain.ll create mode 100644 test/CodeGen/X86/2010-09-30-CMOV-JumpTable-PHI.ll create mode 100644 test/CodeGen/X86/2010-10-08-cmpxchg8b.ll create mode 100644 test/CodeGen/X86/2010-11-02-DbgParameter.ll create mode 100644 test/CodeGen/X86/2010-11-09-MOVLPS.ll create mode 100644 test/CodeGen/X86/2010-11-18-SelectOfExtload.ll create mode 100644 test/CodeGen/X86/2010-12-02-MC-Set.ll create mode 100644 test/CodeGen/X86/2011-01-07-LegalizeTypesCrash.ll create mode 100644 test/CodeGen/X86/2011-01-10-DagCombineHang.ll create mode 100644 test/CodeGen/X86/2011-01-24-DbgValue-Before-Use.ll create mode 100644 test/CodeGen/X86/2011-02-04-FastRegallocNoFP.ll create mode 100644 test/CodeGen/X86/add-of-carry.ll create mode 100644 test/CodeGen/X86/alldiv-divdi3.ll create mode 100644 test/CodeGen/X86/andimm8.ll create mode 100644 test/CodeGen/X86/apm.ll create mode 100644 test/CodeGen/X86/bc-extract.ll create mode 100644 test/CodeGen/X86/bit-test-shift.ll delete mode 100644 test/CodeGen/X86/cmp-test.ll create mode 100644 test/CodeGen/X86/cmp.ll delete mode 100644 test/CodeGen/X86/cmp0.ll delete mode 100644 test/CodeGen/X86/cmp2.ll create mode 100644 test/CodeGen/X86/complex-asm.ll create mode 100644 test/CodeGen/X86/conditional-indecrement.ll delete mode 100644 test/CodeGen/X86/const-select.ll create mode 100644 test/CodeGen/X86/critical-edge-split-2.ll delete mode 100644 test/CodeGen/X86/critical-edge-split.ll create mode 100644 test/CodeGen/X86/ctpop-combine.ll create mode 100644 test/CodeGen/X86/dbg-live-in-location.ll create mode 100644 test/CodeGen/X86/dbg-merge-loc-entry.ll create mode 100644 test/CodeGen/X86/dbg-value-inlined-parameter.ll create mode 100644 test/CodeGen/X86/dbg-value-location.ll create mode 100644 test/CodeGen/X86/dbg-value-range.ll delete mode 100644 test/CodeGen/X86/div_const.ll create mode 100644 test/CodeGen/X86/divide-by-constant.ll create mode 100644 test/CodeGen/X86/fast-isel-avoid-unnecessary-pic-base.ll create mode 100644 test/CodeGen/X86/fltused.ll create mode 100644 test/CodeGen/X86/inline-asm-h.ll create mode 100644 test/CodeGen/X86/inline-asm-ptr-cast.ll create mode 100644 test/CodeGen/X86/legalize-sub-zero-2.ll create mode 100644 test/CodeGen/X86/legalize-sub-zero.ll delete mode 100644 test/CodeGen/X86/memmove-0.ll delete mode 100644 test/CodeGen/X86/memmove-1.ll delete mode 100644 test/CodeGen/X86/memmove-2.ll delete mode 100644 test/CodeGen/X86/memmove-3.ll create mode 100644 test/CodeGen/X86/misaligned-memset.ll create mode 100644 test/CodeGen/X86/mmx-builtins.ll create mode 100644 test/CodeGen/X86/mult-alt-generic-i686.ll create mode 100644 test/CodeGen/X86/mult-alt-generic-x86_64.ll create mode 100644 test/CodeGen/X86/mult-alt-x86.ll create mode 100644 test/CodeGen/X86/narrow-shl-load.ll create mode 100644 test/CodeGen/X86/non-globl-eh-frame.ll create mode 100644 test/CodeGen/X86/popcnt.ll create mode 100644 test/CodeGen/X86/pr9127.ll delete mode 100644 test/CodeGen/X86/select-aggregate.ll delete mode 100644 test/CodeGen/X86/select-zero-one.ll delete mode 100644 test/CodeGen/X86/sext-select.ll create mode 100644 test/CodeGen/X86/sibcall-5.ll delete mode 100644 test/CodeGen/X86/split-select.ll create mode 100644 test/CodeGen/X86/stdcall-notailcall.ll create mode 100644 test/CodeGen/X86/switch-or.ll create mode 100644 test/CodeGen/X86/tailcall-ri64.ll delete mode 100644 test/CodeGen/X86/tls-1.ll create mode 100644 test/CodeGen/X86/tlv-1.ll create mode 100644 test/CodeGen/X86/tlv-2.ll create mode 100644 test/CodeGen/X86/uint64-to-float.ll create mode 100644 test/CodeGen/X86/umulo-64.ll create mode 100644 test/CodeGen/X86/vec-sign.ll delete mode 100644 test/CodeGen/X86/vec_select.ll create mode 100644 test/CodeGen/X86/visibility.ll delete mode 100644 test/CodeGen/X86/widen_select-1.ll create mode 100644 test/CodeGen/X86/win64_params.ll create mode 100644 test/CodeGen/X86/win64_vararg.ll create mode 100644 test/CodeGen/X86/x86-64-extend-shift.ll create mode 100644 test/CodeGen/X86/x86_64-mul-by-const.ll create mode 100644 test/CodeGen/X86/zext-extract_subreg.ll create mode 100644 test/CodeGen/XCore/2011-01-31-DAGCombineBug.ll create mode 100644 test/CodeGen/XCore/resources.ll create mode 100644 test/CodeGen/XCore/trampoline.ll create mode 100644 test/DebugInfo/2010-10-01-crash.ll create mode 100644 test/FrontendAda/Support/real_cst.ads create mode 100644 test/FrontendAda/real_cst.adb delete mode 100644 test/FrontendC++/2003-08-20-ExceptionFail.cpp delete mode 100644 test/FrontendC++/2003-08-21-EmptyClass.cpp delete mode 100644 test/FrontendC++/2003-08-24-Cleanup.cpp delete mode 100644 test/FrontendC++/2003-08-27-TypeNamespaces.cpp delete mode 100644 test/FrontendC++/2003-08-28-ForwardType.cpp delete mode 100644 test/FrontendC++/2003-08-28-SaveExprBug.cpp delete mode 100644 test/FrontendC++/2003-08-29-ArgPassingBug.cpp delete mode 100644 test/FrontendC++/2003-08-31-StructLayout.cpp delete mode 100644 test/FrontendC++/2003-09-22-CompositeExprValue.cpp delete mode 100644 test/FrontendC++/2003-09-29-ArgumentNumberMismatch.cpp delete mode 100644 test/FrontendC++/2003-09-30-CommaExprBug.cpp delete mode 100644 test/FrontendC++/2003-09-30-ForIncrementExprBug.cpp delete mode 100644 test/FrontendC++/2003-09-30-ForIncrementExprBug2.cpp delete mode 100644 test/FrontendC++/2003-09-30-NestedFunctionDecl.cpp delete mode 100644 test/FrontendC++/2003-10-17-BoolBitfields.cpp delete mode 100644 test/FrontendC++/2003-10-21-InnerClass.cpp delete mode 100644 test/FrontendC++/2003-10-27-VirtualBaseClassCrash.cpp delete mode 100644 test/FrontendC++/2003-11-04-ArrayConstructors.cpp delete mode 100644 test/FrontendC++/2003-11-04-CatchLabelName.cpp delete mode 100644 test/FrontendC++/2003-11-08-ArrayAddress.cpp delete mode 100644 test/FrontendC++/2003-11-18-EnumArray.cpp delete mode 100644 test/FrontendC++/2006-11-30-NoCompileUnit.cpp create mode 100644 test/FrontendC/2010-11-16-asmblock.c create mode 100644 test/FrontendC/2010-12-01-CommonGlobal.c create mode 100644 test/FrontendC/arrayderef.c create mode 100644 test/LLVMC/C++/just-compile.cpp create mode 100644 test/LLVMC/C++/unknown_suffix.unk create mode 100644 test/LLVMC/C/emit-llvm-opt.c create mode 100644 test/LLVMC/MultipleOutputLanguages.td create mode 100644 test/Linker/PR8300.ll create mode 100644 test/Linker/available_externally_a.ll create mode 100644 test/Linker/available_externally_b.ll create mode 100644 test/Linker/unnamed-addr1-a.ll create mode 100644 test/Linker/unnamed-addr1-b.ll create mode 100644 test/MC/ARM/arm_fixups.s create mode 100644 test/MC/ARM/arm_instructions.s create mode 100644 test/MC/ARM/arm_word_directive.s create mode 100644 test/MC/ARM/dg.exp create mode 100644 test/MC/ARM/elf-eflags-eabi.s create mode 100644 test/MC/ARM/elf-movt.s create mode 100644 test/MC/ARM/elf-reloc-01.ll create mode 100644 test/MC/ARM/elf-reloc-02.ll create mode 100644 test/MC/ARM/elf-reloc-03.ll create mode 100644 test/MC/ARM/hilo-16bit-relocations.s create mode 100644 test/MC/ARM/neon-abs-encoding.s create mode 100644 test/MC/ARM/neon-absdiff-encoding.s create mode 100644 test/MC/ARM/neon-add-encoding.s create mode 100644 test/MC/ARM/neon-bitcount-encoding.s create mode 100644 test/MC/ARM/neon-bitwise-encoding.s create mode 100644 test/MC/ARM/neon-cmp-encoding.s create mode 100644 test/MC/ARM/neon-convert-encoding.s create mode 100644 test/MC/ARM/neon-dup-encoding.s create mode 100644 test/MC/ARM/neon-minmax-encoding.s create mode 100644 test/MC/ARM/neon-mov-encoding.s create mode 100644 test/MC/ARM/neon-mul-accum-encoding.s create mode 100644 test/MC/ARM/neon-mul-encoding.s create mode 100644 test/MC/ARM/neon-neg-encoding.s create mode 100644 test/MC/ARM/neon-pairwise-encoding.s create mode 100644 test/MC/ARM/neon-reciprocal-encoding.s create mode 100644 test/MC/ARM/neon-reverse-encoding.s create mode 100644 test/MC/ARM/neon-satshift-encoding.s create mode 100644 test/MC/ARM/neon-shift-encoding.s create mode 100644 test/MC/ARM/neon-shiftaccum-encoding.s create mode 100644 test/MC/ARM/neon-shuffle-encoding.s create mode 100644 test/MC/ARM/neon-sub-encoding.s create mode 100644 test/MC/ARM/neon-table-encoding.s create mode 100644 test/MC/ARM/neon-vld-encoding.s create mode 100644 test/MC/ARM/neon-vst-encoding.s create mode 100644 test/MC/ARM/neont2-abs-encoding.s create mode 100644 test/MC/ARM/neont2-absdiff-encoding.s create mode 100644 test/MC/ARM/neont2-add-encoding.s create mode 100644 test/MC/ARM/neont2-bitcount-encoding.s create mode 100644 test/MC/ARM/neont2-bitwise-encoding.s create mode 100644 test/MC/ARM/neont2-cmp-encoding.s create mode 100644 test/MC/ARM/neont2-convert-encoding.s create mode 100644 test/MC/ARM/neont2-dup-encoding.s create mode 100644 test/MC/ARM/neont2-minmax-encoding.s create mode 100644 test/MC/ARM/neont2-mov-encoding.s create mode 100644 test/MC/ARM/neont2-mul-accum-encoding.s create mode 100644 test/MC/ARM/neont2-mul-encoding.s create mode 100644 test/MC/ARM/neont2-neg-encoding.s create mode 100644 test/MC/ARM/neont2-pairwise-encoding.s create mode 100644 test/MC/ARM/neont2-reciprocal-encoding.s create mode 100644 test/MC/ARM/neont2-reverse-encoding.s create mode 100644 test/MC/ARM/neont2-satshift-encoding.s create mode 100644 test/MC/ARM/neont2-shift-encoding.s create mode 100644 test/MC/ARM/neont2-shiftaccum-encoding.s create mode 100644 test/MC/ARM/neont2-shuffle-encoding.s create mode 100644 test/MC/ARM/neont2-sub-encoding.s create mode 100644 test/MC/ARM/neont2-table-encoding.s create mode 100644 test/MC/ARM/neont2-vld-encoding.s create mode 100644 test/MC/ARM/neont2-vst-encoding.s create mode 100644 test/MC/ARM/prefetch.ll create mode 100644 test/MC/ARM/reg-list.s create mode 100644 test/MC/ARM/simple-encoding.ll create mode 100644 test/MC/ARM/simple-fp-encoding.s create mode 100644 test/MC/ARM/thumb.s create mode 100644 test/MC/ARM/thumb2.s create mode 100644 test/MC/ARM/thumb2_instructions.s delete mode 100644 test/MC/AsmParser/ARM/arm_instructions.s delete mode 100644 test/MC/AsmParser/ARM/arm_word_directive.s delete mode 100644 test/MC/AsmParser/ARM/dg.exp delete mode 100644 test/MC/AsmParser/ELF/dg.exp delete mode 100644 test/MC/AsmParser/ELF/directive_previous.s delete mode 100644 test/MC/AsmParser/ELF/directive_section.s delete mode 100644 test/MC/AsmParser/X86/dg.exp delete mode 100644 test/MC/AsmParser/X86/x86_32-avx-clmul-encoding.s delete mode 100644 test/MC/AsmParser/X86/x86_32-avx-encoding.s delete mode 100644 test/MC/AsmParser/X86/x86_32-bit.s delete mode 100644 test/MC/AsmParser/X86/x86_32-bit_cat.s delete mode 100644 test/MC/AsmParser/X86/x86_32-encoding.s delete mode 100644 test/MC/AsmParser/X86/x86_32-fma3-encoding.s delete mode 100644 test/MC/AsmParser/X86/x86_32-mismatched-add.s delete mode 100644 test/MC/AsmParser/X86/x86_32-new-encoder.s delete mode 100644 test/MC/AsmParser/X86/x86_64-avx-clmul-encoding.s delete mode 100644 test/MC/AsmParser/X86/x86_64-avx-encoding.s delete mode 100644 test/MC/AsmParser/X86/x86_64-encoding.s delete mode 100644 test/MC/AsmParser/X86/x86_64-fma3-encoding.s delete mode 100644 test/MC/AsmParser/X86/x86_64-imm-widths.s delete mode 100644 test/MC/AsmParser/X86/x86_64-incl_decl.s delete mode 100644 test/MC/AsmParser/X86/x86_64-new-encoder.s delete mode 100644 test/MC/AsmParser/X86/x86_64-operands.s delete mode 100644 test/MC/AsmParser/X86/x86_64-suffix-matching.s delete mode 100644 test/MC/AsmParser/X86/x86_instruction_errors.s delete mode 100644 test/MC/AsmParser/X86/x86_instructions.s delete mode 100644 test/MC/AsmParser/X86/x86_operands.s delete mode 100644 test/MC/AsmParser/X86/x86_word_directive.s create mode 100644 test/MC/AsmParser/dash-n.s create mode 100644 test/MC/AsmParser/equ.s create mode 100644 test/MC/AsmParser/expr_symbol_modifiers.s create mode 100644 test/MC/AsmParser/floating-literals.s create mode 100644 test/MC/AsmParser/full_line_comment.s create mode 100644 test/MC/AsmParser/ifdef.s create mode 100644 test/MC/AsmParser/ifndef.s create mode 100644 test/MC/AsmParser/paren.s create mode 100644 test/MC/AsmParser/rename.s create mode 100644 test/MC/AsmParser/section.s create mode 100644 test/MC/COFF/align-nops.s delete mode 100644 test/MC/COFF/basic-coff.ll create mode 100644 test/MC/COFF/basic-coff.s create mode 100644 test/MC/COFF/bss.s create mode 100644 test/MC/COFF/module-asm.ll create mode 100644 test/MC/COFF/simple-fixups.s create mode 100644 test/MC/COFF/symbol-alias.s delete mode 100644 test/MC/COFF/symbol-fragment-offset.ll create mode 100644 test/MC/COFF/symbol-fragment-offset.s create mode 100644 test/MC/COFF/weak.s create mode 100644 test/MC/Disassembler/ARM/arm-tests.txt create mode 100644 test/MC/Disassembler/ARM/dg.exp create mode 100644 test/MC/Disassembler/ARM/neon-tests.txt create mode 100644 test/MC/Disassembler/ARM/thumb-tests.txt create mode 100644 test/MC/Disassembler/MBlaze/dg.exp create mode 100644 test/MC/Disassembler/MBlaze/mblaze_branch.txt create mode 100644 test/MC/Disassembler/MBlaze/mblaze_fpu.txt create mode 100644 test/MC/Disassembler/MBlaze/mblaze_fsl.txt create mode 100644 test/MC/Disassembler/MBlaze/mblaze_imm.txt create mode 100644 test/MC/Disassembler/MBlaze/mblaze_memory.txt create mode 100644 test/MC/Disassembler/MBlaze/mblaze_operands.txt create mode 100644 test/MC/Disassembler/MBlaze/mblaze_pattern.txt create mode 100644 test/MC/Disassembler/MBlaze/mblaze_shift.txt create mode 100644 test/MC/Disassembler/MBlaze/mblaze_special.txt create mode 100644 test/MC/Disassembler/MBlaze/mblaze_typea.txt create mode 100644 test/MC/Disassembler/MBlaze/mblaze_typeb.txt create mode 100644 test/MC/Disassembler/X86/dg.exp create mode 100644 test/MC/Disassembler/X86/simple-tests.txt create mode 100644 test/MC/Disassembler/X86/truncated-input.txt delete mode 100644 test/MC/Disassembler/arm-tests.txt delete mode 100644 test/MC/Disassembler/dg.exp delete mode 100644 test/MC/Disassembler/neon-tests.txt delete mode 100644 test/MC/Disassembler/simple-tests.txt delete mode 100644 test/MC/Disassembler/thumb-tests.txt create mode 100644 test/MC/ELF/abs.s create mode 100644 test/MC/ELF/alias-reloc.s create mode 100644 test/MC/ELF/alias.s create mode 100644 test/MC/ELF/align-bss.s create mode 100644 test/MC/ELF/align-nops.s create mode 100644 test/MC/ELF/align-size.s create mode 100644 test/MC/ELF/align-text.s create mode 100644 test/MC/ELF/align.s create mode 100644 test/MC/ELF/bad-section.s create mode 100644 test/MC/ELF/basic-elf-32.s create mode 100644 test/MC/ELF/basic-elf-64.s create mode 100644 test/MC/ELF/call-abs.s create mode 100644 test/MC/ELF/cfi-advance-loc2.s create mode 100644 test/MC/ELF/cfi-def-cfa-offset.s create mode 100644 test/MC/ELF/cfi-def-cfa-register.s create mode 100644 test/MC/ELF/cfi-def-cfa.s create mode 100644 test/MC/ELF/cfi-offset.s create mode 100644 test/MC/ELF/cfi-remember.s create mode 100644 test/MC/ELF/cfi-zero-addr-delta.s create mode 100644 test/MC/ELF/cfi.s create mode 100644 test/MC/ELF/comdat.s create mode 100644 test/MC/ELF/common.s create mode 100644 test/MC/ELF/common2.s create mode 100644 test/MC/ELF/debug-line.s create mode 100644 test/MC/ELF/debug-loc.s create mode 100644 test/MC/ELF/diff.s create mode 100644 test/MC/ELF/diff2.s create mode 100644 test/MC/ELF/elf_directive_previous.s create mode 100644 test/MC/ELF/elf_directive_section.s create mode 100644 test/MC/ELF/empty-dwarf-lines.s create mode 100644 test/MC/ELF/empty.s create mode 100644 test/MC/ELF/entsize.ll create mode 100644 test/MC/ELF/entsize.s create mode 100644 test/MC/ELF/file.s create mode 100644 test/MC/ELF/global-offset.s create mode 100644 test/MC/ELF/got.s create mode 100644 test/MC/ELF/ident.s create mode 100644 test/MC/ELF/invalid-symver.s create mode 100644 test/MC/ELF/leb128.s create mode 100644 test/MC/ELF/local-reloc.s create mode 100644 test/MC/ELF/merge.s create mode 100644 test/MC/ELF/n_bytes.s create mode 100644 test/MC/ELF/no-fixup.s create mode 100644 test/MC/ELF/noexec.s create mode 100644 test/MC/ELF/norelocation.s create mode 100644 test/MC/ELF/pic-diff.s create mode 100644 test/MC/ELF/plt.s create mode 100644 test/MC/ELF/relax-arith.s create mode 100644 test/MC/ELF/relax-crash.s create mode 100644 test/MC/ELF/relax.s create mode 100644 test/MC/ELF/relocation-386.s create mode 100644 test/MC/ELF/relocation.s create mode 100644 test/MC/ELF/rename.s create mode 100644 test/MC/ELF/section.s create mode 100644 test/MC/ELF/set.s create mode 100644 test/MC/ELF/sleb.s create mode 100644 test/MC/ELF/symref.s create mode 100644 test/MC/ELF/tls-i386.s create mode 100644 test/MC/ELF/tls.s create mode 100644 test/MC/ELF/type.s create mode 100644 test/MC/ELF/uleb.s create mode 100644 test/MC/ELF/undef.s create mode 100644 test/MC/ELF/undef2.s create mode 100644 test/MC/ELF/weak.s create mode 100644 test/MC/ELF/weakref-plt.s create mode 100644 test/MC/ELF/weakref-reloc.s create mode 100644 test/MC/ELF/weakref.s create mode 100644 test/MC/ELF/zero.s create mode 100644 test/MC/MBlaze/dg.exp create mode 100644 test/MC/MBlaze/mblaze_branch.s create mode 100644 test/MC/MBlaze/mblaze_fpu.s create mode 100644 test/MC/MBlaze/mblaze_fsl.s create mode 100644 test/MC/MBlaze/mblaze_imm.s create mode 100644 test/MC/MBlaze/mblaze_memory.s create mode 100644 test/MC/MBlaze/mblaze_operands.s create mode 100644 test/MC/MBlaze/mblaze_pattern.s create mode 100644 test/MC/MBlaze/mblaze_shift.s create mode 100644 test/MC/MBlaze/mblaze_special.s create mode 100644 test/MC/MBlaze/mblaze_typea.s create mode 100644 test/MC/MBlaze/mblaze_typeb.s create mode 100644 test/MC/MachO/darwin-ARM-reloc.s create mode 100644 test/MC/MachO/darwin-Thumb-reloc.s create mode 100644 test/MC/MachO/darwin-complex-difference.s create mode 100644 test/MC/MachO/diff-with-two-sections.s create mode 100644 test/MC/MachO/empty-dwarf-lines.s create mode 100644 test/MC/MachO/loc.s create mode 100644 test/MC/MachO/pcrel-to-other-section.s create mode 100644 test/MC/MachO/symbol-diff.s create mode 100644 test/MC/MachO/weakdef.s create mode 100644 test/MC/X86/3DNow.s create mode 100644 test/MC/X86/dg.exp create mode 100644 test/MC/X86/x86-32-avx.s create mode 100644 test/MC/X86/x86-32-coverage.s create mode 100644 test/MC/X86/x86-32-fma3.s create mode 100644 test/MC/X86/x86-32.s create mode 100644 test/MC/X86/x86-64.s create mode 100644 test/MC/X86/x86_64-avx-clmul-encoding.s create mode 100644 test/MC/X86/x86_64-avx-encoding.s create mode 100644 test/MC/X86/x86_64-encoding.s create mode 100644 test/MC/X86/x86_64-fma3-encoding.s create mode 100644 test/MC/X86/x86_64-imm-widths.s create mode 100644 test/MC/X86/x86_directives.s create mode 100644 test/MC/X86/x86_errors.s create mode 100644 test/MC/X86/x86_operands.s create mode 100644 test/Object/TestObjectFiles/trivial-object-test.coff-i386 create mode 100644 test/Object/TestObjectFiles/trivial-object-test.coff-x86-64 create mode 100644 test/Object/TestObjectFiles/trivial-object-test.elf-i386 create mode 100644 test/Object/TestObjectFiles/trivial-object-test.elf-x86-64 create mode 100644 test/Object/TestObjectFiles/trivial-object-test.macho-i386 create mode 100644 test/Object/TestObjectFiles/trivial-object-test.macho-x86-64 create mode 100644 test/Object/dg.exp create mode 100644 test/Object/nm-trivial-object.test-broken create mode 100644 test/Object/objdump-trivial-object.test-broken delete mode 100644 test/Other/2008-08-14-PassManager.ll create mode 100644 test/Other/extract.ll create mode 100644 test/Scripts/common_dump.py create mode 100755 test/Scripts/elf-dump create mode 100644 test/Scripts/elf-dump.bat delete mode 100755 test/Scripts/macho-dump delete mode 100644 test/Scripts/macho-dump.bat create mode 100755 test/Scripts/macho-dumpx create mode 100644 test/Scripts/macho-dumpx.bat create mode 100644 test/TableGen/Dag.td delete mode 100644 test/TableGen/DagDefSubst.td delete mode 100644 test/TableGen/DagIntSubst.td delete mode 100644 test/TableGen/nameconcat.td create mode 100644 test/Transforms/CodeGenPrepare/basic.ll delete mode 100644 test/Transforms/ConstProp/bitcast2.ll create mode 100644 test/Transforms/ConstProp/extractvalue.ll create mode 100644 test/Transforms/ConstProp/insertvalue.ll delete mode 100644 test/Transforms/ConstProp/nottest.ll create mode 100644 test/Transforms/ConstantMerge/2011-01-15-EitherOrder.ll create mode 100644 test/Transforms/ConstantMerge/merge-both.ll create mode 100644 test/Transforms/ConstantMerge/unnamed-addr.ll create mode 100644 test/Transforms/CorrelatedValuePropagation/2010-09-26-MergeConstantRange.ll create mode 100644 test/Transforms/CorrelatedValuePropagation/crash.ll create mode 100644 test/Transforms/CorrelatedValuePropagation/non-null.ll delete mode 100644 test/Transforms/DeadStoreElimination/2004-11-28-LiveStoreDeleted.ll delete mode 100644 test/Transforms/DeadStoreElimination/2004-12-28-PartialStore.ll delete mode 100644 test/Transforms/DeadStoreElimination/2005-11-30-vaarg.ll delete mode 100644 test/Transforms/DeadStoreElimination/2006-06-27-AST-Remove.ll delete mode 100644 test/Transforms/DeadStoreElimination/2008-07-28-load-store.ll delete mode 100644 test/Transforms/DeadStoreElimination/2008-11-28-MemDepUpdate.ll delete mode 100644 test/Transforms/DeadStoreElimination/2008-11-29-OffEndOfBlock.ll delete mode 100644 test/Transforms/DeadStoreElimination/2009-11-10-Trampoline.ll delete mode 100644 test/Transforms/DeadStoreElimination/alloca.ll delete mode 100644 test/Transforms/DeadStoreElimination/byval.ll delete mode 100644 test/Transforms/DeadStoreElimination/context-sensitive.ll delete mode 100644 test/Transforms/DeadStoreElimination/memcpy.ll delete mode 100644 test/Transforms/DeadStoreElimination/partial-overwrite.ll delete mode 100644 test/Transforms/DeadStoreElimination/volatile-load.ll create mode 100644 test/Transforms/EarlyCSE/basic.ll create mode 100644 test/Transforms/EarlyCSE/dg.exp create mode 100644 test/Transforms/FunctionAttrs/2010-10-30-volatile.ll create mode 100644 test/Transforms/GVN/2010-11-13-Simplify.ll create mode 100644 test/Transforms/GVN/load-pre-licm.ll create mode 100644 test/Transforms/GVN/non-local-offset.ll create mode 100644 test/Transforms/GVN/phi-translate.ll create mode 100644 test/Transforms/GVN/preserve-tbaa.ll create mode 100644 test/Transforms/GlobalOpt/2010-10-19-WeakOdr.ll create mode 100644 test/Transforms/GlobalOpt/ctor-list-opt-constexpr.ll create mode 100644 test/Transforms/GlobalOpt/unnamed-addr.ll delete mode 100644 test/Transforms/IndVarSimplify/loop-invariant-step.ll delete mode 100644 test/Transforms/Inline/byval2.ll create mode 100644 test/Transforms/InstCombine/2010-11-01-lshr-mask.ll create mode 100644 test/Transforms/InstCombine/2010-11-21-SizeZeroTypeGEP.ll create mode 100644 test/Transforms/InstCombine/2010-11-23-Distributed.ll create mode 100644 test/Transforms/InstCombine/2011-02-14-InfLoop.ll create mode 100644 test/Transforms/InstCombine/2011-02-16-InsertelementHang.ll create mode 100644 test/Transforms/InstCombine/bitcast-store.ll create mode 100644 test/Transforms/InstCombine/bitcast-vec-uniform.ll delete mode 100644 test/Transforms/InstCombine/div-cmp-overflow.ll delete mode 100644 test/Transforms/InstCombine/exact-sdiv.ll create mode 100644 test/Transforms/InstCombine/exact.ll create mode 100644 test/Transforms/InstCombine/fold-calls.ll create mode 100644 test/Transforms/InstCombine/fold-vector-select.ll create mode 100644 test/Transforms/InstCombine/memset2.ll create mode 100644 test/Transforms/InstCombine/neon-intrinsics.ll create mode 100644 test/Transforms/InstCombine/overflow.ll create mode 100644 test/Transforms/InstCombine/pr8547.ll create mode 100644 test/Transforms/InstCombine/select-crash.ll delete mode 100644 test/Transforms/InstCombine/vec_demanded_elts-2.ll delete mode 100644 test/Transforms/InstCombine/vec_demanded_elts-3.ll create mode 100644 test/Transforms/InstCombine/vec_sext.ll create mode 100644 test/Transforms/InstSimplify/2010-12-20-Boolean.ll create mode 100644 test/Transforms/InstSimplify/2010-12-20-Distribute.ll create mode 100644 test/Transforms/InstSimplify/2011-01-14-Thread.ll create mode 100644 test/Transforms/InstSimplify/2011-02-01-Vector.ll create mode 100644 test/Transforms/InstSimplify/compare.ll create mode 100644 test/Transforms/InstSimplify/dg.exp create mode 100644 test/Transforms/InstSimplify/exact-nsw-nuw.ll create mode 100644 test/Transforms/InstSimplify/fdiv.ll create mode 100644 test/Transforms/InstSimplify/reassociate.ll create mode 100644 test/Transforms/JumpThreading/degenerate-phi.ll create mode 100644 test/Transforms/JumpThreading/indirectbr.ll create mode 100644 test/Transforms/JumpThreading/select.ll delete mode 100644 test/Transforms/LICM/2009-03-25-AliasSetTracker.ll create mode 100644 test/Transforms/LoopIdiom/basic.ll create mode 100644 test/Transforms/LoopIdiom/dg.exp delete mode 100644 test/Transforms/LoopIndexSplit/2007-09-21-LoopBound.ll delete mode 100644 test/Transforms/LoopIndexSplit/2007-09-24-UpdateIterationSpace.ll delete mode 100644 test/Transforms/LoopIndexSplit/2007-09-25-UpdateIterationSpace-2.ll delete mode 100644 test/Transforms/LoopIndexSplit/2008-01-28-IndDecrement.ll delete mode 100644 test/Transforms/LoopIndexSplit/2008-02-08-Crash.ll delete mode 100644 test/Transforms/LoopIndexSplit/2008-02-13-ExitValueNum.ll delete mode 100644 test/Transforms/LoopIndexSplit/2008-02-13-LoopLatch.ll delete mode 100644 test/Transforms/LoopIndexSplit/2008-02-13-LoopLatchPHI.ll delete mode 100644 test/Transforms/LoopIndexSplit/2008-02-14-Crash.ll delete mode 100644 test/Transforms/LoopIndexSplit/2008-03-24-ExitPhi.ll delete mode 100644 test/Transforms/LoopIndexSplit/2008-05-19-IndVar.ll delete mode 100644 test/Transforms/LoopIndexSplit/2008-06-03-DomFrontier.ll delete mode 100644 test/Transforms/LoopIndexSplit/2008-07-08-MisCompilation.ll delete mode 100644 test/Transforms/LoopIndexSplit/2008-09-17-IVUse.ll delete mode 100644 test/Transforms/LoopIndexSplit/2008-09-20-Crash.ll delete mode 100644 test/Transforms/LoopIndexSplit/2008-10-06-Crash.ll delete mode 100644 test/Transforms/LoopIndexSplit/2008-10-10-OneIteration.ll delete mode 100644 test/Transforms/LoopIndexSplit/2008-11-10-Sign.ll delete mode 100644 test/Transforms/LoopIndexSplit/2009-03-02-UpdateIterationSpace-crash.ll delete mode 100644 test/Transforms/LoopIndexSplit/2009-03-30-undef.ll delete mode 100644 test/Transforms/LoopIndexSplit/Crash-2007-08-17.ll delete mode 100644 test/Transforms/LoopIndexSplit/Crash-2007-12-03.ll delete mode 100644 test/Transforms/LoopIndexSplit/Crash2-2007-08-17.ll delete mode 100644 test/Transforms/LoopIndexSplit/ExitCondition-2007-09-10.ll delete mode 100644 test/Transforms/LoopIndexSplit/OneIterLoop-2007-08-17.ll delete mode 100644 test/Transforms/LoopIndexSplit/OneIterLoop2-2007-08-17.ll delete mode 100644 test/Transforms/LoopIndexSplit/OneIterLoop3-2007-08-17.ll delete mode 100644 test/Transforms/LoopIndexSplit/PR3913.ll delete mode 100644 test/Transforms/LoopIndexSplit/PR4174-2.ll delete mode 100644 test/Transforms/LoopIndexSplit/PR4174.ll delete mode 100644 test/Transforms/LoopIndexSplit/SaveLastValue-2007-08-17.ll delete mode 100644 test/Transforms/LoopIndexSplit/SplitValue-2007-08-24.ll delete mode 100644 test/Transforms/LoopIndexSplit/UpperBound-2007-08-24.ll delete mode 100644 test/Transforms/LoopIndexSplit/dg.exp delete mode 100644 test/Transforms/LoopIndexSplit/non-iv-cmp-operand.ll delete mode 100644 test/Transforms/LoopRotate/LRCrash-1.ll delete mode 100644 test/Transforms/LoopRotate/LRCrash-2.ll delete mode 100644 test/Transforms/LoopRotate/LRCrash-3.ll delete mode 100644 test/Transforms/LoopRotate/LRCrash-4.ll delete mode 100644 test/Transforms/LoopRotate/LRCrash-5.ll create mode 100644 test/Transforms/LoopRotate/basic.ll create mode 100644 test/Transforms/LoopRotate/crash.ll create mode 100644 test/Transforms/LoopRotate/dbgvalue.ll create mode 100644 test/Transforms/LoopSimplify/2010-12-26-PHIInfiniteLoop.ll create mode 100644 test/Transforms/LoopStrengthReduce/hoist-parent-preheader.ll create mode 100644 test/Transforms/LoopUnroll/basic.ll create mode 100644 test/Transforms/LoopUnswitch/2010-11-18-LCSSA.ll delete mode 100644 test/Transforms/MemCpyOpt/2008-04-29-SRetRemoval.ll delete mode 100644 test/Transforms/MemCpyOpt/form-memset2.ll create mode 100644 test/Transforms/MemCpyOpt/loadstore-sret.ll create mode 100644 test/Transforms/MemCpyOpt/memcpy-to-memset.ll create mode 100644 test/Transforms/MemCpyOpt/smaller.ll create mode 100644 test/Transforms/MergeFunc/2011-02-08-RemoveEqual.ll create mode 100644 test/Transforms/MergeFunc/vector.ll delete mode 100644 test/Transforms/PartialSpecialize/dg.exp delete mode 100644 test/Transforms/PartialSpecialize/two-specializations.ll create mode 100644 test/Transforms/Reassociate/2011-01-26-UseAfterFree.ll create mode 100644 test/Transforms/Reassociate/optional-flags.ll delete mode 100644 test/Transforms/ScalarRepl/2003-05-30-InvalidIndices.ll delete mode 100644 test/Transforms/ScalarRepl/2003-05-30-MultiLevel.ll delete mode 100644 test/Transforms/ScalarRepl/2005-12-14-UnionPromoteCrash.ll delete mode 100644 test/Transforms/ScalarRepl/2006-01-24-IllegalUnionPromoteCrash.ll delete mode 100644 test/Transforms/ScalarRepl/2006-04-20-PromoteCrash.ll delete mode 100644 test/Transforms/ScalarRepl/2006-10-23-PointerUnionCrash.ll delete mode 100644 test/Transforms/ScalarRepl/2006-12-11-SROA-Crash.ll delete mode 100644 test/Transforms/ScalarRepl/2007-03-19-CanonicalizeMemcpy.ll delete mode 100644 test/Transforms/ScalarRepl/2009-01-09-scalarrepl-empty.ll delete mode 100644 test/Transforms/ScalarRepl/2009-04-21-ZeroLengthMemSet.ll delete mode 100644 test/Transforms/ScalarRepl/2009-05-08-I1Crash.ll delete mode 100644 test/Transforms/ScalarRepl/2009-06-01-BitcastIntPadding.ll delete mode 100644 test/Transforms/ScalarRepl/2009-08-16-VLA.ll create mode 100644 test/Transforms/ScalarRepl/crash.ll create mode 100644 test/Transforms/ScalarRepl/phi-select.ll create mode 100644 test/Transforms/SimplifyCFG/2010-10-24-OnlyUnwindInEntry.ll create mode 100644 test/Transforms/SimplifyCFG/speculate-with-offset.ll create mode 100644 test/Transforms/SimplifyCFG/switch-to-icmp.ll delete mode 100644 test/Transforms/SimplifyCFG/switch_formation.ll create mode 100644 test/Transforms/SimplifyLibCalls/FPuts.ll create mode 100644 test/Transforms/SimplifyLibCalls/StrPBrk.ll create mode 100644 test/Transforms/SimplifyLibCalls/StrRChr.ll create mode 100644 test/Transforms/SimplifyLibCalls/StrSpn.ll create mode 100644 test/Transforms/TailCallElim/dup_tail.ll create mode 100644 tools/llvm-objdump/CMakeLists.txt create mode 100644 tools/llvm-objdump/Makefile create mode 100644 tools/llvm-objdump/llvm-objdump.cpp create mode 100644 tools/macho-dump/CMakeLists.txt create mode 100644 tools/macho-dump/Makefile create mode 100644 tools/macho-dump/macho-dump.cpp create mode 100644 unittests/ADT/FoldingSet.cpp create mode 100644 unittests/ADT/IntEqClassesTest.cpp create mode 100644 unittests/ADT/IntervalMapTest.cpp delete mode 100644 unittests/ADT/ValueMapTest.cpp create mode 100644 unittests/CMakeLists.txt create mode 100644 unittests/ExecutionEngine/JIT/JITTests.def create mode 100644 unittests/Support/EndianTest.cpp create mode 100644 unittests/Support/Path.cpp create mode 100644 unittests/Support/SwapByteOrderTest.cpp delete mode 100644 unittests/Support/System.cpp create mode 100644 unittests/Support/TimeValue.cpp create mode 100644 unittests/Transforms/Utils/Local.cpp create mode 100644 unittests/VMCore/ValueMapTest.cpp create mode 100755 utils/CollectDebugInfoUsingLLDB.py create mode 100755 utils/CompareDebugInfo.py create mode 100755 utils/GetRepositoryPath create mode 100644 utils/KillTheDoctor/CMakeLists.txt create mode 100644 utils/KillTheDoctor/KillTheDoctor.cpp delete mode 100644 utils/OldenDataRecover.pl create mode 100644 utils/TableGen/ClangSACheckersEmitter.cpp create mode 100644 utils/TableGen/ClangSACheckersEmitter.h create mode 100644 utils/TableGen/FixedLenDecoderEmitter.cpp create mode 100644 utils/TableGen/FixedLenDecoderEmitter.h create mode 100644 utils/TableGen/StringMatcher.cpp create mode 100644 utils/TableGen/StringMatcher.h create mode 100644 utils/Target/ARM/analyze-match-table.py create mode 100644 utils/kate/README create mode 100644 utils/kate/llvm.xml delete mode 100755 utils/lit/lit/lit.py create mode 100755 utils/lit/lit/main.py create mode 100644 utils/llvm-lit/CMakeLists.txt create mode 100755 utils/release/test-release.sh create mode 100755 utils/test_debuginfo.pl create mode 100644 utils/unittest/CMakeLists.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000000..2e2713a48ae5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +#==============================================================================# +# This file specifies intentionally untracked files that git should ignore. +# See: http://www.kernel.org/pub/software/scm/git/docs/gitignore.html +# +# This file is intentionally different from the output of `git svn show-ignore`, +# as most of those are useless. +#==============================================================================# + +#==============================================================================# +# File extensions to be ignored anywhere in the tree. +#==============================================================================# +# Temp files created by most text editors. +*~ +# Merge files created by git. +*.orig +# Byte compiled python modules. +*.pyc + +#==============================================================================# +# Explicit files to ignore (only matches one). +#==============================================================================# +.gitusers +cscope.files +cscope.out +autoconf/aclocal.m4 +autoconf/autom4te.cache + +#==============================================================================# +# Directories to ignore (do not add trailing '/'s, they skip symlinks). +#==============================================================================# +# External projects that are tracked independently. +projects/* +!projects/sample +!projects/CMakeLists.txt +!projects/Makefile +# Clang, which is tracked independently. +tools/clang diff --git a/CMakeLists.txt b/CMakeLists.txt index a6099d17c56a..0a5d5f39d85a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,9 +10,16 @@ set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" ) -set(PACKAGE_VERSION "2.8") +set(PACKAGE_VERSION "2.9") + include(VersionFromVCS) -add_version_info_from_vcs(PACKAGE_VERSION) + +option(LLVM_APPEND_VC_REV + "Append the version control system revision id to LLVM version" OFF) + +if( LLVM_APPEND_VC_REV ) + add_version_info_from_vcs(PACKAGE_VERSION) +endif() set(PACKAGE_NAME llvm) set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") @@ -64,8 +71,8 @@ set(LLVM_ALL_TARGETS Mips MBlaze MSP430 - PIC16 PowerPC + PTX Sparc SystemZ X86 @@ -80,36 +87,25 @@ else( MSVC ) CACHE STRING "Semicolon-separated list of targets to build, or \"all\".") endif( MSVC ) -set(C_INCLUDE_DIRS "" CACHE STRING - "Colon separated list of directories clang will search for headers.") +option(LLVM_ENABLE_CBE_PRINTF_A "Set to ON if CBE is enabled for printf %a output" ON) +if(LLVM_ENABLE_CBE_PRINTF_A) + set(ENABLE_CBE_PRINTF_A 1) +endif() + +option(LLVM_ENABLE_TIMESTAMPS "Enable embedding timestamp information in build" ON) +if(LLVM_ENABLE_TIMESTAMPS) + set(ENABLE_TIMESTAMPS 1) +endif() + +option(LLVM_ENABLE_FFI "Use libffi to call external functions from the interpreter" OFF) +set(FFI_LIBRARY_DIR "" CACHE PATH "Additional directory, where CMake should search for libffi.so") +set(FFI_INCLUDE_DIR "" CACHE PATH "Additional directory, where CMake should search for ffi.h or ffi/ffi.h") set(LLVM_TARGET_ARCH "host" CACHE STRING "Set target to use for LLVM JIT or use \"host\" for automatic detection.") option(LLVM_ENABLE_THREADS "Use threads if available." ON) -if( uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE" ) - option(LLVM_ENABLE_ASSERTIONS "Enable assertions" OFF) -else() - option(LLVM_ENABLE_ASSERTIONS "Enable assertions" ON) -endif() - -if( LLVM_ENABLE_ASSERTIONS ) - # MSVC doesn't like _DEBUG on release builds. See PR 4379. - if( NOT MSVC ) - add_definitions( -D_DEBUG ) - endif() - # On Release builds cmake automatically defines NDEBUG, so we - # explicitly undefine it: - if( uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE" ) - add_definitions( -UNDEBUG ) - endif() -else() - if( NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE" ) - add_definitions( -DNDEBUG ) - endif() -endif() - if( LLVM_TARGETS_TO_BUILD STREQUAL "all" ) set( LLVM_TARGETS_TO_BUILD ${LLVM_ALL_TARGETS} ) endif() @@ -135,65 +131,34 @@ set(llvm_builded_incs_dir ${LLVM_BINARY_DIR}/include/llvm) include(AddLLVMDefinitions) -if(WIN32) - if(CYGWIN) - set(LLVM_ON_WIN32 0) - set(LLVM_ON_UNIX 1) - else(CYGWIN) - set(LLVM_ON_WIN32 1) - set(LLVM_ON_UNIX 0) - endif(CYGWIN) - set(LTDL_SHLIB_EXT ".dll") - set(EXEEXT ".exe") - # Maximum path length is 160 for non-unicode paths - set(MAXPATHLEN 160) -else(WIN32) - if(UNIX) - set(LLVM_ON_WIN32 0) - set(LLVM_ON_UNIX 1) - if(APPLE) - set(LTDL_SHLIB_EXT ".dylib") - else(APPLE) - set(LTDL_SHLIB_EXT ".so") - endif(APPLE) - set(EXEEXT "") - # FIXME: Maximum path length is currently set to 'safe' fixed value - set(MAXPATHLEN 2024) - else(UNIX) - MESSAGE(SEND_ERROR "Unable to determine platform") - endif(UNIX) -endif(WIN32) +option(LLVM_ENABLE_PIC "Build Position-Independent Code" ON) include(config-ix) -option(LLVM_ENABLE_PIC "Build Position-Independent Code" ON) +include(HandleLLVMOptions) -set(ENABLE_PIC 0) -if( LLVM_ENABLE_PIC ) - if( XCODE ) - # Xcode has -mdynamic-no-pic on by default, which overrides -fPIC. I don't - # know how to disable this, so just force ENABLE_PIC off for now. - message(STATUS "Warning: -fPIC not supported with Xcode.") - else( XCODE ) - if( SUPPORTS_FPIC_FLAG ) - message(STATUS "Building with -fPIC") - add_llvm_definitions(-fPIC) - set(ENABLE_PIC 1) - else( SUPPORTS_FPIC_FLAG ) - message(STATUS "Warning: -fPIC not supported.") - endif() - endif() +if( uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE" ) + option(LLVM_ENABLE_ASSERTIONS "Enable assertions" OFF) +else() + option(LLVM_ENABLE_ASSERTIONS "Enable assertions" ON) endif() +configure_file( + ${LLVM_MAIN_INCLUDE_DIR}/llvm/Config/config.h.cmake + ${LLVM_BINARY_DIR}/include/llvm/Config/config.h) + +configure_file( + ${LLVM_MAIN_INCLUDE_DIR}/llvm/Config/llvm-config.h.cmake + ${LLVM_BINARY_DIR}/include/llvm/Config/llvm-config.h) + +configure_file( + ${LLVM_MAIN_INCLUDE_DIR}/llvm/Support/DataTypes.h.cmake + ${LLVM_BINARY_DIR}/include/llvm/Support/DataTypes.h) + set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LLVM_TOOLS_BINARY_DIR} ) set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LLVM_BINARY_DIR}/lib ) set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LLVM_BINARY_DIR}/lib ) -# set(CMAKE_VERBOSE_MAKEFILE true) - -add_llvm_definitions( -D__STDC_LIMIT_MACROS ) -add_llvm_definitions( -D__STDC_CONSTANT_MACROS ) - # MSVC has a gazillion warnings with this. if( MSVC ) option(LLVM_ENABLE_WARNINGS "Enable compiler warnings." OFF) @@ -204,65 +169,34 @@ endif() option(LLVM_ENABLE_PEDANTIC "Compile with pedantic enabled." ON) option(LLVM_ENABLE_WERROR "Fail and stop if a warning is triggered." OFF) -if( CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT WIN32 ) - # TODO: support other platforms and toolchains. - option(LLVM_BUILD_32_BITS "Build 32 bits executables and libraries." OFF) - if( LLVM_BUILD_32_BITS ) - message(STATUS "Building 32 bits executables and libraries.") - add_llvm_definitions( -m32 ) - list(APPEND CMAKE_EXE_LINKER_FLAGS -m32) - list(APPEND CMAKE_SHARED_LINKER_FLAGS -m32) - endif( LLVM_BUILD_32_BITS ) -endif( CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT WIN32 ) - -if( MSVC ) - include(ChooseMSVCCRT) - - add_llvm_definitions( -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS ) - add_llvm_definitions( -D_SCL_SECURE_NO_WARNINGS -DCRT_NONSTDC_NO_WARNINGS ) - add_llvm_definitions( -D_SCL_SECURE_NO_DEPRECATE ) - add_llvm_definitions( -wd4146 -wd4503 -wd4996 -wd4800 -wd4244 -wd4624 ) - add_llvm_definitions( -wd4355 -wd4715 -wd4180 -wd4345 -wd4224 ) - - # Suppress 'new behavior: elements of array 'array' will be default initialized' - add_llvm_definitions( -wd4351 ) - - # Enable warnings - if (LLVM_ENABLE_WARNINGS) - add_llvm_definitions( /W4 /Wall ) - if (LLVM_ENABLE_PEDANTIC) - # No MSVC equivalent available - endif (LLVM_ENABLE_PEDANTIC) - endif (LLVM_ENABLE_WARNINGS) - if (LLVM_ENABLE_WERROR) - add_llvm_definitions( /WX ) - endif (LLVM_ENABLE_WERROR) -elseif( CMAKE_COMPILER_IS_GNUCXX ) - if (LLVM_ENABLE_WARNINGS) - add_llvm_definitions( -Wall -W -Wno-unused-parameter -Wwrite-strings ) - if (LLVM_ENABLE_PEDANTIC) - add_llvm_definitions( -pedantic -Wno-long-long ) - endif (LLVM_ENABLE_PEDANTIC) - endif (LLVM_ENABLE_WARNINGS) - if (LLVM_ENABLE_WERROR) - add_llvm_definitions( -Werror ) - endif (LLVM_ENABLE_WERROR) -endif( MSVC ) +set(CMAKE_INCLUDE_CURRENT_DIR ON) include_directories( ${LLVM_BINARY_DIR}/include ${LLVM_MAIN_INCLUDE_DIR}) if( ${CMAKE_SYSTEM_NAME} MATCHES SunOS ) - SET(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-include llvm/System/Solaris.h") + SET(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-include llvm/Support/Solaris.h") endif( ${CMAKE_SYSTEM_NAME} MATCHES SunOS ) include(AddLLVM) include(TableGen) -add_subdirectory(lib/Support) -add_subdirectory(lib/System) +if( MINGW ) + get_system_libs(LLVM_SYSTEM_LIBS_LIST) + foreach(l ${LLVM_SYSTEM_LIBS_LIST}) + set(LLVM_SYSTEM_LIBS "${LLVM_SYSTEM_LIBS} -l${l}") + endforeach() + set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES}${LLVM_SYSTEM_LIBS}") + set(CMAKE_C_STANDARD_LIBRARIES "${CMAKE_C_STANDARD_LIBRARIES}${LLVM_SYSTEM_LIBS}") +endif() + +if( MINGW ) + # People report that -O3 is unreliable on MinGW. The traditional + # build also uses -O2 for that reason: + llvm_replace_compiler_option(CMAKE_CXX_FLAGS_RELEASE "-O3" "-O2") +endif() -# Everything else depends on Support and System: -set(LLVM_COMMON_DEPENDS ${LLVM_COMMON_DEPENDS} ${LLVM_LIBS} ) +# Put this before tblgen. Else we have a circular dependence. +add_subdirectory(lib/Support) set(LLVM_TABLEGEN "tblgen" CACHE STRING "Native TableGen executable. Saves building one when cross-compiling.") @@ -278,87 +212,43 @@ endif( CMAKE_CROSSCOMPILING ) add_subdirectory(include/llvm) -add_subdirectory(lib/VMCore) -add_subdirectory(lib/CodeGen) -add_subdirectory(lib/CodeGen/SelectionDAG) -add_subdirectory(lib/CodeGen/AsmPrinter) -add_subdirectory(lib/Bitcode/Reader) -add_subdirectory(lib/Bitcode/Writer) -add_subdirectory(lib/Transforms/Utils) -add_subdirectory(lib/Transforms/Instrumentation) -add_subdirectory(lib/Transforms/InstCombine) -add_subdirectory(lib/Transforms/Scalar) -add_subdirectory(lib/Transforms/IPO) -add_subdirectory(lib/Transforms/Hello) -add_subdirectory(lib/Linker) -add_subdirectory(lib/Analysis) -add_subdirectory(lib/Analysis/IPA) -add_subdirectory(lib/MC) -add_subdirectory(lib/MC/MCParser) -add_subdirectory(lib/MC/MCDisassembler) -add_subdirectory(test) +add_subdirectory(lib) add_subdirectory(utils/FileCheck) +add_subdirectory(utils/FileUpdate) add_subdirectory(utils/count) add_subdirectory(utils/not) - -set(LLVM_ENUM_ASM_PRINTERS "") -set(LLVM_ENUM_ASM_PARSERS "") -set(LLVM_ENUM_DISASSEMBLERS "") -foreach(t ${LLVM_TARGETS_TO_BUILD}) - message(STATUS "Targeting ${t}") - add_subdirectory(lib/Target/${t}) - add_subdirectory(lib/Target/${t}/TargetInfo) - if( EXISTS ${LLVM_MAIN_SRC_DIR}/lib/Target/${t}/AsmPrinter/CMakeLists.txt ) - add_subdirectory(lib/Target/${t}/AsmPrinter) - set(LLVM_ENUM_ASM_PRINTERS - "${LLVM_ENUM_ASM_PRINTERS}LLVM_ASM_PRINTER(${t})\n") - endif( EXISTS ${LLVM_MAIN_SRC_DIR}/lib/Target/${t}/AsmPrinter/CMakeLists.txt ) - if( EXISTS ${LLVM_MAIN_SRC_DIR}/lib/Target/${t}/AsmParser/CMakeLists.txt ) - add_subdirectory(lib/Target/${t}/AsmParser) - set(LLVM_ENUM_ASM_PARSERS - "${LLVM_ENUM_ASM_PARSERS}LLVM_ASM_PARSER(${t})\n") - endif( EXISTS ${LLVM_MAIN_SRC_DIR}/lib/Target/${t}/AsmParser/CMakeLists.txt ) - if( EXISTS ${LLVM_MAIN_SRC_DIR}/lib/Target/${t}/Disassembler/CMakeLists.txt ) - add_subdirectory(lib/Target/${t}/Disassembler) - set(LLVM_ENUM_DISASSEMBLERS - "${LLVM_ENUM_DISASSEMBLERS}LLVM_DISASSEMBLER(${t})\n") - endif( EXISTS ${LLVM_MAIN_SRC_DIR}/lib/Target/${t}/Disassembler/CMakeLists.txt ) - set(CURRENT_LLVM_TARGET) -endforeach(t) - -# Produce llvm/Config/AsmPrinters.def -configure_file( - ${LLVM_MAIN_INCLUDE_DIR}/llvm/Config/AsmPrinters.def.in - ${LLVM_BINARY_DIR}/include/llvm/Config/AsmPrinters.def - ) - -# Produce llvm/Config/AsmParsers.def -configure_file( - ${LLVM_MAIN_INCLUDE_DIR}/llvm/Config/AsmParsers.def.in - ${LLVM_BINARY_DIR}/include/llvm/Config/AsmParsers.def - ) - -# Produce llvm/Config/Disassemblers.def -configure_file( - ${LLVM_MAIN_INCLUDE_DIR}/llvm/Config/Disassemblers.def.in - ${LLVM_BINARY_DIR}/include/llvm/Config/Disassemblers.def - ) - -add_subdirectory(lib/ExecutionEngine) -add_subdirectory(lib/ExecutionEngine/Interpreter) -add_subdirectory(lib/ExecutionEngine/JIT) -add_subdirectory(lib/Target) -add_subdirectory(lib/AsmParser) -add_subdirectory(lib/Archive) +add_subdirectory(utils/llvm-lit) add_subdirectory(projects) -option(LLVM_BUILD_TOOLS "Build LLVM tool programs." ON) -add_subdirectory(tools) +option(LLVM_BUILD_TOOLS + "Build the LLVM tools. If OFF, just generate build targets." ON) +option(LLVM_INCLUDE_TOOLS "Generate build targets for the LLVM tools." ON) +if( LLVM_INCLUDE_TOOLS ) + add_subdirectory(tools) +endif() -option(LLVM_BUILD_EXAMPLES "Build LLVM example programs." OFF) -add_subdirectory(examples) +option(LLVM_BUILD_EXAMPLES + "Build the LLVM example programs. If OFF, just generate build targets." OFF) +option(LLVM_INCLUDE_EXAMPLES "Generate build targets for the LLVM examples" ON) +if( LLVM_INCLUDE_EXAMPLES ) + add_subdirectory(examples) +endif() + +option(LLVM_BUILD_TESTS + "Build LLVM unit tests. If OFF, just generate build targes." OFF) +option(LLVM_INCLUDE_TESTS "Generate build targets for the LLVM unit tests." ON) +if( LLVM_INCLUDE_TESTS ) + add_subdirectory(test) + add_subdirectory(utils/unittest) + add_subdirectory(unittests) + if (MSVC) + # This utility is used to prevent chrashing tests from calling Dr. Watson on + # Windows. + add_subdirectory(utils/KillTheDoctor) + endif() +endif() add_subdirectory(cmake/modules) @@ -385,3 +275,18 @@ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/ ) # TODO: make and install documentation. + +set(CPACK_PACKAGE_VENDOR "LLVM") +set(CPACK_PACKAGE_VERSION_MAJOR 2) +set(CPACK_PACKAGE_VERSION_MINOR 9) +add_version_info_from_vcs(CPACK_PACKAGE_VERSION_PATCH) +include(CPack) + +# Workaround for MSVS10 to avoid the Dialog Hell +# FIXME: This could be removed with future version of CMake. +if(MSVC_VERSION EQUAL 1600) + set(LLVM_SLN_FILENAME "${CMAKE_CURRENT_BINARY_DIR}/LLVM.sln") + if( EXISTS "${LLVM_SLN_FILENAME}" ) + file(APPEND "${LLVM_SLN_FILENAME}" "\n# This should be regenerated!\n") + endif() +endif() diff --git a/CREDITS.TXT b/CREDITS.TXT index aeecfe2e21e1..ab01dde338a5 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -8,6 +8,7 @@ beautification by scripts. The fields are: name (N), email (E), web-address (W), PGP key ID and fingerprint (P), description (D), and snail-mail address (S). + N: Vikram Adve E: vadve@cs.uiuc.edu W: http://www.cs.uiuc.edu/~vadve/ @@ -39,7 +40,7 @@ N: Misha Brukman E: brukman+llvm@uiuc.edu W: http://misha.brukman.net D: Portions of X86 and Sparc JIT compilers, PowerPC backend -D: Incremental bytecode loader +D: Incremental bitcode loader N: Cameron Buschardt E: buschard@uiuc.edu @@ -328,6 +329,7 @@ D: The `paths' pass N: Michael J. Spencer E: bigcheesegs@gmail.com D: Shepherding Windows COFF support into MC. +D: Lots of Windows stuff. N: Reid Spencer E: rspencer@reidspencer.com diff --git a/Makefile b/Makefile index ae650b7f2d93..dbb759dd5fce 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ LEVEL := . # Top-Level LLVM Build Stages: -# 1. Build lib/System and lib/Support, which are used by utils (tblgen). +# 1. Build lib/Support, which is used by utils (tblgen). # 2. Build utils, which is used by VMCore. # 3. Build VMCore, which builds the Intrinsics.inc file used by libs. # 4. Build libs, which are needed by llvm-config. @@ -27,10 +27,10 @@ LEVEL := . ifneq ($(findstring llvmCore, $(RC_ProjectName)),llvmCore) # Normal build (not "Apple-style"). ifeq ($(BUILD_DIRS_ONLY),1) - DIRS := lib/System lib/Support utils + DIRS := lib/Support utils OPTIONAL_DIRS := else - DIRS := lib/System lib/Support utils lib/VMCore lib tools/llvm-shlib \ + DIRS := lib/Support utils lib/VMCore lib tools/llvm-shlib \ tools/llvm-config tools runtime docs unittests OPTIONAL_DIRS := projects bindings endif @@ -47,6 +47,10 @@ ifneq ($(ENABLE_SHARED),1) DIRS := $(filter-out tools/llvm-shlib, $(DIRS)) endif +ifneq ($(ENABLE_DOCS),1) + DIRS := $(filter-out docs, $(DIRS)) +endif + ifeq ($(MAKECMDGOALS),libs-only) DIRS := $(filter-out tools runtime docs, $(DIRS)) OPTIONAL_DIRS := @@ -95,6 +99,11 @@ ifeq ($(MAKECMDGOALS),install) OPTIONAL_DIRS := $(filter bindings, $(OPTIONAL_DIRS)) endif +# Don't build unittests when ONLY_TOOLS is set. +ifneq ($(ONLY_TOOLS),) + DIRS := $(filter-out unittests, $(DIRS)) +endif + # If we're cross-compiling, build the build-hosted tools first ifeq ($(LLVM_CROSS_COMPILING),1) all:: cross-compile-build-tools @@ -150,7 +159,7 @@ dist-hook:: $(Echo) Eliminating files constructed by configure $(Verb) $(RM) -f \ $(TopDistDir)/include/llvm/Config/config.h \ - $(TopDistDir)/include/llvm/System/DataTypes.h + $(TopDistDir)/include/llvm/Support/DataTypes.h clang-only: all tools-only: all @@ -169,7 +178,7 @@ FilesToConfig := \ include/llvm/Config/AsmPrinters.def \ include/llvm/Config/AsmParsers.def \ include/llvm/Config/Disassemblers.def \ - include/llvm/System/DataTypes.h \ + include/llvm/Support/DataTypes.h \ tools/llvmc/src/Base.td FilesToConfigPATH := $(addprefix $(LLVM_OBJ_ROOT)/,$(FilesToConfig)) diff --git a/Makefile.config.in b/Makefile.config.in index 5ebd80384fb0..5c737580632e 100644 --- a/Makefile.config.in +++ b/Makefile.config.in @@ -164,7 +164,7 @@ CAT := @CAT@ DOT := @DOT@ DOXYGEN := @DOXYGEN@ GROFF := @GROFF@ -GZIP := @GZIP@ +GZIPBIN := @GZIPBIN@ OCAMLC := @OCAMLC@ OCAMLOPT := @OCAMLOPT@ OCAMLDEP := @OCAMLDEP@ @@ -195,6 +195,7 @@ LLVMGXX := @LLVMGXX@ LLVMCC1 := @LLVMCC1@ LLVMCC1PLUS := @LLVMCC1PLUS@ LLVMGCC_LANGS := @LLVMGCC_LANGS@ +LLVMGCC_DRAGONEGG := @LLVMGCC_DRAGONEGG@ # Information on Clang, if configured. CLANGPATH := @CLANGPATH@ @@ -204,6 +205,10 @@ ENABLE_BUILT_CLANG := @ENABLE_BUILT_CLANG@ # The LLVM capable compiler to use. LLVMCC_OPTION := @LLVMCC_OPTION@ +# The flag used to emit LLVM IR. +LLVMCC_EMITIR_FLAG = @LLVMCC_EMITIR_FLAG@ +LLVMCC_DISABLEOPT_FLAGS := @LLVMCC_DISABLEOPT_FLAGS@ + # Path to directory where object files should be stored during a build. # Set OBJ_ROOT to "." if you do not want to use a separate place for # object files. @@ -259,6 +264,9 @@ OPTIMIZE_OPTION := @OPTIMIZE_OPTION@ # information to allow gprof to be used to get execution frequencies. #ENABLE_PROFILING = 1 +# When ENABLE_DOCS is disabled, docs/ will not be built. +ENABLE_DOCS = @ENABLE_DOCS@ + # When ENABLE_DOXYGEN is enabled, the doxygen documentation will be built ENABLE_DOXYGEN = @ENABLE_DOXYGEN@ @@ -271,6 +279,9 @@ ENABLE_PIC := @ENABLE_PIC@ # Do we want to build a shared library and link the tools with it? ENABLE_SHARED := @ENABLE_SHARED@ +# Do we want to link the stdc++ into a shared library? (Cygming) +ENABLE_EMBED_STDCXX := @ENABLE_EMBED_STDCXX@ + # Use -fvisibility-inlines-hidden? ENABLE_VISIBILITY_INLINES_HIDDEN := @ENABLE_VISIBILITY_INLINES_HIDDEN@ @@ -341,6 +352,8 @@ NO_MISSING_FIELD_INITIALIZERS = @NO_MISSING_FIELD_INITIALIZERS@ # -Wno-variadic-macros NO_VARIADIC_MACROS = @NO_VARIADIC_MACROS@ +# Was polly found in tools/polly? +LLVM_HAS_POLLY = @LLVM_HAS_POLLY@ # Flags supported by the linker. # bfd ld / gold --version-script=file HAVE_LINK_VERSION_SCRIPT = @HAVE_LINK_VERSION_SCRIPT@ diff --git a/Makefile.rules b/Makefile.rules index 9cff1053d0d9..363fa9605b5a 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -129,11 +129,8 @@ reconfigure: $(ConfigStatusScript) --recheck $(ConfigureScriptFLAGS) && \ $(ConfigStatusScript) -# FIXME: The {PIC16,MSP430}/AsmPrinter line here is a hack to force a reconfigure to pick -# up AsmPrinter changes. Remove it after a reasonable delay from 2009-08-13. - .PRECIOUS: $(ConfigStatusScript) -$(ConfigStatusScript): $(ConfigureScript) $(LLVM_SRC_ROOT)/lib/Target/PIC16/AsmPrinter/Makefile $(LLVM_SRC_ROOT)/lib/Target/MSP430/AsmPrinter/Makefile +$(ConfigStatusScript): $(ConfigureScript) $(Echo) Reconfiguring with $< $(Verb) cd $(PROJ_OBJ_ROOT) && \ if test -w $(PROJ_OBJ_ROOT)/config.cache ; then \ @@ -161,9 +158,13 @@ endif # If the Makefile in the source tree has been updated, copy it over into the # build tree. But, only do this if the source and object makefiles differ #------------------------------------------------------------------------ +ifndef PROJ_MAKEFILE +PROJ_MAKEFILE := $(PROJ_SRC_DIR)/Makefile +endif + ifneq ($(PROJ_OBJ_DIR),$(PROJ_SRC_DIR)) -Makefile: $(PROJ_SRC_DIR)/Makefile $(ExtraMakefiles) +Makefile: $(PROJ_MAKEFILE) $(ExtraMakefiles) $(Echo) "Updating Makefile" $(Verb) $(MKDIR) $(@D) $(Verb) $(CP) -f $< $@ @@ -171,7 +172,7 @@ Makefile: $(PROJ_SRC_DIR)/Makefile $(ExtraMakefiles) # Copy the Makefile.* files unless we're in the root directory which avoids # the copying of Makefile.config.in or other things that should be explicitly # taken care of. -$(PROJ_OBJ_DIR)/Makefile% : $(PROJ_SRC_DIR)/Makefile% +$(PROJ_OBJ_DIR)/Makefile% : $(PROJ_MAKEFILE)% @case '$?' in \ *Makefile.rules) ;; \ *.in) ;; \ @@ -204,7 +205,7 @@ ifdef LLVMC_BASED_DRIVER TOOLNAME = $(LLVMC_BASED_DRIVER) LLVMLIBS = CompilerDriver.a -LINK_COMPONENTS = support system +LINK_COMPONENTS = support endif # LLVMC_BASED_DRIVER @@ -300,7 +301,7 @@ ifneq ($(REQUIRES_RTTI), 1) CXX.Flags += -fno-rtti endif -ifdef ENABLE_COVERAGE +ifeq ($(ENABLE_COVERAGE),1) BuildMode := $(BuildMode)+Coverage CXX.Flags += -ftest-coverage -fprofile-arcs C.Flags += -ftest-coverage -fprofile-arcs @@ -308,17 +309,17 @@ endif # If DISABLE_ASSERTIONS=1 is specified (make command line or configured), # then disable assertions by defining the appropriate preprocessor symbols. -ifndef DISABLE_ASSERTIONS +ifeq ($(DISABLE_ASSERTIONS),1) + CPP.Defines += -DNDEBUG +else BuildMode := $(BuildMode)+Asserts CPP.Defines += -D_DEBUG -else - CPP.Defines += -DNDEBUG endif # If ENABLE_EXPENSIVE_CHECKS=1 is specified (make command line or # configured), then enable expensive checks by defining the # appropriate preprocessor symbols. -ifdef ENABLE_EXPENSIVE_CHECKS +ifeq ($(ENABLE_EXPENSIVE_CHECKS),1) BuildMode := $(BuildMode)+Checks CPP.Defines += -D_GLIBCXX_DEBUG -DXDEBUG endif @@ -387,12 +388,21 @@ ifeq ($(ENABLE_PIC),0) CXX.Flags += -fPIC CPP.BaseFlags += -fPIC endif -endif -ifeq ($(ARCH),Alpha) LD.Flags += -Wl,--no-relax endif +# GNU ld/PECOFF accepts but ignores them below; +# --version-script +# --export-dynamic +# --rpath +# FIXME: autoconf should be aware of them. +ifneq (,$(filter $(HOST_OS),Cygwin MingW)) + HAVE_LINK_VERSION_SCRIPT := 0 + RPATH := + RDYNAMIC := -Wl,--export-all-symbols +endif + #-------------------------------------------------------------------- # Directory locations #-------------------------------------------------------------------- @@ -497,8 +507,8 @@ ifeq ($(HOST_OS),Darwin) # Get "4" out of 10.4 for later pieces in the makefile. DARWIN_MAJVERS := $(shell echo $(DARWIN_VERSION)| sed -E 's/10.([0-9]).*/\1/') - SharedLinkOptions=-Wl,-flat_namespace -Wl,-undefined,suppress \ - -dynamiclib + LoadableModuleOptions := -Wl,-flat_namespace -Wl,-undefined,suppress + SharedLinkOptions := -dynamiclib ifneq ($(ARCH),ARM) SharedLinkOptions += -mmacosx-version-min=$(DARWIN_VERSION) endif @@ -516,10 +526,6 @@ ifdef SHARED_LIBRARY ifneq ($(HOST_OS), $(filter $(HOST_OS), Cygwin MingW)) ifneq ($(HOST_OS),Darwin) LD.Flags += $(RPATH) -Wl,'$$ORIGIN' -else -ifneq ($(DARWIN_MAJVERS),4) - LD.Flags += $(RPATH) -Wl,$(SharedLibDir) -endif endif endif endif @@ -547,15 +553,21 @@ ifndef KEEP_SYMBOLS Install.StripFlag += -s endif +ifdef TOOL_NO_EXPORTS + DynamicFlags := +else + DynamicFlag := $(RDYNAMIC) +endif + # Adjust linker flags for building an executable ifneq ($(HOST_OS), $(filter $(HOST_OS), Cygwin MingW)) ifneq ($(HOST_OS), Darwin) ifdef TOOLNAME LD.Flags += $(RPATH) -Wl,'$$ORIGIN/../lib' ifdef EXAMPLE_TOOL - LD.Flags += $(RPATH) -Wl,$(ExmplDir) $(RDYNAMIC) + LD.Flags += $(RPATH) -Wl,$(ExmplDir) $(DynamicFlag) else - LD.Flags += $(RPATH) -Wl,$(ToolDir) $(RDYNAMIC) + LD.Flags += $(RPATH) -Wl,$(ToolDir) $(DynamicFlag) endif endif else @@ -618,11 +630,11 @@ else endif ifeq ($(HOST_OS),SunOS) -CPP.BaseFlags += -include llvm/System/Solaris.h +CPP.BaseFlags += -include llvm/Support/Solaris.h endif ifeq ($(HOST_OS),AuroraUX) -CPP.BaseFlags += -include llvm/System/Solaris.h +CPP.BaseFlags += -include llvm/Support/Solaris.h endif # !HOST_OS - AuroraUX. LD.Flags += -L$(LibDir) -L$(LLVMLibDir) @@ -828,7 +840,9 @@ $(RecursiveTargets):: else $(RecursiveTargets):: $(Verb) for dir in $(OPTIONAL_DIRS); do \ - ($(MAKE) -C$$dir $@ ) || exit 1; \ + if [ -d $(PROJ_SRC_DIR)/$$dir ]; then\ + ($(MAKE) -C$$dir $@ ) || exit 1; \ + fi \ done endif endif @@ -890,10 +904,13 @@ LLVMUsedLibs := $(patsubst %.a.o, lib%.a, $(addsuffix .o, $(LLVMLIBS))) LLVMLibsPaths := $(addprefix $(LLVMLibDir)/,$(LLVMUsedLibs)) endif -# Win32.DLL may refer to other components. -ifeq ($(HOST_OS), $(filter $(HOST_OS), Cygwin MingW)) +# Loadable module for Win32 requires all symbols resolved for linking. +# Then all symbols in LLVM.dll will be available. +ifeq ($(ENABLE_SHARED),1) ifdef LOADABLE_MODULE - LINK_COMPONENTS := all + ifneq (,$(filter $(HOST_OS),Cygwin MingW)) + LINK_COMPONENTS += all + endif endif endif @@ -941,11 +958,6 @@ ifdef EXPORTED_SYMBOL_FILE # First, set up the native export file, which may differ from the source # export file. -# The option --version-script is not effective on GNU ld win32. -ifneq (,$(filter $(HOST_OS),Cygwin MingW)) - HAVE_LINK_VERSION_SCRIPT := 0 -endif - ifeq ($(HOST_OS),Darwin) # Darwin convention prefixes symbols with underscores. NativeExportsFile := $(ObjDir)/$(notdir $(EXPORTED_SYMBOL_FILE)).sed @@ -1073,12 +1085,14 @@ ifdef LIBRARYNAME # Make sure there isn't any extraneous whitespace on the LIBRARYNAME option LIBRARYNAME := $(strip $(LIBRARYNAME)) ifdef LOADABLE_MODULE -LibName.A := $(LibDir)/$(LIBRARYNAME).a -LibName.SO := $(SharedLibDir)/$(LIBRARYNAME)$(SHLIBEXT) +BaseLibName.A := $(LIBRARYNAME).a +BaseLibName.SO := $(LIBRARYNAME)$(SHLIBEXT) else -LibName.A := $(LibDir)/lib$(LIBRARYNAME).a -LibName.SO := $(SharedLibDir)/$(SharedPrefix)$(LIBRARYNAME)$(SHLIBEXT) +BaseLibName.A := lib$(LIBRARYNAME).a +BaseLibName.SO := $(SharedPrefix)$(LIBRARYNAME)$(SHLIBEXT) endif +LibName.A := $(LibDir)/$(BaseLibName.A) +LibName.SO := $(SharedLibDir)/$(BaseLibName.SO) LibName.O := $(LibDir)/$(LIBRARYNAME).o LibName.BCA:= $(LibDir)/lib$(LIBRARYNAME).bca @@ -1099,6 +1113,7 @@ endif ifdef LINK_LIBS_IN_SHARED ifdef LOADABLE_MODULE SharedLibKindMessage := "Loadable Module" +SharedLinkOptions := $(LoadableModuleOptions) $(SharedLinkOptions) else SharedLibKindMessage := "Shared Library" endif @@ -1131,7 +1146,7 @@ DestSharedLibDir := $(DESTDIR)$(PROJ_bindir) else DestSharedLibDir := $(DESTDIR)$(PROJ_libdir) endif -DestSharedLib := $(DestSharedLibDir)/$(SharedPrefix)$(LIBRARYNAME)$(SHLIBEXT) +DestSharedLib := $(DestSharedLibDir)/$(BaseLibName.SO) install-local:: $(DestSharedLib) @@ -1323,6 +1338,18 @@ endif endif endif +#--------------------------------------------------------- +# Tool Order File Support +#--------------------------------------------------------- + +ifeq ($(HOST_OS),Darwin) +ifdef TOOL_ORDER_FINE + +LD.Flags += -Wl,-order_file,$(TOOL_ORDER_FILE) + +endif +endif + #--------------------------------------------------------- # Tool Version Info Support #--------------------------------------------------------- @@ -1441,27 +1468,27 @@ DEPEND_OPTIONS = -MMD -MP -MF "$(ObjDir)/$*.d.tmp" \ DEPEND_MOVEFILE = then $(MV) -f "$(ObjDir)/$*.d.tmp" "$(ObjDir)/$*.d"; \ else $(RM) "$(ObjDir)/$*.d.tmp"; exit 1; fi -$(ObjDir)/%.o: %.cpp $(ObjDir)/.dir $(BUILT_SOURCES) $(PROJ_SRC_DIR)/Makefile +$(ObjDir)/%.o: %.cpp $(ObjDir)/.dir $(BUILT_SOURCES) $(PROJ_MAKEFILE) $(Echo) "Compiling $*.cpp for $(BuildMode) build" $(PIC_FLAG) $(Verb) if $(Compile.CXX) $(DEPEND_OPTIONS) $< -o $(ObjDir)/$*.o ; \ $(DEPEND_MOVEFILE) -$(ObjDir)/%.o: %.mm $(ObjDir)/.dir $(BUILT_SOURCES) $(PROJ_SRC_DIR)/Makefile +$(ObjDir)/%.o: %.mm $(ObjDir)/.dir $(BUILT_SOURCES) $(PROJ_MAKEFILE) $(Echo) "Compiling $*.mm for $(BuildMode) build" $(PIC_FLAG) $(Verb) if $(Compile.CXX) $(DEPEND_OPTIONS) $< -o $(ObjDir)/$*.o ; \ $(DEPEND_MOVEFILE) -$(ObjDir)/%.o: %.cc $(ObjDir)/.dir $(BUILT_SOURCES) $(PROJ_SRC_DIR)/Makefile +$(ObjDir)/%.o: %.cc $(ObjDir)/.dir $(BUILT_SOURCES) $(PROJ_MAKEFILE) $(Echo) "Compiling $*.cc for $(BuildMode) build" $(PIC_FLAG) $(Verb) if $(Compile.CXX) $(DEPEND_OPTIONS) $< -o $(ObjDir)/$*.o ; \ $(DEPEND_MOVEFILE) -$(ObjDir)/%.o: %.c $(ObjDir)/.dir $(BUILT_SOURCES) $(PROJ_SRC_DIR)/Makefile +$(ObjDir)/%.o: %.c $(ObjDir)/.dir $(BUILT_SOURCES) $(PROJ_MAKEFILE) $(Echo) "Compiling $*.c for $(BuildMode) build" $(PIC_FLAG) $(Verb) if $(Compile.C) $(DEPEND_OPTIONS) $< -o $(ObjDir)/$*.o ; \ $(DEPEND_MOVEFILE) -$(ObjDir)/%.o: %.m $(ObjDir)/.dir $(BUILT_SOURCES) $(PROJ_SRC_DIR)/Makefile +$(ObjDir)/%.o: %.m $(ObjDir)/.dir $(BUILT_SOURCES) $(PROJ_MAKEFILE) $(Echo) "Compiling $*.m for $(BuildMode) build" $(PIC_FLAG) $(Verb) if $(Compile.C) $(DEPEND_OPTIONS) $< -o $(ObjDir)/$*.o ; \ $(DEPEND_MOVEFILE) @@ -1481,31 +1508,31 @@ BC_DEPEND_MOVEFILE = then $(MV) -f "$(ObjDir)/$*.bc.d.tmp" "$(ObjDir)/$*.bc.d"; $(ObjDir)/%.ll: %.cpp $(ObjDir)/.dir $(BUILT_SOURCES) $(LLVMCXX) $(Echo) "Compiling $*.cpp for $(BuildMode) build (bytecode)" $(Verb) if $(BCCompile.CXX) $(BC_DEPEND_OPTIONS) \ - $< -o $(ObjDir)/$*.ll -S -emit-llvm ; \ + $< -o $(ObjDir)/$*.ll -S -$(LLVMCC_EMITIR_FLAG) ; \ $(BC_DEPEND_MOVEFILE) $(ObjDir)/%.ll: %.mm $(ObjDir)/.dir $(BUILT_SOURCES) $(LLVMCXX) $(Echo) "Compiling $*.mm for $(BuildMode) build (bytecode)" $(Verb) if $(BCCompile.CXX) $(BC_DEPEND_OPTIONS) \ - $< -o $(ObjDir)/$*.ll -S -emit-llvm ; \ + $< -o $(ObjDir)/$*.ll -S -$(LLVMCC_EMITIR_FLAG) ; \ $(BC_DEPEND_MOVEFILE) $(ObjDir)/%.ll: %.cc $(ObjDir)/.dir $(BUILT_SOURCES) $(LLVMCXX) $(Echo) "Compiling $*.cc for $(BuildMode) build (bytecode)" $(Verb) if $(BCCompile.CXX) $(BC_DEPEND_OPTIONS) \ - $< -o $(ObjDir)/$*.ll -S -emit-llvm ; \ + $< -o $(ObjDir)/$*.ll -S -$(LLVMCC_EMITIR_FLAG) ; \ $(BC_DEPEND_MOVEFILE) $(ObjDir)/%.ll: %.c $(ObjDir)/.dir $(BUILT_SOURCES) $(LLVMCC) $(Echo) "Compiling $*.c for $(BuildMode) build (bytecode)" $(Verb) if $(BCCompile.C) $(BC_DEPEND_OPTIONS) \ - $< -o $(ObjDir)/$*.ll -S -emit-llvm ; \ + $< -o $(ObjDir)/$*.ll -S -$(LLVMCC_EMITIR_FLAG) ; \ $(BC_DEPEND_MOVEFILE) $(ObjDir)/%.ll: %.m $(ObjDir)/.dir $(BUILT_SOURCES) $(LLVMCC) $(Echo) "Compiling $*.m for $(BuildMode) build (bytecode)" $(Verb) if $(BCCompile.C) $(BC_DEPEND_OPTIONS) \ - $< -o $(ObjDir)/$*.ll -S -emit-llvm ; \ + $< -o $(ObjDir)/$*.ll -S -$(LLVMCC_EMITIR_FLAG) ; \ $(BC_DEPEND_MOVEFILE) # Provide alternate rule sets if dependencies are disabled @@ -1533,23 +1560,23 @@ $(ObjDir)/%.o: %.m $(ObjDir)/.dir $(BUILT_SOURCES) $(ObjDir)/%.ll: %.cpp $(ObjDir)/.dir $(BUILT_SOURCES) $(LLVMCXX) $(Echo) "Compiling $*.cpp for $(BuildMode) build (bytecode)" - $(BCCompile.CXX) $< -o $@ -S -emit-llvm + $(BCCompile.CXX) $< -o $@ -S -$(LLVMCC_EMITIR_FLAG) $(ObjDir)/%.ll: %.mm $(ObjDir)/.dir $(BUILT_SOURCES) $(LLVMCXX) $(Echo) "Compiling $*.mm for $(BuildMode) build (bytecode)" - $(BCCompile.CXX) $< -o $@ -S -emit-llvm + $(BCCompile.CXX) $< -o $@ -S -$(LLVMCC_EMITIR_FLAG) $(ObjDir)/%.ll: %.cc $(ObjDir)/.dir $(BUILT_SOURCES) $(LLVMCXX) $(Echo) "Compiling $*.cc for $(BuildMode) build (bytecode)" - $(BCCompile.CXX) $< -o $@ -S -emit-llvm + $(BCCompile.CXX) $< -o $@ -S -$(LLVMCC_EMITIR_FLAG) $(ObjDir)/%.ll: %.c $(ObjDir)/.dir $(BUILT_SOURCES) $(LLVMCC) $(Echo) "Compiling $*.c for $(BuildMode) build (bytecode)" - $(BCCompile.C) $< -o $@ -S -emit-llvm + $(BCCompile.C) $< -o $@ -S -$(LLVMCC_EMITIR_FLAG) $(ObjDir)/%.ll: %.m $(ObjDir)/.dir $(BUILT_SOURCES) $(LLVMCC) $(Echo) "Compiling $*.m for $(BuildMode) build (bytecode)" - $(BCCompile.C) $< -o $@ -S -emit-llvm + $(BCCompile.C) $< -o $@ -S -$(LLVMCC_EMITIR_FLAG) endif @@ -1699,6 +1726,11 @@ $(ObjDir)/%GenAsmMatcher.inc.tmp : %.td $(ObjDir)/.dir $(Echo) "Building $( /dev/null 2>&1 + if test $? -eq 0 ; then + llvm_cv_llvmgcc_dragonegg="yes" + fi + rm conftest.c +fi]) + +dnl Set the flags needed to emit LLVM IR and to disable optimizations +dnl in llvmgcc +if test "$llvm_cv_llvmgcc_dragonegg" = "yes" ; then + LLVMCC_EMITIR_FLAG="-fplugin-arg-dragonegg-emit-ir" + LLVMCC_DISABLEOPT_FLAGS="-fplugin-arg-dragonegg-disable-llvm-optzns" +else + LLVMCC_EMITIR_FLAG="-emit-llvm" + LLVMCC_DISABLEOPT_FLAGS="-mllvm -disable-llvm-optzns" +fi + +AC_SUBST(LLVMCC_EMITIR_FLAG) + dnl See if the llvm-gcc executable can compile to LLVM assembly AC_CACHE_CHECK([whether llvm-gcc is sane],[llvm_cv_llvmgcc_sanity], [llvm_cv_llvmgcc_sanity="no" -if test -x "$LLVMGCC" ; then +if test -n "$LLVMGCC" ; then cp /dev/null conftest.c - "$LLVMGCC" -emit-llvm -S -o - conftest.c | \ + $LLVMGCC "$LLVMCC_EMITIR_FLAG" -S -o - conftest.c | \ grep 'target datalayout =' > /dev/null 2>&1 if test $? -eq 0 ; then llvm_cv_llvmgcc_sanity="yes" @@ -1386,16 +1525,19 @@ if test -x "$LLVMGCC" ; then fi]) dnl Since we have a sane llvm-gcc, identify it and its sub-tools +dnl Furthermore, add some information about the tools if test "$llvm_cv_llvmgcc_sanity" = "yes" ; then AC_MSG_CHECKING([llvm-gcc component support]) - llvmcc1path=`"$LLVMGCC" --print-prog-name=cc1` + llvmcc1path=`$LLVMGCC --print-prog-name=cc1` AC_SUBST(LLVMCC1,$llvmcc1path) - llvmcc1pluspath=`"$LLVMGCC" --print-prog-name=cc1plus` + llvmcc1pluspath=`$LLVMGCC --print-prog-name=cc1plus` AC_SUBST(LLVMCC1PLUS,$llvmcc1pluspath) llvmgccdir=`echo "$llvmcc1path" | sed 's,/libexec/.*,,'` AC_SUBST(LLVMGCCDIR,$llvmgccdir) - llvmgcclangs=[`"$LLVMGCC" -v --help 2>&1 | grep '^Configured with:' | sed 's/^.*--enable-languages=\([^ ]*\).*/\1/'`] + llvmgcclangs=[`$LLVMGCC -v --help 2>&1 | grep '^Configured with:' | sed 's/^.*--enable-languages=\([^ ]*\).*/\1/'`] AC_SUBST(LLVMGCC_LANGS,$llvmgcclangs) + AC_SUBST(LLVMGCC_DRAGONEGG,$llvm_cv_llvmgcc_dragonegg) + AC_SUBST(LLVMCC_DISABLEOPT_FLAGS) AC_MSG_RESULT([ok]) fi @@ -1548,7 +1690,7 @@ AC_CONFIG_FILES([include/llvm/Config/Targets.def]) AC_CONFIG_FILES([include/llvm/Config/AsmPrinters.def]) AC_CONFIG_FILES([include/llvm/Config/AsmParsers.def]) AC_CONFIG_FILES([include/llvm/Config/Disassemblers.def]) -AC_CONFIG_HEADERS([include/llvm/System/DataTypes.h]) +AC_CONFIG_HEADERS([include/llvm/Support/DataTypes.h]) dnl Configure the makefile's configuration data AC_CONFIG_FILES([Makefile.config]) diff --git a/bindings/ada/analysis/llvm_analysis-binding.ads b/bindings/ada/analysis/llvm_analysis-binding.ads deleted file mode 100644 index c51a50353f11..000000000000 --- a/bindings/ada/analysis/llvm_analysis-binding.ads +++ /dev/null @@ -1,32 +0,0 @@ --- This file is generated by SWIG. Do *not* modify by hand. --- - -with llvm; -with Interfaces.C.Strings; - - -package LLVM_Analysis.Binding is - - function LLVMVerifyModule - (M : in llvm.LLVMModuleRef; - Action : in LLVM_Analysis.LLVMVerifierFailureAction; - OutMessage : access Interfaces.C.Strings.chars_ptr) - return Interfaces.C.int; - - function LLVMVerifyFunction - (Fn : in llvm.LLVMValueRef; - Action : in LLVM_Analysis.LLVMVerifierFailureAction) - return Interfaces.C.int; - - procedure LLVMViewFunctionCFG (Fn : in llvm.LLVMValueRef); - - procedure LLVMViewFunctionCFGOnly (Fn : in llvm.LLVMValueRef); - -private - - pragma Import (C, LLVMVerifyModule, "Ada_LLVMVerifyModule"); - pragma Import (C, LLVMVerifyFunction, "Ada_LLVMVerifyFunction"); - pragma Import (C, LLVMViewFunctionCFG, "Ada_LLVMViewFunctionCFG"); - pragma Import (C, LLVMViewFunctionCFGOnly, "Ada_LLVMViewFunctionCFGOnly"); - -end LLVM_Analysis.Binding; diff --git a/bindings/ada/analysis/llvm_analysis.ads b/bindings/ada/analysis/llvm_analysis.ads deleted file mode 100644 index aa7b3f0e2e91..000000000000 --- a/bindings/ada/analysis/llvm_analysis.ads +++ /dev/null @@ -1,30 +0,0 @@ --- This file is generated by SWIG. Do *not* modify by hand. --- - -with Interfaces.C; - - -package LLVM_Analysis is - - -- LLVMVerifierFailureAction - -- - type LLVMVerifierFailureAction is ( - LLVMAbortProcessAction, - LLVMPrintMessageAction, - LLVMReturnStatusAction); - - for LLVMVerifierFailureAction use - (LLVMAbortProcessAction => 0, - LLVMPrintMessageAction => 1, - LLVMReturnStatusAction => 2); - - pragma Convention (C, LLVMVerifierFailureAction); - - type LLVMVerifierFailureAction_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_Analysis.LLVMVerifierFailureAction; - - type LLVMVerifierFailureAction_view is access all - LLVM_Analysis.LLVMVerifierFailureAction; - -end LLVM_Analysis; diff --git a/bindings/ada/analysis/llvm_analysis_wrap.cxx b/bindings/ada/analysis/llvm_analysis_wrap.cxx deleted file mode 100644 index f2a8637343de..000000000000 --- a/bindings/ada/analysis/llvm_analysis_wrap.cxx +++ /dev/null @@ -1,369 +0,0 @@ -/* ---------------------------------------------------------------------------- - * This file was automatically generated by SWIG (http://www.swig.org). - * Version 1.3.36 - * - * This file is not intended to be easily readable and contains a number of - * coding conventions designed to improve portability and efficiency. Do not make - * changes to this file unless you know what you are doing--modify the SWIG - * interface file instead. - * ----------------------------------------------------------------------------- */ - - -#ifdef __cplusplus -template class SwigValueWrapper { - T *tt; -public: - SwigValueWrapper() : tt(0) { } - SwigValueWrapper(const SwigValueWrapper& rhs) : tt(new T(*rhs.tt)) { } - SwigValueWrapper(const T& t) : tt(new T(t)) { } - ~SwigValueWrapper() { delete tt; } - SwigValueWrapper& operator=(const T& t) { delete tt; tt = new T(t); return *this; } - operator T&() const { return *tt; } - T *operator&() { return tt; } -private: - SwigValueWrapper& operator=(const SwigValueWrapper& rhs); -}; - -template T SwigValueInit() { - return T(); -} -#endif - -/* ----------------------------------------------------------------------------- - * This section contains generic SWIG labels for method/variable - * declarations/attributes, and other compiler dependent labels. - * ----------------------------------------------------------------------------- */ - -/* template workaround for compilers that cannot correctly implement the C++ standard */ -#ifndef SWIGTEMPLATEDISAMBIGUATOR -# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) -# define SWIGTEMPLATEDISAMBIGUATOR template -# elif defined(__HP_aCC) -/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ -/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ -# define SWIGTEMPLATEDISAMBIGUATOR template -# else -# define SWIGTEMPLATEDISAMBIGUATOR -# endif -#endif - -/* inline attribute */ -#ifndef SWIGINLINE -# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) -# define SWIGINLINE inline -# else -# define SWIGINLINE -# endif -#endif - -/* attribute recognised by some compilers to avoid 'unused' warnings */ -#ifndef SWIGUNUSED -# if defined(__GNUC__) -# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -# elif defined(__ICC) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -#endif - -#ifndef SWIGUNUSEDPARM -# ifdef __cplusplus -# define SWIGUNUSEDPARM(p) -# else -# define SWIGUNUSEDPARM(p) p SWIGUNUSED -# endif -#endif - -/* internal SWIG method */ -#ifndef SWIGINTERN -# define SWIGINTERN static SWIGUNUSED -#endif - -/* internal inline SWIG method */ -#ifndef SWIGINTERNINLINE -# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE -#endif - -/* exporting methods */ -#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -# ifndef GCC_HASCLASSVISIBILITY -# define GCC_HASCLASSVISIBILITY -# endif -#endif - -#ifndef SWIGEXPORT -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# if defined(STATIC_LINKED) -# define SWIGEXPORT -# else -# define SWIGEXPORT __declspec(dllexport) -# endif -# else -# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) -# define SWIGEXPORT __attribute__ ((visibility("default"))) -# else -# define SWIGEXPORT -# endif -# endif -#endif - -/* calling conventions for Windows */ -#ifndef SWIGSTDCALL -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# define SWIGSTDCALL __stdcall -# else -# define SWIGSTDCALL -# endif -#endif - -/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ -#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) -# define _CRT_SECURE_NO_DEPRECATE -#endif - -/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ -#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) -# define _SCL_SECURE_NO_DEPRECATE -#endif - - - -#include -#include -#include -#if defined(_WIN32) || defined(__CYGWIN32__) -# define DllExport __declspec( dllexport ) -# define SWIGSTDCALL __stdcall -#else -# define DllExport -# define SWIGSTDCALL -#endif - - -#ifdef __cplusplus -# include -#endif - - - - -/* Support for throwing Ada exceptions from C/C++ */ - -typedef enum -{ - SWIG_AdaException, - SWIG_AdaOutOfMemoryException, - SWIG_AdaIndexOutOfRangeException, - SWIG_AdaDivideByZeroException, - SWIG_AdaArgumentOutOfRangeException, - SWIG_AdaNullReferenceException -} SWIG_AdaExceptionCodes; - - -typedef void (SWIGSTDCALL* SWIG_AdaExceptionCallback_t)(const char *); - - -typedef struct -{ - SWIG_AdaExceptionCodes code; - SWIG_AdaExceptionCallback_t callback; -} - SWIG_AdaExceptions_t; - - -static -SWIG_AdaExceptions_t -SWIG_ada_exceptions[] = -{ - { SWIG_AdaException, NULL }, - { SWIG_AdaOutOfMemoryException, NULL }, - { SWIG_AdaIndexOutOfRangeException, NULL }, - { SWIG_AdaDivideByZeroException, NULL }, - { SWIG_AdaArgumentOutOfRangeException, NULL }, - { SWIG_AdaNullReferenceException, NULL } -}; - - -static -void -SWIG_AdaThrowException (SWIG_AdaExceptionCodes code, const char *msg) -{ - SWIG_AdaExceptionCallback_t callback = SWIG_ada_exceptions[SWIG_AdaException].callback; - if (code >=0 && (size_t)code < sizeof(SWIG_ada_exceptions)/sizeof(SWIG_AdaExceptions_t)) { - callback = SWIG_ada_exceptions[code].callback; - } - callback(msg); -} - - - -#ifdef __cplusplus -extern "C" -#endif - -DllExport void SWIGSTDCALL SWIGRegisterExceptionCallbacks_LLVM_Analysis (SWIG_AdaExceptionCallback_t systemException, - SWIG_AdaExceptionCallback_t outOfMemory, - SWIG_AdaExceptionCallback_t indexOutOfRange, - SWIG_AdaExceptionCallback_t divideByZero, - SWIG_AdaExceptionCallback_t argumentOutOfRange, - SWIG_AdaExceptionCallback_t nullReference) -{ - SWIG_ada_exceptions [SWIG_AdaException].callback = systemException; - SWIG_ada_exceptions [SWIG_AdaOutOfMemoryException].callback = outOfMemory; - SWIG_ada_exceptions [SWIG_AdaIndexOutOfRangeException].callback = indexOutOfRange; - SWIG_ada_exceptions [SWIG_AdaDivideByZeroException].callback = divideByZero; - SWIG_ada_exceptions [SWIG_AdaArgumentOutOfRangeException].callback = argumentOutOfRange; - SWIG_ada_exceptions [SWIG_AdaNullReferenceException].callback = nullReference; -} - - -/* Callback for returning strings to Ada without leaking memory */ - -typedef char * (SWIGSTDCALL* SWIG_AdaStringHelperCallback)(const char *); -static SWIG_AdaStringHelperCallback SWIG_ada_string_callback = NULL; - - - -/* probably obsolete ... -#ifdef __cplusplus -extern "C" -#endif -DllExport void SWIGSTDCALL SWIGRegisterStringCallback_LLVM_Analysis(SWIG_AdaStringHelperCallback callback) { - SWIG_ada_string_callback = callback; -} -*/ - - - -/* Contract support */ - -#define SWIG_contract_assert(nullreturn, expr, msg) if (!(expr)) {SWIG_AdaThrowException(SWIG_AdaArgumentOutOfRangeException, msg); return nullreturn; } else - - -#define protected public -#define private public - -#include "llvm-c/Analysis.h" -//#include "llvm-c/BitReader.h" -//#include "llvm-c/BitWriter.h" -//#include "llvm-c/Core.h" -//#include "llvm-c/ExecutionEngine.h" -//#include "llvm-c/LinkTimeOptimizer.h" -//#include "llvm-c/lto.h" -//#include "llvm-c/Target.h" - - - -// struct LLVMCtxt; - - -#undef protected -#undef private -#ifdef __cplusplus -extern "C" { -#endif -DllExport int SWIGSTDCALL Ada_LLVMVerifyModule ( - void * jarg1 - , - - int jarg2 - , - - void * jarg3 - ) -{ - int jresult ; - LLVMModuleRef arg1 = (LLVMModuleRef) 0 ; - LLVMVerifierFailureAction arg2 ; - char **arg3 = (char **) 0 ; - int result; - - arg1 = (LLVMModuleRef)jarg1; - - arg2 = (LLVMVerifierFailureAction) jarg2; - - arg3 = (char **)jarg3; - - result = (int)LLVMVerifyModule(arg1,arg2,arg3); - jresult = result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMVerifyFunction ( - void * jarg1 - , - - int jarg2 - ) -{ - int jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMVerifierFailureAction arg2 ; - int result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMVerifierFailureAction) jarg2; - - result = (int)LLVMVerifyFunction(arg1,arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMViewFunctionCFG ( - void * jarg1 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - - arg1 = (LLVMValueRef)jarg1; - - LLVMViewFunctionCFG(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMViewFunctionCFGOnly ( - void * jarg1 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - - arg1 = (LLVMValueRef)jarg1; - - LLVMViewFunctionCFGOnly(arg1); - - -} - - - -#ifdef __cplusplus -} -#endif -#ifdef __cplusplus -extern "C" { -#endif -#ifdef __cplusplus -} -#endif - diff --git a/bindings/ada/bitreader/llvm_bit_reader-binding.ads b/bindings/ada/bitreader/llvm_bit_reader-binding.ads deleted file mode 100644 index 4fcdb4a84fcf..000000000000 --- a/bindings/ada/bitreader/llvm_bit_reader-binding.ads +++ /dev/null @@ -1,52 +0,0 @@ --- This file is generated by SWIG. Do *not* modify by hand. --- - -with llvm; -with Interfaces.C.Strings; - - -package LLVM_bit_Reader.Binding is - - function LLVMParseBitcode - (MemBuf : in llvm.LLVMMemoryBufferRef; - OutModule : access llvm.LLVMModuleRef; - OutMessage : access Interfaces.C.Strings.chars_ptr) - return Interfaces.C.int; - - function LLVMParseBitcodeInContext - (MemBuf : in llvm.LLVMMemoryBufferRef; - ContextRef : in llvm.LLVMContextRef; - OutModule : access llvm.LLVMModuleRef; - OutMessage : access Interfaces.C.Strings.chars_ptr) - return Interfaces.C.int; - - function LLVMGetBitcodeModuleProvider - (MemBuf : in llvm.LLVMMemoryBufferRef; - OutMP : access llvm.LLVMModuleProviderRef; - OutMessage : access Interfaces.C.Strings.chars_ptr) - return Interfaces.C.int; - - function LLVMGetBitcodeModuleProviderInContext - (MemBuf : in llvm.LLVMMemoryBufferRef; - ContextRef : in llvm.LLVMContextRef; - OutMP : access llvm.LLVMModuleProviderRef; - OutMessage : access Interfaces.C.Strings.chars_ptr) - return Interfaces.C.int; - -private - - pragma Import (C, LLVMParseBitcode, "Ada_LLVMParseBitcode"); - pragma Import - (C, - LLVMParseBitcodeInContext, - "Ada_LLVMParseBitcodeInContext"); - pragma Import - (C, - LLVMGetBitcodeModuleProvider, - "Ada_LLVMGetBitcodeModuleProvider"); - pragma Import - (C, - LLVMGetBitcodeModuleProviderInContext, - "Ada_LLVMGetBitcodeModuleProviderInContext"); - -end LLVM_bit_Reader.Binding; diff --git a/bindings/ada/bitreader/llvm_bit_reader.ads b/bindings/ada/bitreader/llvm_bit_reader.ads deleted file mode 100644 index 7579dea2819d..000000000000 --- a/bindings/ada/bitreader/llvm_bit_reader.ads +++ /dev/null @@ -1,6 +0,0 @@ --- This file is generated by SWIG. Do *not* modify by hand. --- - -package LLVM_bit_Reader is - -end LLVM_bit_Reader; diff --git a/bindings/ada/bitreader/llvm_bitreader_wrap.cxx b/bindings/ada/bitreader/llvm_bitreader_wrap.cxx deleted file mode 100644 index b7ecbed355af..000000000000 --- a/bindings/ada/bitreader/llvm_bitreader_wrap.cxx +++ /dev/null @@ -1,423 +0,0 @@ -/* ---------------------------------------------------------------------------- - * This file was automatically generated by SWIG (http://www.swig.org). - * Version 1.3.36 - * - * This file is not intended to be easily readable and contains a number of - * coding conventions designed to improve portability and efficiency. Do not make - * changes to this file unless you know what you are doing--modify the SWIG - * interface file instead. - * ----------------------------------------------------------------------------- */ - - -#ifdef __cplusplus -template class SwigValueWrapper { - T *tt; -public: - SwigValueWrapper() : tt(0) { } - SwigValueWrapper(const SwigValueWrapper& rhs) : tt(new T(*rhs.tt)) { } - SwigValueWrapper(const T& t) : tt(new T(t)) { } - ~SwigValueWrapper() { delete tt; } - SwigValueWrapper& operator=(const T& t) { delete tt; tt = new T(t); return *this; } - operator T&() const { return *tt; } - T *operator&() { return tt; } -private: - SwigValueWrapper& operator=(const SwigValueWrapper& rhs); -}; - -template T SwigValueInit() { - return T(); -} -#endif - -/* ----------------------------------------------------------------------------- - * This section contains generic SWIG labels for method/variable - * declarations/attributes, and other compiler dependent labels. - * ----------------------------------------------------------------------------- */ - -/* template workaround for compilers that cannot correctly implement the C++ standard */ -#ifndef SWIGTEMPLATEDISAMBIGUATOR -# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) -# define SWIGTEMPLATEDISAMBIGUATOR template -# elif defined(__HP_aCC) -/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ -/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ -# define SWIGTEMPLATEDISAMBIGUATOR template -# else -# define SWIGTEMPLATEDISAMBIGUATOR -# endif -#endif - -/* inline attribute */ -#ifndef SWIGINLINE -# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) -# define SWIGINLINE inline -# else -# define SWIGINLINE -# endif -#endif - -/* attribute recognised by some compilers to avoid 'unused' warnings */ -#ifndef SWIGUNUSED -# if defined(__GNUC__) -# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -# elif defined(__ICC) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -#endif - -#ifndef SWIGUNUSEDPARM -# ifdef __cplusplus -# define SWIGUNUSEDPARM(p) -# else -# define SWIGUNUSEDPARM(p) p SWIGUNUSED -# endif -#endif - -/* internal SWIG method */ -#ifndef SWIGINTERN -# define SWIGINTERN static SWIGUNUSED -#endif - -/* internal inline SWIG method */ -#ifndef SWIGINTERNINLINE -# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE -#endif - -/* exporting methods */ -#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -# ifndef GCC_HASCLASSVISIBILITY -# define GCC_HASCLASSVISIBILITY -# endif -#endif - -#ifndef SWIGEXPORT -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# if defined(STATIC_LINKED) -# define SWIGEXPORT -# else -# define SWIGEXPORT __declspec(dllexport) -# endif -# else -# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) -# define SWIGEXPORT __attribute__ ((visibility("default"))) -# else -# define SWIGEXPORT -# endif -# endif -#endif - -/* calling conventions for Windows */ -#ifndef SWIGSTDCALL -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# define SWIGSTDCALL __stdcall -# else -# define SWIGSTDCALL -# endif -#endif - -/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ -#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) -# define _CRT_SECURE_NO_DEPRECATE -#endif - -/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ -#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) -# define _SCL_SECURE_NO_DEPRECATE -#endif - - - -#include -#include -#include -#if defined(_WIN32) || defined(__CYGWIN32__) -# define DllExport __declspec( dllexport ) -# define SWIGSTDCALL __stdcall -#else -# define DllExport -# define SWIGSTDCALL -#endif - - -#ifdef __cplusplus -# include -#endif - - - - -/* Support for throwing Ada exceptions from C/C++ */ - -typedef enum -{ - SWIG_AdaException, - SWIG_AdaOutOfMemoryException, - SWIG_AdaIndexOutOfRangeException, - SWIG_AdaDivideByZeroException, - SWIG_AdaArgumentOutOfRangeException, - SWIG_AdaNullReferenceException -} SWIG_AdaExceptionCodes; - - -typedef void (SWIGSTDCALL* SWIG_AdaExceptionCallback_t)(const char *); - - -typedef struct -{ - SWIG_AdaExceptionCodes code; - SWIG_AdaExceptionCallback_t callback; -} - SWIG_AdaExceptions_t; - - -static -SWIG_AdaExceptions_t -SWIG_ada_exceptions[] = -{ - { SWIG_AdaException, NULL }, - { SWIG_AdaOutOfMemoryException, NULL }, - { SWIG_AdaIndexOutOfRangeException, NULL }, - { SWIG_AdaDivideByZeroException, NULL }, - { SWIG_AdaArgumentOutOfRangeException, NULL }, - { SWIG_AdaNullReferenceException, NULL } -}; - - -static -void -SWIG_AdaThrowException (SWIG_AdaExceptionCodes code, const char *msg) -{ - SWIG_AdaExceptionCallback_t callback = SWIG_ada_exceptions[SWIG_AdaException].callback; - if (code >=0 && (size_t)code < sizeof(SWIG_ada_exceptions)/sizeof(SWIG_AdaExceptions_t)) { - callback = SWIG_ada_exceptions[code].callback; - } - callback(msg); -} - - - -#ifdef __cplusplus -extern "C" -#endif - -DllExport void SWIGSTDCALL SWIGRegisterExceptionCallbacks_LLVM_bit_Reader (SWIG_AdaExceptionCallback_t systemException, - SWIG_AdaExceptionCallback_t outOfMemory, - SWIG_AdaExceptionCallback_t indexOutOfRange, - SWIG_AdaExceptionCallback_t divideByZero, - SWIG_AdaExceptionCallback_t argumentOutOfRange, - SWIG_AdaExceptionCallback_t nullReference) -{ - SWIG_ada_exceptions [SWIG_AdaException].callback = systemException; - SWIG_ada_exceptions [SWIG_AdaOutOfMemoryException].callback = outOfMemory; - SWIG_ada_exceptions [SWIG_AdaIndexOutOfRangeException].callback = indexOutOfRange; - SWIG_ada_exceptions [SWIG_AdaDivideByZeroException].callback = divideByZero; - SWIG_ada_exceptions [SWIG_AdaArgumentOutOfRangeException].callback = argumentOutOfRange; - SWIG_ada_exceptions [SWIG_AdaNullReferenceException].callback = nullReference; -} - - -/* Callback for returning strings to Ada without leaking memory */ - -typedef char * (SWIGSTDCALL* SWIG_AdaStringHelperCallback)(const char *); -static SWIG_AdaStringHelperCallback SWIG_ada_string_callback = NULL; - - - -/* probably obsolete ... -#ifdef __cplusplus -extern "C" -#endif -DllExport void SWIGSTDCALL SWIGRegisterStringCallback_LLVM_bit_Reader(SWIG_AdaStringHelperCallback callback) { - SWIG_ada_string_callback = callback; -} -*/ - - - -/* Contract support */ - -#define SWIG_contract_assert(nullreturn, expr, msg) if (!(expr)) {SWIG_AdaThrowException(SWIG_AdaArgumentOutOfRangeException, msg); return nullreturn; } else - - -#define protected public -#define private public - -//#include "llvm-c/Analysis.h" -#include "llvm-c/BitReader.h" -//#include "llvm-c/BitWriter.h" -//#include "llvm-c/Core.h" -//#include "llvm-c/ExecutionEngine.h" -//#include "llvm-c/LinkTimeOptimizer.h" -//#include "llvm-c/lto.h" -//#include "llvm-c/Target.h" - - - -// struct LLVMCtxt; - - -#undef protected -#undef private -#ifdef __cplusplus -extern "C" { -#endif -DllExport int SWIGSTDCALL Ada_LLVMParseBitcode ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - ) -{ - int jresult ; - LLVMMemoryBufferRef arg1 = (LLVMMemoryBufferRef) 0 ; - LLVMModuleRef *arg2 = (LLVMModuleRef *) 0 ; - char **arg3 = (char **) 0 ; - int result; - - arg1 = (LLVMMemoryBufferRef)jarg1; - - arg2 = (LLVMModuleRef *)jarg2; - - arg3 = (char **)jarg3; - - result = (int)LLVMParseBitcode(arg1,arg2,arg3); - jresult = result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMParseBitcodeInContext ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - void * jarg4 - ) -{ - int jresult ; - LLVMMemoryBufferRef arg1 = (LLVMMemoryBufferRef) 0 ; - LLVMContextRef arg2 = (LLVMContextRef) 0 ; - LLVMModuleRef *arg3 = (LLVMModuleRef *) 0 ; - char **arg4 = (char **) 0 ; - int result; - - arg1 = (LLVMMemoryBufferRef)jarg1; - - arg2 = (LLVMContextRef)jarg2; - - arg3 = (LLVMModuleRef *)jarg3; - - arg4 = (char **)jarg4; - - result = (int)LLVMParseBitcodeInContext(arg1,arg2,arg3,arg4); - jresult = result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMGetBitcodeModuleProvider ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - ) -{ - int jresult ; - LLVMMemoryBufferRef arg1 = (LLVMMemoryBufferRef) 0 ; - LLVMModuleProviderRef *arg2 = (LLVMModuleProviderRef *) 0 ; - char **arg3 = (char **) 0 ; - int result; - - arg1 = (LLVMMemoryBufferRef)jarg1; - - arg2 = (LLVMModuleProviderRef *)jarg2; - - arg3 = (char **)jarg3; - - result = (int)LLVMGetBitcodeModuleProvider(arg1,arg2,arg3); - jresult = result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMGetBitcodeModuleProviderInContext ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - void * jarg4 - ) -{ - int jresult ; - LLVMMemoryBufferRef arg1 = (LLVMMemoryBufferRef) 0 ; - LLVMContextRef arg2 = (LLVMContextRef) 0 ; - LLVMModuleProviderRef *arg3 = (LLVMModuleProviderRef *) 0 ; - char **arg4 = (char **) 0 ; - int result; - - arg1 = (LLVMMemoryBufferRef)jarg1; - - arg2 = (LLVMContextRef)jarg2; - - arg3 = (LLVMModuleProviderRef *)jarg3; - - arg4 = (char **)jarg4; - - result = (int)LLVMGetBitcodeModuleProviderInContext(arg1,arg2,arg3,arg4); - jresult = result; - - - - return jresult; - -} - - - -#ifdef __cplusplus -} -#endif -#ifdef __cplusplus -extern "C" { -#endif -#ifdef __cplusplus -} -#endif - diff --git a/bindings/ada/bitwriter/llvm_bit_writer-binding.ads b/bindings/ada/bitwriter/llvm_bit_writer-binding.ads deleted file mode 100644 index b5542df0e062..000000000000 --- a/bindings/ada/bitwriter/llvm_bit_writer-binding.ads +++ /dev/null @@ -1,28 +0,0 @@ --- This file is generated by SWIG. Do *not* modify by hand. --- - -with llvm; -with Interfaces.C.Strings; - - -package LLVM_bit_Writer.Binding is - - function LLVMWriteBitcodeToFileHandle - (M : in llvm.LLVMModuleRef; - Handle : in Interfaces.C.int) - return Interfaces.C.int; - - function LLVMWriteBitcodeToFile - (M : in llvm.LLVMModuleRef; - Path : in Interfaces.C.Strings.chars_ptr) - return Interfaces.C.int; - -private - - pragma Import - (C, - LLVMWriteBitcodeToFileHandle, - "Ada_LLVMWriteBitcodeToFileHandle"); - pragma Import (C, LLVMWriteBitcodeToFile, "Ada_LLVMWriteBitcodeToFile"); - -end LLVM_bit_Writer.Binding; diff --git a/bindings/ada/bitwriter/llvm_bit_writer.ads b/bindings/ada/bitwriter/llvm_bit_writer.ads deleted file mode 100644 index 35b1f38aa996..000000000000 --- a/bindings/ada/bitwriter/llvm_bit_writer.ads +++ /dev/null @@ -1,6 +0,0 @@ --- This file is generated by SWIG. Do *not* modify by hand. --- - -package LLVM_bit_Writer is - -end LLVM_bit_Writer; diff --git a/bindings/ada/bitwriter/llvm_bitwriter_wrap.cxx b/bindings/ada/bitwriter/llvm_bitwriter_wrap.cxx deleted file mode 100644 index 4abf44fffd5c..000000000000 --- a/bindings/ada/bitwriter/llvm_bitwriter_wrap.cxx +++ /dev/null @@ -1,335 +0,0 @@ -/* ---------------------------------------------------------------------------- - * This file was automatically generated by SWIG (http://www.swig.org). - * Version 1.3.36 - * - * This file is not intended to be easily readable and contains a number of - * coding conventions designed to improve portability and efficiency. Do not make - * changes to this file unless you know what you are doing--modify the SWIG - * interface file instead. - * ----------------------------------------------------------------------------- */ - - -#ifdef __cplusplus -template class SwigValueWrapper { - T *tt; -public: - SwigValueWrapper() : tt(0) { } - SwigValueWrapper(const SwigValueWrapper& rhs) : tt(new T(*rhs.tt)) { } - SwigValueWrapper(const T& t) : tt(new T(t)) { } - ~SwigValueWrapper() { delete tt; } - SwigValueWrapper& operator=(const T& t) { delete tt; tt = new T(t); return *this; } - operator T&() const { return *tt; } - T *operator&() { return tt; } -private: - SwigValueWrapper& operator=(const SwigValueWrapper& rhs); -}; - -template T SwigValueInit() { - return T(); -} -#endif - -/* ----------------------------------------------------------------------------- - * This section contains generic SWIG labels for method/variable - * declarations/attributes, and other compiler dependent labels. - * ----------------------------------------------------------------------------- */ - -/* template workaround for compilers that cannot correctly implement the C++ standard */ -#ifndef SWIGTEMPLATEDISAMBIGUATOR -# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) -# define SWIGTEMPLATEDISAMBIGUATOR template -# elif defined(__HP_aCC) -/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ -/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ -# define SWIGTEMPLATEDISAMBIGUATOR template -# else -# define SWIGTEMPLATEDISAMBIGUATOR -# endif -#endif - -/* inline attribute */ -#ifndef SWIGINLINE -# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) -# define SWIGINLINE inline -# else -# define SWIGINLINE -# endif -#endif - -/* attribute recognised by some compilers to avoid 'unused' warnings */ -#ifndef SWIGUNUSED -# if defined(__GNUC__) -# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -# elif defined(__ICC) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -#endif - -#ifndef SWIGUNUSEDPARM -# ifdef __cplusplus -# define SWIGUNUSEDPARM(p) -# else -# define SWIGUNUSEDPARM(p) p SWIGUNUSED -# endif -#endif - -/* internal SWIG method */ -#ifndef SWIGINTERN -# define SWIGINTERN static SWIGUNUSED -#endif - -/* internal inline SWIG method */ -#ifndef SWIGINTERNINLINE -# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE -#endif - -/* exporting methods */ -#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -# ifndef GCC_HASCLASSVISIBILITY -# define GCC_HASCLASSVISIBILITY -# endif -#endif - -#ifndef SWIGEXPORT -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# if defined(STATIC_LINKED) -# define SWIGEXPORT -# else -# define SWIGEXPORT __declspec(dllexport) -# endif -# else -# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) -# define SWIGEXPORT __attribute__ ((visibility("default"))) -# else -# define SWIGEXPORT -# endif -# endif -#endif - -/* calling conventions for Windows */ -#ifndef SWIGSTDCALL -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# define SWIGSTDCALL __stdcall -# else -# define SWIGSTDCALL -# endif -#endif - -/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ -#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) -# define _CRT_SECURE_NO_DEPRECATE -#endif - -/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ -#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) -# define _SCL_SECURE_NO_DEPRECATE -#endif - - - -#include -#include -#include -#if defined(_WIN32) || defined(__CYGWIN32__) -# define DllExport __declspec( dllexport ) -# define SWIGSTDCALL __stdcall -#else -# define DllExport -# define SWIGSTDCALL -#endif - - -#ifdef __cplusplus -# include -#endif - - - - -/* Support for throwing Ada exceptions from C/C++ */ - -typedef enum -{ - SWIG_AdaException, - SWIG_AdaOutOfMemoryException, - SWIG_AdaIndexOutOfRangeException, - SWIG_AdaDivideByZeroException, - SWIG_AdaArgumentOutOfRangeException, - SWIG_AdaNullReferenceException -} SWIG_AdaExceptionCodes; - - -typedef void (SWIGSTDCALL* SWIG_AdaExceptionCallback_t)(const char *); - - -typedef struct -{ - SWIG_AdaExceptionCodes code; - SWIG_AdaExceptionCallback_t callback; -} - SWIG_AdaExceptions_t; - - -static -SWIG_AdaExceptions_t -SWIG_ada_exceptions[] = -{ - { SWIG_AdaException, NULL }, - { SWIG_AdaOutOfMemoryException, NULL }, - { SWIG_AdaIndexOutOfRangeException, NULL }, - { SWIG_AdaDivideByZeroException, NULL }, - { SWIG_AdaArgumentOutOfRangeException, NULL }, - { SWIG_AdaNullReferenceException, NULL } -}; - - -static -void -SWIG_AdaThrowException (SWIG_AdaExceptionCodes code, const char *msg) -{ - SWIG_AdaExceptionCallback_t callback = SWIG_ada_exceptions[SWIG_AdaException].callback; - if (code >=0 && (size_t)code < sizeof(SWIG_ada_exceptions)/sizeof(SWIG_AdaExceptions_t)) { - callback = SWIG_ada_exceptions[code].callback; - } - callback(msg); -} - - - -#ifdef __cplusplus -extern "C" -#endif - -DllExport void SWIGSTDCALL SWIGRegisterExceptionCallbacks_LLVM_bit_Writer (SWIG_AdaExceptionCallback_t systemException, - SWIG_AdaExceptionCallback_t outOfMemory, - SWIG_AdaExceptionCallback_t indexOutOfRange, - SWIG_AdaExceptionCallback_t divideByZero, - SWIG_AdaExceptionCallback_t argumentOutOfRange, - SWIG_AdaExceptionCallback_t nullReference) -{ - SWIG_ada_exceptions [SWIG_AdaException].callback = systemException; - SWIG_ada_exceptions [SWIG_AdaOutOfMemoryException].callback = outOfMemory; - SWIG_ada_exceptions [SWIG_AdaIndexOutOfRangeException].callback = indexOutOfRange; - SWIG_ada_exceptions [SWIG_AdaDivideByZeroException].callback = divideByZero; - SWIG_ada_exceptions [SWIG_AdaArgumentOutOfRangeException].callback = argumentOutOfRange; - SWIG_ada_exceptions [SWIG_AdaNullReferenceException].callback = nullReference; -} - - -/* Callback for returning strings to Ada without leaking memory */ - -typedef char * (SWIGSTDCALL* SWIG_AdaStringHelperCallback)(const char *); -static SWIG_AdaStringHelperCallback SWIG_ada_string_callback = NULL; - - - -/* probably obsolete ... -#ifdef __cplusplus -extern "C" -#endif -DllExport void SWIGSTDCALL SWIGRegisterStringCallback_LLVM_bit_Writer(SWIG_AdaStringHelperCallback callback) { - SWIG_ada_string_callback = callback; -} -*/ - - - -/* Contract support */ - -#define SWIG_contract_assert(nullreturn, expr, msg) if (!(expr)) {SWIG_AdaThrowException(SWIG_AdaArgumentOutOfRangeException, msg); return nullreturn; } else - - -#define protected public -#define private public - -#include "llvm-c/Analysis.h" -#include "llvm-c/BitReader.h" -#include "llvm-c/BitWriter.h" -#include "llvm-c/Core.h" -#include "llvm-c/ExecutionEngine.h" -#include "llvm-c/LinkTimeOptimizer.h" -#include "llvm-c/lto.h" -#include "llvm-c/Target.h" - - - -// struct LLVMCtxt; - - -#undef protected -#undef private -#ifdef __cplusplus -extern "C" { -#endif -DllExport int SWIGSTDCALL Ada_LLVMWriteBitcodeToFileHandle ( - void * jarg1 - , - - int jarg2 - ) -{ - int jresult ; - LLVMModuleRef arg1 = (LLVMModuleRef) 0 ; - int arg2 ; - int result; - - arg1 = (LLVMModuleRef)jarg1; - - - arg2 = (int) jarg2; - - - result = (int)LLVMWriteBitcodeToFileHandle(arg1,arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMWriteBitcodeToFile ( - void * jarg1 - , - - char * jarg2 - ) -{ - int jresult ; - LLVMModuleRef arg1 = (LLVMModuleRef) 0 ; - char *arg2 = (char *) 0 ; - int result; - - arg1 = (LLVMModuleRef)jarg1; - - arg2 = jarg2; - - result = (int)LLVMWriteBitcodeToFile(arg1,(char const *)arg2); - jresult = result; - - - - return jresult; - -} - - - -#ifdef __cplusplus -} -#endif -#ifdef __cplusplus -extern "C" { -#endif -#ifdef __cplusplus -} -#endif - diff --git a/bindings/ada/executionengine/llvm_execution_engine-binding.ads b/bindings/ada/executionengine/llvm_execution_engine-binding.ads deleted file mode 100644 index a37c462cf324..000000000000 --- a/bindings/ada/executionengine/llvm_execution_engine-binding.ads +++ /dev/null @@ -1,192 +0,0 @@ --- This file is generated by SWIG. Do *not* modify by hand. --- - -with llvm; -with Interfaces.C.Strings; - - -package LLVM_execution_Engine.Binding is - - procedure LLVMLinkInJIT; - - procedure LLVMLinkInInterpreter; - - function LLVMCreateGenericValueOfInt - (Ty : in llvm.LLVMTypeRef; - N : in Interfaces.C.Extensions.unsigned_long_long; - IsSigned : in Interfaces.C.int) - return LLVM_execution_Engine.LLVMGenericValueRef; - - function LLVMCreateGenericValueOfPointer - (P : access Interfaces.C.Extensions.void) - return LLVM_execution_Engine.LLVMGenericValueRef; - - function LLVMCreateGenericValueOfFloat - (Ty : in llvm.LLVMTypeRef; - N : in Interfaces.C.double) - return LLVM_execution_Engine.LLVMGenericValueRef; - - function LLVMGenericValueIntWidth - (GenValRef : in LLVM_execution_Engine.LLVMGenericValueRef) - return Interfaces.C.unsigned; - - function LLVMGenericValueToInt - (GenVal : in LLVM_execution_Engine.LLVMGenericValueRef; - IsSigned : in Interfaces.C.int) - return Interfaces.C.Extensions.unsigned_long_long; - - function LLVMGenericValueToPointer - (GenVal : in LLVM_execution_Engine.LLVMGenericValueRef) - return access Interfaces.C.Extensions.void; - - function LLVMGenericValueToFloat - (TyRef : in llvm.LLVMTypeRef; - GenVal : in LLVM_execution_Engine.LLVMGenericValueRef) - return Interfaces.C.double; - - procedure LLVMDisposeGenericValue - (GenVal : in LLVM_execution_Engine.LLVMGenericValueRef); - - function LLVMCreateExecutionEngine - (OutEE : access LLVM_execution_Engine.LLVMExecutionEngineRef; - MP : in llvm.LLVMModuleProviderRef; - OutError : access Interfaces.C.Strings.chars_ptr) - return Interfaces.C.int; - - function LLVMCreateInterpreter - (OutInterp : access LLVM_execution_Engine.LLVMExecutionEngineRef; - MP : in llvm.LLVMModuleProviderRef; - OutError : access Interfaces.C.Strings.chars_ptr) - return Interfaces.C.int; - - function LLVMCreateJITCompiler - (OutJIT : access LLVM_execution_Engine.LLVMExecutionEngineRef; - MP : in llvm.LLVMModuleProviderRef; - OptLevel : in Interfaces.C.unsigned; - OutError : access Interfaces.C.Strings.chars_ptr) - return Interfaces.C.int; - - procedure LLVMDisposeExecutionEngine - (EE : in LLVM_execution_Engine.LLVMExecutionEngineRef); - - procedure LLVMRunStaticConstructors - (EE : in LLVM_execution_Engine.LLVMExecutionEngineRef); - - procedure LLVMRunStaticDestructors - (EE : in LLVM_execution_Engine.LLVMExecutionEngineRef); - - function LLVMRunFunctionAsMain - (EE : in LLVM_execution_Engine.LLVMExecutionEngineRef; - F : in llvm.LLVMValueRef; - ArgC : in Interfaces.C.unsigned; - ArgV : access Interfaces.C.Strings.chars_ptr; - EnvP : access Interfaces.C.Strings.chars_ptr) - return Interfaces.C.int; - - function LLVMRunFunction - (EE : in LLVM_execution_Engine.LLVMExecutionEngineRef; - F : in llvm.LLVMValueRef; - NumArgs : in Interfaces.C.unsigned; - Args : access LLVM_execution_Engine.LLVMGenericValueRef) - return LLVM_execution_Engine.LLVMGenericValueRef; - - procedure LLVMFreeMachineCodeForFunction - (EE : in LLVM_execution_Engine.LLVMExecutionEngineRef; - F : in llvm.LLVMValueRef); - - procedure LLVMAddModuleProvider - (EE : in LLVM_execution_Engine.LLVMExecutionEngineRef; - MP : in llvm.LLVMModuleProviderRef); - - function LLVMRemoveModuleProvider - (EE : in LLVM_execution_Engine.LLVMExecutionEngineRef; - MP : in llvm.LLVMModuleProviderRef; - OutMod : access llvm.LLVMModuleRef; - OutError : access Interfaces.C.Strings.chars_ptr) - return Interfaces.C.int; - - function LLVMFindFunction - (EE : in LLVM_execution_Engine.LLVMExecutionEngineRef; - Name : in Interfaces.C.Strings.chars_ptr; - OutFn : access llvm.LLVMValueRef) - return Interfaces.C.int; - - function LLVMGetExecutionEngineTargetData - (EE : in LLVM_execution_Engine.LLVMExecutionEngineRef) - return LLVM_execution_Engine.LLVMTargetDataRef; - - procedure LLVMAddGlobalMapping - (EE : in LLVM_execution_Engine.LLVMExecutionEngineRef; - Global : in llvm.LLVMValueRef; - Addr : access Interfaces.C.Extensions.void); - - function LLVMGetPointerToGlobal - (EE : in LLVM_execution_Engine.LLVMExecutionEngineRef; - Global : in llvm.LLVMValueRef) - return access Interfaces.C.Extensions.void; - -private - - pragma Import (C, LLVMLinkInJIT, "Ada_LLVMLinkInJIT"); - pragma Import (C, LLVMLinkInInterpreter, "Ada_LLVMLinkInInterpreter"); - pragma Import - (C, - LLVMCreateGenericValueOfInt, - "Ada_LLVMCreateGenericValueOfInt"); - pragma Import - (C, - LLVMCreateGenericValueOfPointer, - "Ada_LLVMCreateGenericValueOfPointer"); - pragma Import - (C, - LLVMCreateGenericValueOfFloat, - "Ada_LLVMCreateGenericValueOfFloat"); - pragma Import - (C, - LLVMGenericValueIntWidth, - "Ada_LLVMGenericValueIntWidth"); - pragma Import (C, LLVMGenericValueToInt, "Ada_LLVMGenericValueToInt"); - pragma Import - (C, - LLVMGenericValueToPointer, - "Ada_LLVMGenericValueToPointer"); - pragma Import (C, LLVMGenericValueToFloat, "Ada_LLVMGenericValueToFloat"); - pragma Import (C, LLVMDisposeGenericValue, "Ada_LLVMDisposeGenericValue"); - pragma Import - (C, - LLVMCreateExecutionEngine, - "Ada_LLVMCreateExecutionEngine"); - pragma Import (C, LLVMCreateInterpreter, "Ada_LLVMCreateInterpreter"); - pragma Import (C, LLVMCreateJITCompiler, "Ada_LLVMCreateJITCompiler"); - pragma Import - (C, - LLVMDisposeExecutionEngine, - "Ada_LLVMDisposeExecutionEngine"); - pragma Import - (C, - LLVMRunStaticConstructors, - "Ada_LLVMRunStaticConstructors"); - pragma Import - (C, - LLVMRunStaticDestructors, - "Ada_LLVMRunStaticDestructors"); - pragma Import (C, LLVMRunFunctionAsMain, "Ada_LLVMRunFunctionAsMain"); - pragma Import (C, LLVMRunFunction, "Ada_LLVMRunFunction"); - pragma Import - (C, - LLVMFreeMachineCodeForFunction, - "Ada_LLVMFreeMachineCodeForFunction"); - pragma Import (C, LLVMAddModuleProvider, "Ada_LLVMAddModuleProvider"); - pragma Import - (C, - LLVMRemoveModuleProvider, - "Ada_LLVMRemoveModuleProvider"); - pragma Import (C, LLVMFindFunction, "Ada_LLVMFindFunction"); - pragma Import - (C, - LLVMGetExecutionEngineTargetData, - "Ada_LLVMGetExecutionEngineTargetData"); - pragma Import (C, LLVMAddGlobalMapping, "Ada_LLVMAddGlobalMapping"); - pragma Import (C, LLVMGetPointerToGlobal, "Ada_LLVMGetPointerToGlobal"); - -end LLVM_execution_Engine.Binding; diff --git a/bindings/ada/executionengine/llvm_execution_engine.ads b/bindings/ada/executionengine/llvm_execution_engine.ads deleted file mode 100644 index c7669920f7ac..000000000000 --- a/bindings/ada/executionengine/llvm_execution_engine.ads +++ /dev/null @@ -1,90 +0,0 @@ --- This file is generated by SWIG. Do *not* modify by hand. --- - -with Interfaces.C.Extensions; - - -package LLVM_execution_Engine is - - -- LLVMOpaqueGenericValue - -- - type LLVMOpaqueGenericValue is new - Interfaces.C.Extensions.opaque_structure_def; - - type LLVMOpaqueGenericValue_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_execution_Engine.LLVMOpaqueGenericValue; - - type LLVMOpaqueGenericValue_view is access all - LLVM_execution_Engine.LLVMOpaqueGenericValue; - - -- LLVMGenericValueRef - -- - type LLVMGenericValueRef is access all - LLVM_execution_Engine.LLVMOpaqueGenericValue; - - type LLVMGenericValueRef_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_execution_Engine.LLVMGenericValueRef; - - type LLVMGenericValueRef_view is access all - LLVM_execution_Engine.LLVMGenericValueRef; - - -- LLVMOpaqueExecutionEngine - -- - type LLVMOpaqueExecutionEngine is new - Interfaces.C.Extensions.opaque_structure_def; - - type LLVMOpaqueExecutionEngine_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_execution_Engine.LLVMOpaqueExecutionEngine; - - type LLVMOpaqueExecutionEngine_view is access all - LLVM_execution_Engine.LLVMOpaqueExecutionEngine; - - -- LLVMExecutionEngineRef - -- - type LLVMExecutionEngineRef is access all - LLVM_execution_Engine.LLVMOpaqueExecutionEngine; - - type LLVMExecutionEngineRef_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_execution_Engine.LLVMExecutionEngineRef; - - type LLVMExecutionEngineRef_view is access all - LLVM_execution_Engine.LLVMExecutionEngineRef; - - -- LLVMTargetDataRef - -- - type LLVMTargetDataRef is new Interfaces.C.Extensions.opaque_structure_def; - - type LLVMTargetDataRef_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_execution_Engine.LLVMTargetDataRef; - - type LLVMTargetDataRef_view is access all - LLVM_execution_Engine.LLVMTargetDataRef; - - -- GenericValue - -- - type GenericValue is new Interfaces.C.Extensions.opaque_structure_def; - - type GenericValue_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_execution_Engine.GenericValue; - - type GenericValue_view is access all LLVM_execution_Engine.GenericValue; - - -- ExecutionEngine - -- - type ExecutionEngine is new Interfaces.C.Extensions.incomplete_class_def; - - type ExecutionEngine_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_execution_Engine.ExecutionEngine; - - type ExecutionEngine_view is access all - LLVM_execution_Engine.ExecutionEngine; - - -end LLVM_execution_Engine; diff --git a/bindings/ada/executionengine/llvm_executionengine_wrap.cxx b/bindings/ada/executionengine/llvm_executionengine_wrap.cxx deleted file mode 100644 index b63acacb361f..000000000000 --- a/bindings/ada/executionengine/llvm_executionengine_wrap.cxx +++ /dev/null @@ -1,924 +0,0 @@ -/* ---------------------------------------------------------------------------- - * This file was automatically generated by SWIG (http://www.swig.org). - * Version 1.3.36 - * - * This file is not intended to be easily readable and contains a number of - * coding conventions designed to improve portability and efficiency. Do not make - * changes to this file unless you know what you are doing--modify the SWIG - * interface file instead. - * ----------------------------------------------------------------------------- */ - - -#ifdef __cplusplus -template class SwigValueWrapper { - T *tt; -public: - SwigValueWrapper() : tt(0) { } - SwigValueWrapper(const SwigValueWrapper& rhs) : tt(new T(*rhs.tt)) { } - SwigValueWrapper(const T& t) : tt(new T(t)) { } - ~SwigValueWrapper() { delete tt; } - SwigValueWrapper& operator=(const T& t) { delete tt; tt = new T(t); return *this; } - operator T&() const { return *tt; } - T *operator&() { return tt; } -private: - SwigValueWrapper& operator=(const SwigValueWrapper& rhs); -}; - -template T SwigValueInit() { - return T(); -} -#endif - -/* ----------------------------------------------------------------------------- - * This section contains generic SWIG labels for method/variable - * declarations/attributes, and other compiler dependent labels. - * ----------------------------------------------------------------------------- */ - -/* template workaround for compilers that cannot correctly implement the C++ standard */ -#ifndef SWIGTEMPLATEDISAMBIGUATOR -# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) -# define SWIGTEMPLATEDISAMBIGUATOR template -# elif defined(__HP_aCC) -/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ -/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ -# define SWIGTEMPLATEDISAMBIGUATOR template -# else -# define SWIGTEMPLATEDISAMBIGUATOR -# endif -#endif - -/* inline attribute */ -#ifndef SWIGINLINE -# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) -# define SWIGINLINE inline -# else -# define SWIGINLINE -# endif -#endif - -/* attribute recognised by some compilers to avoid 'unused' warnings */ -#ifndef SWIGUNUSED -# if defined(__GNUC__) -# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -# elif defined(__ICC) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -#endif - -#ifndef SWIGUNUSEDPARM -# ifdef __cplusplus -# define SWIGUNUSEDPARM(p) -# else -# define SWIGUNUSEDPARM(p) p SWIGUNUSED -# endif -#endif - -/* internal SWIG method */ -#ifndef SWIGINTERN -# define SWIGINTERN static SWIGUNUSED -#endif - -/* internal inline SWIG method */ -#ifndef SWIGINTERNINLINE -# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE -#endif - -/* exporting methods */ -#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -# ifndef GCC_HASCLASSVISIBILITY -# define GCC_HASCLASSVISIBILITY -# endif -#endif - -#ifndef SWIGEXPORT -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# if defined(STATIC_LINKED) -# define SWIGEXPORT -# else -# define SWIGEXPORT __declspec(dllexport) -# endif -# else -# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) -# define SWIGEXPORT __attribute__ ((visibility("default"))) -# else -# define SWIGEXPORT -# endif -# endif -#endif - -/* calling conventions for Windows */ -#ifndef SWIGSTDCALL -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# define SWIGSTDCALL __stdcall -# else -# define SWIGSTDCALL -# endif -#endif - -/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ -#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) -# define _CRT_SECURE_NO_DEPRECATE -#endif - -/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ -#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) -# define _SCL_SECURE_NO_DEPRECATE -#endif - - - -#include -#include -#include -#if defined(_WIN32) || defined(__CYGWIN32__) -# define DllExport __declspec( dllexport ) -# define SWIGSTDCALL __stdcall -#else -# define DllExport -# define SWIGSTDCALL -#endif - - -#ifdef __cplusplus -# include -#endif - - - - -/* Support for throwing Ada exceptions from C/C++ */ - -typedef enum -{ - SWIG_AdaException, - SWIG_AdaOutOfMemoryException, - SWIG_AdaIndexOutOfRangeException, - SWIG_AdaDivideByZeroException, - SWIG_AdaArgumentOutOfRangeException, - SWIG_AdaNullReferenceException -} SWIG_AdaExceptionCodes; - - -typedef void (SWIGSTDCALL* SWIG_AdaExceptionCallback_t)(const char *); - - -typedef struct -{ - SWIG_AdaExceptionCodes code; - SWIG_AdaExceptionCallback_t callback; -} - SWIG_AdaExceptions_t; - - -static -SWIG_AdaExceptions_t -SWIG_ada_exceptions[] = -{ - { SWIG_AdaException, NULL }, - { SWIG_AdaOutOfMemoryException, NULL }, - { SWIG_AdaIndexOutOfRangeException, NULL }, - { SWIG_AdaDivideByZeroException, NULL }, - { SWIG_AdaArgumentOutOfRangeException, NULL }, - { SWIG_AdaNullReferenceException, NULL } -}; - - -static -void -SWIG_AdaThrowException (SWIG_AdaExceptionCodes code, const char *msg) -{ - SWIG_AdaExceptionCallback_t callback = SWIG_ada_exceptions[SWIG_AdaException].callback; - if (code >=0 && (size_t)code < sizeof(SWIG_ada_exceptions)/sizeof(SWIG_AdaExceptions_t)) { - callback = SWIG_ada_exceptions[code].callback; - } - callback(msg); -} - - - -#ifdef __cplusplus -extern "C" -#endif - -DllExport void SWIGSTDCALL SWIGRegisterExceptionCallbacks_LLVM_execution_Engine (SWIG_AdaExceptionCallback_t systemException, - SWIG_AdaExceptionCallback_t outOfMemory, - SWIG_AdaExceptionCallback_t indexOutOfRange, - SWIG_AdaExceptionCallback_t divideByZero, - SWIG_AdaExceptionCallback_t argumentOutOfRange, - SWIG_AdaExceptionCallback_t nullReference) -{ - SWIG_ada_exceptions [SWIG_AdaException].callback = systemException; - SWIG_ada_exceptions [SWIG_AdaOutOfMemoryException].callback = outOfMemory; - SWIG_ada_exceptions [SWIG_AdaIndexOutOfRangeException].callback = indexOutOfRange; - SWIG_ada_exceptions [SWIG_AdaDivideByZeroException].callback = divideByZero; - SWIG_ada_exceptions [SWIG_AdaArgumentOutOfRangeException].callback = argumentOutOfRange; - SWIG_ada_exceptions [SWIG_AdaNullReferenceException].callback = nullReference; -} - - -/* Callback for returning strings to Ada without leaking memory */ - -typedef char * (SWIGSTDCALL* SWIG_AdaStringHelperCallback)(const char *); -static SWIG_AdaStringHelperCallback SWIG_ada_string_callback = NULL; - - - -/* probably obsolete ... -#ifdef __cplusplus -extern "C" -#endif -DllExport void SWIGSTDCALL SWIGRegisterStringCallback_LLVM_execution_Engine(SWIG_AdaStringHelperCallback callback) { - SWIG_ada_string_callback = callback; -} -*/ - - - -/* Contract support */ - -#define SWIG_contract_assert(nullreturn, expr, msg) if (!(expr)) {SWIG_AdaThrowException(SWIG_AdaArgumentOutOfRangeException, msg); return nullreturn; } else - - -#define protected public -#define private public - -#include "llvm-c/ExecutionEngine.h" - - - -// struct LLVMCtxt; - - -#undef protected -#undef private -#ifdef __cplusplus -extern "C" { -#endif -DllExport void SWIGSTDCALL Ada_LLVMLinkInJIT ( - ) -{ - LLVMLinkInJIT(); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMLinkInInterpreter ( - ) -{ - LLVMLinkInInterpreter(); - - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMCreateGenericValueOfInt ( - void * jarg1 - , - - unsigned long long jarg2 - , - - int jarg3 - ) -{ - void * jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - unsigned long long arg2 ; - int arg3 ; - LLVMGenericValueRef result; - - arg1 = (LLVMTypeRef)jarg1; - - - arg2 = (unsigned long long) jarg2; - - - - arg3 = (int) jarg3; - - - result = (LLVMGenericValueRef)LLVMCreateGenericValueOfInt(arg1,arg2,arg3); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMCreateGenericValueOfPointer ( - void* jarg1 - ) -{ - void * jresult ; - void *arg1 = (void *) 0 ; - LLVMGenericValueRef result; - - arg1 = (void *)jarg1; - - result = (LLVMGenericValueRef)LLVMCreateGenericValueOfPointer(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMCreateGenericValueOfFloat ( - void * jarg1 - , - - double jarg2 - ) -{ - void * jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - double arg2 ; - LLVMGenericValueRef result; - - arg1 = (LLVMTypeRef)jarg1; - - - arg2 = (double) jarg2; - - - result = (LLVMGenericValueRef)LLVMCreateGenericValueOfFloat(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_LLVMGenericValueIntWidth ( - void * jarg1 - ) -{ - unsigned int jresult ; - LLVMGenericValueRef arg1 = (LLVMGenericValueRef) 0 ; - unsigned int result; - - arg1 = (LLVMGenericValueRef)jarg1; - - result = (unsigned int)LLVMGenericValueIntWidth(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport unsigned long long SWIGSTDCALL Ada_LLVMGenericValueToInt ( - void * jarg1 - , - - int jarg2 - ) -{ - unsigned long long jresult ; - LLVMGenericValueRef arg1 = (LLVMGenericValueRef) 0 ; - int arg2 ; - unsigned long long result; - - arg1 = (LLVMGenericValueRef)jarg1; - - - arg2 = (int) jarg2; - - - result = (unsigned long long)LLVMGenericValueToInt(arg1,arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport void* SWIGSTDCALL Ada_LLVMGenericValueToPointer ( - void * jarg1 - ) -{ - void* jresult ; - LLVMGenericValueRef arg1 = (LLVMGenericValueRef) 0 ; - void *result = 0 ; - - arg1 = (LLVMGenericValueRef)jarg1; - - result = (void *)LLVMGenericValueToPointer(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport double SWIGSTDCALL Ada_LLVMGenericValueToFloat ( - void * jarg1 - , - - void * jarg2 - ) -{ - double jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - LLVMGenericValueRef arg2 = (LLVMGenericValueRef) 0 ; - double result; - - arg1 = (LLVMTypeRef)jarg1; - - arg2 = (LLVMGenericValueRef)jarg2; - - result = (double)LLVMGenericValueToFloat(arg1,arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMDisposeGenericValue ( - void * jarg1 - ) -{ - LLVMGenericValueRef arg1 = (LLVMGenericValueRef) 0 ; - - arg1 = (LLVMGenericValueRef)jarg1; - - LLVMDisposeGenericValue(arg1); - - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMCreateExecutionEngine ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - ) -{ - int jresult ; - LLVMExecutionEngineRef *arg1 = (LLVMExecutionEngineRef *) 0 ; - LLVMModuleProviderRef arg2 = (LLVMModuleProviderRef) 0 ; - char **arg3 = (char **) 0 ; - int result; - - arg1 = (LLVMExecutionEngineRef *)jarg1; - - arg2 = (LLVMModuleProviderRef)jarg2; - - arg3 = (char **)jarg3; - - result = (int)LLVMCreateExecutionEngine(arg1,arg2,arg3); - jresult = result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMCreateInterpreter ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - ) -{ - int jresult ; - LLVMExecutionEngineRef *arg1 = (LLVMExecutionEngineRef *) 0 ; - LLVMModuleProviderRef arg2 = (LLVMModuleProviderRef) 0 ; - char **arg3 = (char **) 0 ; - int result; - - arg1 = (LLVMExecutionEngineRef *)jarg1; - - arg2 = (LLVMModuleProviderRef)jarg2; - - arg3 = (char **)jarg3; - - result = (int)LLVMCreateInterpreter(arg1,arg2,arg3); - jresult = result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMCreateJITCompiler ( - void * jarg1 - , - - void * jarg2 - , - - unsigned int jarg3 - , - - void * jarg4 - ) -{ - int jresult ; - LLVMExecutionEngineRef *arg1 = (LLVMExecutionEngineRef *) 0 ; - LLVMModuleProviderRef arg2 = (LLVMModuleProviderRef) 0 ; - unsigned int arg3 ; - char **arg4 = (char **) 0 ; - int result; - - arg1 = (LLVMExecutionEngineRef *)jarg1; - - arg2 = (LLVMModuleProviderRef)jarg2; - - - arg3 = (unsigned int) jarg3; - - - arg4 = (char **)jarg4; - - result = (int)LLVMCreateJITCompiler(arg1,arg2,arg3,arg4); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMDisposeExecutionEngine ( - void * jarg1 - ) -{ - LLVMExecutionEngineRef arg1 = (LLVMExecutionEngineRef) 0 ; - - arg1 = (LLVMExecutionEngineRef)jarg1; - - LLVMDisposeExecutionEngine(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMRunStaticConstructors ( - void * jarg1 - ) -{ - LLVMExecutionEngineRef arg1 = (LLVMExecutionEngineRef) 0 ; - - arg1 = (LLVMExecutionEngineRef)jarg1; - - LLVMRunStaticConstructors(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMRunStaticDestructors ( - void * jarg1 - ) -{ - LLVMExecutionEngineRef arg1 = (LLVMExecutionEngineRef) 0 ; - - arg1 = (LLVMExecutionEngineRef)jarg1; - - LLVMRunStaticDestructors(arg1); - - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMRunFunctionAsMain ( - void * jarg1 - , - - void * jarg2 - , - - unsigned int jarg3 - , - - void * jarg4 - , - - void * jarg5 - ) -{ - int jresult ; - LLVMExecutionEngineRef arg1 = (LLVMExecutionEngineRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - unsigned int arg3 ; - char **arg4 = (char **) 0 ; - char **arg5 = (char **) 0 ; - int result; - - arg1 = (LLVMExecutionEngineRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - - arg3 = (unsigned int) jarg3; - - - arg4 = (char **)jarg4; - - arg5 = (char **)jarg5; - - result = (int)LLVMRunFunctionAsMain(arg1,arg2,arg3,(char const *const *)arg4,(char const *const *)arg5); - jresult = result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMRunFunction ( - void * jarg1 - , - - void * jarg2 - , - - unsigned int jarg3 - , - - void * jarg4 - ) -{ - void * jresult ; - LLVMExecutionEngineRef arg1 = (LLVMExecutionEngineRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - unsigned int arg3 ; - LLVMGenericValueRef *arg4 = (LLVMGenericValueRef *) 0 ; - LLVMGenericValueRef result; - - arg1 = (LLVMExecutionEngineRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - - arg3 = (unsigned int) jarg3; - - - arg4 = (LLVMGenericValueRef *)jarg4; - - result = (LLVMGenericValueRef)LLVMRunFunction(arg1,arg2,arg3,arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMFreeMachineCodeForFunction ( - void * jarg1 - , - - void * jarg2 - ) -{ - LLVMExecutionEngineRef arg1 = (LLVMExecutionEngineRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - - arg1 = (LLVMExecutionEngineRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - LLVMFreeMachineCodeForFunction(arg1,arg2); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddModuleProvider ( - void * jarg1 - , - - void * jarg2 - ) -{ - LLVMExecutionEngineRef arg1 = (LLVMExecutionEngineRef) 0 ; - LLVMModuleProviderRef arg2 = (LLVMModuleProviderRef) 0 ; - - arg1 = (LLVMExecutionEngineRef)jarg1; - - arg2 = (LLVMModuleProviderRef)jarg2; - - LLVMAddModuleProvider(arg1,arg2); - - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMRemoveModuleProvider ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - void * jarg4 - ) -{ - int jresult ; - LLVMExecutionEngineRef arg1 = (LLVMExecutionEngineRef) 0 ; - LLVMModuleProviderRef arg2 = (LLVMModuleProviderRef) 0 ; - LLVMModuleRef *arg3 = (LLVMModuleRef *) 0 ; - char **arg4 = (char **) 0 ; - int result; - - arg1 = (LLVMExecutionEngineRef)jarg1; - - arg2 = (LLVMModuleProviderRef)jarg2; - - arg3 = (LLVMModuleRef *)jarg3; - - arg4 = (char **)jarg4; - - result = (int)LLVMRemoveModuleProvider(arg1,arg2,arg3,arg4); - jresult = result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMFindFunction ( - void * jarg1 - , - - char * jarg2 - , - - void * jarg3 - ) -{ - int jresult ; - LLVMExecutionEngineRef arg1 = (LLVMExecutionEngineRef) 0 ; - char *arg2 = (char *) 0 ; - LLVMValueRef *arg3 = (LLVMValueRef *) 0 ; - int result; - - arg1 = (LLVMExecutionEngineRef)jarg1; - - arg2 = jarg2; - - arg3 = (LLVMValueRef *)jarg3; - - result = (int)LLVMFindFunction(arg1,(char const *)arg2,arg3); - jresult = result; - - - - return jresult; - -} - - - -DllExport LLVMTargetDataRef SWIGSTDCALL Ada_LLVMGetExecutionEngineTargetData ( - void * jarg1 - ) -{ - LLVMTargetDataRef jresult ; - LLVMExecutionEngineRef arg1 = (LLVMExecutionEngineRef) 0 ; - LLVMTargetDataRef result; - - arg1 = (LLVMExecutionEngineRef)jarg1; - - result = LLVMGetExecutionEngineTargetData(arg1); - - jresult = result; - //jresult = new LLVMTargetDataRef ((LLVMTargetDataRef &) result); - - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddGlobalMapping ( - void * jarg1 - , - - void * jarg2 - , - - void* jarg3 - ) -{ - LLVMExecutionEngineRef arg1 = (LLVMExecutionEngineRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - void *arg3 = (void *) 0 ; - - arg1 = (LLVMExecutionEngineRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (void *)jarg3; - - LLVMAddGlobalMapping(arg1,arg2,arg3); - - -} - - - -DllExport void* SWIGSTDCALL Ada_LLVMGetPointerToGlobal ( - void * jarg1 - , - - void * jarg2 - ) -{ - void* jresult ; - LLVMExecutionEngineRef arg1 = (LLVMExecutionEngineRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - void *result = 0 ; - - arg1 = (LLVMExecutionEngineRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - result = (void *)LLVMGetPointerToGlobal(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -#ifdef __cplusplus -} -#endif -#ifdef __cplusplus -extern "C" { -#endif -#ifdef __cplusplus -} -#endif - diff --git a/bindings/ada/llvm.gpr b/bindings/ada/llvm.gpr deleted file mode 100644 index 8e87af4fa12e..000000000000 --- a/bindings/ada/llvm.gpr +++ /dev/null @@ -1,34 +0,0 @@ -project LLVM is - - for Languages use ("Ada", "C++"); - for Source_Dirs use (".", "analysis", "bitreader", "bitwriter", "executionengine", "llvm", "target", "transforms"); - for Object_Dir use "build"; - for Exec_Dir use "."; - for Library_Name use "llvm_ada"; - for Library_Dir use "lib"; - for Library_Ali_Dir use "objects"; - - package Naming is - for Specification_Suffix ("c++") use ".h"; - for Implementation_Suffix ("c++") use ".cxx"; - end Naming; - - package Builder is - for Default_Switches ("ada") use ("-g"); - end Builder; - - package Compiler is - for Default_Switches ("ada") use ("-gnato", "-fstack-check", "-g", "-gnata", "-gnat05", "-I/usr/local/include"); - for Default_Switches ("c++") use ("-D__STDC_LIMIT_MACROS", "-D__STDC_CONSTANT_MACROS", "-I../../include", "-g"); - end Compiler; - - package Binder is - for Default_Switches ("ada") use ("-E"); - end Binder; - - package Linker is - for Default_Switches ("c++") use ("-g"); - end Linker; - -end LLVM; - diff --git a/bindings/ada/llvm/llvm-binding.ads b/bindings/ada/llvm/llvm-binding.ads deleted file mode 100644 index c0e48a1b5bf3..000000000000 --- a/bindings/ada/llvm/llvm-binding.ads +++ /dev/null @@ -1,1974 +0,0 @@ --- This file is generated by SWIG. Do *not* modify by hand. --- - -with Interfaces.C.Strings; - - -package llvm.Binding is - - procedure LLVMDisposeMessage - (Message : in Interfaces.C.Strings.chars_ptr); - - function LLVMContextCreate return llvm.LLVMContextRef; - - function LLVMGetGlobalContext return llvm.LLVMContextRef; - - procedure LLVMContextDispose (C : in llvm.LLVMContextRef); - - function LLVMModuleCreateWithName - (ModuleID : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMModuleRef; - - function LLVMModuleCreateWithNameInContext - (ModuleID : in Interfaces.C.Strings.chars_ptr; - C : in llvm.LLVMContextRef) - return llvm.LLVMModuleRef; - - procedure LLVMDisposeModule (M : in llvm.LLVMModuleRef); - - function LLVMGetDataLayout - (M : in llvm.LLVMModuleRef) - return Interfaces.C.Strings.chars_ptr; - - procedure LLVMSetDataLayout - (M : in llvm.LLVMModuleRef; - Triple : in Interfaces.C.Strings.chars_ptr); - - function LLVMGetTarget - (M : in llvm.LLVMModuleRef) - return Interfaces.C.Strings.chars_ptr; - - procedure LLVMSetTarget - (M : in llvm.LLVMModuleRef; - Triple : in Interfaces.C.Strings.chars_ptr); - - function LLVMAddTypeName - (M : in llvm.LLVMModuleRef; - Name : in Interfaces.C.Strings.chars_ptr; - Ty : in llvm.LLVMTypeRef) - return Interfaces.C.int; - - procedure LLVMDeleteTypeName - (M : in llvm.LLVMModuleRef; - Name : in Interfaces.C.Strings.chars_ptr); - - function LLVMGetTypeByName - (M : in llvm.LLVMModuleRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMTypeRef; - - procedure LLVMDumpModule (M : in llvm.LLVMModuleRef); - - function LLVMGetTypeKind - (Ty : in llvm.LLVMTypeRef) - return llvm.LLVMTypeKind; - - function LLVMInt1Type return llvm.LLVMTypeRef; - - function LLVMInt8Type return llvm.LLVMTypeRef; - - function LLVMInt16Type return llvm.LLVMTypeRef; - - function LLVMInt32Type return llvm.LLVMTypeRef; - - function LLVMInt64Type return llvm.LLVMTypeRef; - - function LLVMIntType - (NumBits : in Interfaces.C.unsigned) - return llvm.LLVMTypeRef; - - function LLVMGetIntTypeWidth - (IntegerTy : in llvm.LLVMTypeRef) - return Interfaces.C.unsigned; - - function LLVMFloatType return llvm.LLVMTypeRef; - - function LLVMDoubleType return llvm.LLVMTypeRef; - - function LLVMX86FP80Type return llvm.LLVMTypeRef; - - function LLVMFP128Type return llvm.LLVMTypeRef; - - function LLVMPPCFP128Type return llvm.LLVMTypeRef; - - function LLVMFunctionType - (ReturnType : in llvm.LLVMTypeRef; - ParamTypes : access llvm.LLVMTypeRef; - ParamCount : in Interfaces.C.unsigned; - IsVarArg : in Interfaces.C.int) - return llvm.LLVMTypeRef; - - function LLVMIsFunctionVarArg - (FunctionTy : in llvm.LLVMTypeRef) - return Interfaces.C.int; - - function LLVMGetReturnType - (FunctionTy : in llvm.LLVMTypeRef) - return llvm.LLVMTypeRef; - - function LLVMCountParamTypes - (FunctionTy : in llvm.LLVMTypeRef) - return Interfaces.C.unsigned; - - procedure LLVMGetParamTypes - (FunctionTy : in llvm.LLVMTypeRef; - Dest : access llvm.LLVMTypeRef); - - function LLVMStructType - (ElementTypes : access llvm.LLVMTypeRef; - ElementCount : in Interfaces.C.unsigned; - Packed : in Interfaces.C.int) - return llvm.LLVMTypeRef; - - function LLVMCountStructElementTypes - (StructTy : in llvm.LLVMTypeRef) - return Interfaces.C.unsigned; - - procedure LLVMGetStructElementTypes - (StructTy : in llvm.LLVMTypeRef; - Dest : access llvm.LLVMTypeRef); - - function LLVMIsPackedStruct - (StructTy : in llvm.LLVMTypeRef) - return Interfaces.C.int; - - function LLVMArrayType - (ElementType : in llvm.LLVMTypeRef; - ElementCount : in Interfaces.C.unsigned) - return llvm.LLVMTypeRef; - - function LLVMPointerType - (ElementType : in llvm.LLVMTypeRef; - AddressSpace : in Interfaces.C.unsigned) - return llvm.LLVMTypeRef; - - function LLVMVectorType - (ElementType : in llvm.LLVMTypeRef; - ElementCount : in Interfaces.C.unsigned) - return llvm.LLVMTypeRef; - - function LLVMGetElementType - (Ty : in llvm.LLVMTypeRef) - return llvm.LLVMTypeRef; - - function LLVMGetArrayLength - (ArrayTy : in llvm.LLVMTypeRef) - return Interfaces.C.unsigned; - - function LLVMGetPointerAddressSpace - (PointerTy : in llvm.LLVMTypeRef) - return Interfaces.C.unsigned; - - function LLVMGetVectorSize - (VectorTy : in llvm.LLVMTypeRef) - return Interfaces.C.unsigned; - - function LLVMVoidType return llvm.LLVMTypeRef; - - function LLVMLabelType return llvm.LLVMTypeRef; - - function LLVMOpaqueType return llvm.LLVMTypeRef; - - function LLVMCreateTypeHandle - (PotentiallyAbstractTy : in llvm.LLVMTypeRef) - return llvm.LLVMTypeHandleRef; - - procedure LLVMRefineType - (AbstractTy : in llvm.LLVMTypeRef; - ConcreteTy : in llvm.LLVMTypeRef); - - function LLVMResolveTypeHandle - (TypeHandle : in llvm.LLVMTypeHandleRef) - return llvm.LLVMTypeRef; - - procedure LLVMDisposeTypeHandle (TypeHandle : in llvm.LLVMTypeHandleRef); - - function LLVMTypeOf (Val : in llvm.LLVMValueRef) return llvm.LLVMTypeRef; - - function LLVMGetValueName - (Val : in llvm.LLVMValueRef) - return Interfaces.C.Strings.chars_ptr; - - procedure LLVMSetValueName - (Val : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr); - - procedure LLVMDumpValue (Val : in llvm.LLVMValueRef); - - function LLVMIsAArgument - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsABasicBlock - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAInlineAsm - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAUser - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAConstant - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAConstantAggregateZero - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAConstantArray - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAConstantExpr - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAConstantFP - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAConstantInt - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAConstantPointerNull - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAConstantStruct - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAConstantVector - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAGlobalValue - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAFunction - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAGlobalAlias - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAGlobalVariable - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAUndefValue - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAInstruction - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsABinaryOperator - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsACallInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAIntrinsicInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsADbgInfoIntrinsic - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsADbgDeclareInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsADbgFuncStartInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsADbgRegionEndInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsADbgRegionStartInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsADbgStopPointInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAEHSelectorInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAMemIntrinsic - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAMemCpyInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAMemMoveInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAMemSetInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsACmpInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAFCmpInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAICmpInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAExtractElementInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAGetElementPtrInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAInsertElementInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAInsertValueInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAPHINode - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsASelectInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAShuffleVectorInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAStoreInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsATerminatorInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsABranchInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAInvokeInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAReturnInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsASwitchInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAUnreachableInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAUnwindInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAUnaryInstruction - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAAllocationInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAAllocaInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAMallocInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsACastInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsABitCastInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAFPExtInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAFPToSIInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAFPToUIInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAFPTruncInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAIntToPtrInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAPtrToIntInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsASExtInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsASIToFPInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsATruncInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAUIToFPInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAZExtInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAExtractValueInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAFreeInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsALoadInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMIsAVAArgInst - (Val : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstNull - (Ty : in llvm.LLVMTypeRef) - return llvm.LLVMValueRef; - - function LLVMConstAllOnes - (Ty : in llvm.LLVMTypeRef) - return llvm.LLVMValueRef; - - function LLVMGetUndef - (Ty : in llvm.LLVMTypeRef) - return llvm.LLVMValueRef; - - function LLVMIsConstant - (Val : in llvm.LLVMValueRef) - return Interfaces.C.int; - - function LLVMIsNull (Val : in llvm.LLVMValueRef) return Interfaces.C.int; - - function LLVMIsUndef - (Val : in llvm.LLVMValueRef) - return Interfaces.C.int; - - function LLVMConstPointerNull - (Ty : in llvm.LLVMTypeRef) - return llvm.LLVMValueRef; - - function LLVMConstInt - (IntTy : in llvm.LLVMTypeRef; - N : in Interfaces.C.Extensions.unsigned_long_long; - SignExtend : in Interfaces.C.int) - return llvm.LLVMValueRef; - - function LLVMConstReal - (RealTy : in llvm.LLVMTypeRef; - N : in Interfaces.C.double) - return llvm.LLVMValueRef; - - function LLVMConstRealOfString - (RealTy : in llvm.LLVMTypeRef; - Text : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMConstString - (Str : in Interfaces.C.Strings.chars_ptr; - Length : in Interfaces.C.unsigned; - DontNullTerminate : in Interfaces.C.int) - return llvm.LLVMValueRef; - - function LLVMConstArray - (ElementTy : in llvm.LLVMTypeRef; - ConstantVals : access llvm.LLVMValueRef; - Length : in Interfaces.C.unsigned) - return llvm.LLVMValueRef; - - function LLVMConstStruct - (ConstantVals : access llvm.LLVMValueRef; - Count : in Interfaces.C.unsigned; - packed : in Interfaces.C.int) - return llvm.LLVMValueRef; - - function LLVMConstVector - (ScalarConstantVals : access llvm.LLVMValueRef; - Size : in Interfaces.C.unsigned) - return llvm.LLVMValueRef; - - function LLVMSizeOf (Ty : in llvm.LLVMTypeRef) return llvm.LLVMValueRef; - - function LLVMConstNeg - (ConstantVal : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstNot - (ConstantVal : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstAdd - (LHSConstant : in llvm.LLVMValueRef; - RHSConstant : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstSub - (LHSConstant : in llvm.LLVMValueRef; - RHSConstant : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstMul - (LHSConstant : in llvm.LLVMValueRef; - RHSConstant : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstUDiv - (LHSConstant : in llvm.LLVMValueRef; - RHSConstant : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstSDiv - (LHSConstant : in llvm.LLVMValueRef; - RHSConstant : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstFDiv - (LHSConstant : in llvm.LLVMValueRef; - RHSConstant : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstURem - (LHSConstant : in llvm.LLVMValueRef; - RHSConstant : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstSRem - (LHSConstant : in llvm.LLVMValueRef; - RHSConstant : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstFRem - (LHSConstant : in llvm.LLVMValueRef; - RHSConstant : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstAnd - (LHSConstant : in llvm.LLVMValueRef; - RHSConstant : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstOr - (LHSConstant : in llvm.LLVMValueRef; - RHSConstant : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstXor - (LHSConstant : in llvm.LLVMValueRef; - RHSConstant : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstICmp - (Predicate : in llvm.LLVMIntPredicate; - LHSConstant : in llvm.LLVMValueRef; - RHSConstant : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstFCmp - (Predicate : in llvm.LLVMRealPredicate; - LHSConstant : in llvm.LLVMValueRef; - RHSConstant : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstShl - (LHSConstant : in llvm.LLVMValueRef; - RHSConstant : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstLShr - (LHSConstant : in llvm.LLVMValueRef; - RHSConstant : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstAShr - (LHSConstant : in llvm.LLVMValueRef; - RHSConstant : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstGEP - (ConstantVal : in llvm.LLVMValueRef; - ConstantIndices : access llvm.LLVMValueRef; - NumIndices : in Interfaces.C.unsigned) - return llvm.LLVMValueRef; - - function LLVMConstTrunc - (ConstantVal : in llvm.LLVMValueRef; - ToType : in llvm.LLVMTypeRef) - return llvm.LLVMValueRef; - - function LLVMConstSExt - (ConstantVal : in llvm.LLVMValueRef; - ToType : in llvm.LLVMTypeRef) - return llvm.LLVMValueRef; - - function LLVMConstZExt - (ConstantVal : in llvm.LLVMValueRef; - ToType : in llvm.LLVMTypeRef) - return llvm.LLVMValueRef; - - function LLVMConstFPTrunc - (ConstantVal : in llvm.LLVMValueRef; - ToType : in llvm.LLVMTypeRef) - return llvm.LLVMValueRef; - - function LLVMConstFPExt - (ConstantVal : in llvm.LLVMValueRef; - ToType : in llvm.LLVMTypeRef) - return llvm.LLVMValueRef; - - function LLVMConstUIToFP - (ConstantVal : in llvm.LLVMValueRef; - ToType : in llvm.LLVMTypeRef) - return llvm.LLVMValueRef; - - function LLVMConstSIToFP - (ConstantVal : in llvm.LLVMValueRef; - ToType : in llvm.LLVMTypeRef) - return llvm.LLVMValueRef; - - function LLVMConstFPToUI - (ConstantVal : in llvm.LLVMValueRef; - ToType : in llvm.LLVMTypeRef) - return llvm.LLVMValueRef; - - function LLVMConstFPToSI - (ConstantVal : in llvm.LLVMValueRef; - ToType : in llvm.LLVMTypeRef) - return llvm.LLVMValueRef; - - function LLVMConstPtrToInt - (ConstantVal : in llvm.LLVMValueRef; - ToType : in llvm.LLVMTypeRef) - return llvm.LLVMValueRef; - - function LLVMConstIntToPtr - (ConstantVal : in llvm.LLVMValueRef; - ToType : in llvm.LLVMTypeRef) - return llvm.LLVMValueRef; - - function LLVMConstBitCast - (ConstantVal : in llvm.LLVMValueRef; - ToType : in llvm.LLVMTypeRef) - return llvm.LLVMValueRef; - - function LLVMConstSelect - (ConstantCondition : in llvm.LLVMValueRef; - ConstantIfTrue : in llvm.LLVMValueRef; - ConstantIfFalse : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstExtractElement - (VectorConstant : in llvm.LLVMValueRef; - IndexConstant : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstInsertElement - (VectorConstant : in llvm.LLVMValueRef; - ElementValueConstant : in llvm.LLVMValueRef; - IndexConstant : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstShuffleVector - (VectorAConstant : in llvm.LLVMValueRef; - VectorBConstant : in llvm.LLVMValueRef; - MaskConstant : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMConstExtractValue - (AggConstant : in llvm.LLVMValueRef; - IdxList : access Interfaces.C.unsigned; - NumIdx : in Interfaces.C.unsigned) - return llvm.LLVMValueRef; - - function LLVMConstInsertValue - (AggConstant : in llvm.LLVMValueRef; - ElementValueConstant : in llvm.LLVMValueRef; - IdxList : access Interfaces.C.unsigned; - NumIdx : in Interfaces.C.unsigned) - return llvm.LLVMValueRef; - - function LLVMConstInlineAsm - (Ty : in llvm.LLVMTypeRef; - AsmString : in Interfaces.C.Strings.chars_ptr; - Constraints : in Interfaces.C.Strings.chars_ptr; - HasSideEffects : in Interfaces.C.int) - return llvm.LLVMValueRef; - - function LLVMGetGlobalParent - (Global : in llvm.LLVMValueRef) - return llvm.LLVMModuleRef; - - function LLVMIsDeclaration - (Global : in llvm.LLVMValueRef) - return Interfaces.C.int; - - function LLVMGetLinkage - (Global : in llvm.LLVMValueRef) - return llvm.LLVMLinkage; - - procedure LLVMSetLinkage - (Global : in llvm.LLVMValueRef; - Linkage : in llvm.LLVMLinkage); - - function LLVMGetSection - (Global : in llvm.LLVMValueRef) - return Interfaces.C.Strings.chars_ptr; - - procedure LLVMSetSection - (Global : in llvm.LLVMValueRef; - Section : in Interfaces.C.Strings.chars_ptr); - - function LLVMGetVisibility - (Global : in llvm.LLVMValueRef) - return llvm.LLVMVisibility; - - procedure LLVMSetVisibility - (Global : in llvm.LLVMValueRef; - Viz : in llvm.LLVMVisibility); - - function LLVMGetAlignment - (Global : in llvm.LLVMValueRef) - return Interfaces.C.unsigned; - - procedure LLVMSetAlignment - (Global : in llvm.LLVMValueRef; - Bytes : in Interfaces.C.unsigned); - - function LLVMAddGlobal - (M : in llvm.LLVMModuleRef; - Ty : in llvm.LLVMTypeRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMGetNamedGlobal - (M : in llvm.LLVMModuleRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMGetFirstGlobal - (M : in llvm.LLVMModuleRef) - return llvm.LLVMValueRef; - - function LLVMGetLastGlobal - (M : in llvm.LLVMModuleRef) - return llvm.LLVMValueRef; - - function LLVMGetNextGlobal - (GlobalVar : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMGetPreviousGlobal - (GlobalVar : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - procedure LLVMDeleteGlobal (GlobalVar : in llvm.LLVMValueRef); - - function LLVMGetInitializer - (GlobalVar : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - procedure LLVMSetInitializer - (GlobalVar : in llvm.LLVMValueRef; - ConstantVal : in llvm.LLVMValueRef); - - function LLVMIsThreadLocal - (GlobalVar : in llvm.LLVMValueRef) - return Interfaces.C.int; - - procedure LLVMSetThreadLocal - (GlobalVar : in llvm.LLVMValueRef; - IsThreadLocal : in Interfaces.C.int); - - function LLVMIsGlobalConstant - (GlobalVar : in llvm.LLVMValueRef) - return Interfaces.C.int; - - procedure LLVMSetGlobalConstant - (GlobalVar : in llvm.LLVMValueRef; - IsConstant : in Interfaces.C.int); - - function LLVMAddAlias - (M : in llvm.LLVMModuleRef; - Ty : in llvm.LLVMTypeRef; - Aliasee : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMAddFunction - (M : in llvm.LLVMModuleRef; - Name : in Interfaces.C.Strings.chars_ptr; - FunctionTy : in llvm.LLVMTypeRef) - return llvm.LLVMValueRef; - - function LLVMGetNamedFunction - (M : in llvm.LLVMModuleRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMGetFirstFunction - (M : in llvm.LLVMModuleRef) - return llvm.LLVMValueRef; - - function LLVMGetLastFunction - (M : in llvm.LLVMModuleRef) - return llvm.LLVMValueRef; - - function LLVMGetNextFunction - (Fn : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMGetPreviousFunction - (Fn : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - procedure LLVMDeleteFunction (Fn : in llvm.LLVMValueRef); - - function LLVMGetIntrinsicID - (Fn : in llvm.LLVMValueRef) - return Interfaces.C.unsigned; - - function LLVMGetFunctionCallConv - (Fn : in llvm.LLVMValueRef) - return Interfaces.C.unsigned; - - procedure LLVMSetFunctionCallConv - (Fn : in llvm.LLVMValueRef; - CC : in Interfaces.C.unsigned); - - function LLVMGetGC - (Fn : in llvm.LLVMValueRef) - return Interfaces.C.Strings.chars_ptr; - - procedure LLVMSetGC - (Fn : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr); - - procedure LLVMAddFunctionAttr - (Fn : in llvm.LLVMValueRef; - PA : in llvm.LLVMAttribute); - - procedure LLVMRemoveFunctionAttr - (Fn : in llvm.LLVMValueRef; - PA : in llvm.LLVMAttribute); - - function LLVMCountParams - (Fn : in llvm.LLVMValueRef) - return Interfaces.C.unsigned; - - procedure LLVMGetParams - (Fn : in llvm.LLVMValueRef; - Params : access llvm.LLVMValueRef); - - function LLVMGetParam - (Fn : in llvm.LLVMValueRef; - Index : in Interfaces.C.unsigned) - return llvm.LLVMValueRef; - - function LLVMGetParamParent - (Inst : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMGetFirstParam - (Fn : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMGetLastParam - (Fn : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMGetNextParam - (Arg : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMGetPreviousParam - (Arg : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - procedure LLVMAddAttribute - (Arg : in llvm.LLVMValueRef; - PA : in llvm.LLVMAttribute); - - procedure LLVMRemoveAttribute - (Arg : in llvm.LLVMValueRef; - PA : in llvm.LLVMAttribute); - - procedure LLVMSetParamAlignment - (Arg : in llvm.LLVMValueRef; - align : in Interfaces.C.unsigned); - - function LLVMBasicBlockAsValue - (BB : in llvm.LLVMBasicBlockRef) - return llvm.LLVMValueRef; - - function LLVMValueIsBasicBlock - (Val : in llvm.LLVMValueRef) - return Interfaces.C.int; - - function LLVMValueAsBasicBlock - (Val : in llvm.LLVMValueRef) - return llvm.LLVMBasicBlockRef; - - function LLVMGetBasicBlockParent - (BB : in llvm.LLVMBasicBlockRef) - return llvm.LLVMValueRef; - - function LLVMCountBasicBlocks - (Fn : in llvm.LLVMValueRef) - return Interfaces.C.unsigned; - - procedure LLVMGetBasicBlocks - (Fn : in llvm.LLVMValueRef; - BasicBlocks : access llvm.LLVMBasicBlockRef); - - function LLVMGetFirstBasicBlock - (Fn : in llvm.LLVMValueRef) - return llvm.LLVMBasicBlockRef; - - function LLVMGetLastBasicBlock - (Fn : in llvm.LLVMValueRef) - return llvm.LLVMBasicBlockRef; - - function LLVMGetNextBasicBlock - (BB : in llvm.LLVMBasicBlockRef) - return llvm.LLVMBasicBlockRef; - - function LLVMGetPreviousBasicBlock - (BB : in llvm.LLVMBasicBlockRef) - return llvm.LLVMBasicBlockRef; - - function LLVMGetEntryBasicBlock - (Fn : in llvm.LLVMValueRef) - return llvm.LLVMBasicBlockRef; - - function LLVMAppendBasicBlock - (Fn : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMBasicBlockRef; - - function LLVMInsertBasicBlock - (InsertBeforeBB : in llvm.LLVMBasicBlockRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMBasicBlockRef; - - procedure LLVMDeleteBasicBlock (BB : in llvm.LLVMBasicBlockRef); - - function LLVMGetInstructionParent - (Inst : in llvm.LLVMValueRef) - return llvm.LLVMBasicBlockRef; - - function LLVMGetFirstInstruction - (BB : in llvm.LLVMBasicBlockRef) - return llvm.LLVMValueRef; - - function LLVMGetLastInstruction - (BB : in llvm.LLVMBasicBlockRef) - return llvm.LLVMValueRef; - - function LLVMGetNextInstruction - (Inst : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMGetPreviousInstruction - (Inst : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - procedure LLVMSetInstructionCallConv - (Instr : in llvm.LLVMValueRef; - CC : in Interfaces.C.unsigned); - - function LLVMGetInstructionCallConv - (Instr : in llvm.LLVMValueRef) - return Interfaces.C.unsigned; - - procedure LLVMAddInstrAttribute - (Instr : in llvm.LLVMValueRef; - index : in Interfaces.C.unsigned; - arg_1 : in llvm.LLVMAttribute); - - procedure LLVMRemoveInstrAttribute - (Instr : in llvm.LLVMValueRef; - index : in Interfaces.C.unsigned; - arg_1 : in llvm.LLVMAttribute); - - procedure LLVMSetInstrParamAlignment - (Instr : in llvm.LLVMValueRef; - index : in Interfaces.C.unsigned; - align : in Interfaces.C.unsigned); - - function LLVMIsTailCall - (CallInst : in llvm.LLVMValueRef) - return Interfaces.C.int; - - procedure LLVMSetTailCall - (CallInst : in llvm.LLVMValueRef; - IsTailCall : in Interfaces.C.int); - - procedure LLVMAddIncoming - (PhiNode : in llvm.LLVMValueRef; - IncomingValues : access llvm.LLVMValueRef; - IncomingBlocks : access llvm.LLVMBasicBlockRef; - Count : in Interfaces.C.unsigned); - - function LLVMCountIncoming - (PhiNode : in llvm.LLVMValueRef) - return Interfaces.C.unsigned; - - function LLVMGetIncomingValue - (PhiNode : in llvm.LLVMValueRef; - Index : in Interfaces.C.unsigned) - return llvm.LLVMValueRef; - - function LLVMGetIncomingBlock - (PhiNode : in llvm.LLVMValueRef; - Index : in Interfaces.C.unsigned) - return llvm.LLVMBasicBlockRef; - - function LLVMCreateBuilder return llvm.LLVMBuilderRef; - - procedure LLVMPositionBuilder - (Builder : in llvm.LLVMBuilderRef; - Block : in llvm.LLVMBasicBlockRef; - Instr : in llvm.LLVMValueRef); - - procedure LLVMPositionBuilderBefore - (Builder : in llvm.LLVMBuilderRef; - Instr : in llvm.LLVMValueRef); - - procedure LLVMPositionBuilderAtEnd - (Builder : in llvm.LLVMBuilderRef; - Block : in llvm.LLVMBasicBlockRef); - - function LLVMGetInsertBlock - (Builder : in llvm.LLVMBuilderRef) - return llvm.LLVMBasicBlockRef; - - procedure LLVMClearInsertionPosition (Builder : in llvm.LLVMBuilderRef); - - procedure LLVMInsertIntoBuilder - (Builder : in llvm.LLVMBuilderRef; - Instr : in llvm.LLVMValueRef); - - procedure LLVMDisposeBuilder (Builder : in llvm.LLVMBuilderRef); - - function LLVMBuildRetVoid - (arg_1 : in llvm.LLVMBuilderRef) - return llvm.LLVMValueRef; - - function LLVMBuildRet - (arg_1 : in llvm.LLVMBuilderRef; - V : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMBuildBr - (arg_1 : in llvm.LLVMBuilderRef; - Dest : in llvm.LLVMBasicBlockRef) - return llvm.LLVMValueRef; - - function LLVMBuildCondBr - (arg_1 : in llvm.LLVMBuilderRef; - the_If : in llvm.LLVMValueRef; - the_Then : in llvm.LLVMBasicBlockRef; - the_Else : in llvm.LLVMBasicBlockRef) - return llvm.LLVMValueRef; - - function LLVMBuildSwitch - (arg_1 : in llvm.LLVMBuilderRef; - V : in llvm.LLVMValueRef; - the_Else : in llvm.LLVMBasicBlockRef; - NumCases : in Interfaces.C.unsigned) - return llvm.LLVMValueRef; - - function LLVMBuildInvoke - (arg_1 : in llvm.LLVMBuilderRef; - Fn : in llvm.LLVMValueRef; - Args : access llvm.LLVMValueRef; - NumArgs : in Interfaces.C.unsigned; - the_Then : in llvm.LLVMBasicBlockRef; - Catch : in llvm.LLVMBasicBlockRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildUnwind - (arg_1 : in llvm.LLVMBuilderRef) - return llvm.LLVMValueRef; - - function LLVMBuildUnreachable - (arg_1 : in llvm.LLVMBuilderRef) - return llvm.LLVMValueRef; - - procedure LLVMAddCase - (Switch : in llvm.LLVMValueRef; - OnVal : in llvm.LLVMValueRef; - Dest : in llvm.LLVMBasicBlockRef); - - function LLVMBuildAdd - (arg_1 : in llvm.LLVMBuilderRef; - LHS : in llvm.LLVMValueRef; - RHS : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildSub - (arg_1 : in llvm.LLVMBuilderRef; - LHS : in llvm.LLVMValueRef; - RHS : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildMul - (arg_1 : in llvm.LLVMBuilderRef; - LHS : in llvm.LLVMValueRef; - RHS : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildUDiv - (arg_1 : in llvm.LLVMBuilderRef; - LHS : in llvm.LLVMValueRef; - RHS : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildSDiv - (arg_1 : in llvm.LLVMBuilderRef; - LHS : in llvm.LLVMValueRef; - RHS : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildFDiv - (arg_1 : in llvm.LLVMBuilderRef; - LHS : in llvm.LLVMValueRef; - RHS : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildURem - (arg_1 : in llvm.LLVMBuilderRef; - LHS : in llvm.LLVMValueRef; - RHS : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildSRem - (arg_1 : in llvm.LLVMBuilderRef; - LHS : in llvm.LLVMValueRef; - RHS : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildFRem - (arg_1 : in llvm.LLVMBuilderRef; - LHS : in llvm.LLVMValueRef; - RHS : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildShl - (arg_1 : in llvm.LLVMBuilderRef; - LHS : in llvm.LLVMValueRef; - RHS : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildLShr - (arg_1 : in llvm.LLVMBuilderRef; - LHS : in llvm.LLVMValueRef; - RHS : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildAShr - (arg_1 : in llvm.LLVMBuilderRef; - LHS : in llvm.LLVMValueRef; - RHS : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildAnd - (arg_1 : in llvm.LLVMBuilderRef; - LHS : in llvm.LLVMValueRef; - RHS : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildOr - (arg_1 : in llvm.LLVMBuilderRef; - LHS : in llvm.LLVMValueRef; - RHS : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildXor - (arg_1 : in llvm.LLVMBuilderRef; - LHS : in llvm.LLVMValueRef; - RHS : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildNeg - (arg_1 : in llvm.LLVMBuilderRef; - V : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildNot - (arg_1 : in llvm.LLVMBuilderRef; - V : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildMalloc - (arg_1 : in llvm.LLVMBuilderRef; - Ty : in llvm.LLVMTypeRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildArrayMalloc - (arg_1 : in llvm.LLVMBuilderRef; - Ty : in llvm.LLVMTypeRef; - Val : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildAlloca - (arg_1 : in llvm.LLVMBuilderRef; - Ty : in llvm.LLVMTypeRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildArrayAlloca - (arg_1 : in llvm.LLVMBuilderRef; - Ty : in llvm.LLVMTypeRef; - Val : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildFree - (arg_1 : in llvm.LLVMBuilderRef; - PointerVal : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMBuildLoad - (arg_1 : in llvm.LLVMBuilderRef; - PointerVal : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildStore - (arg_1 : in llvm.LLVMBuilderRef; - Val : in llvm.LLVMValueRef; - Ptr : in llvm.LLVMValueRef) - return llvm.LLVMValueRef; - - function LLVMBuildGEP - (B : in llvm.LLVMBuilderRef; - Pointer : in llvm.LLVMValueRef; - Indices : access llvm.LLVMValueRef; - NumIndices : in Interfaces.C.unsigned; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildTrunc - (arg_1 : in llvm.LLVMBuilderRef; - Val : in llvm.LLVMValueRef; - DestTy : in llvm.LLVMTypeRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildZExt - (arg_1 : in llvm.LLVMBuilderRef; - Val : in llvm.LLVMValueRef; - DestTy : in llvm.LLVMTypeRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildSExt - (arg_1 : in llvm.LLVMBuilderRef; - Val : in llvm.LLVMValueRef; - DestTy : in llvm.LLVMTypeRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildFPToUI - (arg_1 : in llvm.LLVMBuilderRef; - Val : in llvm.LLVMValueRef; - DestTy : in llvm.LLVMTypeRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildFPToSI - (arg_1 : in llvm.LLVMBuilderRef; - Val : in llvm.LLVMValueRef; - DestTy : in llvm.LLVMTypeRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildUIToFP - (arg_1 : in llvm.LLVMBuilderRef; - Val : in llvm.LLVMValueRef; - DestTy : in llvm.LLVMTypeRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildSIToFP - (arg_1 : in llvm.LLVMBuilderRef; - Val : in llvm.LLVMValueRef; - DestTy : in llvm.LLVMTypeRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildFPTrunc - (arg_1 : in llvm.LLVMBuilderRef; - Val : in llvm.LLVMValueRef; - DestTy : in llvm.LLVMTypeRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildFPExt - (arg_1 : in llvm.LLVMBuilderRef; - Val : in llvm.LLVMValueRef; - DestTy : in llvm.LLVMTypeRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildPtrToInt - (arg_1 : in llvm.LLVMBuilderRef; - Val : in llvm.LLVMValueRef; - DestTy : in llvm.LLVMTypeRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildIntToPtr - (arg_1 : in llvm.LLVMBuilderRef; - Val : in llvm.LLVMValueRef; - DestTy : in llvm.LLVMTypeRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildBitCast - (arg_1 : in llvm.LLVMBuilderRef; - Val : in llvm.LLVMValueRef; - DestTy : in llvm.LLVMTypeRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildICmp - (arg_1 : in llvm.LLVMBuilderRef; - Op : in llvm.LLVMIntPredicate; - LHS : in llvm.LLVMValueRef; - RHS : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildFCmp - (arg_1 : in llvm.LLVMBuilderRef; - Op : in llvm.LLVMRealPredicate; - LHS : in llvm.LLVMValueRef; - RHS : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildPhi - (arg_1 : in llvm.LLVMBuilderRef; - Ty : in llvm.LLVMTypeRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildCall - (arg_1 : in llvm.LLVMBuilderRef; - Fn : in llvm.LLVMValueRef; - Args : access llvm.LLVMValueRef; - NumArgs : in Interfaces.C.unsigned; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildSelect - (arg_1 : in llvm.LLVMBuilderRef; - the_If : in llvm.LLVMValueRef; - the_Then : in llvm.LLVMValueRef; - the_Else : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildVAArg - (arg_1 : in llvm.LLVMBuilderRef; - List : in llvm.LLVMValueRef; - Ty : in llvm.LLVMTypeRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildExtractElement - (arg_1 : in llvm.LLVMBuilderRef; - VecVal : in llvm.LLVMValueRef; - Index : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildInsertElement - (arg_1 : in llvm.LLVMBuilderRef; - VecVal : in llvm.LLVMValueRef; - EltVal : in llvm.LLVMValueRef; - Index : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildShuffleVector - (arg_1 : in llvm.LLVMBuilderRef; - V1 : in llvm.LLVMValueRef; - V2 : in llvm.LLVMValueRef; - Mask : in llvm.LLVMValueRef; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildExtractValue - (arg_1 : in llvm.LLVMBuilderRef; - AggVal : in llvm.LLVMValueRef; - Index : in Interfaces.C.unsigned; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMBuildInsertValue - (arg_1 : in llvm.LLVMBuilderRef; - AggVal : in llvm.LLVMValueRef; - EltVal : in llvm.LLVMValueRef; - Index : in Interfaces.C.unsigned; - Name : in Interfaces.C.Strings.chars_ptr) - return llvm.LLVMValueRef; - - function LLVMCreateModuleProviderForExistingModule - (M : in llvm.LLVMModuleRef) - return llvm.LLVMModuleProviderRef; - - procedure LLVMDisposeModuleProvider (MP : in llvm.LLVMModuleProviderRef); - - function LLVMCreateMemoryBufferWithContentsOfFile - (Path : in Interfaces.C.Strings.chars_ptr; - OutMemBuf : access llvm.LLVMMemoryBufferRef; - OutMessage : access Interfaces.C.Strings.chars_ptr) - return Interfaces.C.int; - - function LLVMCreateMemoryBufferWithSTDIN - (OutMemBuf : access llvm.LLVMMemoryBufferRef; - OutMessage : access Interfaces.C.Strings.chars_ptr) - return Interfaces.C.int; - - procedure LLVMDisposeMemoryBuffer (MemBuf : in llvm.LLVMMemoryBufferRef); - - function LLVMCreatePassManager return llvm.LLVMPassManagerRef; - - function LLVMCreateFunctionPassManager - (MP : in llvm.LLVMModuleProviderRef) - return llvm.LLVMPassManagerRef; - - function LLVMRunPassManager - (PM : in llvm.LLVMPassManagerRef; - M : in llvm.LLVMModuleRef) - return Interfaces.C.int; - - function LLVMInitializeFunctionPassManager - (FPM : in llvm.LLVMPassManagerRef) - return Interfaces.C.int; - - function LLVMRunFunctionPassManager - (FPM : in llvm.LLVMPassManagerRef; - F : in llvm.LLVMValueRef) - return Interfaces.C.int; - - function LLVMFinalizeFunctionPassManager - (FPM : in llvm.LLVMPassManagerRef) - return Interfaces.C.int; - - procedure LLVMDisposePassManager (PM : in llvm.LLVMPassManagerRef); - -private - - pragma Import (C, LLVMDisposeMessage, "Ada_LLVMDisposeMessage"); - pragma Import (C, LLVMContextCreate, "Ada_LLVMContextCreate"); - pragma Import (C, LLVMGetGlobalContext, "Ada_LLVMGetGlobalContext"); - pragma Import (C, LLVMContextDispose, "Ada_LLVMContextDispose"); - pragma Import - (C, - LLVMModuleCreateWithName, - "Ada_LLVMModuleCreateWithName"); - pragma Import - (C, - LLVMModuleCreateWithNameInContext, - "Ada_LLVMModuleCreateWithNameInContext"); - pragma Import (C, LLVMDisposeModule, "Ada_LLVMDisposeModule"); - pragma Import (C, LLVMGetDataLayout, "Ada_LLVMGetDataLayout"); - pragma Import (C, LLVMSetDataLayout, "Ada_LLVMSetDataLayout"); - pragma Import (C, LLVMGetTarget, "Ada_LLVMGetTarget"); - pragma Import (C, LLVMSetTarget, "Ada_LLVMSetTarget"); - pragma Import (C, LLVMAddTypeName, "Ada_LLVMAddTypeName"); - pragma Import (C, LLVMDeleteTypeName, "Ada_LLVMDeleteTypeName"); - pragma Import (C, LLVMGetTypeByName, "Ada_LLVMGetTypeByName"); - pragma Import (C, LLVMDumpModule, "Ada_LLVMDumpModule"); - pragma Import (C, LLVMGetTypeKind, "Ada_LLVMGetTypeKind"); - pragma Import (C, LLVMInt1Type, "Ada_LLVMInt1Type"); - pragma Import (C, LLVMInt8Type, "Ada_LLVMInt8Type"); - pragma Import (C, LLVMInt16Type, "Ada_LLVMInt16Type"); - pragma Import (C, LLVMInt32Type, "Ada_LLVMInt32Type"); - pragma Import (C, LLVMInt64Type, "Ada_LLVMInt64Type"); - pragma Import (C, LLVMIntType, "Ada_LLVMIntType"); - pragma Import (C, LLVMGetIntTypeWidth, "Ada_LLVMGetIntTypeWidth"); - pragma Import (C, LLVMFloatType, "Ada_LLVMFloatType"); - pragma Import (C, LLVMDoubleType, "Ada_LLVMDoubleType"); - pragma Import (C, LLVMX86FP80Type, "Ada_LLVMX86FP80Type"); - pragma Import (C, LLVMFP128Type, "Ada_LLVMFP128Type"); - pragma Import (C, LLVMPPCFP128Type, "Ada_LLVMPPCFP128Type"); - pragma Import (C, LLVMFunctionType, "Ada_LLVMFunctionType"); - pragma Import (C, LLVMIsFunctionVarArg, "Ada_LLVMIsFunctionVarArg"); - pragma Import (C, LLVMGetReturnType, "Ada_LLVMGetReturnType"); - pragma Import (C, LLVMCountParamTypes, "Ada_LLVMCountParamTypes"); - pragma Import (C, LLVMGetParamTypes, "Ada_LLVMGetParamTypes"); - pragma Import (C, LLVMStructType, "Ada_LLVMStructType"); - pragma Import - (C, - LLVMCountStructElementTypes, - "Ada_LLVMCountStructElementTypes"); - pragma Import - (C, - LLVMGetStructElementTypes, - "Ada_LLVMGetStructElementTypes"); - pragma Import (C, LLVMIsPackedStruct, "Ada_LLVMIsPackedStruct"); - pragma Import (C, LLVMArrayType, "Ada_LLVMArrayType"); - pragma Import (C, LLVMPointerType, "Ada_LLVMPointerType"); - pragma Import (C, LLVMVectorType, "Ada_LLVMVectorType"); - pragma Import (C, LLVMGetElementType, "Ada_LLVMGetElementType"); - pragma Import (C, LLVMGetArrayLength, "Ada_LLVMGetArrayLength"); - pragma Import - (C, - LLVMGetPointerAddressSpace, - "Ada_LLVMGetPointerAddressSpace"); - pragma Import (C, LLVMGetVectorSize, "Ada_LLVMGetVectorSize"); - pragma Import (C, LLVMVoidType, "Ada_LLVMVoidType"); - pragma Import (C, LLVMLabelType, "Ada_LLVMLabelType"); - pragma Import (C, LLVMOpaqueType, "Ada_LLVMOpaqueType"); - pragma Import (C, LLVMCreateTypeHandle, "Ada_LLVMCreateTypeHandle"); - pragma Import (C, LLVMRefineType, "Ada_LLVMRefineType"); - pragma Import (C, LLVMResolveTypeHandle, "Ada_LLVMResolveTypeHandle"); - pragma Import (C, LLVMDisposeTypeHandle, "Ada_LLVMDisposeTypeHandle"); - pragma Import (C, LLVMTypeOf, "Ada_LLVMTypeOf"); - pragma Import (C, LLVMGetValueName, "Ada_LLVMGetValueName"); - pragma Import (C, LLVMSetValueName, "Ada_LLVMSetValueName"); - pragma Import (C, LLVMDumpValue, "Ada_LLVMDumpValue"); - pragma Import (C, LLVMIsAArgument, "Ada_LLVMIsAArgument"); - pragma Import (C, LLVMIsABasicBlock, "Ada_LLVMIsABasicBlock"); - pragma Import (C, LLVMIsAInlineAsm, "Ada_LLVMIsAInlineAsm"); - pragma Import (C, LLVMIsAUser, "Ada_LLVMIsAUser"); - pragma Import (C, LLVMIsAConstant, "Ada_LLVMIsAConstant"); - pragma Import - (C, - LLVMIsAConstantAggregateZero, - "Ada_LLVMIsAConstantAggregateZero"); - pragma Import (C, LLVMIsAConstantArray, "Ada_LLVMIsAConstantArray"); - pragma Import (C, LLVMIsAConstantExpr, "Ada_LLVMIsAConstantExpr"); - pragma Import (C, LLVMIsAConstantFP, "Ada_LLVMIsAConstantFP"); - pragma Import (C, LLVMIsAConstantInt, "Ada_LLVMIsAConstantInt"); - pragma Import - (C, - LLVMIsAConstantPointerNull, - "Ada_LLVMIsAConstantPointerNull"); - pragma Import (C, LLVMIsAConstantStruct, "Ada_LLVMIsAConstantStruct"); - pragma Import (C, LLVMIsAConstantVector, "Ada_LLVMIsAConstantVector"); - pragma Import (C, LLVMIsAGlobalValue, "Ada_LLVMIsAGlobalValue"); - pragma Import (C, LLVMIsAFunction, "Ada_LLVMIsAFunction"); - pragma Import (C, LLVMIsAGlobalAlias, "Ada_LLVMIsAGlobalAlias"); - pragma Import (C, LLVMIsAGlobalVariable, "Ada_LLVMIsAGlobalVariable"); - pragma Import (C, LLVMIsAUndefValue, "Ada_LLVMIsAUndefValue"); - pragma Import (C, LLVMIsAInstruction, "Ada_LLVMIsAInstruction"); - pragma Import (C, LLVMIsABinaryOperator, "Ada_LLVMIsABinaryOperator"); - pragma Import (C, LLVMIsACallInst, "Ada_LLVMIsACallInst"); - pragma Import (C, LLVMIsAIntrinsicInst, "Ada_LLVMIsAIntrinsicInst"); - pragma Import (C, LLVMIsADbgInfoIntrinsic, "Ada_LLVMIsADbgInfoIntrinsic"); - pragma Import (C, LLVMIsADbgDeclareInst, "Ada_LLVMIsADbgDeclareInst"); - pragma Import (C, LLVMIsADbgFuncStartInst, "Ada_LLVMIsADbgFuncStartInst"); - pragma Import (C, LLVMIsADbgRegionEndInst, "Ada_LLVMIsADbgRegionEndInst"); - pragma Import - (C, - LLVMIsADbgRegionStartInst, - "Ada_LLVMIsADbgRegionStartInst"); - pragma Import (C, LLVMIsADbgStopPointInst, "Ada_LLVMIsADbgStopPointInst"); - pragma Import (C, LLVMIsAEHSelectorInst, "Ada_LLVMIsAEHSelectorInst"); - pragma Import (C, LLVMIsAMemIntrinsic, "Ada_LLVMIsAMemIntrinsic"); - pragma Import (C, LLVMIsAMemCpyInst, "Ada_LLVMIsAMemCpyInst"); - pragma Import (C, LLVMIsAMemMoveInst, "Ada_LLVMIsAMemMoveInst"); - pragma Import (C, LLVMIsAMemSetInst, "Ada_LLVMIsAMemSetInst"); - pragma Import (C, LLVMIsACmpInst, "Ada_LLVMIsACmpInst"); - pragma Import (C, LLVMIsAFCmpInst, "Ada_LLVMIsAFCmpInst"); - pragma Import (C, LLVMIsAICmpInst, "Ada_LLVMIsAICmpInst"); - pragma Import - (C, - LLVMIsAExtractElementInst, - "Ada_LLVMIsAExtractElementInst"); - pragma Import - (C, - LLVMIsAGetElementPtrInst, - "Ada_LLVMIsAGetElementPtrInst"); - pragma Import - (C, - LLVMIsAInsertElementInst, - "Ada_LLVMIsAInsertElementInst"); - pragma Import (C, LLVMIsAInsertValueInst, "Ada_LLVMIsAInsertValueInst"); - pragma Import (C, LLVMIsAPHINode, "Ada_LLVMIsAPHINode"); - pragma Import (C, LLVMIsASelectInst, "Ada_LLVMIsASelectInst"); - pragma Import - (C, - LLVMIsAShuffleVectorInst, - "Ada_LLVMIsAShuffleVectorInst"); - pragma Import (C, LLVMIsAStoreInst, "Ada_LLVMIsAStoreInst"); - pragma Import (C, LLVMIsATerminatorInst, "Ada_LLVMIsATerminatorInst"); - pragma Import (C, LLVMIsABranchInst, "Ada_LLVMIsABranchInst"); - pragma Import (C, LLVMIsAInvokeInst, "Ada_LLVMIsAInvokeInst"); - pragma Import (C, LLVMIsAReturnInst, "Ada_LLVMIsAReturnInst"); - pragma Import (C, LLVMIsASwitchInst, "Ada_LLVMIsASwitchInst"); - pragma Import (C, LLVMIsAUnreachableInst, "Ada_LLVMIsAUnreachableInst"); - pragma Import (C, LLVMIsAUnwindInst, "Ada_LLVMIsAUnwindInst"); - pragma Import (C, LLVMIsAUnaryInstruction, "Ada_LLVMIsAUnaryInstruction"); - pragma Import (C, LLVMIsAAllocationInst, "Ada_LLVMIsAAllocationInst"); - pragma Import (C, LLVMIsAAllocaInst, "Ada_LLVMIsAAllocaInst"); - pragma Import (C, LLVMIsAMallocInst, "Ada_LLVMIsAMallocInst"); - pragma Import (C, LLVMIsACastInst, "Ada_LLVMIsACastInst"); - pragma Import (C, LLVMIsABitCastInst, "Ada_LLVMIsABitCastInst"); - pragma Import (C, LLVMIsAFPExtInst, "Ada_LLVMIsAFPExtInst"); - pragma Import (C, LLVMIsAFPToSIInst, "Ada_LLVMIsAFPToSIInst"); - pragma Import (C, LLVMIsAFPToUIInst, "Ada_LLVMIsAFPToUIInst"); - pragma Import (C, LLVMIsAFPTruncInst, "Ada_LLVMIsAFPTruncInst"); - pragma Import (C, LLVMIsAIntToPtrInst, "Ada_LLVMIsAIntToPtrInst"); - pragma Import (C, LLVMIsAPtrToIntInst, "Ada_LLVMIsAPtrToIntInst"); - pragma Import (C, LLVMIsASExtInst, "Ada_LLVMIsASExtInst"); - pragma Import (C, LLVMIsASIToFPInst, "Ada_LLVMIsASIToFPInst"); - pragma Import (C, LLVMIsATruncInst, "Ada_LLVMIsATruncInst"); - pragma Import (C, LLVMIsAUIToFPInst, "Ada_LLVMIsAUIToFPInst"); - pragma Import (C, LLVMIsAZExtInst, "Ada_LLVMIsAZExtInst"); - pragma Import (C, LLVMIsAExtractValueInst, "Ada_LLVMIsAExtractValueInst"); - pragma Import (C, LLVMIsAFreeInst, "Ada_LLVMIsAFreeInst"); - pragma Import (C, LLVMIsALoadInst, "Ada_LLVMIsALoadInst"); - pragma Import (C, LLVMIsAVAArgInst, "Ada_LLVMIsAVAArgInst"); - pragma Import (C, LLVMConstNull, "Ada_LLVMConstNull"); - pragma Import (C, LLVMConstAllOnes, "Ada_LLVMConstAllOnes"); - pragma Import (C, LLVMGetUndef, "Ada_LLVMGetUndef"); - pragma Import (C, LLVMIsConstant, "Ada_LLVMIsConstant"); - pragma Import (C, LLVMIsNull, "Ada_LLVMIsNull"); - pragma Import (C, LLVMIsUndef, "Ada_LLVMIsUndef"); - pragma Import (C, LLVMConstPointerNull, "Ada_LLVMConstPointerNull"); - pragma Import (C, LLVMConstInt, "Ada_LLVMConstInt"); - pragma Import (C, LLVMConstReal, "Ada_LLVMConstReal"); - pragma Import (C, LLVMConstRealOfString, "Ada_LLVMConstRealOfString"); - pragma Import (C, LLVMConstString, "Ada_LLVMConstString"); - pragma Import (C, LLVMConstArray, "Ada_LLVMConstArray"); - pragma Import (C, LLVMConstStruct, "Ada_LLVMConstStruct"); - pragma Import (C, LLVMConstVector, "Ada_LLVMConstVector"); - pragma Import (C, LLVMSizeOf, "Ada_LLVMSizeOf"); - pragma Import (C, LLVMConstNeg, "Ada_LLVMConstNeg"); - pragma Import (C, LLVMConstNot, "Ada_LLVMConstNot"); - pragma Import (C, LLVMConstAdd, "Ada_LLVMConstAdd"); - pragma Import (C, LLVMConstSub, "Ada_LLVMConstSub"); - pragma Import (C, LLVMConstMul, "Ada_LLVMConstMul"); - pragma Import (C, LLVMConstUDiv, "Ada_LLVMConstUDiv"); - pragma Import (C, LLVMConstSDiv, "Ada_LLVMConstSDiv"); - pragma Import (C, LLVMConstFDiv, "Ada_LLVMConstFDiv"); - pragma Import (C, LLVMConstURem, "Ada_LLVMConstURem"); - pragma Import (C, LLVMConstSRem, "Ada_LLVMConstSRem"); - pragma Import (C, LLVMConstFRem, "Ada_LLVMConstFRem"); - pragma Import (C, LLVMConstAnd, "Ada_LLVMConstAnd"); - pragma Import (C, LLVMConstOr, "Ada_LLVMConstOr"); - pragma Import (C, LLVMConstXor, "Ada_LLVMConstXor"); - pragma Import (C, LLVMConstICmp, "Ada_LLVMConstICmp"); - pragma Import (C, LLVMConstFCmp, "Ada_LLVMConstFCmp"); - pragma Import (C, LLVMConstShl, "Ada_LLVMConstShl"); - pragma Import (C, LLVMConstLShr, "Ada_LLVMConstLShr"); - pragma Import (C, LLVMConstAShr, "Ada_LLVMConstAShr"); - pragma Import (C, LLVMConstGEP, "Ada_LLVMConstGEP"); - pragma Import (C, LLVMConstTrunc, "Ada_LLVMConstTrunc"); - pragma Import (C, LLVMConstSExt, "Ada_LLVMConstSExt"); - pragma Import (C, LLVMConstZExt, "Ada_LLVMConstZExt"); - pragma Import (C, LLVMConstFPTrunc, "Ada_LLVMConstFPTrunc"); - pragma Import (C, LLVMConstFPExt, "Ada_LLVMConstFPExt"); - pragma Import (C, LLVMConstUIToFP, "Ada_LLVMConstUIToFP"); - pragma Import (C, LLVMConstSIToFP, "Ada_LLVMConstSIToFP"); - pragma Import (C, LLVMConstFPToUI, "Ada_LLVMConstFPToUI"); - pragma Import (C, LLVMConstFPToSI, "Ada_LLVMConstFPToSI"); - pragma Import (C, LLVMConstPtrToInt, "Ada_LLVMConstPtrToInt"); - pragma Import (C, LLVMConstIntToPtr, "Ada_LLVMConstIntToPtr"); - pragma Import (C, LLVMConstBitCast, "Ada_LLVMConstBitCast"); - pragma Import (C, LLVMConstSelect, "Ada_LLVMConstSelect"); - pragma Import (C, LLVMConstExtractElement, "Ada_LLVMConstExtractElement"); - pragma Import (C, LLVMConstInsertElement, "Ada_LLVMConstInsertElement"); - pragma Import (C, LLVMConstShuffleVector, "Ada_LLVMConstShuffleVector"); - pragma Import (C, LLVMConstExtractValue, "Ada_LLVMConstExtractValue"); - pragma Import (C, LLVMConstInsertValue, "Ada_LLVMConstInsertValue"); - pragma Import (C, LLVMConstInlineAsm, "Ada_LLVMConstInlineAsm"); - pragma Import (C, LLVMGetGlobalParent, "Ada_LLVMGetGlobalParent"); - pragma Import (C, LLVMIsDeclaration, "Ada_LLVMIsDeclaration"); - pragma Import (C, LLVMGetLinkage, "Ada_LLVMGetLinkage"); - pragma Import (C, LLVMSetLinkage, "Ada_LLVMSetLinkage"); - pragma Import (C, LLVMGetSection, "Ada_LLVMGetSection"); - pragma Import (C, LLVMSetSection, "Ada_LLVMSetSection"); - pragma Import (C, LLVMGetVisibility, "Ada_LLVMGetVisibility"); - pragma Import (C, LLVMSetVisibility, "Ada_LLVMSetVisibility"); - pragma Import (C, LLVMGetAlignment, "Ada_LLVMGetAlignment"); - pragma Import (C, LLVMSetAlignment, "Ada_LLVMSetAlignment"); - pragma Import (C, LLVMAddGlobal, "Ada_LLVMAddGlobal"); - pragma Import (C, LLVMGetNamedGlobal, "Ada_LLVMGetNamedGlobal"); - pragma Import (C, LLVMGetFirstGlobal, "Ada_LLVMGetFirstGlobal"); - pragma Import (C, LLVMGetLastGlobal, "Ada_LLVMGetLastGlobal"); - pragma Import (C, LLVMGetNextGlobal, "Ada_LLVMGetNextGlobal"); - pragma Import (C, LLVMGetPreviousGlobal, "Ada_LLVMGetPreviousGlobal"); - pragma Import (C, LLVMDeleteGlobal, "Ada_LLVMDeleteGlobal"); - pragma Import (C, LLVMGetInitializer, "Ada_LLVMGetInitializer"); - pragma Import (C, LLVMSetInitializer, "Ada_LLVMSetInitializer"); - pragma Import (C, LLVMIsThreadLocal, "Ada_LLVMIsThreadLocal"); - pragma Import (C, LLVMSetThreadLocal, "Ada_LLVMSetThreadLocal"); - pragma Import (C, LLVMIsGlobalConstant, "Ada_LLVMIsGlobalConstant"); - pragma Import (C, LLVMSetGlobalConstant, "Ada_LLVMSetGlobalConstant"); - pragma Import (C, LLVMAddAlias, "Ada_LLVMAddAlias"); - pragma Import (C, LLVMAddFunction, "Ada_LLVMAddFunction"); - pragma Import (C, LLVMGetNamedFunction, "Ada_LLVMGetNamedFunction"); - pragma Import (C, LLVMGetFirstFunction, "Ada_LLVMGetFirstFunction"); - pragma Import (C, LLVMGetLastFunction, "Ada_LLVMGetLastFunction"); - pragma Import (C, LLVMGetNextFunction, "Ada_LLVMGetNextFunction"); - pragma Import (C, LLVMGetPreviousFunction, "Ada_LLVMGetPreviousFunction"); - pragma Import (C, LLVMDeleteFunction, "Ada_LLVMDeleteFunction"); - pragma Import (C, LLVMGetIntrinsicID, "Ada_LLVMGetIntrinsicID"); - pragma Import (C, LLVMGetFunctionCallConv, "Ada_LLVMGetFunctionCallConv"); - pragma Import (C, LLVMSetFunctionCallConv, "Ada_LLVMSetFunctionCallConv"); - pragma Import (C, LLVMGetGC, "Ada_LLVMGetGC"); - pragma Import (C, LLVMSetGC, "Ada_LLVMSetGC"); - pragma Import (C, LLVMAddFunctionAttr, "Ada_LLVMAddFunctionAttr"); - pragma Import (C, LLVMRemoveFunctionAttr, "Ada_LLVMRemoveFunctionAttr"); - pragma Import (C, LLVMCountParams, "Ada_LLVMCountParams"); - pragma Import (C, LLVMGetParams, "Ada_LLVMGetParams"); - pragma Import (C, LLVMGetParam, "Ada_LLVMGetParam"); - pragma Import (C, LLVMGetParamParent, "Ada_LLVMGetParamParent"); - pragma Import (C, LLVMGetFirstParam, "Ada_LLVMGetFirstParam"); - pragma Import (C, LLVMGetLastParam, "Ada_LLVMGetLastParam"); - pragma Import (C, LLVMGetNextParam, "Ada_LLVMGetNextParam"); - pragma Import (C, LLVMGetPreviousParam, "Ada_LLVMGetPreviousParam"); - pragma Import (C, LLVMAddAttribute, "Ada_LLVMAddAttribute"); - pragma Import (C, LLVMRemoveAttribute, "Ada_LLVMRemoveAttribute"); - pragma Import (C, LLVMSetParamAlignment, "Ada_LLVMSetParamAlignment"); - pragma Import (C, LLVMBasicBlockAsValue, "Ada_LLVMBasicBlockAsValue"); - pragma Import (C, LLVMValueIsBasicBlock, "Ada_LLVMValueIsBasicBlock"); - pragma Import (C, LLVMValueAsBasicBlock, "Ada_LLVMValueAsBasicBlock"); - pragma Import (C, LLVMGetBasicBlockParent, "Ada_LLVMGetBasicBlockParent"); - pragma Import (C, LLVMCountBasicBlocks, "Ada_LLVMCountBasicBlocks"); - pragma Import (C, LLVMGetBasicBlocks, "Ada_LLVMGetBasicBlocks"); - pragma Import (C, LLVMGetFirstBasicBlock, "Ada_LLVMGetFirstBasicBlock"); - pragma Import (C, LLVMGetLastBasicBlock, "Ada_LLVMGetLastBasicBlock"); - pragma Import (C, LLVMGetNextBasicBlock, "Ada_LLVMGetNextBasicBlock"); - pragma Import - (C, - LLVMGetPreviousBasicBlock, - "Ada_LLVMGetPreviousBasicBlock"); - pragma Import (C, LLVMGetEntryBasicBlock, "Ada_LLVMGetEntryBasicBlock"); - pragma Import (C, LLVMAppendBasicBlock, "Ada_LLVMAppendBasicBlock"); - pragma Import (C, LLVMInsertBasicBlock, "Ada_LLVMInsertBasicBlock"); - pragma Import (C, LLVMDeleteBasicBlock, "Ada_LLVMDeleteBasicBlock"); - pragma Import - (C, - LLVMGetInstructionParent, - "Ada_LLVMGetInstructionParent"); - pragma Import (C, LLVMGetFirstInstruction, "Ada_LLVMGetFirstInstruction"); - pragma Import (C, LLVMGetLastInstruction, "Ada_LLVMGetLastInstruction"); - pragma Import (C, LLVMGetNextInstruction, "Ada_LLVMGetNextInstruction"); - pragma Import - (C, - LLVMGetPreviousInstruction, - "Ada_LLVMGetPreviousInstruction"); - pragma Import - (C, - LLVMSetInstructionCallConv, - "Ada_LLVMSetInstructionCallConv"); - pragma Import - (C, - LLVMGetInstructionCallConv, - "Ada_LLVMGetInstructionCallConv"); - pragma Import (C, LLVMAddInstrAttribute, "Ada_LLVMAddInstrAttribute"); - pragma Import - (C, - LLVMRemoveInstrAttribute, - "Ada_LLVMRemoveInstrAttribute"); - pragma Import - (C, - LLVMSetInstrParamAlignment, - "Ada_LLVMSetInstrParamAlignment"); - pragma Import (C, LLVMIsTailCall, "Ada_LLVMIsTailCall"); - pragma Import (C, LLVMSetTailCall, "Ada_LLVMSetTailCall"); - pragma Import (C, LLVMAddIncoming, "Ada_LLVMAddIncoming"); - pragma Import (C, LLVMCountIncoming, "Ada_LLVMCountIncoming"); - pragma Import (C, LLVMGetIncomingValue, "Ada_LLVMGetIncomingValue"); - pragma Import (C, LLVMGetIncomingBlock, "Ada_LLVMGetIncomingBlock"); - pragma Import (C, LLVMCreateBuilder, "Ada_LLVMCreateBuilder"); - pragma Import (C, LLVMPositionBuilder, "Ada_LLVMPositionBuilder"); - pragma Import - (C, - LLVMPositionBuilderBefore, - "Ada_LLVMPositionBuilderBefore"); - pragma Import - (C, - LLVMPositionBuilderAtEnd, - "Ada_LLVMPositionBuilderAtEnd"); - pragma Import (C, LLVMGetInsertBlock, "Ada_LLVMGetInsertBlock"); - pragma Import - (C, - LLVMClearInsertionPosition, - "Ada_LLVMClearInsertionPosition"); - pragma Import (C, LLVMInsertIntoBuilder, "Ada_LLVMInsertIntoBuilder"); - pragma Import (C, LLVMDisposeBuilder, "Ada_LLVMDisposeBuilder"); - pragma Import (C, LLVMBuildRetVoid, "Ada_LLVMBuildRetVoid"); - pragma Import (C, LLVMBuildRet, "Ada_LLVMBuildRet"); - pragma Import (C, LLVMBuildBr, "Ada_LLVMBuildBr"); - pragma Import (C, LLVMBuildCondBr, "Ada_LLVMBuildCondBr"); - pragma Import (C, LLVMBuildSwitch, "Ada_LLVMBuildSwitch"); - pragma Import (C, LLVMBuildInvoke, "Ada_LLVMBuildInvoke"); - pragma Import (C, LLVMBuildUnwind, "Ada_LLVMBuildUnwind"); - pragma Import (C, LLVMBuildUnreachable, "Ada_LLVMBuildUnreachable"); - pragma Import (C, LLVMAddCase, "Ada_LLVMAddCase"); - pragma Import (C, LLVMBuildAdd, "Ada_LLVMBuildAdd"); - pragma Import (C, LLVMBuildSub, "Ada_LLVMBuildSub"); - pragma Import (C, LLVMBuildMul, "Ada_LLVMBuildMul"); - pragma Import (C, LLVMBuildUDiv, "Ada_LLVMBuildUDiv"); - pragma Import (C, LLVMBuildSDiv, "Ada_LLVMBuildSDiv"); - pragma Import (C, LLVMBuildFDiv, "Ada_LLVMBuildFDiv"); - pragma Import (C, LLVMBuildURem, "Ada_LLVMBuildURem"); - pragma Import (C, LLVMBuildSRem, "Ada_LLVMBuildSRem"); - pragma Import (C, LLVMBuildFRem, "Ada_LLVMBuildFRem"); - pragma Import (C, LLVMBuildShl, "Ada_LLVMBuildShl"); - pragma Import (C, LLVMBuildLShr, "Ada_LLVMBuildLShr"); - pragma Import (C, LLVMBuildAShr, "Ada_LLVMBuildAShr"); - pragma Import (C, LLVMBuildAnd, "Ada_LLVMBuildAnd"); - pragma Import (C, LLVMBuildOr, "Ada_LLVMBuildOr"); - pragma Import (C, LLVMBuildXor, "Ada_LLVMBuildXor"); - pragma Import (C, LLVMBuildNeg, "Ada_LLVMBuildNeg"); - pragma Import (C, LLVMBuildNot, "Ada_LLVMBuildNot"); - pragma Import (C, LLVMBuildMalloc, "Ada_LLVMBuildMalloc"); - pragma Import (C, LLVMBuildArrayMalloc, "Ada_LLVMBuildArrayMalloc"); - pragma Import (C, LLVMBuildAlloca, "Ada_LLVMBuildAlloca"); - pragma Import (C, LLVMBuildArrayAlloca, "Ada_LLVMBuildArrayAlloca"); - pragma Import (C, LLVMBuildFree, "Ada_LLVMBuildFree"); - pragma Import (C, LLVMBuildLoad, "Ada_LLVMBuildLoad"); - pragma Import (C, LLVMBuildStore, "Ada_LLVMBuildStore"); - pragma Import (C, LLVMBuildGEP, "Ada_LLVMBuildGEP"); - pragma Import (C, LLVMBuildTrunc, "Ada_LLVMBuildTrunc"); - pragma Import (C, LLVMBuildZExt, "Ada_LLVMBuildZExt"); - pragma Import (C, LLVMBuildSExt, "Ada_LLVMBuildSExt"); - pragma Import (C, LLVMBuildFPToUI, "Ada_LLVMBuildFPToUI"); - pragma Import (C, LLVMBuildFPToSI, "Ada_LLVMBuildFPToSI"); - pragma Import (C, LLVMBuildUIToFP, "Ada_LLVMBuildUIToFP"); - pragma Import (C, LLVMBuildSIToFP, "Ada_LLVMBuildSIToFP"); - pragma Import (C, LLVMBuildFPTrunc, "Ada_LLVMBuildFPTrunc"); - pragma Import (C, LLVMBuildFPExt, "Ada_LLVMBuildFPExt"); - pragma Import (C, LLVMBuildPtrToInt, "Ada_LLVMBuildPtrToInt"); - pragma Import (C, LLVMBuildIntToPtr, "Ada_LLVMBuildIntToPtr"); - pragma Import (C, LLVMBuildBitCast, "Ada_LLVMBuildBitCast"); - pragma Import (C, LLVMBuildICmp, "Ada_LLVMBuildICmp"); - pragma Import (C, LLVMBuildFCmp, "Ada_LLVMBuildFCmp"); - pragma Import (C, LLVMBuildPhi, "Ada_LLVMBuildPhi"); - pragma Import (C, LLVMBuildCall, "Ada_LLVMBuildCall"); - pragma Import (C, LLVMBuildSelect, "Ada_LLVMBuildSelect"); - pragma Import (C, LLVMBuildVAArg, "Ada_LLVMBuildVAArg"); - pragma Import (C, LLVMBuildExtractElement, "Ada_LLVMBuildExtractElement"); - pragma Import (C, LLVMBuildInsertElement, "Ada_LLVMBuildInsertElement"); - pragma Import (C, LLVMBuildShuffleVector, "Ada_LLVMBuildShuffleVector"); - pragma Import (C, LLVMBuildExtractValue, "Ada_LLVMBuildExtractValue"); - pragma Import (C, LLVMBuildInsertValue, "Ada_LLVMBuildInsertValue"); - pragma Import - (C, - LLVMCreateModuleProviderForExistingModule, - "Ada_LLVMCreateModuleProviderForExistingModule"); - pragma Import - (C, - LLVMDisposeModuleProvider, - "Ada_LLVMDisposeModuleProvider"); - pragma Import - (C, - LLVMCreateMemoryBufferWithContentsOfFile, - "Ada_LLVMCreateMemoryBufferWithContentsOfFile"); - pragma Import - (C, - LLVMCreateMemoryBufferWithSTDIN, - "Ada_LLVMCreateMemoryBufferWithSTDIN"); - pragma Import (C, LLVMDisposeMemoryBuffer, "Ada_LLVMDisposeMemoryBuffer"); - pragma Import (C, LLVMCreatePassManager, "Ada_LLVMCreatePassManager"); - pragma Import - (C, - LLVMCreateFunctionPassManager, - "Ada_LLVMCreateFunctionPassManager"); - pragma Import (C, LLVMRunPassManager, "Ada_LLVMRunPassManager"); - pragma Import - (C, - LLVMInitializeFunctionPassManager, - "Ada_LLVMInitializeFunctionPassManager"); - pragma Import - (C, - LLVMRunFunctionPassManager, - "Ada_LLVMRunFunctionPassManager"); - pragma Import - (C, - LLVMFinalizeFunctionPassManager, - "Ada_LLVMFinalizeFunctionPassManager"); - pragma Import (C, LLVMDisposePassManager, "Ada_LLVMDisposePassManager"); - -end llvm.Binding; diff --git a/bindings/ada/llvm/llvm.ads b/bindings/ada/llvm/llvm.ads deleted file mode 100644 index 20fc940f8c24..000000000000 --- a/bindings/ada/llvm/llvm.ads +++ /dev/null @@ -1,497 +0,0 @@ --- This file is generated by SWIG. Do *not* modify by hand. --- - -with Interfaces.C.Extensions; - - -package llvm is - - -- LLVMCtxt - -- - type LLVMCtxt is new Interfaces.C.Extensions.opaque_structure_def; - - type LLVMCtxt_array is - array (Interfaces.C.size_t range <>) of aliased llvm.LLVMCtxt; - - type LLVMCtxt_view is access all llvm.LLVMCtxt; - - -- LLVMContextRef - -- - type LLVMContextRef is access all llvm.LLVMCtxt; - - type LLVMContextRef_array is - array (Interfaces.C.size_t range <>) of aliased llvm.LLVMContextRef; - - type LLVMContextRef_view is access all llvm.LLVMContextRef; - - -- LLVMOpaqueModule - -- - type LLVMOpaqueModule is new Interfaces.C.Extensions.opaque_structure_def; - - type LLVMOpaqueModule_array is - array (Interfaces.C.size_t range <>) of aliased llvm.LLVMOpaqueModule; - - type LLVMOpaqueModule_view is access all llvm.LLVMOpaqueModule; - - -- LLVMModuleRef - -- - type LLVMModuleRef is access all llvm.LLVMOpaqueModule; - - type LLVMModuleRef_array is - array (Interfaces.C.size_t range <>) of aliased llvm.LLVMModuleRef; - - type LLVMModuleRef_view is access all llvm.LLVMModuleRef; - - -- LLVMOpaqueType - -- - type LLVMOpaqueType is new Interfaces.C.Extensions.opaque_structure_def; - - type LLVMOpaqueType_array is - array (Interfaces.C.size_t range <>) of aliased llvm.LLVMOpaqueType; - - type LLVMOpaqueType_view is access all llvm.LLVMOpaqueType; - - -- LLVMTypeRef - -- - type LLVMTypeRef is access all llvm.LLVMOpaqueType; - - type LLVMTypeRef_array is - array (Interfaces.C.size_t range <>) of aliased llvm.LLVMTypeRef; - - type LLVMTypeRef_view is access all llvm.LLVMTypeRef; - - -- LLVMOpaqueTypeHandle - -- - type LLVMOpaqueTypeHandle is new - Interfaces.C.Extensions.opaque_structure_def; - - type LLVMOpaqueTypeHandle_array is - array (Interfaces.C.size_t range <>) - of aliased llvm.LLVMOpaqueTypeHandle; - - type LLVMOpaqueTypeHandle_view is access all llvm.LLVMOpaqueTypeHandle; - - -- LLVMTypeHandleRef - -- - type LLVMTypeHandleRef is access all llvm.LLVMOpaqueTypeHandle; - - type LLVMTypeHandleRef_array is - array (Interfaces.C.size_t range <>) - of aliased llvm.LLVMTypeHandleRef; - - type LLVMTypeHandleRef_view is access all llvm.LLVMTypeHandleRef; - - -- LLVMOpaqueValue - -- - type LLVMOpaqueValue is new Interfaces.C.Extensions.opaque_structure_def; - - type LLVMOpaqueValue_array is - array (Interfaces.C.size_t range <>) of aliased llvm.LLVMOpaqueValue; - - type LLVMOpaqueValue_view is access all llvm.LLVMOpaqueValue; - - -- LLVMValueRef - -- - type LLVMValueRef is access all llvm.LLVMOpaqueValue; - - type LLVMValueRef_array is - array (Interfaces.C.size_t range <>) of aliased llvm.LLVMValueRef; - - type LLVMValueRef_view is access all llvm.LLVMValueRef; - - -- LLVMOpaqueBasicBlock - -- - type LLVMOpaqueBasicBlock is new - Interfaces.C.Extensions.opaque_structure_def; - - type LLVMOpaqueBasicBlock_array is - array (Interfaces.C.size_t range <>) - of aliased llvm.LLVMOpaqueBasicBlock; - - type LLVMOpaqueBasicBlock_view is access all llvm.LLVMOpaqueBasicBlock; - - -- LLVMBasicBlockRef - -- - type LLVMBasicBlockRef is access all llvm.LLVMOpaqueBasicBlock; - - type LLVMBasicBlockRef_array is - array (Interfaces.C.size_t range <>) - of aliased llvm.LLVMBasicBlockRef; - - type LLVMBasicBlockRef_view is access all llvm.LLVMBasicBlockRef; - - -- LLVMOpaqueBuilder - -- - type LLVMOpaqueBuilder is new Interfaces.C.Extensions.opaque_structure_def; - - type LLVMOpaqueBuilder_array is - array (Interfaces.C.size_t range <>) - of aliased llvm.LLVMOpaqueBuilder; - - type LLVMOpaqueBuilder_view is access all llvm.LLVMOpaqueBuilder; - - -- LLVMBuilderRef - -- - type LLVMBuilderRef is access all llvm.LLVMOpaqueBuilder; - - type LLVMBuilderRef_array is - array (Interfaces.C.size_t range <>) of aliased llvm.LLVMBuilderRef; - - type LLVMBuilderRef_view is access all llvm.LLVMBuilderRef; - - -- LLVMOpaqueModuleProvider - -- - type LLVMOpaqueModuleProvider is new - Interfaces.C.Extensions.opaque_structure_def; - - type LLVMOpaqueModuleProvider_array is - array (Interfaces.C.size_t range <>) - of aliased llvm.LLVMOpaqueModuleProvider; - - type LLVMOpaqueModuleProvider_view is access all - llvm.LLVMOpaqueModuleProvider; - - -- LLVMModuleProviderRef - -- - type LLVMModuleProviderRef is access all llvm.LLVMOpaqueModuleProvider; - - type LLVMModuleProviderRef_array is - array (Interfaces.C.size_t range <>) - of aliased llvm.LLVMModuleProviderRef; - - type LLVMModuleProviderRef_view is access all llvm.LLVMModuleProviderRef; - - -- LLVMOpaqueMemoryBuffer - -- - type LLVMOpaqueMemoryBuffer is new - Interfaces.C.Extensions.opaque_structure_def; - - type LLVMOpaqueMemoryBuffer_array is - array (Interfaces.C.size_t range <>) - of aliased llvm.LLVMOpaqueMemoryBuffer; - - type LLVMOpaqueMemoryBuffer_view is access all llvm.LLVMOpaqueMemoryBuffer; - - -- LLVMMemoryBufferRef - -- - type LLVMMemoryBufferRef is access all llvm.LLVMOpaqueMemoryBuffer; - - type LLVMMemoryBufferRef_array is - array (Interfaces.C.size_t range <>) - of aliased llvm.LLVMMemoryBufferRef; - - type LLVMMemoryBufferRef_view is access all llvm.LLVMMemoryBufferRef; - - -- LLVMOpaquePassManager - -- - type LLVMOpaquePassManager is new - Interfaces.C.Extensions.opaque_structure_def; - - type LLVMOpaquePassManager_array is - array (Interfaces.C.size_t range <>) - of aliased llvm.LLVMOpaquePassManager; - - type LLVMOpaquePassManager_view is access all llvm.LLVMOpaquePassManager; - - -- LLVMPassManagerRef - -- - type LLVMPassManagerRef is access all llvm.LLVMOpaquePassManager; - - type LLVMPassManagerRef_array is - array (Interfaces.C.size_t range <>) - of aliased llvm.LLVMPassManagerRef; - - type LLVMPassManagerRef_view is access all llvm.LLVMPassManagerRef; - - -- LLVMAttribute - -- - type LLVMAttribute is ( - LLVMZExtAttribute, - LLVMSExtAttribute, - LLVMNoReturnAttribute, - LLVMInRegAttribute, - LLVMStructRetAttribute, - LLVMNoUnwindAttribute, - LLVMNoAliasAttribute, - LLVMByValAttribute, - LLVMNestAttribute, - LLVMReadNoneAttribute, - LLVMReadOnlyAttribute, - LLVMNoInlineAttribute, - LLVMAlwaysInlineAttribute, - LLVMOptimizeForSizeAttribute, - LLVMStackProtectAttribute, - LLVMStackProtectReqAttribute, - LLVMNoCaptureAttribute, - LLVMNoRedZoneAttribute, - LLVMNoImplicitFloatAttribute, - LLVMNakedAttribute); - - for LLVMAttribute use - (LLVMZExtAttribute => 1, - LLVMSExtAttribute => 2, - LLVMNoReturnAttribute => 4, - LLVMInRegAttribute => 8, - LLVMStructRetAttribute => 16, - LLVMNoUnwindAttribute => 32, - LLVMNoAliasAttribute => 64, - LLVMByValAttribute => 128, - LLVMNestAttribute => 256, - LLVMReadNoneAttribute => 512, - LLVMReadOnlyAttribute => 1024, - LLVMNoInlineAttribute => 2048, - LLVMAlwaysInlineAttribute => 4096, - LLVMOptimizeForSizeAttribute => 8192, - LLVMStackProtectAttribute => 16384, - LLVMStackProtectReqAttribute => 32768, - LLVMNoCaptureAttribute => 2097152, - LLVMNoRedZoneAttribute => 4194304, - LLVMNoImplicitFloatAttribute => 8388608, - LLVMNakedAttribute => 16777216); - - pragma Convention (C, LLVMAttribute); - - type LLVMAttribute_array is - array (Interfaces.C.size_t range <>) of aliased llvm.LLVMAttribute; - - type LLVMAttribute_view is access all llvm.LLVMAttribute; - - -- LLVMTypeKind - -- - type LLVMTypeKind is ( - LLVMVoidTypeKind, - LLVMFloatTypeKind, - LLVMDoubleTypeKind, - LLVMX86_FP80TypeKind, - LLVMFP128TypeKind, - LLVMPPC_FP128TypeKind, - LLVMLabelTypeKind, - LLVMIntegerTypeKind, - LLVMFunctionTypeKind, - LLVMStructTypeKind, - LLVMArrayTypeKind, - LLVMPointerTypeKind, - LLVMOpaqueTypeKind, - LLVMVectorTypeKind, - LLVMMetadataTypeKind); - - for LLVMTypeKind use - (LLVMVoidTypeKind => 0, - LLVMFloatTypeKind => 1, - LLVMDoubleTypeKind => 2, - LLVMX86_FP80TypeKind => 3, - LLVMFP128TypeKind => 4, - LLVMPPC_FP128TypeKind => 5, - LLVMLabelTypeKind => 6, - LLVMIntegerTypeKind => 7, - LLVMFunctionTypeKind => 8, - LLVMStructTypeKind => 9, - LLVMArrayTypeKind => 10, - LLVMPointerTypeKind => 11, - LLVMOpaqueTypeKind => 12, - LLVMVectorTypeKind => 13, - LLVMMetadataTypeKind => 14); - - pragma Convention (C, LLVMTypeKind); - - type LLVMTypeKind_array is - array (Interfaces.C.size_t range <>) of aliased llvm.LLVMTypeKind; - - type LLVMTypeKind_view is access all llvm.LLVMTypeKind; - - -- LLVMLinkage - -- - type LLVMLinkage is ( - LLVMExternalLinkage, - LLVMAvailableExternallyLinkage, - LLVMLinkOnceAnyLinkage, - LLVMLinkOnceODRLinkage, - LLVMWeakAnyLinkage, - LLVMWeakODRLinkage, - LLVMAppendingLinkage, - LLVMInternalLinkage, - LLVMPrivateLinkage, - LLVMDLLImportLinkage, - LLVMDLLExportLinkage, - LLVMExternalWeakLinkage, - LLVMGhostLinkage, - LLVMCommonLinkage, - LLVMLinkerPrivateLinkage, - LLVMLinkerPrivateWeakLinkage, - LinkerPrivateWeakDefAutoLinkage); - - for LLVMLinkage use - (LLVMExternalLinkage => 0, - LLVMAvailableExternallyLinkage => 1, - LLVMLinkOnceAnyLinkage => 2, - LLVMLinkOnceODRLinkage => 3, - LLVMWeakAnyLinkage => 4, - LLVMWeakODRLinkage => 5, - LLVMAppendingLinkage => 6, - LLVMInternalLinkage => 7, - LLVMPrivateLinkage => 8, - LLVMDLLImportLinkage => 9, - LLVMDLLExportLinkage => 10, - LLVMExternalWeakLinkage => 11, - LLVMGhostLinkage => 12, - LLVMCommonLinkage => 13, - LLVMLinkerPrivateLinkage => 14, - LLVMLinkerPrivateWeakLinkage => 15, - LinkerPrivateWeakDefAutoLinkage => 16); - - pragma Convention (C, LLVMLinkage); - - type LLVMLinkage_array is - array (Interfaces.C.size_t range <>) of aliased llvm.LLVMLinkage; - - type LLVMLinkage_view is access all llvm.LLVMLinkage; - - -- LLVMVisibility - -- - type LLVMVisibility is ( - LLVMDefaultVisibility, - LLVMHiddenVisibility, - LLVMProtectedVisibility); - - for LLVMVisibility use - (LLVMDefaultVisibility => 0, - LLVMHiddenVisibility => 1, - LLVMProtectedVisibility => 2); - - pragma Convention (C, LLVMVisibility); - - type LLVMVisibility_array is - array (Interfaces.C.size_t range <>) of aliased llvm.LLVMVisibility; - - type LLVMVisibility_view is access all llvm.LLVMVisibility; - - -- LLVMCallConv - -- - type LLVMCallConv is ( - LLVMCCallConv, - LLVMFastCallConv, - LLVMColdCallConv, - LLVMX86StdcallCallConv, - LLVMX86FastcallCallConv); - - for LLVMCallConv use - (LLVMCCallConv => 0, - LLVMFastCallConv => 8, - LLVMColdCallConv => 9, - LLVMX86StdcallCallConv => 64, - LLVMX86FastcallCallConv => 65); - - pragma Convention (C, LLVMCallConv); - - type LLVMCallConv_array is - array (Interfaces.C.size_t range <>) of aliased llvm.LLVMCallConv; - - type LLVMCallConv_view is access all llvm.LLVMCallConv; - - -- LLVMIntPredicate - -- - type LLVMIntPredicate is ( - LLVMIntEQ, - LLVMIntNE, - LLVMIntUGT, - LLVMIntUGE, - LLVMIntULT, - LLVMIntULE, - LLVMIntSGT, - LLVMIntSGE, - LLVMIntSLT, - LLVMIntSLE); - - for LLVMIntPredicate use - (LLVMIntEQ => 32, - LLVMIntNE => 33, - LLVMIntUGT => 34, - LLVMIntUGE => 35, - LLVMIntULT => 36, - LLVMIntULE => 37, - LLVMIntSGT => 38, - LLVMIntSGE => 39, - LLVMIntSLT => 40, - LLVMIntSLE => 41); - - pragma Convention (C, LLVMIntPredicate); - - type LLVMIntPredicate_array is - array (Interfaces.C.size_t range <>) of aliased llvm.LLVMIntPredicate; - - type LLVMIntPredicate_view is access all llvm.LLVMIntPredicate; - - -- LLVMRealPredicate - -- - type LLVMRealPredicate is ( - LLVMRealPredicateFalse, - LLVMRealOEQ, - LLVMRealOGT, - LLVMRealOGE, - LLVMRealOLT, - LLVMRealOLE, - LLVMRealONE, - LLVMRealORD, - LLVMRealUNO, - LLVMRealUEQ, - LLVMRealUGT, - LLVMRealUGE, - LLVMRealULT, - LLVMRealULE, - LLVMRealUNE, - LLVMRealPredicateTrue); - - for LLVMRealPredicate use - (LLVMRealPredicateFalse => 0, - LLVMRealOEQ => 1, - LLVMRealOGT => 2, - LLVMRealOGE => 3, - LLVMRealOLT => 4, - LLVMRealOLE => 5, - LLVMRealONE => 6, - LLVMRealORD => 7, - LLVMRealUNO => 8, - LLVMRealUEQ => 9, - LLVMRealUGT => 10, - LLVMRealUGE => 11, - LLVMRealULT => 12, - LLVMRealULE => 13, - LLVMRealUNE => 14, - LLVMRealPredicateTrue => 15); - - pragma Convention (C, LLVMRealPredicate); - - type LLVMRealPredicate_array is - array (Interfaces.C.size_t range <>) - of aliased llvm.LLVMRealPredicate; - - type LLVMRealPredicate_view is access all llvm.LLVMRealPredicate; - - -- ModuleProvider - -- - type ModuleProvider is new Interfaces.C.Extensions.incomplete_class_def; - - type ModuleProvider_array is - array (Interfaces.C.size_t range <>) of aliased llvm.ModuleProvider; - - type ModuleProvider_view is access all llvm.ModuleProvider; - - -- MemoryBuffer - -- - type MemoryBuffer is new Interfaces.C.Extensions.incomplete_class_def; - - type MemoryBuffer_array is - array (Interfaces.C.size_t range <>) of aliased llvm.MemoryBuffer; - - type MemoryBuffer_view is access all llvm.MemoryBuffer; - - -- PassManagerBase - -- - type PassManagerBase is new Interfaces.C.Extensions.incomplete_class_def; - - type PassManagerBase_array is - array (Interfaces.C.size_t range <>) of aliased llvm.PassManagerBase; - - type PassManagerBase_view is access all llvm.PassManagerBase; - -end llvm; diff --git a/bindings/ada/llvm/llvm_link_time_optimizer-binding.ads b/bindings/ada/llvm/llvm_link_time_optimizer-binding.ads deleted file mode 100644 index 7c0b086b4282..000000000000 --- a/bindings/ada/llvm/llvm_link_time_optimizer-binding.ads +++ /dev/null @@ -1,207 +0,0 @@ --- This file is generated by SWIG. Do *not* modify by hand. --- - -with Interfaces.C.Strings; - - -package LLVM_link_time_Optimizer.Binding is - - LTO_H : constant := 1; - LTO_API_VERSION : constant := 3; - - function lto_get_version return Interfaces.C.Strings.chars_ptr; - - function lto_get_error_message return Interfaces.C.Strings.chars_ptr; - - function lto_module_is_object_file - (path : in Interfaces.C.Strings.chars_ptr) - return Interfaces.C.Extensions.bool; - - function lto_module_is_object_file_for_target - (path : in Interfaces.C.Strings.chars_ptr; - target_triple_prefix : in Interfaces.C.Strings.chars_ptr) - return Interfaces.C.Extensions.bool; - - function lto_module_is_object_file_in_memory - (mem : access Interfaces.C.Extensions.void; - length : in Interfaces.C.size_t) - return Interfaces.C.Extensions.bool; - - function lto_module_is_object_file_in_memory_for_target - (mem : access Interfaces.C.Extensions.void; - length : in Interfaces.C.size_t; - target_triple_prefix : in Interfaces.C.Strings.chars_ptr) - return Interfaces.C.Extensions.bool; - - function lto_module_create - (path : in Interfaces.C.Strings.chars_ptr) - return LLVM_link_time_Optimizer.lto_module_t; - - function lto_module_create_from_memory - (mem : access Interfaces.C.Extensions.void; - length : in Interfaces.C.size_t) - return LLVM_link_time_Optimizer.lto_module_t; - - procedure lto_module_dispose - (the_mod : in LLVM_link_time_Optimizer.lto_module_t); - - function lto_module_get_target_triple - (the_mod : in LLVM_link_time_Optimizer.lto_module_t) - return Interfaces.C.Strings.chars_ptr; - - function lto_module_get_num_symbols - (the_mod : in LLVM_link_time_Optimizer.lto_module_t) - return Interfaces.C.unsigned; - - function lto_module_get_symbol_name - (the_mod : in LLVM_link_time_Optimizer.lto_module_t; - index : in Interfaces.C.unsigned) - return Interfaces.C.Strings.chars_ptr; - - function lto_module_get_symbol_attribute - (the_mod : in LLVM_link_time_Optimizer.lto_module_t; - index : in Interfaces.C.unsigned) - return LLVM_link_time_Optimizer.lto_symbol_attributes; - - function lto_codegen_create return LLVM_link_time_Optimizer.lto_code_gen_t; - - procedure lto_codegen_dispose - (arg_1 : in LLVM_link_time_Optimizer.lto_code_gen_t); - - function lto_codegen_add_module - (cg : in LLVM_link_time_Optimizer.lto_code_gen_t; - the_mod : in LLVM_link_time_Optimizer.lto_module_t) - return Interfaces.C.Extensions.bool; - - function lto_codegen_set_debug_model - (cg : in LLVM_link_time_Optimizer.lto_code_gen_t; - arg_1 : in LLVM_link_time_Optimizer.lto_debug_model) - return Interfaces.C.Extensions.bool; - - function lto_codegen_set_pic_model - (cg : in LLVM_link_time_Optimizer.lto_code_gen_t; - arg_1 : in LLVM_link_time_Optimizer.lto_codegen_model) - return Interfaces.C.Extensions.bool; - - procedure lto_codegen_set_gcc_path - (cg : in LLVM_link_time_Optimizer.lto_code_gen_t; - path : in Interfaces.C.Strings.chars_ptr); - - procedure lto_codegen_set_assembler_path - (cg : in LLVM_link_time_Optimizer.lto_code_gen_t; - path : in Interfaces.C.Strings.chars_ptr); - - procedure lto_codegen_add_must_preserve_symbol - (cg : in LLVM_link_time_Optimizer.lto_code_gen_t; - symbol : in Interfaces.C.Strings.chars_ptr); - - function lto_codegen_write_merged_modules - (cg : in LLVM_link_time_Optimizer.lto_code_gen_t; - path : in Interfaces.C.Strings.chars_ptr) - return Interfaces.C.Extensions.bool; - - function lto_codegen_compile - (cg : in LLVM_link_time_Optimizer.lto_code_gen_t; - length : access Interfaces.C.size_t) - return access Interfaces.C.Extensions.void; - - procedure lto_codegen_debug_options - (cg : in LLVM_link_time_Optimizer.lto_code_gen_t; - arg_1 : in Interfaces.C.Strings.chars_ptr); - - function llvm_create_optimizer return - LLVM_link_time_Optimizer.llvm_lto_t; - - procedure llvm_destroy_optimizer - (lto : in LLVM_link_time_Optimizer.llvm_lto_t); - - function llvm_read_object_file - (lto : in LLVM_link_time_Optimizer.llvm_lto_t; - input_filename : in Interfaces.C.Strings.chars_ptr) - return LLVM_link_time_Optimizer.llvm_lto_status_t; - - function llvm_optimize_modules - (lto : in LLVM_link_time_Optimizer.llvm_lto_t; - output_filename : in Interfaces.C.Strings.chars_ptr) - return LLVM_link_time_Optimizer.llvm_lto_status_t; - -private - - pragma Import (C, lto_get_version, "Ada_lto_get_version"); - pragma Import (C, lto_get_error_message, "Ada_lto_get_error_message"); - pragma Import - (C, - lto_module_is_object_file, - "Ada_lto_module_is_object_file"); - pragma Import - (C, - lto_module_is_object_file_for_target, - "Ada_lto_module_is_object_file_for_target"); - pragma Import - (C, - lto_module_is_object_file_in_memory, - "Ada_lto_module_is_object_file_in_memory"); - pragma Import - (C, - lto_module_is_object_file_in_memory_for_target, - "Ada_lto_module_is_object_file_in_memory_for_target"); - pragma Import (C, lto_module_create, "Ada_lto_module_create"); - pragma Import - (C, - lto_module_create_from_memory, - "Ada_lto_module_create_from_memory"); - pragma Import (C, lto_module_dispose, "Ada_lto_module_dispose"); - pragma Import - (C, - lto_module_get_target_triple, - "Ada_lto_module_get_target_triple"); - pragma Import - (C, - lto_module_get_num_symbols, - "Ada_lto_module_get_num_symbols"); - pragma Import - (C, - lto_module_get_symbol_name, - "Ada_lto_module_get_symbol_name"); - pragma Import - (C, - lto_module_get_symbol_attribute, - "Ada_lto_module_get_symbol_attribute"); - pragma Import (C, lto_codegen_create, "Ada_lto_codegen_create"); - pragma Import (C, lto_codegen_dispose, "Ada_lto_codegen_dispose"); - pragma Import (C, lto_codegen_add_module, "Ada_lto_codegen_add_module"); - pragma Import - (C, - lto_codegen_set_debug_model, - "Ada_lto_codegen_set_debug_model"); - pragma Import - (C, - lto_codegen_set_pic_model, - "Ada_lto_codegen_set_pic_model"); - pragma Import - (C, - lto_codegen_set_gcc_path, - "Ada_lto_codegen_set_gcc_path"); - pragma Import - (C, - lto_codegen_set_assembler_path, - "Ada_lto_codegen_set_assembler_path"); - pragma Import - (C, - lto_codegen_add_must_preserve_symbol, - "Ada_lto_codegen_add_must_preserve_symbol"); - pragma Import - (C, - lto_codegen_write_merged_modules, - "Ada_lto_codegen_write_merged_modules"); - pragma Import (C, lto_codegen_compile, "Ada_lto_codegen_compile"); - pragma Import - (C, - lto_codegen_debug_options, - "Ada_lto_codegen_debug_options"); - pragma Import (C, llvm_create_optimizer, "Ada_llvm_create_optimizer"); - pragma Import (C, llvm_destroy_optimizer, "Ada_llvm_destroy_optimizer"); - pragma Import (C, llvm_read_object_file, "Ada_llvm_read_object_file"); - pragma Import (C, llvm_optimize_modules, "Ada_llvm_optimize_modules"); - -end LLVM_link_time_Optimizer.Binding; diff --git a/bindings/ada/llvm/llvm_link_time_optimizer.ads b/bindings/ada/llvm/llvm_link_time_optimizer.ads deleted file mode 100644 index c27f7c5893b6..000000000000 --- a/bindings/ada/llvm/llvm_link_time_optimizer.ads +++ /dev/null @@ -1,184 +0,0 @@ --- This file is generated by SWIG. Do *not* modify by hand. --- - -with Interfaces.C.Extensions; - - -package LLVM_link_time_Optimizer is - - -- lto_symbol_attributes - -- - type lto_symbol_attributes is ( - LTO_SYMBOL_ALIGNMENT_MASK, - LTO_SYMBOL_PERMISSIONS_RODATA, - LTO_SYMBOL_PERMISSIONS_CODE, - LTO_SYMBOL_PERMISSIONS_DATA, - LTO_SYMBOL_PERMISSIONS_MASK, - LTO_SYMBOL_DEFINITION_REGULAR, - LTO_SYMBOL_DEFINITION_TENTATIVE, - LTO_SYMBOL_DEFINITION_WEAK, - LTO_SYMBOL_DEFINITION_UNDEFINED, - LTO_SYMBOL_DEFINITION_WEAKUNDEF, - LTO_SYMBOL_DEFINITION_MASK, - LTO_SYMBOL_SCOPE_INTERNAL, - LTO_SYMBOL_SCOPE_HIDDEN, - LTO_SYMBOL_SCOPE_DEFAULT, - LTO_SYMBOL_SCOPE_PROTECTED, - LTO_SYMBOL_SCOPE_MASK); - - for lto_symbol_attributes use - (LTO_SYMBOL_ALIGNMENT_MASK => 31, - LTO_SYMBOL_PERMISSIONS_RODATA => 128, - LTO_SYMBOL_PERMISSIONS_CODE => 160, - LTO_SYMBOL_PERMISSIONS_DATA => 192, - LTO_SYMBOL_PERMISSIONS_MASK => 224, - LTO_SYMBOL_DEFINITION_REGULAR => 256, - LTO_SYMBOL_DEFINITION_TENTATIVE => 512, - LTO_SYMBOL_DEFINITION_WEAK => 768, - LTO_SYMBOL_DEFINITION_UNDEFINED => 1024, - LTO_SYMBOL_DEFINITION_WEAKUNDEF => 1280, - LTO_SYMBOL_DEFINITION_MASK => 1792, - LTO_SYMBOL_SCOPE_INTERNAL => 2048, - LTO_SYMBOL_SCOPE_HIDDEN => 4096, - LTO_SYMBOL_SCOPE_DEFAULT => 6144, - LTO_SYMBOL_SCOPE_PROTECTED => 8192, - LTO_SYMBOL_SCOPE_MASK => 14336); - - pragma Convention (C, lto_symbol_attributes); - - type lto_symbol_attributes_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_link_time_Optimizer.lto_symbol_attributes; - - type lto_symbol_attributes_view is access all - LLVM_link_time_Optimizer.lto_symbol_attributes; - - -- lto_debug_model - -- - type lto_debug_model is (LTO_DEBUG_MODEL_NONE, LTO_DEBUG_MODEL_DWARF); - - for lto_debug_model use - (LTO_DEBUG_MODEL_NONE => 0, - LTO_DEBUG_MODEL_DWARF => 1); - - pragma Convention (C, lto_debug_model); - - type lto_debug_model_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_link_time_Optimizer.lto_debug_model; - - type lto_debug_model_view is access all - LLVM_link_time_Optimizer.lto_debug_model; - - -- lto_codegen_model - -- - type lto_codegen_model is ( - LTO_CODEGEN_PIC_MODEL_STATIC, - LTO_CODEGEN_PIC_MODEL_DYNAMIC, - LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC); - - for lto_codegen_model use - (LTO_CODEGEN_PIC_MODEL_STATIC => 0, - LTO_CODEGEN_PIC_MODEL_DYNAMIC => 1, - LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC => 2); - - pragma Convention (C, lto_codegen_model); - - type lto_codegen_model_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_link_time_Optimizer.lto_codegen_model; - - type lto_codegen_model_view is access all - LLVM_link_time_Optimizer.lto_codegen_model; - - -- LTOModule - -- - type LTOModule is new Interfaces.C.Extensions.opaque_structure_def; - - type LTOModule_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_link_time_Optimizer.LTOModule; - - type LTOModule_view is access all LLVM_link_time_Optimizer.LTOModule; - - -- lto_module_t - -- - type lto_module_t is access all LLVM_link_time_Optimizer.LTOModule; - - type lto_module_t_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_link_time_Optimizer.lto_module_t; - - type lto_module_t_view is access all LLVM_link_time_Optimizer.lto_module_t; - - -- LTOCodeGenerator - -- - type LTOCodeGenerator is new Interfaces.C.Extensions.opaque_structure_def; - - type LTOCodeGenerator_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_link_time_Optimizer.LTOCodeGenerator; - - type LTOCodeGenerator_view is access all - LLVM_link_time_Optimizer.LTOCodeGenerator; - - -- lto_code_gen_t - -- - type lto_code_gen_t is access all LLVM_link_time_Optimizer.LTOCodeGenerator; - - type lto_code_gen_t_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_link_time_Optimizer.lto_code_gen_t; - - type lto_code_gen_t_view is access all - LLVM_link_time_Optimizer.lto_code_gen_t; - - -- llvm_lto_status_t - -- - type llvm_lto_status_t is ( - LLVM_LTO_UNKNOWN, - LLVM_LTO_OPT_SUCCESS, - LLVM_LTO_READ_SUCCESS, - LLVM_LTO_READ_FAILURE, - LLVM_LTO_WRITE_FAILURE, - LLVM_LTO_NO_TARGET, - LLVM_LTO_NO_WORK, - LLVM_LTO_MODULE_MERGE_FAILURE, - LLVM_LTO_ASM_FAILURE, - LLVM_LTO_NULL_OBJECT); - - for llvm_lto_status_t use - (LLVM_LTO_UNKNOWN => 0, - LLVM_LTO_OPT_SUCCESS => 1, - LLVM_LTO_READ_SUCCESS => 2, - LLVM_LTO_READ_FAILURE => 3, - LLVM_LTO_WRITE_FAILURE => 4, - LLVM_LTO_NO_TARGET => 5, - LLVM_LTO_NO_WORK => 6, - LLVM_LTO_MODULE_MERGE_FAILURE => 7, - LLVM_LTO_ASM_FAILURE => 8, - LLVM_LTO_NULL_OBJECT => 9); - - pragma Convention (C, llvm_lto_status_t); - - type llvm_lto_status_t_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_link_time_Optimizer.llvm_lto_status_t; - - type llvm_lto_status_t_view is access all - LLVM_link_time_Optimizer.llvm_lto_status_t; - - - -- llvm_lto_t - -- - type llvm_lto_t is access all Interfaces.C.Extensions.void; - - type llvm_lto_t_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_link_time_Optimizer.llvm_lto_t; - - type llvm_lto_t_view is access all - LLVM_link_time_Optimizer.llvm_lto_t; - - -end LLVM_link_time_Optimizer; diff --git a/bindings/ada/llvm/llvm_linktimeoptimizer_wrap.cxx b/bindings/ada/llvm/llvm_linktimeoptimizer_wrap.cxx deleted file mode 100644 index eb2e7ab15633..000000000000 --- a/bindings/ada/llvm/llvm_linktimeoptimizer_wrap.cxx +++ /dev/null @@ -1,923 +0,0 @@ -/* ---------------------------------------------------------------------------- - * This file was automatically generated by SWIG (http://www.swig.org). - * Version 1.3.36 - * - * This file is not intended to be easily readable and contains a number of - * coding conventions designed to improve portability and efficiency. Do not make - * changes to this file unless you know what you are doing--modify the SWIG - * interface file instead. - * ----------------------------------------------------------------------------- */ - - -#ifdef __cplusplus -template class SwigValueWrapper { - T *tt; -public: - SwigValueWrapper() : tt(0) { } - SwigValueWrapper(const SwigValueWrapper& rhs) : tt(new T(*rhs.tt)) { } - SwigValueWrapper(const T& t) : tt(new T(t)) { } - ~SwigValueWrapper() { delete tt; } - SwigValueWrapper& operator=(const T& t) { delete tt; tt = new T(t); return *this; } - operator T&() const { return *tt; } - T *operator&() { return tt; } -private: - SwigValueWrapper& operator=(const SwigValueWrapper& rhs); -}; - -template T SwigValueInit() { - return T(); -} -#endif - -/* ----------------------------------------------------------------------------- - * This section contains generic SWIG labels for method/variable - * declarations/attributes, and other compiler dependent labels. - * ----------------------------------------------------------------------------- */ - -/* template workaround for compilers that cannot correctly implement the C++ standard */ -#ifndef SWIGTEMPLATEDISAMBIGUATOR -# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) -# define SWIGTEMPLATEDISAMBIGUATOR template -# elif defined(__HP_aCC) -/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ -/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ -# define SWIGTEMPLATEDISAMBIGUATOR template -# else -# define SWIGTEMPLATEDISAMBIGUATOR -# endif -#endif - -/* inline attribute */ -#ifndef SWIGINLINE -# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) -# define SWIGINLINE inline -# else -# define SWIGINLINE -# endif -#endif - -/* attribute recognised by some compilers to avoid 'unused' warnings */ -#ifndef SWIGUNUSED -# if defined(__GNUC__) -# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -# elif defined(__ICC) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -#endif - -#ifndef SWIGUNUSEDPARM -# ifdef __cplusplus -# define SWIGUNUSEDPARM(p) -# else -# define SWIGUNUSEDPARM(p) p SWIGUNUSED -# endif -#endif - -/* internal SWIG method */ -#ifndef SWIGINTERN -# define SWIGINTERN static SWIGUNUSED -#endif - -/* internal inline SWIG method */ -#ifndef SWIGINTERNINLINE -# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE -#endif - -/* exporting methods */ -#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -# ifndef GCC_HASCLASSVISIBILITY -# define GCC_HASCLASSVISIBILITY -# endif -#endif - -#ifndef SWIGEXPORT -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# if defined(STATIC_LINKED) -# define SWIGEXPORT -# else -# define SWIGEXPORT __declspec(dllexport) -# endif -# else -# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) -# define SWIGEXPORT __attribute__ ((visibility("default"))) -# else -# define SWIGEXPORT -# endif -# endif -#endif - -/* calling conventions for Windows */ -#ifndef SWIGSTDCALL -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# define SWIGSTDCALL __stdcall -# else -# define SWIGSTDCALL -# endif -#endif - -/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ -#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) -# define _CRT_SECURE_NO_DEPRECATE -#endif - -/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ -#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) -# define _SCL_SECURE_NO_DEPRECATE -#endif - - - -#include -#include -#include -#if defined(_WIN32) || defined(__CYGWIN32__) -# define DllExport __declspec( dllexport ) -# define SWIGSTDCALL __stdcall -#else -# define DllExport -# define SWIGSTDCALL -#endif - - -#ifdef __cplusplus -# include -#endif - - - - -/* Support for throwing Ada exceptions from C/C++ */ - -typedef enum -{ - SWIG_AdaException, - SWIG_AdaOutOfMemoryException, - SWIG_AdaIndexOutOfRangeException, - SWIG_AdaDivideByZeroException, - SWIG_AdaArgumentOutOfRangeException, - SWIG_AdaNullReferenceException -} SWIG_AdaExceptionCodes; - - -typedef void (SWIGSTDCALL* SWIG_AdaExceptionCallback_t)(const char *); - - -typedef struct -{ - SWIG_AdaExceptionCodes code; - SWIG_AdaExceptionCallback_t callback; -} - SWIG_AdaExceptions_t; - - -static -SWIG_AdaExceptions_t -SWIG_ada_exceptions[] = -{ - { SWIG_AdaException, NULL }, - { SWIG_AdaOutOfMemoryException, NULL }, - { SWIG_AdaIndexOutOfRangeException, NULL }, - { SWIG_AdaDivideByZeroException, NULL }, - { SWIG_AdaArgumentOutOfRangeException, NULL }, - { SWIG_AdaNullReferenceException, NULL } -}; - - -static -void -SWIG_AdaThrowException (SWIG_AdaExceptionCodes code, const char *msg) -{ - SWIG_AdaExceptionCallback_t callback = SWIG_ada_exceptions[SWIG_AdaException].callback; - if (code >=0 && (size_t)code < sizeof(SWIG_ada_exceptions)/sizeof(SWIG_AdaExceptions_t)) { - callback = SWIG_ada_exceptions[code].callback; - } - callback(msg); -} - - - -#ifdef __cplusplus -extern "C" -#endif - -DllExport void SWIGSTDCALL SWIGRegisterExceptionCallbacks_LLVM_link_time_Optimizer (SWIG_AdaExceptionCallback_t systemException, - SWIG_AdaExceptionCallback_t outOfMemory, - SWIG_AdaExceptionCallback_t indexOutOfRange, - SWIG_AdaExceptionCallback_t divideByZero, - SWIG_AdaExceptionCallback_t argumentOutOfRange, - SWIG_AdaExceptionCallback_t nullReference) -{ - SWIG_ada_exceptions [SWIG_AdaException].callback = systemException; - SWIG_ada_exceptions [SWIG_AdaOutOfMemoryException].callback = outOfMemory; - SWIG_ada_exceptions [SWIG_AdaIndexOutOfRangeException].callback = indexOutOfRange; - SWIG_ada_exceptions [SWIG_AdaDivideByZeroException].callback = divideByZero; - SWIG_ada_exceptions [SWIG_AdaArgumentOutOfRangeException].callback = argumentOutOfRange; - SWIG_ada_exceptions [SWIG_AdaNullReferenceException].callback = nullReference; -} - - -/* Callback for returning strings to Ada without leaking memory */ - -typedef char * (SWIGSTDCALL* SWIG_AdaStringHelperCallback)(const char *); -static SWIG_AdaStringHelperCallback SWIG_ada_string_callback = NULL; - - - -/* probably obsolete ... -#ifdef __cplusplus -extern "C" -#endif -DllExport void SWIGSTDCALL SWIGRegisterStringCallback_LLVM_link_time_Optimizer(SWIG_AdaStringHelperCallback callback) { - SWIG_ada_string_callback = callback; -} -*/ - - - -/* Contract support */ - -#define SWIG_contract_assert(nullreturn, expr, msg) if (!(expr)) {SWIG_AdaThrowException(SWIG_AdaArgumentOutOfRangeException, msg); return nullreturn; } else - - -#define protected public -#define private public - -#include "llvm-c/lto.h" -#include "llvm-c/LinkTimeOptimizer.h" - - - -// struct LLVMCtxt; - - -#undef protected -#undef private -#ifdef __cplusplus -extern "C" { -#endif -DllExport char * SWIGSTDCALL Ada_lto_get_version ( - ) -{ - char * jresult ; - char *result = 0 ; - - result = (char *)lto_get_version(); - jresult = result; - - - - return jresult; - -} - - - -DllExport char * SWIGSTDCALL Ada_lto_get_error_message ( - ) -{ - char * jresult ; - char *result = 0 ; - - result = (char *)lto_get_error_message(); - jresult = result; - - - - return jresult; - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_lto_module_is_object_file ( - char * jarg1 - ) -{ - unsigned int jresult ; - char *arg1 = (char *) 0 ; - bool result; - - arg1 = jarg1; - - result = (bool)lto_module_is_object_file((char const *)arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_lto_module_is_object_file_for_target ( - char * jarg1 - , - - char * jarg2 - ) -{ - unsigned int jresult ; - char *arg1 = (char *) 0 ; - char *arg2 = (char *) 0 ; - bool result; - - arg1 = jarg1; - - arg2 = jarg2; - - result = (bool)lto_module_is_object_file_for_target((char const *)arg1,(char const *)arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_lto_module_is_object_file_in_memory ( - void* jarg1 - , - - size_t jarg2 - ) -{ - unsigned int jresult ; - void *arg1 = (void *) 0 ; - size_t arg2 ; - bool result; - - arg1 = (void *)jarg1; - - - arg2 = (size_t) jarg2; - - - result = (bool)lto_module_is_object_file_in_memory((void const *)arg1,arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_lto_module_is_object_file_in_memory_for_target ( - void* jarg1 - , - - size_t jarg2 - , - - char * jarg3 - ) -{ - unsigned int jresult ; - void *arg1 = (void *) 0 ; - size_t arg2 ; - char *arg3 = (char *) 0 ; - bool result; - - arg1 = (void *)jarg1; - - - arg2 = (size_t) jarg2; - - - arg3 = jarg3; - - result = (bool)lto_module_is_object_file_in_memory_for_target((void const *)arg1,arg2,(char const *)arg3); - jresult = result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_lto_module_create ( - char * jarg1 - ) -{ - void * jresult ; - char *arg1 = (char *) 0 ; - lto_module_t result; - - arg1 = jarg1; - - result = (lto_module_t)lto_module_create((char const *)arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_lto_module_create_from_memory ( - void* jarg1 - , - - size_t jarg2 - ) -{ - void * jresult ; - void *arg1 = (void *) 0 ; - size_t arg2 ; - lto_module_t result; - - arg1 = (void *)jarg1; - - - arg2 = (size_t) jarg2; - - - result = (lto_module_t)lto_module_create_from_memory((void const *)arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_lto_module_dispose ( - void * jarg1 - ) -{ - lto_module_t arg1 = (lto_module_t) 0 ; - - arg1 = (lto_module_t)jarg1; - - lto_module_dispose(arg1); - - -} - - - -DllExport char * SWIGSTDCALL Ada_lto_module_get_target_triple ( - void * jarg1 - ) -{ - char * jresult ; - lto_module_t arg1 = (lto_module_t) 0 ; - char *result = 0 ; - - arg1 = (lto_module_t)jarg1; - - result = (char *)lto_module_get_target_triple(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_lto_module_get_num_symbols ( - void * jarg1 - ) -{ - unsigned int jresult ; - lto_module_t arg1 = (lto_module_t) 0 ; - unsigned int result; - - arg1 = (lto_module_t)jarg1; - - result = (unsigned int)lto_module_get_num_symbols(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport char * SWIGSTDCALL Ada_lto_module_get_symbol_name ( - void * jarg1 - , - - unsigned int jarg2 - ) -{ - char * jresult ; - lto_module_t arg1 = (lto_module_t) 0 ; - unsigned int arg2 ; - char *result = 0 ; - - arg1 = (lto_module_t)jarg1; - - - arg2 = (unsigned int) jarg2; - - - result = (char *)lto_module_get_symbol_name(arg1,arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_lto_module_get_symbol_attribute ( - void * jarg1 - , - - unsigned int jarg2 - ) -{ - int jresult ; - lto_module_t arg1 = (lto_module_t) 0 ; - unsigned int arg2 ; - lto_symbol_attributes result; - - arg1 = (lto_module_t)jarg1; - - - arg2 = (unsigned int) jarg2; - - - result = (lto_symbol_attributes)lto_module_get_symbol_attribute(arg1,arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_lto_codegen_create ( - ) -{ - void * jresult ; - lto_code_gen_t result; - - result = (lto_code_gen_t)lto_codegen_create(); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_lto_codegen_dispose ( - void * jarg1 - ) -{ - lto_code_gen_t arg1 = (lto_code_gen_t) 0 ; - - arg1 = (lto_code_gen_t)jarg1; - - lto_codegen_dispose(arg1); - - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_lto_codegen_add_module ( - void * jarg1 - , - - void * jarg2 - ) -{ - unsigned int jresult ; - lto_code_gen_t arg1 = (lto_code_gen_t) 0 ; - lto_module_t arg2 = (lto_module_t) 0 ; - bool result; - - arg1 = (lto_code_gen_t)jarg1; - - arg2 = (lto_module_t)jarg2; - - result = (bool)lto_codegen_add_module(arg1,arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_lto_codegen_set_debug_model ( - void * jarg1 - , - - int jarg2 - ) -{ - unsigned int jresult ; - lto_code_gen_t arg1 = (lto_code_gen_t) 0 ; - lto_debug_model arg2 ; - bool result; - - arg1 = (lto_code_gen_t)jarg1; - - arg2 = (lto_debug_model) jarg2; - - result = (bool)lto_codegen_set_debug_model(arg1,arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_lto_codegen_set_pic_model ( - void * jarg1 - , - - int jarg2 - ) -{ - unsigned int jresult ; - lto_code_gen_t arg1 = (lto_code_gen_t) 0 ; - lto_codegen_model arg2 ; - bool result; - - arg1 = (lto_code_gen_t)jarg1; - - arg2 = (lto_codegen_model) jarg2; - - result = (bool)lto_codegen_set_pic_model(arg1,arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_lto_codegen_set_gcc_path ( - void * jarg1 - , - - char * jarg2 - ) -{ - lto_code_gen_t arg1 = (lto_code_gen_t) 0 ; - char *arg2 = (char *) 0 ; - - arg1 = (lto_code_gen_t)jarg1; - - arg2 = jarg2; - - lto_codegen_set_gcc_path(arg1,(char const *)arg2); - - -} - - - -DllExport void SWIGSTDCALL Ada_lto_codegen_set_assembler_path ( - void * jarg1 - , - - char * jarg2 - ) -{ - lto_code_gen_t arg1 = (lto_code_gen_t) 0 ; - char *arg2 = (char *) 0 ; - - arg1 = (lto_code_gen_t)jarg1; - - arg2 = jarg2; - - lto_codegen_set_assembler_path(arg1,(char const *)arg2); - - -} - - - -DllExport void SWIGSTDCALL Ada_lto_codegen_add_must_preserve_symbol ( - void * jarg1 - , - - char * jarg2 - ) -{ - lto_code_gen_t arg1 = (lto_code_gen_t) 0 ; - char *arg2 = (char *) 0 ; - - arg1 = (lto_code_gen_t)jarg1; - - arg2 = jarg2; - - lto_codegen_add_must_preserve_symbol(arg1,(char const *)arg2); - - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_lto_codegen_write_merged_modules ( - void * jarg1 - , - - char * jarg2 - ) -{ - unsigned int jresult ; - lto_code_gen_t arg1 = (lto_code_gen_t) 0 ; - char *arg2 = (char *) 0 ; - bool result; - - arg1 = (lto_code_gen_t)jarg1; - - arg2 = jarg2; - - result = (bool)lto_codegen_write_merged_modules(arg1,(char const *)arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport void* SWIGSTDCALL Ada_lto_codegen_compile ( - void * jarg1 - , - - size_t* jarg2 - ) -{ - void* jresult ; - lto_code_gen_t arg1 = (lto_code_gen_t) 0 ; - size_t *arg2 = (size_t *) 0 ; - void *result = 0 ; - - arg1 = (lto_code_gen_t)jarg1; - - - arg2 = (size_t *) jarg2; - - - result = (void *)lto_codegen_compile(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_lto_codegen_debug_options ( - void * jarg1 - , - - char * jarg2 - ) -{ - lto_code_gen_t arg1 = (lto_code_gen_t) 0 ; - char *arg2 = (char *) 0 ; - - arg1 = (lto_code_gen_t)jarg1; - - arg2 = jarg2; - - lto_codegen_debug_options(arg1,(char const *)arg2); - - -} - - - -DllExport void* SWIGSTDCALL Ada_llvm_create_optimizer ( - ) -{ - void* jresult ; - llvm_lto_t result; - - result = (llvm_lto_t)llvm_create_optimizer(); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_llvm_destroy_optimizer ( - void* jarg1 - ) -{ - llvm_lto_t arg1 = (llvm_lto_t) 0 ; - - arg1 = (llvm_lto_t)jarg1; - - llvm_destroy_optimizer(arg1); - - -} - - - -DllExport int SWIGSTDCALL Ada_llvm_read_object_file ( - void* jarg1 - , - - char * jarg2 - ) -{ - int jresult ; - llvm_lto_t arg1 = (llvm_lto_t) 0 ; - char *arg2 = (char *) 0 ; - llvm_lto_status_t result; - - arg1 = (llvm_lto_t)jarg1; - - arg2 = jarg2; - - result = (llvm_lto_status_t)llvm_read_object_file(arg1,(char const *)arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_llvm_optimize_modules ( - void* jarg1 - , - - char * jarg2 - ) -{ - int jresult ; - llvm_lto_t arg1 = (llvm_lto_t) 0 ; - char *arg2 = (char *) 0 ; - llvm_lto_status_t result; - - arg1 = (llvm_lto_t)jarg1; - - arg2 = jarg2; - - result = (llvm_lto_status_t)llvm_optimize_modules(arg1,(char const *)arg2); - jresult = result; - - - - return jresult; - -} - - - -#ifdef __cplusplus -} -#endif -#ifdef __cplusplus -extern "C" { -#endif -#ifdef __cplusplus -} -#endif - diff --git a/bindings/ada/llvm/llvm_wrap.cxx b/bindings/ada/llvm/llvm_wrap.cxx deleted file mode 100644 index 79b19ff4c0bb..000000000000 --- a/bindings/ada/llvm/llvm_wrap.cxx +++ /dev/null @@ -1,8817 +0,0 @@ -/* ---------------------------------------------------------------------------- - * This file was automatically generated by SWIG (http://www.swig.org). - * Version 1.3.36 - * - * This file is not intended to be easily readable and contains a number of - * coding conventions designed to improve portability and efficiency. Do not make - * changes to this file unless you know what you are doing--modify the SWIG - * interface file instead. - * ----------------------------------------------------------------------------- */ - - -#ifdef __cplusplus -template class SwigValueWrapper { - T *tt; -public: - SwigValueWrapper() : tt(0) { } - SwigValueWrapper(const SwigValueWrapper& rhs) : tt(new T(*rhs.tt)) { } - SwigValueWrapper(const T& t) : tt(new T(t)) { } - ~SwigValueWrapper() { delete tt; } - SwigValueWrapper& operator=(const T& t) { delete tt; tt = new T(t); return *this; } - operator T&() const { return *tt; } - T *operator&() { return tt; } -private: - SwigValueWrapper& operator=(const SwigValueWrapper& rhs); -}; - -template T SwigValueInit() { - return T(); -} -#endif - -/* ----------------------------------------------------------------------------- - * This section contains generic SWIG labels for method/variable - * declarations/attributes, and other compiler dependent labels. - * ----------------------------------------------------------------------------- */ - -/* template workaround for compilers that cannot correctly implement the C++ standard */ -#ifndef SWIGTEMPLATEDISAMBIGUATOR -# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) -# define SWIGTEMPLATEDISAMBIGUATOR template -# elif defined(__HP_aCC) -/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ -/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ -# define SWIGTEMPLATEDISAMBIGUATOR template -# else -# define SWIGTEMPLATEDISAMBIGUATOR -# endif -#endif - -/* inline attribute */ -#ifndef SWIGINLINE -# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) -# define SWIGINLINE inline -# else -# define SWIGINLINE -# endif -#endif - -/* attribute recognised by some compilers to avoid 'unused' warnings */ -#ifndef SWIGUNUSED -# if defined(__GNUC__) -# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -# elif defined(__ICC) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -#endif - -#ifndef SWIGUNUSEDPARM -# ifdef __cplusplus -# define SWIGUNUSEDPARM(p) -# else -# define SWIGUNUSEDPARM(p) p SWIGUNUSED -# endif -#endif - -/* internal SWIG method */ -#ifndef SWIGINTERN -# define SWIGINTERN static SWIGUNUSED -#endif - -/* internal inline SWIG method */ -#ifndef SWIGINTERNINLINE -# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE -#endif - -/* exporting methods */ -#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -# ifndef GCC_HASCLASSVISIBILITY -# define GCC_HASCLASSVISIBILITY -# endif -#endif - -#ifndef SWIGEXPORT -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# if defined(STATIC_LINKED) -# define SWIGEXPORT -# else -# define SWIGEXPORT __declspec(dllexport) -# endif -# else -# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) -# define SWIGEXPORT __attribute__ ((visibility("default"))) -# else -# define SWIGEXPORT -# endif -# endif -#endif - -/* calling conventions for Windows */ -#ifndef SWIGSTDCALL -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# define SWIGSTDCALL __stdcall -# else -# define SWIGSTDCALL -# endif -#endif - -/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ -#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) -# define _CRT_SECURE_NO_DEPRECATE -#endif - -/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ -#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) -# define _SCL_SECURE_NO_DEPRECATE -#endif - - - -#include -#include -#include -#if defined(_WIN32) || defined(__CYGWIN32__) -# define DllExport __declspec( dllexport ) -# define SWIGSTDCALL __stdcall -#else -# define DllExport -# define SWIGSTDCALL -#endif - - -#ifdef __cplusplus -# include -#endif - - - - -/* Support for throwing Ada exceptions from C/C++ */ - -typedef enum -{ - SWIG_AdaException, - SWIG_AdaOutOfMemoryException, - SWIG_AdaIndexOutOfRangeException, - SWIG_AdaDivideByZeroException, - SWIG_AdaArgumentOutOfRangeException, - SWIG_AdaNullReferenceException -} SWIG_AdaExceptionCodes; - - -typedef void (SWIGSTDCALL* SWIG_AdaExceptionCallback_t)(const char *); - - -typedef struct -{ - SWIG_AdaExceptionCodes code; - SWIG_AdaExceptionCallback_t callback; -} - SWIG_AdaExceptions_t; - - -static -SWIG_AdaExceptions_t -SWIG_ada_exceptions[] = -{ - { SWIG_AdaException, NULL }, - { SWIG_AdaOutOfMemoryException, NULL }, - { SWIG_AdaIndexOutOfRangeException, NULL }, - { SWIG_AdaDivideByZeroException, NULL }, - { SWIG_AdaArgumentOutOfRangeException, NULL }, - { SWIG_AdaNullReferenceException, NULL } -}; - - -static -void -SWIG_AdaThrowException (SWIG_AdaExceptionCodes code, const char *msg) -{ - SWIG_AdaExceptionCallback_t callback = SWIG_ada_exceptions[SWIG_AdaException].callback; - if (code >=0 && (size_t)code < sizeof(SWIG_ada_exceptions)/sizeof(SWIG_AdaExceptions_t)) { - callback = SWIG_ada_exceptions[code].callback; - } - callback(msg); -} - - - -#ifdef __cplusplus -extern "C" -#endif - -DllExport void SWIGSTDCALL SWIGRegisterExceptionCallbacks_llvm (SWIG_AdaExceptionCallback_t systemException, - SWIG_AdaExceptionCallback_t outOfMemory, - SWIG_AdaExceptionCallback_t indexOutOfRange, - SWIG_AdaExceptionCallback_t divideByZero, - SWIG_AdaExceptionCallback_t argumentOutOfRange, - SWIG_AdaExceptionCallback_t nullReference) -{ - SWIG_ada_exceptions [SWIG_AdaException].callback = systemException; - SWIG_ada_exceptions [SWIG_AdaOutOfMemoryException].callback = outOfMemory; - SWIG_ada_exceptions [SWIG_AdaIndexOutOfRangeException].callback = indexOutOfRange; - SWIG_ada_exceptions [SWIG_AdaDivideByZeroException].callback = divideByZero; - SWIG_ada_exceptions [SWIG_AdaArgumentOutOfRangeException].callback = argumentOutOfRange; - SWIG_ada_exceptions [SWIG_AdaNullReferenceException].callback = nullReference; -} - - -/* Callback for returning strings to Ada without leaking memory */ - -typedef char * (SWIGSTDCALL* SWIG_AdaStringHelperCallback)(const char *); -static SWIG_AdaStringHelperCallback SWIG_ada_string_callback = NULL; - - - -/* probably obsolete ... -#ifdef __cplusplus -extern "C" -#endif -DllExport void SWIGSTDCALL SWIGRegisterStringCallback_llvm(SWIG_AdaStringHelperCallback callback) { - SWIG_ada_string_callback = callback; -} -*/ - - - -/* Contract support */ - -#define SWIG_contract_assert(nullreturn, expr, msg) if (!(expr)) {SWIG_AdaThrowException(SWIG_AdaArgumentOutOfRangeException, msg); return nullreturn; } else - - -#define protected public -#define private public - -//#include "llvm-c/Analysis.h" -//#include "llvm-c/BitReader.h" -//#include "llvm-c/BitWriter.h" -#include "llvm-c/Core.h" -//#include "llvm-c/ExecutionEngine.h" -//#include "llvm-c/LinkTimeOptimizer.h" -//#include "llvm-c/lto.h" -//#include "llvm-c/Target.h" - - - - struct LLVMCtxt; -// struct LLVMOpaqueType; -// struct LLVMOpaqueValue; - -#undef protected -#undef private -#ifdef __cplusplus -extern "C" { -#endif -DllExport void SWIGSTDCALL Ada_LLVMDisposeMessage ( - char * jarg1 - ) -{ - char *arg1 = (char *) 0 ; - - arg1 = jarg1; - - LLVMDisposeMessage(arg1); - - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMContextCreate ( - ) -{ - void * jresult ; - LLVMContextRef result; - - result = (LLVMContextRef)LLVMContextCreate(); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetGlobalContext ( - ) -{ - void * jresult ; - LLVMContextRef result; - - result = (LLVMContextRef)LLVMGetGlobalContext(); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMContextDispose ( - void * jarg1 - ) -{ - LLVMContextRef arg1 = (LLVMContextRef) 0 ; - - arg1 = (LLVMContextRef)jarg1; - - LLVMContextDispose(arg1); - - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMModuleCreateWithName ( - char * jarg1 - ) -{ - void * jresult ; - char *arg1 = (char *) 0 ; - LLVMModuleRef result; - - arg1 = jarg1; - - result = (LLVMModuleRef)LLVMModuleCreateWithName((char const *)arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMModuleCreateWithNameInContext ( - char * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - char *arg1 = (char *) 0 ; - LLVMContextRef arg2 = (LLVMContextRef) 0 ; - LLVMModuleRef result; - - arg1 = jarg1; - - arg2 = (LLVMContextRef)jarg2; - - result = (LLVMModuleRef)LLVMModuleCreateWithNameInContext((char const *)arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMDisposeModule ( - void * jarg1 - ) -{ - LLVMModuleRef arg1 = (LLVMModuleRef) 0 ; - - arg1 = (LLVMModuleRef)jarg1; - - LLVMDisposeModule(arg1); - - -} - - - -DllExport char * SWIGSTDCALL Ada_LLVMGetDataLayout ( - void * jarg1 - ) -{ - char * jresult ; - LLVMModuleRef arg1 = (LLVMModuleRef) 0 ; - char *result = 0 ; - - arg1 = (LLVMModuleRef)jarg1; - - result = (char *)LLVMGetDataLayout(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMSetDataLayout ( - void * jarg1 - , - - char * jarg2 - ) -{ - LLVMModuleRef arg1 = (LLVMModuleRef) 0 ; - char *arg2 = (char *) 0 ; - - arg1 = (LLVMModuleRef)jarg1; - - arg2 = jarg2; - - LLVMSetDataLayout(arg1,(char const *)arg2); - - -} - - - -DllExport char * SWIGSTDCALL Ada_LLVMGetTarget ( - void * jarg1 - ) -{ - char * jresult ; - LLVMModuleRef arg1 = (LLVMModuleRef) 0 ; - char *result = 0 ; - - arg1 = (LLVMModuleRef)jarg1; - - result = (char *)LLVMGetTarget(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMSetTarget ( - void * jarg1 - , - - char * jarg2 - ) -{ - LLVMModuleRef arg1 = (LLVMModuleRef) 0 ; - char *arg2 = (char *) 0 ; - - arg1 = (LLVMModuleRef)jarg1; - - arg2 = jarg2; - - LLVMSetTarget(arg1,(char const *)arg2); - - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMAddTypeName ( - void * jarg1 - , - - char * jarg2 - , - - void * jarg3 - ) -{ - int jresult ; - LLVMModuleRef arg1 = (LLVMModuleRef) 0 ; - char *arg2 = (char *) 0 ; - LLVMTypeRef arg3 = (LLVMTypeRef) 0 ; - int result; - - arg1 = (LLVMModuleRef)jarg1; - - arg2 = jarg2; - - arg3 = (LLVMTypeRef)jarg3; - - result = (int)LLVMAddTypeName(arg1,(char const *)arg2,arg3); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMDeleteTypeName ( - void * jarg1 - , - - char * jarg2 - ) -{ - LLVMModuleRef arg1 = (LLVMModuleRef) 0 ; - char *arg2 = (char *) 0 ; - - arg1 = (LLVMModuleRef)jarg1; - - arg2 = jarg2; - - LLVMDeleteTypeName(arg1,(char const *)arg2); - - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetTypeByName ( - void * jarg1 - , - - char * jarg2 - ) -{ - void * jresult ; - LLVMModuleRef arg1 = (LLVMModuleRef) 0 ; - char *arg2 = (char *) 0 ; - LLVMTypeRef result; - - arg1 = (LLVMModuleRef)jarg1; - - arg2 = jarg2; - - result = (LLVMTypeRef)LLVMGetTypeByName(arg1,(char const *)arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMDumpModule ( - void * jarg1 - ) -{ - LLVMModuleRef arg1 = (LLVMModuleRef) 0 ; - - arg1 = (LLVMModuleRef)jarg1; - - LLVMDumpModule(arg1); - - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMGetTypeKind ( - void * jarg1 - ) -{ - int jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - LLVMTypeKind result; - - arg1 = (LLVMTypeRef)jarg1; - - result = (LLVMTypeKind)LLVMGetTypeKind(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMInt1Type ( - ) -{ - void * jresult ; - LLVMTypeRef result; - - result = (LLVMTypeRef)LLVMInt1Type(); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMInt8Type ( - ) -{ - void * jresult ; - LLVMTypeRef result; - - result = (LLVMTypeRef)LLVMInt8Type(); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMInt16Type ( - ) -{ - void * jresult ; - LLVMTypeRef result; - - result = (LLVMTypeRef)LLVMInt16Type(); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMInt32Type ( - ) -{ - void * jresult ; - LLVMTypeRef result; - - result = (LLVMTypeRef)LLVMInt32Type(); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMInt64Type ( - ) -{ - void * jresult ; - LLVMTypeRef result; - - result = (LLVMTypeRef)LLVMInt64Type(); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIntType ( - unsigned int jarg1 - ) -{ - void * jresult ; - unsigned int arg1 ; - LLVMTypeRef result; - - - arg1 = (unsigned int) jarg1; - - - result = (LLVMTypeRef)LLVMIntType(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_LLVMGetIntTypeWidth ( - void * jarg1 - ) -{ - unsigned int jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - unsigned int result; - - arg1 = (LLVMTypeRef)jarg1; - - result = (unsigned int)LLVMGetIntTypeWidth(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMFloatType ( - ) -{ - void * jresult ; - LLVMTypeRef result; - - result = (LLVMTypeRef)LLVMFloatType(); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMDoubleType ( - ) -{ - void * jresult ; - LLVMTypeRef result; - - result = (LLVMTypeRef)LLVMDoubleType(); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMX86FP80Type ( - ) -{ - void * jresult ; - LLVMTypeRef result; - - result = (LLVMTypeRef)LLVMX86FP80Type(); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMFP128Type ( - ) -{ - void * jresult ; - LLVMTypeRef result; - - result = (LLVMTypeRef)LLVMFP128Type(); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMPPCFP128Type ( - ) -{ - void * jresult ; - LLVMTypeRef result; - - result = (LLVMTypeRef)LLVMPPCFP128Type(); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMFunctionType ( - void * jarg1 - , - - void * jarg2 - , - - unsigned int jarg3 - , - - int jarg4 - ) -{ - void * jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - LLVMTypeRef *arg2 = (LLVMTypeRef *) 0 ; - unsigned int arg3 ; - int arg4 ; - LLVMTypeRef result; - - arg1 = (LLVMTypeRef)jarg1; - - arg2 = (LLVMTypeRef *)jarg2; - - - arg3 = (unsigned int) jarg3; - - - - arg4 = (int) jarg4; - - - result = (LLVMTypeRef)LLVMFunctionType(arg1,arg2,arg3,arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMIsFunctionVarArg ( - void * jarg1 - ) -{ - int jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - int result; - - arg1 = (LLVMTypeRef)jarg1; - - result = (int)LLVMIsFunctionVarArg(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetReturnType ( - void * jarg1 - ) -{ - void * jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - LLVMTypeRef result; - - arg1 = (LLVMTypeRef)jarg1; - - result = (LLVMTypeRef)LLVMGetReturnType(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_LLVMCountParamTypes ( - void * jarg1 - ) -{ - unsigned int jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - unsigned int result; - - arg1 = (LLVMTypeRef)jarg1; - - result = (unsigned int)LLVMCountParamTypes(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMGetParamTypes ( - void * jarg1 - , - - void * jarg2 - ) -{ - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - LLVMTypeRef *arg2 = (LLVMTypeRef *) 0 ; - - arg1 = (LLVMTypeRef)jarg1; - - arg2 = (LLVMTypeRef *)jarg2; - - LLVMGetParamTypes(arg1,arg2); - - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMStructType ( - void * jarg1 - , - - unsigned int jarg2 - , - - int jarg3 - ) -{ - void * jresult ; - LLVMTypeRef *arg1 = (LLVMTypeRef *) 0 ; - unsigned int arg2 ; - int arg3 ; - LLVMTypeRef result; - - arg1 = (LLVMTypeRef *)jarg1; - - - arg2 = (unsigned int) jarg2; - - - - arg3 = (int) jarg3; - - - result = (LLVMTypeRef)LLVMStructType(arg1,arg2,arg3); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_LLVMCountStructElementTypes ( - void * jarg1 - ) -{ - unsigned int jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - unsigned int result; - - arg1 = (LLVMTypeRef)jarg1; - - result = (unsigned int)LLVMCountStructElementTypes(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMGetStructElementTypes ( - void * jarg1 - , - - void * jarg2 - ) -{ - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - LLVMTypeRef *arg2 = (LLVMTypeRef *) 0 ; - - arg1 = (LLVMTypeRef)jarg1; - - arg2 = (LLVMTypeRef *)jarg2; - - LLVMGetStructElementTypes(arg1,arg2); - - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMIsPackedStruct ( - void * jarg1 - ) -{ - int jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - int result; - - arg1 = (LLVMTypeRef)jarg1; - - result = (int)LLVMIsPackedStruct(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMArrayType ( - void * jarg1 - , - - unsigned int jarg2 - ) -{ - void * jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - unsigned int arg2 ; - LLVMTypeRef result; - - arg1 = (LLVMTypeRef)jarg1; - - - arg2 = (unsigned int) jarg2; - - - result = (LLVMTypeRef)LLVMArrayType(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMPointerType ( - void * jarg1 - , - - unsigned int jarg2 - ) -{ - void * jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - unsigned int arg2 ; - LLVMTypeRef result; - - arg1 = (LLVMTypeRef)jarg1; - - - arg2 = (unsigned int) jarg2; - - - result = (LLVMTypeRef)LLVMPointerType(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMVectorType ( - void * jarg1 - , - - unsigned int jarg2 - ) -{ - void * jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - unsigned int arg2 ; - LLVMTypeRef result; - - arg1 = (LLVMTypeRef)jarg1; - - - arg2 = (unsigned int) jarg2; - - - result = (LLVMTypeRef)LLVMVectorType(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetElementType ( - void * jarg1 - ) -{ - void * jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - LLVMTypeRef result; - - arg1 = (LLVMTypeRef)jarg1; - - result = (LLVMTypeRef)LLVMGetElementType(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_LLVMGetArrayLength ( - void * jarg1 - ) -{ - unsigned int jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - unsigned int result; - - arg1 = (LLVMTypeRef)jarg1; - - result = (unsigned int)LLVMGetArrayLength(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_LLVMGetPointerAddressSpace ( - void * jarg1 - ) -{ - unsigned int jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - unsigned int result; - - arg1 = (LLVMTypeRef)jarg1; - - result = (unsigned int)LLVMGetPointerAddressSpace(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_LLVMGetVectorSize ( - void * jarg1 - ) -{ - unsigned int jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - unsigned int result; - - arg1 = (LLVMTypeRef)jarg1; - - result = (unsigned int)LLVMGetVectorSize(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMVoidType ( - ) -{ - void * jresult ; - LLVMTypeRef result; - - result = (LLVMTypeRef)LLVMVoidType(); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMLabelType ( - ) -{ - void * jresult ; - LLVMTypeRef result; - - result = (LLVMTypeRef)LLVMLabelType(); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMOpaqueType ( - ) -{ - void * jresult ; - LLVMTypeRef result; - - result = (LLVMTypeRef)LLVMOpaqueType(); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMCreateTypeHandle ( - void * jarg1 - ) -{ - void * jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - LLVMTypeHandleRef result; - - arg1 = (LLVMTypeRef)jarg1; - - result = (LLVMTypeHandleRef)LLVMCreateTypeHandle(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMRefineType ( - void * jarg1 - , - - void * jarg2 - ) -{ - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - - arg1 = (LLVMTypeRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - LLVMRefineType(arg1,arg2); - - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMResolveTypeHandle ( - void * jarg1 - ) -{ - void * jresult ; - LLVMTypeHandleRef arg1 = (LLVMTypeHandleRef) 0 ; - LLVMTypeRef result; - - arg1 = (LLVMTypeHandleRef)jarg1; - - result = (LLVMTypeRef)LLVMResolveTypeHandle(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMDisposeTypeHandle ( - void * jarg1 - ) -{ - LLVMTypeHandleRef arg1 = (LLVMTypeHandleRef) 0 ; - - arg1 = (LLVMTypeHandleRef)jarg1; - - LLVMDisposeTypeHandle(arg1); - - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMTypeOf ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMTypeRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMTypeRef)LLVMTypeOf(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport char * SWIGSTDCALL Ada_LLVMGetValueName ( - void * jarg1 - ) -{ - char * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - char *result = 0 ; - - arg1 = (LLVMValueRef)jarg1; - - result = (char *)LLVMGetValueName(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMSetValueName ( - void * jarg1 - , - - char * jarg2 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - char *arg2 = (char *) 0 ; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = jarg2; - - LLVMSetValueName(arg1,(char const *)arg2); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMDumpValue ( - void * jarg1 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - - arg1 = (LLVMValueRef)jarg1; - - LLVMDumpValue(arg1); - - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAArgument ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAArgument(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsABasicBlock ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsABasicBlock(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAInlineAsm ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAInlineAsm(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAUser ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAUser(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAConstant ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAConstant(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAConstantAggregateZero ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAConstantAggregateZero(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAConstantArray ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAConstantArray(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAConstantExpr ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAConstantExpr(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAConstantFP ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAConstantFP(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAConstantInt ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAConstantInt(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAConstantPointerNull ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAConstantPointerNull(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAConstantStruct ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAConstantStruct(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAConstantVector ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAConstantVector(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAGlobalValue ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAGlobalValue(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAFunction ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAFunction(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAGlobalAlias ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAGlobalAlias(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAGlobalVariable ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAGlobalVariable(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAUndefValue ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAUndefValue(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAInstruction ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAInstruction(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsABinaryOperator ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsABinaryOperator(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsACallInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsACallInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAIntrinsicInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAIntrinsicInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsADbgInfoIntrinsic ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsADbgInfoIntrinsic(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsADbgDeclareInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsADbgDeclareInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsADbgFuncStartInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsADbgFuncStartInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsADbgRegionEndInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsADbgRegionEndInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsADbgRegionStartInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsADbgRegionStartInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsADbgStopPointInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsADbgStopPointInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAEHSelectorInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAEHSelectorInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAMemIntrinsic ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAMemIntrinsic(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAMemCpyInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAMemCpyInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAMemMoveInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAMemMoveInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAMemSetInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAMemSetInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsACmpInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsACmpInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAFCmpInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAFCmpInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAICmpInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAICmpInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAExtractElementInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAExtractElementInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAGetElementPtrInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAGetElementPtrInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAInsertElementInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAInsertElementInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAInsertValueInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAInsertValueInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAPHINode ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAPHINode(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsASelectInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsASelectInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAShuffleVectorInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAShuffleVectorInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAStoreInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAStoreInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsATerminatorInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsATerminatorInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsABranchInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsABranchInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAInvokeInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAInvokeInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAReturnInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAReturnInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsASwitchInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsASwitchInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAUnreachableInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAUnreachableInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAUnwindInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAUnwindInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAUnaryInstruction ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAUnaryInstruction(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAAllocationInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAAllocationInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAAllocaInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAAllocaInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAMallocInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAMallocInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsACastInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsACastInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsABitCastInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsABitCastInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAFPExtInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAFPExtInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAFPToSIInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAFPToSIInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAFPToUIInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAFPToUIInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAFPTruncInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAFPTruncInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAIntToPtrInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAIntToPtrInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAPtrToIntInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAPtrToIntInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsASExtInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsASExtInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsASIToFPInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsASIToFPInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsATruncInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsATruncInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAUIToFPInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAUIToFPInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAZExtInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAZExtInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAExtractValueInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAExtractValueInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAFreeInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAFreeInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsALoadInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsALoadInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIsAVAArgInst ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMIsAVAArgInst(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstNull ( - void * jarg1 - ) -{ - void * jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMTypeRef)jarg1; - - result = (LLVMValueRef)LLVMConstNull(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstAllOnes ( - void * jarg1 - ) -{ - void * jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMTypeRef)jarg1; - - result = (LLVMValueRef)LLVMConstAllOnes(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetUndef ( - void * jarg1 - ) -{ - void * jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMTypeRef)jarg1; - - result = (LLVMValueRef)LLVMGetUndef(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMIsConstant ( - void * jarg1 - ) -{ - int jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - int result; - - arg1 = (LLVMValueRef)jarg1; - - result = (int)LLVMIsConstant(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMIsNull ( - void * jarg1 - ) -{ - int jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - int result; - - arg1 = (LLVMValueRef)jarg1; - - result = (int)LLVMIsNull(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMIsUndef ( - void * jarg1 - ) -{ - int jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - int result; - - arg1 = (LLVMValueRef)jarg1; - - result = (int)LLVMIsUndef(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstPointerNull ( - void * jarg1 - ) -{ - void * jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMTypeRef)jarg1; - - result = (LLVMValueRef)LLVMConstPointerNull(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstInt ( - void * jarg1 - , - - unsigned long long jarg2 - , - - int jarg3 - ) -{ - void * jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - unsigned long long arg2 ; - int arg3 ; - LLVMValueRef result; - - arg1 = (LLVMTypeRef)jarg1; - - - arg2 = (unsigned long long) jarg2; - - - - arg3 = (int) jarg3; - - - result = (LLVMValueRef)LLVMConstInt(arg1,arg2,arg3); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstReal ( - void * jarg1 - , - - double jarg2 - ) -{ - void * jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - double arg2 ; - LLVMValueRef result; - - arg1 = (LLVMTypeRef)jarg1; - - - arg2 = (double) jarg2; - - - result = (LLVMValueRef)LLVMConstReal(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstRealOfString ( - void * jarg1 - , - - char * jarg2 - ) -{ - void * jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - char *arg2 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMTypeRef)jarg1; - - arg2 = jarg2; - - result = (LLVMValueRef)LLVMConstRealOfString(arg1,(char const *)arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstString ( - char * jarg1 - , - - unsigned int jarg2 - , - - int jarg3 - ) -{ - void * jresult ; - char *arg1 = (char *) 0 ; - unsigned int arg2 ; - int arg3 ; - LLVMValueRef result; - - arg1 = jarg1; - - - arg2 = (unsigned int) jarg2; - - - - arg3 = (int) jarg3; - - - result = (LLVMValueRef)LLVMConstString((char const *)arg1,arg2,arg3); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstArray ( - void * jarg1 - , - - void * jarg2 - , - - unsigned int jarg3 - ) -{ - void * jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - LLVMValueRef *arg2 = (LLVMValueRef *) 0 ; - unsigned int arg3 ; - LLVMValueRef result; - - arg1 = (LLVMTypeRef)jarg1; - - arg2 = (LLVMValueRef *)jarg2; - - - arg3 = (unsigned int) jarg3; - - - result = (LLVMValueRef)LLVMConstArray(arg1,arg2,arg3); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstStruct ( - void * jarg1 - , - - unsigned int jarg2 - , - - int jarg3 - ) -{ - void * jresult ; - LLVMValueRef *arg1 = (LLVMValueRef *) 0 ; - unsigned int arg2 ; - int arg3 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef *)jarg1; - - - arg2 = (unsigned int) jarg2; - - - - arg3 = (int) jarg3; - - - result = (LLVMValueRef)LLVMConstStruct(arg1,arg2,arg3); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstVector ( - void * jarg1 - , - - unsigned int jarg2 - ) -{ - void * jresult ; - LLVMValueRef *arg1 = (LLVMValueRef *) 0 ; - unsigned int arg2 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef *)jarg1; - - - arg2 = (unsigned int) jarg2; - - - result = (LLVMValueRef)LLVMConstVector(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMSizeOf ( - void * jarg1 - ) -{ - void * jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMTypeRef)jarg1; - - result = (LLVMValueRef)LLVMSizeOf(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstNeg ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMConstNeg(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstNot ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMConstNot(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstAdd ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - result = (LLVMValueRef)LLVMConstAdd(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstSub ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - result = (LLVMValueRef)LLVMConstSub(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstMul ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - result = (LLVMValueRef)LLVMConstMul(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstUDiv ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - result = (LLVMValueRef)LLVMConstUDiv(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstSDiv ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - result = (LLVMValueRef)LLVMConstSDiv(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstFDiv ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - result = (LLVMValueRef)LLVMConstFDiv(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstURem ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - result = (LLVMValueRef)LLVMConstURem(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstSRem ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - result = (LLVMValueRef)LLVMConstSRem(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstFRem ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - result = (LLVMValueRef)LLVMConstFRem(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstAnd ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - result = (LLVMValueRef)LLVMConstAnd(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstOr ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - result = (LLVMValueRef)LLVMConstOr(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstXor ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - result = (LLVMValueRef)LLVMConstXor(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstICmp ( - int jarg1 - , - - void * jarg2 - , - - void * jarg3 - ) -{ - void * jresult ; - LLVMIntPredicate arg1 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMIntPredicate) jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - result = (LLVMValueRef)LLVMConstICmp(arg1,arg2,arg3); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstFCmp ( - int jarg1 - , - - void * jarg2 - , - - void * jarg3 - ) -{ - void * jresult ; - LLVMRealPredicate arg1 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMRealPredicate) jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - result = (LLVMValueRef)LLVMConstFCmp(arg1,arg2,arg3); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstShl ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - result = (LLVMValueRef)LLVMConstShl(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstLShr ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - result = (LLVMValueRef)LLVMConstLShr(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstAShr ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - result = (LLVMValueRef)LLVMConstAShr(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstGEP ( - void * jarg1 - , - - void * jarg2 - , - - unsigned int jarg3 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef *arg2 = (LLVMValueRef *) 0 ; - unsigned int arg3 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef *)jarg2; - - - arg3 = (unsigned int) jarg3; - - - result = (LLVMValueRef)LLVMConstGEP(arg1,arg2,arg3); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstTrunc ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - result = (LLVMValueRef)LLVMConstTrunc(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstSExt ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - result = (LLVMValueRef)LLVMConstSExt(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstZExt ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - result = (LLVMValueRef)LLVMConstZExt(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstFPTrunc ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - result = (LLVMValueRef)LLVMConstFPTrunc(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstFPExt ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - result = (LLVMValueRef)LLVMConstFPExt(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstUIToFP ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - result = (LLVMValueRef)LLVMConstUIToFP(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstSIToFP ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - result = (LLVMValueRef)LLVMConstSIToFP(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstFPToUI ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - result = (LLVMValueRef)LLVMConstFPToUI(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstFPToSI ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - result = (LLVMValueRef)LLVMConstFPToSI(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstPtrToInt ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - result = (LLVMValueRef)LLVMConstPtrToInt(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstIntToPtr ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - result = (LLVMValueRef)LLVMConstIntToPtr(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstBitCast ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - result = (LLVMValueRef)LLVMConstBitCast(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstSelect ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - result = (LLVMValueRef)LLVMConstSelect(arg1,arg2,arg3); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstExtractElement ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - result = (LLVMValueRef)LLVMConstExtractElement(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstInsertElement ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - result = (LLVMValueRef)LLVMConstInsertElement(arg1,arg2,arg3); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstShuffleVector ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - result = (LLVMValueRef)LLVMConstShuffleVector(arg1,arg2,arg3); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstExtractValue ( - void * jarg1 - , - - unsigned int* jarg2 - , - - unsigned int jarg3 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - unsigned int *arg2 = (unsigned int *) 0 ; - unsigned int arg3 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - - arg2 = (unsigned int *) jarg2; - - - - arg3 = (unsigned int) jarg3; - - - result = (LLVMValueRef)LLVMConstExtractValue(arg1,arg2,arg3); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstInsertValue ( - void * jarg1 - , - - void * jarg2 - , - - unsigned int* jarg3 - , - - unsigned int jarg4 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - unsigned int *arg3 = (unsigned int *) 0 ; - unsigned int arg4 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - - arg3 = (unsigned int *) jarg3; - - - - arg4 = (unsigned int) jarg4; - - - result = (LLVMValueRef)LLVMConstInsertValue(arg1,arg2,arg3,arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMConstInlineAsm ( - void * jarg1 - , - - char * jarg2 - , - - char * jarg3 - , - - int jarg4 - ) -{ - void * jresult ; - LLVMTypeRef arg1 = (LLVMTypeRef) 0 ; - char *arg2 = (char *) 0 ; - char *arg3 = (char *) 0 ; - int arg4 ; - LLVMValueRef result; - - arg1 = (LLVMTypeRef)jarg1; - - arg2 = jarg2; - - arg3 = jarg3; - - - arg4 = (int) jarg4; - - - result = (LLVMValueRef)LLVMConstInlineAsm(arg1,(char const *)arg2,(char const *)arg3,arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetGlobalParent ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMModuleRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMModuleRef)LLVMGetGlobalParent(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMIsDeclaration ( - void * jarg1 - ) -{ - int jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - int result; - - arg1 = (LLVMValueRef)jarg1; - - result = (int)LLVMIsDeclaration(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMGetLinkage ( - void * jarg1 - ) -{ - int jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMLinkage result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMLinkage)LLVMGetLinkage(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMSetLinkage ( - void * jarg1 - , - - int jarg2 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMLinkage arg2 ; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMLinkage) jarg2; - - LLVMSetLinkage(arg1,arg2); - - -} - - - -DllExport char * SWIGSTDCALL Ada_LLVMGetSection ( - void * jarg1 - ) -{ - char * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - char *result = 0 ; - - arg1 = (LLVMValueRef)jarg1; - - result = (char *)LLVMGetSection(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMSetSection ( - void * jarg1 - , - - char * jarg2 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - char *arg2 = (char *) 0 ; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = jarg2; - - LLVMSetSection(arg1,(char const *)arg2); - - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMGetVisibility ( - void * jarg1 - ) -{ - int jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMVisibility result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMVisibility)LLVMGetVisibility(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMSetVisibility ( - void * jarg1 - , - - int jarg2 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMVisibility arg2 ; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMVisibility) jarg2; - - LLVMSetVisibility(arg1,arg2); - - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_LLVMGetAlignment ( - void * jarg1 - ) -{ - unsigned int jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - unsigned int result; - - arg1 = (LLVMValueRef)jarg1; - - result = (unsigned int)LLVMGetAlignment(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMSetAlignment ( - void * jarg1 - , - - unsigned int jarg2 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - unsigned int arg2 ; - - arg1 = (LLVMValueRef)jarg1; - - - arg2 = (unsigned int) jarg2; - - - LLVMSetAlignment(arg1,arg2); - - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMAddGlobal ( - void * jarg1 - , - - void * jarg2 - , - - char * jarg3 - ) -{ - void * jresult ; - LLVMModuleRef arg1 = (LLVMModuleRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - char *arg3 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMModuleRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - arg3 = jarg3; - - result = (LLVMValueRef)LLVMAddGlobal(arg1,arg2,(char const *)arg3); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetNamedGlobal ( - void * jarg1 - , - - char * jarg2 - ) -{ - void * jresult ; - LLVMModuleRef arg1 = (LLVMModuleRef) 0 ; - char *arg2 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMModuleRef)jarg1; - - arg2 = jarg2; - - result = (LLVMValueRef)LLVMGetNamedGlobal(arg1,(char const *)arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetFirstGlobal ( - void * jarg1 - ) -{ - void * jresult ; - LLVMModuleRef arg1 = (LLVMModuleRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMModuleRef)jarg1; - - result = (LLVMValueRef)LLVMGetFirstGlobal(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetLastGlobal ( - void * jarg1 - ) -{ - void * jresult ; - LLVMModuleRef arg1 = (LLVMModuleRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMModuleRef)jarg1; - - result = (LLVMValueRef)LLVMGetLastGlobal(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetNextGlobal ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMGetNextGlobal(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetPreviousGlobal ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMGetPreviousGlobal(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMDeleteGlobal ( - void * jarg1 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - - arg1 = (LLVMValueRef)jarg1; - - LLVMDeleteGlobal(arg1); - - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetInitializer ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMGetInitializer(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMSetInitializer ( - void * jarg1 - , - - void * jarg2 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - LLVMSetInitializer(arg1,arg2); - - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMIsThreadLocal ( - void * jarg1 - ) -{ - int jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - int result; - - arg1 = (LLVMValueRef)jarg1; - - result = (int)LLVMIsThreadLocal(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMSetThreadLocal ( - void * jarg1 - , - - int jarg2 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - int arg2 ; - - arg1 = (LLVMValueRef)jarg1; - - - arg2 = (int) jarg2; - - - LLVMSetThreadLocal(arg1,arg2); - - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMIsGlobalConstant ( - void * jarg1 - ) -{ - int jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - int result; - - arg1 = (LLVMValueRef)jarg1; - - result = (int)LLVMIsGlobalConstant(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMSetGlobalConstant ( - void * jarg1 - , - - int jarg2 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - int arg2 ; - - arg1 = (LLVMValueRef)jarg1; - - - arg2 = (int) jarg2; - - - LLVMSetGlobalConstant(arg1,arg2); - - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMAddAlias ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMModuleRef arg1 = (LLVMModuleRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMModuleRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMAddAlias(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMAddFunction ( - void * jarg1 - , - - char * jarg2 - , - - void * jarg3 - ) -{ - void * jresult ; - LLVMModuleRef arg1 = (LLVMModuleRef) 0 ; - char *arg2 = (char *) 0 ; - LLVMTypeRef arg3 = (LLVMTypeRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMModuleRef)jarg1; - - arg2 = jarg2; - - arg3 = (LLVMTypeRef)jarg3; - - result = (LLVMValueRef)LLVMAddFunction(arg1,(char const *)arg2,arg3); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetNamedFunction ( - void * jarg1 - , - - char * jarg2 - ) -{ - void * jresult ; - LLVMModuleRef arg1 = (LLVMModuleRef) 0 ; - char *arg2 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMModuleRef)jarg1; - - arg2 = jarg2; - - result = (LLVMValueRef)LLVMGetNamedFunction(arg1,(char const *)arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetFirstFunction ( - void * jarg1 - ) -{ - void * jresult ; - LLVMModuleRef arg1 = (LLVMModuleRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMModuleRef)jarg1; - - result = (LLVMValueRef)LLVMGetFirstFunction(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetLastFunction ( - void * jarg1 - ) -{ - void * jresult ; - LLVMModuleRef arg1 = (LLVMModuleRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMModuleRef)jarg1; - - result = (LLVMValueRef)LLVMGetLastFunction(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetNextFunction ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMGetNextFunction(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetPreviousFunction ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMGetPreviousFunction(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMDeleteFunction ( - void * jarg1 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - - arg1 = (LLVMValueRef)jarg1; - - LLVMDeleteFunction(arg1); - - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_LLVMGetIntrinsicID ( - void * jarg1 - ) -{ - unsigned int jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - unsigned int result; - - arg1 = (LLVMValueRef)jarg1; - - result = (unsigned int)LLVMGetIntrinsicID(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_LLVMGetFunctionCallConv ( - void * jarg1 - ) -{ - unsigned int jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - unsigned int result; - - arg1 = (LLVMValueRef)jarg1; - - result = (unsigned int)LLVMGetFunctionCallConv(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMSetFunctionCallConv ( - void * jarg1 - , - - unsigned int jarg2 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - unsigned int arg2 ; - - arg1 = (LLVMValueRef)jarg1; - - - arg2 = (unsigned int) jarg2; - - - LLVMSetFunctionCallConv(arg1,arg2); - - -} - - - -DllExport char * SWIGSTDCALL Ada_LLVMGetGC ( - void * jarg1 - ) -{ - char * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - char *result = 0 ; - - arg1 = (LLVMValueRef)jarg1; - - result = (char *)LLVMGetGC(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMSetGC ( - void * jarg1 - , - - char * jarg2 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - char *arg2 = (char *) 0 ; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = jarg2; - - LLVMSetGC(arg1,(char const *)arg2); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddFunctionAttr ( - void * jarg1 - , - - int jarg2 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMAttribute arg2 ; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMAttribute) jarg2; - - LLVMAddFunctionAttr(arg1,arg2); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMRemoveFunctionAttr ( - void * jarg1 - , - - int jarg2 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMAttribute arg2 ; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMAttribute) jarg2; - - LLVMRemoveFunctionAttr(arg1,arg2); - - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_LLVMCountParams ( - void * jarg1 - ) -{ - unsigned int jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - unsigned int result; - - arg1 = (LLVMValueRef)jarg1; - - result = (unsigned int)LLVMCountParams(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMGetParams ( - void * jarg1 - , - - void * jarg2 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef *arg2 = (LLVMValueRef *) 0 ; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef *)jarg2; - - LLVMGetParams(arg1,arg2); - - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetParam ( - void * jarg1 - , - - unsigned int jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - unsigned int arg2 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - - arg2 = (unsigned int) jarg2; - - - result = (LLVMValueRef)LLVMGetParam(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetParamParent ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMGetParamParent(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetFirstParam ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMGetFirstParam(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetLastParam ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMGetLastParam(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetNextParam ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMGetNextParam(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetPreviousParam ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMGetPreviousParam(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddAttribute ( - void * jarg1 - , - - int jarg2 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMAttribute arg2 ; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMAttribute) jarg2; - - LLVMAddAttribute(arg1,arg2); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMRemoveAttribute ( - void * jarg1 - , - - int jarg2 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMAttribute arg2 ; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMAttribute) jarg2; - - LLVMRemoveAttribute(arg1,arg2); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMSetParamAlignment ( - void * jarg1 - , - - unsigned int jarg2 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - unsigned int arg2 ; - - arg1 = (LLVMValueRef)jarg1; - - - arg2 = (unsigned int) jarg2; - - - LLVMSetParamAlignment(arg1,arg2); - - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBasicBlockAsValue ( - void * jarg1 - ) -{ - void * jresult ; - LLVMBasicBlockRef arg1 = (LLVMBasicBlockRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBasicBlockRef)jarg1; - - result = (LLVMValueRef)LLVMBasicBlockAsValue(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMValueIsBasicBlock ( - void * jarg1 - ) -{ - int jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - int result; - - arg1 = (LLVMValueRef)jarg1; - - result = (int)LLVMValueIsBasicBlock(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMValueAsBasicBlock ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMBasicBlockRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMBasicBlockRef)LLVMValueAsBasicBlock(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetBasicBlockParent ( - void * jarg1 - ) -{ - void * jresult ; - LLVMBasicBlockRef arg1 = (LLVMBasicBlockRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBasicBlockRef)jarg1; - - result = (LLVMValueRef)LLVMGetBasicBlockParent(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_LLVMCountBasicBlocks ( - void * jarg1 - ) -{ - unsigned int jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - unsigned int result; - - arg1 = (LLVMValueRef)jarg1; - - result = (unsigned int)LLVMCountBasicBlocks(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMGetBasicBlocks ( - void * jarg1 - , - - void * jarg2 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMBasicBlockRef *arg2 = (LLVMBasicBlockRef *) 0 ; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMBasicBlockRef *)jarg2; - - LLVMGetBasicBlocks(arg1,arg2); - - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetFirstBasicBlock ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMBasicBlockRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMBasicBlockRef)LLVMGetFirstBasicBlock(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetLastBasicBlock ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMBasicBlockRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMBasicBlockRef)LLVMGetLastBasicBlock(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetNextBasicBlock ( - void * jarg1 - ) -{ - void * jresult ; - LLVMBasicBlockRef arg1 = (LLVMBasicBlockRef) 0 ; - LLVMBasicBlockRef result; - - arg1 = (LLVMBasicBlockRef)jarg1; - - result = (LLVMBasicBlockRef)LLVMGetNextBasicBlock(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetPreviousBasicBlock ( - void * jarg1 - ) -{ - void * jresult ; - LLVMBasicBlockRef arg1 = (LLVMBasicBlockRef) 0 ; - LLVMBasicBlockRef result; - - arg1 = (LLVMBasicBlockRef)jarg1; - - result = (LLVMBasicBlockRef)LLVMGetPreviousBasicBlock(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetEntryBasicBlock ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMBasicBlockRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMBasicBlockRef)LLVMGetEntryBasicBlock(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMAppendBasicBlock ( - void * jarg1 - , - - char * jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - char *arg2 = (char *) 0 ; - LLVMBasicBlockRef result; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = jarg2; - - result = (LLVMBasicBlockRef)LLVMAppendBasicBlock(arg1,(char const *)arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMInsertBasicBlock ( - void * jarg1 - , - - char * jarg2 - ) -{ - void * jresult ; - LLVMBasicBlockRef arg1 = (LLVMBasicBlockRef) 0 ; - char *arg2 = (char *) 0 ; - LLVMBasicBlockRef result; - - arg1 = (LLVMBasicBlockRef)jarg1; - - arg2 = jarg2; - - result = (LLVMBasicBlockRef)LLVMInsertBasicBlock(arg1,(char const *)arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMDeleteBasicBlock ( - void * jarg1 - ) -{ - LLVMBasicBlockRef arg1 = (LLVMBasicBlockRef) 0 ; - - arg1 = (LLVMBasicBlockRef)jarg1; - - LLVMDeleteBasicBlock(arg1); - - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetInstructionParent ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMBasicBlockRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMBasicBlockRef)LLVMGetInstructionParent(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetFirstInstruction ( - void * jarg1 - ) -{ - void * jresult ; - LLVMBasicBlockRef arg1 = (LLVMBasicBlockRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBasicBlockRef)jarg1; - - result = (LLVMValueRef)LLVMGetFirstInstruction(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetLastInstruction ( - void * jarg1 - ) -{ - void * jresult ; - LLVMBasicBlockRef arg1 = (LLVMBasicBlockRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBasicBlockRef)jarg1; - - result = (LLVMValueRef)LLVMGetLastInstruction(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetNextInstruction ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMGetNextInstruction(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetPreviousInstruction ( - void * jarg1 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - result = (LLVMValueRef)LLVMGetPreviousInstruction(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMSetInstructionCallConv ( - void * jarg1 - , - - unsigned int jarg2 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - unsigned int arg2 ; - - arg1 = (LLVMValueRef)jarg1; - - - arg2 = (unsigned int) jarg2; - - - LLVMSetInstructionCallConv(arg1,arg2); - - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_LLVMGetInstructionCallConv ( - void * jarg1 - ) -{ - unsigned int jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - unsigned int result; - - arg1 = (LLVMValueRef)jarg1; - - result = (unsigned int)LLVMGetInstructionCallConv(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddInstrAttribute ( - void * jarg1 - , - - unsigned int jarg2 - , - - int jarg3 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - unsigned int arg2 ; - LLVMAttribute arg3 ; - - arg1 = (LLVMValueRef)jarg1; - - - arg2 = (unsigned int) jarg2; - - - arg3 = (LLVMAttribute) jarg3; - - LLVMAddInstrAttribute(arg1,arg2,arg3); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMRemoveInstrAttribute ( - void * jarg1 - , - - unsigned int jarg2 - , - - int jarg3 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - unsigned int arg2 ; - LLVMAttribute arg3 ; - - arg1 = (LLVMValueRef)jarg1; - - - arg2 = (unsigned int) jarg2; - - - arg3 = (LLVMAttribute) jarg3; - - LLVMRemoveInstrAttribute(arg1,arg2,arg3); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMSetInstrParamAlignment ( - void * jarg1 - , - - unsigned int jarg2 - , - - unsigned int jarg3 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - unsigned int arg2 ; - unsigned int arg3 ; - - arg1 = (LLVMValueRef)jarg1; - - - arg2 = (unsigned int) jarg2; - - - - arg3 = (unsigned int) jarg3; - - - LLVMSetInstrParamAlignment(arg1,arg2,arg3); - - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMIsTailCall ( - void * jarg1 - ) -{ - int jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - int result; - - arg1 = (LLVMValueRef)jarg1; - - result = (int)LLVMIsTailCall(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMSetTailCall ( - void * jarg1 - , - - int jarg2 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - int arg2 ; - - arg1 = (LLVMValueRef)jarg1; - - - arg2 = (int) jarg2; - - - LLVMSetTailCall(arg1,arg2); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddIncoming ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - unsigned int jarg4 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef *arg2 = (LLVMValueRef *) 0 ; - LLVMBasicBlockRef *arg3 = (LLVMBasicBlockRef *) 0 ; - unsigned int arg4 ; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef *)jarg2; - - arg3 = (LLVMBasicBlockRef *)jarg3; - - - arg4 = (unsigned int) jarg4; - - - LLVMAddIncoming(arg1,arg2,arg3,arg4); - - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_LLVMCountIncoming ( - void * jarg1 - ) -{ - unsigned int jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - unsigned int result; - - arg1 = (LLVMValueRef)jarg1; - - result = (unsigned int)LLVMCountIncoming(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetIncomingValue ( - void * jarg1 - , - - unsigned int jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - unsigned int arg2 ; - LLVMValueRef result; - - arg1 = (LLVMValueRef)jarg1; - - - arg2 = (unsigned int) jarg2; - - - result = (LLVMValueRef)LLVMGetIncomingValue(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetIncomingBlock ( - void * jarg1 - , - - unsigned int jarg2 - ) -{ - void * jresult ; - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - unsigned int arg2 ; - LLVMBasicBlockRef result; - - arg1 = (LLVMValueRef)jarg1; - - - arg2 = (unsigned int) jarg2; - - - result = (LLVMBasicBlockRef)LLVMGetIncomingBlock(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMCreateBuilder ( - ) -{ - void * jresult ; - LLVMBuilderRef result; - - result = (LLVMBuilderRef)LLVMCreateBuilder(); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMPositionBuilder ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - ) -{ - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMBasicBlockRef arg2 = (LLVMBasicBlockRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMBasicBlockRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - LLVMPositionBuilder(arg1,arg2,arg3); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMPositionBuilderBefore ( - void * jarg1 - , - - void * jarg2 - ) -{ - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - LLVMPositionBuilderBefore(arg1,arg2); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMPositionBuilderAtEnd ( - void * jarg1 - , - - void * jarg2 - ) -{ - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMBasicBlockRef arg2 = (LLVMBasicBlockRef) 0 ; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMBasicBlockRef)jarg2; - - LLVMPositionBuilderAtEnd(arg1,arg2); - - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMGetInsertBlock ( - void * jarg1 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMBasicBlockRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - result = (LLVMBasicBlockRef)LLVMGetInsertBlock(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMClearInsertionPosition ( - void * jarg1 - ) -{ - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - - arg1 = (LLVMBuilderRef)jarg1; - - LLVMClearInsertionPosition(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMInsertIntoBuilder ( - void * jarg1 - , - - void * jarg2 - ) -{ - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - LLVMInsertIntoBuilder(arg1,arg2); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMDisposeBuilder ( - void * jarg1 - ) -{ - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - - arg1 = (LLVMBuilderRef)jarg1; - - LLVMDisposeBuilder(arg1); - - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildRetVoid ( - void * jarg1 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - result = (LLVMValueRef)LLVMBuildRetVoid(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildRet ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - result = (LLVMValueRef)LLVMBuildRet(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildBr ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMBasicBlockRef arg2 = (LLVMBasicBlockRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMBasicBlockRef)jarg2; - - result = (LLVMValueRef)LLVMBuildBr(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildCondBr ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - void * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMBasicBlockRef arg3 = (LLVMBasicBlockRef) 0 ; - LLVMBasicBlockRef arg4 = (LLVMBasicBlockRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMBasicBlockRef)jarg3; - - arg4 = (LLVMBasicBlockRef)jarg4; - - result = (LLVMValueRef)LLVMBuildCondBr(arg1,arg2,arg3,arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildSwitch ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - unsigned int jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMBasicBlockRef arg3 = (LLVMBasicBlockRef) 0 ; - unsigned int arg4 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMBasicBlockRef)jarg3; - - - arg4 = (unsigned int) jarg4; - - - result = (LLVMValueRef)LLVMBuildSwitch(arg1,arg2,arg3,arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildInvoke ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - unsigned int jarg4 - , - - void * jarg5 - , - - void * jarg6 - , - - char * jarg7 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef *arg3 = (LLVMValueRef *) 0 ; - unsigned int arg4 ; - LLVMBasicBlockRef arg5 = (LLVMBasicBlockRef) 0 ; - LLVMBasicBlockRef arg6 = (LLVMBasicBlockRef) 0 ; - char *arg7 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef *)jarg3; - - - arg4 = (unsigned int) jarg4; - - - arg5 = (LLVMBasicBlockRef)jarg5; - - arg6 = (LLVMBasicBlockRef)jarg6; - - arg7 = jarg7; - - result = (LLVMValueRef)LLVMBuildInvoke(arg1,arg2,arg3,arg4,arg5,arg6,(char const *)arg7); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildUnwind ( - void * jarg1 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - result = (LLVMValueRef)LLVMBuildUnwind(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildUnreachable ( - void * jarg1 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - result = (LLVMValueRef)LLVMBuildUnreachable(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddCase ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - ) -{ - LLVMValueRef arg1 = (LLVMValueRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMBasicBlockRef arg3 = (LLVMBasicBlockRef) 0 ; - - arg1 = (LLVMValueRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMBasicBlockRef)jarg3; - - LLVMAddCase(arg1,arg2,arg3); - - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildAdd ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildAdd(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildSub ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildSub(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildMul ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildMul(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildUDiv ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildUDiv(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildSDiv ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildSDiv(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildFDiv ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildFDiv(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildURem ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildURem(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildSRem ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildSRem(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildFRem ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildFRem(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildShl ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildShl(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildLShr ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildLShr(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildAShr ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildAShr(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildAnd ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildAnd(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildOr ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildOr(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildXor ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildXor(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildNeg ( - void * jarg1 - , - - void * jarg2 - , - - char * jarg3 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - char *arg3 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = jarg3; - - result = (LLVMValueRef)LLVMBuildNeg(arg1,arg2,(char const *)arg3); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildNot ( - void * jarg1 - , - - void * jarg2 - , - - char * jarg3 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - char *arg3 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = jarg3; - - result = (LLVMValueRef)LLVMBuildNot(arg1,arg2,(char const *)arg3); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildMalloc ( - void * jarg1 - , - - void * jarg2 - , - - char * jarg3 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - char *arg3 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - arg3 = jarg3; - - result = (LLVMValueRef)LLVMBuildMalloc(arg1,arg2,(char const *)arg3); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildArrayMalloc ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildArrayMalloc(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildAlloca ( - void * jarg1 - , - - void * jarg2 - , - - char * jarg3 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - char *arg3 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - arg3 = jarg3; - - result = (LLVMValueRef)LLVMBuildAlloca(arg1,arg2,(char const *)arg3); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildArrayAlloca ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildArrayAlloca(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildFree ( - void * jarg1 - , - - void * jarg2 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - result = (LLVMValueRef)LLVMBuildFree(arg1,arg2); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildLoad ( - void * jarg1 - , - - void * jarg2 - , - - char * jarg3 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - char *arg3 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = jarg3; - - result = (LLVMValueRef)LLVMBuildLoad(arg1,arg2,(char const *)arg3); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildStore ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - result = (LLVMValueRef)LLVMBuildStore(arg1,arg2,arg3); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildGEP ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - unsigned int jarg4 - , - - char * jarg5 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef *arg3 = (LLVMValueRef *) 0 ; - unsigned int arg4 ; - char *arg5 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef *)jarg3; - - - arg4 = (unsigned int) jarg4; - - - arg5 = jarg5; - - result = (LLVMValueRef)LLVMBuildGEP(arg1,arg2,arg3,arg4,(char const *)arg5); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildTrunc ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMTypeRef arg3 = (LLVMTypeRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMTypeRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildTrunc(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildZExt ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMTypeRef arg3 = (LLVMTypeRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMTypeRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildZExt(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildSExt ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMTypeRef arg3 = (LLVMTypeRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMTypeRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildSExt(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildFPToUI ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMTypeRef arg3 = (LLVMTypeRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMTypeRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildFPToUI(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildFPToSI ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMTypeRef arg3 = (LLVMTypeRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMTypeRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildFPToSI(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildUIToFP ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMTypeRef arg3 = (LLVMTypeRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMTypeRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildUIToFP(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildSIToFP ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMTypeRef arg3 = (LLVMTypeRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMTypeRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildSIToFP(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildFPTrunc ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMTypeRef arg3 = (LLVMTypeRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMTypeRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildFPTrunc(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildFPExt ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMTypeRef arg3 = (LLVMTypeRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMTypeRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildFPExt(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildPtrToInt ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMTypeRef arg3 = (LLVMTypeRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMTypeRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildPtrToInt(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildIntToPtr ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMTypeRef arg3 = (LLVMTypeRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMTypeRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildIntToPtr(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildBitCast ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMTypeRef arg3 = (LLVMTypeRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMTypeRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildBitCast(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildICmp ( - void * jarg1 - , - - int jarg2 - , - - void * jarg3 - , - - void * jarg4 - , - - char * jarg5 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMIntPredicate arg2 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - LLVMValueRef arg4 = (LLVMValueRef) 0 ; - char *arg5 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMIntPredicate) jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = (LLVMValueRef)jarg4; - - arg5 = jarg5; - - result = (LLVMValueRef)LLVMBuildICmp(arg1,arg2,arg3,arg4,(char const *)arg5); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildFCmp ( - void * jarg1 - , - - int jarg2 - , - - void * jarg3 - , - - void * jarg4 - , - - char * jarg5 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMRealPredicate arg2 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - LLVMValueRef arg4 = (LLVMValueRef) 0 ; - char *arg5 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMRealPredicate) jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = (LLVMValueRef)jarg4; - - arg5 = jarg5; - - result = (LLVMValueRef)LLVMBuildFCmp(arg1,arg2,arg3,arg4,(char const *)arg5); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildPhi ( - void * jarg1 - , - - void * jarg2 - , - - char * jarg3 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - char *arg3 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - arg3 = jarg3; - - result = (LLVMValueRef)LLVMBuildPhi(arg1,arg2,(char const *)arg3); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildCall ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - unsigned int jarg4 - , - - char * jarg5 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef *arg3 = (LLVMValueRef *) 0 ; - unsigned int arg4 ; - char *arg5 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef *)jarg3; - - - arg4 = (unsigned int) jarg4; - - - arg5 = jarg5; - - result = (LLVMValueRef)LLVMBuildCall(arg1,arg2,arg3,arg4,(char const *)arg5); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildSelect ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - void * jarg4 - , - - char * jarg5 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - LLVMValueRef arg4 = (LLVMValueRef) 0 ; - char *arg5 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = (LLVMValueRef)jarg4; - - arg5 = jarg5; - - result = (LLVMValueRef)LLVMBuildSelect(arg1,arg2,arg3,arg4,(char const *)arg5); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildVAArg ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMTypeRef arg3 = (LLVMTypeRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMTypeRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildVAArg(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildExtractElement ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildExtractElement(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildInsertElement ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - void * jarg4 - , - - char * jarg5 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - LLVMValueRef arg4 = (LLVMValueRef) 0 ; - char *arg5 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = (LLVMValueRef)jarg4; - - arg5 = jarg5; - - result = (LLVMValueRef)LLVMBuildInsertElement(arg1,arg2,arg3,arg4,(char const *)arg5); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildShuffleVector ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - void * jarg4 - , - - char * jarg5 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - LLVMValueRef arg4 = (LLVMValueRef) 0 ; - char *arg5 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - arg4 = (LLVMValueRef)jarg4; - - arg5 = jarg5; - - result = (LLVMValueRef)LLVMBuildShuffleVector(arg1,arg2,arg3,arg4,(char const *)arg5); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildExtractValue ( - void * jarg1 - , - - void * jarg2 - , - - unsigned int jarg3 - , - - char * jarg4 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - unsigned int arg3 ; - char *arg4 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - - arg3 = (unsigned int) jarg3; - - - arg4 = jarg4; - - result = (LLVMValueRef)LLVMBuildExtractValue(arg1,arg2,arg3,(char const *)arg4); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMBuildInsertValue ( - void * jarg1 - , - - void * jarg2 - , - - void * jarg3 - , - - unsigned int jarg4 - , - - char * jarg5 - ) -{ - void * jresult ; - LLVMBuilderRef arg1 = (LLVMBuilderRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - LLVMValueRef arg3 = (LLVMValueRef) 0 ; - unsigned int arg4 ; - char *arg5 = (char *) 0 ; - LLVMValueRef result; - - arg1 = (LLVMBuilderRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - arg3 = (LLVMValueRef)jarg3; - - - arg4 = (unsigned int) jarg4; - - - arg5 = jarg5; - - result = (LLVMValueRef)LLVMBuildInsertValue(arg1,arg2,arg3,arg4,(char const *)arg5); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMCreateModuleProviderForExistingModule ( - void * jarg1 - ) -{ - void * jresult ; - LLVMModuleRef arg1 = (LLVMModuleRef) 0 ; - LLVMModuleProviderRef result; - - arg1 = (LLVMModuleRef)jarg1; - - result = (LLVMModuleProviderRef)LLVMCreateModuleProviderForExistingModule(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMDisposeModuleProvider ( - void * jarg1 - ) -{ - LLVMModuleProviderRef arg1 = (LLVMModuleProviderRef) 0 ; - - arg1 = (LLVMModuleProviderRef)jarg1; - - LLVMDisposeModuleProvider(arg1); - - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMCreateMemoryBufferWithContentsOfFile ( - char * jarg1 - , - - void * jarg2 - , - - void * jarg3 - ) -{ - int jresult ; - char *arg1 = (char *) 0 ; - LLVMMemoryBufferRef *arg2 = (LLVMMemoryBufferRef *) 0 ; - char **arg3 = (char **) 0 ; - int result; - - arg1 = jarg1; - - arg2 = (LLVMMemoryBufferRef *)jarg2; - - arg3 = (char **)jarg3; - - result = (int)LLVMCreateMemoryBufferWithContentsOfFile((char const *)arg1,arg2,arg3); - jresult = result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMCreateMemoryBufferWithSTDIN ( - void * jarg1 - , - - void * jarg2 - ) -{ - int jresult ; - LLVMMemoryBufferRef *arg1 = (LLVMMemoryBufferRef *) 0 ; - char **arg2 = (char **) 0 ; - int result; - - arg1 = (LLVMMemoryBufferRef *)jarg1; - - arg2 = (char **)jarg2; - - result = (int)LLVMCreateMemoryBufferWithSTDIN(arg1,arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMDisposeMemoryBuffer ( - void * jarg1 - ) -{ - LLVMMemoryBufferRef arg1 = (LLVMMemoryBufferRef) 0 ; - - arg1 = (LLVMMemoryBufferRef)jarg1; - - LLVMDisposeMemoryBuffer(arg1); - - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMCreatePassManager ( - ) -{ - void * jresult ; - LLVMPassManagerRef result; - - result = (LLVMPassManagerRef)LLVMCreatePassManager(); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMCreateFunctionPassManager ( - void * jarg1 - ) -{ - void * jresult ; - LLVMModuleProviderRef arg1 = (LLVMModuleProviderRef) 0 ; - LLVMPassManagerRef result; - - arg1 = (LLVMModuleProviderRef)jarg1; - - result = (LLVMPassManagerRef)LLVMCreateFunctionPassManager(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMRunPassManager ( - void * jarg1 - , - - void * jarg2 - ) -{ - int jresult ; - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - LLVMModuleRef arg2 = (LLVMModuleRef) 0 ; - int result; - - arg1 = (LLVMPassManagerRef)jarg1; - - arg2 = (LLVMModuleRef)jarg2; - - result = (int)LLVMRunPassManager(arg1,arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMInitializeFunctionPassManager ( - void * jarg1 - ) -{ - int jresult ; - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - int result; - - arg1 = (LLVMPassManagerRef)jarg1; - - result = (int)LLVMInitializeFunctionPassManager(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMRunFunctionPassManager ( - void * jarg1 - , - - void * jarg2 - ) -{ - int jresult ; - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - int result; - - arg1 = (LLVMPassManagerRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - result = (int)LLVMRunFunctionPassManager(arg1,arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMFinalizeFunctionPassManager ( - void * jarg1 - ) -{ - int jresult ; - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - int result; - - arg1 = (LLVMPassManagerRef)jarg1; - - result = (int)LLVMFinalizeFunctionPassManager(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMDisposePassManager ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMDisposePassManager(arg1); - - -} - - - -#ifdef __cplusplus -} -#endif -#ifdef __cplusplus -extern "C" { -#endif -#ifdef __cplusplus -} -#endif - diff --git a/bindings/ada/target/llvm_target-binding.ads b/bindings/ada/target/llvm_target-binding.ads deleted file mode 100644 index 61201c8d1753..000000000000 --- a/bindings/ada/target/llvm_target-binding.ads +++ /dev/null @@ -1,138 +0,0 @@ --- This file is generated by SWIG. Do *not* modify by hand. --- - -with llvm; -with Interfaces.C.Strings; - - -package LLVM_Target.Binding is - - LLVMBigEndian : constant := 0; - LLVMLittleEndian : constant := 1; - - procedure LLVMInitializeAllTargets; - - function LLVMInitializeNativeTarget return Interfaces.C.int; - - function LLVMCreateTargetData - (StringRep : in Interfaces.C.Strings.chars_ptr) - return LLVM_Target.LLVMTargetDataRef; - - procedure LLVMAddTargetData - (arg_2_1 : in LLVM_Target.LLVMTargetDataRef; - arg_2_2 : in llvm.LLVMPassManagerRef); - - function LLVMCopyStringRepOfTargetData - (arg_1 : in LLVM_Target.LLVMTargetDataRef) - return Interfaces.C.Strings.chars_ptr; - - function LLVMByteOrder - (arg_1 : in LLVM_Target.LLVMTargetDataRef) - return LLVM_Target.LLVMByteOrdering; - - function LLVMPointerSize - (arg_1 : in LLVM_Target.LLVMTargetDataRef) - return Interfaces.C.unsigned; - - function LLVMIntPtrType - (arg_1 : in LLVM_Target.LLVMTargetDataRef) - return llvm.LLVMTypeRef; - - function LLVMSizeOfTypeInBits - (arg_2_1 : in LLVM_Target.LLVMTargetDataRef; - arg_2_2 : in llvm.LLVMTypeRef) - return Interfaces.C.Extensions.unsigned_long_long; - - function LLVMStoreSizeOfType - (arg_2_1 : in LLVM_Target.LLVMTargetDataRef; - arg_2_2 : in llvm.LLVMTypeRef) - return Interfaces.C.Extensions.unsigned_long_long; - - function LLVMABISizeOfType - (arg_2_1 : in LLVM_Target.LLVMTargetDataRef; - arg_2_2 : in llvm.LLVMTypeRef) - return Interfaces.C.Extensions.unsigned_long_long; - - function LLVMABIAlignmentOfType - (arg_2_1 : in LLVM_Target.LLVMTargetDataRef; - arg_2_2 : in llvm.LLVMTypeRef) - return Interfaces.C.unsigned; - - function LLVMCallFrameAlignmentOfType - (arg_2_1 : in LLVM_Target.LLVMTargetDataRef; - arg_2_2 : in llvm.LLVMTypeRef) - return Interfaces.C.unsigned; - - function LLVMPreferredAlignmentOfType - (arg_2_1 : in LLVM_Target.LLVMTargetDataRef; - arg_2_2 : in llvm.LLVMTypeRef) - return Interfaces.C.unsigned; - - function LLVMPreferredAlignmentOfGlobal - (arg_1 : in LLVM_Target.LLVMTargetDataRef; - GlobalVar : in llvm.LLVMValueRef) - return Interfaces.C.unsigned; - - function LLVMElementAtOffset - (arg_1 : in LLVM_Target.LLVMTargetDataRef; - StructTy : in llvm.LLVMTypeRef; - Offset : in Interfaces.C.Extensions.unsigned_long_long) - return Interfaces.C.unsigned; - - function LLVMOffsetOfElement - (arg_1 : in LLVM_Target.LLVMTargetDataRef; - StructTy : in llvm.LLVMTypeRef; - Element : in Interfaces.C.unsigned) - return Interfaces.C.Extensions.unsigned_long_long; - - procedure LLVMInvalidateStructLayout - (arg_1 : in LLVM_Target.LLVMTargetDataRef; - StructTy : in llvm.LLVMTypeRef); - - procedure LLVMDisposeTargetData - (arg_1 : in LLVM_Target.LLVMTargetDataRef); - -private - - pragma Import - (C, - LLVMInitializeAllTargets, - "Ada_LLVMInitializeAllTargets"); - pragma Import - (C, - LLVMInitializeNativeTarget, - "Ada_LLVMInitializeNativeTarget"); - pragma Import (C, LLVMCreateTargetData, "Ada_LLVMCreateTargetData"); - pragma Import (C, LLVMAddTargetData, "Ada_LLVMAddTargetData"); - pragma Import - (C, - LLVMCopyStringRepOfTargetData, - "Ada_LLVMCopyStringRepOfTargetData"); - pragma Import (C, LLVMByteOrder, "Ada_LLVMByteOrder"); - pragma Import (C, LLVMPointerSize, "Ada_LLVMPointerSize"); - pragma Import (C, LLVMIntPtrType, "Ada_LLVMIntPtrType"); - pragma Import (C, LLVMSizeOfTypeInBits, "Ada_LLVMSizeOfTypeInBits"); - pragma Import (C, LLVMStoreSizeOfType, "Ada_LLVMStoreSizeOfType"); - pragma Import (C, LLVMABISizeOfType, "Ada_LLVMABISizeOfType"); - pragma Import (C, LLVMABIAlignmentOfType, "Ada_LLVMABIAlignmentOfType"); - pragma Import - (C, - LLVMCallFrameAlignmentOfType, - "Ada_LLVMCallFrameAlignmentOfType"); - pragma Import - (C, - LLVMPreferredAlignmentOfType, - "Ada_LLVMPreferredAlignmentOfType"); - pragma Import - (C, - LLVMPreferredAlignmentOfGlobal, - "Ada_LLVMPreferredAlignmentOfGlobal"); - pragma Import (C, LLVMElementAtOffset, "Ada_LLVMElementAtOffset"); - pragma Import (C, LLVMOffsetOfElement, "Ada_LLVMOffsetOfElement"); - pragma Import - (C, - LLVMInvalidateStructLayout, - "Ada_LLVMInvalidateStructLayout"); - pragma Import (C, LLVMDisposeTargetData, "Ada_LLVMDisposeTargetData"); - -end LLVM_Target.Binding; diff --git a/bindings/ada/target/llvm_target.ads b/bindings/ada/target/llvm_target.ads deleted file mode 100644 index 11cb05d55b35..000000000000 --- a/bindings/ada/target/llvm_target.ads +++ /dev/null @@ -1,72 +0,0 @@ --- This file is generated by SWIG. Do *not* modify by hand. --- - -with Interfaces.C.Extensions; - - -package LLVM_Target is - - -- LLVMOpaqueTargetData - -- - type LLVMOpaqueTargetData is new - Interfaces.C.Extensions.opaque_structure_def; - - type LLVMOpaqueTargetData_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_Target.LLVMOpaqueTargetData; - - type LLVMOpaqueTargetData_view is access all - LLVM_Target.LLVMOpaqueTargetData; - - -- LLVMTargetDataRef - -- - type LLVMTargetDataRef is access all LLVM_Target.LLVMOpaqueTargetData; - - type LLVMTargetDataRef_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_Target.LLVMTargetDataRef; - - type LLVMTargetDataRef_view is access all LLVM_Target.LLVMTargetDataRef; - - -- LLVMStructLayout - -- - type LLVMStructLayout is new Interfaces.C.Extensions.opaque_structure_def; - - type LLVMStructLayout_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_Target.LLVMStructLayout; - - type LLVMStructLayout_view is access all LLVM_Target.LLVMStructLayout; - - -- LLVMStructLayoutRef - -- - type LLVMStructLayoutRef is access all LLVM_Target.LLVMStructLayout; - - type LLVMStructLayoutRef_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_Target.LLVMStructLayoutRef; - - type LLVMStructLayoutRef_view is access all LLVM_Target.LLVMStructLayoutRef; - - -- TargetData - -- - type TargetData is new Interfaces.C.Extensions.incomplete_class_def; - - type TargetData_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_Target.TargetData; - - type TargetData_view is access all LLVM_Target.TargetData; - - -- LLVMByteOrdering - -- - type LLVMByteOrdering is new Interfaces.C.int; - - type LLVMByteOrdering_array is - array (Interfaces.C.size_t range <>) - of aliased LLVM_Target.LLVMByteOrdering; - - type LLVMByteOrdering_view is access all LLVM_Target.LLVMByteOrdering; - - -end LLVM_Target; diff --git a/bindings/ada/target/llvm_target_wrap.cxx b/bindings/ada/target/llvm_target_wrap.cxx deleted file mode 100644 index 16aca8a4379a..000000000000 --- a/bindings/ada/target/llvm_target_wrap.cxx +++ /dev/null @@ -1,720 +0,0 @@ -/* ---------------------------------------------------------------------------- - * This file was automatically generated by SWIG (http://www.swig.org). - * Version 1.3.36 - * - * This file is not intended to be easily readable and contains a number of - * coding conventions designed to improve portability and efficiency. Do not make - * changes to this file unless you know what you are doing--modify the SWIG - * interface file instead. - * ----------------------------------------------------------------------------- */ - - -#ifdef __cplusplus -template class SwigValueWrapper { - T *tt; -public: - SwigValueWrapper() : tt(0) { } - SwigValueWrapper(const SwigValueWrapper& rhs) : tt(new T(*rhs.tt)) { } - SwigValueWrapper(const T& t) : tt(new T(t)) { } - ~SwigValueWrapper() { delete tt; } - SwigValueWrapper& operator=(const T& t) { delete tt; tt = new T(t); return *this; } - operator T&() const { return *tt; } - T *operator&() { return tt; } -private: - SwigValueWrapper& operator=(const SwigValueWrapper& rhs); -}; - -template T SwigValueInit() { - return T(); -} -#endif - -/* ----------------------------------------------------------------------------- - * This section contains generic SWIG labels for method/variable - * declarations/attributes, and other compiler dependent labels. - * ----------------------------------------------------------------------------- */ - -/* template workaround for compilers that cannot correctly implement the C++ standard */ -#ifndef SWIGTEMPLATEDISAMBIGUATOR -# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) -# define SWIGTEMPLATEDISAMBIGUATOR template -# elif defined(__HP_aCC) -/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ -/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ -# define SWIGTEMPLATEDISAMBIGUATOR template -# else -# define SWIGTEMPLATEDISAMBIGUATOR -# endif -#endif - -/* inline attribute */ -#ifndef SWIGINLINE -# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) -# define SWIGINLINE inline -# else -# define SWIGINLINE -# endif -#endif - -/* attribute recognised by some compilers to avoid 'unused' warnings */ -#ifndef SWIGUNUSED -# if defined(__GNUC__) -# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -# elif defined(__ICC) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -#endif - -#ifndef SWIGUNUSEDPARM -# ifdef __cplusplus -# define SWIGUNUSEDPARM(p) -# else -# define SWIGUNUSEDPARM(p) p SWIGUNUSED -# endif -#endif - -/* internal SWIG method */ -#ifndef SWIGINTERN -# define SWIGINTERN static SWIGUNUSED -#endif - -/* internal inline SWIG method */ -#ifndef SWIGINTERNINLINE -# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE -#endif - -/* exporting methods */ -#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -# ifndef GCC_HASCLASSVISIBILITY -# define GCC_HASCLASSVISIBILITY -# endif -#endif - -#ifndef SWIGEXPORT -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# if defined(STATIC_LINKED) -# define SWIGEXPORT -# else -# define SWIGEXPORT __declspec(dllexport) -# endif -# else -# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) -# define SWIGEXPORT __attribute__ ((visibility("default"))) -# else -# define SWIGEXPORT -# endif -# endif -#endif - -/* calling conventions for Windows */ -#ifndef SWIGSTDCALL -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# define SWIGSTDCALL __stdcall -# else -# define SWIGSTDCALL -# endif -#endif - -/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ -#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) -# define _CRT_SECURE_NO_DEPRECATE -#endif - -/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ -#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) -# define _SCL_SECURE_NO_DEPRECATE -#endif - - - -#include -#include -#include -#if defined(_WIN32) || defined(__CYGWIN32__) -# define DllExport __declspec( dllexport ) -# define SWIGSTDCALL __stdcall -#else -# define DllExport -# define SWIGSTDCALL -#endif - - -#ifdef __cplusplus -# include -#endif - - - - -/* Support for throwing Ada exceptions from C/C++ */ - -typedef enum -{ - SWIG_AdaException, - SWIG_AdaOutOfMemoryException, - SWIG_AdaIndexOutOfRangeException, - SWIG_AdaDivideByZeroException, - SWIG_AdaArgumentOutOfRangeException, - SWIG_AdaNullReferenceException -} SWIG_AdaExceptionCodes; - - -typedef void (SWIGSTDCALL* SWIG_AdaExceptionCallback_t)(const char *); - - -typedef struct -{ - SWIG_AdaExceptionCodes code; - SWIG_AdaExceptionCallback_t callback; -} - SWIG_AdaExceptions_t; - - -static -SWIG_AdaExceptions_t -SWIG_ada_exceptions[] = -{ - { SWIG_AdaException, NULL }, - { SWIG_AdaOutOfMemoryException, NULL }, - { SWIG_AdaIndexOutOfRangeException, NULL }, - { SWIG_AdaDivideByZeroException, NULL }, - { SWIG_AdaArgumentOutOfRangeException, NULL }, - { SWIG_AdaNullReferenceException, NULL } -}; - - -static -void -SWIG_AdaThrowException (SWIG_AdaExceptionCodes code, const char *msg) -{ - SWIG_AdaExceptionCallback_t callback = SWIG_ada_exceptions[SWIG_AdaException].callback; - if (code >=0 && (size_t)code < sizeof(SWIG_ada_exceptions)/sizeof(SWIG_AdaExceptions_t)) { - callback = SWIG_ada_exceptions[code].callback; - } - callback(msg); -} - - - -#ifdef __cplusplus -extern "C" -#endif - -DllExport void SWIGSTDCALL SWIGRegisterExceptionCallbacks_LLVM_Target (SWIG_AdaExceptionCallback_t systemException, - SWIG_AdaExceptionCallback_t outOfMemory, - SWIG_AdaExceptionCallback_t indexOutOfRange, - SWIG_AdaExceptionCallback_t divideByZero, - SWIG_AdaExceptionCallback_t argumentOutOfRange, - SWIG_AdaExceptionCallback_t nullReference) -{ - SWIG_ada_exceptions [SWIG_AdaException].callback = systemException; - SWIG_ada_exceptions [SWIG_AdaOutOfMemoryException].callback = outOfMemory; - SWIG_ada_exceptions [SWIG_AdaIndexOutOfRangeException].callback = indexOutOfRange; - SWIG_ada_exceptions [SWIG_AdaDivideByZeroException].callback = divideByZero; - SWIG_ada_exceptions [SWIG_AdaArgumentOutOfRangeException].callback = argumentOutOfRange; - SWIG_ada_exceptions [SWIG_AdaNullReferenceException].callback = nullReference; -} - - -/* Callback for returning strings to Ada without leaking memory */ - -typedef char * (SWIGSTDCALL* SWIG_AdaStringHelperCallback)(const char *); -static SWIG_AdaStringHelperCallback SWIG_ada_string_callback = NULL; - - - -/* probably obsolete ... -#ifdef __cplusplus -extern "C" -#endif -DllExport void SWIGSTDCALL SWIGRegisterStringCallback_LLVM_Target(SWIG_AdaStringHelperCallback callback) { - SWIG_ada_string_callback = callback; -} -*/ - - - -/* Contract support */ - -#define SWIG_contract_assert(nullreturn, expr, msg) if (!(expr)) {SWIG_AdaThrowException(SWIG_AdaArgumentOutOfRangeException, msg); return nullreturn; } else - - -#define protected public -#define private public - -#include "llvm-c/Target.h" - - - -// struct LLVMCtxt; - - -#undef protected -#undef private -#ifdef __cplusplus -extern "C" { -#endif -DllExport void SWIGSTDCALL Ada_LLVMInitializeAllTargets ( - ) -{ - LLVMInitializeAllTargets(); - - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMInitializeNativeTarget ( - ) -{ - int jresult ; - int result; - - result = (int)LLVMInitializeNativeTarget(); - jresult = result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMCreateTargetData ( - char * jarg1 - ) -{ - void * jresult ; - char *arg1 = (char *) 0 ; - LLVMTargetDataRef result; - - arg1 = jarg1; - - result = (LLVMTargetDataRef)LLVMCreateTargetData((char const *)arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddTargetData ( - void * jarg1 - , - - void * jarg2 - ) -{ - LLVMTargetDataRef arg1 = (LLVMTargetDataRef) 0 ; - LLVMPassManagerRef arg2 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMTargetDataRef)jarg1; - - arg2 = (LLVMPassManagerRef)jarg2; - - LLVMAddTargetData(arg1,arg2); - - -} - - - -DllExport char * SWIGSTDCALL Ada_LLVMCopyStringRepOfTargetData ( - void * jarg1 - ) -{ - char * jresult ; - LLVMTargetDataRef arg1 = (LLVMTargetDataRef) 0 ; - char *result = 0 ; - - arg1 = (LLVMTargetDataRef)jarg1; - - result = (char *)LLVMCopyStringRepOfTargetData(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport int SWIGSTDCALL Ada_LLVMByteOrder ( - void * jarg1 - ) -{ - int jresult ; - LLVMTargetDataRef arg1 = (LLVMTargetDataRef) 0 ; - LLVMByteOrdering result; - - arg1 = (LLVMTargetDataRef)jarg1; - - result = (LLVMByteOrdering)LLVMByteOrder(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_LLVMPointerSize ( - void * jarg1 - ) -{ - unsigned int jresult ; - LLVMTargetDataRef arg1 = (LLVMTargetDataRef) 0 ; - unsigned int result; - - arg1 = (LLVMTargetDataRef)jarg1; - - result = (unsigned int)LLVMPointerSize(arg1); - jresult = result; - - - - return jresult; - -} - - - -DllExport void * SWIGSTDCALL Ada_LLVMIntPtrType ( - void * jarg1 - ) -{ - void * jresult ; - LLVMTargetDataRef arg1 = (LLVMTargetDataRef) 0 ; - LLVMTypeRef result; - - arg1 = (LLVMTargetDataRef)jarg1; - - result = (LLVMTypeRef)LLVMIntPtrType(arg1); - jresult = (void *) result; - - - - return jresult; - -} - - - -DllExport unsigned long long SWIGSTDCALL Ada_LLVMSizeOfTypeInBits ( - void * jarg1 - , - - void * jarg2 - ) -{ - unsigned long long jresult ; - LLVMTargetDataRef arg1 = (LLVMTargetDataRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - unsigned long long result; - - arg1 = (LLVMTargetDataRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - result = (unsigned long long)LLVMSizeOfTypeInBits(arg1,arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport unsigned long long SWIGSTDCALL Ada_LLVMStoreSizeOfType ( - void * jarg1 - , - - void * jarg2 - ) -{ - unsigned long long jresult ; - LLVMTargetDataRef arg1 = (LLVMTargetDataRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - unsigned long long result; - - arg1 = (LLVMTargetDataRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - result = (unsigned long long)LLVMStoreSizeOfType(arg1,arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport unsigned long long SWIGSTDCALL Ada_LLVMABISizeOfType ( - void * jarg1 - , - - void * jarg2 - ) -{ - unsigned long long jresult ; - LLVMTargetDataRef arg1 = (LLVMTargetDataRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - unsigned long long result; - - arg1 = (LLVMTargetDataRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - result = (unsigned long long)LLVMABISizeOfType(arg1,arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_LLVMABIAlignmentOfType ( - void * jarg1 - , - - void * jarg2 - ) -{ - unsigned int jresult ; - LLVMTargetDataRef arg1 = (LLVMTargetDataRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - unsigned int result; - - arg1 = (LLVMTargetDataRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - result = (unsigned int)LLVMABIAlignmentOfType(arg1,arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_LLVMCallFrameAlignmentOfType ( - void * jarg1 - , - - void * jarg2 - ) -{ - unsigned int jresult ; - LLVMTargetDataRef arg1 = (LLVMTargetDataRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - unsigned int result; - - arg1 = (LLVMTargetDataRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - result = (unsigned int)LLVMCallFrameAlignmentOfType(arg1,arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_LLVMPreferredAlignmentOfType ( - void * jarg1 - , - - void * jarg2 - ) -{ - unsigned int jresult ; - LLVMTargetDataRef arg1 = (LLVMTargetDataRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - unsigned int result; - - arg1 = (LLVMTargetDataRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - result = (unsigned int)LLVMPreferredAlignmentOfType(arg1,arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_LLVMPreferredAlignmentOfGlobal ( - void * jarg1 - , - - void * jarg2 - ) -{ - unsigned int jresult ; - LLVMTargetDataRef arg1 = (LLVMTargetDataRef) 0 ; - LLVMValueRef arg2 = (LLVMValueRef) 0 ; - unsigned int result; - - arg1 = (LLVMTargetDataRef)jarg1; - - arg2 = (LLVMValueRef)jarg2; - - result = (unsigned int)LLVMPreferredAlignmentOfGlobal(arg1,arg2); - jresult = result; - - - - return jresult; - -} - - - -DllExport unsigned int SWIGSTDCALL Ada_LLVMElementAtOffset ( - void * jarg1 - , - - void * jarg2 - , - - unsigned long long jarg3 - ) -{ - unsigned int jresult ; - LLVMTargetDataRef arg1 = (LLVMTargetDataRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - unsigned long long arg3 ; - unsigned int result; - - arg1 = (LLVMTargetDataRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - - arg3 = (unsigned long long) jarg3; - - - result = (unsigned int)LLVMElementAtOffset(arg1,arg2,arg3); - jresult = result; - - - - return jresult; - -} - - - -DllExport unsigned long long SWIGSTDCALL Ada_LLVMOffsetOfElement ( - void * jarg1 - , - - void * jarg2 - , - - unsigned int jarg3 - ) -{ - unsigned long long jresult ; - LLVMTargetDataRef arg1 = (LLVMTargetDataRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - unsigned int arg3 ; - unsigned long long result; - - arg1 = (LLVMTargetDataRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - - arg3 = (unsigned int) jarg3; - - - result = (unsigned long long)LLVMOffsetOfElement(arg1,arg2,arg3); - jresult = result; - - - - return jresult; - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMInvalidateStructLayout ( - void * jarg1 - , - - void * jarg2 - ) -{ - LLVMTargetDataRef arg1 = (LLVMTargetDataRef) 0 ; - LLVMTypeRef arg2 = (LLVMTypeRef) 0 ; - - arg1 = (LLVMTargetDataRef)jarg1; - - arg2 = (LLVMTypeRef)jarg2; - - LLVMInvalidateStructLayout(arg1,arg2); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMDisposeTargetData ( - void * jarg1 - ) -{ - LLVMTargetDataRef arg1 = (LLVMTargetDataRef) 0 ; - - arg1 = (LLVMTargetDataRef)jarg1; - - LLVMDisposeTargetData(arg1); - - -} - - - -#ifdef __cplusplus -} -#endif -#ifdef __cplusplus -extern "C" { -#endif -#ifdef __cplusplus -} -#endif - diff --git a/bindings/ada/transforms/llvm_transforms-binding.ads b/bindings/ada/transforms/llvm_transforms-binding.ads deleted file mode 100644 index 2254b6eec2c3..000000000000 --- a/bindings/ada/transforms/llvm_transforms-binding.ads +++ /dev/null @@ -1,206 +0,0 @@ --- This file is generated by SWIG. Do *not* modify by hand. --- - -with llvm; - - -package LLVM_Transforms.Binding is - - procedure LLVMAddArgumentPromotionPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddConstantMergePass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddDeadArgEliminationPass - (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddDeadTypeEliminationPass - (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddFunctionAttrsPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddFunctionInliningPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddGlobalDCEPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddGlobalOptimizerPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddIPConstantPropagationPass - (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddLowerSetJmpPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddPruneEHPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddRaiseAllocationsPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddStripDeadPrototypesPass - (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddStripSymbolsPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddAggressiveDCEPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddCFGSimplificationPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddCondPropagationPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddDeadStoreEliminationPass - (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddGVNPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddIndVarSimplifyPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddInstructionCombiningPass - (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddJumpThreadingPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddLICMPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddLoopDeletionPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddLoopIndexSplitPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddLoopRotatePass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddLoopUnrollPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddLoopUnswitchPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddMemCpyOptPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddPromoteMemoryToRegisterPass - (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddReassociatePass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddSCCPPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddScalarReplAggregatesPass - (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddSimplifyLibCallsPass (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddTailCallEliminationPass - (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddConstantPropagationPass - (PM : in llvm.LLVMPassManagerRef); - - procedure LLVMAddDemoteMemoryToRegisterPass - (PM : in llvm.LLVMPassManagerRef); - -private - - pragma Import - (C, - LLVMAddArgumentPromotionPass, - "Ada_LLVMAddArgumentPromotionPass"); - pragma Import - (C, - LLVMAddConstantMergePass, - "Ada_LLVMAddConstantMergePass"); - pragma Import - (C, - LLVMAddDeadArgEliminationPass, - "Ada_LLVMAddDeadArgEliminationPass"); - pragma Import - (C, - LLVMAddDeadTypeEliminationPass, - "Ada_LLVMAddDeadTypeEliminationPass"); - pragma Import - (C, - LLVMAddFunctionAttrsPass, - "Ada_LLVMAddFunctionAttrsPass"); - pragma Import - (C, - LLVMAddFunctionInliningPass, - "Ada_LLVMAddFunctionInliningPass"); - pragma Import (C, LLVMAddGlobalDCEPass, "Ada_LLVMAddGlobalDCEPass"); - pragma Import - (C, - LLVMAddGlobalOptimizerPass, - "Ada_LLVMAddGlobalOptimizerPass"); - pragma Import - (C, - LLVMAddIPConstantPropagationPass, - "Ada_LLVMAddIPConstantPropagationPass"); - pragma Import (C, LLVMAddLowerSetJmpPass, "Ada_LLVMAddLowerSetJmpPass"); - pragma Import (C, LLVMAddPruneEHPass, "Ada_LLVMAddPruneEHPass"); - pragma Import - (C, - LLVMAddRaiseAllocationsPass, - "Ada_LLVMAddRaiseAllocationsPass"); - pragma Import - (C, - LLVMAddStripDeadPrototypesPass, - "Ada_LLVMAddStripDeadPrototypesPass"); - pragma Import (C, LLVMAddStripSymbolsPass, "Ada_LLVMAddStripSymbolsPass"); - pragma Import - (C, - LLVMAddAggressiveDCEPass, - "Ada_LLVMAddAggressiveDCEPass"); - pragma Import - (C, - LLVMAddCFGSimplificationPass, - "Ada_LLVMAddCFGSimplificationPass"); - pragma Import - (C, - LLVMAddCondPropagationPass, - "Ada_LLVMAddCondPropagationPass"); - pragma Import - (C, - LLVMAddDeadStoreEliminationPass, - "Ada_LLVMAddDeadStoreEliminationPass"); - pragma Import (C, LLVMAddGVNPass, "Ada_LLVMAddGVNPass"); - pragma Import - (C, - LLVMAddIndVarSimplifyPass, - "Ada_LLVMAddIndVarSimplifyPass"); - pragma Import - (C, - LLVMAddInstructionCombiningPass, - "Ada_LLVMAddInstructionCombiningPass"); - pragma Import - (C, - LLVMAddJumpThreadingPass, - "Ada_LLVMAddJumpThreadingPass"); - pragma Import (C, LLVMAddLICMPass, "Ada_LLVMAddLICMPass"); - pragma Import (C, LLVMAddLoopDeletionPass, "Ada_LLVMAddLoopDeletionPass"); - pragma Import - (C, - LLVMAddLoopIndexSplitPass, - "Ada_LLVMAddLoopIndexSplitPass"); - pragma Import (C, LLVMAddLoopRotatePass, "Ada_LLVMAddLoopRotatePass"); - pragma Import (C, LLVMAddLoopUnrollPass, "Ada_LLVMAddLoopUnrollPass"); - pragma Import (C, LLVMAddLoopUnswitchPass, "Ada_LLVMAddLoopUnswitchPass"); - pragma Import (C, LLVMAddMemCpyOptPass, "Ada_LLVMAddMemCpyOptPass"); - pragma Import - (C, - LLVMAddPromoteMemoryToRegisterPass, - "Ada_LLVMAddPromoteMemoryToRegisterPass"); - pragma Import (C, LLVMAddReassociatePass, "Ada_LLVMAddReassociatePass"); - pragma Import (C, LLVMAddSCCPPass, "Ada_LLVMAddSCCPPass"); - pragma Import - (C, - LLVMAddScalarReplAggregatesPass, - "Ada_LLVMAddScalarReplAggregatesPass"); - pragma Import - (C, - LLVMAddSimplifyLibCallsPass, - "Ada_LLVMAddSimplifyLibCallsPass"); - pragma Import - (C, - LLVMAddTailCallEliminationPass, - "Ada_LLVMAddTailCallEliminationPass"); - pragma Import - (C, - LLVMAddConstantPropagationPass, - "Ada_LLVMAddConstantPropagationPass"); - pragma Import - (C, - LLVMAddDemoteMemoryToRegisterPass, - "Ada_LLVMAddDemoteMemoryToRegisterPass"); - -end LLVM_Transforms.Binding; diff --git a/bindings/ada/transforms/llvm_transforms.ads b/bindings/ada/transforms/llvm_transforms.ads deleted file mode 100644 index 4f37aafe805c..000000000000 --- a/bindings/ada/transforms/llvm_transforms.ads +++ /dev/null @@ -1,6 +0,0 @@ --- This file is generated by SWIG. Do *not* modify by hand. --- - -package LLVM_Transforms is - -end LLVM_Transforms; diff --git a/bindings/ada/transforms/llvm_transforms_wrap.cxx b/bindings/ada/transforms/llvm_transforms_wrap.cxx deleted file mode 100644 index 8cb04db791aa..000000000000 --- a/bindings/ada/transforms/llvm_transforms_wrap.cxx +++ /dev/null @@ -1,828 +0,0 @@ -/* ---------------------------------------------------------------------------- - * This file was automatically generated by SWIG (http://www.swig.org). - * Version 1.3.36 - * - * This file is not intended to be easily readable and contains a number of - * coding conventions designed to improve portability and efficiency. Do not make - * changes to this file unless you know what you are doing--modify the SWIG - * interface file instead. - * ----------------------------------------------------------------------------- */ - - -#ifdef __cplusplus -template class SwigValueWrapper { - T *tt; -public: - SwigValueWrapper() : tt(0) { } - SwigValueWrapper(const SwigValueWrapper& rhs) : tt(new T(*rhs.tt)) { } - SwigValueWrapper(const T& t) : tt(new T(t)) { } - ~SwigValueWrapper() { delete tt; } - SwigValueWrapper& operator=(const T& t) { delete tt; tt = new T(t); return *this; } - operator T&() const { return *tt; } - T *operator&() { return tt; } -private: - SwigValueWrapper& operator=(const SwigValueWrapper& rhs); -}; - -template T SwigValueInit() { - return T(); -} -#endif - -/* ----------------------------------------------------------------------------- - * This section contains generic SWIG labels for method/variable - * declarations/attributes, and other compiler dependent labels. - * ----------------------------------------------------------------------------- */ - -/* template workaround for compilers that cannot correctly implement the C++ standard */ -#ifndef SWIGTEMPLATEDISAMBIGUATOR -# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) -# define SWIGTEMPLATEDISAMBIGUATOR template -# elif defined(__HP_aCC) -/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ -/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ -# define SWIGTEMPLATEDISAMBIGUATOR template -# else -# define SWIGTEMPLATEDISAMBIGUATOR -# endif -#endif - -/* inline attribute */ -#ifndef SWIGINLINE -# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) -# define SWIGINLINE inline -# else -# define SWIGINLINE -# endif -#endif - -/* attribute recognised by some compilers to avoid 'unused' warnings */ -#ifndef SWIGUNUSED -# if defined(__GNUC__) -# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -# elif defined(__ICC) -# define SWIGUNUSED __attribute__ ((__unused__)) -# else -# define SWIGUNUSED -# endif -#endif - -#ifndef SWIGUNUSEDPARM -# ifdef __cplusplus -# define SWIGUNUSEDPARM(p) -# else -# define SWIGUNUSEDPARM(p) p SWIGUNUSED -# endif -#endif - -/* internal SWIG method */ -#ifndef SWIGINTERN -# define SWIGINTERN static SWIGUNUSED -#endif - -/* internal inline SWIG method */ -#ifndef SWIGINTERNINLINE -# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE -#endif - -/* exporting methods */ -#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -# ifndef GCC_HASCLASSVISIBILITY -# define GCC_HASCLASSVISIBILITY -# endif -#endif - -#ifndef SWIGEXPORT -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# if defined(STATIC_LINKED) -# define SWIGEXPORT -# else -# define SWIGEXPORT __declspec(dllexport) -# endif -# else -# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) -# define SWIGEXPORT __attribute__ ((visibility("default"))) -# else -# define SWIGEXPORT -# endif -# endif -#endif - -/* calling conventions for Windows */ -#ifndef SWIGSTDCALL -# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# define SWIGSTDCALL __stdcall -# else -# define SWIGSTDCALL -# endif -#endif - -/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ -#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) -# define _CRT_SECURE_NO_DEPRECATE -#endif - -/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ -#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) -# define _SCL_SECURE_NO_DEPRECATE -#endif - - - -#include -#include -#include -#if defined(_WIN32) || defined(__CYGWIN32__) -# define DllExport __declspec( dllexport ) -# define SWIGSTDCALL __stdcall -#else -# define DllExport -# define SWIGSTDCALL -#endif - - -#ifdef __cplusplus -# include -#endif - - - - -/* Support for throwing Ada exceptions from C/C++ */ - -typedef enum -{ - SWIG_AdaException, - SWIG_AdaOutOfMemoryException, - SWIG_AdaIndexOutOfRangeException, - SWIG_AdaDivideByZeroException, - SWIG_AdaArgumentOutOfRangeException, - SWIG_AdaNullReferenceException -} SWIG_AdaExceptionCodes; - - -typedef void (SWIGSTDCALL* SWIG_AdaExceptionCallback_t)(const char *); - - -typedef struct -{ - SWIG_AdaExceptionCodes code; - SWIG_AdaExceptionCallback_t callback; -} - SWIG_AdaExceptions_t; - - -static -SWIG_AdaExceptions_t -SWIG_ada_exceptions[] = -{ - { SWIG_AdaException, NULL }, - { SWIG_AdaOutOfMemoryException, NULL }, - { SWIG_AdaIndexOutOfRangeException, NULL }, - { SWIG_AdaDivideByZeroException, NULL }, - { SWIG_AdaArgumentOutOfRangeException, NULL }, - { SWIG_AdaNullReferenceException, NULL } -}; - - -static -void -SWIG_AdaThrowException (SWIG_AdaExceptionCodes code, const char *msg) -{ - SWIG_AdaExceptionCallback_t callback = SWIG_ada_exceptions[SWIG_AdaException].callback; - if (code >=0 && (size_t)code < sizeof(SWIG_ada_exceptions)/sizeof(SWIG_AdaExceptions_t)) { - callback = SWIG_ada_exceptions[code].callback; - } - callback(msg); -} - - - -#ifdef __cplusplus -extern "C" -#endif - -DllExport void SWIGSTDCALL SWIGRegisterExceptionCallbacks_LLVM_Transforms (SWIG_AdaExceptionCallback_t systemException, - SWIG_AdaExceptionCallback_t outOfMemory, - SWIG_AdaExceptionCallback_t indexOutOfRange, - SWIG_AdaExceptionCallback_t divideByZero, - SWIG_AdaExceptionCallback_t argumentOutOfRange, - SWIG_AdaExceptionCallback_t nullReference) -{ - SWIG_ada_exceptions [SWIG_AdaException].callback = systemException; - SWIG_ada_exceptions [SWIG_AdaOutOfMemoryException].callback = outOfMemory; - SWIG_ada_exceptions [SWIG_AdaIndexOutOfRangeException].callback = indexOutOfRange; - SWIG_ada_exceptions [SWIG_AdaDivideByZeroException].callback = divideByZero; - SWIG_ada_exceptions [SWIG_AdaArgumentOutOfRangeException].callback = argumentOutOfRange; - SWIG_ada_exceptions [SWIG_AdaNullReferenceException].callback = nullReference; -} - - -/* Callback for returning strings to Ada without leaking memory */ - -typedef char * (SWIGSTDCALL* SWIG_AdaStringHelperCallback)(const char *); -static SWIG_AdaStringHelperCallback SWIG_ada_string_callback = NULL; - - - -/* probably obsolete ... -#ifdef __cplusplus -extern "C" -#endif -DllExport void SWIGSTDCALL SWIGRegisterStringCallback_LLVM_Transforms(SWIG_AdaStringHelperCallback callback) { - SWIG_ada_string_callback = callback; -} -*/ - - - -/* Contract support */ - -#define SWIG_contract_assert(nullreturn, expr, msg) if (!(expr)) {SWIG_AdaThrowException(SWIG_AdaArgumentOutOfRangeException, msg); return nullreturn; } else - - -#define protected public -#define private public - -#include "llvm-c/Transforms/IPO.h" -#include "llvm-c/Transforms/Scalar.h" - - - -// struct LLVMCtxt; - - -#undef protected -#undef private -#ifdef __cplusplus -extern "C" { -#endif -DllExport void SWIGSTDCALL Ada_LLVMAddArgumentPromotionPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddArgumentPromotionPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddConstantMergePass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddConstantMergePass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddDeadArgEliminationPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddDeadArgEliminationPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddDeadTypeEliminationPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddDeadTypeEliminationPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddFunctionAttrsPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddFunctionAttrsPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddFunctionInliningPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddFunctionInliningPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddGlobalDCEPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddGlobalDCEPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddGlobalOptimizerPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddGlobalOptimizerPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddIPConstantPropagationPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddIPConstantPropagationPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddLowerSetJmpPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddLowerSetJmpPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddPruneEHPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddPruneEHPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddRaiseAllocationsPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddRaiseAllocationsPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddStripDeadPrototypesPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddStripDeadPrototypesPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddStripSymbolsPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddStripSymbolsPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddAggressiveDCEPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddAggressiveDCEPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddCFGSimplificationPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddCFGSimplificationPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddCondPropagationPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddCondPropagationPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddDeadStoreEliminationPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddDeadStoreEliminationPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddGVNPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddGVNPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddIndVarSimplifyPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddIndVarSimplifyPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddInstructionCombiningPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddInstructionCombiningPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddJumpThreadingPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddJumpThreadingPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddLICMPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddLICMPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddLoopDeletionPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddLoopDeletionPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddLoopIndexSplitPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddLoopIndexSplitPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddLoopRotatePass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddLoopRotatePass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddLoopUnrollPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddLoopUnrollPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddLoopUnswitchPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddLoopUnswitchPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddMemCpyOptPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddMemCpyOptPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddPromoteMemoryToRegisterPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddPromoteMemoryToRegisterPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddReassociatePass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddReassociatePass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddSCCPPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddSCCPPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddScalarReplAggregatesPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddScalarReplAggregatesPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddSimplifyLibCallsPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddSimplifyLibCallsPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddTailCallEliminationPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddTailCallEliminationPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddConstantPropagationPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddConstantPropagationPass(arg1); - - -} - - - -DllExport void SWIGSTDCALL Ada_LLVMAddDemoteMemoryToRegisterPass ( - void * jarg1 - ) -{ - LLVMPassManagerRef arg1 = (LLVMPassManagerRef) 0 ; - - arg1 = (LLVMPassManagerRef)jarg1; - - LLVMAddDemoteMemoryToRegisterPass(arg1); - - -} - - - -#ifdef __cplusplus -} -#endif -#ifdef __cplusplus -extern "C" { -#endif -#ifdef __cplusplus -} -#endif - diff --git a/bindings/ocaml/Makefile.ocaml b/bindings/ocaml/Makefile.ocaml index 1cff422c28d4..40ecc9c08e09 100644 --- a/bindings/ocaml/Makefile.ocaml +++ b/bindings/ocaml/Makefile.ocaml @@ -73,8 +73,13 @@ Archive.EXE := $(strip $(OCAMLC) -cc $(CXX) $(OCAMLCFLAGS) $(OCAMLDEBUGFLAG:%=%. endif # Source files +ifndef OcamlSources1 OcamlSources1 := $(sort $(wildcard $(PROJ_SRC_DIR)/*.ml)) +endif + +ifndef OcamlHeaders1 OcamlHeaders1 := $(sort $(wildcard $(PROJ_SRC_DIR)/*.mli)) +endif OcamlSources2 := $(filter-out $(ExcludeSources),$(OcamlSources1)) OcamlHeaders2 := $(filter-out $(ExcludeHeaders),$(OcamlHeaders1)) @@ -352,11 +357,11 @@ $(OutputEXE): $(ToolEXE) $(OcamlDir)/.dir ifndef OCAMLOPT $(ToolEXE): $(ObjectsCMO) $(OcamlDir)/.dir $(Echo) "Archiving $(notdir $@) for $(BuildMode) build" - $(Verb) $(Archive.EXE) $@ $< + $(Verb) $(Archive.EXE) $@ $(ObjectsCMO) else $(ToolEXE): $(ObjectsCMX) $(OcamlDir)/.dir $(Echo) "Archiving $(notdir $@) for $(BuildMode) build" - $(Verb) $(Archive.EXE) $@ $< + $(Verb) $(Archive.EXE) $@ $(ObjectsCMX) endif endif diff --git a/bindings/ocaml/bitreader/llvm_bitreader.mli b/bindings/ocaml/bitreader/llvm_bitreader.mli index 5e2240974af4..1d333191c1d3 100644 --- a/bindings/ocaml/bitreader/llvm_bitreader.mli +++ b/bindings/ocaml/bitreader/llvm_bitreader.mli @@ -18,12 +18,12 @@ exception Error of string memory buffer [mb] in the context [context]. Returns [m] if successful, or raises [Error msg] otherwise, where [msg] is a description of the error encountered. See the function [llvm::getBitcodeModule]. *) -external get_module : Llvm.llcontext -> Llvm.llmemorybuffer -> Llvm.llmodule - = "llvm_get_module" +val get_module : Llvm.llcontext -> Llvm.llmemorybuffer -> Llvm.llmodule + (** [parse_bitcode context mb] parses the bitcode for a new module [m] from the memory buffer [mb] in the context [context]. Returns [m] if successful, or raises [Error msg] otherwise, where [msg] is a description of the error encountered. See the function [llvm::ParseBitcodeFile]. *) -external parse_bitcode : Llvm.llcontext -> Llvm.llmemorybuffer -> Llvm.llmodule - = "llvm_parse_bitcode" +val parse_bitcode : Llvm.llcontext -> Llvm.llmemorybuffer -> Llvm.llmodule + diff --git a/bindings/ocaml/executionengine/llvm_executionengine.mli b/bindings/ocaml/executionengine/llvm_executionengine.mli index ce25f9d0ae09..166b7bcddca6 100644 --- a/bindings/ocaml/executionengine/llvm_executionengine.mli +++ b/bindings/ocaml/executionengine/llvm_executionengine.mli @@ -25,58 +25,58 @@ module GenericValue: sig (** [of_float fpty n] boxes the float [n] in a float-valued generic value according to the floating point type [fpty]. See the fields [llvm::GenericValue::DoubleVal] and [llvm::GenericValue::FloatVal]. *) - external of_float : Llvm.lltype -> float -> t = "llvm_genericvalue_of_float" + val of_float : Llvm.lltype -> float -> t (** [of_pointer v] boxes the pointer value [v] in a generic value. See the field [llvm::GenericValue::PointerVal]. *) - external of_pointer : 'a -> t = "llvm_genericvalue_of_pointer" + val of_pointer : 'a -> t (** [of_int32 n w] boxes the int32 [i] in a generic value with the bitwidth [w]. See the field [llvm::GenericValue::IntVal]. *) - external of_int32 : Llvm.lltype -> int32 -> t = "llvm_genericvalue_of_int32" + val of_int32 : Llvm.lltype -> int32 -> t (** [of_int n w] boxes the int [i] in a generic value with the bitwidth [w]. See the field [llvm::GenericValue::IntVal]. *) - external of_int : Llvm.lltype -> int -> t = "llvm_genericvalue_of_int" + val of_int : Llvm.lltype -> int -> t (** [of_natint n w] boxes the native int [i] in a generic value with the bitwidth [w]. See the field [llvm::GenericValue::IntVal]. *) - external of_nativeint : Llvm.lltype -> nativeint -> t - = "llvm_genericvalue_of_nativeint" + val of_nativeint : Llvm.lltype -> nativeint -> t + (** [of_int64 n w] boxes the int64 [i] in a generic value with the bitwidth [w]. See the field [llvm::GenericValue::IntVal]. *) - external of_int64 : Llvm.lltype -> int64 -> t = "llvm_genericvalue_of_int64" + val of_int64 : Llvm.lltype -> int64 -> t (** [as_float fpty gv] unboxes the floating point-valued generic value [gv] of floating point type [fpty]. See the fields [llvm::GenericValue::DoubleVal] and [llvm::GenericValue::FloatVal]. *) - external as_float : Llvm.lltype -> t -> float = "llvm_genericvalue_as_float" + val as_float : Llvm.lltype -> t -> float (** [as_pointer gv] unboxes the pointer-valued generic value [gv]. See the field [llvm::GenericValue::PointerVal]. *) - external as_pointer : t -> 'a = "llvm_genericvalue_as_pointer" + val as_pointer : t -> 'a (** [as_int32 gv] unboxes the integer-valued generic value [gv] as an [int32]. Is invalid if [gv] has a bitwidth greater than 32 bits. See the field [llvm::GenericValue::IntVal]. *) - external as_int32 : t -> int32 = "llvm_genericvalue_as_int32" + val as_int32 : t -> int32 (** [as_int gv] unboxes the integer-valued generic value [gv] as an [int]. Is invalid if [gv] has a bitwidth greater than the host bit width (but the most significant bit may be lost). See the field [llvm::GenericValue::IntVal]. *) - external as_int : t -> int = "llvm_genericvalue_as_int" + val as_int : t -> int (** [as_natint gv] unboxes the integer-valued generic value [gv] as a [nativeint]. Is invalid if [gv] has a bitwidth greater than [nativeint]. See the field [llvm::GenericValue::IntVal]. *) - external as_nativeint : t -> nativeint = "llvm_genericvalue_as_nativeint" + val as_nativeint : t -> nativeint (** [as_int64 gv] returns the integer-valued generic value [gv] as an [int64]. Is invalid if [gv] has a bitwidth greater than [int64]. See the field [llvm::GenericValue::IntVal]. *) - external as_int64 : t -> int64 = "llvm_genericvalue_as_int64" + val as_int64 : t -> int64 end @@ -91,73 +91,73 @@ module ExecutionEngine: sig interpreter. Raises [Error msg] if an error occurrs. The execution engine is not garbage collected and must be destroyed with [dispose ee]. See the function [llvm::EngineBuilder::create]. *) - external create : Llvm.llmodule -> t = "llvm_ee_create" + val create : Llvm.llmodule -> t (** [create_interpreter m] creates a new interpreter, taking ownership of the module [m] if successful. Raises [Error msg] if an error occurrs. The execution engine is not garbage collected and must be destroyed with [dispose ee]. See the function [llvm::EngineBuilder::create]. *) - external create_interpreter : Llvm.llmodule -> t = "llvm_ee_create_interpreter" + val create_interpreter : Llvm.llmodule -> t (** [create_jit m optlevel] creates a new JIT (just-in-time compiler), taking ownership of the module [m] if successful with the desired optimization level [optlevel]. Raises [Error msg] if an error occurrs. The execution engine is not garbage collected and must be destroyed with [dispose ee]. See the function [llvm::EngineBuilder::create]. *) - external create_jit : Llvm.llmodule -> int -> t = "llvm_ee_create_jit" + val create_jit : Llvm.llmodule -> int -> t (** [dispose ee] releases the memory used by the execution engine and must be invoked to avoid memory leaks. *) - external dispose : t -> unit = "llvm_ee_dispose" + val dispose : t -> unit (** [add_module m ee] adds the module [m] to the execution engine [ee]. *) - external add_module : Llvm.llmodule -> t -> unit = "llvm_ee_add_module" + val add_module : Llvm.llmodule -> t -> unit (** [remove_module m ee] removes the module [m] from the execution engine [ee], disposing of [m] and the module referenced by [mp]. Raises [Error msg] if an error occurs. *) - external remove_module : Llvm.llmodule -> t -> Llvm.llmodule - = "llvm_ee_remove_module" + val remove_module : Llvm.llmodule -> t -> Llvm.llmodule + (** [find_function n ee] finds the function named [n] defined in any of the modules owned by the execution engine [ee]. Returns [None] if the function is not found and [Some f] otherwise. *) - external find_function : string -> t -> Llvm.llvalue option - = "llvm_ee_find_function" + val find_function : string -> t -> Llvm.llvalue option + (** [run_function f args ee] synchronously executes the function [f] with the arguments [args], which must be compatible with the parameter types. *) - external run_function : Llvm.llvalue -> GenericValue.t array -> t -> + val run_function : Llvm.llvalue -> GenericValue.t array -> t -> GenericValue.t - = "llvm_ee_run_function" + (** [run_static_ctors ee] executes the static constructors of each module in the execution engine [ee]. *) - external run_static_ctors : t -> unit = "llvm_ee_run_static_ctors" + val run_static_ctors : t -> unit (** [run_static_dtors ee] executes the static destructors of each module in the execution engine [ee]. *) - external run_static_dtors : t -> unit = "llvm_ee_run_static_dtors" + val run_static_dtors : t -> unit (** [run_function_as_main f args env ee] executes the function [f] as a main function, passing it [argv] and [argc] according to the string array [args], and [envp] as specified by the array [env]. Returns the integer return value of the function. *) - external run_function_as_main : Llvm.llvalue -> string array -> + val run_function_as_main : Llvm.llvalue -> string array -> (string * string) array -> t -> int - = "llvm_ee_run_function_as_main" + (** [free_machine_code f ee] releases the memory in the execution engine [ee] used to store the machine code for the function [f]. *) - external free_machine_code : Llvm.llvalue -> t -> unit - = "llvm_ee_free_machine_code" + val free_machine_code : Llvm.llvalue -> t -> unit + (** [target_data ee] is the target data owned by the execution engine [ee]. *) - external target_data : t -> Llvm_target.TargetData.t - = "LLVMGetExecutionEngineTargetData" + val target_data : t -> Llvm_target.TargetData.t + end -external initialize_native_target : unit -> bool - = "llvm_initialize_native_target" +val initialize_native_target : unit -> bool + diff --git a/bindings/ocaml/llvm/llvm.mli b/bindings/ocaml/llvm/llvm.mli index ba3bbe248b71..9b037aae7a46 100644 --- a/bindings/ocaml/llvm/llvm.mli +++ b/bindings/ocaml/llvm/llvm.mli @@ -212,19 +212,19 @@ exception IoError of string (** [create_context ()] creates a context for storing the "global" state in LLVM. See the constructor [llvm::LLVMContext]. *) -external create_context : unit -> llcontext = "llvm_create_context" +val create_context : unit -> llcontext (** [destroy_context ()] destroys a context. See the destructor [llvm::LLVMContext::~LLVMContext]. *) -external dispose_context : llcontext -> unit = "llvm_dispose_context" +val dispose_context : llcontext -> unit (** See the function [llvm::getGlobalContext]. *) -external global_context : unit -> llcontext = "llvm_global_context" +val global_context : unit -> llcontext (** [mdkind_id context name] returns the MDKind ID that corresponds to the name [name] in the context [context]. See the function [llvm::LLVMContext::getMDKindID]. *) -external mdkind_id : llcontext -> string -> int = "llvm_mdkind_id" +val mdkind_id : llcontext -> string -> int (** {6 Modules} *) @@ -233,71 +233,71 @@ external mdkind_id : llcontext -> string -> int = "llvm_mdkind_id" the context [context]. Modules are not garbage collected; it is mandatory to call {!dispose_module} to free memory. See the constructor [llvm::Module::Module]. *) -external create_module : llcontext -> string -> llmodule = "llvm_create_module" +val create_module : llcontext -> string -> llmodule (** [dispose_module m] destroys a module [m] and all of the IR objects it contained. All references to subordinate objects are invalidated; referencing them will invoke undefined behavior. See the destructor [llvm::Module::~Module]. *) -external dispose_module : llmodule -> unit = "llvm_dispose_module" +val dispose_module : llmodule -> unit (** [target_triple m] is the target specifier for the module [m], something like [i686-apple-darwin8]. See the method [llvm::Module::getTargetTriple]. *) -external target_triple: llmodule -> string - = "llvm_target_triple" +val target_triple: llmodule -> string + (** [target_triple triple m] changes the target specifier for the module [m] to the string [triple]. See the method [llvm::Module::setTargetTriple]. *) -external set_target_triple: string -> llmodule -> unit - = "llvm_set_target_triple" +val set_target_triple: string -> llmodule -> unit + (** [data_layout m] is the data layout specifier for the module [m], something like [e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-...-a0:0:64-f80:128:128]. See the method [llvm::Module::getDataLayout]. *) -external data_layout: llmodule -> string - = "llvm_data_layout" +val data_layout: llmodule -> string + (** [set_data_layout s m] changes the data layout specifier for the module [m] to the string [s]. See the method [llvm::Module::setDataLayout]. *) -external set_data_layout: string -> llmodule -> unit - = "llvm_set_data_layout" +val set_data_layout: string -> llmodule -> unit + (** [define_type_name name ty m] adds a named type to the module's symbol table. Returns [true] if successful. If such a name already exists, then no entry is added and [false] is returned. See the [llvm::Module::addTypeName] method. *) -external define_type_name : string -> lltype -> llmodule -> bool - = "llvm_add_type_name" +val define_type_name : string -> lltype -> llmodule -> bool + (** [delete_type_name name] removes a type name from the module's symbol table. *) -external delete_type_name : string -> llmodule -> unit - = "llvm_delete_type_name" +val delete_type_name : string -> llmodule -> unit + (** [type_by_name m n] returns the type in the module [m] named [n], or [None] if it does not exist. See the method [llvm::Module::getTypeByName]. *) -external type_by_name : llmodule -> string -> lltype option - = "llvm_type_by_name" +val type_by_name : llmodule -> string -> lltype option + (** [dump_module m] prints the .ll representation of the module [m] to standard error. See the method [llvm::Module::dump]. *) -external dump_module : llmodule -> unit = "llvm_dump_module" +val dump_module : llmodule -> unit (** [set_module_inline_asm m asm] sets the inline assembler for the module. See the method [llvm::Module::setModuleInlineAsm]. *) -external set_module_inline_asm : llmodule -> string -> unit - = "llvm_set_module_inline_asm" +val set_module_inline_asm : llmodule -> string -> unit + (** {6 Types} *) (** [classify_type ty] returns the {!TypeKind.t} corresponding to the type [ty]. See the method [llvm::Type::getTypeID]. *) -external classify_type : lltype -> TypeKind.t = "llvm_classify_type" +val classify_type : lltype -> TypeKind.t (** [type_context ty] returns the {!llcontext} corresponding to the type [ty]. See the method [llvm::Type::getContext]. *) -external type_context : lltype -> llcontext = "llvm_type_context" +val type_context : lltype -> llcontext (** [string_of_lltype ty] returns a string describing the type [ty]. *) val string_of_lltype : lltype -> string @@ -306,54 +306,54 @@ val string_of_lltype : lltype -> string (** [i1_type c] returns an integer type of bitwidth 1 in the context [c]. See [llvm::Type::Int1Ty]. *) -external i1_type : llcontext -> lltype = "llvm_i1_type" +val i1_type : llcontext -> lltype (** [i8_type c] returns an integer type of bitwidth 8 in the context [c]. See [llvm::Type::Int8Ty]. *) -external i8_type : llcontext -> lltype = "llvm_i8_type" +val i8_type : llcontext -> lltype (** [i16_type c] returns an integer type of bitwidth 16 in the context [c]. See [llvm::Type::Int16Ty]. *) -external i16_type : llcontext -> lltype = "llvm_i16_type" +val i16_type : llcontext -> lltype (** [i32_type c] returns an integer type of bitwidth 32 in the context [c]. See [llvm::Type::Int32Ty]. *) -external i32_type : llcontext -> lltype = "llvm_i32_type" +val i32_type : llcontext -> lltype (** [i64_type c] returns an integer type of bitwidth 64 in the context [c]. See [llvm::Type::Int64Ty]. *) -external i64_type : llcontext -> lltype = "llvm_i64_type" +val i64_type : llcontext -> lltype (** [integer_type c n] returns an integer type of bitwidth [n] in the context [c]. See the method [llvm::IntegerType::get]. *) -external integer_type : llcontext -> int -> lltype = "llvm_integer_type" +val integer_type : llcontext -> int -> lltype (** [integer_bitwidth c ty] returns the number of bits in the integer type [ty] in the context [c]. See the method [llvm::IntegerType::getBitWidth]. *) -external integer_bitwidth : lltype -> int = "llvm_integer_bitwidth" +val integer_bitwidth : lltype -> int (** {7 Operations on real types} *) (** [float_type c] returns the IEEE 32-bit floating point type in the context [c]. See [llvm::Type::FloatTy]. *) -external float_type : llcontext -> lltype = "llvm_float_type" +val float_type : llcontext -> lltype (** [double_type c] returns the IEEE 64-bit floating point type in the context [c]. See [llvm::Type::DoubleTy]. *) -external double_type : llcontext -> lltype = "llvm_double_type" +val double_type : llcontext -> lltype (** [x86fp80_type c] returns the x87 80-bit floating point type in the context [c]. See [llvm::Type::X86_FP80Ty]. *) -external x86fp80_type : llcontext -> lltype = "llvm_x86fp80_type" +val x86fp80_type : llcontext -> lltype (** [fp128_type c] returns the IEEE 128-bit floating point type in the context [c]. See [llvm::Type::FP128Ty]. *) -external fp128_type : llcontext -> lltype = "llvm_fp128_type" +val fp128_type : llcontext -> lltype (** [ppc_fp128_type c] returns the PowerPC 128-bit floating point type in the context [c]. See [llvm::Type::PPC_FP128Ty]. *) -external ppc_fp128_type : llcontext -> lltype = "llvm_ppc_fp128_type" +val ppc_fp128_type : llcontext -> lltype (** {7 Operations on function types} *) @@ -361,26 +361,26 @@ external ppc_fp128_type : llcontext -> lltype = "llvm_ppc_fp128_type" (** [function_type ret_ty param_tys] returns the function type returning [ret_ty] and taking [param_tys] as parameters. See the method [llvm::FunctionType::get]. *) -external function_type : lltype -> lltype array -> lltype = "llvm_function_type" +val function_type : lltype -> lltype array -> lltype (** [va_arg_function_type ret_ty param_tys] is just like [function_type ret_ty param_tys] except that it returns the function type which also takes a variable number of arguments. See the method [llvm::FunctionType::get]. *) -external var_arg_function_type : lltype -> lltype array -> lltype - = "llvm_var_arg_function_type" +val var_arg_function_type : lltype -> lltype array -> lltype + (** [is_var_arg fty] returns [true] if [fty] is a varargs function type, [false] otherwise. See the method [llvm::FunctionType::isVarArg]. *) -external is_var_arg : lltype -> bool = "llvm_is_var_arg" +val is_var_arg : lltype -> bool (** [return_type fty] gets the return type of the function type [fty]. See the method [llvm::FunctionType::getReturnType]. *) -external return_type : lltype -> lltype = "LLVMGetReturnType" +val return_type : lltype -> lltype (** [param_types fty] gets the parameter types of the function type [fty]. See the method [llvm::FunctionType::getParamType]. *) -external param_types : lltype -> lltype array = "llvm_param_types" +val param_types : lltype -> lltype array (** {7 Operations on struct types} *) @@ -388,61 +388,61 @@ external param_types : lltype -> lltype array = "llvm_param_types" (** [struct_type context tys] returns the structure type in the context [context] containing in the types in the array [tys]. See the method [llvm::StructType::get]. *) -external struct_type : llcontext -> lltype array -> lltype - = "llvm_struct_type" +val struct_type : llcontext -> lltype array -> lltype + (** [packed_struct_type context ys] returns the packed structure type in the context [context] containing in the types in the array [tys]. See the method [llvm::StructType::get]. *) -external packed_struct_type : llcontext -> lltype array -> lltype - = "llvm_packed_struct_type" +val packed_struct_type : llcontext -> lltype array -> lltype + (** [struct_element_types sty] returns the constituent types of the struct type [sty]. See the method [llvm::StructType::getElementType]. *) -external struct_element_types : lltype -> lltype array - = "llvm_struct_element_types" +val struct_element_types : lltype -> lltype array + (** [is_packed sty] returns [true] if the structure type [sty] is packed, [false] otherwise. See the method [llvm::StructType::isPacked]. *) -external is_packed : lltype -> bool = "llvm_is_packed" +val is_packed : lltype -> bool (** {7 Operations on pointer, vector, and array types} *) (** [array_type ty n] returns the array type containing [n] elements of type [ty]. See the method [llvm::ArrayType::get]. *) -external array_type : lltype -> int -> lltype = "llvm_array_type" +val array_type : lltype -> int -> lltype (** [pointer_type ty] returns the pointer type referencing objects of type [ty] in the default address space (0). See the method [llvm::PointerType::getUnqual]. *) -external pointer_type : lltype -> lltype = "llvm_pointer_type" +val pointer_type : lltype -> lltype (** [qualified_pointer_type ty as] returns the pointer type referencing objects of type [ty] in address space [as]. See the method [llvm::PointerType::get]. *) -external qualified_pointer_type : lltype -> int -> lltype - = "llvm_qualified_pointer_type" +val qualified_pointer_type : lltype -> int -> lltype + (** [vector_type ty n] returns the array type containing [n] elements of the primitive type [ty]. See the method [llvm::ArrayType::get]. *) -external vector_type : lltype -> int -> lltype = "llvm_vector_type" +val vector_type : lltype -> int -> lltype (** [element_type ty] returns the element type of the pointer, vector, or array type [ty]. See the method [llvm::SequentialType::get]. *) -external element_type : lltype -> lltype = "LLVMGetElementType" +val element_type : lltype -> lltype (** [element_type aty] returns the element count of the array type [aty]. See the method [llvm::ArrayType::getNumElements]. *) -external array_length : lltype -> int = "llvm_array_length" +val array_length : lltype -> int (** [address_space pty] returns the address space qualifier of the pointer type [pty]. See the method [llvm::PointerType::getAddressSpace]. *) -external address_space : lltype -> int = "llvm_address_space" +val address_space : lltype -> int (** [element_type ty] returns the element count of the vector type [ty]. See the method [llvm::VectorType::getNumElements]. *) -external vector_size : lltype -> int = "llvm_vector_size" +val vector_size : lltype -> int (** {7 Operations on other types} *) @@ -450,15 +450,15 @@ external vector_size : lltype -> int = "llvm_vector_size" (** [opaque_type c] creates a new opaque type distinct from any other in the context [c]. Opaque types are useful for building recursive types in combination with {!refine_type}. See [llvm::OpaqueType::get]. *) -external opaque_type : llcontext -> lltype = "llvm_opaque_type" +val opaque_type : llcontext -> lltype (** [void_type c] creates a type of a function which does not return any value in the context [c]. See [llvm::Type::VoidTy]. *) -external void_type : llcontext -> lltype = "llvm_void_type" +val void_type : llcontext -> lltype (** [label_type c] creates a type of a basic block in the context [c]. See [llvm::Type::LabelTy]. *) -external label_type : llcontext -> lltype = "llvm_label_type" +val label_type : llcontext -> lltype (** {7 Operations on type handles} *) @@ -466,43 +466,43 @@ external label_type : llcontext -> lltype = "llvm_label_type" refined as a result of a call to {!refine_type}, the handle will be updated; any bare [lltype] references will become invalid. See the class [llvm::PATypeHolder]. *) -external handle_to_type : lltype -> lltypehandle = "llvm_handle_to_type" +val handle_to_type : lltype -> lltypehandle (** [type_of_handle tyh] resolves the type handle [tyh]. See the method [llvm::PATypeHolder::get()]. *) -external type_of_handle : lltypehandle -> lltype = "llvm_type_of_handle" +val type_of_handle : lltypehandle -> lltype (** [refine_type opaque_ty ty] replaces the abstract type [opaque_ty] with the concrete type [ty] in all users. Warning: This may invalidate {!lltype} values! Use {!lltypehandle} to manipulate potentially abstract types. See the method [llvm::Type::refineAbstractType]. *) -external refine_type : lltype -> lltype -> unit = "llvm_refine_type" +val refine_type : lltype -> lltype -> unit (* {6 Values} *) (** [type_of v] returns the type of the value [v]. See the method [llvm::Value::getType]. *) -external type_of : llvalue -> lltype = "llvm_type_of" +val type_of : llvalue -> lltype (** [value_name v] returns the name of the value [v]. For global values, this is the symbol name. For instructions and basic blocks, it is the SSA register name. It is meaningless for constants. See the method [llvm::Value::getName]. *) -external value_name : llvalue -> string = "llvm_value_name" +val value_name : llvalue -> string (** [set_value_name n v] sets the name of the value [v] to [n]. See the method [llvm::Value::setName]. *) -external set_value_name : string -> llvalue -> unit = "llvm_set_value_name" +val set_value_name : string -> llvalue -> unit (** [dump_value v] prints the .ll representation of the value [v] to standard error. See the method [llvm::Value::dump]. *) -external dump_value : llvalue -> unit = "llvm_dump_value" +val dump_value : llvalue -> unit (** [replace_all_uses_with old new] replaces all uses of the value [old] * with the value [new]. See the method [llvm::Value::replaceAllUsesWith]. *) -external replace_all_uses_with : llvalue -> llvalue -> unit - = "LLVMReplaceAllUsesWith" +val replace_all_uses_with : llvalue -> llvalue -> unit + (* {6 Uses} *) @@ -510,19 +510,19 @@ external replace_all_uses_with : llvalue -> llvalue -> unit (** [use_begin v] returns the first position in the use list for the value [v]. [use_begin] and [use_succ] can e used to iterate over the use list in order. See the method [llvm::Value::use_begin]. *) -external use_begin : llvalue -> lluse option = "llvm_use_begin" +val use_begin : llvalue -> lluse option (** [use_succ u] returns the use list position succeeding [u]. See the method [llvm::use_value_iterator::operator++]. *) -external use_succ : lluse -> lluse option = "llvm_use_succ" +val use_succ : lluse -> lluse option (** [user u] returns the user of the use [u]. See the method [llvm::Use::getUser]. *) -external user : lluse -> llvalue = "llvm_user" +val user : lluse -> llvalue (** [used_value u] returns the usee of the use [u]. See the method [llvm::Use::getUsedValue]. *) -external used_value : lluse -> llvalue = "llvm_used_value" +val used_value : lluse -> llvalue (** [iter_uses f v] applies function [f] to each of the users of the value [v] in order. Tail recursive. *) @@ -541,46 +541,46 @@ val fold_right_uses : (lluse -> 'a -> 'a) -> llvalue -> 'a -> 'a (** [operand v i] returns the operand at index [i] for the value [v]. See the method [llvm::User::getOperand]. *) -external operand : llvalue -> int -> llvalue = "llvm_operand" +val operand : llvalue -> int -> llvalue (** [set_operand v i o] sets the operand of the value [v] at the index [i] to the value [o]. See the method [llvm::User::setOperand]. *) -external set_operand : llvalue -> int -> llvalue -> unit = "llvm_set_operand" +val set_operand : llvalue -> int -> llvalue -> unit (** [num_operands v] returns the number of operands for the value [v]. See the method [llvm::User::getNumOperands]. *) -external num_operands : llvalue -> int = "llvm_num_operands" +val num_operands : llvalue -> int (** {7 Operations on constants of (mostly) any type} *) (** [is_constant v] returns [true] if the value [v] is a constant, [false] otherwise. Similar to [llvm::isa]. *) -external is_constant : llvalue -> bool = "llvm_is_constant" +val is_constant : llvalue -> bool (** [const_null ty] returns the constant null (zero) of the type [ty]. See the method [llvm::Constant::getNullValue]. *) -external const_null : lltype -> llvalue = "LLVMConstNull" +val const_null : lltype -> llvalue (** [const_all_ones ty] returns the constant '-1' of the integer or vector type [ty]. See the method [llvm::Constant::getAllOnesValue]. *) -external const_all_ones : (*int|vec*)lltype -> llvalue = "LLVMConstAllOnes" +val const_all_ones : (*int|vec*)lltype -> llvalue (** [const_pointer_null ty] returns the constant null (zero) pointer of the type [ty]. See the method [llvm::ConstantPointerNull::get]. *) -external const_pointer_null : lltype -> llvalue = "LLVMConstPointerNull" +val const_pointer_null : lltype -> llvalue (** [undef ty] returns the undefined value of the type [ty]. See the method [llvm::UndefValue::get]. *) -external undef : lltype -> llvalue = "LLVMGetUndef" +val undef : lltype -> llvalue (** [is_null v] returns [true] if the value [v] is the null (zero) value. See the method [llvm::Constant::isNullValue]. *) -external is_null : llvalue -> bool = "llvm_is_null" +val is_null : llvalue -> bool (** [is_undef v] returns [true] if the value [v] is an undefined value, [false] otherwise. Similar to [llvm::isa]. *) -external is_undef : llvalue -> bool = "llvm_is_undef" +val is_undef : llvalue -> bool (** {7 Operations on instructions} *) @@ -588,58 +588,58 @@ external is_undef : llvalue -> bool = "llvm_is_undef" (** [has_metadata i] returns whether or not the instruction [i] has any metadata attached to it. See the function [llvm::Instruction::hasMetadata]. *) -external has_metadata : llvalue -> bool = "llvm_has_metadata" +val has_metadata : llvalue -> bool (** [metadata i kind] optionally returns the metadata associated with the kind [kind] in the instruction [i] See the function [llvm::Instruction::getMetadata]. *) -external metadata : llvalue -> int -> llvalue option = "llvm_metadata" +val metadata : llvalue -> int -> llvalue option (** [set_metadata i kind md] sets the metadata [md] of kind [kind] in the instruction [i]. See the function [llvm::Instruction::setMetadata]. *) -external set_metadata : llvalue -> int -> llvalue -> unit = "llvm_set_metadata" +val set_metadata : llvalue -> int -> llvalue -> unit (** [clear_metadata i kind] clears the metadata of kind [kind] in the instruction [i]. See the function [llvm::Instruction::setMetadata]. *) -external clear_metadata : llvalue -> int -> unit = "llvm_clear_metadata" +val clear_metadata : llvalue -> int -> unit (** {7 Operations on metadata} *) (** [mdstring c s] returns the MDString of the string [s] in the context [c]. See the method [llvm::MDNode::get]. *) -external mdstring : llcontext -> string -> llvalue = "llvm_mdstring" +val mdstring : llcontext -> string -> llvalue (** [mdnode c elts] returns the MDNode containing the values [elts] in the context [c]. See the method [llvm::MDNode::get]. *) -external mdnode : llcontext -> llvalue array -> llvalue = "llvm_mdnode" +val mdnode : llcontext -> llvalue array -> llvalue (** {7 Operations on scalar constants} *) (** [const_int ty i] returns the integer constant of type [ty] and value [i]. See the method [llvm::ConstantInt::get]. *) -external const_int : lltype -> int -> llvalue = "llvm_const_int" +val const_int : lltype -> int -> llvalue (** [const_of_int64 ty i] returns the integer constant of type [ty] and value [i]. See the method [llvm::ConstantInt::get]. *) -external const_of_int64 : lltype -> Int64.t -> bool -> llvalue - = "llvm_const_of_int64" +val const_of_int64 : lltype -> Int64.t -> bool -> llvalue + (** [const_int_of_string ty s r] returns the integer constant of type [ty] and * value [s], with the radix [r]. See the method [llvm::ConstantInt::get]. *) -external const_int_of_string : lltype -> string -> int -> llvalue - = "llvm_const_int_of_string" +val const_int_of_string : lltype -> string -> int -> llvalue + (** [const_float ty n] returns the floating point constant of type [ty] and value [n]. See the method [llvm::ConstantFP::get]. *) -external const_float : lltype -> float -> llvalue = "llvm_const_float" +val const_float : lltype -> float -> llvalue (** [const_float_of_string ty s] returns the floating point constant of type [ty] and value [n]. See the method [llvm::ConstantFP::get]. *) -external const_float_of_string : lltype -> string -> llvalue - = "llvm_const_float_of_string" +val const_float_of_string : lltype -> string -> llvalue + (** {7 Operations on composite constants} *) @@ -649,39 +649,39 @@ external const_float_of_string : lltype -> string -> llvalue null-terminated (but see {!const_stringz}). This value can in turn be used as the initializer for a global variable. See the method [llvm::ConstantArray::get]. *) -external const_string : llcontext -> string -> llvalue = "llvm_const_string" +val const_string : llcontext -> string -> llvalue (** [const_stringz c s] returns the constant [i8] array with the values of the characters in the string [s] and a null terminator in the context [c]. This value can in turn be used as the initializer for a global variable. See the method [llvm::ConstantArray::get]. *) -external const_stringz : llcontext -> string -> llvalue = "llvm_const_stringz" +val const_stringz : llcontext -> string -> llvalue (** [const_array ty elts] returns the constant array of type [array_type ty (Array.length elts)] and containing the values [elts]. This value can in turn be used as the initializer for a global variable. See the method [llvm::ConstantArray::get]. *) -external const_array : lltype -> llvalue array -> llvalue = "llvm_const_array" +val const_array : lltype -> llvalue array -> llvalue (** [const_struct context elts] returns the structured constant of type [struct_type (Array.map type_of elts)] and containing the values [elts] in the context [context]. This value can in turn be used as the initializer for a global variable. See the method [llvm::ConstantStruct::get]. *) -external const_struct : llcontext -> llvalue array -> llvalue - = "llvm_const_struct" +val const_struct : llcontext -> llvalue array -> llvalue + (** [const_packed_struct context elts] returns the structured constant of type {!packed_struct_type} [(Array.map type_of elts)] and containing the values [elts] in the context [context]. This value can in turn be used as the initializer for a global variable. See the method [llvm::ConstantStruct::get]. *) -external const_packed_struct : llcontext -> llvalue array -> llvalue - = "llvm_const_packed_struct" +val const_packed_struct : llcontext -> llvalue array -> llvalue + (** [const_vector elts] returns the vector constant of type [vector_type (type_of elts.(0)) (Array.length elts)] and containing the values [elts]. See the method [llvm::ConstantVector::get]. *) -external const_vector : llvalue array -> llvalue = "llvm_const_vector" +val const_vector : llvalue array -> llvalue (** {7 Constant expressions} *) @@ -690,286 +690,286 @@ external const_vector : llvalue array -> llvalue = "llvm_const_vector" equivalent to [const_ptrtoint (const_gep (const_null (pointer_type {i8,ty})) (const_int i32_type 0) (const_int i32_type 1)) i32_type], but considerably more readable. See the method [llvm::ConstantExpr::getAlignOf]. *) -external align_of : lltype -> llvalue = "LLVMAlignOf" +val align_of : lltype -> llvalue (** [size_of ty] returns the sizeof constant for the type [ty]. This is equivalent to [const_ptrtoint (const_gep (const_null (pointer_type ty)) (const_int i32_type 1)) i64_type], but considerably more readable. See the method [llvm::ConstantExpr::getSizeOf]. *) -external size_of : lltype -> llvalue = "LLVMSizeOf" +val size_of : lltype -> llvalue (** [const_neg c] returns the arithmetic negation of the constant [c]. See the method [llvm::ConstantExpr::getNeg]. *) -external const_neg : llvalue -> llvalue = "LLVMConstNeg" +val const_neg : llvalue -> llvalue (** [const_nsw_neg c] returns the arithmetic negation of the constant [c] with no signed wrapping. The result is undefined if the negation overflows. See the method [llvm::ConstantExpr::getNSWNeg]. *) -external const_nsw_neg : llvalue -> llvalue = "LLVMConstNSWNeg" +val const_nsw_neg : llvalue -> llvalue (** [const_nuw_neg c] returns the arithmetic negation of the constant [c] with no unsigned wrapping. The result is undefined if the negation overflows. See the method [llvm::ConstantExpr::getNUWNeg]. *) -external const_nuw_neg : llvalue -> llvalue = "LLVMConstNUWNeg" +val const_nuw_neg : llvalue -> llvalue (** [const_fneg c] returns the arithmetic negation of the constant float [c]. See the method [llvm::ConstantExpr::getFNeg]. *) -external const_fneg : llvalue -> llvalue = "LLVMConstFNeg" +val const_fneg : llvalue -> llvalue (** [const_not c] returns the bitwise inverse of the constant [c]. See the method [llvm::ConstantExpr::getNot]. *) -external const_not : llvalue -> llvalue = "LLVMConstNot" +val const_not : llvalue -> llvalue (** [const_add c1 c2] returns the constant sum of two constants. See the method [llvm::ConstantExpr::getAdd]. *) -external const_add : llvalue -> llvalue -> llvalue = "LLVMConstAdd" +val const_add : llvalue -> llvalue -> llvalue (** [const_nsw_add c1 c2] returns the constant sum of two constants with no signed wrapping. The result is undefined if the sum overflows. See the method [llvm::ConstantExpr::getNSWAdd]. *) -external const_nsw_add : llvalue -> llvalue -> llvalue = "LLVMConstNSWAdd" +val const_nsw_add : llvalue -> llvalue -> llvalue (** [const_nuw_add c1 c2] returns the constant sum of two constants with no unsigned wrapping. The result is undefined if the sum overflows. See the method [llvm::ConstantExpr::getNSWAdd]. *) -external const_nuw_add : llvalue -> llvalue -> llvalue = "LLVMConstNUWAdd" +val const_nuw_add : llvalue -> llvalue -> llvalue (** [const_fadd c1 c2] returns the constant sum of two constant floats. See the method [llvm::ConstantExpr::getFAdd]. *) -external const_fadd : llvalue -> llvalue -> llvalue = "LLVMConstFAdd" +val const_fadd : llvalue -> llvalue -> llvalue (** [const_sub c1 c2] returns the constant difference, [c1 - c2], of two constants. See the method [llvm::ConstantExpr::getSub]. *) -external const_sub : llvalue -> llvalue -> llvalue = "LLVMConstSub" +val const_sub : llvalue -> llvalue -> llvalue (** [const_nsw_sub c1 c2] returns the constant difference of two constants with no signed wrapping. The result is undefined if the sum overflows. See the method [llvm::ConstantExpr::getNSWSub]. *) -external const_nsw_sub : llvalue -> llvalue -> llvalue = "LLVMConstNSWSub" +val const_nsw_sub : llvalue -> llvalue -> llvalue (** [const_nuw_sub c1 c2] returns the constant difference of two constants with no unsigned wrapping. The result is undefined if the sum overflows. See the method [llvm::ConstantExpr::getNSWSub]. *) -external const_nuw_sub : llvalue -> llvalue -> llvalue = "LLVMConstNUWSub" +val const_nuw_sub : llvalue -> llvalue -> llvalue (** [const_fsub c1 c2] returns the constant difference, [c1 - c2], of two constant floats. See the method [llvm::ConstantExpr::getFSub]. *) -external const_fsub : llvalue -> llvalue -> llvalue = "LLVMConstFSub" +val const_fsub : llvalue -> llvalue -> llvalue (** [const_mul c1 c2] returns the constant product of two constants. See the method [llvm::ConstantExpr::getMul]. *) -external const_mul : llvalue -> llvalue -> llvalue = "LLVMConstMul" +val const_mul : llvalue -> llvalue -> llvalue (** [const_nsw_mul c1 c2] returns the constant product of two constants with no signed wrapping. The result is undefined if the sum overflows. See the method [llvm::ConstantExpr::getNSWMul]. *) -external const_nsw_mul : llvalue -> llvalue -> llvalue = "LLVMConstNSWMul" +val const_nsw_mul : llvalue -> llvalue -> llvalue (** [const_nuw_mul c1 c2] returns the constant product of two constants with no unsigned wrapping. The result is undefined if the sum overflows. See the method [llvm::ConstantExpr::getNSWMul]. *) -external const_nuw_mul : llvalue -> llvalue -> llvalue = "LLVMConstNUWMul" +val const_nuw_mul : llvalue -> llvalue -> llvalue (** [const_fmul c1 c2] returns the constant product of two constants floats. See the method [llvm::ConstantExpr::getFMul]. *) -external const_fmul : llvalue -> llvalue -> llvalue = "LLVMConstFMul" +val const_fmul : llvalue -> llvalue -> llvalue (** [const_udiv c1 c2] returns the constant quotient [c1 / c2] of two unsigned integer constants. See the method [llvm::ConstantExpr::getUDiv]. *) -external const_udiv : llvalue -> llvalue -> llvalue = "LLVMConstUDiv" +val const_udiv : llvalue -> llvalue -> llvalue (** [const_sdiv c1 c2] returns the constant quotient [c1 / c2] of two signed integer constants. See the method [llvm::ConstantExpr::getSDiv]. *) -external const_sdiv : llvalue -> llvalue -> llvalue = "LLVMConstSDiv" +val const_sdiv : llvalue -> llvalue -> llvalue (** [const_exact_sdiv c1 c2] returns the constant quotient [c1 / c2] of two signed integer constants. The result is undefined if the result is rounded or overflows. See the method [llvm::ConstantExpr::getExactSDiv]. *) -external const_exact_sdiv : llvalue -> llvalue -> llvalue = "LLVMConstExactSDiv" +val const_exact_sdiv : llvalue -> llvalue -> llvalue (** [const_fdiv c1 c2] returns the constant quotient [c1 / c2] of two floating point constants. See the method [llvm::ConstantExpr::getFDiv]. *) -external const_fdiv : llvalue -> llvalue -> llvalue = "LLVMConstFDiv" +val const_fdiv : llvalue -> llvalue -> llvalue (** [const_urem c1 c2] returns the constant remainder [c1 MOD c2] of two unsigned integer constants. See the method [llvm::ConstantExpr::getURem]. *) -external const_urem : llvalue -> llvalue -> llvalue = "LLVMConstURem" +val const_urem : llvalue -> llvalue -> llvalue (** [const_srem c1 c2] returns the constant remainder [c1 MOD c2] of two signed integer constants. See the method [llvm::ConstantExpr::getSRem]. *) -external const_srem : llvalue -> llvalue -> llvalue = "LLVMConstSRem" +val const_srem : llvalue -> llvalue -> llvalue (** [const_frem c1 c2] returns the constant remainder [c1 MOD c2] of two signed floating point constants. See the method [llvm::ConstantExpr::getFRem]. *) -external const_frem : llvalue -> llvalue -> llvalue = "LLVMConstFRem" +val const_frem : llvalue -> llvalue -> llvalue (** [const_and c1 c2] returns the constant bitwise [AND] of two integer constants. See the method [llvm::ConstantExpr::getAnd]. *) -external const_and : llvalue -> llvalue -> llvalue = "LLVMConstAnd" +val const_and : llvalue -> llvalue -> llvalue (** [const_or c1 c2] returns the constant bitwise [OR] of two integer constants. See the method [llvm::ConstantExpr::getOr]. *) -external const_or : llvalue -> llvalue -> llvalue = "LLVMConstOr" +val const_or : llvalue -> llvalue -> llvalue (** [const_xor c1 c2] returns the constant bitwise [XOR] of two integer constants. See the method [llvm::ConstantExpr::getXor]. *) -external const_xor : llvalue -> llvalue -> llvalue = "LLVMConstXor" +val const_xor : llvalue -> llvalue -> llvalue (** [const_icmp pred c1 c2] returns the constant comparison of two integer constants, [c1 pred c2]. See the method [llvm::ConstantExpr::getICmp]. *) -external const_icmp : Icmp.t -> llvalue -> llvalue -> llvalue - = "llvm_const_icmp" +val const_icmp : Icmp.t -> llvalue -> llvalue -> llvalue + (** [const_fcmp pred c1 c2] returns the constant comparison of two floating point constants, [c1 pred c2]. See the method [llvm::ConstantExpr::getFCmp]. *) -external const_fcmp : Fcmp.t -> llvalue -> llvalue -> llvalue - = "llvm_const_fcmp" +val const_fcmp : Fcmp.t -> llvalue -> llvalue -> llvalue + (** [const_shl c1 c2] returns the constant integer [c1] left-shifted by the constant integer [c2]. See the method [llvm::ConstantExpr::getShl]. *) -external const_shl : llvalue -> llvalue -> llvalue = "LLVMConstShl" +val const_shl : llvalue -> llvalue -> llvalue (** [const_lshr c1 c2] returns the constant integer [c1] right-shifted by the constant integer [c2] with zero extension. See the method [llvm::ConstantExpr::getLShr]. *) -external const_lshr : llvalue -> llvalue -> llvalue = "LLVMConstLShr" +val const_lshr : llvalue -> llvalue -> llvalue (** [const_ashr c1 c2] returns the constant integer [c1] right-shifted by the constant integer [c2] with sign extension. See the method [llvm::ConstantExpr::getAShr]. *) -external const_ashr : llvalue -> llvalue -> llvalue = "LLVMConstAShr" +val const_ashr : llvalue -> llvalue -> llvalue (** [const_gep pc indices] returns the constant [getElementPtr] of [p1] with the constant integers indices from the array [indices]. See the method [llvm::ConstantExpr::getGetElementPtr]. *) -external const_gep : llvalue -> llvalue array -> llvalue = "llvm_const_gep" +val const_gep : llvalue -> llvalue array -> llvalue (** [const_in_bounds_gep pc indices] returns the constant [getElementPtr] of [p1] with the constant integers indices from the array [indices]. See the method [llvm::ConstantExpr::getInBoundsGetElementPtr]. *) -external const_in_bounds_gep : llvalue -> llvalue array -> llvalue - = "llvm_const_in_bounds_gep" +val const_in_bounds_gep : llvalue -> llvalue array -> llvalue + (** [const_trunc c ty] returns the constant truncation of integer constant [c] to the smaller integer type [ty]. See the method [llvm::ConstantExpr::getTrunc]. *) -external const_trunc : llvalue -> lltype -> llvalue = "LLVMConstTrunc" +val const_trunc : llvalue -> lltype -> llvalue (** [const_sext c ty] returns the constant sign extension of integer constant [c] to the larger integer type [ty]. See the method [llvm::ConstantExpr::getSExt]. *) -external const_sext : llvalue -> lltype -> llvalue = "LLVMConstSExt" +val const_sext : llvalue -> lltype -> llvalue (** [const_zext c ty] returns the constant zero extension of integer constant [c] to the larger integer type [ty]. See the method [llvm::ConstantExpr::getZExt]. *) -external const_zext : llvalue -> lltype -> llvalue = "LLVMConstZExt" +val const_zext : llvalue -> lltype -> llvalue (** [const_fptrunc c ty] returns the constant truncation of floating point constant [c] to the smaller floating point type [ty]. See the method [llvm::ConstantExpr::getFPTrunc]. *) -external const_fptrunc : llvalue -> lltype -> llvalue = "LLVMConstFPTrunc" +val const_fptrunc : llvalue -> lltype -> llvalue (** [const_fpext c ty] returns the constant extension of floating point constant [c] to the larger floating point type [ty]. See the method [llvm::ConstantExpr::getFPExt]. *) -external const_fpext : llvalue -> lltype -> llvalue = "LLVMConstFPExt" +val const_fpext : llvalue -> lltype -> llvalue (** [const_uitofp c ty] returns the constant floating point conversion of unsigned integer constant [c] to the floating point type [ty]. See the method [llvm::ConstantExpr::getUIToFP]. *) -external const_uitofp : llvalue -> lltype -> llvalue = "LLVMConstUIToFP" +val const_uitofp : llvalue -> lltype -> llvalue (** [const_sitofp c ty] returns the constant floating point conversion of signed integer constant [c] to the floating point type [ty]. See the method [llvm::ConstantExpr::getSIToFP]. *) -external const_sitofp : llvalue -> lltype -> llvalue = "LLVMConstSIToFP" +val const_sitofp : llvalue -> lltype -> llvalue (** [const_fptoui c ty] returns the constant unsigned integer conversion of floating point constant [c] to integer type [ty]. See the method [llvm::ConstantExpr::getFPToUI]. *) -external const_fptoui : llvalue -> lltype -> llvalue = "LLVMConstFPToUI" +val const_fptoui : llvalue -> lltype -> llvalue (** [const_fptoui c ty] returns the constant unsigned integer conversion of floating point constant [c] to integer type [ty]. See the method [llvm::ConstantExpr::getFPToSI]. *) -external const_fptosi : llvalue -> lltype -> llvalue = "LLVMConstFPToSI" +val const_fptosi : llvalue -> lltype -> llvalue (** [const_ptrtoint c ty] returns the constant integer conversion of pointer constant [c] to integer type [ty]. See the method [llvm::ConstantExpr::getPtrToInt]. *) -external const_ptrtoint : llvalue -> lltype -> llvalue = "LLVMConstPtrToInt" +val const_ptrtoint : llvalue -> lltype -> llvalue (** [const_inttoptr c ty] returns the constant pointer conversion of integer constant [c] to pointer type [ty]. See the method [llvm::ConstantExpr::getIntToPtr]. *) -external const_inttoptr : llvalue -> lltype -> llvalue = "LLVMConstIntToPtr" +val const_inttoptr : llvalue -> lltype -> llvalue (** [const_bitcast c ty] returns the constant bitwise conversion of constant [c] to type [ty] of equal size. See the method [llvm::ConstantExpr::getBitCast]. *) -external const_bitcast : llvalue -> lltype -> llvalue = "LLVMConstBitCast" +val const_bitcast : llvalue -> lltype -> llvalue (** [const_zext_or_bitcast c ty] returns a constant zext or bitwise cast conversion of constant [c] to type [ty]. See the method [llvm::ConstantExpr::getZExtOrBitCast]. *) -external const_zext_or_bitcast : llvalue -> lltype -> llvalue - = "LLVMConstZExtOrBitCast" +val const_zext_or_bitcast : llvalue -> lltype -> llvalue + (** [const_sext_or_bitcast c ty] returns a constant sext or bitwise cast conversion of constant [c] to type [ty]. See the method [llvm::ConstantExpr::getSExtOrBitCast]. *) -external const_sext_or_bitcast : llvalue -> lltype -> llvalue - = "LLVMConstSExtOrBitCast" +val const_sext_or_bitcast : llvalue -> lltype -> llvalue + (** [const_trunc_or_bitcast c ty] returns a constant trunc or bitwise cast conversion of constant [c] to type [ty]. See the method [llvm::ConstantExpr::getTruncOrBitCast]. *) -external const_trunc_or_bitcast : llvalue -> lltype -> llvalue - = "LLVMConstTruncOrBitCast" +val const_trunc_or_bitcast : llvalue -> lltype -> llvalue + (** [const_pointercast c ty] returns a constant bitcast or a pointer-to-int cast conversion of constant [c] to type [ty] of equal size. See the method [llvm::ConstantExpr::getPointerCast]. *) -external const_pointercast : llvalue -> lltype -> llvalue - = "LLVMConstPointerCast" +val const_pointercast : llvalue -> lltype -> llvalue + (** [const_intcast c ty] returns a constant zext, bitcast, or trunc for integer -> integer casts of constant [c] to type [ty]. See the method [llvm::ConstantExpr::getIntCast]. *) -external const_intcast : llvalue -> lltype -> llvalue - = "LLVMConstIntCast" +val const_intcast : llvalue -> lltype -> llvalue + (** [const_fpcast c ty] returns a constant fpext, bitcast, or fptrunc for fp -> fp casts of constant [c] to type [ty]. See the method [llvm::ConstantExpr::getFPCast]. *) -external const_fpcast : llvalue -> lltype -> llvalue - = "LLVMConstFPCast" +val const_fpcast : llvalue -> lltype -> llvalue + (** [const_select cond t f] returns the constant conditional which returns value [t] if the boolean constant [cond] is true and the value [f] otherwise. See the method [llvm::ConstantExpr::getSelect]. *) -external const_select : llvalue -> llvalue -> llvalue -> llvalue - = "LLVMConstSelect" +val const_select : llvalue -> llvalue -> llvalue -> llvalue + (** [const_extractelement vec i] returns the constant [i]th element of constant vector [vec]. [i] must be a constant [i32] value unsigned less than the size of the vector. See the method [llvm::ConstantExpr::getExtractElement]. *) -external const_extractelement : llvalue -> llvalue -> llvalue - = "LLVMConstExtractElement" +val const_extractelement : llvalue -> llvalue -> llvalue + (** [const_insertelement vec v i] returns the constant vector with the same elements as constant vector [v] but the [i]th element replaced by the @@ -977,82 +977,82 @@ external const_extractelement : llvalue -> llvalue -> llvalue elements. [i] must be a constant [i32] value unsigned less than the size of the vector. See the method [llvm::ConstantExpr::getInsertElement]. *) -external const_insertelement : llvalue -> llvalue -> llvalue -> llvalue - = "LLVMConstInsertElement" +val const_insertelement : llvalue -> llvalue -> llvalue -> llvalue + (** [const_shufflevector a b mask] returns a constant [shufflevector]. See the LLVM Language Reference for details on the [shufflevector] instruction. See the method [llvm::ConstantExpr::getShuffleVector]. *) -external const_shufflevector : llvalue -> llvalue -> llvalue -> llvalue - = "LLVMConstShuffleVector" +val const_shufflevector : llvalue -> llvalue -> llvalue -> llvalue + (** [const_extractvalue agg idxs] returns the constant [idxs]th value of constant aggregate [agg]. Each [idxs] must be less than the size of the aggregate. See the method [llvm::ConstantExpr::getExtractValue]. *) -external const_extractvalue : llvalue -> int array -> llvalue - = "llvm_const_extractvalue" +val const_extractvalue : llvalue -> int array -> llvalue + (** [const_insertvalue agg val idxs] inserts the value [val] in the specified indexs [idxs] in the aggegate [agg]. Each [idxs] must be less than the size of the aggregate. See the method [llvm::ConstantExpr::getInsertValue]. *) -external const_insertvalue : llvalue -> llvalue -> int array -> llvalue - = "llvm_const_insertvalue" +val const_insertvalue : llvalue -> llvalue -> int array -> llvalue + (** [const_inline_asm ty asm con side align] inserts a inline assembly string. See the method [llvm::InlineAsm::get]. *) -external const_inline_asm : lltype -> string -> string -> bool -> bool -> +val const_inline_asm : lltype -> string -> string -> bool -> bool -> llvalue - = "llvm_const_inline_asm" + (** [block_address f bb] returns the address of the basic block [bb] in the function [f]. See the method [llvm::BasicBlock::get]. *) -external block_address : llvalue -> llbasicblock -> llvalue = "LLVMBlockAddress" +val block_address : llvalue -> llbasicblock -> llvalue (** {7 Operations on global variables, functions, and aliases (globals)} *) (** [global_parent g] is the enclosing module of the global value [g]. See the method [llvm::GlobalValue::getParent]. *) -external global_parent : llvalue -> llmodule = "LLVMGetGlobalParent" +val global_parent : llvalue -> llmodule (** [is_declaration g] returns [true] if the global value [g] is a declaration only. Returns [false] otherwise. See the method [llvm::GlobalValue::isDeclaration]. *) -external is_declaration : llvalue -> bool = "llvm_is_declaration" +val is_declaration : llvalue -> bool (** [linkage g] returns the linkage of the global value [g]. See the method [llvm::GlobalValue::getLinkage]. *) -external linkage : llvalue -> Linkage.t = "llvm_linkage" +val linkage : llvalue -> Linkage.t (** [set_linkage l g] sets the linkage of the global value [g] to [l]. See the method [llvm::GlobalValue::setLinkage]. *) -external set_linkage : Linkage.t -> llvalue -> unit = "llvm_set_linkage" +val set_linkage : Linkage.t -> llvalue -> unit (** [section g] returns the linker section of the global value [g]. See the method [llvm::GlobalValue::getSection]. *) -external section : llvalue -> string = "llvm_section" +val section : llvalue -> string (** [set_section s g] sets the linker section of the global value [g] to [s]. See the method [llvm::GlobalValue::setSection]. *) -external set_section : string -> llvalue -> unit = "llvm_set_section" +val set_section : string -> llvalue -> unit (** [visibility g] returns the linker visibility of the global value [g]. See the method [llvm::GlobalValue::getVisibility]. *) -external visibility : llvalue -> Visibility.t = "llvm_visibility" +val visibility : llvalue -> Visibility.t (** [set_visibility v g] sets the linker visibility of the global value [g] to [v]. See the method [llvm::GlobalValue::setVisibility]. *) -external set_visibility : Visibility.t -> llvalue -> unit - = "llvm_set_visibility" +val set_visibility : Visibility.t -> llvalue -> unit + (** [alignment g] returns the required alignment of the global value [g]. See the method [llvm::GlobalValue::getAlignment]. *) -external alignment : llvalue -> int = "llvm_alignment" +val alignment : llvalue -> int (** [set_alignment n g] sets the required alignment of the global value [g] to [n] bytes. See the method [llvm::GlobalValue::setAlignment]. *) -external set_alignment : int -> llvalue -> unit = "llvm_set_alignment" +val set_alignment : int -> llvalue -> unit (** {7 Operations on global variables} *) @@ -1061,55 +1061,55 @@ external set_alignment : int -> llvalue -> unit = "llvm_set_alignment" with name [name] in module [m] in the default address space (0). If such a global variable already exists, it is returned. If the type of the existing global differs, then a bitcast to [ty] is returned. *) -external declare_global : lltype -> string -> llmodule -> llvalue - = "llvm_declare_global" +val declare_global : lltype -> string -> llmodule -> llvalue + (** [declare_qualified_global ty name addrspace m] returns a new global variable of type [ty] and with name [name] in module [m] in the address space [addrspace]. If such a global variable already exists, it is returned. If the type of the existing global differs, then a bitcast to [ty] is returned. *) -external declare_qualified_global : lltype -> string -> int -> llmodule -> +val declare_qualified_global : lltype -> string -> int -> llmodule -> llvalue - = "llvm_declare_qualified_global" + (** [define_global name init m] returns a new global with name [name] and initializer [init] in module [m] in the default address space (0). If the named global already exists, it is renamed. See the constructor of [llvm::GlobalVariable]. *) -external define_global : string -> llvalue -> llmodule -> llvalue - = "llvm_define_global" +val define_global : string -> llvalue -> llmodule -> llvalue + (** [define_qualified_global name init addrspace m] returns a new global with name [name] and initializer [init] in module [m] in the address space [addrspace]. If the named global already exists, it is renamed. See the constructor of [llvm::GlobalVariable]. *) -external define_qualified_global : string -> llvalue -> int -> llmodule -> +val define_qualified_global : string -> llvalue -> int -> llmodule -> llvalue - = "llvm_define_qualified_global" + (** [lookup_global name m] returns [Some g] if a global variable with name [name] exists in module [m]. If no such global exists, returns [None]. See the [llvm::GlobalVariable] constructor. *) -external lookup_global : string -> llmodule -> llvalue option - = "llvm_lookup_global" +val lookup_global : string -> llmodule -> llvalue option + (** [delete_global gv] destroys the global variable [gv]. See the method [llvm::GlobalVariable::eraseFromParent]. *) -external delete_global : llvalue -> unit = "llvm_delete_global" +val delete_global : llvalue -> unit (** [global_begin m] returns the first position in the global variable list of the module [m]. [global_begin] and [global_succ] can be used to iterate over the global list in order. See the method [llvm::Module::global_begin]. *) -external global_begin : llmodule -> (llmodule, llvalue) llpos - = "llvm_global_begin" +val global_begin : llmodule -> (llmodule, llvalue) llpos + (** [global_succ gv] returns the global variable list position succeeding [Before gv]. See the method [llvm::Module::global_iterator::operator++]. *) -external global_succ : llvalue -> (llmodule, llvalue) llpos - = "llvm_global_succ" +val global_succ : llvalue -> (llmodule, llvalue) llpos + (** [iter_globals f m] applies function [f] to each of the global variables of module [m] in order. Tail recursive. *) @@ -1123,14 +1123,14 @@ val fold_left_globals : ('a -> llvalue -> 'a) -> 'a -> llmodule -> 'a module [m]. [global_end] and [global_pred] can be used to iterate over the global list in reverse. See the method [llvm::Module::global_end]. *) -external global_end : llmodule -> (llmodule, llvalue) llrev_pos - = "llvm_global_end" +val global_end : llmodule -> (llmodule, llvalue) llrev_pos + (** [global_pred gv] returns the global variable list position preceding [After gv]. See the method [llvm::Module::global_iterator::operator--]. *) -external global_pred : llvalue -> (llmodule, llvalue) llrev_pos - = "llvm_global_pred" +val global_pred : llvalue -> (llmodule, llvalue) llrev_pos + (** [rev_iter_globals f m] applies function [f] to each of the global variables of module [m] in reverse order. Tail recursive. *) @@ -1143,37 +1143,37 @@ val fold_right_globals : (llvalue -> 'a -> 'a) -> llmodule -> 'a -> 'a (** [is_global_constant gv] returns [true] if the global variabile [gv] is a constant. Returns [false] otherwise. See the method [llvm::GlobalVariable::isConstant]. *) -external is_global_constant : llvalue -> bool = "llvm_is_global_constant" +val is_global_constant : llvalue -> bool (** [set_global_constant c gv] sets the global variable [gv] to be a constant if [c] is [true] and not if [c] is [false]. See the method [llvm::GlobalVariable::setConstant]. *) -external set_global_constant : bool -> llvalue -> unit - = "llvm_set_global_constant" +val set_global_constant : bool -> llvalue -> unit + (** [global_initializer gv] returns the initializer for the global variable [gv]. See the method [llvm::GlobalVariable::getInitializer]. *) -external global_initializer : llvalue -> llvalue = "LLVMGetInitializer" +val global_initializer : llvalue -> llvalue (** [set_initializer c gv] sets the initializer for the global variable [gv] to the constant [c]. See the method [llvm::GlobalVariable::setInitializer]. *) -external set_initializer : llvalue -> llvalue -> unit = "llvm_set_initializer" +val set_initializer : llvalue -> llvalue -> unit (** [remove_initializer gv] unsets the initializer for the global variable [gv]. See the method [llvm::GlobalVariable::setInitializer]. *) -external remove_initializer : llvalue -> unit = "llvm_remove_initializer" +val remove_initializer : llvalue -> unit (** [is_thread_local gv] returns [true] if the global variable [gv] is thread-local and [false] otherwise. See the method [llvm::GlobalVariable::isThreadLocal]. *) -external is_thread_local : llvalue -> bool = "llvm_is_thread_local" +val is_thread_local : llvalue -> bool (** [set_thread_local c gv] sets the global variable [gv] to be thread local if [c] is [true] and not otherwise. See the method [llvm::GlobalVariable::setThreadLocal]. *) -external set_thread_local : bool -> llvalue -> unit = "llvm_set_thread_local" +val set_thread_local : bool -> llvalue -> unit (** {7 Operations on aliases} *) @@ -1181,8 +1181,8 @@ external set_thread_local : bool -> llvalue -> unit = "llvm_set_thread_local" (** [add_alias m t a n] inserts an alias in the module [m] with the type [t] and the aliasee [a] with the name [n]. See the constructor for [llvm::GlobalAlias]. *) -external add_alias : llmodule -> lltype -> llvalue -> string -> llvalue - = "llvm_add_alias" +val add_alias : llmodule -> lltype -> llvalue -> string -> llvalue + (** {7 Operations on functions} *) @@ -1191,38 +1191,38 @@ external add_alias : llmodule -> lltype -> llvalue -> string -> llvalue with name [name] in module [m]. If such a function already exists, it is returned. If the type of the existing function differs, then a bitcast to [ty] is returned. *) -external declare_function : string -> lltype -> llmodule -> llvalue - = "llvm_declare_function" +val declare_function : string -> lltype -> llmodule -> llvalue + (** [define_function name ty m] creates a new function with name [name] and type [ty] in module [m]. If the named function already exists, it is renamed. An entry basic block is created in the function. See the constructor of [llvm::GlobalVariable]. *) -external define_function : string -> lltype -> llmodule -> llvalue - = "llvm_define_function" +val define_function : string -> lltype -> llmodule -> llvalue + (** [lookup_function name m] returns [Some f] if a function with name [name] exists in module [m]. If no such function exists, returns [None]. See the method [llvm::Module] constructor. *) -external lookup_function : string -> llmodule -> llvalue option - = "llvm_lookup_function" +val lookup_function : string -> llmodule -> llvalue option + (** [delete_function f] destroys the function [f]. See the method [llvm::Function::eraseFromParent]. *) -external delete_function : llvalue -> unit = "llvm_delete_function" +val delete_function : llvalue -> unit (** [function_begin m] returns the first position in the function list of the module [m]. [function_begin] and [function_succ] can be used to iterate over the function list in order. See the method [llvm::Module::begin]. *) -external function_begin : llmodule -> (llmodule, llvalue) llpos - = "llvm_function_begin" +val function_begin : llmodule -> (llmodule, llvalue) llpos + (** [function_succ gv] returns the function list position succeeding [Before gv]. See the method [llvm::Module::iterator::operator++]. *) -external function_succ : llvalue -> (llmodule, llvalue) llpos - = "llvm_function_succ" +val function_succ : llvalue -> (llmodule, llvalue) llpos + (** [iter_functions f m] applies function [f] to each of the functions of module [m] in order. Tail recursive. *) @@ -1236,13 +1236,13 @@ val fold_left_functions : ('a -> llvalue -> 'a) -> 'a -> llmodule -> 'a the module [m]. [function_end] and [function_pred] can be used to iterate over the function list in reverse. See the method [llvm::Module::end]. *) -external function_end : llmodule -> (llmodule, llvalue) llrev_pos - = "llvm_function_end" +val function_end : llmodule -> (llmodule, llvalue) llrev_pos + (** [function_pred gv] returns the function list position preceding [After gv]. See the method [llvm::Module::iterator::operator--]. *) -external function_pred : llvalue -> (llmodule, llvalue) llrev_pos - = "llvm_function_pred" +val function_pred : llvalue -> (llmodule, llvalue) llrev_pos + (** [rev_iter_functions f fn] applies function [f] to each of the functions of module [m] in reverse order. Tail recursive. *) @@ -1254,26 +1254,26 @@ val fold_right_functions : (llvalue -> 'a -> 'a) -> llmodule -> 'a -> 'a (** [is_intrinsic f] returns true if the function [f] is an intrinsic. See the method [llvm::Function::isIntrinsic]. *) -external is_intrinsic : llvalue -> bool = "llvm_is_intrinsic" +val is_intrinsic : llvalue -> bool (** [function_call_conv f] returns the calling convention of the function [f]. See the method [llvm::Function::getCallingConv]. *) -external function_call_conv : llvalue -> int = "llvm_function_call_conv" +val function_call_conv : llvalue -> int (** [set_function_call_conv cc f] sets the calling convention of the function [f] to the calling convention numbered [cc]. See the method [llvm::Function::setCallingConv]. *) -external set_function_call_conv : int -> llvalue -> unit - = "llvm_set_function_call_conv" +val set_function_call_conv : int -> llvalue -> unit + (** [gc f] returns [Some name] if the function [f] has a garbage collection algorithm specified and [None] otherwise. See the method [llvm::Function::getGC]. *) -external gc : llvalue -> string option = "llvm_gc" +val gc : llvalue -> string option (** [set_gc gc f] sets the collection algorithm for the function [f] to [gc]. See the method [llvm::Function::setGC]. *) -external set_gc : string option -> llvalue -> unit = "llvm_set_gc" +val set_gc : string option -> llvalue -> unit (** [add_function_attr f a] adds attribute [a] to the return type of function [f]. *) @@ -1287,26 +1287,26 @@ val remove_function_attr : llvalue -> Attribute.t -> unit (** [params f] returns the parameters of function [f]. See the method [llvm::Function::getArgumentList]. *) -external params : llvalue -> llvalue array = "llvm_params" +val params : llvalue -> llvalue array (** [param f n] returns the [n]th parameter of function [f]. See the method [llvm::Function::getArgumentList]. *) -external param : llvalue -> int -> llvalue = "llvm_param" +val param : llvalue -> int -> llvalue (** [param_parent p] returns the parent function that owns the parameter. See the method [llvm::Argument::getParent]. *) -external param_parent : llvalue -> llvalue = "LLVMGetParamParent" +val param_parent : llvalue -> llvalue (** [param_begin f] returns the first position in the parameter list of the function [f]. [param_begin] and [param_succ] can be used to iterate over the parameter list in order. See the method [llvm::Function::arg_begin]. *) -external param_begin : llvalue -> (llvalue, llvalue) llpos = "llvm_param_begin" +val param_begin : llvalue -> (llvalue, llvalue) llpos (** [param_succ bb] returns the parameter list position succeeding [Before bb]. See the method [llvm::Function::arg_iterator::operator++]. *) -external param_succ : llvalue -> (llvalue, llvalue) llpos = "llvm_param_succ" +val param_succ : llvalue -> (llvalue, llvalue) llpos (** [iter_params f fn] applies function [f] to each of the parameters of function [fn] in order. Tail recursive. *) @@ -1320,12 +1320,12 @@ val fold_left_params : ('a -> llvalue -> 'a) -> 'a -> llvalue -> 'a the function [f]. [param_end] and [param_pred] can be used to iterate over the parameter list in reverse. See the method [llvm::Function::arg_end]. *) -external param_end : llvalue -> (llvalue, llvalue) llrev_pos = "llvm_param_end" +val param_end : llvalue -> (llvalue, llvalue) llrev_pos (** [param_pred gv] returns the function list position preceding [After gv]. See the method [llvm::Function::arg_iterator::operator--]. *) -external param_pred : llvalue -> (llvalue, llvalue) llrev_pos - = "llvm_param_pred" +val param_pred : llvalue -> (llvalue, llvalue) llrev_pos + (** [rev_iter_params f fn] applies function [f] to each of the parameters of function [fn] in reverse order. Tail recursive. *) @@ -1342,51 +1342,51 @@ val add_param_attr : llvalue -> Attribute.t -> unit val remove_param_attr : llvalue -> Attribute.t -> unit (** [set_param_alignment p a] set the alignment of parameter [p] to [a]. *) -external set_param_alignment : llvalue -> int -> unit - = "llvm_set_param_alignment" +val set_param_alignment : llvalue -> int -> unit + (** {7 Operations on basic blocks} *) (** [basic_blocks fn] returns the basic blocks of the function [f]. See the method [llvm::Function::getBasicBlockList]. *) -external basic_blocks : llvalue -> llbasicblock array = "llvm_basic_blocks" +val basic_blocks : llvalue -> llbasicblock array (** [entry_block fn] returns the entry basic block of the function [f]. See the method [llvm::Function::getEntryBlock]. *) -external entry_block : llvalue -> llbasicblock = "LLVMGetEntryBasicBlock" +val entry_block : llvalue -> llbasicblock (** [delete_block bb] deletes the basic block [bb]. See the method [llvm::BasicBlock::eraseFromParent]. *) -external delete_block : llbasicblock -> unit = "llvm_delete_block" +val delete_block : llbasicblock -> unit (** [append_block c name f] creates a new basic block named [name] at the end of function [f] in the context [c]. See the constructor of [llvm::BasicBlock]. *) -external append_block : llcontext -> string -> llvalue -> llbasicblock - = "llvm_append_block" +val append_block : llcontext -> string -> llvalue -> llbasicblock + (** [insert_block c name bb] creates a new basic block named [name] before the basic block [bb] in the context [c]. See the constructor of [llvm::BasicBlock]. *) -external insert_block : llcontext -> string -> llbasicblock -> llbasicblock - = "llvm_insert_block" +val insert_block : llcontext -> string -> llbasicblock -> llbasicblock + (** [block_parent bb] returns the parent function that owns the basic block. See the method [llvm::BasicBlock::getParent]. *) -external block_parent : llbasicblock -> llvalue = "LLVMGetBasicBlockParent" +val block_parent : llbasicblock -> llvalue (** [block_begin f] returns the first position in the basic block list of the function [f]. [block_begin] and [block_succ] can be used to iterate over the basic block list in order. See the method [llvm::Function::begin]. *) -external block_begin : llvalue -> (llvalue, llbasicblock) llpos - = "llvm_block_begin" +val block_begin : llvalue -> (llvalue, llbasicblock) llpos + (** [block_succ bb] returns the basic block list position succeeding [Before bb]. See the method [llvm::Function::iterator::operator++]. *) -external block_succ : llbasicblock -> (llvalue, llbasicblock) llpos - = "llvm_block_succ" +val block_succ : llbasicblock -> (llvalue, llbasicblock) llpos + (** [iter_blocks f fn] applies function [f] to each of the basic blocks of function [fn] in order. Tail recursive. *) @@ -1400,13 +1400,13 @@ val fold_left_blocks : ('a -> llbasicblock -> 'a) -> 'a -> llvalue -> 'a the function [f]. [block_end] and [block_pred] can be used to iterate over the basic block list in reverse. See the method [llvm::Function::end]. *) -external block_end : llvalue -> (llvalue, llbasicblock) llrev_pos - = "llvm_block_end" +val block_end : llvalue -> (llvalue, llbasicblock) llrev_pos + (** [block_pred gv] returns the function list position preceding [After gv]. See the method [llvm::Function::iterator::operator--]. *) -external block_pred : llbasicblock -> (llvalue, llbasicblock) llrev_pos - = "llvm_block_pred" +val block_pred : llbasicblock -> (llvalue, llbasicblock) llrev_pos + (** [rev_iter_blocks f fn] applies function [f] to each of the basic blocks of function [fn] in reverse order. Tail recursive. *) @@ -1417,34 +1417,34 @@ val rev_iter_blocks : (llbasicblock -> unit) -> llvalue -> unit val fold_right_blocks : (llbasicblock -> 'a -> 'a) -> llvalue -> 'a -> 'a (** [value_of_block bb] losslessly casts [bb] to an [llvalue]. *) -external value_of_block : llbasicblock -> llvalue = "LLVMBasicBlockAsValue" +val value_of_block : llbasicblock -> llvalue (** [value_is_block v] returns [true] if the value [v] is a basic block and [false] otherwise. Similar to [llvm::isa]. *) -external value_is_block : llvalue -> bool = "llvm_value_is_block" +val value_is_block : llvalue -> bool (** [block_of_value v] losslessly casts [v] to an [llbasicblock]. *) -external block_of_value : llvalue -> llbasicblock = "LLVMValueAsBasicBlock" +val block_of_value : llvalue -> llbasicblock (** {7 Operations on instructions} *) (** [instr_parent i] is the enclosing basic block of the instruction [i]. See the method [llvm::Instruction::getParent]. *) -external instr_parent : llvalue -> llbasicblock = "LLVMGetInstructionParent" +val instr_parent : llvalue -> llbasicblock (** [instr_begin bb] returns the first position in the instruction list of the basic block [bb]. [instr_begin] and [instr_succ] can be used to iterate over the instruction list in order. See the method [llvm::BasicBlock::begin]. *) -external instr_begin : llbasicblock -> (llbasicblock, llvalue) llpos - = "llvm_instr_begin" +val instr_begin : llbasicblock -> (llbasicblock, llvalue) llpos + (** [instr_succ i] returns the instruction list position succeeding [Before i]. See the method [llvm::BasicBlock::iterator::operator++]. *) -external instr_succ : llvalue -> (llbasicblock, llvalue) llpos - = "llvm_instr_succ" +val instr_succ : llvalue -> (llbasicblock, llvalue) llpos + (** [iter_instrs f bb] applies function [f] to each of the instructions of basic block [bb] in order. Tail recursive. *) @@ -1458,13 +1458,13 @@ val fold_left_instrs: ('a -> llvalue -> 'a) -> 'a -> llbasicblock -> 'a basic block [bb]. [instr_end] and [instr_pred] can be used to iterate over the instruction list in reverse. See the method [llvm::BasicBlock::end]. *) -external instr_end : llbasicblock -> (llbasicblock, llvalue) llrev_pos - = "llvm_instr_end" +val instr_end : llbasicblock -> (llbasicblock, llvalue) llrev_pos + (** [instr_pred i] returns the instruction list position preceding [After i]. See the method [llvm::BasicBlock::iterator::operator--]. *) -external instr_pred : llvalue -> (llbasicblock, llvalue) llrev_pos - = "llvm_instr_pred" +val instr_pred : llvalue -> (llbasicblock, llvalue) llrev_pos + (** [fold_right_instrs f bb init] is [f (... (f init fN) ...) f1] where [f1,...,fN] are the instructions of basic block [bb]. Tail recursive. *) @@ -1477,16 +1477,16 @@ val fold_right_instrs: (llvalue -> 'a -> 'a) -> llbasicblock -> 'a -> 'a instruction [ci], which may be one of the values from the module {!CallConv}. See the method [llvm::CallInst::getCallingConv] and [llvm::InvokeInst::getCallingConv]. *) -external instruction_call_conv: llvalue -> int - = "llvm_instruction_call_conv" +val instruction_call_conv: llvalue -> int + (** [set_instruction_call_conv cc ci] sets the calling convention for the call or invoke instruction [ci] to the integer [cc], which can be one of the values from the module {!CallConv}. See the method [llvm::CallInst::setCallingConv] and [llvm::InvokeInst::setCallingConv]. *) -external set_instruction_call_conv: int -> llvalue -> unit - = "llvm_set_instruction_call_conv" +val set_instruction_call_conv: int -> llvalue -> unit + (** [add_instruction_param_attr ci i a] adds attribute [a] to the [i]th parameter of the call or invoke instruction [ci]. [i]=0 denotes the return @@ -1503,23 +1503,23 @@ val remove_instruction_param_attr : llvalue -> int -> Attribute.t -> unit (** [is_tail_call ci] is [true] if the call instruction [ci] is flagged as eligible for tail call optimization, [false] otherwise. See the method [llvm::CallInst::isTailCall]. *) -external is_tail_call : llvalue -> bool = "llvm_is_tail_call" +val is_tail_call : llvalue -> bool (** [set_tail_call tc ci] flags the call instruction [ci] as eligible for tail call optimization if [tc] is [true], clears otherwise. See the method [llvm::CallInst::setTailCall]. *) -external set_tail_call : bool -> llvalue -> unit = "llvm_set_tail_call" +val set_tail_call : bool -> llvalue -> unit (** {7 Operations on phi nodes} *) (** [add_incoming (v, bb) pn] adds the value [v] to the phi node [pn] for use with branches from [bb]. See the method [llvm::PHINode::addIncoming]. *) -external add_incoming : (llvalue * llbasicblock) -> llvalue -> unit - = "llvm_add_incoming" +val add_incoming : (llvalue * llbasicblock) -> llvalue -> unit + (** [incoming pn] returns the list of value-block pairs for phi node [pn]. See the method [llvm::PHINode::getIncomingValue]. *) -external incoming : llvalue -> (llvalue * llbasicblock) list = "llvm_incoming" +val incoming : llvalue -> (llvalue * llbasicblock) list @@ -1529,7 +1529,7 @@ external incoming : llvalue -> (llvalue * llbasicblock) list = "llvm_incoming" the context [context]. It is invalid to use this builder until its position is set with {!position_before} or {!position_at_end}. See the constructor for [llvm::LLVMBuilder]. *) -external builder : llcontext -> llbuilder = "llvm_builder" +val builder : llcontext -> llbuilder (** [builder_at ip] creates an instruction builder positioned at [ip]. See the constructor for [llvm::LLVMBuilder]. *) @@ -1546,8 +1546,8 @@ val builder_at_end : llcontext -> llbasicblock -> llbuilder (** [position_builder ip bb] moves the instruction builder [bb] to the position [ip]. See the constructor for [llvm::LLVMBuilder]. *) -external position_builder : (llbasicblock, llvalue) llpos -> llbuilder -> unit - = "llvm_position_builder" +val position_builder : (llbasicblock, llvalue) llpos -> llbuilder -> unit + (** [position_before ins b] moves the instruction builder [b] to before the instruction [isn]. See the method [llvm::LLVMBuilder::SetInsertPoint]. *) @@ -1561,38 +1561,38 @@ val position_at_end : llbasicblock -> llbuilder -> unit positioned to insert into. Raises [Not_Found] if the instruction builder is uninitialized. See the method [llvm::LLVMBuilder::GetInsertBlock]. *) -external insertion_block : llbuilder -> llbasicblock = "llvm_insertion_block" +val insertion_block : llbuilder -> llbasicblock (** [insert_into_builder i name b] inserts the specified instruction [i] at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::Insert]. *) -external insert_into_builder : llvalue -> string -> llbuilder -> unit - = "llvm_insert_into_builder" +val insert_into_builder : llvalue -> string -> llbuilder -> unit + (** {7 Metadata} *) (** [set_current_debug_location b md] sets the current debug location [md] in the builder [b]. See the method [llvm::IRBuilder::SetDebugLocation]. *) -external set_current_debug_location : llbuilder -> llvalue -> unit - = "llvm_set_current_debug_location" +val set_current_debug_location : llbuilder -> llvalue -> unit + (** [clear_current_debug_location b] clears the current debug location in the builder [b]. *) -external clear_current_debug_location : llbuilder -> unit - = "llvm_clear_current_debug_location" +val clear_current_debug_location : llbuilder -> unit + (** [current_debug_location b] returns the current debug location, or None if none is currently set. See the method [llvm::IRBuilder::GetDebugLocation]. *) -external current_debug_location : llbuilder -> llvalue option - = "llvm_current_debug_location" +val current_debug_location : llbuilder -> llvalue option + (** [set_inst_debug_location b i] sets the current debug location of the builder [b] to the instruction [i]. See the method [llvm::IRBuilder::SetInstDebugLocation]. *) -external set_inst_debug_location : llbuilder -> llvalue -> unit - = "llvm_set_inst_debug_location" +val set_inst_debug_location : llbuilder -> llvalue -> unit + (** {7 Terminators} *) @@ -1600,81 +1600,81 @@ external set_inst_debug_location : llbuilder -> llvalue -> unit [ret void] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateRetVoid]. *) -external build_ret_void : llbuilder -> llvalue = "llvm_build_ret_void" +val build_ret_void : llbuilder -> llvalue (** [build_ret v b] creates a [ret %v] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateRet]. *) -external build_ret : llvalue -> llbuilder -> llvalue = "llvm_build_ret" +val build_ret : llvalue -> llbuilder -> llvalue (** [build_aggregate_ret vs b] creates a [ret {...} { %v1, %v2, ... } ] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateAggregateRet]. *) -external build_aggregate_ret : llvalue array -> llbuilder -> llvalue - = "llvm_build_aggregate_ret" +val build_aggregate_ret : llvalue array -> llbuilder -> llvalue + (** [build_br bb b] creates a [br %bb] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateBr]. *) -external build_br : llbasicblock -> llbuilder -> llvalue = "llvm_build_br" +val build_br : llbasicblock -> llbuilder -> llvalue (** [build_cond_br cond tbb fbb b] creates a [br %cond, %tbb, %fbb] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateCondBr]. *) -external build_cond_br : llvalue -> llbasicblock -> llbasicblock -> llbuilder -> - llvalue = "llvm_build_cond_br" +val build_cond_br : llvalue -> llbasicblock -> llbasicblock -> llbuilder -> + llvalue (** [build_switch case elsebb count b] creates an empty [switch %case, %elsebb] instruction at the position specified by the instruction builder [b] with space reserved for [count] cases. See the method [llvm::LLVMBuilder::CreateSwitch]. *) -external build_switch : llvalue -> llbasicblock -> int -> llbuilder -> llvalue - = "llvm_build_switch" +val build_switch : llvalue -> llbasicblock -> int -> llbuilder -> llvalue + (** [add_case sw onval bb] causes switch instruction [sw] to branch to [bb] when its input matches the constant [onval]. See the method [llvm::SwitchInst::addCase]. **) -external add_case : llvalue -> llvalue -> llbasicblock -> unit - = "llvm_add_case" +val add_case : llvalue -> llvalue -> llbasicblock -> unit + (** [build_indirect_br addr count b] creates a [indirectbr %addr] instruction at the position specified by the instruction builder [b] with space reserved for [count] destinations. See the method [llvm::LLVMBuilder::CreateIndirectBr]. *) -external build_indirect_br : llvalue -> int -> llbuilder -> llvalue - = "llvm_build_indirect_br" +val build_indirect_br : llvalue -> int -> llbuilder -> llvalue + (** [add_destination br bb] adds the basic block [bb] as a possible branch location for the indirectbr instruction [br]. See the method [llvm::IndirectBrInst::addDestination]. **) -external add_destination : llvalue -> llbasicblock -> unit - = "llvm_add_destination" +val add_destination : llvalue -> llbasicblock -> unit + (** [build_invoke fn args tobb unwindbb name b] creates an [%name = invoke %fn(args) to %tobb unwind %unwindbb] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateInvoke]. *) -external build_invoke : llvalue -> llvalue array -> llbasicblock -> +val build_invoke : llvalue -> llvalue array -> llbasicblock -> llbasicblock -> string -> llbuilder -> llvalue - = "llvm_build_invoke_bc" "llvm_build_invoke_nat" + (** [build_unwind b] creates an [unwind] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateUnwind]. *) -external build_unwind : llbuilder -> llvalue = "llvm_build_unwind" +val build_unwind : llbuilder -> llvalue (** [build_unreachable b] creates an [unreachable] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateUnwind]. *) -external build_unreachable : llbuilder -> llvalue = "llvm_build_unreachable" +val build_unreachable : llbuilder -> llvalue (** {7 Arithmetic} *) @@ -1683,216 +1683,216 @@ external build_unreachable : llbuilder -> llvalue = "llvm_build_unreachable" [%name = add %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateAdd]. *) -external build_add : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_add" +val build_add : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_nsw_add x y name b] creates a [%name = nsw add %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateNSWAdd]. *) -external build_nsw_add : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_nsw_add" +val build_nsw_add : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_nuw_add x y name b] creates a [%name = nuw add %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateNUWAdd]. *) -external build_nuw_add : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_nuw_add" +val build_nuw_add : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_fadd x y name b] creates a [%name = fadd %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateFAdd]. *) -external build_fadd : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_fadd" +val build_fadd : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_sub x y name b] creates a [%name = sub %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateSub]. *) -external build_sub : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_sub" +val build_sub : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_nsw_sub x y name b] creates a [%name = nsw sub %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateNSWSub]. *) -external build_nsw_sub : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_nsw_sub" +val build_nsw_sub : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_nuw_sub x y name b] creates a [%name = nuw sub %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateNUWSub]. *) -external build_nuw_sub : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_nuw_sub" +val build_nuw_sub : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_fsub x y name b] creates a [%name = fsub %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateFSub]. *) -external build_fsub : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_fsub" +val build_fsub : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_mul x y name b] creates a [%name = mul %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateMul]. *) -external build_mul : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_mul" +val build_mul : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_nsw_mul x y name b] creates a [%name = nsw mul %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateNSWMul]. *) -external build_nsw_mul : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_nsw_mul" +val build_nsw_mul : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_nuw_mul x y name b] creates a [%name = nuw mul %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateNUWMul]. *) -external build_nuw_mul : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_nuw_mul" +val build_nuw_mul : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_fmul x y name b] creates a [%name = fmul %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateFMul]. *) -external build_fmul : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_fmul" +val build_fmul : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_udiv x y name b] creates a [%name = udiv %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateUDiv]. *) -external build_udiv : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_udiv" +val build_udiv : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_sdiv x y name b] creates a [%name = sdiv %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateSDiv]. *) -external build_sdiv : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_sdiv" +val build_sdiv : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_exact_sdiv x y name b] creates a [%name = exact sdiv %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateExactSDiv]. *) -external build_exact_sdiv : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_exact_sdiv" +val build_exact_sdiv : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_fdiv x y name b] creates a [%name = fdiv %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateFDiv]. *) -external build_fdiv : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_fdiv" +val build_fdiv : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_urem x y name b] creates a [%name = urem %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateURem]. *) -external build_urem : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_urem" +val build_urem : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_SRem x y name b] creates a [%name = srem %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateSRem]. *) -external build_srem : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_srem" +val build_srem : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_frem x y name b] creates a [%name = frem %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateFRem]. *) -external build_frem : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_frem" +val build_frem : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_shl x y name b] creates a [%name = shl %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateShl]. *) -external build_shl : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_shl" +val build_shl : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_lshr x y name b] creates a [%name = lshr %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateLShr]. *) -external build_lshr : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_lshr" +val build_lshr : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_ashr x y name b] creates a [%name = ashr %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateAShr]. *) -external build_ashr : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_ashr" +val build_ashr : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_and x y name b] creates a [%name = and %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateAnd]. *) -external build_and : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_and" +val build_and : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_or x y name b] creates a [%name = or %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateOr]. *) -external build_or : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_or" +val build_or : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_xor x y name b] creates a [%name = xor %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateXor]. *) -external build_xor : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_xor" +val build_xor : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** [build_neg x name b] creates a [%name = sub 0, %x] instruction at the position specified by the instruction builder [b]. [-0.0] is used for floating point types to compute the correct sign. See the method [llvm::LLVMBuilder::CreateNeg]. *) -external build_neg : llvalue -> string -> llbuilder -> llvalue - = "llvm_build_neg" +val build_neg : llvalue -> string -> llbuilder -> llvalue + (** [build_nsw_neg x name b] creates a [%name = nsw sub 0, %x] instruction at the position specified by the instruction builder [b]. [-0.0] is used for floating point types to compute the correct sign. See the method [llvm::LLVMBuilder::CreateNeg]. *) -external build_nsw_neg : llvalue -> string -> llbuilder -> llvalue - = "llvm_build_nsw_neg" +val build_nsw_neg : llvalue -> string -> llbuilder -> llvalue + (** [build_nuw_neg x name b] creates a [%name = nuw sub 0, %x] instruction at the position specified by the instruction builder [b]. [-0.0] is used for floating point types to compute the correct sign. See the method [llvm::LLVMBuilder::CreateNeg]. *) -external build_nuw_neg : llvalue -> string -> llbuilder -> llvalue - = "llvm_build_nuw_neg" +val build_nuw_neg : llvalue -> string -> llbuilder -> llvalue + (** [build_fneg x name b] creates a [%name = fsub 0, %x] instruction at the position specified by the instruction builder [b]. [-0.0] is used for floating point types to compute the correct sign. See the method [llvm::LLVMBuilder::CreateFNeg]. *) -external build_fneg : llvalue -> string -> llbuilder -> llvalue - = "llvm_build_fneg" +val build_fneg : llvalue -> string -> llbuilder -> llvalue + (** [build_xor x name b] creates a [%name = xor %x, -1] instruction at the position specified by the instruction builder [b]. [-1] is the correct "all ones" value for the type of [x]. See the method [llvm::LLVMBuilder::CreateXor]. *) -external build_not : llvalue -> string -> llbuilder -> llvalue - = "llvm_build_not" +val build_not : llvalue -> string -> llbuilder -> llvalue + (** {7 Memory} *) @@ -1901,63 +1901,63 @@ external build_not : llvalue -> string -> llbuilder -> llvalue [%name = alloca %ty] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateAlloca]. *) -external build_alloca : lltype -> string -> llbuilder -> llvalue - = "llvm_build_alloca" +val build_alloca : lltype -> string -> llbuilder -> llvalue + (** [build_array_alloca ty n name b] creates a [%name = alloca %ty, %n] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateAlloca]. *) -external build_array_alloca : lltype -> llvalue -> string -> llbuilder -> - llvalue = "llvm_build_array_alloca" +val build_array_alloca : lltype -> llvalue -> string -> llbuilder -> + llvalue (** [build_load v name b] creates a [%name = load %v] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateLoad]. *) -external build_load : llvalue -> string -> llbuilder -> llvalue - = "llvm_build_load" +val build_load : llvalue -> string -> llbuilder -> llvalue + (** [build_store v p b] creates a [store %v, %p] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateStore]. *) -external build_store : llvalue -> llvalue -> llbuilder -> llvalue - = "llvm_build_store" +val build_store : llvalue -> llvalue -> llbuilder -> llvalue + (** [build_gep p indices name b] creates a [%name = getelementptr %p, indices...] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateGetElementPtr]. *) -external build_gep : llvalue -> llvalue array -> string -> llbuilder -> llvalue - = "llvm_build_gep" +val build_gep : llvalue -> llvalue array -> string -> llbuilder -> llvalue + (** [build_in_bounds_gep p indices name b] creates a [%name = gelementptr inbounds %p, indices...] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateInBoundsGetElementPtr]. *) -external build_in_bounds_gep : llvalue -> llvalue array -> string -> llbuilder -> - llvalue = "llvm_build_in_bounds_gep" +val build_in_bounds_gep : llvalue -> llvalue array -> string -> llbuilder -> + llvalue (** [build_struct_gep p idx name b] creates a [%name = getelementptr %p, 0, idx] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateStructGetElementPtr]. *) -external build_struct_gep : llvalue -> int -> string -> llbuilder -> - llvalue = "llvm_build_struct_gep" +val build_struct_gep : llvalue -> int -> string -> llbuilder -> + llvalue (** [build_global_string str name b] creates a series of instructions that adds a global string at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateGlobalString]. *) -external build_global_string : string -> string -> llbuilder -> llvalue - = "llvm_build_global_string" +val build_global_string : string -> string -> llbuilder -> llvalue + (** [build_global_stringptr str name b] creates a series of instructions that adds a global string pointer at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateGlobalStringPtr]. *) -external build_global_stringptr : string -> string -> llbuilder -> llvalue - = "llvm_build_global_stringptr" +val build_global_stringptr : string -> string -> llbuilder -> llvalue + (** {7 Casts} *) @@ -1966,121 +1966,121 @@ external build_global_stringptr : string -> string -> llbuilder -> llvalue [%name = trunc %p to %ty] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateTrunc]. *) -external build_trunc : llvalue -> lltype -> string -> llbuilder -> llvalue - = "llvm_build_trunc" +val build_trunc : llvalue -> lltype -> string -> llbuilder -> llvalue + (** [build_zext v ty name b] creates a [%name = zext %p to %ty] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateZExt]. *) -external build_zext : llvalue -> lltype -> string -> llbuilder -> llvalue - = "llvm_build_zext" +val build_zext : llvalue -> lltype -> string -> llbuilder -> llvalue + (** [build_sext v ty name b] creates a [%name = sext %p to %ty] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateSExt]. *) -external build_sext : llvalue -> lltype -> string -> llbuilder -> llvalue - = "llvm_build_sext" +val build_sext : llvalue -> lltype -> string -> llbuilder -> llvalue + (** [build_fptoui v ty name b] creates a [%name = fptoui %p to %ty] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateFPToUI]. *) -external build_fptoui : llvalue -> lltype -> string -> llbuilder -> llvalue - = "llvm_build_fptoui" +val build_fptoui : llvalue -> lltype -> string -> llbuilder -> llvalue + (** [build_fptosi v ty name b] creates a [%name = fptosi %p to %ty] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateFPToSI]. *) -external build_fptosi : llvalue -> lltype -> string -> llbuilder -> llvalue - = "llvm_build_fptosi" +val build_fptosi : llvalue -> lltype -> string -> llbuilder -> llvalue + (** [build_uitofp v ty name b] creates a [%name = uitofp %p to %ty] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateUIToFP]. *) -external build_uitofp : llvalue -> lltype -> string -> llbuilder -> llvalue - = "llvm_build_uitofp" +val build_uitofp : llvalue -> lltype -> string -> llbuilder -> llvalue + (** [build_sitofp v ty name b] creates a [%name = sitofp %p to %ty] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateSIToFP]. *) -external build_sitofp : llvalue -> lltype -> string -> llbuilder -> llvalue - = "llvm_build_sitofp" +val build_sitofp : llvalue -> lltype -> string -> llbuilder -> llvalue + (** [build_fptrunc v ty name b] creates a [%name = fptrunc %p to %ty] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateFPTrunc]. *) -external build_fptrunc : llvalue -> lltype -> string -> llbuilder -> llvalue - = "llvm_build_fptrunc" +val build_fptrunc : llvalue -> lltype -> string -> llbuilder -> llvalue + (** [build_fpext v ty name b] creates a [%name = fpext %p to %ty] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateFPExt]. *) -external build_fpext : llvalue -> lltype -> string -> llbuilder -> llvalue - = "llvm_build_fpext" +val build_fpext : llvalue -> lltype -> string -> llbuilder -> llvalue + (** [build_ptrtoint v ty name b] creates a [%name = prtotint %p to %ty] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreatePtrToInt]. *) -external build_ptrtoint : llvalue -> lltype -> string -> llbuilder -> llvalue - = "llvm_build_prttoint" +val build_ptrtoint : llvalue -> lltype -> string -> llbuilder -> llvalue + (** [build_inttoptr v ty name b] creates a [%name = inttoptr %p to %ty] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateIntToPtr]. *) -external build_inttoptr : llvalue -> lltype -> string -> llbuilder -> llvalue - = "llvm_build_inttoptr" +val build_inttoptr : llvalue -> lltype -> string -> llbuilder -> llvalue + (** [build_bitcast v ty name b] creates a [%name = bitcast %p to %ty] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateBitCast]. *) -external build_bitcast : llvalue -> lltype -> string -> llbuilder -> llvalue - = "llvm_build_bitcast" +val build_bitcast : llvalue -> lltype -> string -> llbuilder -> llvalue + (** [build_zext_or_bitcast v ty name b] creates a zext or bitcast instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateZExtOrBitCast]. *) -external build_zext_or_bitcast : llvalue -> lltype -> string -> llbuilder -> - llvalue = "llvm_build_zext_or_bitcast" +val build_zext_or_bitcast : llvalue -> lltype -> string -> llbuilder -> + llvalue (** [build_sext_or_bitcast v ty name b] creates a sext or bitcast instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateSExtOrBitCast]. *) -external build_sext_or_bitcast : llvalue -> lltype -> string -> llbuilder -> - llvalue = "llvm_build_sext_or_bitcast" +val build_sext_or_bitcast : llvalue -> lltype -> string -> llbuilder -> + llvalue (** [build_trunc_or_bitcast v ty name b] creates a trunc or bitcast instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateZExtOrBitCast]. *) -external build_trunc_or_bitcast : llvalue -> lltype -> string -> llbuilder -> - llvalue = "llvm_build_trunc_or_bitcast" +val build_trunc_or_bitcast : llvalue -> lltype -> string -> llbuilder -> + llvalue (** [build_pointercast v ty name b] creates a bitcast or pointer-to-int instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreatePointerCast]. *) -external build_pointercast : llvalue -> lltype -> string -> llbuilder -> llvalue - = "llvm_build_pointercast" +val build_pointercast : llvalue -> lltype -> string -> llbuilder -> llvalue + (** [build_intcast v ty name b] creates a zext, bitcast, or trunc instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateIntCast]. *) -external build_intcast : llvalue -> lltype -> string -> llbuilder -> llvalue - = "llvm_build_intcast" +val build_intcast : llvalue -> lltype -> string -> llbuilder -> llvalue + (** [build_fpcast v ty name b] creates a fpext, bitcast, or fptrunc instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateFPCast]. *) -external build_fpcast : llvalue -> lltype -> string -> llbuilder -> llvalue - = "llvm_build_fpcast" +val build_fpcast : llvalue -> lltype -> string -> llbuilder -> llvalue + (** {7 Comparisons} *) @@ -2089,15 +2089,15 @@ external build_fpcast : llvalue -> lltype -> string -> llbuilder -> llvalue [%name = icmp %pred %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateICmp]. *) -external build_icmp : Icmp.t -> llvalue -> llvalue -> string -> - llbuilder -> llvalue = "llvm_build_icmp" +val build_icmp : Icmp.t -> llvalue -> llvalue -> string -> + llbuilder -> llvalue (** [build_fcmp pred x y name b] creates a [%name = fcmp %pred %x, %y] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateFCmp]. *) -external build_fcmp : Fcmp.t -> llvalue -> llvalue -> string -> - llbuilder -> llvalue = "llvm_build_fcmp" +val build_fcmp : Fcmp.t -> llvalue -> llvalue -> string -> + llbuilder -> llvalue (** {7 Miscellaneous instructions} *) @@ -2107,85 +2107,85 @@ external build_fcmp : Fcmp.t -> llvalue -> llvalue -> string -> instruction at the position specified by the instruction builder [b]. [incoming] is a list of [(llvalue, llbasicblock)] tuples. See the method [llvm::LLVMBuilder::CreatePHI]. *) -external build_phi : (llvalue * llbasicblock) list -> string -> llbuilder -> - llvalue = "llvm_build_phi" +val build_phi : (llvalue * llbasicblock) list -> string -> llbuilder -> + llvalue (** [build_call fn args name b] creates a [%name = call %fn(args...)] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateCall]. *) -external build_call : llvalue -> llvalue array -> string -> llbuilder -> llvalue - = "llvm_build_call" +val build_call : llvalue -> llvalue array -> string -> llbuilder -> llvalue + (** [build_select cond thenv elsev name b] creates a [%name = select %cond, %thenv, %elsev] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateSelect]. *) -external build_select : llvalue -> llvalue -> llvalue -> string -> llbuilder -> - llvalue = "llvm_build_select" +val build_select : llvalue -> llvalue -> llvalue -> string -> llbuilder -> + llvalue (** [build_va_arg valist argty name b] creates a [%name = va_arg %valist, %argty] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateVAArg]. *) -external build_va_arg : llvalue -> lltype -> string -> llbuilder -> llvalue - = "llvm_build_va_arg" +val build_va_arg : llvalue -> lltype -> string -> llbuilder -> llvalue + (** [build_extractelement vec i name b] creates a [%name = extractelement %vec, %i] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateExtractElement]. *) -external build_extractelement : llvalue -> llvalue -> string -> llbuilder -> - llvalue = "llvm_build_extractelement" +val build_extractelement : llvalue -> llvalue -> string -> llbuilder -> + llvalue (** [build_insertelement vec elt i name b] creates a [%name = insertelement %vec, %elt, %i] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateInsertElement]. *) -external build_insertelement : llvalue -> llvalue -> llvalue -> string -> - llbuilder -> llvalue = "llvm_build_insertelement" +val build_insertelement : llvalue -> llvalue -> llvalue -> string -> + llbuilder -> llvalue (** [build_shufflevector veca vecb mask name b] creates a [%name = shufflevector %veca, %vecb, %mask] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateShuffleVector]. *) -external build_shufflevector : llvalue -> llvalue -> llvalue -> string -> - llbuilder -> llvalue = "llvm_build_shufflevector" +val build_shufflevector : llvalue -> llvalue -> llvalue -> string -> + llbuilder -> llvalue (** [build_insertvalue agg idx name b] creates a [%name = extractvalue %agg, %idx] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateExtractValue]. *) -external build_extractvalue : llvalue -> int -> string -> llbuilder -> llvalue - = "llvm_build_extractvalue" +val build_extractvalue : llvalue -> int -> string -> llbuilder -> llvalue + (** [build_insertvalue agg val idx name b] creates a [%name = insertvalue %agg, %val, %idx] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateInsertValue]. *) -external build_insertvalue : llvalue -> llvalue -> int -> string -> llbuilder -> - llvalue = "llvm_build_insertvalue" +val build_insertvalue : llvalue -> llvalue -> int -> string -> llbuilder -> + llvalue (** [build_is_null val name b] creates a [%name = icmp eq %val, null] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateIsNull]. *) -external build_is_null : llvalue -> string -> llbuilder -> llvalue - = "llvm_build_is_null" +val build_is_null : llvalue -> string -> llbuilder -> llvalue + (** [build_is_not_null val name b] creates a [%name = icmp ne %val, null] instruction at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreateIsNotNull]. *) -external build_is_not_null : llvalue -> string -> llbuilder -> llvalue - = "llvm_build_is_not_null" +val build_is_not_null : llvalue -> string -> llbuilder -> llvalue + (** [build_ptrdiff lhs rhs name b] creates a series of instructions that measure the difference between two pointer values at the position specified by the instruction builder [b]. See the method [llvm::LLVMBuilder::CreatePtrDiff]. *) -external build_ptrdiff : llvalue -> llvalue -> string -> llbuilder -> llvalue - = "llvm_build_ptrdiff" +val build_ptrdiff : llvalue -> llvalue -> string -> llbuilder -> llvalue + (** {6 Memory buffers} *) @@ -2194,14 +2194,14 @@ module MemoryBuffer : sig (** [of_file p] is the memory buffer containing the contents of the file at path [p]. If the file could not be read, then [IoError msg] is raised. *) - external of_file : string -> llmemorybuffer = "llvm_memorybuffer_of_file" + val of_file : string -> llmemorybuffer (** [stdin ()] is the memory buffer containing the contents of standard input. If standard input is empty, then [IoError msg] is raised. *) - external of_stdin : unit -> llmemorybuffer = "llvm_memorybuffer_of_stdin" + val of_stdin : unit -> llmemorybuffer (** Disposes of a memory buffer. *) - external dispose : llmemorybuffer -> unit = "llvm_memorybuffer_dispose" + val dispose : llmemorybuffer -> unit end @@ -2216,44 +2216,44 @@ module PassManager : sig type of pipeline is suitable for link-time optimization and whole-module transformations. See the constructor of [llvm::PassManager]. *) - external create : unit -> [ `Module ] t = "llvm_passmanager_create" + val create : unit -> [ `Module ] t (** [PassManager.create_function m] constructs a new function-by-function pass pipeline over the module [m]. It does not take ownership of [m]. This type of pipeline is suitable for code generation and JIT compilation tasks. See the constructor of [llvm::FunctionPassManager]. *) - external create_function : llmodule -> [ `Function ] t - = "LLVMCreateFunctionPassManager" + val create_function : llmodule -> [ `Function ] t + (** [run_module m pm] initializes, executes on the module [m], and finalizes all of the passes scheduled in the pass manager [pm]. Returns [true] if any of the passes modified the module, [false] otherwise. See the [llvm::PassManager::run] method. *) - external run_module : llmodule -> [ `Module ] t -> bool - = "llvm_passmanager_run_module" + val run_module : llmodule -> [ `Module ] t -> bool + (** [initialize fpm] initializes all of the function passes scheduled in the function pass manager [fpm]. Returns [true] if any of the passes modified the module, [false] otherwise. See the [llvm::FunctionPassManager::doInitialization] method. *) - external initialize : [ `Function ] t -> bool = "llvm_passmanager_initialize" + val initialize : [ `Function ] t -> bool (** [run_function f fpm] executes all of the function passes scheduled in the function pass manager [fpm] over the function [f]. Returns [true] if any of the passes modified [f], [false] otherwise. See the [llvm::FunctionPassManager::run] method. *) - external run_function : llvalue -> [ `Function ] t -> bool - = "llvm_passmanager_run_function" + val run_function : llvalue -> [ `Function ] t -> bool + (** [finalize fpm] finalizes all of the function passes scheduled in in the function pass manager [fpm]. Returns [true] if any of the passes modified the module, [false] otherwise. See the [llvm::FunctionPassManager::doFinalization] method. *) - external finalize : [ `Function ] t -> bool = "llvm_passmanager_finalize" + val finalize : [ `Function ] t -> bool (** Frees the memory of a pass pipeline. For function pipelines, does not free the module. See the destructor of [llvm::BasePassManager]. *) - external dispose : [< any ] t -> unit = "llvm_passmanager_dispose" + val dispose : [< any ] t -> unit end diff --git a/bindings/ocaml/llvm/llvm_ocaml.c b/bindings/ocaml/llvm/llvm_ocaml.c index ef2e3d66629c..ce6cf8ea79e9 100644 --- a/bindings/ocaml/llvm/llvm_ocaml.c +++ b/bindings/ocaml/llvm/llvm_ocaml.c @@ -264,6 +264,11 @@ CAMLprim LLVMTypeRef llvm_ppc_fp128_type(LLVMContextRef Context) { return LLVMPPCFP128TypeInContext(Context); } +/* llcontext -> lltype */ +CAMLprim LLVMTypeRef llvm_x86mmx_type(LLVMContextRef Context) { + return LLVMX86MMXTypeInContext(Context); +} + /*--... Operations on function types .......................................--*/ /* lltype -> lltype array -> lltype */ diff --git a/bindings/ocaml/transforms/scalar/llvm_scalar_opts.ml b/bindings/ocaml/transforms/scalar/llvm_scalar_opts.ml index 5699152b5a92..276e1182d054 100644 --- a/bindings/ocaml/transforms/scalar/llvm_scalar_opts.ml +++ b/bindings/ocaml/transforms/scalar/llvm_scalar_opts.ml @@ -39,9 +39,6 @@ external add_loop_unroll : [ unit = "llvm_add_loop_rotation" -external add_loop_index_split : [ unit - = "llvm_add_loop_index_split" external add_memory_to_register_promotion : [ unit diff --git a/bindings/ocaml/transforms/scalar/llvm_scalar_opts.mli b/bindings/ocaml/transforms/scalar/llvm_scalar_opts.mli index 9f95fbce9f89..d7162c769e43 100644 --- a/bindings/ocaml/transforms/scalar/llvm_scalar_opts.mli +++ b/bindings/ocaml/transforms/scalar/llvm_scalar_opts.mli @@ -66,11 +66,6 @@ external add_loop_rotation : [ unit = "llvm_add_loop_rotation" -(** See the [llvm::createLoopIndexSplitPass] function. *) -external add_loop_index_split : [ unit - = "llvm_add_loop_index_split" - (** See the [llvm::createPromoteMemoryToRegisterPass] function. *) external add_memory_to_register_promotion : [ unit */ -CAMLprim value llvm_add_loop_index_split(LLVMPassManagerRef PM) { - LLVMAddLoopIndexSplitPass(PM); - return Val_unit; -} - /* [ unit */ CAMLprim value llvm_add_memory_to_register_promotion(LLVMPassManagerRef PM) { LLVMAddPromoteMemoryToRegisterPass(PM); diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index f75e5dfb2656..c2fe4317b53a 100755 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -1,8 +1,14 @@ +if( WIN32 AND NOT CYGWIN ) + # We consider Cygwin as another Unix + set(PURE_WINDOWS 1) +endif() + include(CheckIncludeFile) include(CheckLibraryExists) include(CheckSymbolExists) include(CheckFunctionExists) include(CheckCXXSourceCompiles) +include(TestBigEndian) if( UNIX AND NOT BEOS ) # Used by check_symbol_exists: @@ -30,6 +36,7 @@ endfunction() # include checks check_include_file(argz.h HAVE_ARGZ_H) check_include_file(assert.h HAVE_ASSERT_H) +check_include_file(ctype.h HAVE_CTYPE_H) check_include_file(dirent.h HAVE_DIRENT_H) check_include_file(dl.h HAVE_DL_H) check_include_file(dld.h HAVE_DLD_H) @@ -44,7 +51,7 @@ check_include_file(malloc.h HAVE_MALLOC_H) check_include_file(malloc/malloc.h HAVE_MALLOC_MALLOC_H) check_include_file(memory.h HAVE_MEMORY_H) check_include_file(ndir.h HAVE_NDIR_H) -if( NOT LLVM_ON_WIN32 ) +if( NOT PURE_WINDOWS ) check_include_file(pthread.h HAVE_PTHREAD_H) endif() check_include_file(setjmp.h HAVE_SETJMP_H) @@ -53,6 +60,7 @@ check_include_file(stdint.h HAVE_STDINT_H) check_include_file(stdio.h HAVE_STDIO_H) check_include_file(stdlib.h HAVE_STDLIB_H) check_include_file(string.h HAVE_STRING_H) +check_include_file(strings.h HAVE_STRINGS_H) check_include_file(sys/dir.h HAVE_SYS_DIR_H) check_include_file(sys/dl.h HAVE_SYS_DL_H) check_include_file(sys/ioctl.h HAVE_SYS_IOCTL_H) @@ -63,15 +71,19 @@ check_include_file(sys/resource.h HAVE_SYS_RESOURCE_H) check_include_file(sys/stat.h HAVE_SYS_STAT_H) check_include_file(sys/time.h HAVE_SYS_TIME_H) check_include_file(sys/types.h HAVE_SYS_TYPES_H) +check_include_file(sys/uio.h HAVE_SYS_UIO_H) check_include_file(sys/wait.h HAVE_SYS_WAIT_H) check_include_file(termios.h HAVE_TERMIOS_H) check_include_file(unistd.h HAVE_UNISTD_H) check_include_file(utime.h HAVE_UTIME_H) check_include_file(valgrind/valgrind.h HAVE_VALGRIND_VALGRIND_H) check_include_file(windows.h HAVE_WINDOWS_H) +check_include_file(fenv.h HAVE_FENV_H) +check_include_file(mach/mach.h HAVE_MACH_MACH_H) +check_include_file(mach-o/dyld.h HAVE_MACH_O_DYLD_H) # library checks -if( NOT LLVM_ON_WIN32 ) +if( NOT PURE_WINDOWS ) check_library_exists(pthread pthread_create "" HAVE_LIBPTHREAD) check_library_exists(pthread pthread_getspecific "" HAVE_PTHREAD_GETSPECIFIC) check_library_exists(pthread pthread_rwlock_init "" HAVE_PTHREAD_RWLOCK_INIT) @@ -83,6 +95,7 @@ check_symbol_exists(getpagesize unistd.h HAVE_GETPAGESIZE) check_symbol_exists(getrusage sys/resource.h HAVE_GETRUSAGE) check_symbol_exists(setrlimit sys/resource.h HAVE_SETRLIMIT) check_function_exists(isatty HAVE_ISATTY) +check_symbol_exists(index strings.h HAVE_INDEX) check_symbol_exists(isinf cmath HAVE_ISINF_IN_CMATH) check_symbol_exists(isinf math.h HAVE_ISINF_IN_MATH_H) check_symbol_exists(finite ieeefp.h HAVE_FINITE_IN_IEEEFP_H) @@ -90,6 +103,16 @@ check_symbol_exists(isnan cmath HAVE_ISNAN_IN_CMATH) check_symbol_exists(isnan math.h HAVE_ISNAN_IN_MATH_H) check_symbol_exists(ceilf math.h HAVE_CEILF) check_symbol_exists(floorf math.h HAVE_FLOORF) +check_symbol_exists(fmodf math.h HAVE_FMODF) +if( HAVE_SETJMP_H ) + check_symbol_exists(longjmp setjmp.h HAVE_LONGJMP) + check_symbol_exists(setjmp setjmp.h HAVE_SETJMP) + check_symbol_exists(siglongjmp setjmp.h HAVE_SIGLONGJMP) + check_symbol_exists(sigsetjmp setjmp.h HAVE_SIGSETJMP) +endif() +if( HAVE_SYS_UIO_H ) + check_symbol_exists(writev sys/uio.h HAVE_WRITEV) +endif() check_symbol_exists(nearbyintf math.h HAVE_NEARBYINTF) check_symbol_exists(mallinfo malloc.h HAVE_MALLINFO) check_symbol_exists(malloc_zone_statistics malloc/malloc.h @@ -97,15 +120,78 @@ check_symbol_exists(malloc_zone_statistics malloc/malloc.h check_symbol_exists(mkdtemp "stdlib.h;unistd.h" HAVE_MKDTEMP) check_symbol_exists(mkstemp "stdlib.h;unistd.h" HAVE_MKSTEMP) check_symbol_exists(mktemp "stdlib.h;unistd.h" HAVE_MKTEMP) -if( NOT LLVM_ON_WIN32 ) +check_symbol_exists(closedir "sys/types.h;dirent.h" HAVE_CLOSEDIR) +check_symbol_exists(opendir "sys/types.h;dirent.h" HAVE_OPENDIR) +check_symbol_exists(readdir "sys/types.h;dirent.h" HAVE_READDIR) +check_symbol_exists(getcwd unistd.h HAVE_GETCWD) +check_symbol_exists(gettimeofday sys/time.h HAVE_GETTIMEOFDAY) +check_symbol_exists(getrlimit "sys/types.h;sys/time.h;sys/resource.h" HAVE_GETRLIMIT) +check_symbol_exists(rindex strings.h HAVE_RINDEX) +check_symbol_exists(strchr string.h HAVE_STRCHR) +check_symbol_exists(strcmp string.h HAVE_STRCMP) +check_symbol_exists(strdup string.h HAVE_STRDUP) +check_symbol_exists(strrchr string.h HAVE_STRRCHR) +if( NOT PURE_WINDOWS ) check_symbol_exists(pthread_mutex_lock pthread.h HAVE_PTHREAD_MUTEX_LOCK) endif() check_symbol_exists(sbrk unistd.h HAVE_SBRK) +check_symbol_exists(srand48 stdlib.h HAVE_RAND48_SRAND48) +if( HAVE_RAND48_SRAND48 ) + check_symbol_exists(lrand48 stdlib.h HAVE_RAND48_LRAND48) + if( HAVE_RAND48_LRAND48 ) + check_symbol_exists(drand48 stdlib.h HAVE_RAND48_DRAND48) + if( HAVE_RAND48_DRAND48 ) + set(HAVE_RAND48 1 CACHE INTERNAL "are srand48/lrand48/drand48 available?") + endif() + endif() +endif() check_symbol_exists(strtoll stdlib.h HAVE_STRTOLL) +check_symbol_exists(strtoq stdlib.h HAVE_STRTOQ) check_symbol_exists(strerror string.h HAVE_STRERROR) check_symbol_exists(strerror_r string.h HAVE_STRERROR_R) -check_symbol_exists(strerror_s string.h HAVE_STRERROR_S) +check_symbol_exists(strerror_s string.h HAVE_DECL_STRERROR_S) +check_symbol_exists(memcpy string.h HAVE_MEMCPY) +check_symbol_exists(memmove string.h HAVE_MEMMOVE) check_symbol_exists(setenv stdlib.h HAVE_SETENV) +if( PURE_WINDOWS ) + check_symbol_exists(_chsize_s io.h HAVE__CHSIZE_S) + + check_function_exists(_alloca HAVE__ALLOCA) + check_function_exists(__alloca HAVE___ALLOCA) + check_function_exists(__chkstk HAVE___CHKSTK) + check_function_exists(___chkstk HAVE____CHKSTK) + + check_function_exists(__ashldi3 HAVE___ASHLDI3) + check_function_exists(__ashrdi3 HAVE___ASHRDI3) + check_function_exists(__divdi3 HAVE___DIVDI3) + check_function_exists(__fixdfdi HAVE___FIXDFDI) + check_function_exists(__fixsfdi HAVE___FIXSFDI) + check_function_exists(__floatdidf HAVE___FLOATDIDF) + check_function_exists(__lshrdi3 HAVE___LSHRDI3) + check_function_exists(__moddi3 HAVE___MODDI3) + check_function_exists(__udivdi3 HAVE___UDIVDI3) + check_function_exists(__umoddi3 HAVE___UMODDI3) + + check_function_exists(__main HAVE___MAIN) + check_function_exists(__cmpdi2 HAVE___CMPDI2) +endif() +if( HAVE_ARGZ_H ) + check_symbol_exists(argz_append argz.h HAVE_ARGZ_APPEND) + check_symbol_exists(argz_create_sep argz.h HAVE_ARGZ_CREATE_SEP) + check_symbol_exists(argz_insert argz.h HAVE_ARGZ_INSERT) + check_symbol_exists(argz_next argz.h HAVE_ARGZ_NEXT) + check_symbol_exists(argz_stringify argz.h HAVE_ARGZ_STRINGIFY) +endif() +if( HAVE_DLFCN_H ) + if( HAVE_LIBDL ) + list(APPEND CMAKE_REQUIRED_LIBRARIES dl) + endif() + check_symbol_exists(dlerror dlfcn.h HAVE_DLERROR) + check_symbol_exists(dlopen dlfcn.h HAVE_DLOPEN) + if( HAVE_LIBDL ) + list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES dl) + endif() +endif() check_symbol_exists(__GLIBC__ stdio.h LLVM_USING_GLIBC) if( LLVM_USING_GLIBC ) @@ -130,8 +216,10 @@ if (HAVE_STDINT_H) set(headers ${headers} "stdint.h") endif() +check_type_exists(int64_t "${headers}" HAVE_INT64_T) check_type_exists(uint64_t "${headers}" HAVE_UINT64_T) check_type_exists(u_int64_t "${headers}" HAVE_U_INT64_T) +check_type_exists(error_t errno.h HAVE_ERROR_T) # available programs checks function(llvm_find_program name) @@ -154,16 +242,48 @@ llvm_find_program(fdp) llvm_find_program(dot) llvm_find_program(dotty) +if( LLVM_ENABLE_FFI ) + find_path(FFI_INCLUDE_PATH ffi.h PATHS ${FFI_INCLUDE_DIR}) + if( FFI_INCLUDE_PATH ) + set(FFI_HEADER ffi.h CACHE INTERNAL "") + set(HAVE_FFI_H 1 CACHE INTERNAL "") + else() + find_path(FFI_INCLUDE_PATH ffi/ffi.h PATHS ${FFI_INCLUDE_DIR}) + if( FFI_INCLUDE_PATH ) + set(FFI_HEADER ffi/ffi.h CACHE INTERNAL "") + set(HAVE_FFI_FFI_H 1 CACHE INTERNAL "") + endif() + endif() + + if( NOT FFI_HEADER ) + message(FATAL_ERROR "libffi includes are not found.") + endif() + + find_library(FFI_LIBRARY_PATH ffi PATHS ${FFI_LIBRARY_DIR}) + if( NOT FFI_LIBRARY_PATH ) + message(FATAL_ERROR "libffi is not found.") + endif() + + list(APPEND CMAKE_REQUIRED_LIBRARIES ${FFI_LIBRARY_PATH}) + list(APPEND CMAKE_REQUIRED_INCLUDES ${FFI_INCLUDE_PATH}) + check_symbol_exists(ffi_call ${FFI_HEADER} HAVE_FFI_CALL) + list(REMOVE_ITEM CMAKE_REQUIRED_INCLUDES ${FFI_INCLUDE_PATH}) + list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES ${FFI_LIBRARY_PATH}) +endif( LLVM_ENABLE_FFI ) + # Define LLVM_MULTITHREADED if gcc atomic builtins exists. include(CheckAtomic) -include(CheckCXXCompilerFlag) -# On windows all code is position-independent and mingw warns if -fPIC -# is in the command-line. -if( NOT WIN32 ) - check_cxx_compiler_flag("-fPIC" SUPPORTS_FPIC_FLAG) +if( LLVM_ENABLE_PIC ) + set(ENABLE_PIC 1) +else() + set(ENABLE_PIC 0) endif() +include(CheckCXXCompilerFlag) + +check_cxx_compiler_flag("-Wno-variadic-macros" SUPPORTS_NO_VARIADIC_MACROS_FLAG) + include(GetTargetTriple) get_target_triple(LLVM_HOSTTRIPLE) @@ -194,22 +314,20 @@ elseif (LLVM_NATIVE_ARCH MATCHES "arm") set(LLVM_NATIVE_ARCH ARM) elseif (LLVM_NATIVE_ARCH MATCHES "mips") set(LLVM_NATIVE_ARCH Mips) -elseif (LLVM_NATIVE_ARCH MATCHES "pic16") - set(LLVM_NATIVE_ARCH "PIC16") elseif (LLVM_NATIVE_ARCH MATCHES "xcore") set(LLVM_NATIVE_ARCH XCore) elseif (LLVM_NATIVE_ARCH MATCHES "msp430") set(LLVM_NATIVE_ARCH MSP430) else () - message(STATUS + message(STATUS "Unknown architecture ${LLVM_NATIVE_ARCH}; lli will not JIT code") set(LLVM_NATIVE_ARCH) endif () - + if (LLVM_NATIVE_ARCH) list(FIND LLVM_TARGETS_TO_BUILD ${LLVM_NATIVE_ARCH} NATIVE_ARCH_IDX) if (NATIVE_ARCH_IDX EQUAL -1) - message(STATUS + message(STATUS "Native target ${LLVM_NATIVE_ARCH} is not selected; lli will not JIT code") set(LLVM_NATIVE_ARCH) else () @@ -263,19 +381,3 @@ else( ENABLE_THREADS ) endif() set(LLVM_PREFIX ${CMAKE_INSTALL_PREFIX}) - -configure_file( - ${LLVM_MAIN_INCLUDE_DIR}/llvm/Config/config.h.cmake - ${LLVM_BINARY_DIR}/include/llvm/Config/config.h - ) - -configure_file( - ${LLVM_MAIN_INCLUDE_DIR}/llvm/Config/llvm-config.h.cmake - ${LLVM_BINARY_DIR}/include/llvm/Config/llvm-config.h - ) - -configure_file( - ${LLVM_MAIN_INCLUDE_DIR}/llvm/System/DataTypes.h.cmake - ${LLVM_BINARY_DIR}/include/llvm/System/DataTypes.h - ) - diff --git a/cmake/modules/AddLLVM.cmake b/cmake/modules/AddLLVM.cmake index 0ecd153c6be4..dfe67cded331 100755 --- a/cmake/modules/AddLLVM.cmake +++ b/cmake/modules/AddLLVM.cmake @@ -4,11 +4,17 @@ include(LLVMConfig) macro(add_llvm_library name) llvm_process_sources( ALL_FILES ${ARGN} ) add_library( ${name} ${ALL_FILES} ) - set( llvm_libs ${llvm_libs} ${name} PARENT_SCOPE) - set( llvm_lib_targets ${llvm_lib_targets} ${name} PARENT_SCOPE ) + set_property( GLOBAL APPEND PROPERTY LLVM_LIBS ${name} ) + set_property( GLOBAL APPEND PROPERTY LLVM_LIB_TARGETS ${name} ) if( LLVM_COMMON_DEPENDS ) add_dependencies( ${name} ${LLVM_COMMON_DEPENDS} ) endif( LLVM_COMMON_DEPENDS ) + + if( BUILD_SHARED_LIBS ) + get_system_libs(sl) + target_link_libraries( ${name} ${sl} ) + endif() + install(TARGETS ${name} LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX} ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}) @@ -23,12 +29,20 @@ endmacro(add_llvm_library name) macro(add_llvm_loadable_module name) - if( NOT LLVM_ON_UNIX ) + if( NOT LLVM_ON_UNIX OR CYGWIN ) message(STATUS "Loadable modules not supported on this platform. ${name} ignored.") + # Add empty "phony" target + add_custom_target(${name}) else() llvm_process_sources( ALL_FILES ${ARGN} ) - add_library( ${name} MODULE ${ALL_FILES} ) + if (MODULE) + set(libkind MODULE) + else() + set(libkind SHARED) + endif() + + add_library( ${name} ${libkind} ${ALL_FILES} ) set_target_properties( ${name} PROPERTIES PREFIX "" ) if (APPLE) @@ -60,13 +74,15 @@ macro(add_llvm_executable name) if( LLVM_LINK_COMPONENTS ) llvm_config(${name} ${LLVM_LINK_COMPONENTS}) endif( LLVM_LINK_COMPONENTS ) - get_system_libs(llvm_system_libs) - if( llvm_system_libs ) - target_link_libraries(${name} ${llvm_system_libs}) - endif() if( LLVM_COMMON_DEPENDS ) add_dependencies( ${name} ${LLVM_COMMON_DEPENDS} ) endif( LLVM_COMMON_DEPENDS ) + if( NOT MINGW ) + get_system_libs(llvm_system_libs) + if( llvm_system_libs ) + target_link_libraries(${name} ${llvm_system_libs}) + endif() + endif() endmacro(add_llvm_executable name) @@ -105,5 +121,5 @@ macro(add_llvm_target target_name) if ( TABLEGEN_OUTPUT ) add_dependencies(LLVM${target_name} ${target_name}Table_gen) endif (TABLEGEN_OUTPUT) - set(CURRENT_LLVM_TARGET LLVM${target_name} PARENT_SCOPE) + set( CURRENT_LLVM_TARGET LLVM${target_name} ) endmacro(add_llvm_target) diff --git a/cmake/modules/AddLLVMDefinitions.cmake b/cmake/modules/AddLLVMDefinitions.cmake index 0f6d81f736d5..33ac9731db5d 100644 --- a/cmake/modules/AddLLVMDefinitions.cmake +++ b/cmake/modules/AddLLVMDefinitions.cmake @@ -1,11 +1,13 @@ -# There is no clear way of keeping track of compiler command-line -# options chosen via `add_definitions', so we need our own method for -# using it on tools/llvm-config/CMakeLists.txt. - -# Beware that there is no implementation of remove_llvm_definitions. - -macro(add_llvm_definitions) - set(LLVM_DEFINITIONS "${LLVM_DEFINITIONS} ${ARGN}") - add_definitions( ${ARGN} ) -endmacro(add_llvm_definitions) - +# There is no clear way of keeping track of compiler command-line +# options chosen via `add_definitions', so we need our own method for +# using it on tools/llvm-config/CMakeLists.txt. + +# Beware that there is no implementation of remove_llvm_definitions. + +macro(add_llvm_definitions) + # We don't want no semicolons on LLVM_DEFINITIONS: + foreach(arg ${ARGN}) + set(LLVM_DEFINITIONS "${LLVM_DEFINITIONS} ${arg}") + endforeach(arg) + add_definitions( ${ARGN} ) +endmacro(add_llvm_definitions) diff --git a/cmake/modules/CMakeLists.txt b/cmake/modules/CMakeLists.txt index 416d7f478564..9a5566effb08 100644 --- a/cmake/modules/CMakeLists.txt +++ b/cmake/modules/CMakeLists.txt @@ -1,5 +1,8 @@ set(llvm_cmake_builddir "${LLVM_BINARY_DIR}/share/llvm/cmake") +get_property(llvm_libs GLOBAL PROPERTY LLVM_LIBS) +get_property(llvm_lib_targets GLOBAL PROPERTY LLVM_LIB_TARGETS) + configure_file( LLVM.cmake ${llvm_cmake_builddir}/LLVM.cmake @@ -10,3 +13,21 @@ install(FILES LLVMConfig.cmake LLVMLibDeps.cmake DESTINATION share/llvm/cmake) + +install(DIRECTORY . + DESTINATION share/llvm/cmake + FILES_MATCHING PATTERN *.cmake + PATTERN .svn EXCLUDE + PATTERN LLVM.cmake EXCLUDE + PATTERN LLVMConfig.cmake EXCLUDE + PATTERN LLVMLibDeps.cmake EXCLUDE + PATTERN FindBison.cmake EXCLUDE + PATTERN GetTargetTriple.cmake EXCLUDE + PATTERN VersionFromVCS.cmake EXCLUDE + PATTERN CheckAtomic.cmake EXCLUDE) + +install(FILES + ${llvm_cmake_builddir}/LLVM.cmake + LLVMConfig.cmake + LLVMLibDeps.cmake + DESTINATION share/llvm/cmake) diff --git a/cmake/modules/CrossCompileLLVM.cmake b/cmake/modules/CrossCompileLLVM.cmake index 138ff0e9fe65..98e60a54366f 100644 --- a/cmake/modules/CrossCompileLLVM.cmake +++ b/cmake/modules/CrossCompileLLVM.cmake @@ -1,26 +1,26 @@ - -if( ${LLVM_TABLEGEN} STREQUAL "tblgen" ) - set(CX_NATIVE_TG_DIR "${CMAKE_BINARY_DIR}/native") - set(LLVM_TABLEGEN_EXE "${CX_NATIVE_TG_DIR}/bin/tblgen") - - add_custom_command(OUTPUT ${CX_NATIVE_TG_DIR} - COMMAND ${CMAKE_COMMAND} -E make_directory ${CX_NATIVE_TG_DIR} - COMMENT "Creating ${CX_NATIVE_TG_DIR}...") - - add_custom_command(OUTPUT ${CX_NATIVE_TG_DIR}/CMakeCache.txt - COMMAND ${CMAKE_COMMAND} -UMAKE_TOOLCHAIN_FILE -DCMAKE_BUILD_TYPE=Release ${CMAKE_SOURCE_DIR} - WORKING_DIRECTORY ${CX_NATIVE_TG_DIR} - DEPENDS ${CX_NATIVE_TG_DIR} - COMMENT "Configuring native TableGen...") - - add_custom_command(OUTPUT ${LLVM_TABLEGEN_EXE} - COMMAND ${CMAKE_BUILD_TOOL} - DEPENDS ${CX_NATIVE_TG_DIR}/CMakeCache.txt - WORKING_DIRECTORY ${CX_NATIVE_TG_DIR}/utils/TableGen - COMMENT "Building native TableGen...") - add_custom_target(NativeTableGen DEPENDS ${LLVM_TABLEGEN_EXE}) - - add_dependencies(tblgen NativeTableGen) - - set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ${CX_NATIVE_TG_DIR}) -endif() + +if( ${LLVM_TABLEGEN} STREQUAL "tblgen" ) + set(CX_NATIVE_TG_DIR "${CMAKE_BINARY_DIR}/native") + set(LLVM_TABLEGEN_EXE "${CX_NATIVE_TG_DIR}/bin/tblgen") + + add_custom_command(OUTPUT ${CX_NATIVE_TG_DIR} + COMMAND ${CMAKE_COMMAND} -E make_directory ${CX_NATIVE_TG_DIR} + COMMENT "Creating ${CX_NATIVE_TG_DIR}...") + + add_custom_command(OUTPUT ${CX_NATIVE_TG_DIR}/CMakeCache.txt + COMMAND ${CMAKE_COMMAND} -UMAKE_TOOLCHAIN_FILE -DCMAKE_BUILD_TYPE=Release ${CMAKE_SOURCE_DIR} + WORKING_DIRECTORY ${CX_NATIVE_TG_DIR} + DEPENDS ${CX_NATIVE_TG_DIR} + COMMENT "Configuring native TableGen...") + + add_custom_command(OUTPUT ${LLVM_TABLEGEN_EXE} + COMMAND ${CMAKE_BUILD_TOOL} + DEPENDS ${CX_NATIVE_TG_DIR}/CMakeCache.txt + WORKING_DIRECTORY ${CX_NATIVE_TG_DIR}/utils/TableGen + COMMENT "Building native TableGen...") + add_custom_target(NativeTableGen DEPENDS ${LLVM_TABLEGEN_EXE}) + + add_dependencies(tblgen NativeTableGen) + + set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ${CX_NATIVE_TG_DIR}) +endif() diff --git a/cmake/modules/GetTargetTriple.cmake b/cmake/modules/GetTargetTriple.cmake index ac0c00924266..f4321c9b67ec 100644 --- a/cmake/modules/GetTargetTriple.cmake +++ b/cmake/modules/GetTargetTriple.cmake @@ -9,7 +9,11 @@ function( get_target_triple var ) set( value "i686-pc-win32" ) endif() elseif( MINGW AND NOT MSYS ) - set( value "i686-pc-mingw32" ) + if( CMAKE_SIZEOF_VOID_P EQUAL 8 ) + set( value "x86_64-w64-mingw32" ) + else() + set( value "i686-pc-mingw32" ) + endif() else( MSVC ) set(config_guess ${LLVM_MAIN_SRC_DIR}/autoconf/config.guess) execute_process(COMMAND sh ${config_guess} diff --git a/cmake/modules/HandleLLVMOptions.cmake b/cmake/modules/HandleLLVMOptions.cmake new file mode 100644 index 000000000000..7ca2bd07fd53 --- /dev/null +++ b/cmake/modules/HandleLLVMOptions.cmake @@ -0,0 +1,161 @@ +include(AddLLVMDefinitions) + +# Run-time build mode; It is used for unittests. +if(MSVC_IDE) + # Expect "$(Configuration)", "$(OutDir)", etc. + # It is expanded by msbuild or similar. + set(RUNTIME_BUILD_MODE "${CMAKE_CFG_INTDIR}") +elseif(NOT CMAKE_BUILD_TYPE STREQUAL "") + # Expect "Release" "Debug", etc. + # Or unittests could not run. + set(RUNTIME_BUILD_MODE ${CMAKE_BUILD_TYPE}) +else() + # It might be "." + set(RUNTIME_BUILD_MODE "${CMAKE_CFG_INTDIR}") +endif() + +set(LIT_ARGS_DEFAULT "-sv") +if (MSVC OR XCODE) + set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar") +endif() +set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" + CACHE STRING "Default options for lit") + +if( LLVM_ENABLE_ASSERTIONS ) + # MSVC doesn't like _DEBUG on release builds. See PR 4379. + if( NOT MSVC ) + add_definitions( -D_DEBUG ) + endif() + # On Release builds cmake automatically defines NDEBUG, so we + # explicitly undefine it: + if( uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE" ) + add_definitions( -UNDEBUG ) + endif() +else() + if( NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE" ) + if( NOT MSVC_IDE AND NOT XCODE ) + add_definitions( -DNDEBUG ) + endif() + endif() +endif() + +if(WIN32) + if(CYGWIN) + set(LLVM_ON_WIN32 0) + set(LLVM_ON_UNIX 1) + else(CYGWIN) + set(LLVM_ON_WIN32 1) + set(LLVM_ON_UNIX 0) + + # This is effective only on Win32 hosts to use gnuwin32 tools. + set(LLVM_LIT_TOOLS_DIR "" CACHE PATH "Path to GnuWin32 tools") + endif(CYGWIN) + set(LTDL_SHLIB_EXT ".dll") + set(EXEEXT ".exe") + # Maximum path length is 160 for non-unicode paths + set(MAXPATHLEN 160) +else(WIN32) + if(UNIX) + set(LLVM_ON_WIN32 0) + set(LLVM_ON_UNIX 1) + if(APPLE) + set(LTDL_SHLIB_EXT ".dylib") + else(APPLE) + set(LTDL_SHLIB_EXT ".so") + endif(APPLE) + set(EXEEXT "") + # FIXME: Maximum path length is currently set to 'safe' fixed value + set(MAXPATHLEN 2024) + else(UNIX) + MESSAGE(SEND_ERROR "Unable to determine platform") + endif(UNIX) +endif(WIN32) + +if( LLVM_ENABLE_PIC ) + if( XCODE ) + # Xcode has -mdynamic-no-pic on by default, which overrides -fPIC. I don't + # know how to disable this, so just force ENABLE_PIC off for now. + message(WARNING "-fPIC not supported with Xcode.") + elseif( WIN32 ) + # On Windows all code is PIC. MinGW warns if -fPIC is used. + else() + include(CheckCXXCompilerFlag) + check_cxx_compiler_flag("-fPIC" SUPPORTS_FPIC_FLAG) + if( SUPPORTS_FPIC_FLAG ) + message(STATUS "Building with -fPIC") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") + set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") + else( SUPPORTS_FPIC_FLAG ) + message(WARNING "-fPIC not supported.") + endif() + endif() +endif() + +if( CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT WIN32 ) + # TODO: support other platforms and toolchains. + option(LLVM_BUILD_32_BITS "Build 32 bits executables and libraries." OFF) + if( LLVM_BUILD_32_BITS ) + message(STATUS "Building 32 bits executables and libraries.") + add_llvm_definitions( -m32 ) + list(APPEND CMAKE_EXE_LINKER_FLAGS -m32) + list(APPEND CMAKE_SHARED_LINKER_FLAGS -m32) + endif( LLVM_BUILD_32_BITS ) +endif( CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT WIN32 ) + +if( MSVC ) + include(ChooseMSVCCRT) + + # Add definitions that make MSVC much less annoying. + add_llvm_definitions( + # For some reason MS wants to deprecate a bunch of standard functions... + -D_CRT_SECURE_NO_DEPRECATE + -D_CRT_SECURE_NO_WARNINGS + -D_CRT_NONSTDC_NO_DEPRECATE + -D_CRT_NONSTDC_NO_WARNINGS + -D_SCL_SECURE_NO_DEPRECATE + -D_SCL_SECURE_NO_WARNINGS + + -wd4146 # Suppress 'unary minus operator applied to unsigned type, result still unsigned' + -wd4180 # Suppress 'qualifier applied to function type has no meaning; ignored' + -wd4224 # Suppress 'nonstandard extension used : formal parameter 'identifier' was previously defined as a type' + -wd4244 # Suppress ''argument' : conversion from 'type1' to 'type2', possible loss of data' + -wd4267 # Suppress ''var' : conversion from 'size_t' to 'type', possible loss of data' + -wd4275 # Suppress 'An exported class was derived from a class that was not exported.' + -wd4291 # Suppress ''declaration' : no matching operator delete found; memory will not be freed if initialization throws an exception' + -wd4345 # Suppress 'behavior change: an object of POD type constructed with an initializer of the form () will be default-initialized' + -wd4351 # Suppress 'new behavior: elements of array 'array' will be default initialized' + -wd4355 # Suppress ''this' : used in base member initializer list' + -wd4503 # Suppress ''identifier' : decorated name length exceeded, name was truncated' + -wd4624 # Suppress ''derived class' : destructor could not be generated because a base class destructor is inaccessible' + -wd4715 # Suppress ''function' : not all control paths return a value' + -wd4800 # Suppress ''type' : forcing value to bool 'true' or 'false' (performance warning)' + -wd4065 # Suppress 'switch statement contains 'default' but no 'case' labels' + + -w14062 # Promote "enumerator in switch of enum is not handled" to level 1 warning. + ) + + # Enable warnings + if (LLVM_ENABLE_WARNINGS) + add_llvm_definitions( /W4 /Wall ) + if (LLVM_ENABLE_PEDANTIC) + # No MSVC equivalent available + endif (LLVM_ENABLE_PEDANTIC) + endif (LLVM_ENABLE_WARNINGS) + if (LLVM_ENABLE_WERROR) + add_llvm_definitions( /WX ) + endif (LLVM_ENABLE_WERROR) +elseif( CMAKE_COMPILER_IS_GNUCXX ) + if (LLVM_ENABLE_WARNINGS) + add_llvm_definitions( -Wall -W -Wno-unused-parameter -Wwrite-strings ) + if (LLVM_ENABLE_PEDANTIC) + add_llvm_definitions( -pedantic -Wno-long-long ) + endif (LLVM_ENABLE_PEDANTIC) + endif (LLVM_ENABLE_WARNINGS) + if (LLVM_ENABLE_WERROR) + add_llvm_definitions( -Werror ) + endif (LLVM_ENABLE_WERROR) +endif( MSVC ) + +add_llvm_definitions( -D__STDC_LIMIT_MACROS ) +add_llvm_definitions( -D__STDC_CONSTANT_MACROS ) + diff --git a/cmake/modules/LLVM.cmake b/cmake/modules/LLVM.cmake index 9621454f4119..d610f3e76516 100644 --- a/cmake/modules/LLVM.cmake +++ b/cmake/modules/LLVM.cmake @@ -1,11 +1,15 @@ # This file provides information and services to the final user. +set(LLVM_PACKAGE_VERSION @PACKAGE_VERSION@) + set(LLVM_COMMON_DEPENDS @LLVM_COMMON_DEPENDS@) set(llvm_libs @llvm_libs@) set(llvm_lib_targets @llvm_lib_targets@) +set(LLVM_ALL_TARGETS @LLVM_ALL_TARGETS@) + set(LLVM_TARGETS_TO_BUILD @LLVM_TARGETS_TO_BUILD@) set(LLVM_TOOLS_BINARY_DIR @LLVM_TOOLS_BINARY_DIR@) @@ -14,6 +18,13 @@ set(LLVM_ENABLE_THREADS @LLVM_ENABLE_THREADS@) set(LLVM_NATIVE_ARCH @LLVM_NATIVE_ARCH@) +set(LLVM_ENABLE_PIC @LLVM_ENABLE_PIC@) + +set(LLVM_ENABLE_THREADS @LLVM_ENABLE_THREADS) + +set(HAVE_LIBDL @HAVE_LIBDL@) +set(HAVE_LIBPTHREAD @HAVE_LIBPTHREAD) + # We try to include using the current setting of CMAKE_MODULE_PATH, # which suppossedly was filled by the user with the directory where # this file was installed: diff --git a/cmake/modules/LLVMConfig.cmake b/cmake/modules/LLVMConfig.cmake index e5497084be84..349544edc335 100755 --- a/cmake/modules/LLVMConfig.cmake +++ b/cmake/modules/LLVMConfig.cmake @@ -59,6 +59,9 @@ endfunction(llvm_map_components_to_libraries) function(explicit_map_components_to_libraries out_libs) set( link_components ${ARGN} ) + get_property(llvm_libs GLOBAL PROPERTY LLVM_LIBS) + string(TOUPPER "${llvm_libs}" capitalized_libs) + # Translate symbolic component names to real libraries: foreach(c ${link_components}) # add codegen, asmprinter, asmparser, disassembler list(FIND LLVM_TARGETS_TO_BUILD ${c} idx) @@ -102,39 +105,48 @@ function(explicit_map_components_to_libraries out_libs) elseif( c STREQUAL "all" ) list(APPEND expanded_components ${llvm_libs}) else( NOT idx LESS 0 ) - list(APPEND expanded_components LLVM${c}) + # Canonize the component name: + string(TOUPPER "${c}" capitalized) + list(FIND capitalized_libs LLVM${capitalized} lib_idx) + if( lib_idx LESS 0 ) + # The component is unkown. Maybe is an ommitted target? + is_llvm_target_library(${c} iltl_result) + if( NOT iltl_result ) + message(FATAL_ERROR "Library `${c}' not found in list of llvm libraries.") + endif() + else( lib_idx LESS 0 ) + list(GET llvm_libs ${lib_idx} canonical_lib) + list(APPEND expanded_components ${canonical_lib}) + endif( lib_idx LESS 0 ) endif( NOT idx LESS 0 ) endforeach(c) - # We must match capitalization. - string(TOUPPER "${llvm_libs}" capitalized_libs) - list(REMOVE_DUPLICATES expanded_components) + # Expand dependencies while topologically sorting the list of libraries: list(LENGTH expanded_components lst_size) - set(result "") - while( 0 LESS ${lst_size} ) - list(GET expanded_components 0 c) - string(TOUPPER "${c}" capitalized) - list(FIND capitalized_libs ${capitalized} idx) - set(add_it ON) - if( idx LESS 0 ) - # The library is unkown. Maybe is an ommitted target? - is_llvm_target_library(${c} iltl_result) - if( NOT iltl_result ) - message(FATAL_ERROR "Library ${c} not found in list of llvm libraries.") - endif() - set(add_it OFF) - endif( idx LESS 0 ) - list(GET llvm_libs ${idx} canonical_lib) - list(REMOVE_ITEM result ${canonical_lib}) - foreach(c ${MSVC_LIB_DEPS_${canonical_lib}}) - list(REMOVE_ITEM expanded_components ${c}) - endforeach() - if( add_it ) - list(APPEND result ${canonical_lib}) - list(APPEND expanded_components ${MSVC_LIB_DEPS_${canonical_lib}}) - endif() - list(REMOVE_AT expanded_components 0) + set(cursor 0) + set(processed) + while( cursor LESS lst_size ) + list(GET expanded_components ${cursor} lib) + list(APPEND expanded_components ${MSVC_LIB_DEPS_${lib}}) + # Remove duplicates at the front: + list(REVERSE expanded_components) + list(REMOVE_DUPLICATES expanded_components) + list(REVERSE expanded_components) + list(APPEND processed ${lib}) + # Find the maximum index that doesn't have to be re-processed: + while(NOT "${expanded_components}" MATCHES "^${processed}.*" ) + list(REMOVE_AT processed -1) + endwhile() + list(LENGTH processed cursor) list(LENGTH expanded_components lst_size) - endwhile( 0 LESS ${lst_size} ) + endwhile( cursor LESS lst_size ) + # Return just the libraries included in this build: + set(result) + foreach(c ${expanded_components}) + list(FIND llvm_libs ${c} lib_idx) + if( NOT lib_idx LESS 0 ) + set(result ${result} ${c}) + endif() + endforeach(c) set(${out_libs} ${result} PARENT_SCOPE) endfunction(explicit_map_components_to_libraries) @@ -151,13 +163,13 @@ endfunction(explicit_map_components_to_libraries) # The format generated by GenLibDeps.pl -# libLLVMARMAsmPrinter.a: libLLVMMC.a libLLVMSupport.a +# LLVMARMAsmPrinter.o: LLVMARMCodeGen.o libLLVMAsmPrinter.a libLLVMCodeGen.a libLLVMCore.a libLLVMSupport.a libLLVMTarget.a # is translated to: -# set(MSVC_LIB_DEPS_LLVMARMAsmPrinter LLVMMC LLVMSupport) +# set(MSVC_LIB_DEPS_LLVMARMAsmPrinter LLVMARMCodeGen LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMSupport LLVMTarget) -# It is necessary to remove the `lib' prefix and the `.a' suffix. +# It is necessary to remove the `lib' prefix and the `.a'. # This 'sed' script should do the trick: # sed -e s'#\.a##g' -e 's#libLLVM#LLVM#g' -e 's#: # #' -e 's#\(.*\)#set(MSVC_LIB_DEPS_\1)#' ~/llvm/tools/llvm-config/LibDeps.txt diff --git a/cmake/modules/LLVMLibDeps.cmake b/cmake/modules/LLVMLibDeps.cmake index e639b04e9800..afba85e45aa3 100644 --- a/cmake/modules/LLVMLibDeps.cmake +++ b/cmake/modules/LLVMLibDeps.cmake @@ -1,71 +1,68 @@ -set(MSVC_LIB_DEPS_LLVMARMAsmParser LLVMARMInfo LLVMMC LLVMMCParser LLVMSupport LLVMTarget) +set(MSVC_LIB_DEPS_LLVMARMAsmParser LLVMARMCodeGen LLVMARMInfo LLVMMC LLVMMCParser LLVMSupport LLVMTarget) set(MSVC_LIB_DEPS_LLVMARMAsmPrinter LLVMMC LLVMSupport) -set(MSVC_LIB_DEPS_LLVMARMCodeGen LLVMARMInfo LLVMAnalysis LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSupport LLVMSystem LLVMTarget) -set(MSVC_LIB_DEPS_LLVMARMInfo LLVMSupport) -set(MSVC_LIB_DEPS_LLVMAlphaAsmPrinter LLVMAlphaInfo LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMTarget) -set(MSVC_LIB_DEPS_LLVMAlphaCodeGen LLVMAlphaInfo LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSupport LLVMSystem LLVMTarget) -set(MSVC_LIB_DEPS_LLVMAlphaInfo LLVMSupport) -set(MSVC_LIB_DEPS_LLVMAnalysis LLVMCore LLVMSupport LLVMSystem LLVMTarget) -set(MSVC_LIB_DEPS_LLVMArchive LLVMBitReader LLVMCore LLVMSupport LLVMSystem) +set(MSVC_LIB_DEPS_LLVMARMCodeGen LLVMARMAsmPrinter LLVMARMInfo LLVMAnalysis LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSupport LLVMTarget) +set(MSVC_LIB_DEPS_LLVMARMDisassembler LLVMARMCodeGen LLVMARMInfo LLVMMC LLVMSupport) +set(MSVC_LIB_DEPS_LLVMARMInfo LLVMMC LLVMSupport) +set(MSVC_LIB_DEPS_LLVMAlphaCodeGen LLVMAlphaInfo LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSupport LLVMTarget) +set(MSVC_LIB_DEPS_LLVMAlphaInfo LLVMMC LLVMSupport) +set(MSVC_LIB_DEPS_LLVMAnalysis LLVMCore LLVMSupport LLVMTarget) +set(MSVC_LIB_DEPS_LLVMArchive LLVMBitReader LLVMCore LLVMSupport) set(MSVC_LIB_DEPS_LLVMAsmParser LLVMCore LLVMSupport) -set(MSVC_LIB_DEPS_LLVMAsmPrinter LLVMAnalysis LLVMCodeGen LLVMCore LLVMMC LLVMMCParser LLVMSupport LLVMSystem LLVMTarget) +set(MSVC_LIB_DEPS_LLVMAsmPrinter LLVMAnalysis LLVMCodeGen LLVMCore LLVMMC LLVMMCParser LLVMSupport LLVMTarget) set(MSVC_LIB_DEPS_LLVMBitReader LLVMCore LLVMSupport) set(MSVC_LIB_DEPS_LLVMBitWriter LLVMCore LLVMSupport) -set(MSVC_LIB_DEPS_LLVMBlackfinAsmPrinter LLVMAsmPrinter LLVMBlackfinInfo LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMTarget) -set(MSVC_LIB_DEPS_LLVMBlackfinCodeGen LLVMBlackfinInfo LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSupport LLVMTarget) -set(MSVC_LIB_DEPS_LLVMBlackfinInfo LLVMSupport) -set(MSVC_LIB_DEPS_LLVMCBackend LLVMAnalysis LLVMCBackendInfo LLVMCodeGen LLVMCore LLVMMC LLVMScalarOpts LLVMSupport LLVMSystem LLVMTarget LLVMTransformUtils LLVMipa) -set(MSVC_LIB_DEPS_LLVMCBackendInfo LLVMSupport) -set(MSVC_LIB_DEPS_LLVMCellSPUAsmPrinter LLVMAsmPrinter LLVMCellSPUInfo LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMTarget) -set(MSVC_LIB_DEPS_LLVMCellSPUCodeGen LLVMCellSPUInfo LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSupport LLVMTarget) -set(MSVC_LIB_DEPS_LLVMCellSPUInfo LLVMSupport) -set(MSVC_LIB_DEPS_LLVMCodeGen LLVMAnalysis LLVMCore LLVMMC LLVMScalarOpts LLVMSupport LLVMSystem LLVMTarget LLVMTransformUtils) -set(MSVC_LIB_DEPS_LLVMCore LLVMSupport LLVMSystem) +set(MSVC_LIB_DEPS_LLVMBlackfinCodeGen LLVMAsmPrinter LLVMBlackfinInfo LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSupport LLVMTarget) +set(MSVC_LIB_DEPS_LLVMBlackfinInfo LLVMMC LLVMSupport) +set(MSVC_LIB_DEPS_LLVMCBackend LLVMAnalysis LLVMCBackendInfo LLVMCodeGen LLVMCore LLVMMC LLVMScalarOpts LLVMSupport LLVMTarget LLVMTransformUtils LLVMipa) +set(MSVC_LIB_DEPS_LLVMCBackendInfo LLVMMC LLVMSupport) +set(MSVC_LIB_DEPS_LLVMCellSPUCodeGen LLVMAsmPrinter LLVMCellSPUInfo LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSupport LLVMTarget) +set(MSVC_LIB_DEPS_LLVMCellSPUInfo LLVMMC LLVMSupport) +set(MSVC_LIB_DEPS_LLVMCodeGen LLVMAnalysis LLVMCore LLVMMC LLVMScalarOpts LLVMSupport LLVMTarget LLVMTransformUtils) +set(MSVC_LIB_DEPS_LLVMCore LLVMSupport) set(MSVC_LIB_DEPS_LLVMCppBackend LLVMCore LLVMCppBackendInfo LLVMSupport LLVMTarget) -set(MSVC_LIB_DEPS_LLVMCppBackendInfo LLVMSupport) -set(MSVC_LIB_DEPS_LLVMExecutionEngine LLVMCore LLVMSupport LLVMSystem LLVMTarget) -set(MSVC_LIB_DEPS_LLVMInstCombine LLVMAnalysis LLVMCore LLVMSupport LLVMSystem LLVMTarget LLVMTransformUtils) -set(MSVC_LIB_DEPS_LLVMInstrumentation LLVMAnalysis LLVMCore LLVMSupport LLVMSystem LLVMTransformUtils) -set(MSVC_LIB_DEPS_LLVMInterpreter LLVMCodeGen LLVMCore LLVMExecutionEngine LLVMSupport LLVMSystem LLVMTarget) -set(MSVC_LIB_DEPS_LLVMJIT LLVMCodeGen LLVMCore LLVMExecutionEngine LLVMMC LLVMSupport LLVMSystem LLVMTarget) -set(MSVC_LIB_DEPS_LLVMLinker LLVMArchive LLVMBitReader LLVMCore LLVMSupport LLVMSystem LLVMTransformUtils) -set(MSVC_LIB_DEPS_LLVMMBlazeAsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMBlazeCodeGen LLVMMBlazeInfo LLVMMC LLVMSupport LLVMTarget) -set(MSVC_LIB_DEPS_LLVMMBlazeCodeGen LLVMCodeGen LLVMCore LLVMMBlazeInfo LLVMMC LLVMSelectionDAG LLVMSupport LLVMSystem LLVMTarget) -set(MSVC_LIB_DEPS_LLVMMBlazeInfo LLVMSupport) -set(MSVC_LIB_DEPS_LLVMMC LLVMSupport LLVMSystem) -set(MSVC_LIB_DEPS_LLVMMCDisassembler LLVMARMAsmParser LLVMARMCodeGen LLVMARMInfo LLVMAlphaAsmPrinter LLVMAlphaCodeGen LLVMAlphaInfo LLVMBlackfinAsmPrinter LLVMBlackfinCodeGen LLVMBlackfinInfo LLVMCBackend LLVMCBackendInfo LLVMCellSPUAsmPrinter LLVMCellSPUCodeGen LLVMCellSPUInfo LLVMCppBackend LLVMCppBackendInfo LLVMMBlazeAsmPrinter LLVMMBlazeCodeGen LLVMMBlazeInfo LLVMMC LLVMMCParser LLVMMSP430AsmPrinter LLVMMSP430CodeGen LLVMMSP430Info LLVMMipsAsmPrinter LLVMMipsCodeGen LLVMMipsInfo LLVMPIC16AsmPrinter LLVMPIC16CodeGen LLVMPIC16Info LLVMPowerPCAsmPrinter LLVMPowerPCCodeGen LLVMPowerPCInfo LLVMSparcAsmPrinter LLVMSparcCodeGen LLVMSparcInfo LLVMSupport LLVMSystem LLVMSystemZAsmPrinter LLVMSystemZCodeGen LLVMSystemZInfo LLVMX86AsmParser LLVMX86CodeGen LLVMX86Disassembler LLVMX86Info LLVMXCoreAsmPrinter LLVMXCoreCodeGen LLVMXCoreInfo) +set(MSVC_LIB_DEPS_LLVMCppBackendInfo LLVMMC LLVMSupport) +set(MSVC_LIB_DEPS_LLVMExecutionEngine LLVMCore LLVMSupport LLVMTarget) +set(MSVC_LIB_DEPS_LLVMInstCombine LLVMAnalysis LLVMCore LLVMSupport LLVMTarget LLVMTransformUtils) +set(MSVC_LIB_DEPS_LLVMInstrumentation LLVMAnalysis LLVMCore LLVMSupport LLVMTransformUtils) +set(MSVC_LIB_DEPS_LLVMInterpreter LLVMCodeGen LLVMCore LLVMExecutionEngine LLVMSupport LLVMTarget) +set(MSVC_LIB_DEPS_LLVMJIT LLVMCodeGen LLVMCore LLVMExecutionEngine LLVMMC LLVMSupport LLVMTarget) +set(MSVC_LIB_DEPS_LLVMLinker LLVMArchive LLVMBitReader LLVMCore LLVMSupport LLVMTransformUtils) +set(MSVC_LIB_DEPS_LLVMMBlazeAsmParser LLVMMBlazeCodeGen LLVMMBlazeInfo LLVMMC LLVMMCParser LLVMSupport LLVMTarget) +set(MSVC_LIB_DEPS_LLVMMBlazeAsmPrinter LLVMMC LLVMSupport) +set(MSVC_LIB_DEPS_LLVMMBlazeCodeGen LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMBlazeAsmPrinter LLVMMBlazeInfo LLVMMC LLVMSelectionDAG LLVMSupport LLVMTarget) +set(MSVC_LIB_DEPS_LLVMMBlazeDisassembler LLVMMBlazeCodeGen LLVMMBlazeInfo LLVMMC LLVMSupport) +set(MSVC_LIB_DEPS_LLVMMBlazeInfo LLVMMC LLVMSupport) +set(MSVC_LIB_DEPS_LLVMMC LLVMSupport) +set(MSVC_LIB_DEPS_LLVMMCDisassembler LLVMARMAsmParser LLVMARMCodeGen LLVMARMDisassembler LLVMARMInfo LLVMAlphaCodeGen LLVMAlphaInfo LLVMBlackfinCodeGen LLVMBlackfinInfo LLVMCBackend LLVMCBackendInfo LLVMCellSPUCodeGen LLVMCellSPUInfo LLVMCppBackend LLVMCppBackendInfo LLVMMBlazeAsmParser LLVMMBlazeCodeGen LLVMMBlazeDisassembler LLVMMBlazeInfo LLVMMC LLVMMCParser LLVMMSP430CodeGen LLVMMSP430Info LLVMMipsCodeGen LLVMMipsInfo LLVMPTXCodeGen LLVMPTXInfo LLVMPowerPCCodeGen LLVMPowerPCInfo LLVMSparcCodeGen LLVMSparcInfo LLVMSupport LLVMSystemZCodeGen LLVMSystemZInfo LLVMX86AsmParser LLVMX86CodeGen LLVMX86Disassembler LLVMX86Info LLVMXCoreCodeGen LLVMXCoreInfo) +set(MSVC_LIB_DEPS_LLVMMCJIT LLVMExecutionEngine LLVMSupport LLVMTarget) set(MSVC_LIB_DEPS_LLVMMCParser LLVMMC LLVMSupport) -set(MSVC_LIB_DEPS_LLVMMSP430AsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMMSP430Info LLVMSupport LLVMTarget) -set(MSVC_LIB_DEPS_LLVMMSP430CodeGen LLVMCodeGen LLVMCore LLVMMC LLVMMSP430Info LLVMSelectionDAG LLVMSupport LLVMSystem LLVMTarget) -set(MSVC_LIB_DEPS_LLVMMSP430Info LLVMSupport) -set(MSVC_LIB_DEPS_LLVMMipsAsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMMipsCodeGen LLVMMipsInfo LLVMSupport LLVMTarget) -set(MSVC_LIB_DEPS_LLVMMipsCodeGen LLVMCodeGen LLVMCore LLVMMC LLVMMipsInfo LLVMSelectionDAG LLVMSupport LLVMSystem LLVMTarget) -set(MSVC_LIB_DEPS_LLVMMipsInfo LLVMSupport) -set(MSVC_LIB_DEPS_LLVMPIC16AsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMPIC16CodeGen LLVMPIC16Info LLVMSupport LLVMTarget) -set(MSVC_LIB_DEPS_LLVMPIC16CodeGen LLVMAnalysis LLVMCodeGen LLVMCore LLVMMC LLVMPIC16Info LLVMSelectionDAG LLVMSupport LLVMTarget) -set(MSVC_LIB_DEPS_LLVMPIC16Info LLVMSupport) -set(MSVC_LIB_DEPS_LLVMPowerPCAsmPrinter LLVMAnalysis LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMPowerPCInfo LLVMSupport LLVMTarget) -set(MSVC_LIB_DEPS_LLVMPowerPCCodeGen LLVMCodeGen LLVMCore LLVMMC LLVMPowerPCInfo LLVMSelectionDAG LLVMSupport LLVMSystem LLVMTarget) -set(MSVC_LIB_DEPS_LLVMPowerPCInfo LLVMSupport) -set(MSVC_LIB_DEPS_LLVMScalarOpts LLVMAnalysis LLVMCore LLVMInstCombine LLVMSupport LLVMSystem LLVMTarget LLVMTransformUtils) -set(MSVC_LIB_DEPS_LLVMSelectionDAG LLVMAnalysis LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMSystem LLVMTarget) -set(MSVC_LIB_DEPS_LLVMSparcAsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSparcInfo LLVMSupport LLVMTarget) -set(MSVC_LIB_DEPS_LLVMSparcCodeGen LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSparcInfo LLVMSupport LLVMSystem LLVMTarget) -set(MSVC_LIB_DEPS_LLVMSparcInfo LLVMSupport) -set(MSVC_LIB_DEPS_LLVMSupport LLVMSystem) -set(MSVC_LIB_DEPS_LLVMSystem ) -set(MSVC_LIB_DEPS_LLVMSystemZAsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMSystemZInfo LLVMTarget) -set(MSVC_LIB_DEPS_LLVMSystemZCodeGen LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSupport LLVMSystemZInfo LLVMTarget) -set(MSVC_LIB_DEPS_LLVMSystemZInfo LLVMSupport) +set(MSVC_LIB_DEPS_LLVMMSP430AsmPrinter LLVMMC LLVMSupport) +set(MSVC_LIB_DEPS_LLVMMSP430CodeGen LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMMSP430AsmPrinter LLVMMSP430Info LLVMSelectionDAG LLVMSupport LLVMTarget) +set(MSVC_LIB_DEPS_LLVMMSP430Info LLVMMC LLVMSupport) +set(MSVC_LIB_DEPS_LLVMMipsCodeGen LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMMipsInfo LLVMSelectionDAG LLVMSupport LLVMTarget) +set(MSVC_LIB_DEPS_LLVMMipsInfo LLVMMC LLVMSupport) +set(MSVC_LIB_DEPS_LLVMObject LLVMSupport) +set(MSVC_LIB_DEPS_LLVMPTXCodeGen LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMPTXInfo LLVMSelectionDAG LLVMSupport LLVMTarget) +set(MSVC_LIB_DEPS_LLVMPTXInfo LLVMMC LLVMSupport) +set(MSVC_LIB_DEPS_LLVMPowerPCAsmPrinter LLVMMC LLVMSupport) +set(MSVC_LIB_DEPS_LLVMPowerPCCodeGen LLVMAnalysis LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMPowerPCAsmPrinter LLVMPowerPCInfo LLVMSelectionDAG LLVMSupport LLVMTarget) +set(MSVC_LIB_DEPS_LLVMPowerPCInfo LLVMMC LLVMSupport) +set(MSVC_LIB_DEPS_LLVMScalarOpts LLVMAnalysis LLVMCore LLVMInstCombine LLVMSupport LLVMTarget LLVMTransformUtils) +set(MSVC_LIB_DEPS_LLVMSelectionDAG LLVMAnalysis LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMTarget LLVMTransformUtils) +set(MSVC_LIB_DEPS_LLVMSparcCodeGen LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSparcInfo LLVMSupport LLVMTarget) +set(MSVC_LIB_DEPS_LLVMSparcInfo LLVMMC LLVMSupport) +set(MSVC_LIB_DEPS_LLVMSupport ) +set(MSVC_LIB_DEPS_LLVMSystemZCodeGen LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSupport LLVMSystemZInfo LLVMTarget) +set(MSVC_LIB_DEPS_LLVMSystemZInfo LLVMMC LLVMSupport) set(MSVC_LIB_DEPS_LLVMTarget LLVMCore LLVMMC LLVMSupport) -set(MSVC_LIB_DEPS_LLVMTransformUtils LLVMAnalysis LLVMCore LLVMSupport LLVMSystem LLVMTarget LLVMipa) +set(MSVC_LIB_DEPS_LLVMTransformUtils LLVMAnalysis LLVMCore LLVMSupport LLVMTarget LLVMipa) set(MSVC_LIB_DEPS_LLVMX86AsmParser LLVMMC LLVMMCParser LLVMSupport LLVMTarget LLVMX86Info) -set(MSVC_LIB_DEPS_LLVMX86AsmPrinter LLVMMC LLVMSupport) -set(MSVC_LIB_DEPS_LLVMX86CodeGen LLVMAnalysis LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSupport LLVMSystem LLVMTarget LLVMX86AsmPrinter LLVMX86Info) +set(MSVC_LIB_DEPS_LLVMX86AsmPrinter LLVMMC LLVMSupport LLVMX86Utils) +set(MSVC_LIB_DEPS_LLVMX86CodeGen LLVMAnalysis LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSupport LLVMTarget LLVMX86AsmPrinter LLVMX86Info LLVMX86Utils) set(MSVC_LIB_DEPS_LLVMX86Disassembler LLVMMC LLVMSupport LLVMX86Info) -set(MSVC_LIB_DEPS_LLVMX86Info LLVMSupport) -set(MSVC_LIB_DEPS_LLVMXCoreAsmPrinter LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSupport LLVMTarget LLVMXCoreInfo) -set(MSVC_LIB_DEPS_LLVMXCoreCodeGen LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSupport LLVMTarget LLVMXCoreInfo) -set(MSVC_LIB_DEPS_LLVMXCoreInfo LLVMSupport) -set(MSVC_LIB_DEPS_LLVMipa LLVMAnalysis LLVMCore LLVMSupport LLVMSystem) -set(MSVC_LIB_DEPS_LLVMipo LLVMAnalysis LLVMCore LLVMScalarOpts LLVMSupport LLVMSystem LLVMTarget LLVMTransformUtils LLVMipa) +set(MSVC_LIB_DEPS_LLVMX86Info LLVMMC LLVMSupport) +set(MSVC_LIB_DEPS_LLVMX86Utils LLVMSupport) +set(MSVC_LIB_DEPS_LLVMXCoreCodeGen LLVMAsmPrinter LLVMCodeGen LLVMCore LLVMMC LLVMSelectionDAG LLVMSupport LLVMTarget LLVMXCoreInfo) +set(MSVC_LIB_DEPS_LLVMXCoreInfo LLVMMC LLVMSupport) +set(MSVC_LIB_DEPS_LLVMipa LLVMAnalysis LLVMCore LLVMSupport) +set(MSVC_LIB_DEPS_LLVMipo LLVMAnalysis LLVMCore LLVMScalarOpts LLVMSupport LLVMTarget LLVMTransformUtils LLVMipa) diff --git a/cmake/modules/LLVMParseArguments.cmake b/cmake/modules/LLVMParseArguments.cmake new file mode 100644 index 000000000000..ce19be114b31 --- /dev/null +++ b/cmake/modules/LLVMParseArguments.cmake @@ -0,0 +1,80 @@ +# Copied from http://www.itk.org/Wiki/CMakeMacroParseArguments under +# http://creativecommons.org/licenses/by/2.5/. +# +# The PARSE_ARGUMENTS macro will take the arguments of another macro and define +# several variables. The first argument to PARSE_ARGUMENTS is a prefix to put on +# all variables it creates. The second argument is a list of names, and the +# third argument is a list of options. Both of these lists should be quoted. The +# rest of PARSE_ARGUMENTS are arguments from another macro to be parsed. +# +# PARSE_ARGUMENTS(prefix arg_names options arg1 arg2...) +# +# For each item in options, PARSE_ARGUMENTS will create a variable with that +# name, prefixed with prefix_. So, for example, if prefix is MY_MACRO and +# options is OPTION1;OPTION2, then PARSE_ARGUMENTS will create the variables +# MY_MACRO_OPTION1 and MY_MACRO_OPTION2. These variables will be set to true if +# the option exists in the command line or false otherwise. +# +#For each item in arg_names, PARSE_ARGUMENTS will create a variable with that +#name, prefixed with prefix_. Each variable will be filled with the arguments +#that occur after the given arg_name is encountered up to the next arg_name or +#the end of the arguments. All options are removed from these +#lists. PARSE_ARGUMENTS also creates a prefix_DEFAULT_ARGS variable containing +#the list of all arguments up to the first arg_name encountered. +# +#Here is a simple, albeit impractical, example of using PARSE_ARGUMENTS that +#demonstrates its behavior. +# +# SET(arguments +# hello OPTION3 world +# LIST3 foo bar +# OPTION2 +# LIST1 fuz baz +# ) +# +# PARSE_ARGUMENTS(ARG "LIST1;LIST2;LIST3" "OPTION1;OPTION2;OPTION3" ${arguments}) +# +# PARSE_ARGUMENTS creates 7 variables and sets them as follows: +# ARG_DEFAULT_ARGS: hello;world +# ARG_LIST1: fuz;baz +# ARG_LIST2: +# ARG_LIST3: foo;bar +# ARG_OPTION1: FALSE +# ARG_OPTION2: TRUE +# ARG_OPTION3: TRUE +# +# If you don't have any options, use an empty string in its place. +# PARSE_ARGUMENTS(ARG "LIST1;LIST2;LIST3" "" ${arguments}) +# Likewise if you have no lists. +# PARSE_ARGUMENTS(ARG "" "OPTION1;OPTION2;OPTION3" ${arguments}) + +MACRO(PARSE_ARGUMENTS prefix arg_names option_names) + SET(DEFAULT_ARGS) + FOREACH(arg_name ${arg_names}) + SET(${prefix}_${arg_name}) + ENDFOREACH(arg_name) + FOREACH(option ${option_names}) + SET(${prefix}_${option} FALSE) + ENDFOREACH(option) + + SET(current_arg_name DEFAULT_ARGS) + SET(current_arg_list) + FOREACH(arg ${ARGN}) + SET(larg_names ${arg_names}) + LIST(FIND larg_names "${arg}" is_arg_name) + IF (is_arg_name GREATER -1) + SET(${prefix}_${current_arg_name} ${current_arg_list}) + SET(current_arg_name ${arg}) + SET(current_arg_list) + ELSE (is_arg_name GREATER -1) + SET(loption_names ${option_names}) + LIST(FIND loption_names "${arg}" is_option) + IF (is_option GREATER -1) + SET(${prefix}_${arg} TRUE) + ELSE (is_option GREATER -1) + SET(current_arg_list ${current_arg_list} ${arg}) + ENDIF (is_option GREATER -1) + ENDIF (is_arg_name GREATER -1) + ENDFOREACH(arg) + SET(${prefix}_${current_arg_name} ${current_arg_list}) +ENDMACRO(PARSE_ARGUMENTS) diff --git a/cmake/modules/LLVMProcessSources.cmake b/cmake/modules/LLVMProcessSources.cmake index b753735cd55e..270292ad3b86 100644 --- a/cmake/modules/LLVMProcessSources.cmake +++ b/cmake/modules/LLVMProcessSources.cmake @@ -1,5 +1,22 @@ include(AddFileDependencies) +function(llvm_replace_compiler_option var old new) + # Replaces a compiler option or switch `old' in `var' by `new'. + # If `old' is not in `var', appends `new' to `var'. + # Example: llvm_replace_compiler_option(CMAKE_CXX_FLAGS_RELEASE "-O3" "-O2") + # If the option already is on the variable, don't add it: + if( "${${var}}" MATCHES "(^| )${new}($| )" ) + set(n "") + else() + set(n "${new}") + endif() + if( "${${var}}" MATCHES "(^| )${old}($| )" ) + string( REGEX REPLACE "(^| )${old}($| )" " ${n} " ${var} "${${var}}" ) + else() + set( ${var} "${${var}} ${n}" ) + endif() + set( ${var} "${${var}}" PARENT_SCOPE ) +endfunction(llvm_replace_compiler_option) macro(add_td_sources srcs) file(GLOB tds *.td) @@ -12,7 +29,7 @@ endmacro(add_td_sources) macro(add_header_files srcs) - file(GLOB hds *.h) + file(GLOB hds *.h *.def) if( hds ) set_source_files_properties(${hds} PROPERTIES HEADER_FILE_ONLY ON) list(APPEND ${srcs} ${hds}) @@ -36,6 +53,25 @@ function(llvm_process_sources OUT_VAR) add_td_sources(sources) add_header_files(sources) endif() + + # Set common compiler options: + if( NOT LLVM_REQUIRES_EH ) + if( CMAKE_COMPILER_IS_GNUCXX ) + add_definitions( -fno-exceptions ) + elseif( MSVC ) + llvm_replace_compiler_option(CMAKE_CXX_FLAGS "/EHsc" "/EHs-c-") + add_definitions( /D_HAS_EXCEPTIONS=0 ) + endif() + endif() + if( NOT LLVM_REQUIRES_RTTI ) + if( CMAKE_COMPILER_IS_GNUCXX ) + llvm_replace_compiler_option(CMAKE_CXX_FLAGS "-frtti" "-fno-rtti") + elseif( MSVC ) + llvm_replace_compiler_option(CMAKE_CXX_FLAGS "/GR" "/GR-") + endif() + endif() + + set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" PARENT_SCOPE ) set( ${OUT_VAR} ${sources} PARENT_SCOPE ) endfunction(llvm_process_sources) diff --git a/cmake/modules/TableGen.cmake b/cmake/modules/TableGen.cmake index cf7cd1f62e52..9d67137bb42a 100644 --- a/cmake/modules/TableGen.cmake +++ b/cmake/modules/TableGen.cmake @@ -12,14 +12,34 @@ macro(tablegen ofn) set(LLVM_TARGET_DEFINITIONS_ABSOLUTE ${CMAKE_CURRENT_SOURCE_DIR}/${LLVM_TARGET_DEFINITIONS}) endif() - add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${ofn} + add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${ofn}.tmp + # Generate tablegen output in a temporary file. COMMAND ${LLVM_TABLEGEN_EXE} ${ARGN} -I ${CMAKE_CURRENT_SOURCE_DIR} -I ${LLVM_MAIN_SRC_DIR}/lib/Target -I ${LLVM_MAIN_INCLUDE_DIR} ${LLVM_TARGET_DEFINITIONS_ABSOLUTE} - -o ${CMAKE_CURRENT_BINARY_DIR}/${ofn} - DEPENDS tblgen ${local_tds} ${global_tds} + -o ${CMAKE_CURRENT_BINARY_DIR}/${ofn}.tmp + # The file in LLVM_TARGET_DEFINITIONS may be not in the current + # directory and local_tds may not contain it, so we must + # explicitly list it here: + DEPENDS ${LLVM_TABLEGEN_EXE} ${local_tds} ${global_tds} + ${LLVM_TARGET_DEFINITIONS_ABSOLUTE} COMMENT "Building ${ofn}..." ) + add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${ofn} + # Only update the real output file if there are any differences. + # This prevents recompilation of all the files depending on it if there + # aren't any. + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${CMAKE_CURRENT_BINARY_DIR}/${ofn}.tmp + ${CMAKE_CURRENT_BINARY_DIR}/${ofn} + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${ofn}.tmp + COMMENT "" + ) + + # `make clean' must remove all those generated files: + set_property(DIRECTORY APPEND + PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${ofn}.tmp ${ofn}) + set(TABLEGEN_OUTPUT ${TABLEGEN_OUTPUT} ${CMAKE_CURRENT_BINARY_DIR}/${ofn}) set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/${ofn} PROPERTIES GENERATED 1) diff --git a/cmake/modules/VersionFromVCS.cmake b/cmake/modules/VersionFromVCS.cmake index 1016df22590d..81739be927a4 100644 --- a/cmake/modules/VersionFromVCS.cmake +++ b/cmake/modules/VersionFromVCS.cmake @@ -4,13 +4,16 @@ function(add_version_info_from_vcs VERS) set(result ${${VERS}}) - if( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.svn ) + if( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.svn" ) set(result "${result}svn") - find_package(Subversion) + # FindSubversion does not work with symlinks. See PR 8437 + if( NOT IS_SYMLINK "${CMAKE_CURRENT_SOURCE_DIR}" ) + find_package(Subversion) + endif() if( Subversion_FOUND ) subversion_wc_info( ${CMAKE_CURRENT_SOURCE_DIR} Project ) if( Project_WC_REVISION ) - set(result "${result}-r${Project_WC_REVISION}") + set(result "${result}-r${Project_WC_REVISION}") endif() endif() elseif( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git ) @@ -19,13 +22,23 @@ function(add_version_info_from_vcs VERS) find_program(git_executable NAMES git git.exe git.cmd) if( git_executable ) execute_process(COMMAND ${git_executable} show-ref HEAD - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - TIMEOUT 5 - RESULT_VARIABLE git_result - OUTPUT_VARIABLE git_output) + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + TIMEOUT 5 + RESULT_VARIABLE git_result + OUTPUT_VARIABLE git_output) if( git_result EQUAL 0 ) - string(SUBSTRING ${git_output} 0 7 git_ref_id) - set(result "${result}-${git_ref_id}") + string(SUBSTRING ${git_output} 0 7 git_ref_id) + set(result "${result}-${git_ref_id}") + else() + execute_process(COMMAND ${git_executable} svn log --limit=1 --oneline + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + TIMEOUT 5 + RESULT_VARIABLE git_result + OUTPUT_VARIABLE git_output) + if( git_result EQUAL 0 ) + string(REGEX MATCH r[0-9]+ git_svn_rev ${git_output}) + set(result "${result}-svn-${git_svn_rev}") + endif() endif() endif() endif() diff --git a/configure b/configure index 776de364bb20..959822fa0e15 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.60 for llvm 2.8. +# Generated by GNU Autoconf 2.60 for llvm 2.9svn. # # Report bugs to . # @@ -561,8 +561,8 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='llvm' PACKAGE_TARNAME='-llvm-' -PACKAGE_VERSION='2.8' -PACKAGE_STRING='llvm 2.8' +PACKAGE_VERSION='2.9svn' +PACKAGE_STRING='llvm 2.9svn' PACKAGE_BUGREPORT='llvmbugs@cs.uiuc.edu' ac_unique_file="lib/VMCore/Module.cpp" @@ -641,6 +641,8 @@ host_alias target_alias LLVM_COPYRIGHT subdirs +ENABLE_POLLY +LLVM_HAS_POLLY build build_cpu build_vendor @@ -686,10 +688,13 @@ DEBUG_RUNTIME DEBUG_SYMBOLS JIT TARGET_HAS_JIT +ENABLE_DOCS ENABLE_DOXYGEN ENABLE_THREADS +ENABLE_PTHREADS ENABLE_PIC ENABLE_SHARED +ENABLE_EMBED_STDCXX ENABLE_TIMESTAMPS TARGETS_TO_BUILD LLVM_ENUM_TARGETS @@ -729,6 +734,7 @@ TWOPI CIRCO GV DOTTY +XDOT_PY PERL HAVE_PERL INSTALL_PROGRAM @@ -738,7 +744,7 @@ BZIP2 CAT DOXYGEN GROFF -GZIP +GZIPBIN POD2HTML POD2MAN PDFROFF @@ -768,10 +774,13 @@ USE_OPROFILE HAVE_PTHREAD HUGE_VAL_SANITY MMAP_FILE +LLVMCC_EMITIR_FLAG LLVMCC1 LLVMCC1PLUS LLVMGCCDIR LLVMGCC_LANGS +LLVMGCC_DRAGONEGG +LLVMCC_DISABLEOPT_FLAGS SHLIBEXT SHLIBPATH_VAR LLVM_PREFIX @@ -816,7 +825,8 @@ projects/llvm-reopt projects/llvm-java projects/llvm-tv projects/safecode -projects/llvm-kernel' +projects/llvm-kernel +tools/polly' # Initialize some variables set by options. ac_init_help= @@ -1318,7 +1328,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures llvm 2.8 to adapt to many kinds of systems. +\`configure' configures llvm 2.9svn to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1384,17 +1394,18 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of llvm 2.8:";; + short | recursive ) echo "Configuration of llvm 2.9svn:";; esac cat <<\_ACEOF Optional Features: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-polly Use polly if available (default is YES) --enable-optimized Compile with optimizations enabled (default is NO) --enable-profiling Compile with profiling enabled (default is NO) --enable-assertions Compile with assertion checks enabled (default is - NO) + YES) --enable-expensive-checks Compile with expensive debug checks enabled (default is NO) @@ -1403,19 +1414,23 @@ Optional Features: --enable-debug-symbols Build compiler with debug symbols (default is NO if optimization is on and YES if it's off) --enable-jit Enable Just In Time Compiling (default is YES) + --enable-docs Build documents (default is YES) --enable-doxygen Build doxygen documentation (default is NO) --enable-threads Use threads if available (default is YES) + --enable-pthreads Use pthreads if available (default is YES) --enable-pic Build LLVM with Position Independent Code (default is YES) --enable-shared Build a shared library and link tools against it (default is NO) + --enable-embed-stdcxx Build a shared library with embedded libstdc++ for + Win32 DLL (default is YES) --enable-timestamps Enable embedding timestamp information in build (default is YES) --enable-targets Build specific host targets: all or target1,target2,... Valid targets are: host, x86, x86_64, sparc, powerpc, alpha, arm, mips, spu, - pic16, xcore, msp430, systemz, blackfin, cbe, and - cpp (default=all) + xcore, msp430, systemz, blackfin, ptx, cbe, and cpp + (default=all) --enable-cbe-printf-a Enable C Backend output with hex floating point via %a (default is YES) --enable-bindings Build specific language bindings: @@ -1441,6 +1456,9 @@ Optional Packages: --with-extra-options Specify additional options to compile LLVM with --with-ocaml-libdir Specify install location for ocaml bindings (default is stdlib) + --with-clang-resource-dir + Relative directory from the Clang binary for + resource files --with-c-include-dirs Colon separated list of directories clang will search for headers --with-cxx-include-root Directory with the libstdc++ headers. @@ -1533,7 +1551,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -llvm configure 2.8 +llvm configure 2.9svn generated by GNU Autoconf 2.60 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, @@ -1549,7 +1567,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by llvm $as_me 2.8, which was +It was created by llvm $as_me 2.9svn, which was generated by GNU Autoconf 2.60. Invocation command line was $ $0 $@ @@ -2011,6 +2029,33 @@ echo "$as_me: WARNING: Unknown project (${i}) won't be configured automatically" fi done +# Check whether --enable-polly was given. +if test "${enable_polly+set}" = set; then + enableval=$enable_polly; +else + enableval=default +fi + +case "$enableval" in + yes) ENABLE_POLLY=1 + ;; + no) ENABLE_POLLY=0 + ;; + default) ENABLE_POLLY=1 + ;; + *) { { echo "$as_me:$LINENO: error: Invalid setting for --enable-polly. Use \"yes\" or \"no\"" >&5 +echo "$as_me: error: Invalid setting for --enable-polly. Use \"yes\" or \"no\"" >&2;} + { (exit 1); exit 1; }; } ;; +esac + + +if (test -d ${srcdir}/tools/polly) && (test $ENABLE_POLLY -eq 1) ; then + LLVM_HAS_POLLY=1 + + subdirs="$subdirs tools/polly" + +fi + # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || @@ -2355,12 +2400,12 @@ else alpha*-*) llvm_cv_target_arch="Alpha" ;; arm*-*) llvm_cv_target_arch="ARM" ;; mips-*) llvm_cv_target_arch="Mips" ;; - pic16-*) llvm_cv_target_arch="PIC16" ;; xcore-*) llvm_cv_target_arch="XCore" ;; msp430-*) llvm_cv_target_arch="MSP430" ;; s390x-*) llvm_cv_target_arch="SystemZ" ;; bfin-*) llvm_cv_target_arch="Blackfin" ;; mblaze-*) llvm_cv_target_arch="MBlaze" ;; + ptx-*) llvm_cv_target_arch="PTX" ;; *) llvm_cv_target_arch="Unknown" ;; esac fi @@ -4699,7 +4744,7 @@ fi if test "${enable_optimized+set}" = set; then enableval=$enable_optimized; else - enableval="yes" + enableval=$optimize fi if test ${enableval} = "no" ; then @@ -4729,7 +4774,7 @@ fi if test "${enable_assertions+set}" = set; then enableval=$enable_assertions; else - enableval="no" + enableval="yes" fi if test ${enableval} = "yes" ; then @@ -4810,13 +4855,11 @@ else ;; x86_64) TARGET_HAS_JIT=1 ;; - Alpha) TARGET_HAS_JIT=1 + Alpha) TARGET_HAS_JIT=0 ;; ARM) TARGET_HAS_JIT=1 ;; Mips) TARGET_HAS_JIT=0 - ;; - PIC16) TARGET_HAS_JIT=0 ;; XCore) TARGET_HAS_JIT=0 ;; @@ -4827,12 +4870,33 @@ else Blackfin) TARGET_HAS_JIT=0 ;; MBlaze) TARGET_HAS_JIT=0 + ;; + PTX) TARGET_HAS_JIT=0 ;; *) TARGET_HAS_JIT=0 ;; esac fi +# Check whether --enable-docs was given. +if test "${enable_docs+set}" = set; then + enableval=$enable_docs; +else + enableval=default +fi + +case "$enableval" in + yes) ENABLE_DOCS=1 + ;; + no) ENABLE_DOCS=0 + ;; + default) ENABLE_DOCS=1 + ;; + *) { { echo "$as_me:$LINENO: error: Invalid setting for --enable-docs. Use \"yes\" or \"no\"" >&5 +echo "$as_me: error: Invalid setting for --enable-docs. Use \"yes\" or \"no\"" >&2;} + { (exit 1); exit 1; }; } ;; +esac + # Check whether --enable-doxygen was given. if test "${enable_doxygen+set}" = set; then enableval=$enable_doxygen; @@ -4876,6 +4940,25 @@ cat >>confdefs.h <<_ACEOF _ACEOF +# Check whether --enable-pthreads was given. +if test "${enable_pthreads+set}" = set; then + enableval=$enable_pthreads; +else + enableval=default +fi + +case "$enableval" in + yes) ENABLE_PTHREADS=1 + ;; + no) ENABLE_PTHREADS=0 + ;; + default) ENABLE_PTHREADS=1 + ;; + *) { { echo "$as_me:$LINENO: error: Invalid setting for --enable-pthreads. Use \"yes\" or \"no\"" >&5 +echo "$as_me: error: Invalid setting for --enable-pthreads. Use \"yes\" or \"no\"" >&2;} + { (exit 1); exit 1; }; } ;; +esac + # Check whether --enable-pic was given. if test "${enable_pic+set}" = set; then enableval=$enable_pic; @@ -4919,6 +5002,25 @@ echo "$as_me: error: Invalid setting for --enable-shared. Use \"yes\" or \"no\"" { (exit 1); exit 1; }; } ;; esac +# Check whether --enable-embed-stdcxx was given. +if test "${enable_embed_stdcxx+set}" = set; then + enableval=$enable_embed_stdcxx; +else + enableval=default +fi + +case "$enableval" in + yes) ENABLE_EMBED_STDCXX=1 + ;; + no) ENABLE_EMBED_STDCXX=0 + ;; + default) ENABLE_EMBED_STDCXX=1 + ;; + *) { { echo "$as_me:$LINENO: error: Invalid setting for --enable-embed-stdcxx. Use \"yes\" or \"no\"" >&5 +echo "$as_me: error: Invalid setting for --enable-embed-stdcxx. Use \"yes\" or \"no\"" >&2;} + { (exit 1); exit 1; }; } ;; +esac + # Check whether --enable-timestamps was given. if test "${enable_timestamps+set}" = set; then enableval=$enable_timestamps; @@ -4955,7 +5057,7 @@ if test "$enableval" = host-only ; then enableval=host fi case "$enableval" in - all) TARGETS_TO_BUILD="X86 Sparc PowerPC Alpha ARM Mips CellSPU PIC16 XCore MSP430 SystemZ Blackfin CBackend CppBackend MBlaze" ;; + all) TARGETS_TO_BUILD="X86 Sparc PowerPC Alpha ARM Mips CellSPU XCore MSP430 SystemZ Blackfin CBackend CppBackend MBlaze PTX" ;; *)for a_target in `echo $enableval|sed -e 's/,/ /g' ` ; do case "$a_target" in x86) TARGETS_TO_BUILD="X86 $TARGETS_TO_BUILD" ;; @@ -4966,7 +5068,6 @@ case "$enableval" in arm) TARGETS_TO_BUILD="ARM $TARGETS_TO_BUILD" ;; mips) TARGETS_TO_BUILD="Mips $TARGETS_TO_BUILD" ;; spu) TARGETS_TO_BUILD="CellSPU $TARGETS_TO_BUILD" ;; - pic16) TARGETS_TO_BUILD="PIC16 $TARGETS_TO_BUILD" ;; xcore) TARGETS_TO_BUILD="XCore $TARGETS_TO_BUILD" ;; msp430) TARGETS_TO_BUILD="MSP430 $TARGETS_TO_BUILD" ;; systemz) TARGETS_TO_BUILD="SystemZ $TARGETS_TO_BUILD" ;; @@ -4974,6 +5075,7 @@ case "$enableval" in cbe) TARGETS_TO_BUILD="CBackend $TARGETS_TO_BUILD" ;; cpp) TARGETS_TO_BUILD="CppBackend $TARGETS_TO_BUILD" ;; mblaze) TARGETS_TO_BUILD="MBlaze $TARGETS_TO_BUILD" ;; + ptx) TARGETS_TO_BUILD="PTX $TARGETS_TO_BUILD" ;; host) case "$llvm_cv_target_arch" in x86) TARGETS_TO_BUILD="X86 $TARGETS_TO_BUILD" ;; x86_64) TARGETS_TO_BUILD="X86 $TARGETS_TO_BUILD" ;; @@ -4984,11 +5086,11 @@ case "$enableval" in Mips) TARGETS_TO_BUILD="Mips $TARGETS_TO_BUILD" ;; MBlaze) TARGETS_TO_BUILD="MBlaze $TARGETS_TO_BUILD" ;; CellSPU|SPU) TARGETS_TO_BUILD="CellSPU $TARGETS_TO_BUILD" ;; - PIC16) TARGETS_TO_BUILD="PIC16 $TARGETS_TO_BUILD" ;; XCore) TARGETS_TO_BUILD="XCore $TARGETS_TO_BUILD" ;; MSP430) TARGETS_TO_BUILD="MSP430 $TARGETS_TO_BUILD" ;; s390x) TARGETS_TO_BUILD="SystemZ $TARGETS_TO_BUILD" ;; Blackfin) TARGETS_TO_BUILD="Blackfin $TARGETS_TO_BUILD" ;; + PTX) TARGETS_TO_BUILD="PTX $TARGETS_TO_BUILD" ;; *) { { echo "$as_me:$LINENO: error: Can not set target to build" >&5 echo "$as_me: error: Can not set target to build" >&2;} { (exit 1); exit 1; }; } ;; @@ -5041,7 +5143,7 @@ LLVM_ENUM_ASM_PARSERS="" LLVM_ENUM_DISASSEMBLERS="" for target_to_build in $TARGETS_TO_BUILD; do LLVM_ENUM_TARGETS="LLVM_TARGET($target_to_build) $LLVM_ENUM_TARGETS" - if test -f ${srcdir}/lib/Target/${target_to_build}/AsmPrinter/Makefile ; then + if test -f ${srcdir}/lib/Target/${target_to_build}/*AsmPrinter.cpp ; then LLVM_ENUM_ASM_PRINTERS="LLVM_ASM_PRINTER($target_to_build) $LLVM_ENUM_ASM_PRINTERS"; fi if test -f ${srcdir}/lib/Target/${target_to_build}/AsmParser/Makefile ; then @@ -5274,6 +5376,20 @@ echo "$as_me: error: Invalid path for --with-ocaml-libdir. Provide full path" >& esac +# Check whether --with-clang-resource-dir was given. +if test "${with_clang_resource_dir+set}" = set; then + withval=$with_clang_resource_dir; +else + withval="" +fi + + +cat >>confdefs.h <<_ACEOF +#define CLANG_RESOURCE_DIR "$withval" +_ACEOF + + + # Check whether --with-c-include-dirs was given. if test "${with_c_include_dirs+set}" = set; then withval=$with_c_include_dirs; @@ -7828,6 +7944,62 @@ cat >>confdefs.h <<_ACEOF #define LLVM_PATH_DOTTY "$DOTTY${EXEEXT}" _ACEOF +fi +# Extract the first word of "xdot.py", so it can be a program name with args. +set dummy xdot.py; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_path_XDOT_PY+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $XDOT_PY in + [\\/]* | ?:[\\/]*) + ac_cv_path_XDOT_PY="$XDOT_PY" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_XDOT_PY="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + test -z "$ac_cv_path_XDOT_PY" && ac_cv_path_XDOT_PY="echo xdot.py" + ;; +esac +fi +XDOT_PY=$ac_cv_path_XDOT_PY +if test -n "$XDOT_PY"; then + { echo "$as_me:$LINENO: result: $XDOT_PY" >&5 +echo "${ECHO_T}$XDOT_PY" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +if test "$XDOT_PY" != "echo xdot.py" ; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_XDOT_PY 1 +_ACEOF + + if test "$llvm_cv_os_type" = "MingW" ; then + XDOT_PY=`echo $XDOT_PY | sed 's/^\/\([A-Za-z]\)\//\1:\//' ` + fi + +cat >>confdefs.h <<_ACEOF +#define LLVM_PATH_XDOT_PY "$XDOT_PY${EXEEXT}" +_ACEOF + fi @@ -8146,12 +8318,12 @@ fi set dummy gzip; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } -if test "${ac_cv_path_GZIP+set}" = set; then +if test "${ac_cv_path_GZIPBIN+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - case $GZIP in + case $GZIPBIN in [\\/]* | ?:[\\/]*) - ac_cv_path_GZIP="$GZIP" # Let the user override the test with a path. + ac_cv_path_GZIPBIN="$GZIPBIN" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -8161,7 +8333,7 @@ do test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_path_GZIP="$as_dir/$ac_word$ac_exec_ext" + ac_cv_path_GZIPBIN="$as_dir/$ac_word$ac_exec_ext" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi @@ -8172,10 +8344,10 @@ IFS=$as_save_IFS ;; esac fi -GZIP=$ac_cv_path_GZIP -if test -n "$GZIP"; then - { echo "$as_me:$LINENO: result: $GZIP" >&5 -echo "${ECHO_T}$GZIP" >&6; } +GZIPBIN=$ac_cv_path_GZIPBIN +if test -n "$GZIPBIN"; then + { echo "$as_me:$LINENO: result: $GZIPBIN" >&5 +echo "${ECHO_T}$GZIPBIN" >&6; } else { echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6; } @@ -11389,7 +11561,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <&5 -echo "$as_me: error: g++|icc required but not found" >&2;} + { { echo "$as_me:$LINENO: error: g++|clang++|icc required but not found" >&5 +echo "$as_me: error: g++|clang++|icc required but not found" >&2;} { (exit 1); exit 1; }; } fi @@ -13865,7 +14037,7 @@ _ACEOF fi -if test "$ENABLE_THREADS" -eq 1 ; then +if test "$ENABLE_THREADS" -eq 1 && test "$ENABLE_PTHREADS" -eq 1 ; then { echo "$as_me:$LINENO: checking for pthread_mutex_init in -lpthread" >&5 echo $ECHO_N "checking for pthread_mutex_init in -lpthread... $ECHO_C" >&6; } @@ -16090,7 +16262,8 @@ done -for ac_header in sys/mman.h sys/param.h sys/resource.h sys/time.h + +for ac_header in sys/mman.h sys/param.h sys/resource.h sys/time.h sys/uio.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then @@ -16599,9 +16772,8 @@ fi done -if test "$ENABLE_THREADS" -eq 1 ; then -for ac_header in pthread.h +for ac_header in fenv.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then @@ -16764,24 +16936,14 @@ if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF - HAVE_PTHREAD=1 - -else - HAVE_PTHREAD=0 fi done -else - HAVE_PTHREAD=0 - -fi +if test "$ENABLE_THREADS" -eq 1 && test "$ENABLE_PTHREADS" -eq 1 ; then -if test "$llvm_cv_enable_libffi" = "yes" ; then - - -for ac_header in ffi.h ffi/ffi.h +for ac_header in pthread.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then @@ -16944,15 +17106,24 @@ if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF + HAVE_PTHREAD=1 + +else + HAVE_PTHREAD=0 fi done +else + HAVE_PTHREAD=0 + fi +if test "$llvm_cv_enable_libffi" = "yes" ; then -for ac_header in CrashReporterClient.h + +for ac_header in ffi.h ffi/ffi.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then @@ -17120,112 +17291,33 @@ fi done - - - - - { echo "$as_me:$LINENO: checking for HUGE_VAL sanity" >&5 -echo $ECHO_N "checking for HUGE_VAL sanity... $ECHO_C" >&6; } -if test "${ac_cv_huge_val_sanity+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - ac_save_CXXFLAGS=$CXXFLAGS - CXXFLAGS=-pedantic - if test "$cross_compiling" = yes; then - ac_cv_huge_val_sanity=yes -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -int -main () -{ -double x = HUGE_VAL; return x != x; - ; - return 0; -} -_ACEOF -rm -f conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_huge_val_sanity=yes -else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -( exit $ac_status ) -ac_cv_huge_val_sanity=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext -fi - - - CXXFLAGS=$ac_save_CXXFLAGS - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - fi -{ echo "$as_me:$LINENO: result: $ac_cv_huge_val_sanity" >&5 -echo "${ECHO_T}$ac_cv_huge_val_sanity" >&6; } - HUGE_VAL_SANITY=$ac_cv_huge_val_sanity -{ echo "$as_me:$LINENO: checking for pid_t" >&5 -echo $ECHO_N "checking for pid_t... $ECHO_C" >&6; } -if test "${ac_cv_type_pid_t+set}" = set; then +for ac_header in CrashReporterClient.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } else - cat >conftest.$ac_ext <<_ACEOF + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default -typedef pid_t ac__type_new_; -int -main () -{ -if ((ac__type_new_ *) 0) - return 0; -if (sizeof (ac__type_new_)) - return 0; - ; - return 0; -} +#include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" @@ -17261,31 +17353,1854 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_type_pid_t=yes + ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_cv_type_pid_t=no + ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ echo "$as_me:$LINENO: result: $ac_cv_type_pid_t" >&5 -echo "${ECHO_T}$ac_cv_type_pid_t" >&6; } -if test $ac_cv_type_pid_t = yes; then - : -else +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } -cat >>confdefs.h <<_ACEOF +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( cat <<\_ASBOX +## ----------------------------------- ## +## Report this to llvmbugs@cs.uiuc.edu ## +## ----------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +{ echo "$as_me:$LINENO: checking __crashreporter_info__" >&5 +echo $ECHO_N "checking __crashreporter_info__... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +extern const char *__crashreporter_info__; + int main() { + __crashreporter_info__ = "test"; + return 0; + } + +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +cat >>confdefs.h <<\_ACEOF +#define HAVE_CRASHREPORTER_INFO 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + +cat >>confdefs.h <<\_ACEOF +#define HAVE_CRASHREPORTER_INFO 0 +_ACEOF + +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + + + + { echo "$as_me:$LINENO: checking for HUGE_VAL sanity" >&5 +echo $ECHO_N "checking for HUGE_VAL sanity... $ECHO_C" >&6; } +if test "${ac_cv_huge_val_sanity+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS=$CXXFLAGS + CXXFLAGS=-pedantic + if test "$cross_compiling" = yes; then + ac_cv_huge_val_sanity=yes +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +double x = HUGE_VAL; return x != x; + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_huge_val_sanity=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_huge_val_sanity=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + + CXXFLAGS=$ac_save_CXXFLAGS + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_huge_val_sanity" >&5 +echo "${ECHO_T}$ac_cv_huge_val_sanity" >&6; } + HUGE_VAL_SANITY=$ac_cv_huge_val_sanity + + +{ echo "$as_me:$LINENO: checking for pid_t" >&5 +echo $ECHO_N "checking for pid_t... $ECHO_C" >&6; } +if test "${ac_cv_type_pid_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +typedef pid_t ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_pid_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_pid_t=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_pid_t" >&5 +echo "${ECHO_T}$ac_cv_type_pid_t" >&6; } +if test $ac_cv_type_pid_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF #define pid_t int _ACEOF fi -{ echo "$as_me:$LINENO: checking for size_t" >&5 -echo $ECHO_N "checking for size_t... $ECHO_C" >&6; } -if test "${ac_cv_type_size_t+set}" = set; then +{ echo "$as_me:$LINENO: checking for size_t" >&5 +echo $ECHO_N "checking for size_t... $ECHO_C" >&6; } +if test "${ac_cv_type_size_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +typedef size_t ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_size_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_size_t=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5 +echo "${ECHO_T}$ac_cv_type_size_t" >&6; } +if test $ac_cv_type_size_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned int +_ACEOF + +fi + + +cat >>confdefs.h <<_ACEOF +#define RETSIGTYPE void +_ACEOF + +{ echo "$as_me:$LINENO: checking whether struct tm is in sys/time.h or time.h" >&5 +echo $ECHO_N "checking whether struct tm is in sys/time.h or time.h... $ECHO_C" >&6; } +if test "${ac_cv_struct_tm+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +struct tm *tp; tp->tm_sec; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_struct_tm=time.h +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_struct_tm=sys/time.h +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_struct_tm" >&5 +echo "${ECHO_T}$ac_cv_struct_tm" >&6; } +if test $ac_cv_struct_tm = sys/time.h; then + +cat >>confdefs.h <<\_ACEOF +#define TM_IN_SYS_TIME 1 +_ACEOF + +fi + +{ echo "$as_me:$LINENO: checking for int64_t" >&5 +echo $ECHO_N "checking for int64_t... $ECHO_C" >&6; } +if test "${ac_cv_type_int64_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +typedef int64_t ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_int64_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_int64_t=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_int64_t" >&5 +echo "${ECHO_T}$ac_cv_type_int64_t" >&6; } +if test $ac_cv_type_int64_t = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_INT64_T 1 +_ACEOF + + +else + { { echo "$as_me:$LINENO: error: Type int64_t required but not found" >&5 +echo "$as_me: error: Type int64_t required but not found" >&2;} + { (exit 1); exit 1; }; } +fi + +{ echo "$as_me:$LINENO: checking for uint64_t" >&5 +echo $ECHO_N "checking for uint64_t... $ECHO_C" >&6; } +if test "${ac_cv_type_uint64_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +typedef uint64_t ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_uint64_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_uint64_t=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_uint64_t" >&5 +echo "${ECHO_T}$ac_cv_type_uint64_t" >&6; } +if test $ac_cv_type_uint64_t = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_UINT64_T 1 +_ACEOF + + +else + { echo "$as_me:$LINENO: checking for u_int64_t" >&5 +echo $ECHO_N "checking for u_int64_t... $ECHO_C" >&6; } +if test "${ac_cv_type_u_int64_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +typedef u_int64_t ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_u_int64_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_u_int64_t=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_u_int64_t" >&5 +echo "${ECHO_T}$ac_cv_type_u_int64_t" >&6; } +if test $ac_cv_type_u_int64_t = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_U_INT64_T 1 +_ACEOF + + +else + { { echo "$as_me:$LINENO: error: Type uint64_t or u_int64_t required but not found" >&5 +echo "$as_me: error: Type uint64_t or u_int64_t required but not found" >&2;} + { (exit 1); exit 1; }; } +fi + +fi + + + + + + + + + + +for ac_func in backtrace ceilf floorf roundf rintf nearbyintf getcwd +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + + + +for ac_func in powf fmodf strtof round +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + + + + +for ac_func in getpagesize getrusage getrlimit setrlimit gettimeofday +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + + +for ac_func in isatty mkdtemp mkstemp +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + + + + + +for ac_func in mktemp posix_spawn realpath sbrk setrlimit strdup +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + + +for ac_func in strerror strerror_r setenv +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + + + +for ac_func in strtoll strtoq sysconf malloc_zone_statistics +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + + + + +for ac_func in setjmp longjmp sigsetjmp siglongjmp writev +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +{ echo "$as_me:$LINENO: checking if printf has the %a format character" >&5 +echo $ECHO_N "checking if printf has the %a format character... $ECHO_C" >&6; } +if test "${llvm_cv_c_printf_a+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + if test "$cross_compiling" = yes; then + llvmac_cv_c_printf_a=no +else + cat >conftest.$ac_ext <<_ACEOF + + /* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +#include + +int +main () +{ + +volatile double A, B; +char Buffer[100]; +A = 1; +A /= 10.0; +sprintf(Buffer, "%a", A); +B = atof(Buffer); +if (A != B) + return (1); +if (A != 0x1.999999999999ap-4) + return (1); +return (0); + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + llvm_cv_c_printf_a=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +llvmac_cv_c_printf_a=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $llvm_cv_c_printf_a" >&5 +echo "${ECHO_T}$llvm_cv_c_printf_a" >&6; } + if test "$llvm_cv_c_printf_a" = "yes"; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_PRINTF_A 1 +_ACEOF + + fi + + +{ echo "$as_me:$LINENO: checking for srand48/lrand48/drand48 in " >&5 +echo $ECHO_N "checking for srand48/lrand48/drand48 in ... $ECHO_C" >&6; } +if test "${ac_cv_func_rand48+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +srand48(0);lrand48();drand48(); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_rand48=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_rand48=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_func_rand48" >&5 +echo "${ECHO_T}$ac_cv_func_rand48" >&6; } + +if test "$ac_cv_func_rand48" = "yes" ; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_RAND48 1 +_ACEOF + +fi + + +{ echo "$as_me:$LINENO: checking whether strerror_s is declared" >&5 +echo $ECHO_N "checking whether strerror_s is declared... $ECHO_C" >&6; } +if test "${ac_cv_have_decl_strerror_s+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF @@ -17295,14 +19210,14 @@ cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default -typedef size_t ac__type_new_; int main () { -if ((ac__type_new_ *) 0) - return 0; -if (sizeof (ac__type_new_)) - return 0; +#ifndef strerror_s + char *p = (char *) strerror_s; + return !p; +#endif + ; return 0; } @@ -17341,63 +19256,243 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_type_size_t=yes + ac_cv_have_decl_strerror_s=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_cv_type_size_t=no + ac_cv_have_decl_strerror_s=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi -{ echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5 -echo "${ECHO_T}$ac_cv_type_size_t" >&6; } -if test $ac_cv_type_size_t = yes; then - : -else +{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_strerror_s" >&5 +echo "${ECHO_T}$ac_cv_have_decl_strerror_s" >&6; } +if test $ac_cv_have_decl_strerror_s = yes; then cat >>confdefs.h <<_ACEOF -#define size_t unsigned int +#define HAVE_DECL_STRERROR_S 1 +_ACEOF + + +else + cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_STRERROR_S 0 _ACEOF + fi -cat >>confdefs.h <<_ACEOF -#define RETSIGTYPE void + +if test "$llvm_cv_os_type" = "MingW" ; then + { echo "$as_me:$LINENO: checking for _alloca in -lgcc" >&5 +echo $ECHO_N "checking for _alloca in -lgcc... $ECHO_C" >&6; } +if test "${ac_cv_lib_gcc__alloca+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgcc $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ _ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ -{ echo "$as_me:$LINENO: checking whether struct tm is in sys/time.h or time.h" >&5 -echo $ECHO_N "checking whether struct tm is in sys/time.h or time.h... $ECHO_C" >&6; } -if test "${ac_cv_struct_tm+set}" = set; then +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char _alloca (); +int +main () +{ +return _alloca (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_gcc__alloca=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_gcc__alloca=no +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_gcc__alloca" >&5 +echo "${ECHO_T}$ac_cv_lib_gcc__alloca" >&6; } +if test $ac_cv_lib_gcc__alloca = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE__ALLOCA 1 +_ACEOF + +fi + + { echo "$as_me:$LINENO: checking for __alloca in -lgcc" >&5 +echo $ECHO_N "checking for __alloca in -lgcc... $ECHO_C" >&6; } +if test "${ac_cv_lib_gcc___alloca+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - cat >conftest.$ac_ext <<_ACEOF + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgcc $LIBS" +cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#include -#include +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char __alloca (); int main () { -struct tm *tp; tp->tm_sec; +return __alloca (); ; return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_gcc___alloca=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_gcc___alloca=no +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_gcc___alloca" >&5 +echo "${ECHO_T}$ac_cv_lib_gcc___alloca" >&6; } +if test $ac_cv_lib_gcc___alloca = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE___ALLOCA 1 +_ACEOF + +fi + + { echo "$as_me:$LINENO: checking for __chkstk in -lgcc" >&5 +echo $ECHO_N "checking for __chkstk in -lgcc... $ECHO_C" >&6; } +if test "${ac_cv_lib_gcc___chkstk+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgcc $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char __chkstk (); +int +main () +{ +return __chkstk (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 @@ -17414,7 +19509,7 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' + { ac_try='test -s conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; @@ -17424,58 +19519,65 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_struct_tm=time.h + ac_cv_lib_gcc___chkstk=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_cv_struct_tm=sys/time.h + ac_cv_lib_gcc___chkstk=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS fi -{ echo "$as_me:$LINENO: result: $ac_cv_struct_tm" >&5 -echo "${ECHO_T}$ac_cv_struct_tm" >&6; } -if test $ac_cv_struct_tm = sys/time.h; then +{ echo "$as_me:$LINENO: result: $ac_cv_lib_gcc___chkstk" >&5 +echo "${ECHO_T}$ac_cv_lib_gcc___chkstk" >&6; } +if test $ac_cv_lib_gcc___chkstk = yes; then cat >>confdefs.h <<\_ACEOF -#define TM_IN_SYS_TIME 1 +#define HAVE___CHKSTK 1 _ACEOF fi -{ echo "$as_me:$LINENO: checking for int64_t" >&5 -echo $ECHO_N "checking for int64_t... $ECHO_C" >&6; } -if test "${ac_cv_type_int64_t+set}" = set; then + { echo "$as_me:$LINENO: checking for ___chkstk in -lgcc" >&5 +echo $ECHO_N "checking for ___chkstk in -lgcc... $ECHO_C" >&6; } +if test "${ac_cv_lib_gcc____chkstk+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - cat >conftest.$ac_ext <<_ACEOF + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgcc $LIBS" +cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -$ac_includes_default -typedef int64_t ac__type_new_; + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char ___chkstk (); int main () { -if ((ac__type_new_ *) 0) - return 0; -if (sizeof (ac__type_new_)) - return 0; +return ___chkstk (); ; return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 + (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 @@ -17492,7 +19594,7 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' + { ac_try='test -s conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; @@ -17502,63 +19604,66 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_type_int64_t=yes + ac_cv_lib_gcc____chkstk=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_cv_type_int64_t=no + ac_cv_lib_gcc____chkstk=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS fi -{ echo "$as_me:$LINENO: result: $ac_cv_type_int64_t" >&5 -echo "${ECHO_T}$ac_cv_type_int64_t" >&6; } -if test $ac_cv_type_int64_t = yes; then +{ echo "$as_me:$LINENO: result: $ac_cv_lib_gcc____chkstk" >&5 +echo "${ECHO_T}$ac_cv_lib_gcc____chkstk" >&6; } +if test $ac_cv_lib_gcc____chkstk = yes; then -cat >>confdefs.h <<_ACEOF -#define HAVE_INT64_T 1 +cat >>confdefs.h <<\_ACEOF +#define HAVE____CHKSTK 1 _ACEOF - -else - { { echo "$as_me:$LINENO: error: Type int64_t required but not found" >&5 -echo "$as_me: error: Type int64_t required but not found" >&2;} - { (exit 1); exit 1; }; } fi -{ echo "$as_me:$LINENO: checking for uint64_t" >&5 -echo $ECHO_N "checking for uint64_t... $ECHO_C" >&6; } -if test "${ac_cv_type_uint64_t+set}" = set; then + + { echo "$as_me:$LINENO: checking for __ashldi3 in -lgcc" >&5 +echo $ECHO_N "checking for __ashldi3 in -lgcc... $ECHO_C" >&6; } +if test "${ac_cv_lib_gcc___ashldi3+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - cat >conftest.$ac_ext <<_ACEOF + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgcc $LIBS" +cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -$ac_includes_default -typedef uint64_t ac__type_new_; + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char __ashldi3 (); int main () { -if ((ac__type_new_ *) 0) - return 0; -if (sizeof (ac__type_new_)) - return 0; +return __ashldi3 (); ; return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 + (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 @@ -17575,7 +19680,7 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' + { ac_try='test -s conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; @@ -17585,58 +19690,65 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_type_uint64_t=yes + ac_cv_lib_gcc___ashldi3=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_cv_type_uint64_t=no + ac_cv_lib_gcc___ashldi3=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS fi -{ echo "$as_me:$LINENO: result: $ac_cv_type_uint64_t" >&5 -echo "${ECHO_T}$ac_cv_type_uint64_t" >&6; } -if test $ac_cv_type_uint64_t = yes; then +{ echo "$as_me:$LINENO: result: $ac_cv_lib_gcc___ashldi3" >&5 +echo "${ECHO_T}$ac_cv_lib_gcc___ashldi3" >&6; } +if test $ac_cv_lib_gcc___ashldi3 = yes; then -cat >>confdefs.h <<_ACEOF -#define HAVE_UINT64_T 1 +cat >>confdefs.h <<\_ACEOF +#define HAVE___ASHLDI3 1 _ACEOF +fi -else - { echo "$as_me:$LINENO: checking for u_int64_t" >&5 -echo $ECHO_N "checking for u_int64_t... $ECHO_C" >&6; } -if test "${ac_cv_type_u_int64_t+set}" = set; then + { echo "$as_me:$LINENO: checking for __ashrdi3 in -lgcc" >&5 +echo $ECHO_N "checking for __ashrdi3 in -lgcc... $ECHO_C" >&6; } +if test "${ac_cv_lib_gcc___ashrdi3+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - cat >conftest.$ac_ext <<_ACEOF + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgcc $LIBS" +cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -$ac_includes_default -typedef u_int64_t ac__type_new_; + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char __ashrdi3 (); int main () { -if ((ac__type_new_ *) 0) - return 0; -if (sizeof (ac__type_new_)) - return 0; +return __ashrdi3 (); ; return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 + (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 @@ -17653,7 +19765,7 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' + { ac_try='test -s conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; @@ -17663,72 +19775,41 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_type_u_int64_t=yes + ac_cv_lib_gcc___ashrdi3=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_cv_type_u_int64_t=no + ac_cv_lib_gcc___ashrdi3=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS fi -{ echo "$as_me:$LINENO: result: $ac_cv_type_u_int64_t" >&5 -echo "${ECHO_T}$ac_cv_type_u_int64_t" >&6; } -if test $ac_cv_type_u_int64_t = yes; then +{ echo "$as_me:$LINENO: result: $ac_cv_lib_gcc___ashrdi3" >&5 +echo "${ECHO_T}$ac_cv_lib_gcc___ashrdi3" >&6; } +if test $ac_cv_lib_gcc___ashrdi3 = yes; then -cat >>confdefs.h <<_ACEOF -#define HAVE_U_INT64_T 1 +cat >>confdefs.h <<\_ACEOF +#define HAVE___ASHRDI3 1 _ACEOF - -else - { { echo "$as_me:$LINENO: error: Type uint64_t or u_int64_t required but not found" >&5 -echo "$as_me: error: Type uint64_t or u_int64_t required but not found" >&2;} - { (exit 1); exit 1; }; } -fi - fi - - - - - - - - - -for ac_func in backtrace ceilf floorf roundf rintf nearbyintf getcwd -do -as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` -{ echo "$as_me:$LINENO: checking for $ac_func" >&5 -echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } -if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for __divdi3 in -lgcc" >&5 +echo $ECHO_N "checking for __divdi3 in -lgcc... $ECHO_C" >&6; } +if test "${ac_cv_lib_gcc___divdi3+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - cat >conftest.$ac_ext <<_ACEOF + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgcc $LIBS" +cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -/* Define $ac_func to an innocuous variant, in case declares $ac_func. - For example, HP-UX 11i declares gettimeofday. */ -#define $ac_func innocuous_$ac_func - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $ac_func /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC @@ -17736,18 +19817,11 @@ cat >>conftest.$ac_ext <<_ACEOF #ifdef __cplusplus extern "C" #endif -char $ac_func (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$ac_func || defined __stub___$ac_func -choke me -#endif - +char __divdi3 (); int main () { -return $ac_func (); +return __divdi3 (); ; return 0; } @@ -17786,62 +19860,41 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - eval "$as_ac_var=yes" + ac_cv_lib_gcc___divdi3=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - eval "$as_ac_var=no" + ac_cv_lib_gcc___divdi3=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS fi -ac_res=`eval echo '${'$as_ac_var'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -if test `eval echo '${'$as_ac_var'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +{ echo "$as_me:$LINENO: result: $ac_cv_lib_gcc___divdi3" >&5 +echo "${ECHO_T}$ac_cv_lib_gcc___divdi3" >&6; } +if test $ac_cv_lib_gcc___divdi3 = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE___DIVDI3 1 _ACEOF fi -done - - - - -for ac_func in powf fmodf strtof round -do -as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` -{ echo "$as_me:$LINENO: checking for $ac_func" >&5 -echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } -if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for __fixdfdi in -lgcc" >&5 +echo $ECHO_N "checking for __fixdfdi in -lgcc... $ECHO_C" >&6; } +if test "${ac_cv_lib_gcc___fixdfdi+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - cat >conftest.$ac_ext <<_ACEOF + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgcc $LIBS" +cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -/* Define $ac_func to an innocuous variant, in case declares $ac_func. - For example, HP-UX 11i declares gettimeofday. */ -#define $ac_func innocuous_$ac_func - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $ac_func /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC @@ -17849,18 +19902,11 @@ cat >>conftest.$ac_ext <<_ACEOF #ifdef __cplusplus extern "C" #endif -char $ac_func (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$ac_func || defined __stub___$ac_func -choke me -#endif - +char __fixdfdi (); int main () { -return $ac_func (); +return __fixdfdi (); ; return 0; } @@ -17899,63 +19945,41 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - eval "$as_ac_var=yes" + ac_cv_lib_gcc___fixdfdi=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - eval "$as_ac_var=no" -fi - -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -ac_res=`eval echo '${'$as_ac_var'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -if test `eval echo '${'$as_ac_var'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - + ac_cv_lib_gcc___fixdfdi=no fi -done - - +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_gcc___fixdfdi" >&5 +echo "${ECHO_T}$ac_cv_lib_gcc___fixdfdi" >&6; } +if test $ac_cv_lib_gcc___fixdfdi = yes; then +cat >>confdefs.h <<\_ACEOF +#define HAVE___FIXDFDI 1 +_ACEOF +fi -for ac_func in getpagesize getrusage getrlimit setrlimit gettimeofday -do -as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` -{ echo "$as_me:$LINENO: checking for $ac_func" >&5 -echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } -if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for __fixsfdi in -lgcc" >&5 +echo $ECHO_N "checking for __fixsfdi in -lgcc... $ECHO_C" >&6; } +if test "${ac_cv_lib_gcc___fixsfdi+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - cat >conftest.$ac_ext <<_ACEOF + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgcc $LIBS" +cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -/* Define $ac_func to an innocuous variant, in case declares $ac_func. - For example, HP-UX 11i declares gettimeofday. */ -#define $ac_func innocuous_$ac_func - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $ac_func /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC @@ -17963,18 +19987,11 @@ cat >>conftest.$ac_ext <<_ACEOF #ifdef __cplusplus extern "C" #endif -char $ac_func (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$ac_func || defined __stub___$ac_func -choke me -#endif - +char __fixsfdi (); int main () { -return $ac_func (); +return __fixsfdi (); ; return 0; } @@ -18013,61 +20030,41 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - eval "$as_ac_var=yes" + ac_cv_lib_gcc___fixsfdi=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - eval "$as_ac_var=no" + ac_cv_lib_gcc___fixsfdi=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS fi -ac_res=`eval echo '${'$as_ac_var'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -if test `eval echo '${'$as_ac_var'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +{ echo "$as_me:$LINENO: result: $ac_cv_lib_gcc___fixsfdi" >&5 +echo "${ECHO_T}$ac_cv_lib_gcc___fixsfdi" >&6; } +if test $ac_cv_lib_gcc___fixsfdi = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE___FIXSFDI 1 _ACEOF fi -done - - - -for ac_func in isatty mkdtemp mkstemp -do -as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` -{ echo "$as_me:$LINENO: checking for $ac_func" >&5 -echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } -if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for __floatdidf in -lgcc" >&5 +echo $ECHO_N "checking for __floatdidf in -lgcc... $ECHO_C" >&6; } +if test "${ac_cv_lib_gcc___floatdidf+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - cat >conftest.$ac_ext <<_ACEOF + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgcc $LIBS" +cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -/* Define $ac_func to an innocuous variant, in case declares $ac_func. - For example, HP-UX 11i declares gettimeofday. */ -#define $ac_func innocuous_$ac_func - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $ac_func /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC @@ -18075,18 +20072,11 @@ cat >>conftest.$ac_ext <<_ACEOF #ifdef __cplusplus extern "C" #endif -char $ac_func (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$ac_func || defined __stub___$ac_func -choke me -#endif - +char __floatdidf (); int main () { -return $ac_func (); +return __floatdidf (); ; return 0; } @@ -18125,64 +20115,41 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - eval "$as_ac_var=yes" + ac_cv_lib_gcc___floatdidf=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - eval "$as_ac_var=no" + ac_cv_lib_gcc___floatdidf=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS fi -ac_res=`eval echo '${'$as_ac_var'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -if test `eval echo '${'$as_ac_var'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +{ echo "$as_me:$LINENO: result: $ac_cv_lib_gcc___floatdidf" >&5 +echo "${ECHO_T}$ac_cv_lib_gcc___floatdidf" >&6; } +if test $ac_cv_lib_gcc___floatdidf = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE___FLOATDIDF 1 _ACEOF fi -done - - - - - - -for ac_func in mktemp posix_spawn realpath sbrk setrlimit strdup -do -as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` -{ echo "$as_me:$LINENO: checking for $ac_func" >&5 -echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } -if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for __lshrdi3 in -lgcc" >&5 +echo $ECHO_N "checking for __lshrdi3 in -lgcc... $ECHO_C" >&6; } +if test "${ac_cv_lib_gcc___lshrdi3+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - cat >conftest.$ac_ext <<_ACEOF + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgcc $LIBS" +cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -/* Define $ac_func to an innocuous variant, in case declares $ac_func. - For example, HP-UX 11i declares gettimeofday. */ -#define $ac_func innocuous_$ac_func - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $ac_func /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC @@ -18190,18 +20157,11 @@ cat >>conftest.$ac_ext <<_ACEOF #ifdef __cplusplus extern "C" #endif -char $ac_func (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$ac_func || defined __stub___$ac_func -choke me -#endif - +char __lshrdi3 (); int main () { -return $ac_func (); +return __lshrdi3 (); ; return 0; } @@ -18240,62 +20200,41 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - eval "$as_ac_var=yes" + ac_cv_lib_gcc___lshrdi3=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - eval "$as_ac_var=no" + ac_cv_lib_gcc___lshrdi3=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS fi -ac_res=`eval echo '${'$as_ac_var'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -if test `eval echo '${'$as_ac_var'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +{ echo "$as_me:$LINENO: result: $ac_cv_lib_gcc___lshrdi3" >&5 +echo "${ECHO_T}$ac_cv_lib_gcc___lshrdi3" >&6; } +if test $ac_cv_lib_gcc___lshrdi3 = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE___LSHRDI3 1 _ACEOF fi -done - - - - -for ac_func in strerror strerror_r strerror_s setenv -do -as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` -{ echo "$as_me:$LINENO: checking for $ac_func" >&5 -echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } -if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for __moddi3 in -lgcc" >&5 +echo $ECHO_N "checking for __moddi3 in -lgcc... $ECHO_C" >&6; } +if test "${ac_cv_lib_gcc___moddi3+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - cat >conftest.$ac_ext <<_ACEOF + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgcc $LIBS" +cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -/* Define $ac_func to an innocuous variant, in case declares $ac_func. - For example, HP-UX 11i declares gettimeofday. */ -#define $ac_func innocuous_$ac_func - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $ac_func /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC @@ -18303,18 +20242,11 @@ cat >>conftest.$ac_ext <<_ACEOF #ifdef __cplusplus extern "C" #endif -char $ac_func (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$ac_func || defined __stub___$ac_func -choke me -#endif - +char __moddi3 (); int main () { -return $ac_func (); +return __moddi3 (); ; return 0; } @@ -18353,62 +20285,41 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - eval "$as_ac_var=yes" + ac_cv_lib_gcc___moddi3=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - eval "$as_ac_var=no" + ac_cv_lib_gcc___moddi3=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS fi -ac_res=`eval echo '${'$as_ac_var'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -if test `eval echo '${'$as_ac_var'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +{ echo "$as_me:$LINENO: result: $ac_cv_lib_gcc___moddi3" >&5 +echo "${ECHO_T}$ac_cv_lib_gcc___moddi3" >&6; } +if test $ac_cv_lib_gcc___moddi3 = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE___MODDI3 1 _ACEOF fi -done - - - - -for ac_func in strtoll strtoq sysconf malloc_zone_statistics -do -as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` -{ echo "$as_me:$LINENO: checking for $ac_func" >&5 -echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } -if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for __udivdi3 in -lgcc" >&5 +echo $ECHO_N "checking for __udivdi3 in -lgcc... $ECHO_C" >&6; } +if test "${ac_cv_lib_gcc___udivdi3+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - cat >conftest.$ac_ext <<_ACEOF + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgcc $LIBS" +cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -/* Define $ac_func to an innocuous variant, in case declares $ac_func. - For example, HP-UX 11i declares gettimeofday. */ -#define $ac_func innocuous_$ac_func - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $ac_func /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC @@ -18416,18 +20327,11 @@ cat >>conftest.$ac_ext <<_ACEOF #ifdef __cplusplus extern "C" #endif -char $ac_func (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$ac_func || defined __stub___$ac_func -choke me -#endif - +char __udivdi3 (); int main () { -return $ac_func (); +return __udivdi3 (); ; return 0; } @@ -18466,62 +20370,41 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - eval "$as_ac_var=yes" + ac_cv_lib_gcc___udivdi3=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - eval "$as_ac_var=no" -fi - -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -ac_res=`eval echo '${'$as_ac_var'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -if test `eval echo '${'$as_ac_var'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - + ac_cv_lib_gcc___udivdi3=no fi -done - +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_gcc___udivdi3" >&5 +echo "${ECHO_T}$ac_cv_lib_gcc___udivdi3" >&6; } +if test $ac_cv_lib_gcc___udivdi3 = yes; then +cat >>confdefs.h <<\_ACEOF +#define HAVE___UDIVDI3 1 +_ACEOF +fi -for ac_func in setjmp longjmp sigsetjmp siglongjmp -do -as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` -{ echo "$as_me:$LINENO: checking for $ac_func" >&5 -echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } -if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for __umoddi3 in -lgcc" >&5 +echo $ECHO_N "checking for __umoddi3 in -lgcc... $ECHO_C" >&6; } +if test "${ac_cv_lib_gcc___umoddi3+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - cat >conftest.$ac_ext <<_ACEOF + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgcc $LIBS" +cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -/* Define $ac_func to an innocuous variant, in case declares $ac_func. - For example, HP-UX 11i declares gettimeofday. */ -#define $ac_func innocuous_$ac_func - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $ac_func /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC @@ -18529,18 +20412,11 @@ cat >>conftest.$ac_ext <<_ACEOF #ifdef __cplusplus extern "C" #endif -char $ac_func (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$ac_func || defined __stub___$ac_func -choke me -#endif - +char __umoddi3 (); int main () { -return $ac_func (); +return __umoddi3 (); ; return 0; } @@ -18579,83 +20455,83 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - eval "$as_ac_var=yes" + ac_cv_lib_gcc___umoddi3=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - eval "$as_ac_var=no" + ac_cv_lib_gcc___umoddi3=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS fi -ac_res=`eval echo '${'$as_ac_var'}'` - { echo "$as_me:$LINENO: result: $ac_res" >&5 -echo "${ECHO_T}$ac_res" >&6; } -if test `eval echo '${'$as_ac_var'}'` = yes; then - cat >>confdefs.h <<_ACEOF -#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +{ echo "$as_me:$LINENO: result: $ac_cv_lib_gcc___umoddi3" >&5 +echo "${ECHO_T}$ac_cv_lib_gcc___umoddi3" >&6; } +if test $ac_cv_lib_gcc___umoddi3 = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE___UMODDI3 1 _ACEOF fi -done -{ echo "$as_me:$LINENO: checking if printf has the %a format character" >&5 -echo $ECHO_N "checking if printf has the %a format character... $ECHO_C" >&6; } -if test "${llvm_cv_c_printf_a+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - if test "$cross_compiling" = yes; then - llvmac_cv_c_printf_a=no + { echo "$as_me:$LINENO: checking for __main in -lgcc" >&5 +echo $ECHO_N "checking for __main in -lgcc... $ECHO_C" >&6; } +if test "${ac_cv_lib_gcc___main+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 else - cat >conftest.$ac_ext <<_ACEOF - - /* confdefs.h. */ + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgcc $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#include -#include - +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char __main (); int main () { - -volatile double A, B; -char Buffer[100]; -A = 1; -A /= 10.0; -sprintf(Buffer, "%a", A); -B = atof(Buffer); -if (A != B) - return (1); -if (A != 0x1.999999999999ap-4) - return (1); -return (0); +return __main (); ; return 0; } _ACEOF -rm -f conftest$ac_exeext +rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>&5 + (eval "$ac_link") 2>conftest.er1 ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; @@ -18665,78 +20541,72 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - llvm_cv_c_printf_a=yes + ac_cv_lib_gcc___main=yes else - echo "$as_me: program exited with status $ac_status" >&5 -echo "$as_me: failed program was:" >&5 + echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -( exit $ac_status ) -llvmac_cv_c_printf_a=no + ac_cv_lib_gcc___main=no fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext -fi - - - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS fi -{ echo "$as_me:$LINENO: result: $llvm_cv_c_printf_a" >&5 -echo "${ECHO_T}$llvm_cv_c_printf_a" >&6; } - if test "$llvm_cv_c_printf_a" = "yes"; then +{ echo "$as_me:$LINENO: result: $ac_cv_lib_gcc___main" >&5 +echo "${ECHO_T}$ac_cv_lib_gcc___main" >&6; } +if test $ac_cv_lib_gcc___main = yes; then cat >>confdefs.h <<\_ACEOF -#define HAVE_PRINTF_A 1 +#define HAVE___MAIN 1 _ACEOF - fi - +fi -{ echo "$as_me:$LINENO: checking for srand48/lrand48/drand48 in " >&5 -echo $ECHO_N "checking for srand48/lrand48/drand48 in ... $ECHO_C" >&6; } -if test "${ac_cv_func_rand48+set}" = set; then + { echo "$as_me:$LINENO: checking for __cmpdi2 in -lgcc" >&5 +echo $ECHO_N "checking for __cmpdi2 in -lgcc... $ECHO_C" >&6; } +if test "${ac_cv_lib_gcc___cmpdi2+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - ac_ext=cpp -ac_cpp='$CXXCPP $CPPFLAGS' -ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_cxx_compiler_gnu - - cat >conftest.$ac_ext <<_ACEOF + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgcc $LIBS" +cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#include + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char __cmpdi2 (); int main () { -srand48(0);lrand48();drand48(); +return __cmpdi2 (); ; return 0; } _ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 + (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; @@ -18746,7 +20616,7 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' + { ac_try='test -s conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; @@ -18756,33 +20626,29 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_func_rand48=yes + ac_cv_lib_gcc___cmpdi2=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_cv_func_rand48=no + ac_cv_lib_gcc___cmpdi2=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS fi -{ echo "$as_me:$LINENO: result: $ac_cv_func_rand48" >&5 -echo "${ECHO_T}$ac_cv_func_rand48" >&6; } - -if test "$ac_cv_func_rand48" = "yes" ; then +{ echo "$as_me:$LINENO: result: $ac_cv_lib_gcc___cmpdi2" >&5 +echo "${ECHO_T}$ac_cv_lib_gcc___cmpdi2" >&6; } +if test $ac_cv_lib_gcc___cmpdi2 = yes; then cat >>confdefs.h <<\_ACEOF -#define HAVE_RAND48 1 +#define HAVE___CMPDI2 1 _ACEOF fi +fi { echo "$as_me:$LINENO: checking for isnan in " >&5 @@ -20282,15 +22148,43 @@ fi done +{ echo "$as_me:$LINENO: checking whether llvm-gcc is dragonegg" >&5 +echo $ECHO_N "checking whether llvm-gcc is dragonegg... $ECHO_C" >&6; } +if test "${llvm_cv_llvmgcc_dragonegg+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + llvm_cv_llvmgcc_dragonegg="no" +if test -n "$LLVMGCC" ; then + cp /dev/null conftest.c + $LLVMGCC -fplugin-arg-dragonegg-emit-ir -S -o - conftest.c > /dev/null 2>&1 + if test $? -eq 0 ; then + llvm_cv_llvmgcc_dragonegg="yes" + fi + rm conftest.c +fi +fi +{ echo "$as_me:$LINENO: result: $llvm_cv_llvmgcc_dragonegg" >&5 +echo "${ECHO_T}$llvm_cv_llvmgcc_dragonegg" >&6; } + +if test "$llvm_cv_llvmgcc_dragonegg" = "yes" ; then + LLVMCC_EMITIR_FLAG="-fplugin-arg-dragonegg-emit-ir" + LLVMCC_DISABLEOPT_FLAGS="-fplugin-arg-dragonegg-disable-llvm-optzns" +else + LLVMCC_EMITIR_FLAG="-emit-llvm" + LLVMCC_DISABLEOPT_FLAGS="-mllvm -disable-llvm-optzns" +fi + + + { echo "$as_me:$LINENO: checking whether llvm-gcc is sane" >&5 echo $ECHO_N "checking whether llvm-gcc is sane... $ECHO_C" >&6; } if test "${llvm_cv_llvmgcc_sanity+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else llvm_cv_llvmgcc_sanity="no" -if test -x "$LLVMGCC" ; then +if test -n "$LLVMGCC" ; then cp /dev/null conftest.c - "$LLVMGCC" -emit-llvm -S -o - conftest.c | \ + $LLVMGCC "$LLVMCC_EMITIR_FLAG" -S -o - conftest.c | \ grep 'target datalayout =' > /dev/null 2>&1 if test $? -eq 0 ; then llvm_cv_llvmgcc_sanity="yes" @@ -20304,18 +22198,21 @@ echo "${ECHO_T}$llvm_cv_llvmgcc_sanity" >&6; } if test "$llvm_cv_llvmgcc_sanity" = "yes" ; then { echo "$as_me:$LINENO: checking llvm-gcc component support" >&5 echo $ECHO_N "checking llvm-gcc component support... $ECHO_C" >&6; } - llvmcc1path=`"$LLVMGCC" --print-prog-name=cc1` + llvmcc1path=`$LLVMGCC --print-prog-name=cc1` LLVMCC1=$llvmcc1path - llvmcc1pluspath=`"$LLVMGCC" --print-prog-name=cc1plus` + llvmcc1pluspath=`$LLVMGCC --print-prog-name=cc1plus` LLVMCC1PLUS=$llvmcc1pluspath llvmgccdir=`echo "$llvmcc1path" | sed 's,/libexec/.*,,'` LLVMGCCDIR=$llvmgccdir - llvmgcclangs=`"$LLVMGCC" -v --help 2>&1 | grep '^Configured with:' | sed 's/^.*--enable-languages=\([^ ]*\).*/\1/'` + llvmgcclangs=`$LLVMGCC -v --help 2>&1 | grep '^Configured with:' | sed 's/^.*--enable-languages=\([^ ]*\).*/\1/'` LLVMGCC_LANGS=$llvmgcclangs + LLVMGCC_DRAGONEGG=$llvm_cv_llvmgcc_dragonegg + + { echo "$as_me:$LINENO: result: ok" >&5 echo "${ECHO_T}ok" >&6; } fi @@ -20591,7 +22488,7 @@ ac_config_files="$ac_config_files include/llvm/Config/AsmParsers.def" ac_config_files="$ac_config_files include/llvm/Config/Disassemblers.def" -ac_config_headers="$ac_config_headers include/llvm/System/DataTypes.h" +ac_config_headers="$ac_config_headers include/llvm/Support/DataTypes.h" ac_config_files="$ac_config_files Makefile.config" @@ -21045,7 +22942,7 @@ exec 6>&1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by llvm $as_me 2.8, which was +This file was extended by llvm $as_me 2.9svn, which was generated by GNU Autoconf 2.60. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -21098,7 +22995,7 @@ Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -llvm config.status 2.8 +llvm config.status 2.9svn configured by $0, generated by GNU Autoconf 2.60, with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" @@ -21217,7 +23114,7 @@ do "include/llvm/Config/AsmPrinters.def") CONFIG_FILES="$CONFIG_FILES include/llvm/Config/AsmPrinters.def" ;; "include/llvm/Config/AsmParsers.def") CONFIG_FILES="$CONFIG_FILES include/llvm/Config/AsmParsers.def" ;; "include/llvm/Config/Disassemblers.def") CONFIG_FILES="$CONFIG_FILES include/llvm/Config/Disassemblers.def" ;; - "include/llvm/System/DataTypes.h") CONFIG_HEADERS="$CONFIG_HEADERS include/llvm/System/DataTypes.h" ;; + "include/llvm/Support/DataTypes.h") CONFIG_HEADERS="$CONFIG_HEADERS include/llvm/Support/DataTypes.h" ;; "Makefile.config") CONFIG_FILES="$CONFIG_FILES Makefile.config" ;; "llvm.spec") CONFIG_FILES="$CONFIG_FILES llvm.spec" ;; "tools/llvmc/src/Base.td") CONFIG_FILES="$CONFIG_FILES tools/llvmc/src/Base.td" ;; @@ -21337,6 +23234,8 @@ host_alias!$host_alias$ac_delim target_alias!$target_alias$ac_delim LLVM_COPYRIGHT!$LLVM_COPYRIGHT$ac_delim subdirs!$subdirs$ac_delim +ENABLE_POLLY!$ENABLE_POLLY$ac_delim +LLVM_HAS_POLLY!$LLVM_HAS_POLLY$ac_delim build!$build$ac_delim build_cpu!$build_cpu$ac_delim build_vendor!$build_vendor$ac_delim @@ -21382,19 +23281,17 @@ DEBUG_RUNTIME!$DEBUG_RUNTIME$ac_delim DEBUG_SYMBOLS!$DEBUG_SYMBOLS$ac_delim JIT!$JIT$ac_delim TARGET_HAS_JIT!$TARGET_HAS_JIT$ac_delim +ENABLE_DOCS!$ENABLE_DOCS$ac_delim ENABLE_DOXYGEN!$ENABLE_DOXYGEN$ac_delim ENABLE_THREADS!$ENABLE_THREADS$ac_delim +ENABLE_PTHREADS!$ENABLE_PTHREADS$ac_delim ENABLE_PIC!$ENABLE_PIC$ac_delim ENABLE_SHARED!$ENABLE_SHARED$ac_delim +ENABLE_EMBED_STDCXX!$ENABLE_EMBED_STDCXX$ac_delim ENABLE_TIMESTAMPS!$ENABLE_TIMESTAMPS$ac_delim TARGETS_TO_BUILD!$TARGETS_TO_BUILD$ac_delim LLVM_ENUM_TARGETS!$LLVM_ENUM_TARGETS$ac_delim LLVM_ENUM_ASM_PRINTERS!$LLVM_ENUM_ASM_PRINTERS$ac_delim -LLVM_ENUM_ASM_PARSERS!$LLVM_ENUM_ASM_PARSERS$ac_delim -LLVM_ENUM_DISASSEMBLERS!$LLVM_ENUM_DISASSEMBLERS$ac_delim -ENABLE_CBE_PRINTF_A!$ENABLE_CBE_PRINTF_A$ac_delim -CLANGPATH!$CLANGPATH$ac_delim -CLANGXXPATH!$CLANGXXPATH$ac_delim _ACEOF if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then @@ -21436,6 +23333,11 @@ _ACEOF ac_delim='%!_!# ' for ac_last_try in false false false false false :; do cat >conf$$subs.sed <<_ACEOF +LLVM_ENUM_ASM_PARSERS!$LLVM_ENUM_ASM_PARSERS$ac_delim +LLVM_ENUM_DISASSEMBLERS!$LLVM_ENUM_DISASSEMBLERS$ac_delim +ENABLE_CBE_PRINTF_A!$ENABLE_CBE_PRINTF_A$ac_delim +CLANGPATH!$CLANGPATH$ac_delim +CLANGXXPATH!$CLANGXXPATH$ac_delim ENABLE_BUILT_CLANG!$ENABLE_BUILT_CLANG$ac_delim OPTIMIZE_OPTION!$OPTIMIZE_OPTION$ac_delim EXTRA_OPTIONS!$EXTRA_OPTIONS$ac_delim @@ -21466,6 +23368,7 @@ TWOPI!$TWOPI$ac_delim CIRCO!$CIRCO$ac_delim GV!$GV$ac_delim DOTTY!$DOTTY$ac_delim +XDOT_PY!$XDOT_PY$ac_delim PERL!$PERL$ac_delim HAVE_PERL!$HAVE_PERL$ac_delim INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim @@ -21475,7 +23378,7 @@ BZIP2!$BZIP2$ac_delim CAT!$CAT$ac_delim DOXYGEN!$DOXYGEN$ac_delim GROFF!$GROFF$ac_delim -GZIP!$GZIP$ac_delim +GZIPBIN!$GZIPBIN$ac_delim POD2HTML!$POD2HTML$ac_delim POD2MAN!$POD2MAN$ac_delim PDFROFF!$PDFROFF$ac_delim @@ -21505,10 +23408,13 @@ USE_OPROFILE!$USE_OPROFILE$ac_delim HAVE_PTHREAD!$HAVE_PTHREAD$ac_delim HUGE_VAL_SANITY!$HUGE_VAL_SANITY$ac_delim MMAP_FILE!$MMAP_FILE$ac_delim +LLVMCC_EMITIR_FLAG!$LLVMCC_EMITIR_FLAG$ac_delim LLVMCC1!$LLVMCC1$ac_delim LLVMCC1PLUS!$LLVMCC1PLUS$ac_delim LLVMGCCDIR!$LLVMGCCDIR$ac_delim LLVMGCC_LANGS!$LLVMGCC_LANGS$ac_delim +LLVMGCC_DRAGONEGG!$LLVMGCC_DRAGONEGG$ac_delim +LLVMCC_DISABLEOPT_FLAGS!$LLVMCC_DISABLEOPT_FLAGS$ac_delim SHLIBEXT!$SHLIBEXT$ac_delim SHLIBPATH_VAR!$SHLIBPATH_VAR$ac_delim LLVM_PREFIX!$LLVM_PREFIX$ac_delim @@ -21524,6 +23430,47 @@ LLVM_CONFIGTIME!$LLVM_CONFIGTIME$ac_delim BINDINGS_TO_BUILD!$BINDINGS_TO_BUILD$ac_delim ALL_BINDINGS!$ALL_BINDINGS$ac_delim OCAML_LIBDIR!$OCAML_LIBDIR$ac_delim +_ACEOF + + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then + break + elif $ac_last_try; then + { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` +if test -n "$ac_eof"; then + ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` + ac_eof=`expr $ac_eof + 1` +fi + +cat >>$CONFIG_STATUS <<_ACEOF +cat >"\$tmp/subs-2.sed" <<\CEOF$ac_eof +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +_ACEOF +sed ' +s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g +s/^/s,@/; s/!/@,|#_!!_#|/ +:n +t n +s/'"$ac_delim"'$/,g/; t +s/$/\\/; p +N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n +' >>$CONFIG_STATUS >$CONFIG_STATUS <<_ACEOF +CEOF$ac_eof +_ACEOF + + +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + cat >conf$$subs.sed <<_ACEOF ENABLE_VISIBILITY_INLINES_HIDDEN!$ENABLE_VISIBILITY_INLINES_HIDDEN$ac_delim RPATH!$RPATH$ac_delim RDYNAMIC!$RDYNAMIC$ac_delim @@ -21531,7 +23478,7 @@ LIBOBJS!$LIBOBJS$ac_delim LTLIBOBJS!$LTLIBOBJS$ac_delim _ACEOF - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 93; then + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 5; then break elif $ac_last_try; then { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 @@ -21549,7 +23496,7 @@ if test -n "$ac_eof"; then fi cat >>$CONFIG_STATUS <<_ACEOF -cat >"\$tmp/subs-2.sed" <<\CEOF$ac_eof +cat >"\$tmp/subs-3.sed" <<\CEOF$ac_eof /@[a-zA-Z_][a-zA-Z_0-9]*@/!b end _ACEOF sed ' @@ -21812,7 +23759,7 @@ s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack -" $ac_file_inputs | sed -f "$tmp/subs-1.sed" | sed -f "$tmp/subs-2.sed" >$tmp/out +" $ac_file_inputs | sed -f "$tmp/subs-1.sed" | sed -f "$tmp/subs-2.sed" | sed -f "$tmp/subs-3.sed" >$tmp/out test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && diff --git a/docs/AliasAnalysis.html b/docs/AliasAnalysis.html index cffaa8206228..20b7e96460f3 100644 --- a/docs/AliasAnalysis.html +++ b/docs/AliasAnalysis.html @@ -31,7 +31,7 @@
  • AliasAnalysis chaining behavior
  • Updating analysis results for transformations
  • Efficiency Issues
  • -
  • Pass Manager Issues
  • +
  • Limitations
  • @@ -188,7 +188,8 @@ that the accesses alias.

    The alias method is the primary interface used to determine whether or not two memory objects alias each other. It takes two memory objects as -input and returns MustAlias, MayAlias, or NoAlias as appropriate.

    +input and returns MustAlias, PartialAlias, MayAlias, or NoAlias as +appropriate.

    Like all AliasAnalysis interfaces, the alias method requires that either the two pointer values be defined within the same function, or at @@ -215,8 +216,10 @@ and reallocation.

    dependencies are ignored.

    The MayAlias response is used whenever the two pointers might refer to the -same object. If the two memory objects overlap, but do not start at the same -location, return MayAlias.

    +same object.

    + +

    The PartialAlias response is used when the two memory objects are known +to be overlapping in some way, but do not start at the same address.

    The MustAlias response may only be returned if the two memory objects are guaranteed to always start at exactly the same location. A MustAlias response @@ -461,7 +464,7 @@ analysis results updated to reflect the changes made by these transformations.

    -The AliasAnalysis interface exposes two methods which are used to +The AliasAnalysis interface exposes four methods which are used to communicate program changes from the clients to the analysis implementations. Various alias analysis implementations should use these methods to ensure that their internal data structures are kept up-to-date as the program changes (for @@ -502,6 +505,28 @@ value, then deleting the old value. This method cannot be overridden by alias analysis implementations.

    + +
    The addEscapingUse method
    + +
    +

    The addEscapingUse method is used when the uses of a pointer +value have changed in ways that may invalidate precomputed analysis information. +Implementations may either use this callback to provide conservative responses +for points whose uses have change since analysis time, or may recompute some +or all of their internal state to continue providing accurate responses.

    + +

    In general, any new use of a pointer value is considered an escaping use, +and must be reported through this callback, except for the +uses below:

    + +
      +
    • A bitcast or getelementptr of the pointer
    • +
    • A store through the pointer (but not a store + of the pointer)
    • +
    • A load through the pointer
    • +
    +
    +
    Efficiency Issues @@ -520,13 +545,13 @@ method as possible (within reason).

    -

    PassManager support for alternative AliasAnalysis implementation -has some issues.

    +

    The AliasAnalysis infrastructure has several limitations which make +writing a new AliasAnalysis implementation difficult.

    There is no way to override the default alias analysis. It would be very useful to be able to do something like "opt -my-aa -O2" and @@ -555,6 +580,40 @@ silently route alias analysis queries directly to passes between each pass, which prevents the use of FunctionPass alias analysis passes.

    +

    The AliasAnalysis API does have functions for notifying +implementations when values are deleted or copied, however these +aren't sufficient. There are many other ways that LLVM IR can be +modified which could be relevant to AliasAnalysis +implementations which can not be expressed.

    + +

    The AliasAnalysisDebugger utility seems to suggest that +AliasAnalysis implementations can expect that they will be +informed of any relevant Value before it appears in an +alias query. However, popular clients such as GVN don't +support this, and are known to trigger errors when run with the +AliasAnalysisDebugger.

    + +

    Due to several of the above limitations, the most obvious use for +the AliasAnalysisCounter utility, collecting stats on all +alias queries in a compilation, doesn't work, even if the +AliasAnalysis implementations don't use FunctionPass. +There's no way to set a default, much less a default sequence, +and there's no way to preserve it.

    + +

    The AliasSetTracker class (which is used by LICM +makes a non-deterministic number of alias queries. This can cause stats +collected by AliasAnalysisCounter to have fluctuations among +identical runs, for example. Another consequence is that debugging +techniques involving pausing execution after a predetermined number +of queries can be unreliable.

    + +

    Many alias queries can be reformulated in terms of other alias +queries. When multiple AliasAnalysis queries are chained together, +it would make sense to start those queries from the beginning of the chain, +with care taken to avoid infinite looping, however currently an +implementation which wants to do this can only start such queries +from itself.

    +
    @@ -713,8 +772,8 @@ problem.

    -

    The -basicaa pass is the default LLVM alias analysis. It is an -aggressive local analysis that "knows" many important facts:

    +

    The -basicaa pass is an aggressive local analysis that "knows" +many important facts:

    • Distinct globals, stack allocations, and heap allocations can never @@ -998,7 +1057,7 @@ analysis directly.

      Chris Lattner
      LLVM Compiler Infrastructure
      - Last modified: $Date: 2010-08-31 01:47:24 +0200 (Tue, 31 Aug 2010) $ + Last modified: $Date: 2011-01-03 22:38:41 +0100 (Mon, 03 Jan 2011) $ diff --git a/docs/BitCodeFormat.html b/docs/BitCodeFormat.html index bd53a1edd76c..8d3d382da7a9 100644 --- a/docs/BitCodeFormat.html +++ b/docs/BitCodeFormat.html @@ -922,6 +922,9 @@ encoding of the visibility of this variable:
    • threadlocal: If present and non-zero, indicates that the variable is thread_local
    • +
    • unnamed_addr: If present and non-zero, indicates that the variable +has unnamed_addr
    • +
    @@ -975,6 +978,10 @@ entries.
  • gc: If present and nonzero, the 1-based garbage collector index in the table of MODULE_CODE_GCNAME entries.
  • + +
  • unnamed_addr: If present and non-zero, indicates that the function +has unnamed_addr
  • +
    @@ -1474,7 +1481,7 @@ name. Each entry corresponds to a single named type. src="http://www.w3.org/Icons/valid-html401-blue" alt="Valid HTML 4.01"> Chris Lattner
    The LLVM Compiler Infrastructure
    -Last modified: $Date: 2010-08-28 06:09:24 +0200 (Sat, 28 Aug 2010) $ +Last modified: $Date: 2011-01-08 17:42:36 +0100 (Sat, 08 Jan 2011) $ diff --git a/docs/CMake.html b/docs/CMake.html index ca0b50f628e9..e303d132b590 100644 --- a/docs/CMake.html +++ b/docs/CMake.html @@ -68,7 +68,7 @@
    1. Download - and install CMake. Version 2.6.2 is the minimum required.

      + and install CMake. Version 2.8 is the minimum required.

    2. Open a shell. Your development tools must be reachable from this shell through the PATH environment variable.

      @@ -257,11 +257,41 @@ with a makefile-based system executing make llvm-as on the root of your build directory. +
      LLVM_INCLUDE_TOOLS:BOOL
      +
      Generate build targets for the LLVM tools. Defaults to + ON. You can use that option for disabling the generation of build + targets for the LLVM tools.
      +
      LLVM_BUILD_EXAMPLES:BOOL
      Build LLVM examples. Defaults to OFF. Targets for building each example are generated in any case. See documentation for LLVM_BUILD_TOOLS above for more details.
      +
      LLVM_INCLUDE_EXAMPLES:BOOL
      +
      Generate build targets for the LLVM examples. Defaults to + ON. You can use that option for disabling the generation of build + targets for the LLVM examples.
      + +
      LLVM_BUILD_TESTS:BOOL
      +
      Build LLVM unit tests. Defaults to OFF. Targets for building + each unit test are generated in any case. You can build a specific + unit test with the target UnitTestNameTests (where at this + time UnitTestName can be ADT, Analysis, ExecutionEngine, + JIT, Support, Transform, VMCore; see the subdirectories + of unittests for an updated list.) It is possible to build + all unit tests with the target UnitTests.
      + +
      LLVM_INCLUDE_TESTS:BOOL
      +
      Generate build targets for the LLVM unit tests. Defaults to + ON. You can use that option for disabling the generation of build + targets for the LLVM unit tests.
      + +
      LLVM_APPEND_VC_REV:BOOL
      +
      Append version control revision info (svn revision number or git + revision id) to LLVM version string (stored in the PACKAGE_VERSION + macro). For this to work cmake must be invoked before the + build. Defaults to OFF.
      +
      LLVM_ENABLE_THREADS:BOOL
      Build with threads support, if available. Defaults to ON.
      @@ -301,6 +331,25 @@
      Full path to a native TableGen executable (usually named tblgen). This is intented for cross-compiling: if the user sets this variable, no native TableGen will be created.
      + +
      LLVM_LIT_ARGS:STRING
      +
      Arguments given to lit. + make check and make clang-test are affected. + By default, "-sv --no-progress-bar" + on Visual C++ and Xcode, + "-sv" on others.
      + +
      LLVM_LIT_TOOLS_DIR:STRING
      +
      The path to GnuWin32 tools for tests. Valid on Windows host. + Defaults to "", then Lit seeks tools according to %PATH%. + Lit can find tools(eg. grep, sort, &c) on LLVM_LIT_TOOLS_DIR at first, + without specifying GnuWin32 to %PATH%.
      + +
      LLVM_ENABLE_FFI:BOOL
      +
      Indicates whether LLVM Interpreter will be linked with Foreign + Function Interface library. If the library or its headers are + installed on a custom location, you can set the variables + FFI_INCLUDE_DIR and FFI_LIBRARY_DIR. Defaults to OFF.
      @@ -321,7 +370,7 @@

      make check

      -

      Testing is not supported on Visual Studio.

      +

      On Visual Studio, you may run tests to build the project "check".

      diff --git a/docs/CodeGenerator.html b/docs/CodeGenerator.html index 4b2e261094bd..925156ff0787 100644 --- a/docs/CodeGenerator.html +++ b/docs/CodeGenerator.html @@ -5,6 +5,17 @@ The LLVM Target-Independent Code Generator + + + @@ -33,7 +44,7 @@
    3. The TargetJITInfo class
    4. -
    5. Machine code description classes +
    6. The "Machine" Code Generator classes
    7. +
    8. The "MC" Layer + +
    9. Target-independent code generation algorithms
    10. -
    11. Code Emission -
    12. +
    13. Code Emission
    14. +
    15. Implementing a Native Assembler
    16. +
    17. Target-specific Implementation Notes
    -

    Written by Chris Lattner, - Bill Wendling, - Fernando Magno Quintao - Pereira and - Jim Laskey

    +

    Written by the LLVM Team.

    @@ -123,7 +138,7 @@ suite of reusable components for translating the LLVM internal representation to the machine code for a specified target—either in assembly form (suitable for a static compiler) or in binary machine code format (usable for - a JIT compiler). The LLVM target-independent code generator consists of five + a JIT compiler). The LLVM target-independent code generator consists of six main components:

      @@ -132,10 +147,17 @@ independently of how they will be used. These interfaces are defined in include/llvm/Target/. -
    1. Classes used to represent the machine code - being generated for a target. These classes are intended to be abstract +
    2. Classes used to represent the code being + generated for a target. These classes are intended to be abstract enough to represent the machine code for any target machine. These - classes are defined in include/llvm/CodeGen/.
    3. + classes are defined in include/llvm/CodeGen/. At this level, + concepts like "constant pool entries" and "jump tables" are explicitly + exposed. + +
    4. Classes and algorithms used to represent code as the object file level, + the MC Layer. These classes represent assembly level + constructs like labels, sections, and instructions. At this level, + concepts like "constant pool entries" and "jump tables" don't exist.
    5. Target-independent algorithms used to implement various phases of native code generation (register allocation, scheduling, @@ -732,6 +754,157 @@ ret
    + + + + + +
    + +

    +The MC Layer is used to represent and process code at the raw machine code +level, devoid of "high level" information like "constant pools", "jump tables", +"global variables" or anything like that. At this level, LLVM handles things +like label names, machine instructions, and sections in the object file. The +code in this layer is used for a number of important purposes: the tail end of +the code generator uses it to write a .s or .o file, and it is also used by the +llvm-mc tool to implement standalone machine codeassemblers and disassemblers. +

    + +

    +This section describes some of the important classes. There are also a number +of important subsystems that interact at this layer, they are described later +in this manual. +

    + +
    + + + + + +
    + +

    +MCStreamer is best thought of as an assembler API. It is an abstract API which +is implemented in different ways (e.g. to output a .s file, output an +ELF .o file, etc) but whose API correspond directly to what you see in a .s +file. MCStreamer has one method per directive, such as EmitLabel, +EmitSymbolAttribute, SwitchSection, EmitValue (for .byte, .word), etc, which +directly correspond to assembly level directives. It also has an +EmitInstruction method, which is used to output an MCInst to the streamer. +

    + +

    +This API is most important for two clients: the llvm-mc stand-alone assembler is +effectively a parser that parses a line, then invokes a method on MCStreamer. In +the code generator, the Code Emission phase of the code +generator lowers higher level LLVM IR and Machine* constructs down to the MC +layer, emitting directives through MCStreamer.

    + +

    +On the implementation side of MCStreamer, there are two major implementations: +one for writing out a .s file (MCAsmStreamer), and one for writing out a .o +file (MCObjectStreamer). MCAsmStreamer is a straight-forward implementation +that prints out a directive for each method (e.g. EmitValue -> .byte), but +MCObjectStreamer implements a full assembler. +

    + +
    + + + + +
    + +

    +The MCContext class is the owner of a variety of uniqued data structures at the +MC layer, including symbols, sections, etc. As such, this is the class that you +interact with to create symbols and sections. This class can not be subclassed. +

    + +
    + + + + +
    + +

    +The MCSymbol class represents a symbol (aka label) in the assembly file. There +are two interesting kinds of symbols: assembler temporary symbols, and normal +symbols. Assembler temporary symbols are used and processed by the assembler +but are discarded when the object file is produced. The distinction is usually +represented by adding a prefix to the label, for example "L" labels are +assembler temporary labels in MachO. +

    + +

    MCSymbols are created by MCContext and uniqued there. This means that +MCSymbols can be compared for pointer equivalence to find out if they are the +same symbol. Note that pointer inequality does not guarantee the labels will +end up at different addresses though. It's perfectly legal to output something +like this to the .s file:

    + +

    +  foo:
    +  bar:
    +    .byte 4
    +
    + +

    In this case, both the foo and bar symbols will have the same address.

    + +
    + + + + +
    + +

    +The MCSection class represents an object-file specific section. It is subclassed +by object file specific implementations (e.g. MCSectionMachO, +MCSectionCOFF, MCSectionELF) and these are created and uniqued +by MCContext. The MCStreamer has a notion of the current section, which can be +changed with the SwitchToSection method (which corresponds to a ".section" +directive in a .s file). +

    + +
    + + + + +
    + +

    +The MCInst class is a target-independent representation of an instruction. It +is a simple class (much more so than MachineInstr) +that holds a target-specific opcode and a vector of MCOperands. MCOperand, in +turn, is a simple discriminated union of three cases: 1) a simple immediate, +2) a target register ID, 3) a symbolic expression (e.g. "Lfoo-Lbar+42") as an +MCExpr. +

    + +

    MCInst is the common currency used to represent machine instructions at the +MC layer. It is the type used by the instruction encoder, the instruction +printer, and the type generated by the assembly parser and disassembler. +

    + +
    + +
    Target-independent code generation algorithms @@ -857,9 +1030,9 @@ ret SelectionDAG optimizer is run to clean up redundancies exposed by type legalization. -
  • Legalize SelectionDAG Types — - This stage transforms SelectionDAG nodes to eliminate any types that are - unsupported on the target.
  • +
  • Legalize SelectionDAG Ops — + This stage transforms SelectionDAG nodes to eliminate any operations + that are unsupported on the target.
  • Optimize SelectionDAG — The SelectionDAG optimizer is run to eliminate inefficiencies introduced by @@ -1386,18 +1559,25 @@ bool RegMapping_Fer::compatible_class(MachineFunction &mf,

    Virtual registers are also denoted by integer numbers. Contrary to physical - registers, different virtual registers never share the same number. The - smallest virtual register is normally assigned the number 1024. This may - change, so, in order to know which is the first virtual register, you should - access TargetRegisterInfo::FirstVirtualRegister. Any register whose - number is greater than or equal - to TargetRegisterInfo::FirstVirtualRegister is considered a virtual - register. Whereas physical registers are statically defined in - a TargetRegisterInfo.td file and cannot be created by the - application developer, that is not the case with virtual registers. In order - to create new virtual registers, use the + registers, different virtual registers never share the same number. Whereas + physical registers are statically defined in a TargetRegisterInfo.td + file and cannot be created by the application developer, that is not the case + with virtual registers. In order to create new virtual registers, use the method MachineRegisterInfo::createVirtualRegister(). This method - will return a virtual register with the highest code.

    + will return a new virtual register. Use an IndexedMap<Foo, + VirtReg2IndexFunctor> to hold information per virtual register. If you + need to enumerate all virtual registers, use the function + TargetRegisterInfo::index2VirtReg() to find the virtual register + numbers:

    + +
    +
    +  for (unsigned i = 0, e = MRI->getNumVirtRegs(); i != e; ++i) {
    +    unsigned VirtReg = TargetRegisterInfo::index2VirtReg(i);
    +    stuff(VirtReg);
    +  }
    +
    +

    Before register allocation, the operands of an instruction are mostly virtual registers, although physical registers may also be used. In order to check if @@ -1635,25 +1815,228 @@ $ llc -regalloc=pbqp file.bc -o pbqp.s; Late Machine Code Optimizations

  • To Be Written

    + -

    To Be Written

    - -
    - Generating Assembly Code + +
    + +

    The code emission step of code generation is responsible for lowering from +the code generator abstractions (like MachineFunction, MachineInstr, etc) down +to the abstractions used by the MC layer (MCInst, +MCStreamer, etc). This is +done with a combination of several different classes: the (misnamed) +target-independent AsmPrinter class, target-specific subclasses of AsmPrinter +(such as SparcAsmPrinter), and the TargetLoweringObjectFile class.

    + +

    Since the MC layer works at the level of abstraction of object files, it +doesn't have a notion of functions, global variables etc. Instead, it thinks +about labels, directives, and instructions. A key class used at this time is +the MCStreamer class. This is an abstract API that is implemented in different +ways (e.g. to output a .s file, output an ELF .o file, etc) that is effectively +an "assembler API". MCStreamer has one method per directive, such as EmitLabel, +EmitSymbolAttribute, SwitchSection, etc, which directly correspond to assembly +level directives. +

    + +

    If you are interested in implementing a code generator for a target, there +are three important things that you have to implement for your target:

    + +
      +
    1. First, you need a subclass of AsmPrinter for your target. This class +implements the general lowering process converting MachineFunction's into MC +label constructs. The AsmPrinter base class provides a number of useful methods +and routines, and also allows you to override the lowering process in some +important ways. You should get much of the lowering for free if you are +implementing an ELF, COFF, or MachO target, because the TargetLoweringObjectFile +class implements much of the common logic.
    2. + +
    3. Second, you need to implement an instruction printer for your target. The +instruction printer takes an MCInst and renders it to a +raw_ostream as text. Most of this is automatically generated from the .td file +(when you specify something like "add $dst, $src1, $src2" in the +instructions), but you need to implement routines to print operands.
    4. + +
    5. Third, you need to implement code that lowers a MachineInstr to an MCInst, usually implemented in +"<target>MCInstLower.cpp". This lowering process is often target +specific, and is responsible for turning jump table entries, constant pool +indices, global variable addresses, etc into MCLabels as appropriate. This +translation layer is also responsible for expanding pseudo ops used by the code +generator into the actual machine instructions they correspond to. The MCInsts +that are generated by this are fed into the instruction printer or the encoder. +
    6. + +
    + +

    Finally, at your choosing, you can also implement an subclass of +MCCodeEmitter which lowers MCInst's into machine code bytes and relocations. +This is important if you want to support direct .o file emission, or would like +to implement an assembler for your target.

    +
    + + + + + + +
    + +

    Though you're probably reading this because you want to write or maintain a +compiler backend, LLVM also fully supports building a native assemblers too. +We've tried hard to automate the generation of the assembler from the .td files +(in particular the instruction syntax and encodings), which means that a large +part of the manual and repetitive data entry can be factored and shared with the +compiler.

    + +
    + + +
    Instruction Parsing
    +

    To Be Written

    + + + +
    + Instruction Alias Processing +
    + +
    +

    Once the instruction is parsed, it enters the MatchInstructionImpl function. +The MatchInstructionImpl function performs alias processing and then does +actual matching.

    + +

    Alias processing is the phase that canonicalizes different lexical forms of +the same instructions down to one representation. There are several different +kinds of alias that are possible to implement and they are listed below in the +order that they are processed (which is in order from simplest/weakest to most +complex/powerful). Generally you want to use the first alias mechanism that +meets the needs of your instruction, because it will allow a more concise +description.

    + +
    + -
    - Generating Binary Machine Code +
    Mnemonic Aliases
    + +
    + +

    The first phase of alias processing is simple instruction mnemonic +remapping for classes of instructions which are allowed with two different +mnemonics. This phase is a simple and unconditionally remapping from one input +mnemonic to one output mnemonic. It isn't possible for this form of alias to +look at the operands at all, so the remapping must apply for all forms of a +given mnemonic. Mnemonic aliases are defined simply, for example X86 has: +

    + +
    +
    +def : MnemonicAlias<"cbw",     "cbtw">;
    +def : MnemonicAlias<"smovq",   "movsq">;
    +def : MnemonicAlias<"fldcww",  "fldcw">;
    +def : MnemonicAlias<"fucompi", "fucomip">;
    +def : MnemonicAlias<"ud2a",    "ud2">;
    +
    +
    + +

    ... and many others. With a MnemonicAlias definition, the mnemonic is +remapped simply and directly. Though MnemonicAlias's can't look at any aspect +of the instruction (such as the operands) they can depend on global modes (the +same ones supported by the matcher), through a Requires clause:

    + +
    +
    +def : MnemonicAlias<"pushf", "pushfq">, Requires<[In64BitMode]>;
    +def : MnemonicAlias<"pushf", "pushfl">, Requires<[In32BitMode]>;
    +
    +

    In this example, the mnemonic gets mapped into different a new one depending +on the current instruction set.

    + +
    + + +
    Instruction Aliases
    +
    -

    For the JIT or .o file writer

    + +

    The most general phase of alias processing occurs while matching is +happening: it provides new forms for the matcher to match along with a specific +instruction to generate. An instruction alias has two parts: the string to +match and the instruction to generate. For example: +

    + +
    +
    +def : InstAlias<"movsx $src, $dst", (MOVSX16rr8W GR16:$dst, GR8  :$src)>;
    +def : InstAlias<"movsx $src, $dst", (MOVSX16rm8W GR16:$dst, i8mem:$src)>;
    +def : InstAlias<"movsx $src, $dst", (MOVSX32rr8  GR32:$dst, GR8  :$src)>;
    +def : InstAlias<"movsx $src, $dst", (MOVSX32rr16 GR32:$dst, GR16 :$src)>;
    +def : InstAlias<"movsx $src, $dst", (MOVSX64rr8  GR64:$dst, GR8  :$src)>;
    +def : InstAlias<"movsx $src, $dst", (MOVSX64rr16 GR64:$dst, GR16 :$src)>;
    +def : InstAlias<"movsx $src, $dst", (MOVSX64rr32 GR64:$dst, GR32 :$src)>;
    +
    +

    This shows a powerful example of the instruction aliases, matching the +same mnemonic in multiple different ways depending on what operands are present +in the assembly. The result of instruction aliases can include operands in a +different order than the destination instruction, and can use an input +multiple times, for example:

    + +
    +
    +def : InstAlias<"clrb $reg", (XOR8rr  GR8 :$reg, GR8 :$reg)>;
    +def : InstAlias<"clrw $reg", (XOR16rr GR16:$reg, GR16:$reg)>;
    +def : InstAlias<"clrl $reg", (XOR32rr GR32:$reg, GR32:$reg)>;
    +def : InstAlias<"clrq $reg", (XOR64rr GR64:$reg, GR64:$reg)>;
    +
    +
    + +

    This example also shows that tied operands are only listed once. In the X86 +backend, XOR8rr has two input GR8's and one output GR8 (where an input is tied +to the output). InstAliases take a flattened operand list without duplicates +for tied operands. The result of an instruction alias can also use immediates +and fixed physical registers which are added as simple immediate operands in the +result, for example:

    + +
    +
    +// Fixed Immediate operand.
    +def : InstAlias<"aad", (AAD8i8 10)>;
    +
    +// Fixed register operand.
    +def : InstAlias<"fcomi", (COM_FIr ST1)>;
    +
    +// Simple alias.
    +def : InstAlias<"fcomi $reg", (COM_FIr RST:$reg)>;
    +
    +
    + + +

    Instruction aliases can also have a Requires clause to make them +subtarget specific.

    + +
    + + + + +
    Instruction Matching
    + +

    To Be Written

    + + +
    @@ -1664,10 +2047,275 @@ $ llc -regalloc=pbqp file.bc -o pbqp.s;

    This section of the document explains features or design decisions that are - specific to the code generator for a particular target.

    + specific to the code generator for a particular target. First we start + with a table that summarizes what features are supported by each target.

    + +
    + + + + +
    + +

    Note that this table does not include the C backend or Cpp backends, since +they do not use the target independent code generator infrastructure. It also +doesn't list features that are not supported fully by any target yet. It +considers a feature to be supported if at least one subtarget supports it. A +feature being supported means that it is useful and works for most cases, it +does not indicate that there are zero known bugs in the implementation. Here +is the key:

    + + + + + + + + + + + + + + + +
    UnknownNo supportPartial SupportComplete Support
    + +

    Here is the table:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Target
    FeatureARMAlphaBlackfinCellSPUMBlazeMSP430MipsPTXPowerPCSparcSystemZX86XCore
    is generally reliable
    assembly parser
    disassembler
    inline asm *
    jit*
    .o file writing
    tail calls
    + +
    + + +
    Is Generally Reliable
    + +
    +

    This box indicates whether the target is considered to be production quality. +This indicates that the target has been used as a static compiler to +compile large amounts of code by a variety of different people and is in +continuous use.

    +
    + + +
    Assembly Parser
    + +
    +

    This box indicates whether the target supports parsing target specific .s +files by implementing the MCAsmParser interface. This is required for llvm-mc +to be able to act as a native assembler and is required for inline assembly +support in the native .o file writer.

    + + +
    Disassembler
    + +
    +

    This box indicates whether the target supports the MCDisassembler API for +disassembling machine opcode bytes into MCInst's.

    + +
    + + +
    Inline Asm
    + +
    +

    This box indicates whether the target supports most popular inline assembly +constraints and modifiers.

    + +

    X86 lacks reliable support for inline assembly +constraints relating to the X86 floating point stack.

    + +
    + + +
    JIT Support
    + +
    +

    This box indicates whether the target supports the JIT compiler through +the ExecutionEngine interface.

    + +

    The ARM backend has basic support for integer code +in ARM codegen mode, but lacks NEON and full Thumb support.

    + +
    + + +
    .o File Writing
    + +
    + +

    This box indicates whether the target supports writing .o files (e.g. MachO, +ELF, and/or COFF) files directly from the target. Note that the target also +must include an assembly parser and general inline assembly support for full +inline assembly support in the .o writer.

    + +

    Targets that don't support this feature can obviously still write out .o +files, they just rely on having an external assembler to translate from a .s +file to a .o file (as is the case for many C compilers).

    + +
    + + +
    Tail Calls
    + +
    + +

    This box indicates whether the target supports guaranteed tail calls. These +are calls marked "tail" and use the fastcc +calling convention. Please see the tail call section +more more details.

    + +
    + + + +
    Tail call optimization @@ -2162,7 +2810,7 @@ MOVSX32rm16 -> movsx, 32-bit register, 16-bit memory Chris Lattner
    The LLVM Compiler Infrastructure
    - Last modified: $Date: 2010-09-01 00:01:07 +0200 (Wed, 01 Sep 2010) $ + Last modified: $Date: 2011-01-09 00:10:59 +0100 (Sun, 09 Jan 2011) $ diff --git a/docs/CodingStandards.html b/docs/CodingStandards.html index bb88a91772aa..4a9ab7d857a8 100644 --- a/docs/CodingStandards.html +++ b/docs/CodingStandards.html @@ -29,37 +29,39 @@
  • Treat Compiler Warnings Like Errors
  • Write Portable Code
  • -
  • Use of class/struct Keywords
  • +
  • Do not use RTTI or Exceptions
  • +
  • Use of class/struct Keywords
  • Style Issues
      -
    1. The High Level Issues +
    2. The High-Level Issues
      1. A Public Header File is a Module
      2. -
      3. #include as Little as Possible
      4. +
      5. #include as Little as Possible
      6. Keep "internal" Headers Private
      7. -
      8. Use Early Exits and 'continue' to Simplify +
      9. Use Early Exits and continue to Simplify Code
      10. -
      11. Don't use "else" after a - return
      12. +
      13. Don't use else after a + return
      14. Turn Predicate Loops into Predicate Functions
    3. -
    4. The Low Level Issues +
    5. The Low-Level Issues
        +
      1. Name Types, Functions, Variables, and Enumerators Properly
      2. Assert Liberally
      3. -
      4. Do not use 'using namespace std'
      5. +
      6. Do not use 'using namespace std'
      7. Provide a virtual method anchor for classes in headers
      8. -
      9. Don't evaluate end() every time through a +
      10. Don't evaluate end() every time through a loop
      11. #include <iostream> is forbidden
      12. +
      13. Use raw_ostream
      14. Avoid std::endl
      15. -
      16. Use raw_ostream
    6. Microscopic Details @@ -167,8 +169,8 @@ this:

      A few things to note about this particular format: The "-*- C++ -*-" string on the first line is there to tell Emacs that the source file -is a C++ file, not a C file (Emacs assumes .h files are C files by default). -Note that this tag is not necessary in .cpp files. The name of the file is also +is a C++ file, not a C file (Emacs assumes .h files are C files by default). +Note that this tag is not necessary in .cpp files. The name of the file is also on the first line, along with a very short description of the purpose of the file. This is important when printing out code and flipping though lots of pages.

      @@ -217,7 +219,7 @@ require less typing, don't have nesting problems, etc. There are a few cases when it is useful to use C style (/* */) comments however:

        -
      1. When writing a C code: Obviously if you are writing C code, use C style +
      2. When writing C code: Obviously if you are writing C code, use C style comments.
      3. When writing a header file that may be #included by a C source file.
      4. @@ -244,12 +246,12 @@ file should be listed. We prefer these #includes to be listed in this order:

          -
        1. Main Module header
        2. +
        3. Main Module Header
        4. Local/Private Headers
        5. llvm/*
        6. llvm/Analysis/*
        7. llvm/Assembly/*
        8. -
        9. llvm/Bytecode/*
        10. +
        11. llvm/Bitcode/*
        12. llvm/CodeGen/*
        13. ...
        14. Support/*
        15. @@ -257,15 +259,15 @@ order:

        16. System #includes
        -

        ... and each category should be sorted by name.

        +

        and each category should be sorted by name.

        -

        The "Main Module Header" file applies to .cpp file -which implement an interface defined by a .h file. This #include +

        The "Main Module Header" file applies to .cpp files +which implement an interface defined by a .h file. This #include should always be included first regardless of where it lives on the file -system. By including a header file first in the .cpp files that implement the +system. By including a header file first in the .cpp files that implement the interfaces, we ensure that the header does not have any hidden dependencies which are not explicitly #included in the header, but should be. It is also a -form of documentation in the .cpp file to indicate where the interfaces it +form of documentation in the .cpp file to indicate where the interfaces it implements are defined.

  • @@ -290,7 +292,7 @@ value and would be detrimental to printing out code. Also many other projects have standardized on 80 columns, so some people have already configured their editors for it (vs something else, like 90 columns).

    -

    This is one of many contentious issues in coding standards, but is not up +

    This is one of many contentious issues in coding standards, but it is not up for debate.

    @@ -304,12 +306,12 @@ for debate.

    In all cases, prefer spaces to tabs in source files. People have different preferred indentation levels, and different styles of indentation that they -like... this is fine. What isn't is that different editors/viewers expand tabs -out to different tab stops. This can cause your code to look completely +like; this is fine. What isn't fine is that different editors/viewers expand +tabs out to different tab stops. This can cause your code to look completely unreadable, and it is not worth dealing with.

    As always, follow the Golden Rule above: follow the -style of existing code if your are modifying and extending it. If you like four +style of existing code if you are modifying and extending it. If you like four spaces of indentation, DO NOT do that in the middle of a chunk of code with two spaces of indentation. Also, do not reindent a whole source file: it makes for incredible diffs that are absolutely worthless.

    @@ -323,7 +325,7 @@ makes for incredible diffs that are absolutely worthless.

    -

    Okay, your first year of programming you were told that indentation is +

    Okay, in your first year of programming you were told that indentation is important. If you didn't believe and internalize this then, now is the time. Just do it.

    @@ -343,17 +345,17 @@ Just do it.

    -

    If your code has compiler warnings in it, something is wrong: you aren't -casting values correctly, your have "questionable" constructs in your code, or -you are doing something legitimately wrong. Compiler warnings can cover up -legitimate errors in output and make dealing with a translation unit +

    If your code has compiler warnings in it, something is wrong — you +aren't casting values correctly, your have "questionable" constructs in your +code, or you are doing something legitimately wrong. Compiler warnings can +cover up legitimate errors in output and make dealing with a translation unit difficult.

    It is not possible to prevent all warnings from all compilers, nor is it desirable. Instead, pick a standard compiler (like gcc) that provides -a good thorough set of warnings, and stick to them. At least in the case of +a good thorough set of warnings, and stick to it. At least in the case of gcc, it is possible to work around any spurious errors by changing the -syntax of the code slightly. For example, an warning that annoys me occurs when +syntax of the code slightly. For example, a warning that annoys me occurs when I write code like this:

    @@ -377,11 +379,16 @@ if ((V = getValue())) {
    -

    ...which shuts gcc up. Any gcc warning that annoys you can +

    which shuts gcc up. Any gcc warning that annoys you can be fixed by massaging the code appropriately.

    -

    These are the gcc warnings that I prefer to enable: -Wall --Winline -W -Wwrite-strings -Wno-unused

    +

    These are the gcc warnings that I prefer to enable:

    + +
    +
    +-Wall -Winline -W -Wwrite-strings -Wno-unused
    +
    +
    @@ -397,9 +404,31 @@ portable code. If there are cases where it isn't possible to write portable code, isolate it behind a well defined (and well documented) interface.

    In practice, this means that you shouldn't assume much about the host -compiler, including its support for "high tech" features like partial -specialization of templates. If these features are used, they should only be -an implementation detail of a library which has a simple exposed API.

    +compiler, and Visual Studio tends to be the lowest common denominator. +If advanced features are used, they should only be an implementation detail of +a library which has a simple exposed API, and preferably be buried in +libSystem.

    + +
    + + + +
    + +

    In an effort to reduce code and executable size, LLVM does not use RTTI +(e.g. dynamic_cast<>) or exceptions. These two language features +violate the general C++ principle of "you only pay for what you use", +causing executable bloat even if exceptions are never used in the code base, or +if RTTI is never used for a class. Because of this, we turn them off globally +in the code.

    + +

    That said, LLVM does make extensive use of a hand-rolled form of RTTI that +use templates like isa<>, +cast<>, and dyn_cast<>. This form of RTTI is +opt-in and can be added to any class. It is also substantially more efficient +than dynamic_cast<>.

    @@ -419,8 +448,9 @@ different symbols based on whether class or struct was used to declare the symbol. This can lead to problems at link time.

    So, the rule for LLVM is to always use the class keyword, unless -all members are public and the type is a C++ "POD" type, in which case -struct is allowed.

    +all members are public and the type is a C++ +POD type, in +which case struct is allowed.

    @@ -433,7 +463,7 @@ declare the symbol. This can lead to problems at link time.

    @@ -448,20 +478,20 @@ declare the symbol. This can lead to problems at link time.

    C++ doesn't do too well in the modularity department. There is no real encapsulation or data hiding (unless you use expensive protocol classes), but it is what we have to work with. When you write a public header file (in the LLVM -source tree, they live in the top level "include" directory), you are defining a -module of functionality.

    +source tree, they live in the top level "include" directory), you are +defining a module of functionality.

    Ideally, modules should be completely independent of each other, and their -header files should only include the absolute minimum number of headers -possible. A module is not just a class, a function, or a namespace: it's a collection -of these that defines an interface. This interface may be several -functions, classes or data structures, but the important issue is how they work -together.

    - -

    In general, a module should be implemented with one or more .cpp +header files should only #include the absolute minimum number of +headers possible. A module is not just a class, a function, or a +namespace: it's +a collection of these that defines an interface. This interface may be +several functions, classes, or data structures, but the important issue is how +they work together.

    + +

    In general, a module should be implemented by one or more .cpp files. Each of these .cpp files should include the header that defines -their interface first. This ensure that all of the dependences of the module +their interface first. This ensures that all of the dependences of the module header have been properly added to the module header itself, and are not implicit. System headers should be included after user headers for a translation unit.

    @@ -478,29 +508,28 @@ translation unit.

    #include hurts compile time performance. Don't do it unless you have to, especially in header files.

    -

    But wait, sometimes you need to have the definition of a class to use it, or +

    But wait! Sometimes you need to have the definition of a class to use it, or to inherit from it. In these cases go ahead and #include that header file. Be aware however that there are many cases where you don't need to have the full definition of a class. If you are using a pointer or reference to a class, you don't need the header file. If you are simply returning a class instance from a prototyped function or method, you don't need it. In fact, for -most cases, you simply don't need the definition of a class... and not +most cases, you simply don't need the definition of a class. And not #include'ing speeds up compilation.

    It is easy to try to go too overboard on this recommendation, however. You -must include all of the header files that you are using -- you can -include them either directly -or indirectly (through another header file). To make sure that you don't -accidentally forget to include a header file in your module header, make sure to -include your module header first in the implementation file (as mentioned -above). This way there won't be any hidden dependencies that you'll find out -about later...

    +must include all of the header files that you are using — you can +include them either directly or indirectly (through another header file). To +make sure that you don't accidentally forget to include a header file in your +module header, make sure to include your module header first in the +implementation file (as mentioned above). This way there won't be any hidden +dependencies that you'll find out about later.

    @@ -508,20 +537,20 @@ about later...

    Many modules have a complex implementation that causes them to use more than one implementation (.cpp) file. It is often tempting to put the internal communication interface (helper classes, extra functions, etc) in the -public module header file. Don't do this.

    +public module header file. Don't do this!

    If you really need to do something like this, put a private header file in the same directory as the source files, and include it locally. This ensures that your private interface remains private and undisturbed by outsiders.

    -

    Note however, that it's okay to put extra implementation methods a public -class itself... just make them private (or protected), and all is well.

    +

    Note however, that it's okay to put extra implementation methods in a public +class itself. Just make them private (or protected) and all is well.

    @@ -530,8 +559,8 @@ class itself... just make them private (or protected), and all is well.

    decisions have to be remembered by the reader to understand a block of code. Aim to reduce indentation where possible when it doesn't make it more difficult to understand the code. One great way to do this is by making use of early -exits and the 'continue' keyword in long loops. As an example of using an early -exit from a function, consider this "bad" code:

    +exits and the continue keyword in long loops. As an example of using +an early exit from a function, consider this "bad" code:

    @@ -546,23 +575,23 @@ Value *DoSomething(Instruction *I) {
     
    -

    This code has several problems if the body of the 'if' is large. When you're -looking at the top of the function, it isn't immediately clear that this -only does interesting things with non-terminator instructions, and only -applies to things with the other predicates. Second, it is relatively difficult -to describe (in comments) why these predicates are important because the if -statement makes it difficult to lay out the comments. Third, when you're deep -within the body of the code, it is indented an extra level. Finally, when -reading the top of the function, it isn't clear what the result is if the -predicate isn't true, you have to read to the end of the function to know that -it returns null.

    +

    This code has several problems if the body of the 'if' is large. +When you're looking at the top of the function, it isn't immediately clear that +this only does interesting things with non-terminator instructions, and +only applies to things with the other predicates. Second, it is relatively +difficult to describe (in comments) why these predicates are important because +the if statement makes it difficult to lay out the comments. Third, +when you're deep within the body of the code, it is indented an extra level. +Finally, when reading the top of the function, it isn't clear what the result is +if the predicate isn't true; you have to read to the end of the function to know +that it returns null.

    It is much preferred to format the code like this:

     Value *DoSomething(Instruction *I) {
    -  // Terminators never need 'something' done to them because, ... 
    +  // Terminators never need 'something' done to them because ... 
       if (isa<TerminatorInst>(I))
         return 0;
     
    @@ -580,7 +609,7 @@ Value *DoSomething(Instruction *I) {
     
    -

    This fixes these problems. A similar problem frequently happens in for +

    This fixes these problems. A similar problem frequently happens in for loops. A silly example is something like this:

    @@ -597,14 +626,13 @@ loops. A silly example is something like this:

    -

    When you have very very small loops, this sort of structure is fine, but if +

    When you have very, very small loops, this sort of structure is fine. But if it exceeds more than 10-15 lines, it becomes difficult for people to read and -understand at a glance. -The problem with this sort of code is that it gets very nested very quickly, -meaning that the reader of the code has to keep a lot of context in their brain -to remember what is going immediately on in the loop, because they don't know -if/when the if conditions will have elses etc. It is strongly preferred to -structure the loop like this:

    +understand at a glance. The problem with this sort of code is that it gets very +nested very quickly. Meaning that the reader of the code has to keep a lot of +context in their brain to remember what is going immediately on in the loop, +because they don't know if/when the if conditions will have elses etc. +It is strongly preferred to structure the loop like this:

    @@ -615,30 +643,32 @@ structure the loop like this:

    Value *LHS = BO->getOperand(0); Value *RHS = BO->getOperand(1); if (LHS == RHS) continue; + + ... }
    -

    This has all the benefits of using early exits from functions: it reduces +

    This has all the benefits of using early exits for functions: it reduces nesting of the loop, it makes it easier to describe why the conditions are true, -and it makes it obvious to the reader that there is no "else" coming up that -they have to push context into their brain for. If a loop is large, this can -be a big understandability win.

    +and it makes it obvious to the reader that there is no else coming up +that they have to push context into their brain for. If a loop is large, this +can be a big understandability win.

    For similar reasons above (reduction of indentation and easier reading), - please do not use "else" or "else if" after something that interrupts - control flow like return, break, continue, goto, etc. For example, this is - "bad":

    - +please do not use 'else' or 'else if' after something that +interrupts control flow — like return, break, +continue, goto, etc. For example, this is bad:

    +
       case 'J': {
    @@ -647,24 +677,24 @@ be a big understandability win.

    if (Type.isNull()) { Error = ASTContext::GE_Missing_sigjmp_buf; return QualType(); - } else { + } else { break; - } + } } else { Type = Context.getjmp_bufType(); if (Type.isNull()) { Error = ASTContext::GE_Missing_jmp_buf; return QualType(); - } else { + } else { break; - } + } } } }
    -

    It is better to write this something like:

    +

    It is better to write it like this:

    @@ -682,11 +712,11 @@ be a big understandability win.

    return QualType(); } } - break; + break;
    -

    Or better yet (in this case), as:

    +

    Or better yet (in this case) as:

    @@ -701,12 +731,12 @@ be a big understandability win.

    ASTContext::GE_Missing_jmp_buf; return QualType(); } - break; + break;

    The idea is to reduce indentation and the amount of code you have to keep - track of when reading the code.

    +track of when reading the code.

    @@ -717,9 +747,9 @@ be a big understandability win.

    -

    It is very common to write small loops that just compute a boolean - value. There are a number of ways that people commonly write these, but an - example of this sort of thing is:

    +

    It is very common to write small loops that just compute a boolean value. +There are a number of ways that people commonly write these, but an example of +this sort of thing is:

    @@ -740,9 +770,7 @@ be a big understandability win.

    Instead of this sort of loop, we strongly prefer to use a predicate function (which may be static) that uses early exits to compute the predicate. We prefer -the code to be structured like this: -

    - +the code to be structured like this:

    @@ -777,11 +805,94 @@ locality.

    + + + +
    + +

    Poorly-chosen names can mislead the reader and cause bugs. We cannot stress +enough how important it is to use descriptive names. Pick names that +match the semantics and role of the underlying entities, within reason. Avoid +abbreviations unless they are well known. After picking a good name, make sure +to use consistent capitalization for the name, as inconsistency requires clients +to either memorize the APIs or to look it up to find the exact spelling.

    + +

    In general, names should be in camel case (e.g. TextFileReader +and isLValue()). Different kinds of declarations have different +rules:

    + +
      +
    • Type names (including classes, structs, enums, typedefs, etc) + should be nouns and start with an upper-case letter (e.g. + TextFileReader).

    • + +
    • Function names should be verb phrases (as they represent + actions), and command-like function should be imperative. The name should + be camel case, and start with a lower case letter (e.g. openFile() + or isFoo()).

    • + +
    • Enum declarations (e.g. enum Foo {...}) are types, so + they should follow the naming conventions for types. A common use for enums + is as a discriminator for a union, or an indicator of a subclass. When an + enum is used for something like this, it should have a Kind suffix + (e.g. ValueKind).

    • + +
    • Enumerators (e.g. enum { Foo, Bar }) and public member + variables should start with an upper-case letter, just like types. + Unless the enumerators are defined in their own small namespace or inside a + class, enumerators should have a prefix corresponding to the enum + declaration name. For example, enum ValueKind { ... }; may contain + enumerators like VK_Argument, VK_BasicBlock, etc. + Enumerators that are just convenience constants are exempt from the + requirement for a prefix. For instance:

      + +
      +
      +enum {
      +  MaxSize = 42,
      +  Density = 12
      +};
      +
      +
      +
    • + +
    + +

    As an exception, classes that mimic STL classes can have member names in +STL's style of lower-case words separated by underscores (e.g. begin(), +push_back(), and empty()).

    + +

    Here are some examples of good and bad names:

    + +
    +
    +class VehicleMaker {
    +  ...
    +  Factory<Tire> F;            // Bad -- abbreviation and non-descriptive.
    +  Factory<Tire> Factory;      // Better.
    +  Factory<Tire> TireFactory;  // Even better -- if VehicleMaker has more than one
    +                              // kind of factories.
    +};
    +
    +Vehicle MakeVehicle(VehicleType Type) {
    +  VehicleMaker M;                         // Might be OK if having a short life-span.
    +  Tire tmp1 = M.makeTire();               // Bad -- 'tmp1' provides no information.
    +  Light headlight = M.makeLight("head");  // Good -- descriptive.
    +  ...
    +}
    +
    +
    + +
    + +
    Assert Liberally @@ -789,7 +900,7 @@ locality.

    -

    Use the "assert" function to its fullest. Check all of your +

    Use the "assert" macro to its fullest. Check all of your preconditions and assumptions, you never know when a bug (not necessarily even yours) might be caught early by an assertion, which reduces debugging time dramatically. The "<cassert>" header file is probably already @@ -797,8 +908,8 @@ included by the header files you are using, so it doesn't cost anything to use it.

    To further assist with debugging, make sure to put some kind of error message -in the assertion statement (which is printed if the assertion is tripped). This -helps the poor debugging make sense of why an assertion is being made and +in the assertion statement, which is printed if the assertion is tripped. This +helps the poor debugger make sense of why an assertion is being made and enforced, and hopefully what to do about it. Here is one complete example:

    @@ -810,7 +921,7 @@ inline Value *getOperand(unsigned i) {
    -

    Here are some examples:

    +

    Here are more examples:

    @@ -826,9 +937,9 @@ assert(isa<PHINode>(Succ->front()) && "Only works on PHId BBs!"
     
    -

    You get the idea...

    +

    You get the idea.

    -

    Please be aware when adding assert statements that not all compilers are aware of +

    Please be aware that, when adding assert statements, not all compilers are aware of the semantics of the assert. In some places, asserts are used to indicate a piece of code that should not be reached. These are typically of the form:

    @@ -851,14 +962,47 @@ return 0;
    +

    Another issue is that values used only by assertions will produce an "unused +value" warning when assertions are disabled. For example, this code will +warn:

    + +
    +
    +unsigned Size = V.size();
    +assert(Size > 42 && "Vector smaller than it should be");
    +
    +bool NewToSet = Myset.insert(Value);
    +assert(NewToSet && "The value shouldn't be in the set yet");
    +
    +
    + +

    These are two interesting different cases. In the first case, the call to +V.size() is only useful for the assert, and we don't want it executed when +assertions are disabled. Code like this should move the call into the assert +itself. In the second case, the side effects of the call must happen whether +the assert is enabled or not. In this case, the value should be cast to void to +disable the warning. To be specific, it is preferred to write the code like +this:

    + +
    +
    +assert(V.size() > 42 && "Vector smaller than it should be");
    +
    +bool NewToSet = Myset.insert(Value); (void)NewToSet;
    +assert(NewToSet && "The value shouldn't be in the set yet");
    +
    +
    + +
    +

    In LLVM, we prefer to explicitly prefix all identifiers from the standard namespace with an "std::" prefix, rather than rely on "using namespace std;".

    @@ -867,10 +1011,10 @@ namespace with an "std::" prefix, rather than rely on the namespace of any source file that #includes the header. This is clearly a bad thing.

    -

    In implementation files (e.g. .cpp files), the rule is more of a stylistic +

    In implementation files (e.g. .cpp files), the rule is more of a stylistic rule, but is still important. Basically, using explicit namespace prefixes makes the code clearer, because it is immediately obvious what facilities -are being used and where they are coming from, and more portable, because +are being used and where they are coming from. And more portable, because namespace clashes cannot occur between LLVM code and other namespaces. The portability rule is important because different standard library implementations expose different symbols (potentially ones they shouldn't), and future revisions @@ -880,18 +1024,20 @@ such, we never use 'using namespace std;' in LLVM.

    The exception to the general rule (i.e. it's not an exception for the std namespace) is for implementation files. For example, all of the code in the LLVM project implements code that lives in the 'llvm' namespace. -As such, it is ok, and actually clearer, for the .cpp files to have a 'using -namespace llvm' directive at their top, after the #includes. The -general form of this rule is that any .cpp file that implements code in any -namespace may use that namespace (and its parents'), but should not use any -others.

    +As such, it is ok, and actually clearer, for the .cpp files to have a +'using namespace llvm;' directive at the top, after the +#includes. This reduces indentation in the body of the file for source +editors that indent based on braces, and keeps the conceptual context cleaner. +The general form of this rule is that any .cpp file that implements +code in any namespace may use that namespace (and its parents'), but should not +use any others.

    @@ -907,15 +1053,16 @@ increasing link times.

    -

    Because C++ doesn't have a standard "foreach" loop (though it can be emulated -with macros and may be coming in C++'0x) we end up writing a lot of loops that -manually iterate from begin to end on a variety of containers or through other -data structures. One common mistake is to write a loop in this style:

    +

    Because C++ doesn't have a standard "foreach" loop (though it can be +emulated with macros and may be coming in C++'0x) we end up writing a lot of +loops that manually iterate from begin to end on a variety of containers or +through other data structures. One common mistake is to write a loop in this +style:

    @@ -946,10 +1093,10 @@ behavior, please write the loop in the first form and add a comment indicating
     that you did it intentionally.

    Why do we prefer the second form (when correct)? Writing the loop in the -first form has two problems: First it may be less efficient than evaluating it -at the start of the loop. In this case, the cost is probably minor: a few extra -loads every time through the loop. However, if the base expression is more -complex, then the cost can rise quickly. I've seen loops where the end +first form has two problems. First it may be less efficient than evaluating it +at the start of the loop. In this case, the cost is probably minor — a +few extra loads every time through the loop. However, if the base expression is +more complex, then the cost can rise quickly. I've seen loops where the end expression was actually something like: "SomeMap[x]->end()" and map lookups really aren't cheap. By writing it in the second form consistently, you eliminate the issue entirely and don't even have to think about it.

    @@ -968,7 +1115,7 @@ prefer it.

    @@ -977,12 +1124,13 @@ prefer it.

    hereby forbidden. The primary reason for doing this is to support clients using LLVM libraries as part of larger systems. In particular, we statically link LLVM into some dynamic libraries. Even if LLVM isn't used, -the static c'tors are run whenever an application start up that uses the dynamic -library. There are two problems with this:

    +the static constructors are run whenever an application starts up that uses the +dynamic library. There are two problems with this:

      -
    1. The time to run the static c'tors impacts startup time of - applications—a critical time for GUI apps.
    2. +
    3. The time to run the static c'tors impacts startup time of applications + — a critical time for GUI apps.
    4. +
    5. The static c'tors cause the app to pull many extra pages of memory off the disk: both the code for the static c'tors in each .o file and the small amount of data that gets touched. In addition, touched/dirty pages @@ -990,12 +1138,10 @@ library. There are two problems with this:

    Note that using the other stream headers (<sstream> for -example) is not problematic in this regard (just <iostream>). -However, raw_ostream provides various APIs that are better performing for almost -every use than std::ostream style APIs, so you should just use it for new -code.

    - -

    New code should always +example) is not problematic in this regard — +just <iostream>. However, raw_ostream provides various +APIs that are better performing for almost every use than std::ostream +style APIs. Therefore new code should always use raw_ostream for writing, or the llvm::MemoryBuffer API for reading files.

    @@ -1004,44 +1150,44 @@ the llvm::MemoryBuffer API for reading files.

    -

    The std::endl modifier, when used with iostreams outputs a newline -to the output stream specified. In addition to doing this, however, it also -flushes the output stream. In other words, these are equivalent:

    - -
    -
    -std::cout << std::endl;
    -std::cout << '\n' << std::flush;
    -
    -
    +

    LLVM includes a lightweight, simple, and efficient stream implementation +in llvm/Support/raw_ostream.h, which provides all of the common +features of std::ostream. All new code should use raw_ostream +instead of ostream.

    -

    Most of the time, you probably have no reason to flush the output stream, so -it's better to use a literal '\n'.

    +

    Unlike std::ostream, raw_ostream is not a template and can +be forward declared as class raw_ostream. Public headers should +generally not include the raw_ostream header, but use forward +declarations and constant references to raw_ostream instances.

    -

    LLVM includes a lightweight, simple, and efficient stream implementation -in llvm/Support/raw_ostream.h which provides all of the common features -of std::ostream. All new code should use raw_ostream instead -of ostream.

    +

    The std::endl modifier, when used with iostreams outputs a +newline to the output stream specified. In addition to doing this, however, it +also flushes the output stream. In other words, these are equivalent:

    -

    Unlike std::ostream, raw_ostream is not a template and can -be forward declared as class raw_ostream. Public headers should -generally not include the raw_ostream header, but use forward -declarations and constant references to raw_ostream instances.

    +
    +
    +std::cout << std::endl;
    +std::cout << '\n' << std::flush;
    +
    +
    + +

    Most of the time, you probably have no reason to flush the output stream, so +it's better to use a literal '\n'.

    @@ -1062,54 +1208,54 @@ reasoning on why we prefer them.

    -

    We prefer to put a space before a parentheses only in control flow +

    We prefer to put a space before an open parenthesis only in control flow statements, but not in normal function call expressions and function-like macros. For example, this is good:

    -  if (x) ...
    -  for (i = 0; i != 100; ++i) ...
    -  while (llvm_rocks) ...
    +if (x) ...
    +for (i = 0; i != 100; ++i) ...
    +while (llvm_rocks) ...
     
    -  somefunc(42);
    -  assert(3 != 4 && "laws of math are failing me");
    +somefunc(42);
    +assert(3 != 4 && "laws of math are failing me");
       
    -  a = foo(42, 92) + bar(x);
    -  
    +a = foo(42, 92) + bar(x); +
    -

    ... and this is bad:

    +

    and this is bad:

    -  if(x) ...
    -  for(i = 0; i != 100; ++i) ...
    -  while(llvm_rocks) ...
    +if(x) ...
    +for(i = 0; i != 100; ++i) ...
    +while(llvm_rocks) ...
     
    -  somefunc (42);
    -  assert (3 != 4 && "laws of math are failing me");
    +somefunc (42);
    +assert (3 != 4 && "laws of math are failing me");
       
    -  a = foo (42, 92) + bar (x);
    +a = foo (42, 92) + bar (x);
     

    The reason for doing this is not completely arbitrary. This style makes - control flow operators stand out more, and makes expressions flow better. The - function call operator binds very tightly as a postfix operator. Putting - a space after a function name (as in the last example) makes it appear that - the code might bind the arguments of the left-hand-side of a binary operator - with the argument list of a function and the name of the right side. More - specifically, it is easy to misread the "a" example as:

    +control flow operators stand out more, and makes expressions flow better. The +function call operator binds very tightly as a postfix operator. Putting a +space after a function name (as in the last example) makes it appear that the +code might bind the arguments of the left-hand-side of a binary operator with +the argument list of a function and the name of the right side. More +specifically, it is easy to misread the "a" example as:

    -  a = foo ((42, 92) + bar) (x);
    +a = foo ((42, 92) + bar) (x);
     
    -

    ... when skimming through the code. By avoiding a space in a function, we -avoid this misinterpretation.

    +

    when skimming through the code. By avoiding a space in a function, we avoid +this misinterpretation.

    @@ -1141,7 +1287,7 @@ get in the habit of always using preincrement, and you won't have a problem.

    -In general, we strive to reduce indentation where ever possible. This is useful +In general, we strive to reduce indentation wherever possible. This is useful because we want code to fit into 80 columns without wrapping horribly, but also because it makes it easier to understand the code. Namespaces are a funny thing: they are often large, and we often desire to put @@ -1186,7 +1332,7 @@ namespace llvm {

    Since the body is small, indenting adds value because it makes it very clear where the namespace starts and ends, and it is easy to take the whole thing in in one "gulp" when reading the code. If the blob of code in the namespace is -larger (as it typically is in a header in the llvm or clang namespaces), do not +larger (as it typically is in a header in the llvm or clang namespaces), do not indent the code, and add a comment indicating what namespace is being closed. For example:

    @@ -1346,7 +1492,7 @@ something.

    Chris Lattner
    LLVM Compiler Infrastructure
    - Last modified: $Date: 2010-05-07 02:28:04 +0200 (Fri, 07 May 2010) $ + Last modified: $Date: 2011-02-20 03:03:04 +0100 (Sun, 20 Feb 2011) $ diff --git a/docs/CommandGuide/FileCheck.pod b/docs/CommandGuide/FileCheck.pod index 433979a87190..3ccaa63e176b 100644 --- a/docs/CommandGuide/FileCheck.pod +++ b/docs/CommandGuide/FileCheck.pod @@ -133,7 +133,7 @@ both 32-bit and 64-bit code generation. =head2 The "CHECK-NEXT:" directive Sometimes you want to match lines and would like to verify that matches -happen on exactly consequtive lines with no other lines in between them. In +happen on exactly consecutive lines with no other lines in between them. In this case, you can use CHECK: and CHECK-NEXT: directives to specify this. If you specified a custom check prefix, just use "-NEXT:". For example, something like this works as you'd expect: @@ -165,7 +165,7 @@ directive in a file. =head2 The "CHECK-NOT:" directive The CHECK-NOT: directive is used to verify that a string doesn't occur -between two matches (or the first match and the beginning of the file). For +between two matches (or before the first match, or after the last match). For example, to verify that a load is removed by a transformation, a test like this can be used: diff --git a/docs/CommandGuide/index.html b/docs/CommandGuide/index.html index 67f0cfc1a110..3c1a9f9ed4f0 100644 --- a/docs/CommandGuide/index.html +++ b/docs/CommandGuide/index.html @@ -151,7 +151,7 @@ options) arguments to the tool you are interested in.

    src="http://www.w3.org/Icons/valid-html401-blue" alt="Valid HTML 4.01"> LLVM Compiler Infrastructure
    - Last modified: $Date: 2010-09-08 01:32:02 +0200 (Wed, 08 Sep 2010) $ + Last modified: $Date: 2010-09-08 01:10:21 +0200 (Wed, 08 Sep 2010) $ diff --git a/docs/CommandGuide/llc.pod b/docs/CommandGuide/llc.pod index ac24aab4ff6b..eb26ec00fd76 100644 --- a/docs/CommandGuide/llc.pod +++ b/docs/CommandGuide/llc.pod @@ -84,6 +84,14 @@ Disable optimizations that may produce excess precision for floating point. Note that this option can dramatically slow down code on some systems (e.g. X86). +=item B<--enable-no-infs-fp-math> + +Enable optimizations that assume no Inf values. + +=item B<--enable-no-nans-fp-math> + +Enable optimizations that assume no NAN values. + =item B<--enable-unsafe-fp-math> Enable optimizations that make unsafe assumptions about IEEE math (e.g. that diff --git a/docs/CommandGuide/lli.pod b/docs/CommandGuide/lli.pod index d368bec8660a..52a2721e7d70 100644 --- a/docs/CommandGuide/lli.pod +++ b/docs/CommandGuide/lli.pod @@ -102,10 +102,13 @@ B /dev/null | llc -march=xyz -mattr=help> Disable optimizations that may increase floating point precision. -=item B<-enable-finite-only-fp-math> +=item B<-enable-no-infs-fp-math> -Enable optimizations that assumes only finite floating point math. That is, -there is no NAN or Inf values. +Enable optimizations that assume no Inf values. + +=item B<-enable-no-nans-fp-math> + +Enable optimizations that assume no NAN values. =item B<-enable-unsafe-fp-math> diff --git a/docs/DeveloperPolicy.html b/docs/DeveloperPolicy.html index 47352009ea04..ef99ebc9d412 100644 --- a/docs/DeveloperPolicy.html +++ b/docs/DeveloperPolicy.html @@ -29,7 +29,6 @@
  • Copyright
  • License
  • Patents
  • -
  • Developer Agreements
  • Written by the LLVM Oversight Team
    @@ -196,7 +195,11 @@
    1. Evan Cheng: Code generator and all targets.
    2. -
    3. Doug Gregor: Clang Basic, Lex, Parse, and Sema Libraries.
    4. +
    5. Greg Clayton: LLDB.
    6. + +
    7. Doug Gregor: Clang Frontend Libraries.
    8. + +
    9. Howard Hinnant: libc++.
    10. Anton Korobeynikov: Exception handling, debug information, and Windows codegen.
    11. @@ -506,40 +509,40 @@ Changes
    -

    For consistency and ease of management, the project requires the copyright - for all LLVM software to be held by a single copyright holder: the University - of Illinois (UIUC).

    - -

    Although UIUC may eventually reassign the copyright of the software to - another entity (e.g. a dedicated non-profit "LLVM Organization") the intent - for the project is to always have a single entity hold the copyrights to LLVM - at any given time.

    - -

    We believe that having a single copyright holder is in the best interests of - all developers and users as it greatly reduces the managerial burden for any - kind of administrative or technical decisions about LLVM. The goal of the - LLVM project is to always keep the code open and licensed - under a very liberal license.

    + +

    The LLVM project does not require copyright assignments, which means that the + copyright for the code in the project is held by its respective contributors + who have each agreed to release their contributed code under the terms of the + LLVM License.

    + +

    An implication of this is that the LLVM license is unlikely to ever change: + changing it would require tracking down all the contributors to LLVM and + getting them to agree that a license change is acceptable for their + contribution. Since there are no plans to change the license, this is not a + cause for concern.

    + +

    As a contributor to the project, this means that you (or your company) retain + ownership of the code you contribute, that it cannot be used in a way that + contradicts the license (which is a liberal BSD-style license), and that the + license for your contributions won't change without your approval in the + future.

    +

    We intend to keep LLVM perpetually open source and to use a liberal open - source license. The current license is the + source license. All of the code in LLVM is available under the University of Illinois/NCSA Open Source License, which boils down to this:

    • You can freely distribute LLVM.
    • -
    • You must retain the copyright notice if you redistribute LLVM.
    • - -
    • Binaries derived from LLVM must reproduce the copyright notice (e.g. in - an included readme file).
    • - +
    • Binaries derived from LLVM must reproduce the copyright notice (e.g. in an + included readme file).
    • You can't use our names to promote your LLVM derived products.
    • -
    • There's no warranty on LLVM at all.
    @@ -549,7 +552,22 @@ Changes
    LLVM's license is not a "copyleft" license like the GPL). We suggest that you read the License if further clarification is needed.

    - + +

    In addition to the UIUC license, the runtime library components of LLVM + (compiler_rt and libc++) are also licensed under the MIT license, + which does not contain the binary redistribution clause. As a user of these + runtime libraries, it means that you can choose to use the code under either + license (and thus don't need the binary redistribution clause), and as a + contributor to the code that you agree that any contributions to these + libraries be licensed under both licenses. We feel that this is important + for runtime libraries, because they are implicitly linked into applications + and therefore should not subject those applications to the binary + redistribution clause. This also means that it is ok to move code from (e.g.) + libc++ to the LLVM core without concern, but that code cannot be moved from + the LLVM core to libc++ without the copyright owner's permission. +

    +

    Note that the LLVM Project does distribute llvm-gcc, which is GPL. This means that anything "linked" into llvm-gcc must itself be compatible with the GPL, and must be releasable under the terms of the GPL. This @@ -563,7 +581,7 @@ Changes

    We have no plans to change the license of LLVM. If you have questions or comments about the license, please contact the - LLVM Oversight Group.

    + LLVM Developer's Mailing List.

    @@ -584,21 +602,6 @@ Changes details.

    - - -
    -

    With regards to the LLVM copyright and licensing, developers agree to assign - their copyrights to UIUC for any contribution made so that the entire - software base can be managed by a single copyright holder. This implies that - any contributions can be licensed under the license that the project - uses.

    - -

    When contributing code, you also affirm that you are legally entitled to - grant this copyright, personally or on behalf of your employer. If the code - belongs to some other entity, please raise this issue with the oversight - group before the code is committed.

    -
    -
    @@ -609,7 +612,7 @@ Changes Written by the LLVM Oversight Group
    The LLVM Compiler Infrastructure
    - Last modified: $Date: 2010-09-02 02:09:17 +0200 (Thu, 02 Sep 2010) $ + Last modified: $Date: 2010-11-16 22:32:53 +0100 (Tue, 16 Nov 2010) $
    diff --git a/docs/ExceptionHandling.html b/docs/ExceptionHandling.html index d324c15390cd..009dbb5abd53 100644 --- a/docs/ExceptionHandling.html +++ b/docs/ExceptionHandling.html @@ -40,6 +40,7 @@
  • llvm.eh.sjlj.longjmp
  • llvm.eh.sjlj.lsda
  • llvm.eh.sjlj.callsite
  • +
  • llvm.eh.sjlj.dispatchsetup
  • Asm Table Formats
      @@ -419,7 +420,7 @@
      -  i32 %llvm.eh.selector(i8*, i8*, i8*, ...)
      +  i32 %llvm.eh.selector(i8*, i8*, ...)
       

      This intrinsic is used to compare the exception with the given type infos, @@ -547,6 +548,23 @@

      + + + +
      + +
      +  void %llvm.eh.sjlj.dispatchsetup(i32)
      +
      + +

      For SJLJ based exception handling, the + llvm.eh.sjlj.dispatchsetup intrinsic is used by targets to do + any unwind-edge setup they need. By default, no action is taken.

      + +
      +
      Asm Table Formats @@ -619,7 +637,7 @@ Chris Lattner
      LLVM Compiler Infrastructure
      - Last modified: $Date: 2010-05-28 19:07:41 +0200 (Fri, 28 May 2010) $ + Last modified: $Date: 2010-12-10 00:05:48 +0100 (Fri, 10 Dec 2010) $ diff --git a/docs/GetElementPtr.html b/docs/GetElementPtr.html index d840c9788ac1..5410137861ff 100644 --- a/docs/GetElementPtr.html +++ b/docs/GetElementPtr.html @@ -598,13 +598,27 @@ idx3 = (char*) &MyVar + 8 What happens if a GEP computation overflows?
      -

      If the GEP has the inbounds keyword, the result value is - undefined.

      - -

      Otherwise, the result value is the result from evaluating the implied - two's complement integer computation. However, since there's no - guarantee of where an object will be allocated in the address space, - such values have limited meaning.

      +

      If the GEP lacks the inbounds keyword, the value is the result + from evaluating the implied two's complement integer computation. However, + since there's no guarantee of where an object will be allocated in the + address space, such values have limited meaning.

      + +

      If the GEP has the inbounds keyword, the result value is + undefined (a "trap value") if the GEP + overflows (i.e. wraps around the end of the address space).

      + +

      As such, there are some ramifications of this for inbounds GEPs: scales + implied by array/vector/pointer indices are always known to be "nsw" since + they are signed values that are scaled by the element size. These values + are also allowed to be negative (e.g. "gep i32 *%P, i32 -1") but the + pointer itself is logically treated as an unsigned value. This means that + GEPs have an asymmetric relation between the pointer base (which is treated + as unsigned) and the offset applied to it (which is treated as signed). The + result of the additions within the offset calculation cannot have signed + overflow, but when applied to the base pointer, there can be signed + overflow. +

      +
      @@ -719,7 +733,7 @@ idx3 = (char*) &MyVar + 8 Valid HTML 4.01 The LLVM Compiler Infrastructure
      - Last modified: $Date: 2010-08-28 06:09:24 +0200 (Sat, 28 Aug 2010) $ + Last modified: $Date: 2011-02-11 22:50:52 +0100 (Fri, 11 Feb 2011) $ diff --git a/docs/GettingStarted.html b/docs/GettingStarted.html index 7c105fea8d11..dfb976a29f1e 100644 --- a/docs/GettingStarted.html +++ b/docs/GettingStarted.html @@ -28,6 +28,7 @@
    1. Setting Up Your Environment
    2. Unpacking the LLVM Archives
    3. Checkout LLVM from Subversion
    4. +
    5. LLVM GIT mirror
    6. Install the GCC Front End
    7. Local LLVM Configuration
    8. Compiling the LLVM Suite Source Code
    9. @@ -44,10 +45,9 @@
    10. llvm/projects
    11. llvm/runtime
    12. llvm/test
    13. -
    14. llvm-test
    15. +
    16. test-suite
    17. llvm/tools
    18. llvm/utils
    19. -
    20. llvm/win32
  • An Example Using the LLVM Tool Chain @@ -80,11 +80,12 @@

    Welcome to LLVM! In order to get started, you first need to know some basic information.

    -

    First, LLVM comes in two pieces. The first piece is the LLVM suite. This -contains all of the tools, libraries, and header files needed to use the low -level virtual machine. It contains an assembler, disassembler, bitcode -analyzer and bitcode optimizer. It also contains a test suite that can be -used to test the LLVM tools and the GCC front end.

    +

    First, LLVM comes in three pieces. The first piece is the LLVM +suite. This contains all of the tools, libraries, and header files +needed to use the low level virtual machine. It contains an +assembler, disassembler, bitcode analyzer and bitcode optimizer. It +also contains basic regression tests that can be used to test the LLVM +tools and the GCC front end.

    The second piece is the GCC front end. This component provides a version of GCC that compiles C and C++ code into LLVM bitcode. Currently, the GCC front @@ -93,7 +94,7 @@ compiled into LLVM bitcode, a program can be manipulated with the LLVM tools from the LLVM suite.

    -There is a third, optional piece called llvm-test. It is a suite of programs +There is a third, optional piece called Test Suite. It is a suite of programs with a testing harness that can be used to further test LLVM's functionality and performance.

    @@ -142,6 +143,7 @@ and performance.
  • cd where-you-want-llvm-to-live
  • cd llvm/projects
  • gunzip --stdout llvm-test-version.tar.gz | tar -xvf - +
  • mv llvm-test-version test-suite
  • @@ -162,7 +164,7 @@ and performance.

    Optionally, specify for directory the full pathname of the C/C++ front end installation to use with this LLVM configuration. If not specified, the PATH will be searched. This is only needed if you - want to run the testsuite or do some special kinds of LLVM builds.

    + want to run test-suite or do some special kinds of LLVM builds.

  • --enable-spec2000=directory

    Enable the SPEC2000 benchmarks for testing. The SPEC2000 benchmarks should be available in @@ -242,6 +244,11 @@ software you will need.

    x861 GCC + + FreeBSD + amd64 + GCC + MacOS X2 PowerPC @@ -564,6 +571,9 @@ as the previous one. It appears to work with ENABLE_OPTIMIZED=0 (the default).GCC 4.3.3 (Debian 4.3.3-10) on ARM: Miscompiles parts of LLVM 2.6 when optimizations are turned on. The symptom is an infinite loop in FoldingSetImpl::RemoveNode while running the code generator.

    +

    GCC 4.3.5 and GCC 4.4.5 on ARM: These can miscompile value >> +1 even at -O0. A test failure in test/Assembler/alignstack.ll is +one symptom of the problem.

    GNU ld 2.16.X. Some 2.16.X versions of the ld linker will produce very long warning messages complaining that some ".gnu.linkonce.t.*" symbol was defined in a discarded section. You can safely ignore these messages as they are @@ -684,7 +694,7 @@ compressed with the gzip program.

    Source release for the LLVM libraries and tools.
    llvm-test-x.y.tar.gz
    -
    Source release for the LLVM test suite.
    +
    Source release for the LLVM test-suite.
    llvm-gcc-4.2-x.y.source.tar.gz
    Source release of the llvm-gcc-4.2 front end. See README.LLVM in the root @@ -726,6 +736,8 @@ revision), you can checkout it from the 'tags' directory (instead of subdirectories of the 'tags' directory:

      +
    • Release 2.8: RELEASE_28
    • +
    • Release 2.7: RELEASE_27
    • Release 2.6: RELEASE_26
    • Release 2.5: RELEASE_25
    • Release 2.4: RELEASE_24
    • @@ -751,7 +763,7 @@ you get it from the Subversion repository:

       % cd llvm/projects
      -% svn co http://llvm.org/svn/llvm-project/test-suite/trunk llvm-test
      +% svn co http://llvm.org/svn/llvm-project/test-suite/trunk test-suite
       
      @@ -765,6 +777,25 @@ instructions to successfully get and build the LLVM GCC front-end.

      + + + +
      + +

      GIT mirrors are available for a number of LLVM subprojects. These mirrors + sync automatically with each Subversion commit and contain all necessary + git-svn marks (so, you can recreate git-svn metadata locally). Note that right + now mirrors reflect only trunk for each project. You can do the + read-only GIT clone of LLVM via: +

      +% git clone http://llvm.org/git/llvm.git
      +
      +

      + +
      +
      Install the GCC Front End @@ -774,7 +805,7 @@ instructions to successfully get and build the LLVM GCC front-end.

      Before configuring and compiling the LLVM suite (or if you want to use just the LLVM GCC front end) you can optionally extract the front end from the binary distribution. -It is used for running the llvm-test testsuite and for compiling C/C++ programs. Note that +It is used for running the LLVM test-suite and for compiling C/C++ programs. Note that you can optionally build llvm-gcc yourself after building the main LLVM repository.

      @@ -795,9 +826,9 @@ to your PATH environment variable. For example, if you uncompressed th

      If you now want to build LLVM from source, when you configure LLVM, it will automatically detect llvm-gcc's presence (if it is in your path) enabling its -use in llvm-test. Note that you can always build or install llvm-gcc at any +use in test-suite. Note that you can always build or install llvm-gcc at any point after building the main LLVM repository: just reconfigure llvm and -llvm-test will pick it up. +test-suite will pick it up.

      As a convenience for Windows users, the front end binaries for MinGW/x86 include @@ -1348,7 +1379,7 @@ end to compile.

      - +

      This is not a directory in the normal llvm module; it is a separate Subversion @@ -1408,7 +1439,7 @@ information is in the Command Guide.

      llvm-ld
      llvm-ld is a general purpose and extensible linker for LLVM. - This is the linker invoked by llvmc. It performsn standard link time + This is the linker invoked by llvmc. It performs standard link time optimizations and allows optimization modules to be loaded and run so that language specific optimizations can be applied at link time.
      @@ -1511,15 +1542,6 @@ are code generators for parts of LLVM infrastructure.

      - - -
      -

      This directory contains build scripts and project files for use with - Visual C++. This allows developers on Windows to build LLVM without the need - for Cygwin. The contents of this directory should be considered experimental - at this time. -

      -
      An Example Using the LLVM Tool Chain @@ -1673,7 +1695,7 @@ out:

      Chris Lattner
      Reid Spencer
      The LLVM Compiler Infrastructure
      - Last modified: $Date: 2010-07-08 10:27:18 +0200 (Thu, 08 Jul 2010) $ + Last modified: $Date: 2011-02-01 21:08:28 +0100 (Tue, 01 Feb 2011) $ diff --git a/docs/GettingStartedVS.html b/docs/GettingStartedVS.html index e467e087c587..b6aa4c692d43 100644 --- a/docs/GettingStartedVS.html +++ b/docs/GettingStartedVS.html @@ -14,26 +14,19 @@
      -

      Written by: +

      Written by: Jeff Cohen

      @@ -47,26 +40,30 @@
      -

      The Visual Studio port at this time is experimental. It is suitable for - use only if you are writing your own compiler front end or otherwise have a - need to dynamically generate machine code. The JIT and interpreter are - functional, but it is currently not possible to generate assembly code which - is then assembled into an executable. You can indirectly create executables - by using the C back end.

      - -

      To emphasize, there is no C/C++ front end currently available. - llvm-gcc is based on GCC, which cannot be bootstrapped using VC++. - Eventually there should be a llvm-gcc based on Cygwin or MinGW that - is usable. There is also the option of generating bitcode files on Unix and - copying them over to Windows. But be aware the odds of linking C++ code - compiled with llvm-gcc with code compiled with VC++ is essentially - zero.

      - -

      The LLVM test suite cannot be run on the Visual Studio port at this +

      Welcome to LLVM on Windows! This document only covers LLVM on Windows using + Visual Studio, not mingw or cygwin. In order to get started, you first need to + know some basic information.

      + +

      There are many different projects that compose LLVM. The first is the LLVM + suite. This contains all of the tools, libraries, and header files needed to + use the low level virtual machine. It contains an assembler, disassembler, + bitcode analyzer and bitcode optimizer. It also contains a test suite that can + be used to test the LLVM tools.

      + +

      Another useful project on Windows is + clang. Clang is a C family + ([Objective]C/C++) compiler. Clang mostly works on Windows, but does not + currently understand all of the Microsoft extensions to C and C++. Because of + this, clang cannot parse the C++ standard library included with Visual Studio, + nor parts of the Windows Platform SDK. However, most standard C programs do + compile. Clang can be used to emit bitcode, directly emit object files or + even linked executables using Visual Studio's link.exe

      + +

      The large LLVM test suite cannot be run on the Visual Studio port at this time.

      Most of the tools build and work. bugpoint does build, but does - not work. The other tools 'should' work, but have not been fully tested.

      + not work.

      Additional information about the LLVM directory structure and tool chain can be found on the main Getting Started @@ -74,89 +71,6 @@

      - - - - -
      - -

      Here's the short story for getting up and running quickly with LLVM:

      - -
        -
      1. Read the documentation.
      2. -
      3. Seriously, read the documentation.
      4. -
      5. Remember that you were warned twice about reading the documentation.
      6. - -
      7. Get the Source Code -
          -
        • With the distributed files: -
            -
          1. cd where-you-want-llvm-to-live -
          2. gunzip --stdout llvm-version.tar.gz | tar -xvf - -       or use WinZip -
          3. cd llvm
          4. -
        • - -
        • With anonymous Subversion access: -
            -
          1. cd where-you-want-llvm-to-live
          2. -
          3. svn co http://llvm.org/svn/llvm-project/llvm-top/trunk llvm-top -
          4. -
          5. make checkout MODULE=llvm -
          6. cd llvm
          7. -
        • -
      8. - -
      9. Use CMake to generate up-to-date - project files: -
        • This step is currently optional as LLVM does still come with a - normal Visual Studio solution file, but it is not always kept up-to-date - and will soon be deprecated in favor of the multi-platform generator - CMake.
        • -
        • If CMake is installed then the most simple way is to just start the - CMake GUI, select the directory where you have LLVM extracted to, and - the default options should all be fine. The one option you may really - want to change, regardless of anything else, might be the - CMAKE_INSTALL_PREFIX setting to select a directory to INSTALL to once - compiling is complete.
        • -
        • If you use CMake to generate the Visual Studio solution and project - files, then the Solution will have a few extra options compared to the - current included one. The projects may still be built individually, but - to build them all do not just select all of them in batch build (as some - are meant as configuration projects), but rather select and build just - the ALL_BUILD project to build everything, or the INSTALL project, which - first builds the ALL_BUILD project, then installs the LLVM headers, libs, - and other useful things to the directory set by the CMAKE_INSTALL_PREFIX - setting when you first configured CMake.
        • -
        -
      10. - -
      11. Start Visual Studio -
          -
        • If you did not use CMake, then simply double click on the solution - file llvm/win32/llvm.sln.
        • -
        • If you used CMake, then the directory you created the project files, - the root directory will have an llvm.sln file, just - double-click on that to open Visual Studio.
        • -
      12. - -
      13. Build the LLVM Suite: -
          -
        • Simply build the solution.
        • -
        • The Fibonacci project is a sample program that uses the JIT. Modify - the project's debugging properties to provide a numeric command line - argument. The program will print the corresponding fibonacci value.
        • -
      14. - -
      - -

      It is strongly encouraged that you get the latest version from Subversion as -changes are continually making the VS support better.

      - -
      -
      Requirements @@ -178,7 +92,7 @@ changes are continually making the VS support better.

      -

      Any system that can adequately run Visual Studio .NET 2005 SP1 is fine. +

      Any system that can adequately run Visual Studio .NET 2005 SP1 is fine. The LLVM source tree and object files, libraries and executables will consume approximately 3GB.

      @@ -190,75 +104,126 @@ changes are continually making the VS support better.

      You will need Visual Studio .NET 2005 SP1 or higher. The VS2005 SP1 beta and the normal VS2005 still have bugs that are not completely - compatible. VS2003 would work except (at last check) it has a bug with - friend classes that you can work-around with some minor code rewriting - (and please submit a patch if you do). Earlier versions of Visual Studio - do not support the C++ standard well enough and will not work.

      - + compatible. Earlier versions of Visual Studio do not support the C++ standard + well enough and will not work.

      +

      You will also need the CMake build system since it generates the project files you will use to build with.

      -

      - Do not install the LLVM directory tree into a path containing spaces (e.g. +

      If you would like to run the LLVM tests you will need + Python. Versions 2.4-2.7 are known to + work. You will need "GnuWin32" + tools, too.

      + +

      Do not install the LLVM directory tree into a path containing spaces (e.g. C:\Documents and Settings\...) as the configure step will fail.

      -

      The remainder of this guide is meant to get you up and running with -LLVM using Visual Studio and to give you some basic information about the LLVM -environment.

      +

      Here's the short story for getting up and running quickly with LLVM:

      -
      +
        +
      1. Read the documentation.
      2. +
      3. Seriously, read the documentation.
      4. +
      5. Remember that you were warned twice about reading the documentation.
      6. - - +
      7. Get the Source Code +
          +
        • With the distributed files: +
            +
          1. cd where-you-want-llvm-to-live +
          2. gunzip --stdout llvm-version.tar.gz | tar -xvf - +       or use WinZip +
          3. cd llvm
          4. +
        • -
          +
        • With anonymous Subversion access: +
            +
          1. cd where-you-want-llvm-to-live
          2. +
          3. svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
          4. +
          5. cd llvm
          6. +
        • +
      8. -

        Throughout this manual, the following names are used to denote paths -specific to the local system and working environment. These are not -environment variables you need to set but just strings used in the rest -of this document below. In any of the examples below, simply replace -each of these names with the appropriate pathname on your local system. -All these paths are absolute:

        +
      9. Use CMake to generate up-to-date + project files: +
          +
        • Once CMake is installed then the simplest way is to just start the + CMake GUI, select the directory where you have LLVM extracted to, and the + default options should all be fine. One option you may really want to + change, regardless of anything else, might be the CMAKE_INSTALL_PREFIX + setting to select a directory to INSTALL to once compiling is complete, + although installation is not mandatory for using LLVM. Another important + option is LLVM_TARGETS_TO_BUILD, which controls the LLVM target + architectures that are included on the build. +
        • See the LLVM CMake guide for + detailed information about how to configure the LLVM + build.
        • +
        +
      10. -
        -
        SRC_ROOT
        -

        This is the top level directory of the LLVM source tree.

        +
      11. Start Visual Studio +
          +
        • In the directory you created the project files will have + an llvm.sln file, just double-click on that to open + Visual Studio.
        • +
      12. -
        OBJ_ROOT
        -

        This is the top level directory of the LLVM object tree (i.e. the - tree where object files and compiled programs will be placed. It is - fixed at SRC_ROOT/win32).

        -
        +
      13. Build the LLVM Suite: +
          +
        • The projects may still be built individually, but + to build them all do not just select all of them in batch build (as some + are meant as configuration projects), but rather select and build just + the ALL_BUILD project to build everything, or the INSTALL project, which + first builds the ALL_BUILD project, then installs the LLVM headers, libs, + and other useful things to the directory set by the CMAKE_INSTALL_PREFIX + setting when you first configured CMake.
        • +
        • The Fibonacci project is a sample program that uses the JIT. + Modify the project's debugging properties to provide a numeric + command line argument or run it from the command line. The + program will print the corresponding fibonacci value.
        • +
      14. -
      +
    • Test LLVM on Visual Studio: +
        +
      • If %PATH% does not contain GnuWin32, you may specify LLVM_LIT_TOOLS_DIR + on CMake for the path to GnuWin32.
      • +
      • You can run LLVM tests to build the project "check".
      • +
      +
    • - -
      - The Location of LLVM Object Files + +
    • Test LLVM: +
        +
      • The LLVM tests can be run by cding to the llvm source directory + and running: + +
        +
        +% llvm-lit test
        +
        -
        +

        Note that quite a few of these test will fail.

        +
      • -

        The object files are placed under OBJ_ROOT/Debug for debug builds - and OBJ_ROOT/Release for release (optimized) builds. These include - both executables and libararies that your application can link against.

        +
      • A specific test or test directory can be run with:
      • -

        The files that configure would create when building on Unix are - created by the Configure project and placed in - OBJ_ROOT/llvm. You application must have OBJ_ROOT in its include - search path just before SRC_ROOT/include.

        +
        +
        +% llvm-lit test/path/to/test
        +
        +
        + +
    • @@ -286,7 +251,7 @@ int main() {
      -% llvm-gcc -c hello.c -emit-llvm -o hello.bc
      +% clang -c hello.c -emit-llvm -o hello.bc
       
      @@ -295,23 +260,27 @@ int main() { facilities that it required. You can execute this file directly using lli tool, compile it to native assembly with the llc, optimize or analyze it further with the opt tool, etc.

      - -

      Note: while you cannot do this step on Windows, you can do it on a - Unix system and transfer hello.bc to Windows. Important: - transfer as a binary file!

      + +

      Alternatively you can directly output an executable with clang with: +

      + +
      +
      +% clang hello.c -o hello.exe
      +
      +
      + +

      The -o hello.exe is required because clang currently outputs + a.out when neither -o nor -c are given.

    • Run the program using the just-in-time compiler:

      - +
       % lli hello.bc
       
      -

      Note: this will only work for trivial C programs. Non-trivial programs - (and any C++ program) will have dependencies on the GCC runtime that - won't be satisfied by the Microsoft runtime libraries.

    • -
    • Use the llvm-dis utility to take a look at the LLVM assembly code:

      @@ -321,31 +290,27 @@ int main() {
    • -
    • Compile the program to C using the LLC code generator:

      +
    • Compile the program to object code using the LLC code generator:

      -% llc -march=c hello.bc
      +% llc -filetype=obj hello.bc
       
    • -
    • Compile to binary using Microsoft C:

      +
    • Link to binary using Microsoft link:

      -% cl hello.cbe.c
      +% link hello.obj -defaultlib:libcmt
       
      -

      Note: this will only work for trivial C programs. Non-trivial programs - (and any C++ program) will have dependencies on the GCC runtime that won't - be satisfied by the Microsoft runtime libraries.

    • -
    • Execute the native code program:

      -% hello.cbe.exe
      +% hello.exe
       
    • @@ -360,17 +325,6 @@ int main() {
      -
        -
      • In Visual C++, if you are linking with the x86 target statically, the - linker will remove the x86 target library from your generated executable or - shared library because there are no references to it. You can force the - linker to include these references by using - "/INCLUDE:_X86TargetMachineModule" when linking. In the Visual - Studio IDE, this can be added in -Project Properties->Linker->Input->Force Symbol References. -
      • -
      -

      If you are having problems building or using LLVM, or if you have any other general questions about LLVM, please consult the Frequently Asked Questions page.

      @@ -411,7 +365,7 @@ out:

      Jeff Cohen
      The LLVM Compiler Infrastructure
      - Last modified: $Date: 2010-05-07 02:28:04 +0200 (Fri, 07 May 2010) $ + Last modified: $Date: 2011-02-09 05:19:28 +0100 (Wed, 09 Feb 2011) $ diff --git a/docs/GoldPlugin.html b/docs/GoldPlugin.html index 3f2e9fb2e640..68c5cf192802 100644 --- a/docs/GoldPlugin.html +++ b/docs/GoldPlugin.html @@ -55,7 +55,7 @@ mkdir binutils cd binutils cvs -z 9 -d :pserver:anoncvs@sourceware.org:/cvs/src login {enter "anoncvs" as the password} -cvs -z 9 -d :pserver:anoncvs@sourceware.org:/cvs/src co src +cvs -z 9 -d :pserver:anoncvs@sourceware.org:/cvs/src co binutils mkdir build cd build ../src/configure --enable-gold --enable-plugins diff --git a/docs/LangRef.html b/docs/LangRef.html index b717531e3479..05130c29efc2 100644 --- a/docs/LangRef.html +++ b/docs/LangRef.html @@ -62,6 +62,7 @@
      1. Integer Type
      2. Floating Point Types
      3. +
      4. X86mmx Type
      5. Void Type
      6. Label Type
      7. Metadata Type
      8. @@ -492,7 +493,7 @@
         ; Declare the string constant as a global constant. 
        -@.LC0 = internal constant [13 x i8] c"hello world\0A\00"      ; [13 x i8]* 
        +@.LC0 = internal constant [13 x i8] c"hello world\0A\00"      ; [13 x i8]* 
         
         ; External declaration of the puts function 
         declare i32 @puts(i8*)                                      ; i32 (i8*)*  
        @@ -845,6 +846,13 @@ define i32 @main() {   ; i32()*  
            region of memory, and all memory objects in LLVM are accessed through
            pointers.

        +

        Global variables can be marked with unnamed_addr which indicates + that the address is not significant, only the content. Constants marked + like this can be merged with other constants if they have the same + initializer. Note that a constant with significant address can + be merged with a unnamed_addr constant, the result being a + constant whose address is significant.

        +

        A global variable may be declared to reside in a target-specific numbered address space. For targets that support them, address spaces may affect how optimizations are performed and/or what target instructions are used to @@ -884,7 +892,8 @@ define i32 @main() { ; i32()*  

        LLVM function definitions consist of the "define" keyword, an optional linkage type, an optional visibility style, an optional - calling convention, a return type, an optional + calling convention, + an optional unnamed_addr attribute, a return type, an optional parameter attribute for the return type, a function name, a (possibly empty) argument list (each with optional parameter attributes), optional @@ -895,7 +904,8 @@ define i32 @main() { ; i32()*  

        LLVM function declarations consist of the "declare" keyword, an optional linkage type, an optional visibility style, an optional - calling convention, a return type, an optional + calling convention, + an optional unnamed_addr attribute, a return type, an optional parameter attribute for the return type, a function name, a possibly empty list of arguments, an optional alignment, and an optional garbage collector name.

        @@ -921,6 +931,9 @@ define i32 @main() { ; i32()*   specified, the function is forced to have at least that much alignment. All alignments must be a power of 2.

        +

        If the unnamed_addr attribute is given, the address is know to not + be significant and two identical functions can be merged

        . +
        Syntax:
         define [linkage] [visibility]
        @@ -1020,8 +1033,9 @@ declare signext i8 @returns_signed_char()
               registers).  Use of this attribute is target-specific.
    byval
    -
    This indicates that the pointer parameter should really be passed by value - to the function. The attribute implies that a hidden copy of the pointee +

    This indicates that the pointer parameter should really be passed by + value to the function. The attribute implies that a hidden copy of the + pointee is made between the caller and the callee, so the callee is unable to modify the value in the callee. This attribute is only valid on LLVM pointer arguments. It is generally used to pass structs and arrays by @@ -1029,10 +1043,13 @@ declare signext i8 @returns_signed_char() to belong to the caller not the callee (for example, readonly functions should not write to byval parameters). This is not a valid attribute for return - values. The byval attribute also supports specifying an alignment with - the align attribute. This has a target-specific effect on the code - generator that usually indicates a desired alignment for the synthesized - stack slot.

    + values.

    + +

    The byval attribute also supports specifying an alignment with + the align attribute. It indicates the alignment of the stack slot to + form and the known alignment of the pointer specified to the call site. If + the alignment is not specified, then the code generator makes a + target-specific assumption.

    sret
    This indicates that the pointer parameter specifies the address of a @@ -1130,6 +1147,14 @@ define void @f() optsize { ... } function into callers whenever possible, ignoring any active inlining size threshold for this caller.
    +
    hotpatch
    +
    This attribute indicates that the function should be 'hotpatchable', + meaning the function can be patched and/or hooked even while it is + loaded into memory. On x86, the function prologue will be preceded + by six bytes of padding and will begin with a two-byte instruction. + Most of the functions in the Windows system DLLs in Windows XP SP2 or + higher were compiled in this fashion.
    +
    inlinehint
    This attribute indicates that the source code contained a hint that inlining this function is desirable (such as the "inline" keyword in C/C++). It @@ -1483,7 +1508,9 @@ Classifications primitive label, void, + integer, floating point, + x86mmx, metadata. @@ -1570,6 +1597,21 @@ Classifications + + + +
    + +
    Overview:
    +

    The x86mmx type represents a value held in an MMX register on an x86 machine. The operations allowed on it are quite limited: parameters and return values, load and store, and bitcast. User-specified MMX instructions are represented as intrinsic or asm calls with arguments and/or results of this type. There are no arrays, vectors or constants of this type.

    + +
    Syntax:
    +
    +  x86mmx
    +
    + +
    + @@ -1893,8 +1935,9 @@ Classifications < <# elements> x <elementtype> > -

    The number of elements is a constant integer value; elementtype may be any - integer or floating point type.

    +

    The number of elements is a constant integer value larger than 0; elementtype + may be any integer or floating point type. Vectors of size zero are not + allowed, and pointers are not allowed as the element type.

    Examples:
    @@ -2050,6 +2093,7 @@ Classifications they match the long double format on your target. All hexadecimal formats are big-endian (sign bit at the left).

    +

    There are no constants of type x86mmx.

    @@ -2135,8 +2179,8 @@ Classifications

    The string 'undef' can be used anywhere a constant is expected, and indicates that the user of the value may receive an unspecified bit-pattern. - Undefined values may be of any type (other than label or void) and be used - anywhere a constant is permitted.

    + Undefined values may be of any type (other than 'label' + or 'void') and be used anywhere a constant is permitted.

    Undefined values are useful because they indicate to the compiler that the program is well defined no matter what value is used. This gives the @@ -2155,7 +2199,7 @@ Safe:

    This is safe because all of the output bits are affected by the undef bits. -Any output bit can have a zero or one depending on the input bits.

    + Any output bit can have a zero or one depending on the input bits.

       %A = or %X, undef
    @@ -2169,13 +2213,14 @@ Unsafe:
     

    These logical operations have bits that are not always affected by the input. -For example, if "%X" has a zero bit, then the output of the 'and' operation will -always be a zero, no matter what the corresponding bit from the undef is. As -such, it is unsafe to optimize or assume that the result of the and is undef. -However, it is safe to assume that all bits of the undef could be 0, and -optimize the and to 0. Likewise, it is safe to assume that all the bits of -the undef operand to the or could be set, allowing the or to be folded to --1.

    + For example, if %X has a zero bit, then the output of the + 'and' operation will always be a zero for that bit, no matter what + the corresponding bit from the 'undef' is. As such, it is unsafe to + optimize or assume that the result of the 'and' is 'undef'. + However, it is safe to assume that all bits of the 'undef' could be + 0, and optimize the 'and' to 0. Likewise, it is safe to assume that + all the bits of the 'undef' operand to the 'or' could be + set, allowing the 'or' to be folded to -1.

       %A = select undef, %X, %Y
    @@ -2191,13 +2236,14 @@ Unsafe:
       %C = undef
     
    -

    This set of examples show that undefined select (and conditional branch) -conditions can go "either way" but they have to come from one of the two -operands. In the %A example, if %X and %Y were both known to have a clear low -bit, then %A would have to have a cleared low bit. However, in the %C example, -the optimizer is allowed to assume that the undef operand could be the same as -%Y, allowing the whole select to be eliminated.

    - +

    This set of examples shows that undefined 'select' (and conditional + branch) conditions can go either way, but they have to come from one + of the two operands. In the %A example, if %X and + %Y were both known to have a clear low bit, then %A would + have to have a cleared low bit. However, in the %C example, the + optimizer is allowed to assume that the 'undef' operand could be the + same as %Y, allowing the whole 'select' to be + eliminated.

       %A = xor undef, undef
    @@ -2218,16 +2264,17 @@ Safe:
       %F = undef
     
    -

    This example points out that two undef operands are not necessarily the same. -This can be surprising to people (and also matches C semantics) where they -assume that "X^X" is always zero, even if X is undef. This isn't true for a -number of reasons, but the short answer is that an undef "variable" can -arbitrarily change its value over its "live range". This is true because the -"variable" doesn't actually have a live range. Instead, the value is -logically read from arbitrary registers that happen to be around when needed, -so the value is not necessarily consistent over time. In fact, %A and %C need -to have the same semantics or the core LLVM "replace all uses with" concept -would not hold.

    +

    This example points out that two 'undef' operands are not + necessarily the same. This can be surprising to people (and also matches C + semantics) where they assume that "X^X" is always zero, even + if X is undefined. This isn't true for a number of reasons, but the + short answer is that an 'undef' "variable" can arbitrarily change + its value over its "live range". This is true because the variable doesn't + actually have a live range. Instead, the value is logically read + from arbitrary registers that happen to be around when needed, so the value + is not necessarily consistent over time. In fact, %A and %C + need to have the same semantics or the core LLVM "replace all uses with" + concept would not hold.

       %A = fdiv undef, %X
    @@ -2238,17 +2285,17 @@ b: unreachable
     

    These examples show the crucial difference between an undefined -value and undefined behavior. An undefined value (like undef) is -allowed to have an arbitrary bit-pattern. This means that the %A operation -can be constant folded to undef because the undef could be an SNaN, and fdiv is -not (currently) defined on SNaN's. However, in the second example, we can make -a more aggressive assumption: because the undef is allowed to be an arbitrary -value, we are allowed to assume that it could be zero. Since a divide by zero -has undefined behavior, we are allowed to assume that the operation -does not execute at all. This allows us to delete the divide and all code after -it: since the undefined operation "can't happen", the optimizer can assume that -it occurs in dead code. -

    + value and undefined behavior. An undefined value (like + 'undef') is allowed to have an arbitrary bit-pattern. This means that + the %A operation can be constant folded to 'undef', because + the 'undef' could be an SNaN, and fdiv is not (currently) + defined on SNaN's. However, in the second example, we can make a more + aggressive assumption: because the undef is allowed to be an + arbitrary value, we are allowed to assume that it could be zero. Since a + divide by zero has undefined behavior, we are allowed to assume that + the operation does not execute at all. This allows us to delete the divide and + all code after it. Because the undefined operation "can't happen", the + optimizer can assume that it occurs in dead code.

     a:  store undef -> %X
    @@ -2258,11 +2305,11 @@ a: <deleted>
     b: unreachable
     
    -

    These examples reiterate the fdiv example: a store "of" an undefined value -can be assumed to not have any effect: we can assume that the value is -overwritten with bits that happen to match what was already there. However, a -store "to" an undefined location could clobber arbitrary memory, therefore, it -has undefined behavior.

    +

    These examples reiterate the fdiv example: a store of an + undefined value can be assumed to not have any effect; we can assume that the + value is overwritten with bits that happen to match what was already there. + However, a store to an undefined location could clobber arbitrary + memory, therefore, it has undefined behavior.

    @@ -2383,18 +2430,17 @@ end: the address of the entry block is illegal.

    This value only has defined behavior when used as an operand to the - 'indirectbr' instruction or for comparisons - against null. Pointer equality tests between labels addresses is undefined - behavior - though, again, comparison against null is ok, and no label is - equal to the null pointer. This may also be passed around as an opaque - pointer sized value as long as the bits are not inspected. This allows - ptrtoint and arithmetic to be performed on these values so long as - the original value is reconstituted before the indirectbr.

    + 'indirectbr' instruction, or for + comparisons against null. Pointer equality tests between labels addresses + results in undefined behavior — though, again, comparison against null + is ok, and no label is equal to the null pointer. This may be passed around + as an opaque pointer sized value as long as the bits are not inspected. This + allows ptrtoint and arithmetic to be performed on these values so + long as the original value is reconstituted before the indirectbr + instruction.

    -

    Finally, some targets may provide defined semantics when - using the value as the operand to an inline assembly, but that is target - specific. -

    +

    Finally, some targets may provide defined semantics when using the value as + the operand to an inline assembly, but that is target specific.

    @@ -2409,7 +2455,7 @@ end: to be used as constants. Constant expressions may be of any first class type and may involve any LLVM operation that does not have side effects (e.g. load and call are not - supported). The following is the syntax for constant expressions:

    + supported). The following is the syntax for constant expressions:

    trunc (CST to TYPE)
    @@ -2596,8 +2642,8 @@ call void asm alignstack "eieio", ""()

    The call instructions that wrap inline asm nodes may have a "!srcloc" MDNode - attached to it that contains a constant integer. If present, the code - generator will use the integer as the location cookie value when report + attached to it that contains a list of constant integers. If present, the + code generator will use the integer as the location cookie value when report errors through the LLVMContext error reporting mechanisms. This allows a front-end to correlate backend errors that occur with inline asm back to the source code that produced it. For example:

    @@ -2609,7 +2655,8 @@ call void asm sideeffect "something bad", ""(), !srcloc !42

    It is up to the front-end to make sense of the magic numbers it places in the - IR.

    + IR. If the MDNode contains multiple constants, the code generator will use + the one that corresponds to the line of the asm that the error occurs on.

    @@ -3394,7 +3441,8 @@ Instruction
    Syntax:
    -  <result> = udiv <ty> <op1>, <op2>   ; yields {ty}:result
    +  <result> = udiv <ty> <op1>, <op2>         ; yields {ty}:result
    +  <result> = udiv exact <ty> <op1>, <op2>   ; yields {ty}:result
     
    Overview:
    @@ -3413,6 +3461,11 @@ Instruction

    Division by zero leads to undefined behavior.

    +

    If the exact keyword is present, the result value of the + udiv is a trap value if %op1 is not a + multiple of %op2 (as such, "((a udiv exact b) mul b) == a").

    + +
    Example:
       <result> = udiv i32 4, %var          ; yields {i32}:result = 4 / %var
    @@ -3631,7 +3684,10 @@ Instruction 
     
     
    Syntax:
    -  <result> = shl <ty> <op1>, <op2>   ; yields {ty}:result
    +  <result> = shl <ty> <op1>, <op2>           ; yields {ty}:result
    +  <result> = shl nuw <ty> <op1>, <op2>       ; yields {ty}:result
    +  <result> = shl nsw <ty> <op1>, <op2>       ; yields {ty}:result
    +  <result> = shl nuw nsw <ty> <op1>, <op2>   ; yields {ty}:result
     
    Overview:
    @@ -3651,6 +3707,14 @@ Instruction vectors, each vector element of op1 is shifted by the corresponding shift amount in op2.

    +

    If the nuw keyword is present, then the shift produces a + trap value if it shifts out any non-zero bits. If + the nsw keyword is present, then the shift produces a + trap value if it shifts out any bits that disagree + with the resultant sign bit. As such, NUW/NSW have the same semantics as + they would if the shift were expressed as a mul instruction with the same + nsw/nuw bits in (mul %op1, (shl 1, %op2)).

    +
    Example:
       <result> = shl i32 4, %var   ; yields {i32}: 4 << %var
    @@ -3670,7 +3734,8 @@ Instruction 
     
     
    Syntax:
    -  <result> = lshr <ty> <op1>, <op2>   ; yields {ty}:result
    +  <result> = lshr <ty> <op1>, <op2>         ; yields {ty}:result
    +  <result> = lshr exact <ty> <op1>, <op2>   ; yields {ty}:result
     
    Overview:
    @@ -3690,6 +3755,11 @@ Instruction vectors, each vector element of op1 is shifted by the corresponding shift amount in op2.

    +

    If the exact keyword is present, the result value of the + lshr is a trap value if any of the bits + shifted out are non-zero.

    + +
    Example:
       <result> = lshr i32 4, 1   ; yields {i32}:result = 2
    @@ -3709,7 +3779,8 @@ Instruction 
     
     
    Syntax:
    -  <result> = ashr <ty> <op1>, <op2>   ; yields {ty}:result
    +  <result> = ashr <ty> <op1>, <op2>         ; yields {ty}:result
    +  <result> = ashr exact <ty> <op1>, <op2>   ; yields {ty}:result
     
    Overview:
    @@ -3730,6 +3801,10 @@ Instruction the arguments are vectors, each vector element of op1 is shifted by the corresponding shift amount in op2.

    +

    If the exact keyword is present, the result value of the + ashr is a trap value if any of the bits + shifted out are non-zero.

    +
    Example:
       <result> = ashr i32 4, 1   ; yields {i32}:result = 2
    @@ -4097,6 +4172,14 @@ Instruction 
        array type.  The operands are constant indices to
        specify which value to extract in a similar manner as indices in a
        'getelementptr' instruction.

    +

    The major differences to getelementptr indexing are:

    +
      +
    • Since the value being indexed is not a pointer, the first index is + omitted and assumed to be zero.
    • +
    • At least one index must be specified.
    • +
    • Not only struct indices but also array indices must be in + bounds.
    • +
    Semantics:

    The result is the value at the position in the aggregate specified by the @@ -4131,7 +4214,7 @@ Instruction array type. The second operand is a first-class value to insert. The following operands are constant indices indicating the position at which to insert the value in a similar manner as indices in a - 'getelementptr' instruction. The + 'extractvalue' instruction. The value to insert must have the same type as the value identified by the indices.

    @@ -7472,7 +7555,7 @@ LLVM.

    Syntax:
    -  declare {}* @llvm.invariant.start(i64 <size>, i8* nocapture <ptr>) readonly
    +  declare {}* @llvm.invariant.start(i64 <size>, i8* nocapture <ptr>)
     
    Overview:
    @@ -7647,7 +7730,7 @@ LLVM.

    the AllocaInst stack slot to be before local variables on the stack. This is to ensure that if a local variable on the stack is overwritten, it will destroy the value of the guard. When the function exits, - the guard on the stack is checked against the original guard. If they're + the guard on the stack is checked against the original guard. If they are different, then the program aborts by calling the __stack_chk_fail() function.

    @@ -7667,25 +7750,24 @@ LLVM.

    Overview:
    -

    The llvm.objectsize intrinsic is designed to provide information - to the optimizers to discover at compile time either a) when an - operation like memcpy will either overflow a buffer that corresponds to - an object, or b) to determine that a runtime check for overflow isn't - necessary. An object in this context means an allocation of a - specific class, structure, array, or other object.

    +

    The llvm.objectsize intrinsic is designed to provide information to + the optimizers to determine at compile time whether a) an operation (like + memcpy) will overflow a buffer that corresponds to an object, or b) that a + runtime check for overflow isn't necessary. An object in this context means + an allocation of a specific class, structure, array, or other object.

    Arguments:
    -

    The llvm.objectsize intrinsic takes two arguments. The first +

    The llvm.objectsize intrinsic takes two arguments. The first argument is a pointer to or into the object. The second argument - is a boolean 0 or 1. This argument determines whether you want the - maximum (0) or minimum (1) bytes remaining. This needs to be a literal 0 or + is a boolean 0 or 1. This argument determines whether you want the + maximum (0) or minimum (1) bytes remaining. This needs to be a literal 0 or 1, variables are not allowed.

    Semantics:

    The llvm.objectsize intrinsic is lowered to either a constant - representing the size of the object concerned or i32/i64 -1 or 0 - (depending on the type argument if the size cannot be determined - at compile time.

    + representing the size of the object concerned, or i32/i64 -1 or 0, + depending on the type argument, if the size cannot be determined at + compile time.

    @@ -7699,7 +7781,7 @@ LLVM.

    Chris Lattner
    The LLVM Compiler Infrastructure
    - Last modified: $Date: 2010-08-28 06:09:24 +0200 (Sat, 28 Aug 2010) $ + Last modified: $Date: 2011-02-09 17:44:44 +0100 (Wed, 09 Feb 2011) $ diff --git a/docs/LinkTimeOptimization.html b/docs/LinkTimeOptimization.html index 03dc67767990..30334744d7f9 100644 --- a/docs/LinkTimeOptimization.html +++ b/docs/LinkTimeOptimization.html @@ -19,7 +19,7 @@
  • Multi-phase communication between LLVM and linker
      -
    • Phase 1 : Read LLVM Bytecode Files
    • +
    • Phase 1 : Read LLVM Bitcode Files
    • Phase 2 : Symbol Resolution
    • Phase 3 : Optimize Bitcode Files
    • Phase 4 : Symbol Resolution after optimization
    • @@ -382,7 +382,7 @@ of the native object files.

      Devang Patel and Nick Kledzik
      LLVM Compiler Infrastructure
      - Last modified: $Date: 2010-05-07 02:28:04 +0200 (Fri, 07 May 2010) $ + Last modified: $Date: 2010-09-29 22:09:55 +0200 (Wed, 29 Sep 2010) $ diff --git a/docs/Makefile b/docs/Makefile index 8f7d6171d3b3..389fd90a485e 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -37,14 +37,21 @@ install_targets := install-html ifeq ($(ENABLE_DOXYGEN),1) install_targets += install-doxygen endif +ifdef OCAMLDOC ifneq (,$(filter ocaml,$(BINDINGS_TO_BUILD))) install_targets += install-ocamldoc endif +endif install-local:: $(install_targets) +generated_targets := doxygen +ifdef OCAMLDOC +generated_targets += ocamldoc +endif + # Live documentation is generated for the web site using this target: # 'make generated BUILD_FOR_WEBSITE=1' -generated:: doxygen ocamldoc +generated:: $(generated_targets) install-html: $(PROJ_OBJ_DIR)/html.tar.gz $(Echo) Installing HTML documentation @@ -59,7 +66,7 @@ $(PROJ_OBJ_DIR)/html.tar.gz: $(HTML) $(Verb) $(RM) -rf $@ $(PROJ_OBJ_DIR)/html.tar $(Verb) cd $(PROJ_SRC_DIR) && \ $(TAR) cf $(PROJ_OBJ_DIR)/html.tar *.html - $(Verb) $(GZIP) $(PROJ_OBJ_DIR)/html.tar + $(Verb) $(GZIPBIN) $(PROJ_OBJ_DIR)/html.tar install-doxygen: doxygen $(Echo) Installing doxygen documentation @@ -82,7 +89,7 @@ $(PROJ_OBJ_DIR)/doxygen.tar.gz: $(DOXYFILES) $(PROJ_OBJ_DIR)/doxygen.cfg $(Echo) Packaging doxygen documentation $(Verb) $(RM) -rf $@ $(PROJ_OBJ_DIR)/doxygen.tar $(Verb) $(TAR) cf $(PROJ_OBJ_DIR)/doxygen.tar doxygen - $(Verb) $(GZIP) $(PROJ_OBJ_DIR)/doxygen.tar + $(Verb) $(GZIPBIN) $(PROJ_OBJ_DIR)/doxygen.tar $(Verb) $(CP) $(PROJ_OBJ_DIR)/doxygen.tar.gz $(PROJ_OBJ_DIR)/doxygen/html/ userloc: $(LLVM_SRC_ROOT)/docs/userloc.html @@ -104,7 +111,7 @@ ocamldoc: regen-ocamldoc $(Echo) Packaging ocamldoc documentation $(Verb) $(RM) -rf $(PROJ_OBJ_DIR)/ocamldoc.tar* $(Verb) $(TAR) cf $(PROJ_OBJ_DIR)/ocamldoc.tar ocamldoc - $(Verb) $(GZIP) $(PROJ_OBJ_DIR)/ocamldoc.tar + $(Verb) $(GZIPBIN) $(PROJ_OBJ_DIR)/ocamldoc.tar $(Verb) $(CP) $(PROJ_OBJ_DIR)/ocamldoc.tar.gz $(PROJ_OBJ_DIR)/ocamldoc/html/ regen-ocamldoc: diff --git a/docs/MakefileGuide.html b/docs/MakefileGuide.html index 38b7ae19fa64..6ceb09db3274 100644 --- a/docs/MakefileGuide.html +++ b/docs/MakefileGuide.html @@ -640,18 +640,18 @@ generate dependencies when running the compiler. Use of this feature is discouraged and it may be removed at a later date.
      ENABLE_OPTIMIZED
      -
      If set to any value, causes the build to generate optimized objects, +
      If set to 1, causes the build to generate optimized objects, libraries and executables. This alters the flags specified to the compilers and linkers. Generally debugging won't be a fun experience with an optimized build.
      ENABLE_PROFILING
      -
      If set to any value, causes the build to generate both optimized and +
      If set to 1, causes the build to generate both optimized and profiled objects, libraries and executables. This alters the flags specified to the compilers and linkers to ensure that profile data can be collected from the tools built. Use the gprof tool to analyze the output from the profiled tools (gmon.out).
      DISABLE_ASSERTIONS
      -
      If set to any value, causes the build to disable assertions, even if +
      If set to 1, causes the build to disable assertions, even if building a debug or profile build. This will exclude all assertion check code from the build. LLVM will execute faster, but with little help when things go wrong.
      @@ -1028,7 +1028,7 @@ Reid Spencer
      The LLVM Compiler Infrastructure
      - Last modified: $Date: 2010-07-24 19:54:00 +0200 (Sat, 24 Jul 2010) $ + Last modified: $Date: 2010-10-22 14:54:34 +0200 (Fri, 22 Oct 2010) $ diff --git a/docs/Passes.html b/docs/Passes.html index 0358745f79f7..fb2aff585bdb 100644 --- a/docs/Passes.html +++ b/docs/Passes.html @@ -166,7 +166,7 @@ perl -e '$/ = undef; for (split(/\n/, <>)) { s:^ *///? ?::; print "

      \n" if !

  • - + @@ -382,7 +382,7 @@ perl -e '$/ = undef; for (split(/\n/, <>)) { s:^ *///? ?::; print "

    \n" if !

    @@ -394,7 +394,7 @@ perl -e '$/ = undef; for (split(/\n/, <>)) { s:^ *///? ?::; print "

    \n" if !

    @@ -1491,7 +1491,7 @@ if (X < 3) {

    @@ -2242,7 +2242,7 @@ if (X < 3) { Reid Spencer
    LLVM Compiler Infrastructure
    - Last modified: $Date: 2010-08-20 03:03:44 +0200 (Fri, 20 Aug 2010) $ + Last modified: $Date: 2011-02-13 21:57:25 +0100 (Sun, 13 Feb 2011) $ diff --git a/docs/ProgrammersManual.html b/docs/ProgrammersManual.html index 8fdd8a00b9bc..0351dd03b7d0 100644 --- a/docs/ProgrammersManual.html +++ b/docs/ProgrammersManual.html @@ -84,6 +84,7 @@ option

  • "llvm/ADT/IndexedMap.h"
  • "llvm/ADT/DenseMap.h"
  • "llvm/ADT/ValueMap.h"
  • +
  • "llvm/ADT/IntervalMap.h"
  • <map>
  • Other Map-Like Container Options
  • @@ -269,9 +270,9 @@ can get, so it will not be discussed in this document.

      -
    1. Dinkumware C++ Library -reference - an excellent reference for the STL and other parts of the -standard C++ library.
    2. +
    3. Dinkumware +C++ Library reference - an excellent reference for the STL and other parts +of the standard C++ library.
    4. C++ In a Nutshell - This is an O'Reilly book in the making. It has a decent Standard Library @@ -1507,6 +1508,23 @@ a Config parameter to the ValueMap template.

    + + + +
    + +

    IntervalMap is a compact map for small keys and values. It maps key +intervals instead of single keys, and it will automatically coalesce adjacent +intervals. When then map only contains a few intervals, they are stored in the +map object itself to avoid allocations.

    + +

    The IntervalMap iterators are quite big, so they should not be passed around +as STL iterators. The heavyweight iterators allow a smaller data structure.

    + +
    +
    <map> @@ -3838,7 +3856,7 @@ doxygen info: BasicBlock Class
    Superclass: Value

    -

    This class represents a single entry multiple exit section of the code, +

    This class represents a single entry single exit section of the code, commonly known as a basic block by the compiler community. The BasicBlock class maintains a list of Instructions, which form the body of the block. @@ -3940,7 +3958,7 @@ arguments. An argument has a pointer to the parent Function.

    Dinakar Dhurjati and Chris Lattner
    The LLVM Compiler Infrastructure
    - Last modified: $Date: 2010-08-04 17:59:16 +0200 (Wed, 04 Aug 2010) $ + Last modified: $Date: 2011-02-17 03:19:22 +0100 (Thu, 17 Feb 2011) $ diff --git a/docs/ReleaseNotes.html b/docs/ReleaseNotes.html index 9b6d5e847e94..84298376a732 100644 --- a/docs/ReleaseNotes.html +++ b/docs/ReleaseNotes.html @@ -126,7 +126,7 @@ production-quality compiler for C, Objective-C, C++ and Objective-C++ on x86
  • Introduced many new warnings, including -Wmissing-field-initializers, -Wshadow, -Wno-protocol, -Wtautological-compare, -Wstrict-selector-match, -Wcast-align, -Wunused improvements, and greatly improved format-string checking.
  • Introduced the "libclang" library, a C interface to Clang intended to support IDE clients.
  • Added support for #pragma GCC visibility, #pragma align, and others.
  • -
  • Added support for SSE, ARM NEON, and Altivec.
  • +
  • Added support for SSE, AVX, ARM NEON, and AltiVec.
  • Improved support for many Microsoft extensions.
  • Implemented support for blocks in C++.
  • Implemented precompiled headers for C++.
  • @@ -269,7 +269,7 @@ support new platforms, new languages, new architectures, and new features.

    -libc++ is another new member of the LLVM +libc++ is another new member of the LLVM family. It is an implementation of the C++ standard library, written from the ground up to specifically target the forthcoming C++'0X standard and focus on delivering great performance.

    @@ -673,7 +673,7 @@ release includes a few major enhancements and additions to the optimizers:

    be 13 in one of the predecessors of a block. It does this in conjunction with the new LazyValueInfo analysis pass.
  • The new RegionInfo analysis pass identifies single-entry single-exit regions - in the CFG. You can play with it with the "opt -regions analyze" or + in the CFG. You can play with it with the "opt -regions -analyze" or "opt -view-regions" commands.
  • The loop optimizer has significantly improved strength reduction and analysis capabilities. Notably it is able to build on the trap value and signed @@ -879,8 +879,9 @@ it run faster:

    variables can be accessed via same base address) and potentially reducing register pressure.
  • -
  • The ARM has received many minor improvements and tweaks which lead to -substantially better performance in a wide range of different scenarios.
  • +
  • The ARM backend has received many minor improvements and tweaks which lead + to substantially better performance in a wide range of different scenarios. +
  • The ARM NEON intrinsics have been substantially reworked to reduce redundancy and improve code generation. Some of the major changes are: @@ -1010,6 +1011,17 @@ API changes are:

    LLVM. The Triple::normalize utility method has been added to help front-ends deal with funky triples.
  • +
  • + The signature of the GCMetadataPrinter::finishAssembly virtual + function changed: the raw_ostream and MCAsmInfo arguments + were dropped. GC plugins which compute stack maps must be updated to avoid + having the old definition overload the new signature. +
  • +
  • + The signature of MemoryBuffer::getMemBuffer changed. Unfortunately + calls intended for the old version still compile, but will not work correctly, + leading to a confusing error about an invalid header in the bitcode. +
  • Some APIs were renamed: @@ -1102,7 +1114,7 @@ components, please contact us on the LLVMdev list.

      -
    • The Alpha, Blackfin, CellSPU, MicroBlaze, MSP430, MIPS, PIC16, SystemZ +
    • The Alpha, Blackfin, CellSPU, MicroBlaze, MSP430, MIPS, SystemZ and XCore backends are experimental.
    • llc "-filetype=obj" is experimental on all targets other than darwin-i386 and darwin-x86_64.
    • @@ -1287,7 +1299,7 @@ lists.

      src="http://www.w3.org/Icons/valid-html401-blue" alt="Valid HTML 4.01"> LLVM Compiler Infrastructure
      - Last modified: $Date: 2010-10-04 22:41:06 +0200 (Mon, 04 Oct 2010) $ + Last modified: $Date: 2010-10-26 14:43:36 +0200 (Tue, 26 Oct 2010) $ diff --git a/docs/SourceLevelDebugging.html b/docs/SourceLevelDebugging.html index 9d82e3ff5c69..186ea4abe732 100644 --- a/docs/SourceLevelDebugging.html +++ b/docs/SourceLevelDebugging.html @@ -78,7 +78,7 @@ height="369"> that the LLVM debug information takes, which is useful for those interested in creating front-ends or dealing directly with the information. Further, this document provides specific examples of what debug information - for C/C++.

      + for C/C++ looks like.

  • @@ -460,15 +460,17 @@ provide details such as name, type and where the variable is defined.

     !3 = metadata !{
    -  i32,     ;; Tag = 13 + LLVMDebugVersion (DW_TAG_lexical_block)
    -  metadata ;; Reference to context descriptor
    +  i32,     ;; Tag = 11 + LLVMDebugVersion (DW_TAG_lexical_block)
    +  metadata,;; Reference to context descriptor
    +  i32,     ;; Line number
    +  i32      ;; Column number
     }
     

    These descriptors provide debug information about nested blocks within a - subprogram. The array of member descriptors is used to define local - variables and deeper nested blocks.

    + subprogram. The line number and column numbers are used to dinstinguish + two lexical blocks at same depth.

    @@ -539,9 +541,9 @@ DW_ATE_unsigned_char = 8 metadata, ;; Name (may be "" for anonymous types) metadata, ;; Reference to file where defined (may be NULL) i32, ;; Line number where defined (may be 0) - i32, ;; Size in bits - i32, ;; Alignment in bits - i32, ;; Offset in bits + i64, ;; Size in bits + i64, ;; Alignment in bits + i64, ;; Offset in bits metadata ;; Reference to type derived from } @@ -586,9 +588,8 @@ DW_TAG_restrict_type = 55 the bit offset if embedded in a composite type.

    -

    Note that the void * type is expressed as a - llvm.dbg.derivedtype.type with tag of DW_TAG_pointer_type - and NULL derived type.

    +

    Note that the void * type is expressed as a type derived from NULL. +

    @@ -687,7 +688,7 @@ DW_TAG_inheritance = 28
    -%llvm.dbg.subrange.type = type {
    +!42 = metadata !{
       i32,    ;; Tag = 33 + LLVMDebugVersion (DW_TAG_subrange_type)
       i64,    ;; Low value
       i64     ;; High value
    @@ -789,15 +790,12 @@ DW_TAG_return_variable = 258
     
     
    -  void %llvm.dbg.declare({}*, metadata)
    +  void %llvm.dbg.declare(metadata, metadata)
     

    This intrinsic provides information about a local element (ex. variable.) The - first argument is the alloca for the variable, cast to a {}*. The - second argument is - the %llvm.dbg.variable containing - the description of the variable.

    - + first argument is metadata holding alloca for the variable.. The + second argument is metadata containing description of the variable.

    @@ -813,10 +811,8 @@ DW_TAG_return_variable = 258

    This intrinsic provides information when a user source variable is set to a new value. The first argument is the new value (wrapped as metadata). The second argument is the offset in the user source variable where the new value - is written. The third argument is - the %llvm.dbg.variable containing - the description of the user source variable.

    - + is written. The third argument is metadata containing description of the + user source variable.

    @@ -862,13 +858,13 @@ entry: %Y = alloca i32, align 4 ; <i32*> [#uses=4] %Z = alloca i32, align 4 ; <i32*> [#uses=3] %0 = bitcast i32* %X to {}* ; <{}*> [#uses=1] - call void @llvm.dbg.declare({}* %0, metadata !0), !dbg !7 + call void @llvm.dbg.declare(metadata !{i32 * %X}, metadata !0), !dbg !7 store i32 21, i32* %X, !dbg !8 %1 = bitcast i32* %Y to {}* ; <{}*> [#uses=1] - call void @llvm.dbg.declare({}* %1, metadata !9), !dbg !10 + call void @llvm.dbg.declare(metadata !{i32 * %Y}, metadata !9), !dbg !10 store i32 22, i32* %Y, !dbg !11 %2 = bitcast i32* %Z to {}* ; <{}*> [#uses=1] - call void @llvm.dbg.declare({}* %2, metadata !12), !dbg !14 + call void @llvm.dbg.declare(metadata !{i32 * %Z}, metadata !12), !dbg !14 store i32 23, i32* %Z, !dbg !15 %tmp = load i32* %X, !dbg !16 ; <i32> [#uses=1] %tmp1 = load i32* %Y, !dbg !16 ; <i32> [#uses=1] @@ -879,7 +875,7 @@ entry: ret void, !dbg !18 } -declare void @llvm.dbg.declare({}*, metadata) nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata) nounwind readnone !0 = metadata !{i32 459008, metadata !1, metadata !"X", metadata !3, i32 2, metadata !6}; [ DW_TAG_auto_variable ] @@ -921,7 +917,7 @@ declare void @llvm.dbg.declare({}*, metadata) nounwind readnone
    -call void @llvm.dbg.declare({}* %0, metadata !0), !dbg !7   
    +call void @llvm.dbg.declare(metadata, metadata !0), !dbg !7   
     
    @@ -956,7 +952,7 @@ call void @llvm.dbg.declare({}* %0, metadata !0), !dbg !7
    -call void @llvm.dbg.declare({}* %2, metadata !12), !dbg !14
    +call void @llvm.dbg.declare(metadata, metadata !12), !dbg !14
     
    @@ -1780,7 +1776,7 @@ enum Trees { Chris Lattner
    LLVM Compiler Infrastructure
    - Last modified: $Date: 2010-07-13 18:53:20 +0200 (Tue, 13 Jul 2010) $ + Last modified: $Date: 2011-02-03 01:22:17 +0100 (Thu, 03 Feb 2011) $ diff --git a/docs/TableGenFundamentals.html b/docs/TableGenFundamentals.html index 0bdb6dd62c53..d118332c9939 100644 --- a/docs/TableGenFundamentals.html +++ b/docs/TableGenFundamentals.html @@ -405,8 +405,6 @@ which case the user must specify it explicitly. the symbol table. If the type of 'a' does not match type, TableGen aborts with an error. !cast<string> is a special case in that the argument must be an object defined by a 'def' construct. -
    !nameconcat<type>(a, b)
    -
    Shorthand for !cast<type>(!strconcat(a, b))
    !subst(a, b, c)
    If 'a' and 'b' are of string type or are symbol references, substitute 'b' for 'a' in 'c.' This operation is analogous to $(subst) in GNU make.
    @@ -414,18 +412,18 @@ be an object defined by a 'def' construct.
    For each member 'b' of dag or list 'a' apply operator 'c.' 'b' is a dummy variable that should be declared as a member variable of an instantiated class. This operation is analogous to $(foreach) in GNU make.
    -
    !car(a)
    +
    !head(a)
    The first element of list 'a.'
    -
    !cdr(a)
    +
    !tail(a)
    The 2nd-N elements of list 'a.'
    -
    !null(a)
    +
    !empty(a)
    An integer {0,1} indicating whether list 'a' is empty.
    !if(a,b,c)
    'b' if the result of 'int' or 'bit' operator 'a' is nonzero, 'c' otherwise.
    !eq(a,b)
    -
    Integer one if string a is equal to string b, zero otherwise. This - only operates on string, int and bit objects. Use !cast to +
    'bit 1' if string a is equal to string b, 0 otherwise. This + only operates on string, int and bit objects. Use !cast<string> to compare other types of objects.
    @@ -844,8 +842,7 @@ more ways to factor out commonality from the records, specially if using several levels of multiclass instanciations. This also avoids the need of using "let" expressions within subsequent records inside a multiclass.

    -
    -
    +
     multiclass basic_r<bits<4> opc> {
       let Predicates = [HasSSE2] in {
         def rr : Instruction<opc, "rr">;
    @@ -871,16 +868,17 @@ several levels of multiclass instanciations. This also avoids the need of using
     
     
     
    +
    +

    Expressions used by code generator to describe instructions and isel patterns:

    -
    - +
    (implicit a)
    an implicitly defined physical register. This tells the dag instruction selection emitter the input pattern's extra definitions matches implicit physical register definitions.
    - +
    @@ -906,7 +904,7 @@ This should highlight the APIs in TableGen/Record.h.

    Chris Lattner
    LLVM Compiler Infrastructure
    - Last modified: $Date: 2010-06-21 22:35:09 +0200 (Mon, 21 Jun 2010) $ + Last modified: $Date: 2011-01-07 18:05:37 +0100 (Fri, 07 Jan 2011) $ diff --git a/docs/TestingGuide.html b/docs/TestingGuide.html index c7353ebb0d43..964bdc31247d 100644 --- a/docs/TestingGuide.html +++ b/docs/TestingGuide.html @@ -18,12 +18,14 @@
  • Quick start
  • Regression test structure @@ -40,7 +42,7 @@
  • Configuring External Tests
  • Running different tests
  • Generating test output
  • -
  • Writing custom tests for llvm-test
  • +
  • Writing custom tests for test-suite
  • @@ -141,6 +143,23 @@ generates code.

    + + + + +
    + +

    The test suite contains tests to check quality of debugging information. +The test are written in C based languages or in LLVM assembly language.

    + +

    These tests are compiled and run under a debugger. The debugger output +is checked to validate of debugging information. See README.txt in the +test suite for more information . This test suite is located in the +debuginfo-tests Subversion module.

    + +
    + @@ -153,7 +172,7 @@ generates code.

    The more comprehensive test suite that includes whole programs in C and C++ is in the test-suite module. This module should be checked out to the llvm/projects directory (don't use another name -then the default "test-suite", for then the test suite will be run every time +than the default "test-suite", for then the test suite will be run every time you run make in the main llvm directory). When you configure the llvm module, the test-suite directory will be automatically configured. @@ -237,7 +256,7 @@ programs), first checkout and setup the test-suite module:

    where $LLVM_GCC_DIR is the directory where -you installed llvm-gcc, not it's src or obj +you installed llvm-gcc, not its src or obj dir. The --with-llvmgccdir option assumes that the llvm-gcc-4.2 module was configured with --program-prefix=llvm-, and therefore that the C and C++ @@ -272,6 +291,25 @@ that subdirectory.

    + + + + +

    To run debugging information tests simply checkout the tests inside +clang/test directory.

    + +
    +
    +%cd clang/test
    +% svn co http://llvm.org/svn/llvm-project/debuginfo-tests/trunk debuginfo-tests
    +
    +
    + +

    These tests are already set up to run as part of clang regression tests.

    + + + @@ -338,6 +376,11 @@ that subdirectory.

    shell. Consequently the syntax differs from normal shell script syntax in a few ways. You can specify as many RUN lines as needed.

    +

    lit performs substitution on each RUN line to replace LLVM tool + names with the full paths to the executable built for each tool (in + $(LLVM_OBJ_ROOT)/$(BuildMode)/bin). This ensures that lit does not + invoke any stray LLVM tools in the user's path during testing.

    +

    Each RUN line is executed on its own, distinct from other lines unless its last character is \. This continuation character causes the RUN line to be concatenated with the next one. In this way you can build up long @@ -561,7 +604,7 @@ name="FileCheck-CHECK-NEXT">The "CHECK-NEXT:" directive

    Sometimes you want to match lines and would like to verify that matches -happen on exactly consequtive lines with no other lines in between them. In +happen on exactly consecutive lines with no other lines in between them. In this case, you can use CHECK: and CHECK-NEXT: directives to specify this. If you specified a custom check prefix, just use "<PREFIX>-NEXT:". For example, something like this works as you'd expect:

    @@ -870,34 +913,34 @@ want tested and run gmake there. Alternatively, you can run a different test using the TEST variable to change what tests or run on the selected programs (see below for more info).

    -

    In addition for testing correctness, the llvm-test directory also +

    In addition for testing correctness, the test-suite directory also performs timing tests of various LLVM optimizations. It also records compilation times for the compilers and the JIT. This information can be used to compare the effectiveness of LLVM's optimizations and code generation.

    -

    llvm-test tests are divided into three types of tests: MultiSource, +

    test-suite tests are divided into three types of tests: MultiSource, SingleSource, and External.

      -
    • llvm-test/SingleSource +
    • test-suite/SingleSource

      The SingleSource directory contains test programs that are only a single source file in size. These are usually small benchmark programs or small programs that calculate a particular value. Several such programs are grouped together in each directory.

    • -
    • llvm-test/MultiSource +
    • test-suite/MultiSource

      The MultiSource directory contains subdirectories which contain entire programs with multiple source files. Large benchmarks and whole applications go here.

    • -
    • llvm-test/External +
    • test-suite/External

      The External directory contains Makefiles for building code that is external to (i.e., not distributed with) LLVM. The most prominent members of this directory are the SPEC 95 and SPEC 2000 benchmark suites. The External directory does not contain these actual tests, but only the Makefiles that know how to properly compile these programs from somewhere else. The presence and -location of these external programs is configured by the llvm-test +location of these external programs is configured by the test-suite configure script.

    @@ -1084,9 +1127,9 @@ many times it triggers. First thing you should do is add an LLVM will tally counts of things you care about.

    Following this, you can set up a test and a report that collects these and -formats them for easy viewing. This consists of two files, an +formats them for easy viewing. This consists of two files, a "test-suite/TEST.XXX.Makefile" fragment (where XXX is the name of your -test) and an "llvm-test/TEST.XXX.report" file that indicates how to +test) and a "test-suite/TEST.XXX.report" file that indicates how to format the output into a table. There are many example reports of various levels of sophistication included with the test suite, and the framework is very general.

    @@ -1147,7 +1190,7 @@ example reports that can do fancy stuff.

    John T. Criswell, Daniel Dunbar, Reid Spencer, and Tanya Lattner
    The LLVM Compiler Infrastructure
    - Last modified: $Date: 2010-08-02 03:20:23 +0200 (Mon, 02 Aug 2010) $ + Last modified: $Date: 2011-02-15 10:23:02 +0100 (Tue, 15 Feb 2011) $ diff --git a/docs/UsingLibraries.html b/docs/UsingLibraries.html index e7a1d3d4b60f..ea28dbec0cc4 100644 --- a/docs/UsingLibraries.html +++ b/docs/UsingLibraries.html @@ -23,7 +23,11 @@

    Written by Reid Spencer

    -

    Warning: This document is out of date, please see llvm-config for more information.

    +

    Warning: This document is out of date, for more + information please + see llvm-config or, + if you use CMake, the CMake LLVM + guide.

    @@ -432,7 +436,7 @@ Reid SpencerThe LLVM Compiler Infrastructure -
    Last modified: $Date: 2010-05-07 02:28:04 +0200 (Fri, 07 May 2010) $ +
    Last modified: $Date: 2010-09-17 02:30:52 +0200 (Fri, 17 Sep 2010) $ + + +
    + +

    RegionPass is similar to LoopPass, +but executes on each single entry single exit region in the function. +RegionPass processes regions in nested order such that the outer most +region is processed last.

    + +

    RegionPass subclasses are allowed to update the region tree by using +the RGPassManager interface. You may overload three virtual methods of +RegionPass to implementing your own region pass is usually. All these +methods should return true if they modified the program, or false if they didn not. +

    +
    + + + + +
    + +
    +  virtual bool doInitialization(Region *, RGPassManager &RGM);
    +
    + +

    The doInitialization method is designed to do simple initialization +type of stuff that does not depend on the functions being processed. The +doInitialization method call is not scheduled to overlap with any +other pass executions (thus it should be very fast). RPPassManager +interface should be used to access Function or Module level analysis +information.

    + +
    + + + + + +
    + +
    +  virtual bool runOnRegion(Region *, RGPassManager &RGM) = 0;
    +

    + +

    The runOnRegion method must be implemented by your subclass to do +the transformation or analysis work of your pass. As usual, a true value should +be returned if the region is modified. RGPassManager interface +should be used to update region tree.

    + +
    + + + + +
    + +
    +  virtual bool doFinalization();
    +
    + +

    The doFinalization method is an infrequently used method that is +called when the pass framework has finished calling runOnRegion for every region in the +program being compiled.

    + +
    + @@ -967,10 +1055,10 @@ remember, you may not modify the LLVM Function or its contents from a pass registration works, and discussed some of the reasons that it is used and what it does. Here we discuss how and why passes are registered.

    -

    As we saw above, passes are registered with the INITIALIZE_PASS -macro. The first parameter is the name of the pass that is to be used on +

    As we saw above, passes are registered with the RegisterPass +template. The template parameter is the name of the pass that is to be used on the command line to specify that the pass should be added to a program (for -example, with opt or bugpoint). The second argument is the +example, with opt or bugpoint). The first argument is the name of the pass, which is to be used for the -help output of programs, as well as for debug output generated by the --debug-pass option.

    @@ -1386,7 +1474,7 @@ results as soon as they are no longer needed.
  • Pipeline the execution of passes on the program - The PassManager attempts to get better cache and memory usage behavior out of a series of passes by pipelining the passes together. This means that, given -a series of consequtive FunctionPass's, it +a series of consecutive FunctionPass's, it will execute all of the FunctionPass's on the first function, then all of the FunctionPasses on the second function, @@ -1833,7 +1921,7 @@ Despite that, we have kept the LLVM passes SMP ready, and you should too.

    Chris Lattner
    The LLVM Compiler Infrastructure
    - Last modified: $Date: 2010-07-22 01:07:00 +0200 (Thu, 22 Jul 2010) $ + Last modified: $Date: 2011-02-15 10:23:02 +0100 (Tue, 15 Feb 2011) $ diff --git a/docs/tutorial/LangImpl3.html b/docs/tutorial/LangImpl3.html index 6cd33b010adc..a320ff7e9064 100644 --- a/docs/tutorial/LangImpl3.html +++ b/docs/tutorial/LangImpl3.html @@ -353,8 +353,8 @@ above.

    The Module symbol table works just like the Function symbol table when it -comes to name conflicts: if a new function is created with a name was previously -added to the symbol table, it will get implicitly renamed when added to the +comes to name conflicts: if a new function is created with a name that was previously +added to the symbol table, the new function will get implicitly renamed when added to the Module. The code above exploits this fact to determine if there was a previous definition of this function.

    @@ -1263,7 +1263,7 @@ int main() { Chris Lattner
    The LLVM Compiler Infrastructure
    - Last modified: $Date: 2010-09-01 22:09:20 +0200 (Wed, 01 Sep 2010) $ + Last modified: $Date: 2011-02-15 01:24:32 +0100 (Tue, 15 Feb 2011) $ diff --git a/docs/tutorial/LangImpl4.html b/docs/tutorial/LangImpl4.html index d286364d2a56..a2511d959e7b 100644 --- a/docs/tutorial/LangImpl4.html +++ b/docs/tutorial/LangImpl4.html @@ -176,6 +176,8 @@ add a set of optimizations to run. The code looks like this:

    // Set up the optimizer pipeline. Start with registering info about how the // target lays out data structures. OurFPM.add(new TargetData(*TheExecutionEngine->getTargetData())); + // Provide basic AliasAnalysis support for GVN. + OurFPM.add(createBasicAliasAnalysisPass()); // Do simple "peephole" optimizations and bit-twiddling optzns. OurFPM.add(createInstructionCombiningPass()); // Reassociate expressions. @@ -507,6 +509,7 @@ at runtime.

    #include "llvm/Module.h" #include "llvm/PassManager.h" #include "llvm/Analysis/Verifier.h" +#include "llvm/Analysis/Passes.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetSelect.h" #include "llvm/Transforms/Scalar.h" @@ -1086,6 +1089,8 @@ int main() { // Set up the optimizer pipeline. Start with registering info about how the // target lays out data structures. OurFPM.add(new TargetData(*TheExecutionEngine->getTargetData())); + // Provide basic AliasAnalysis support for GVN. + OurFPM.add(createBasicAliasAnalysisPass()); // Do simple "peephole" optimizations and bit-twiddling optzns. OurFPM.add(createInstructionCombiningPass()); // Reassociate expressions. @@ -1126,7 +1131,7 @@ int main() { Chris Lattner
    The LLVM Compiler Infrastructure
    - Last modified: $Date: 2010-06-14 08:09:39 +0200 (Mon, 14 Jun 2010) $ + Last modified: $Date: 2010-11-16 18:28:22 +0100 (Tue, 16 Nov 2010) $ diff --git a/docs/tutorial/LangImpl5.html b/docs/tutorial/LangImpl5.html index 4450f2e3a11a..d2c3bd03dc4e 100644 --- a/docs/tutorial/LangImpl5.html +++ b/docs/tutorial/LangImpl5.html @@ -907,6 +907,7 @@ if/then/else and for expressions.. To build this example, use: #include "llvm/Module.h" #include "llvm/PassManager.h" #include "llvm/Analysis/Verifier.h" +#include "llvm/Analysis/Passes.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetSelect.h" #include "llvm/Transforms/Scalar.h" @@ -1731,6 +1732,8 @@ int main() { // Set up the optimizer pipeline. Start with registering info about how the // target lays out data structures. OurFPM.add(new TargetData(*TheExecutionEngine->getTargetData())); + // Provide basic AliasAnalysis support for GVN. + OurFPM.add(createBasicAliasAnalysisPass()); // Do simple "peephole" optimizations and bit-twiddling optzns. OurFPM.add(createInstructionCombiningPass()); // Reassociate expressions. @@ -1771,7 +1774,7 @@ int main() { Chris Lattner
    The LLVM Compiler Infrastructure
    - Last modified: $Date: 2010-09-01 22:09:20 +0200 (Wed, 01 Sep 2010) $ + Last modified: $Date: 2010-11-16 18:28:22 +0100 (Tue, 16 Nov 2010) $ diff --git a/docs/tutorial/LangImpl6.html b/docs/tutorial/LangImpl6.html index c6a0b8a7d603..7ddf3a099cbc 100644 --- a/docs/tutorial/LangImpl6.html +++ b/docs/tutorial/LangImpl6.html @@ -826,6 +826,7 @@ if/then/else and for expressions.. To build this example, use: #include "llvm/Module.h" #include "llvm/PassManager.h" #include "llvm/Analysis/Verifier.h" +#include "llvm/Analysis/Passes.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetSelect.h" #include "llvm/Transforms/Scalar.h" @@ -1768,6 +1769,8 @@ int main() { // Set up the optimizer pipeline. Start with registering info about how the // target lays out data structures. OurFPM.add(new TargetData(*TheExecutionEngine->getTargetData())); + // Provide basic AliasAnalysis support for GVN. + OurFPM.add(createBasicAliasAnalysisPass()); // Do simple "peephole" optimizations and bit-twiddling optzns. OurFPM.add(createInstructionCombiningPass()); // Reassociate expressions. @@ -1808,7 +1811,7 @@ int main() { Chris Lattner
    The LLVM Compiler Infrastructure
    - Last modified: $Date: 2010-09-01 22:09:20 +0200 (Wed, 01 Sep 2010) $ + Last modified: $Date: 2010-11-16 18:28:22 +0100 (Tue, 16 Nov 2010) $ diff --git a/docs/tutorial/LangImpl7.html b/docs/tutorial/LangImpl7.html index 1ec99b15bf5c..3b36129d6716 100644 --- a/docs/tutorial/LangImpl7.html +++ b/docs/tutorial/LangImpl7.html @@ -1009,6 +1009,7 @@ variables and var/in support. To build this example, use: #include "llvm/Module.h" #include "llvm/PassManager.h" #include "llvm/Analysis/Verifier.h" +#include "llvm/Analysis/Passes.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetSelect.h" #include "llvm/Transforms/Scalar.h" @@ -2116,6 +2117,8 @@ int main() { // Set up the optimizer pipeline. Start with registering info about how the // target lays out data structures. OurFPM.add(new TargetData(*TheExecutionEngine->getTargetData())); + // Provide basic AliasAnalysis support for GVN. + OurFPM.add(createBasicAliasAnalysisPass()); // Promote allocas to registers. OurFPM.add(createPromoteMemoryToRegisterPass()); // Do simple "peephole" optimizations and bit-twiddling optzns. @@ -2158,7 +2161,7 @@ int main() { Chris Lattner
    The LLVM Compiler Infrastructure
    - Last modified: $Date: 2010-09-01 22:09:20 +0200 (Wed, 01 Sep 2010) $ + Last modified: $Date: 2010-11-16 18:28:22 +0100 (Tue, 16 Nov 2010) $ diff --git a/docs/tutorial/OCamlLangImpl7.html b/docs/tutorial/OCamlLangImpl7.html index ac31fbfc0766..a9fcd704cf8b 100644 --- a/docs/tutorial/OCamlLangImpl7.html +++ b/docs/tutorial/OCamlLangImpl7.html @@ -30,7 +30,7 @@
  • Full Code Listing
  • -
  • Chapter 8: Conclusion and other useful LLVM +
  • Chapter 8: Conclusion and other useful LLVM tidbits
  • @@ -1901,7 +1901,7 @@ extern double printd(double X) { Chris Lattner
    The LLVM Compiler Infrastructure
    Erick Tryzelaar
    - Last modified: $Date: 2010-05-28 19:07:41 +0200 (Fri, 28 May 2010) $ + Last modified: $Date: 2011-01-01 04:27:43 +0100 (Sat, 01 Jan 2011) $ diff --git a/docs/tutorial/OCamlLangImpl8.html b/docs/tutorial/OCamlLangImpl8.html new file mode 100644 index 000000000000..64a62002c4cc --- /dev/null +++ b/docs/tutorial/OCamlLangImpl8.html @@ -0,0 +1,365 @@ + + + + + Kaleidoscope: Conclusion and other useful LLVM tidbits + + + + + + + +
    Kaleidoscope: Conclusion and other useful LLVM + tidbits
    + + + + +
    +

    Written by Chris Lattner

    +
    + + + + + +
    + +

    Welcome to the the final chapter of the "Implementing a +language with LLVM" tutorial. In the course of this tutorial, we have grown +our little Kaleidoscope language from being a useless toy, to being a +semi-interesting (but probably still useless) toy. :)

    + +

    It is interesting to see how far we've come, and how little code it has +taken. We built the entire lexer, parser, AST, code generator, and an +interactive run-loop (with a JIT!) by-hand in under 700 lines of +(non-comment/non-blank) code.

    + +

    Our little language supports a couple of interesting features: it supports +user defined binary and unary operators, it uses JIT compilation for immediate +evaluation, and it supports a few control flow constructs with SSA construction. +

    + +

    Part of the idea of this tutorial was to show you how easy and fun it can be +to define, build, and play with languages. Building a compiler need not be a +scary or mystical process! Now that you've seen some of the basics, I strongly +encourage you to take the code and hack on it. For example, try adding:

    + +
      +
    • global variables - While global variables have questional value in +modern software engineering, they are often useful when putting together quick +little hacks like the Kaleidoscope compiler itself. Fortunately, our current +setup makes it very easy to add global variables: just have value lookup check +to see if an unresolved variable is in the global variable symbol table before +rejecting it. To create a new global variable, make an instance of the LLVM +GlobalVariable class.
    • + +
    • typed variables - Kaleidoscope currently only supports variables of +type double. This gives the language a very nice elegance, because only +supporting one type means that you never have to specify types. Different +languages have different ways of handling this. The easiest way is to require +the user to specify types for every variable definition, and record the type +of the variable in the symbol table along with its Value*.
    • + +
    • arrays, structs, vectors, etc - Once you add types, you can start +extending the type system in all sorts of interesting ways. Simple arrays are +very easy and are quite useful for many different applications. Adding them is +mostly an exercise in learning how the LLVM getelementptr instruction works: it +is so nifty/unconventional, it has its own FAQ! If you add support +for recursive types (e.g. linked lists), make sure to read the section in the LLVM +Programmer's Manual that describes how to construct them.
    • + +
    • standard runtime - Our current language allows the user to access +arbitrary external functions, and we use it for things like "printd" and +"putchard". As you extend the language to add higher-level constructs, often +these constructs make the most sense if they are lowered to calls into a +language-supplied runtime. For example, if you add hash tables to the language, +it would probably make sense to add the routines to a runtime, instead of +inlining them all the way.
    • + +
    • memory management - Currently we can only access the stack in +Kaleidoscope. It would also be useful to be able to allocate heap memory, +either with calls to the standard libc malloc/free interface or with a garbage +collector. If you would like to use garbage collection, note that LLVM fully +supports Accurate Garbage Collection +including algorithms that move objects and need to scan/update the stack.
    • + +
    • debugger support - LLVM supports generation of DWARF Debug info which is understood by +common debuggers like GDB. Adding support for debug info is fairly +straightforward. The best way to understand it is to compile some C/C++ code +with "llvm-gcc -g -O0" and taking a look at what it produces.
    • + +
    • exception handling support - LLVM supports generation of zero cost exceptions which interoperate +with code compiled in other languages. You could also generate code by +implicitly making every function return an error value and checking it. You +could also make explicit use of setjmp/longjmp. There are many different ways +to go here.
    • + +
    • object orientation, generics, database access, complex numbers, +geometric programming, ... - Really, there is +no end of crazy features that you can add to the language.
    • + +
    • unusual domains - We've been talking about applying LLVM to a domain +that many people are interested in: building a compiler for a specific language. +However, there are many other domains that can use compiler technology that are +not typically considered. For example, LLVM has been used to implement OpenGL +graphics acceleration, translate C++ code to ActionScript, and many other +cute and clever things. Maybe you will be the first to JIT compile a regular +expression interpreter into native code with LLVM?
    • + +
    + +

    +Have fun - try doing something crazy and unusual. Building a language like +everyone else always has, is much less fun than trying something a little crazy +or off the wall and seeing how it turns out. If you get stuck or want to talk +about it, feel free to email the llvmdev mailing +list: it has lots of people who are interested in languages and are often +willing to help out. +

    + +

    Before we end this tutorial, I want to talk about some "tips and tricks" for generating +LLVM IR. These are some of the more subtle things that may not be obvious, but +are very useful if you want to take advantage of LLVM's capabilities.

    + +
    + + + + + +
    + +

    We have a couple common questions about code in the LLVM IR form - lets just +get these out of the way right now, shall we?

    + +
    + + + + + +
    + +

    Kaleidoscope is an example of a "portable language": any program written in +Kaleidoscope will work the same way on any target that it runs on. Many other +languages have this property, e.g. lisp, java, haskell, javascript, python, etc +(note that while these languages are portable, not all their libraries are).

    + +

    One nice aspect of LLVM is that it is often capable of preserving target +independence in the IR: you can take the LLVM IR for a Kaleidoscope-compiled +program and run it on any target that LLVM supports, even emitting C code and +compiling that on targets that LLVM doesn't support natively. You can trivially +tell that the Kaleidoscope compiler generates target-independent code because it +never queries for any target-specific information when generating code.

    + +

    The fact that LLVM provides a compact, target-independent, representation for +code gets a lot of people excited. Unfortunately, these people are usually +thinking about C or a language from the C family when they are asking questions +about language portability. I say "unfortunately", because there is really no +way to make (fully general) C code portable, other than shipping the source code +around (and of course, C source code is not actually portable in general +either - ever port a really old application from 32- to 64-bits?).

    + +

    The problem with C (again, in its full generality) is that it is heavily +laden with target specific assumptions. As one simple example, the preprocessor +often destructively removes target-independence from the code when it processes +the input text:

    + +
    +
    +#ifdef __i386__
    +  int X = 1;
    +#else
    +  int X = 42;
    +#endif
    +
    +
    + +

    While it is possible to engineer more and more complex solutions to problems +like this, it cannot be solved in full generality in a way that is better than shipping +the actual source code.

    + +

    That said, there are interesting subsets of C that can be made portable. If +you are willing to fix primitive types to a fixed size (say int = 32-bits, +and long = 64-bits), don't care about ABI compatibility with existing binaries, +and are willing to give up some other minor features, you can have portable +code. This can make sense for specialized domains such as an +in-kernel language.

    + +
    + + + + + +
    + +

    Many of the languages above are also "safe" languages: it is impossible for +a program written in Java to corrupt its address space and crash the process +(assuming the JVM has no bugs). +Safety is an interesting property that requires a combination of language +design, runtime support, and often operating system support.

    + +

    It is certainly possible to implement a safe language in LLVM, but LLVM IR +does not itself guarantee safety. The LLVM IR allows unsafe pointer casts, +use after free bugs, buffer over-runs, and a variety of other problems. Safety +needs to be implemented as a layer on top of LLVM and, conveniently, several +groups have investigated this. Ask on the llvmdev mailing +list if you are interested in more details.

    + +
    + + + + + +
    + +

    One thing about LLVM that turns off many people is that it does not solve all +the world's problems in one system (sorry 'world hunger', someone else will have +to solve you some other day). One specific complaint is that people perceive +LLVM as being incapable of performing high-level language-specific optimization: +LLVM "loses too much information".

    + +

    Unfortunately, this is really not the place to give you a full and unified +version of "Chris Lattner's theory of compiler design". Instead, I'll make a +few observations:

    + +

    First, you're right that LLVM does lose information. For example, as of this +writing, there is no way to distinguish in the LLVM IR whether an SSA-value came +from a C "int" or a C "long" on an ILP32 machine (other than debug info). Both +get compiled down to an 'i32' value and the information about what it came from +is lost. The more general issue here, is that the LLVM type system uses +"structural equivalence" instead of "name equivalence". Another place this +surprises people is if you have two types in a high-level language that have the +same structure (e.g. two different structs that have a single int field): these +types will compile down into a single LLVM type and it will be impossible to +tell what it came from.

    + +

    Second, while LLVM does lose information, LLVM is not a fixed target: we +continue to enhance and improve it in many different ways. In addition to +adding new features (LLVM did not always support exceptions or debug info), we +also extend the IR to capture important information for optimization (e.g. +whether an argument is sign or zero extended, information about pointers +aliasing, etc). Many of the enhancements are user-driven: people want LLVM to +include some specific feature, so they go ahead and extend it.

    + +

    Third, it is possible and easy to add language-specific +optimizations, and you have a number of choices in how to do it. As one trivial +example, it is easy to add language-specific optimization passes that +"know" things about code compiled for a language. In the case of the C family, +there is an optimization pass that "knows" about the standard C library +functions. If you call "exit(0)" in main(), it knows that it is safe to +optimize that into "return 0;" because C specifies what the 'exit' +function does.

    + +

    In addition to simple library knowledge, it is possible to embed a variety of +other language-specific information into the LLVM IR. If you have a specific +need and run into a wall, please bring the topic up on the llvmdev list. At the +very worst, you can always treat LLVM as if it were a "dumb code generator" and +implement the high-level optimizations you desire in your front-end, on the +language-specific AST. +

    + +
    + + + + + +
    + +

    There is a variety of useful tips and tricks that you come to know after +working on/with LLVM that aren't obvious at first glance. Instead of letting +everyone rediscover them, this section talks about some of these issues.

    + +
    + + + + + +
    + +

    One interesting thing that comes up, if you are trying to keep the code +generated by your compiler "target independent", is that you often need to know +the size of some LLVM type or the offset of some field in an llvm structure. +For example, you might need to pass the size of a type into a function that +allocates memory.

    + +

    Unfortunately, this can vary widely across targets: for example the width of +a pointer is trivially target-specific. However, there is a clever +way to use the getelementptr instruction that allows you to compute this +in a portable way.

    + +
    + + + + + +
    + +

    Some languages want to explicitly manage their stack frames, often so that +they are garbage collected or to allow easy implementation of closures. There +are often better ways to implement these features than explicit stack frames, +but LLVM +does support them, if you want. It requires your front-end to convert the +code into Continuation +Passing Style and the use of tail calls (which LLVM also supports).

    + +
    + + +
    +
    + Valid CSS! + Valid HTML 4.01! + + Chris Lattner
    + The LLVM Compiler Infrastructure
    + Last modified: $Date$ +
    + + diff --git a/docs/tutorial/index.html b/docs/tutorial/index.html index 250b533f3f8a..11dd5e2d732a 100644 --- a/docs/tutorial/index.html +++ b/docs/tutorial/index.html @@ -35,7 +35,7 @@
  • Extending the language: control flow
  • Extending the language: user-defined operators
  • Extending the language: mutable variables / SSA construction
  • -
  • Conclusion and other useful LLVM tidbits
  • +
  • Conclusion and other useful LLVM tidbits
  • Advanced Topics
      diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index f60c0eda0306..54ee6cc3a3a4 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -8,9 +8,6 @@ if( NOT WIN32 ) add_subdirectory(ExceptionDemo) endif() -include(CheckIncludeFile) -check_include_file(pthread.h HAVE_PTHREAD_H) - if( HAVE_PTHREAD_H ) add_subdirectory(ParallelJIT) endif( HAVE_PTHREAD_H ) diff --git a/examples/ExceptionDemo/CMakeLists.txt b/examples/ExceptionDemo/CMakeLists.txt index d66191556843..88c9ab7c1816 100644 --- a/examples/ExceptionDemo/CMakeLists.txt +++ b/examples/ExceptionDemo/CMakeLists.txt @@ -1,4 +1,5 @@ set(LLVM_LINK_COMPONENTS jit nativecodegen) +set(LLVM_REQUIRES_EH 1) add_llvm_example(ExceptionDemo ExceptionDemo.cpp diff --git a/examples/ExceptionDemo/ExceptionDemo.cpp b/examples/ExceptionDemo/ExceptionDemo.cpp index e09c990f8a9f..95ccd24a6894 100644 --- a/examples/ExceptionDemo/ExceptionDemo.cpp +++ b/examples/ExceptionDemo/ExceptionDemo.cpp @@ -1974,6 +1974,9 @@ int main(int argc, char* argv[]) { // Optimizations turned on #ifdef ADD_OPT_PASSES + // Basic AliasAnslysis support for GVN. + fpm.add(llvm::createBasicAliasAnalysisPass()); + // Promote allocas to registers. fpm.add(llvm::createPromoteMemoryToRegisterPass()); diff --git a/examples/Kaleidoscope/Chapter4/toy.cpp b/examples/Kaleidoscope/Chapter4/toy.cpp index 327c5c0591c0..a50d2a43dd28 100644 --- a/examples/Kaleidoscope/Chapter4/toy.cpp +++ b/examples/Kaleidoscope/Chapter4/toy.cpp @@ -5,6 +5,7 @@ #include "llvm/Module.h" #include "llvm/PassManager.h" #include "llvm/Analysis/Verifier.h" +#include "llvm/Analysis/Passes.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetSelect.h" #include "llvm/Transforms/Scalar.h" @@ -584,6 +585,8 @@ int main() { // Set up the optimizer pipeline. Start with registering info about how the // target lays out data structures. OurFPM.add(new TargetData(*TheExecutionEngine->getTargetData())); + // Provide basic AliasAnalysis support for GVN. + OurFPM.add(createBasicAliasAnalysisPass()); // Do simple "peephole" optimizations and bit-twiddling optzns. OurFPM.add(createInstructionCombiningPass()); // Reassociate expressions. diff --git a/examples/Kaleidoscope/Chapter5/toy.cpp b/examples/Kaleidoscope/Chapter5/toy.cpp index c98ee88c394f..26b3db66202f 100644 --- a/examples/Kaleidoscope/Chapter5/toy.cpp +++ b/examples/Kaleidoscope/Chapter5/toy.cpp @@ -5,6 +5,7 @@ #include "llvm/Module.h" #include "llvm/PassManager.h" #include "llvm/Analysis/Verifier.h" +#include "llvm/Analysis/Passes.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetSelect.h" #include "llvm/Transforms/Scalar.h" @@ -829,6 +830,8 @@ int main() { // Set up the optimizer pipeline. Start with registering info about how the // target lays out data structures. OurFPM.add(new TargetData(*TheExecutionEngine->getTargetData())); + // Provide basic AliasAnalysis support for GVN. + OurFPM.add(createBasicAliasAnalysisPass()); // Do simple "peephole" optimizations and bit-twiddling optzns. OurFPM.add(createInstructionCombiningPass()); // Reassociate expressions. diff --git a/examples/Kaleidoscope/Chapter6/toy.cpp b/examples/Kaleidoscope/Chapter6/toy.cpp index b7b8738f587d..838125ae77dc 100644 --- a/examples/Kaleidoscope/Chapter6/toy.cpp +++ b/examples/Kaleidoscope/Chapter6/toy.cpp @@ -5,6 +5,7 @@ #include "llvm/Module.h" #include "llvm/PassManager.h" #include "llvm/Analysis/Verifier.h" +#include "llvm/Analysis/Passes.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetSelect.h" #include "llvm/Transforms/Scalar.h" @@ -947,6 +948,8 @@ int main() { // Set up the optimizer pipeline. Start with registering info about how the // target lays out data structures. OurFPM.add(new TargetData(*TheExecutionEngine->getTargetData())); + // Provide basic AliasAnalysis support for GVN. + OurFPM.add(createBasicAliasAnalysisPass()); // Do simple "peephole" optimizations and bit-twiddling optzns. OurFPM.add(createInstructionCombiningPass()); // Reassociate expressions. diff --git a/examples/Kaleidoscope/Chapter7/CMakeLists.txt b/examples/Kaleidoscope/Chapter7/CMakeLists.txt index 9b8227c69340..da3839843bd0 100644 --- a/examples/Kaleidoscope/Chapter7/CMakeLists.txt +++ b/examples/Kaleidoscope/Chapter7/CMakeLists.txt @@ -1,4 +1,5 @@ set(LLVM_LINK_COMPONENTS core jit interpreter native) +set(LLVM_REQUIRES_RTTI 1) add_llvm_example(Kaleidoscope-Ch7 toy.cpp diff --git a/examples/Kaleidoscope/Chapter7/toy.cpp b/examples/Kaleidoscope/Chapter7/toy.cpp index 0cf7869d02f8..e63578f57e6c 100644 --- a/examples/Kaleidoscope/Chapter7/toy.cpp +++ b/examples/Kaleidoscope/Chapter7/toy.cpp @@ -5,6 +5,7 @@ #include "llvm/Module.h" #include "llvm/PassManager.h" #include "llvm/Analysis/Verifier.h" +#include "llvm/Analysis/Passes.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetSelect.h" #include "llvm/Transforms/Scalar.h" @@ -1111,6 +1112,8 @@ int main() { // Set up the optimizer pipeline. Start with registering info about how the // target lays out data structures. OurFPM.add(new TargetData(*TheExecutionEngine->getTargetData())); + // Provide basic AliasAnalysis support for GVN. + OurFPM.add(createBasicAliasAnalysisPass()); // Promote allocas to registers. OurFPM.add(createPromoteMemoryToRegisterPass()); // Do simple "peephole" optimizations and bit-twiddling optzns. diff --git a/examples/Makefile b/examples/Makefile index bc09b8e0473b..50a6db76aa25 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -10,8 +10,7 @@ LEVEL=.. include $(LEVEL)/Makefile.config -PARALLEL_DIRS:= BrainF Fibonacci HowToUseJIT Kaleidoscope ModuleMaker \ - TracingBrainF +PARALLEL_DIRS:= BrainF Fibonacci HowToUseJIT Kaleidoscope ModuleMaker ifeq ($(HAVE_PTHREAD),1) PARALLEL_DIRS += ParallelJIT diff --git a/examples/ModuleMaker/README.txt b/examples/ModuleMaker/README.txt index ecbe30e4cfe8..66a5d3fe0b1a 100644 --- a/examples/ModuleMaker/README.txt +++ b/examples/ModuleMaker/README.txt @@ -4,5 +4,5 @@ This project is an extremely simple example of using some simple pieces of the LLVM API. The actual executable generated by this project simply emits an -LLVM bytecode file to standard output. It is designed to show some basic +LLVM bitcode file to standard output. It is designed to show some basic usage of LLVM APIs, and how to link to LLVM libraries. diff --git a/examples/OCaml-Kaleidoscope/Chapter6/Makefile b/examples/OCaml-Kaleidoscope/Chapter6/Makefile index 831213863a6e..21f0c53df4b9 100644 --- a/examples/OCaml-Kaleidoscope/Chapter6/Makefile +++ b/examples/OCaml-Kaleidoscope/Chapter6/Makefile @@ -20,6 +20,15 @@ UsedOcamLibs := llvm llvm_analysis llvm_executionengine llvm_target \ OCAMLCFLAGS += -pp camlp4of +OcamlSources1 = \ + $(PROJ_SRC_DIR)/ast.ml \ + $(PROJ_SRC_DIR)/parser.ml \ + $(PROJ_SRC_DIR)/codegen.ml \ + $(PROJ_SRC_DIR)/lexer.ml \ + $(PROJ_SRC_DIR)/token.ml \ + $(PROJ_SRC_DIR)/toplevel.ml \ + $(PROJ_SRC_DIR)/toy.ml + ExcludeSources = $(PROJ_SRC_DIR)/myocamlbuild.ml include $(LEVEL)/bindings/ocaml/Makefile.ocaml diff --git a/examples/OCaml-Kaleidoscope/Chapter7/Makefile b/examples/OCaml-Kaleidoscope/Chapter7/Makefile index ddf667b0e123..99686e17ea80 100644 --- a/examples/OCaml-Kaleidoscope/Chapter7/Makefile +++ b/examples/OCaml-Kaleidoscope/Chapter7/Makefile @@ -20,6 +20,15 @@ UsedOcamLibs := llvm llvm_analysis llvm_executionengine llvm_target \ OCAMLCFLAGS += -pp camlp4of +OcamlSources1 = \ + $(PROJ_SRC_DIR)/ast.ml \ + $(PROJ_SRC_DIR)/parser.ml \ + $(PROJ_SRC_DIR)/codegen.ml \ + $(PROJ_SRC_DIR)/lexer.ml \ + $(PROJ_SRC_DIR)/token.ml \ + $(PROJ_SRC_DIR)/toplevel.ml \ + $(PROJ_SRC_DIR)/toy.ml + ExcludeSources = $(PROJ_SRC_DIR)/myocamlbuild.ml include $(LEVEL)/bindings/ocaml/Makefile.ocaml diff --git a/include/llvm-c/Core.h b/include/llvm-c/Core.h index 75cee7d203a1..39c3cb40117c 100644 --- a/include/llvm-c/Core.h +++ b/include/llvm-c/Core.h @@ -33,13 +33,14 @@ #ifndef LLVM_C_CORE_H #define LLVM_C_CORE_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #ifdef __cplusplus /* Need these includes to support the LLVM 'cast' template for the C++ 'wrap' and 'unwrap' conversion functions. */ #include "llvm/Module.h" +#include "llvm/PassRegistry.h" #include "llvm/Support/IRBuilder.h" extern "C" { @@ -92,6 +93,9 @@ typedef struct LLVMOpaqueMemoryBuffer *LLVMMemoryBufferRef; /** See the llvm::PassManagerBase class. */ typedef struct LLVMOpaquePassManager *LLVMPassManagerRef; +/** See the llvm::PassRegistry class. */ +typedef struct LLVMOpaquePassRegistry *LLVMPassRegistryRef; + /** Used to get the users and usees of a Value. See the llvm::Use class. */ typedef struct LLVMOpaqueUse *LLVMUseRef; @@ -204,7 +208,8 @@ typedef enum { LLVMPointerTypeKind, /**< Pointers */ LLVMOpaqueTypeKind, /**< Opaque: type with unknown structure */ LLVMVectorTypeKind, /**< SIMD 'packed' format, or other vector type */ - LLVMMetadataTypeKind /**< Metadata */ + LLVMMetadataTypeKind, /**< Metadata */ + LLVMX86_MMXTypeKind /**< X86 MMX */ } LLVMTypeKind; typedef enum { @@ -317,6 +322,7 @@ void LLVMSetTarget(LLVMModuleRef M, const char *Triple); LLVMBool LLVMAddTypeName(LLVMModuleRef M, const char *Name, LLVMTypeRef Ty); void LLVMDeleteTypeName(LLVMModuleRef M, const char *Name); LLVMTypeRef LLVMGetTypeByName(LLVMModuleRef M, const char *Name); +const char *LLVMGetTypeName(LLVMModuleRef M, LLVMTypeRef Ty); /** See Module::dump. */ void LLVMDumpModule(LLVMModuleRef M); @@ -324,6 +330,9 @@ void LLVMDumpModule(LLVMModuleRef M); /** See Module::setModuleInlineAsm. */ void LLVMSetModuleInlineAsm(LLVMModuleRef M, const char *Asm); +/** See Module::getContext. */ +LLVMContextRef LLVMGetModuleContext(LLVMModuleRef M); + /*===-- Types -------------------------------------------------------------===*/ /* LLVM types conform to the following hierarchy: @@ -408,10 +417,12 @@ unsigned LLVMGetVectorSize(LLVMTypeRef VectorTy); LLVMTypeRef LLVMVoidTypeInContext(LLVMContextRef C); LLVMTypeRef LLVMLabelTypeInContext(LLVMContextRef C); LLVMTypeRef LLVMOpaqueTypeInContext(LLVMContextRef C); +LLVMTypeRef LLVMX86MMXTypeInContext(LLVMContextRef C); LLVMTypeRef LLVMVoidType(void); LLVMTypeRef LLVMLabelType(void); LLVMTypeRef LLVMOpaqueType(void); +LLVMTypeRef LLVMX86MMXType(void); /* Operations on type handles */ LLVMTypeHandleRef LLVMCreateTypeHandle(LLVMTypeRef PotentiallyAbstractTy); @@ -540,6 +551,9 @@ LLVMValueRef LLVMMDNode(LLVMValueRef *Vals, unsigned Count); /* Operations on scalar constants */ LLVMValueRef LLVMConstInt(LLVMTypeRef IntTy, unsigned long long N, LLVMBool SignExtend); +LLVMValueRef LLVMConstIntOfArbitraryPrecision(LLVMTypeRef IntTy, + unsigned NumWords, + const uint64_t Words[]); LLVMValueRef LLVMConstIntOfString(LLVMTypeRef IntTy, const char *Text, uint8_t Radix); LLVMValueRef LLVMConstIntOfStringAndSize(LLVMTypeRef IntTy, const char *Text, @@ -1013,6 +1027,11 @@ LLVMBool LLVMCreateMemoryBufferWithSTDIN(LLVMMemoryBufferRef *OutMemBuf, char **OutMessage); void LLVMDisposeMemoryBuffer(LLVMMemoryBufferRef MemBuf); +/*===-- Pass Registry -----------------------------------------------------===*/ + +/** Return the global pass registry, for use with initialization functions. + See llvm::PassRegistry::getPassRegistry. */ +LLVMPassRegistryRef LLVMGetGlobalPassRegistry(void); /*===-- Pass Managers -----------------------------------------------------===*/ @@ -1101,6 +1120,7 @@ namespace llvm { DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLVMContext, LLVMContextRef ) DEFINE_SIMPLE_CONVERSION_FUNCTIONS(Use, LLVMUseRef ) DEFINE_STDCXX_CONVERSION_FUNCTIONS(PassManagerBase, LLVMPassManagerRef ) + DEFINE_STDCXX_CONVERSION_FUNCTIONS(PassRegistry, LLVMPassRegistryRef ) /* LLVMModuleProviderRef exists for historical reasons, but now just holds a * Module. */ diff --git a/include/llvm-c/EnhancedDisassembly.h b/include/llvm-c/EnhancedDisassembly.h index d177381988df..28ac0ed2ab35 100644 --- a/include/llvm-c/EnhancedDisassembly.h +++ b/include/llvm-c/EnhancedDisassembly.h @@ -19,7 +19,7 @@ #ifndef LLVM_C_ENHANCEDDISASSEMBLY_H #define LLVM_C_ENHANCEDDISASSEMBLY_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #ifdef __cplusplus extern "C" { diff --git a/include/llvm-c/Initialization.h b/include/llvm-c/Initialization.h new file mode 100644 index 000000000000..3b59abbec03c --- /dev/null +++ b/include/llvm-c/Initialization.h @@ -0,0 +1,40 @@ +/*===-- llvm-c/Initialization.h - Initialization C Interface ------*- C -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This header declares the C interface to LLVM initialization routines, *| +|* which must be called before you can use the functionality provided by *| +|* the corresponding LLVM library. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef LLVM_C_INITIALIZEPASSES_H +#define LLVM_C_INITIALIZEPASSES_H + +#include "llvm-c/Core.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void LLVMInitializeCore(LLVMPassRegistryRef R); +void LLVMInitializeTransformUtils(LLVMPassRegistryRef R); +void LLVMInitializeScalarOpts(LLVMPassRegistryRef R); +void LLVMInitializeInstCombine(LLVMPassRegistryRef R); +void LLVMInitializeIPO(LLVMPassRegistryRef R); +void LLVMInitializeInstrumentation(LLVMPassRegistryRef R); +void LLVMInitializeAnalysis(LLVMPassRegistryRef R); +void LLVMInitializeIPA(LLVMPassRegistryRef R); +void LLVMInitializeCodeGen(LLVMPassRegistryRef R); +void LLVMInitializeTarget(LLVMPassRegistryRef R); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/llvm-c/LinkTimeOptimizer.h b/include/llvm-c/LinkTimeOptimizer.h index ccfdceed0264..fca394681c76 100644 --- a/include/llvm-c/LinkTimeOptimizer.h +++ b/include/llvm-c/LinkTimeOptimizer.h @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // // This header provides a C API to use the LLVM link time optimization -// library. This is inteded to be used by linkers which are C-only in +// library. This is intended to be used by linkers which are C-only in // their implementation for performing LTO. // //===----------------------------------------------------------------------===// diff --git a/include/llvm-c/Transforms/Scalar.h b/include/llvm-c/Transforms/Scalar.h index c94019ac98b0..2ddfb38171c2 100644 --- a/include/llvm-c/Transforms/Scalar.h +++ b/include/llvm-c/Transforms/Scalar.h @@ -52,9 +52,6 @@ void LLVMAddLICMPass(LLVMPassManagerRef PM); /** See llvm::createLoopDeletionPass function. */ void LLVMAddLoopDeletionPass(LLVMPassManagerRef PM); -/** See llvm::createLoopIndexSplitPass function. */ -void LLVMAddLoopIndexSplitPass(LLVMPassManagerRef PM); - /** See llvm::createLoopRotatePass function. */ void LLVMAddLoopRotatePass(LLVMPassManagerRef PM); diff --git a/include/llvm-c/lto.h b/include/llvm-c/lto.h index e6f69afa2ec2..1c42ce0cec77 100644 --- a/include/llvm-c/lto.h +++ b/include/llvm-c/lto.h @@ -18,27 +18,28 @@ #include #include -#include "llvm/System/DataTypes.h" +#include -#define LTO_API_VERSION 3 +#define LTO_API_VERSION 4 typedef enum { - LTO_SYMBOL_ALIGNMENT_MASK = 0x0000001F, /* log2 of alignment */ - LTO_SYMBOL_PERMISSIONS_MASK = 0x000000E0, - LTO_SYMBOL_PERMISSIONS_CODE = 0x000000A0, - LTO_SYMBOL_PERMISSIONS_DATA = 0x000000C0, - LTO_SYMBOL_PERMISSIONS_RODATA = 0x00000080, - LTO_SYMBOL_DEFINITION_MASK = 0x00000700, - LTO_SYMBOL_DEFINITION_REGULAR = 0x00000100, - LTO_SYMBOL_DEFINITION_TENTATIVE = 0x00000200, - LTO_SYMBOL_DEFINITION_WEAK = 0x00000300, - LTO_SYMBOL_DEFINITION_UNDEFINED = 0x00000400, - LTO_SYMBOL_DEFINITION_WEAKUNDEF = 0x00000500, - LTO_SYMBOL_SCOPE_MASK = 0x00003800, - LTO_SYMBOL_SCOPE_INTERNAL = 0x00000800, - LTO_SYMBOL_SCOPE_HIDDEN = 0x00001000, - LTO_SYMBOL_SCOPE_PROTECTED = 0x00002000, - LTO_SYMBOL_SCOPE_DEFAULT = 0x00001800 + LTO_SYMBOL_ALIGNMENT_MASK = 0x0000001F, /* log2 of alignment */ + LTO_SYMBOL_PERMISSIONS_MASK = 0x000000E0, + LTO_SYMBOL_PERMISSIONS_CODE = 0x000000A0, + LTO_SYMBOL_PERMISSIONS_DATA = 0x000000C0, + LTO_SYMBOL_PERMISSIONS_RODATA = 0x00000080, + LTO_SYMBOL_DEFINITION_MASK = 0x00000700, + LTO_SYMBOL_DEFINITION_REGULAR = 0x00000100, + LTO_SYMBOL_DEFINITION_TENTATIVE = 0x00000200, + LTO_SYMBOL_DEFINITION_WEAK = 0x00000300, + LTO_SYMBOL_DEFINITION_UNDEFINED = 0x00000400, + LTO_SYMBOL_DEFINITION_WEAKUNDEF = 0x00000500, + LTO_SYMBOL_SCOPE_MASK = 0x00003800, + LTO_SYMBOL_SCOPE_INTERNAL = 0x00000800, + LTO_SYMBOL_SCOPE_HIDDEN = 0x00001000, + LTO_SYMBOL_SCOPE_PROTECTED = 0x00002000, + LTO_SYMBOL_SCOPE_DEFAULT = 0x00001800, + LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN = 0x00002800 } lto_symbol_attributes; typedef enum { @@ -121,6 +122,13 @@ lto_module_create(const char* path); extern lto_module_t lto_module_create_from_memory(const void* mem, size_t length); +/** + * Loads an object file from disk. The seek point of fd is not preserved. + * Returns NULL on error (check lto_get_error_message() for details). + */ +extern lto_module_t +lto_module_create_from_fd(int fd, const char *path, off_t size); + /** * Frees all memory internally allocated by the module. @@ -146,7 +154,7 @@ lto_module_set_target_triple(lto_module_t mod, const char *triple); /** * Returns the number of symbols in the object module. */ -extern uint32_t +extern unsigned int lto_module_get_num_symbols(lto_module_t mod); @@ -154,14 +162,14 @@ lto_module_get_num_symbols(lto_module_t mod); * Returns the name of the ith symbol in the object module. */ extern const char* -lto_module_get_symbol_name(lto_module_t mod, uint32_t index); +lto_module_get_symbol_name(lto_module_t mod, unsigned int index); /** * Returns the attributes of the ith symbol in the object module. */ extern lto_symbol_attributes -lto_module_get_symbol_attribute(lto_module_t mod, uint32_t index); +lto_module_get_symbol_attribute(lto_module_t mod, unsigned int index); /** diff --git a/include/llvm/ADT/APFloat.h b/include/llvm/ADT/APFloat.h index dfe4e0f49adb..ca4138b825a6 100644 --- a/include/llvm/ADT/APFloat.h +++ b/include/llvm/ADT/APFloat.h @@ -246,6 +246,13 @@ namespace llvm { static APFloat getSmallestNormalized(const fltSemantics &Sem, bool Negative = false); + /// getAllOnesValue - Returns a float which is bitcasted from + /// an all one value int. + /// + /// \param BitWidth - Select float type + /// \param isIEEE - If 128 bit number, select between PPC and IEEE + static APFloat getAllOnesValue(unsigned BitWidth, bool isIEEE = false); + /// Profile - Used to insert APFloat objects, or objects that contain /// APFloat objects, into FoldingSets. void Profile(FoldingSetNodeID& NID) const; diff --git a/include/llvm/ADT/APInt.h b/include/llvm/ADT/APInt.h index 8004cb4b123b..b91d5dc9bcf9 100644 --- a/include/llvm/ADT/APInt.h +++ b/include/llvm/ADT/APInt.h @@ -275,12 +275,6 @@ public: /// objects, into FoldingSets. void Profile(FoldingSetNodeID& id) const; - /// @brief Used by the Bitcode serializer to emit APInts to Bitcode. - void Emit(Serializer& S) const; - - /// @brief Used by the Bitcode deserializer to deserialize APInts. - void Read(Deserializer& D); - /// @} /// @name Value Tests /// @{ @@ -302,7 +296,7 @@ public: /// @returns true if this APInt is positive. /// @brief Determine if this APInt Value is positive. bool isStrictlyPositive() const { - return isNonNegative() && (*this) != 0; + return isNonNegative() && !!*this; } /// This checks to see if the value has all bits of the APInt are set or not. @@ -330,15 +324,14 @@ public: /// value for the APInt's bit width. /// @brief Determine if this is the smallest unsigned value. bool isMinValue() const { - return countPopulation() == 0; + return !*this; } /// This checks to see if the value of this APInt is the minimum signed /// value for the APInt's bit width. /// @brief Determine if this is the smallest signed value. bool isMinSignedValue() const { - return BitWidth == 1 ? VAL == 1 : - isNegative() && countPopulation() == 1; + return BitWidth == 1 ? VAL == 1 : isNegative() && isPowerOf2(); } /// @brief Check if this APInt has an N-bits unsigned integer value. @@ -348,10 +341,8 @@ public: return true; if (isSingleWord()) - return VAL == (VAL & (~0ULL >> (64 - N))); - APInt Tmp(N, getNumWords(), pVal); - Tmp.zext(getBitWidth()); - return Tmp == (*this); + return isUIntN(N, VAL); + return APInt(N, getNumWords(), pVal).zext(getBitWidth()) == (*this); } /// @brief Check if this APInt has an N-bits signed integer value. @@ -361,7 +352,11 @@ public: } /// @returns true if the argument APInt value is a power of two > 0. - bool isPowerOf2() const; + bool isPowerOf2() const { + if (isSingleWord()) + return isPowerOf2_64(VAL); + return countPopulationSlowCase() == 1; + } /// isSignBit - Return true if this is the value returned by getSignBit. bool isSignBit() const { return isMinSignedValue(); } @@ -369,7 +364,7 @@ public: /// This converts the APInt to a boolean value as a test against zero. /// @brief Boolean conversion function. bool getBoolValue() const { - return *this != 0; + return !!*this; } /// getLimitedValue - If this value is smaller than the specified limit, @@ -385,12 +380,14 @@ public: /// @{ /// @brief Gets maximum unsigned value of APInt for specific bit width. static APInt getMaxValue(unsigned numBits) { - return APInt(numBits, 0).set(); + return getAllOnesValue(numBits); } /// @brief Gets maximum signed value of APInt for a specific bit width. static APInt getSignedMaxValue(unsigned numBits) { - return APInt(numBits, 0).set().clear(numBits - 1); + APInt API = getAllOnesValue(numBits); + API.clearBit(numBits - 1); + return API; } /// @brief Gets minimum unsigned value of APInt for a specific bit width. @@ -400,7 +397,9 @@ public: /// @brief Gets minimum signed value of APInt for a specific bit width. static APInt getSignedMinValue(unsigned numBits) { - return APInt(numBits, 0).set(numBits - 1); + APInt API(numBits, 0); + API.setBit(numBits - 1); + return API; } /// getSignBit - This is just a wrapper function of getSignedMinValue(), and @@ -413,7 +412,7 @@ public: /// @returns the all-ones value for an APInt of the specified bit-width. /// @brief Get the all-ones value. static APInt getAllOnesValue(unsigned numBits) { - return APInt(numBits, 0).set(); + return APInt(numBits, -1ULL, true); } /// @returns the '0' value for an APInt of the specified bit-width. @@ -432,6 +431,13 @@ public: /// @returns the low "numBits" bits of this APInt. APInt getLoBits(unsigned numBits) const; + /// getOneBitSet - Return an APInt with exactly one bit set in the result. + static APInt getOneBitSet(unsigned numBits, unsigned BitNo) { + APInt Res(numBits, 0); + Res.setBit(BitNo); + return Res; + } + /// Constructs an APInt value that has a contiguous range of bits set. The /// bits from loBit (inclusive) to hiBit (exclusive) will be set. All other /// bits will be zero. For example, with parameters(32, 0, 16) you would get @@ -530,7 +536,7 @@ public: /// @brief Unary bitwise complement operator. APInt operator~() const { APInt Result(*this); - Result.flip(); + Result.flipAllBits(); return Result; } @@ -741,11 +747,11 @@ public: /// RHS are treated as unsigned quantities for purposes of this division. /// @returns a new APInt value containing the division result /// @brief Unsigned division operation. - APInt udiv(const APInt& RHS) const; + APInt udiv(const APInt &RHS) const; /// Signed divide this APInt by APInt RHS. /// @brief Signed division function for APInt. - APInt sdiv(const APInt& RHS) const { + APInt sdiv(const APInt &RHS) const { if (isNegative()) if (RHS.isNegative()) return (-(*this)).udiv(-RHS); @@ -763,11 +769,11 @@ public: /// which is *this. /// @returns a new APInt value containing the remainder result /// @brief Unsigned remainder operation. - APInt urem(const APInt& RHS) const; + APInt urem(const APInt &RHS) const; /// Signed remainder operation on APInt. /// @brief Function for signed remainder operation. - APInt srem(const APInt& RHS) const { + APInt srem(const APInt &RHS) const { if (isNegative()) if (RHS.isNegative()) return -((-(*this)).urem(-RHS)); @@ -788,8 +794,7 @@ public: APInt &Quotient, APInt &Remainder); static void sdivrem(const APInt &LHS, const APInt &RHS, - APInt &Quotient, APInt &Remainder) - { + APInt &Quotient, APInt &Remainder) { if (LHS.isNegative()) { if (RHS.isNegative()) APInt::udivrem(-LHS, -RHS, Quotient, Remainder); @@ -804,6 +809,16 @@ public: APInt::udivrem(LHS, RHS, Quotient, Remainder); } } + + + // Operations that return overflow indicators. + APInt sadd_ov(const APInt &RHS, bool &Overflow) const; + APInt uadd_ov(const APInt &RHS, bool &Overflow) const; + APInt ssub_ov(const APInt &RHS, bool &Overflow) const; + APInt usub_ov(const APInt &RHS, bool &Overflow) const; + APInt sdiv_ov(const APInt &RHS, bool &Overflow) const; + APInt smul_ov(const APInt &RHS, bool &Overflow) const; + APInt sshl_ov(unsigned Amt, bool &Overflow) const; /// @returns the bit value at bitPosition /// @brief Array-indexing support. @@ -868,7 +883,7 @@ public: /// the validity of the less-than relationship. /// @returns true if *this < RHS when both are considered unsigned. /// @brief Unsigned less than comparison - bool ult(const APInt& RHS) const; + bool ult(const APInt &RHS) const; /// Regards both *this as an unsigned quantity and compares it with RHS for /// the validity of the less-than relationship. @@ -988,6 +1003,9 @@ public: return sge(APInt(getBitWidth(), RHS)); } + + + /// This operation tests if there are any pairs of corresponding bits /// between this APInt and RHS that are both set. bool intersects(const APInt &RHS) const { @@ -1000,80 +1018,78 @@ public: /// Truncate the APInt to a specified width. It is an error to specify a width /// that is greater than or equal to the current width. /// @brief Truncate to new width. - APInt &trunc(unsigned width); + APInt trunc(unsigned width) const; /// This operation sign extends the APInt to a new width. If the high order /// bit is set, the fill on the left will be done with 1 bits, otherwise zero. /// It is an error to specify a width that is less than or equal to the /// current width. /// @brief Sign extend to a new width. - APInt &sext(unsigned width); + APInt sext(unsigned width) const; /// This operation zero extends the APInt to a new width. The high order bits /// are filled with 0 bits. It is an error to specify a width that is less /// than or equal to the current width. /// @brief Zero extend to a new width. - APInt &zext(unsigned width); + APInt zext(unsigned width) const; /// Make this APInt have the bit width given by \p width. The value is sign /// extended, truncated, or left alone to make it that width. /// @brief Sign extend or truncate to width - APInt &sextOrTrunc(unsigned width); + APInt sextOrTrunc(unsigned width) const; /// Make this APInt have the bit width given by \p width. The value is zero /// extended, truncated, or left alone to make it that width. /// @brief Zero extend or truncate to width - APInt &zextOrTrunc(unsigned width); + APInt zextOrTrunc(unsigned width) const; /// @} /// @name Bit Manipulation Operators /// @{ /// @brief Set every bit to 1. - APInt& set() { - if (isSingleWord()) { + void setAllBits() { + if (isSingleWord()) VAL = -1ULL; - return clearUnusedBits(); + else { + // Set all the bits in all the words. + for (unsigned i = 0; i < getNumWords(); ++i) + pVal[i] = -1ULL; } - - // Set all the bits in all the words. - for (unsigned i = 0; i < getNumWords(); ++i) - pVal[i] = -1ULL; // Clear the unused ones - return clearUnusedBits(); + clearUnusedBits(); } /// Set the given bit to 1 whose position is given as "bitPosition". /// @brief Set a given bit to 1. - APInt& set(unsigned bitPosition); + void setBit(unsigned bitPosition); /// @brief Set every bit to 0. - APInt& clear() { + void clearAllBits() { if (isSingleWord()) VAL = 0; else memset(pVal, 0, getNumWords() * APINT_WORD_SIZE); - return *this; } /// Set the given bit to 0 whose position is given as "bitPosition". /// @brief Set a given bit to 0. - APInt& clear(unsigned bitPosition); + void clearBit(unsigned bitPosition); /// @brief Toggle every bit to its opposite value. - APInt& flip() { - if (isSingleWord()) { + void flipAllBits() { + if (isSingleWord()) VAL ^= -1ULL; - return clearUnusedBits(); + else { + for (unsigned i = 0; i < getNumWords(); ++i) + pVal[i] ^= -1ULL; } - for (unsigned i = 0; i < getNumWords(); ++i) - pVal[i] ^= -1ULL; - return clearUnusedBits(); + clearUnusedBits(); } /// Toggle a given bit to its opposite value whose position is given /// as "bitPosition". /// @brief Toggles a given bit to its opposite value. - APInt& flip(unsigned bitPosition); + void flipBit(unsigned bitPosition); /// @} /// @name Value Characterization Functions @@ -1281,37 +1297,27 @@ public: } /// The conversion does not do a translation from double to integer, it just - /// re-interprets the bits of the double. Note that it is valid to do this on - /// any bit width but bits from V may get truncated. + /// re-interprets the bits of the double. /// @brief Converts a double to APInt bits. - APInt& doubleToBits(double V) { + static APInt doubleToBits(double V) { union { uint64_t I; double D; } T; T.D = V; - if (isSingleWord()) - VAL = T.I; - else - pVal[0] = T.I; - return clearUnusedBits(); + return APInt(sizeof T * CHAR_BIT, T.I); } /// The conversion does not do a translation from float to integer, it just - /// re-interprets the bits of the float. Note that it is valid to do this on - /// any bit width but bits from V may get truncated. + /// re-interprets the bits of the float. /// @brief Converts a float to APInt bits. - APInt& floatToBits(float V) { + static APInt floatToBits(float V) { union { unsigned I; float F; } T; T.F = V; - if (isSingleWord()) - VAL = T.I; - else - pVal[0] = T.I; - return clearUnusedBits(); + return APInt(sizeof T * CHAR_BIT, T.I); } /// @} diff --git a/include/llvm/ADT/APSInt.h b/include/llvm/ADT/APSInt.h index 1c9931c30fe5..54a7b601d1f1 100644 --- a/include/llvm/ADT/APSInt.h +++ b/include/llvm/ADT/APSInt.h @@ -68,20 +68,22 @@ public: } using APInt::toString; - APSInt& extend(uint32_t width) { + APSInt trunc(uint32_t width) const { + return APSInt(APInt::trunc(width), IsUnsigned); + } + + APSInt extend(uint32_t width) const { if (IsUnsigned) - zext(width); + return APSInt(zext(width), IsUnsigned); else - sext(width); - return *this; + return APSInt(sext(width), IsUnsigned); } - APSInt& extOrTrunc(uint32_t width) { + APSInt extOrTrunc(uint32_t width) const { if (IsUnsigned) - zextOrTrunc(width); + return APSInt(zextOrTrunc(width), IsUnsigned); else - sextOrTrunc(width); - return *this; + return APSInt(sextOrTrunc(width), IsUnsigned); } const APSInt &operator%=(const APSInt &RHS) { diff --git a/include/llvm/ADT/ArrayRef.h b/include/llvm/ADT/ArrayRef.h new file mode 100644 index 000000000000..1c5470d678b6 --- /dev/null +++ b/include/llvm/ADT/ArrayRef.h @@ -0,0 +1,121 @@ +//===--- ArrayRef.h - Array Reference Wrapper -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_ARRAYREF_H +#define LLVM_ADT_ARRAYREF_H + +#include "llvm/ADT/SmallVector.h" +#include + +namespace llvm { + class APInt; + + /// ArrayRef - Represent a constant reference to an array (0 or more elements + /// consecutively in memory), i.e. a start pointer and a length. It allows + /// various APIs to take consecutive elements easily and conveniently. + /// + /// This class does not own the underlying data, it is expected to be used in + /// situations where the data resides in some other buffer, whose lifetime + /// extends past that of the StringRef. For this reason, it is not in general + /// safe to store a ArrayRef. + /// + /// This is intended to be trivially copyable, so it should be passed by + /// value. + template + class ArrayRef { + public: + typedef const T *iterator; + typedef const T *const_iterator; + typedef size_t size_type; + + private: + /// The start of the array, in an external buffer. + const T *Data; + + /// The number of elements. + size_t Length; + + public: + /// @name Constructors + /// @{ + + /// Construct an empty ArrayRef. + /*implicit*/ ArrayRef() : Data(0), Length(0) {} + + /// Construct an ArrayRef from a single element. + /*implicit*/ ArrayRef(const T &OneElt) + : Data(&OneElt), Length(1) {} + + /// Construct an ArrayRef from a pointer and length. + /*implicit*/ ArrayRef(const T *data, size_t length) + : Data(data), Length(length) {} + + /// Construct an ArrayRef from a SmallVector. + /*implicit*/ ArrayRef(const SmallVectorImpl &Vec) + : Data(Vec.data()), Length(Vec.size()) {} + + /// Construct an ArrayRef from a std::vector. + /*implicit*/ ArrayRef(const std::vector &Vec) + : Data(Vec.empty() ? (T*)0 : &Vec[0]), Length(Vec.size()) {} + + // TODO: C arrays. + + /// @} + /// @name Simple Operations + /// @{ + + iterator begin() const { return Data; } + iterator end() const { return Data + Length; } + + /// empty - Check if the array is empty. + bool empty() const { return Length == 0; } + + /// size - Get the array size. + size_t size() const { return Length; } + + /// front - Get the first element. + const T &front() const { + assert(!empty()); + return Data[0]; + } + + /// back - Get the last element. + const T &back() const { + assert(!empty()); + return Data[Length-1]; + } + + /// @} + /// @name Operator Overloads + /// @{ + + const T &operator[](size_t Index) const { + assert(Index < Length && "Invalid index!"); + return Data[Index]; + } + + /// @} + /// @name Expensive Operations + /// @{ + + std::vector vec() const { + return std::vector(Data, Data+Length); + } + + /// @} + }; + + // ArrayRefs can be treated like a POD type. + template struct isPodLike; + template struct isPodLike > { + static const bool value = true; + }; +} + +#endif diff --git a/include/llvm/ADT/BitVector.h b/include/llvm/ADT/BitVector.h index 9dcb9e106f26..ac1cf0c79a8f 100644 --- a/include/llvm/ADT/BitVector.h +++ b/include/llvm/ADT/BitVector.h @@ -18,6 +18,7 @@ #include #include #include +#include #include namespace llvm { @@ -77,7 +78,7 @@ public: /// bits are initialized to the specified value. explicit BitVector(unsigned s, bool t = false) : Size(s) { Capacity = NumBitWords(s); - Bits = new BitWord[Capacity]; + Bits = (BitWord *)std::malloc(Capacity * sizeof(BitWord)); init_words(Bits, Capacity, t); if (t) clear_unused_bits(); @@ -92,12 +93,12 @@ public: } Capacity = NumBitWords(RHS.size()); - Bits = new BitWord[Capacity]; - std::copy(RHS.Bits, &RHS.Bits[Capacity], Bits); + Bits = (BitWord *)std::malloc(Capacity * sizeof(BitWord)); + std::memcpy(Bits, RHS.Bits, Capacity * sizeof(BitWord)); } ~BitVector() { - delete[] Bits; + std::free(Bits); } /// empty - Tests whether there are no bits in this bitvector. @@ -127,6 +128,12 @@ public: return false; } + /// all - Returns true if all bits are set. + bool all() const { + // TODO: Optimize this. + return count() == size(); + } + /// none - Returns true if none of the bits are set. bool none() const { return !any(); @@ -335,18 +342,18 @@ public: unsigned RHSWords = NumBitWords(Size); if (Size <= Capacity * BITWORD_SIZE) { if (Size) - std::copy(RHS.Bits, &RHS.Bits[RHSWords], Bits); + std::memcpy(Bits, RHS.Bits, RHSWords * sizeof(BitWord)); clear_unused_bits(); return *this; } // Grow the bitvector to have enough elements. Capacity = RHSWords; - BitWord *NewBits = new BitWord[Capacity]; - std::copy(RHS.Bits, &RHS.Bits[RHSWords], NewBits); + BitWord *NewBits = (BitWord *)std::malloc(Capacity * sizeof(BitWord)); + std::memcpy(NewBits, RHS.Bits, Capacity * sizeof(BitWord)); // Destroy the old bits. - delete[] Bits; + std::free(Bits); Bits = NewBits; return *this; @@ -384,17 +391,8 @@ private: } void grow(unsigned NewSize) { - unsigned OldCapacity = Capacity; - Capacity = NumBitWords(NewSize); - BitWord *NewBits = new BitWord[Capacity]; - - // Copy the old bits over. - if (OldCapacity != 0) - std::copy(Bits, &Bits[OldCapacity], NewBits); - - // Destroy the old bits. - delete[] Bits; - Bits = NewBits; + Capacity = std::max(NumBitWords(NewSize), Capacity * 2); + Bits = (BitWord *)std::realloc(Bits, Capacity * sizeof(BitWord)); clear_unused_bits(); } diff --git a/include/llvm/ADT/DenseMap.h b/include/llvm/ADT/DenseMap.h index 06a1575da4d0..61d6ae70e1d9 100644 --- a/include/llvm/ADT/DenseMap.h +++ b/include/llvm/ADT/DenseMap.h @@ -18,6 +18,7 @@ #include "llvm/Support/PointerLikeTypeTraits.h" #include "llvm/Support/type_traits.h" #include "llvm/ADT/DenseMapInfo.h" +#include #include #include #include @@ -385,7 +386,7 @@ private: // Insert the key/value into the new table. BucketT *DestBucket; bool FoundVal = LookupBucketFor(B->first, DestBucket); - FoundVal = FoundVal; // silence warning. + (void)FoundVal; // silence warning. assert(!FoundVal && "Key already in new map?"); DestBucket->first = B->first; new (&DestBucket->second) ValueT(B->second); diff --git a/include/llvm/ADT/DenseMapInfo.h b/include/llvm/ADT/DenseMapInfo.h index 529938699270..25e341bf4fd4 100644 --- a/include/llvm/ADT/DenseMapInfo.h +++ b/include/llvm/ADT/DenseMapInfo.h @@ -102,6 +102,20 @@ template<> struct DenseMapInfo { } }; +// Provide DenseMapInfo for longs. +template<> struct DenseMapInfo { + static inline long getEmptyKey() { + return (1UL << (sizeof(long) * 8 - 1)) - 1L; + } + static inline long getTombstoneKey() { return getEmptyKey() - 1L; } + static unsigned getHashValue(const long& Val) { + return (unsigned)(Val * 37L); + } + static bool isEqual(const long& LHS, const long& RHS) { + return LHS == RHS; + } +}; + // Provide DenseMapInfo for long longs. template<> struct DenseMapInfo { static inline long long getEmptyKey() { return 0x7fffffffffffffffLL; } diff --git a/include/llvm/ADT/DenseSet.h b/include/llvm/ADT/DenseSet.h index 00bcf64a2fc7..67321f539848 100644 --- a/include/llvm/ADT/DenseSet.h +++ b/include/llvm/ADT/DenseSet.h @@ -33,6 +33,9 @@ public: bool empty() const { return TheMap.empty(); } unsigned size() const { return TheMap.size(); } + /// Grow the denseset so that it has at least Size buckets. Does not shrink + void resize(size_t Size) { TheMap.resize(Size); } + void clear() { TheMap.clear(); } diff --git a/include/llvm/ADT/EquivalenceClasses.h b/include/llvm/ADT/EquivalenceClasses.h index 07a5edfdb6ca..771476c30361 100644 --- a/include/llvm/ADT/EquivalenceClasses.h +++ b/include/llvm/ADT/EquivalenceClasses.h @@ -15,7 +15,7 @@ #ifndef LLVM_ADT_EQUIVALENCECLASSES_H #define LLVM_ADT_EQUIVALENCECLASSES_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include #include diff --git a/include/llvm/ADT/FoldingSet.h b/include/llvm/ADT/FoldingSet.h index 662b5e273548..879dbd05e174 100644 --- a/include/llvm/ADT/FoldingSet.h +++ b/include/llvm/ADT/FoldingSet.h @@ -16,7 +16,7 @@ #ifndef LLVM_ADT_FOLDINGSET_H #define LLVM_ADT_FOLDINGSET_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" diff --git a/include/llvm/ADT/ImmutableIntervalMap.h b/include/llvm/ADT/ImmutableIntervalMap.h index 968ce152779f..d3196ca23df9 100644 --- a/include/llvm/ADT/ImmutableIntervalMap.h +++ b/include/llvm/ADT/ImmutableIntervalMap.h @@ -94,7 +94,7 @@ public: : ImutAVLFactory(Alloc) {} TreeTy *Add(TreeTy *T, value_type_ref V) { - T = Add_internal(V,T); + T = add_internal(V,T); this->MarkImmutable(T); return T; } @@ -103,20 +103,20 @@ public: if (!T) return NULL; - key_type_ref CurrentKey = ImutInfo::KeyOfValue(this->Value(T)); + key_type_ref CurrentKey = ImutInfo::KeyOfValue(this->getValue(T)); if (ImutInfo::isContainedIn(K, CurrentKey)) return T; else if (ImutInfo::isLess(K, CurrentKey)) - return Find(this->Left(T), K); + return Find(this->getLeft(T), K); else - return Find(this->Right(T), K); + return Find(this->getRight(T), K); } private: - TreeTy *Add_internal(value_type_ref V, TreeTy *T) { + TreeTy *add_internal(value_type_ref V, TreeTy *T) { key_type_ref K = ImutInfo::KeyOfValue(V); - T = RemoveAllOverlaps(T, K); + T = removeAllOverlaps(T, K); if (this->isEmpty(T)) return this->CreateNode(NULL, V, NULL); @@ -125,38 +125,38 @@ private: key_type_ref KCurrent = ImutInfo::KeyOfValue(this->Value(T)); if (ImutInfo::isLess(K, KCurrent)) - return this->Balance(Add_internal(V, this->Left(T)), this->Value(T), + return this->Balance(add_internal(V, this->Left(T)), this->Value(T), this->Right(T)); else return this->Balance(this->Left(T), this->Value(T), - Add_internal(V, this->Right(T))); + add_internal(V, this->Right(T))); } // Remove all overlaps from T. - TreeTy *RemoveAllOverlaps(TreeTy *T, key_type_ref K) { + TreeTy *removeAllOverlaps(TreeTy *T, key_type_ref K) { bool Changed; do { Changed = false; - T = RemoveOverlap(T, K, Changed); - this->MarkImmutable(T); + T = removeOverlap(T, K, Changed); + this->markImmutable(T); } while (Changed); return T; } // Remove one overlap from T. - TreeTy *RemoveOverlap(TreeTy *T, key_type_ref K, bool &Changed) { + TreeTy *removeOverlap(TreeTy *T, key_type_ref K, bool &Changed) { if (!T) return NULL; Interval CurrentK = ImutInfo::KeyOfValue(this->Value(T)); // If current key does not overlap the inserted key. if (CurrentK.getStart() > K.getEnd()) - return this->Balance(RemoveOverlap(this->Left(T), K, Changed), + return this->Balance(removeOverlap(this->Left(T), K, Changed), this->Value(T), this->Right(T)); else if (CurrentK.getEnd() < K.getStart()) return this->Balance(this->Left(T), this->Value(T), - RemoveOverlap(this->Right(T), K, Changed)); + removeOverlap(this->Right(T), K, Changed)); // Current key overlaps with the inserted key. // Remove the current key. @@ -167,18 +167,18 @@ private: if (CurrentK.getStart() < K.getStart()) { if (CurrentK.getEnd() <= K.getEnd()) { Interval NewK(CurrentK.getStart(), K.getStart()-1); - return Add_internal(std::make_pair(NewK, OldData), T); + return add_internal(std::make_pair(NewK, OldData), T); } else { Interval NewK1(CurrentK.getStart(), K.getStart()-1); - T = Add_internal(std::make_pair(NewK1, OldData), T); + T = add_internal(std::make_pair(NewK1, OldData), T); Interval NewK2(K.getEnd()+1, CurrentK.getEnd()); - return Add_internal(std::make_pair(NewK2, OldData), T); + return add_internal(std::make_pair(NewK2, OldData), T); } } else { if (CurrentK.getEnd() > K.getEnd()) { Interval NewK(K.getEnd()+1, CurrentK.getEnd()); - return Add_internal(std::make_pair(NewK, OldData), T); + return add_internal(std::make_pair(NewK, OldData), T); } else return T; } @@ -209,22 +209,22 @@ public: public: Factory(BumpPtrAllocator& Alloc) : F(Alloc) {} - ImmutableIntervalMap GetEmptyMap() { - return ImmutableIntervalMap(F.GetEmptyTree()); + ImmutableIntervalMap getEmptyMap() { + return ImmutableIntervalMap(F.getEmptyTree()); } - ImmutableIntervalMap Add(ImmutableIntervalMap Old, + ImmutableIntervalMap add(ImmutableIntervalMap Old, key_type_ref K, data_type_ref D) { - TreeTy *T = F.Add(Old.Root, std::make_pair(K, D)); - return ImmutableIntervalMap(F.GetCanonicalTree(T)); + TreeTy *T = F.add(Old.Root, std::make_pair(K, D)); + return ImmutableIntervalMap(F.getCanonicalTree(T)); } - ImmutableIntervalMap Remove(ImmutableIntervalMap Old, key_type_ref K) { - TreeTy *T = F.Remove(Old.Root, K); - return ImmutableIntervalMap(F.GetCanonicalTree(T)); + ImmutableIntervalMap remove(ImmutableIntervalMap Old, key_type_ref K) { + TreeTy *T = F.remove(Old.Root, K); + return ImmutableIntervalMap(F.getCanonicalTree(T)); } - data_type *Lookup(ImmutableIntervalMap M, key_type_ref K) { + data_type *lookup(ImmutableIntervalMap M, key_type_ref K) { TreeTy *T = F.Find(M.getRoot(), K); if (T) return &T->getValue().second; diff --git a/include/llvm/ADT/ImmutableList.h b/include/llvm/ADT/ImmutableList.h index 7757c08770bd..714355b95131 100644 --- a/include/llvm/ADT/ImmutableList.h +++ b/include/llvm/ADT/ImmutableList.h @@ -16,7 +16,7 @@ #include "llvm/Support/Allocator.h" #include "llvm/ADT/FoldingSet.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include namespace llvm { @@ -156,7 +156,7 @@ public: if (ownsAllocator()) delete &getAllocator(); } - ImmutableList Concat(const T& Head, ImmutableList Tail) { + ImmutableList concat(const T& Head, ImmutableList Tail) { // Profile the new list to see if it already exists in our cache. FoldingSetNodeID ID; void* InsertPos; @@ -178,16 +178,16 @@ public: return L; } - ImmutableList Add(const T& D, ImmutableList L) { - return Concat(D, L); + ImmutableList add(const T& D, ImmutableList L) { + return concat(D, L); } - ImmutableList GetEmptyList() const { + ImmutableList getEmptyList() const { return ImmutableList(0); } - ImmutableList Create(const T& X) { - return Concat(X, GetEmptyList()); + ImmutableList create(const T& X) { + return Concat(X, getEmptyList()); } }; diff --git a/include/llvm/ADT/ImmutableMap.h b/include/llvm/ADT/ImmutableMap.h index 8af128ef3bd8..e439a0994821 100644 --- a/include/llvm/ADT/ImmutableMap.h +++ b/include/llvm/ADT/ImmutableMap.h @@ -76,7 +76,23 @@ public: /// should use a Factory object to create maps instead of directly /// invoking the constructor, but there are cases where make this /// constructor public is useful. - explicit ImmutableMap(const TreeTy* R) : Root(const_cast(R)) {} + explicit ImmutableMap(const TreeTy* R) : Root(const_cast(R)) { + if (Root) { Root->retain(); } + } + ImmutableMap(const ImmutableMap &X) : Root(X.Root) { + if (Root) { Root->retain(); } + } + ImmutableMap &operator=(const ImmutableMap &X) { + if (Root != X.Root) { + if (X.Root) { X.Root->retain(); } + if (Root) { Root->release(); } + Root = X.Root; + } + return *this; + } + ~ImmutableMap() { + if (Root) { Root->release(); } + } class Factory { typename TreeTy::Factory F; @@ -89,16 +105,16 @@ public: Factory(BumpPtrAllocator& Alloc, bool canonicalize = true) : F(Alloc), Canonicalize(canonicalize) {} - ImmutableMap GetEmptyMap() { return ImmutableMap(F.GetEmptyTree()); } + ImmutableMap getEmptyMap() { return ImmutableMap(F.getEmptyTree()); } - ImmutableMap Add(ImmutableMap Old, key_type_ref K, data_type_ref D) { - TreeTy *T = F.Add(Old.Root, std::make_pair(K,D)); - return ImmutableMap(Canonicalize ? F.GetCanonicalTree(T): T); + ImmutableMap add(ImmutableMap Old, key_type_ref K, data_type_ref D) { + TreeTy *T = F.add(Old.Root, std::make_pair(K,D)); + return ImmutableMap(Canonicalize ? F.getCanonicalTree(T): T); } - ImmutableMap Remove(ImmutableMap Old, key_type_ref K) { - TreeTy *T = F.Remove(Old.Root,K); - return ImmutableMap(Canonicalize ? F.GetCanonicalTree(T): T); + ImmutableMap remove(ImmutableMap Old, key_type_ref K) { + TreeTy *T = F.remove(Old.Root,K); + return ImmutableMap(Canonicalize ? F.getCanonicalTree(T): T); } private: @@ -110,15 +126,30 @@ public: return Root ? Root->contains(K) : false; } - bool operator==(ImmutableMap RHS) const { + bool operator==(const ImmutableMap &RHS) const { return Root && RHS.Root ? Root->isEqual(*RHS.Root) : Root == RHS.Root; } - bool operator!=(ImmutableMap RHS) const { + bool operator!=(const ImmutableMap &RHS) const { return Root && RHS.Root ? Root->isNotEqual(*RHS.Root) : Root != RHS.Root; } - TreeTy* getRoot() const { return Root; } + TreeTy *getRoot() const { + if (Root) { Root->retain(); } + return Root; + } + + TreeTy *getRootWithoutRetain() const { + return Root; + } + + void manualRetain() { + if (Root) Root->retain(); + } + + void manualRelease() { + if (Root) Root->release(); + } bool isEmpty() const { return !Root; } diff --git a/include/llvm/ADT/ImmutableSet.h b/include/llvm/ADT/ImmutableSet.h index 70c3caf2a061..3ca910ce944f 100644 --- a/include/llvm/ADT/ImmutableSet.h +++ b/include/llvm/ADT/ImmutableSet.h @@ -15,10 +15,13 @@ #define LLVM_ADT_IMSET_H #include "llvm/Support/Allocator.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include #include +#include +#include namespace llvm { @@ -32,7 +35,7 @@ template class ImutAVLTreeInOrderIterator; template class ImutAVLTreeGenericIterator; template -class ImutAVLTree : public FoldingSetNode { +class ImutAVLTree { public: typedef typename ImutInfo::key_type_ref key_type_ref; typedef typename ImutInfo::value_type value_type; @@ -43,7 +46,6 @@ public: friend class ImutIntervalAVLFactory; friend class ImutAVLTreeGenericIterator; - friend class FoldingSet; typedef ImutAVLTreeInOrderIterator iterator; @@ -51,29 +53,27 @@ public: // Public Interface. //===----------------------------------------------------===// - /// getLeft - Returns a pointer to the left subtree. This value + /// Return a pointer to the left subtree. This value /// is NULL if there is no left subtree. - ImutAVLTree *getLeft() const { return Left; } + ImutAVLTree *getLeft() const { return left; } - /// getRight - Returns a pointer to the right subtree. This value is + /// Return a pointer to the right subtree. This value is /// NULL if there is no right subtree. - ImutAVLTree *getRight() const { return Right; } + ImutAVLTree *getRight() const { return right; } /// getHeight - Returns the height of the tree. A tree with no subtrees /// has a height of 1. - unsigned getHeight() const { return Height; } + unsigned getHeight() const { return height; } /// getValue - Returns the data value associated with the tree node. - const value_type& getValue() const { return Value; } + const value_type& getValue() const { return value; } /// find - Finds the subtree associated with the specified key value. /// This method returns NULL if no matching subtree is found. ImutAVLTree* find(key_type_ref K) { ImutAVLTree *T = this; - while (T) { key_type_ref CurrentKey = ImutInfo::KeyOfValue(T->getValue()); - if (ImutInfo::isEqual(K,CurrentKey)) return T; else if (ImutInfo::isLess(K,CurrentKey)) @@ -81,7 +81,6 @@ public: else T = T->getRight(); } - return NULL; } @@ -90,7 +89,7 @@ public: ImutAVLTree* getMaxElement() { ImutAVLTree *T = this; ImutAVLTree *Right = T->getRight(); - while (Right) { T = Right; Right = T->getRight(); } + while (Right) { T = right; right = T->getRight(); } return T; } @@ -98,10 +97,10 @@ public: /// both leaves and non-leaf nodes. unsigned size() const { unsigned n = 1; - - if (const ImutAVLTree* L = getLeft()) n += L->size(); - if (const ImutAVLTree* R = getRight()) n += R->size(); - + if (const ImutAVLTree* L = getLeft()) + n += L->size(); + if (const ImutAVLTree* R = getRight()) + n += R->size(); return n; } @@ -114,7 +113,7 @@ public: /// inorder traversal. iterator end() const { return iterator(); } - bool ElementEqual(value_type_ref V) const { + bool isElementEqual(value_type_ref V) const { // Compare the keys. if (!ImutInfo::isEqual(ImutInfo::KeyOfValue(getValue()), ImutInfo::KeyOfValue(V))) @@ -128,8 +127,8 @@ public: return true; } - bool ElementEqual(const ImutAVLTree* RHS) const { - return ElementEqual(RHS->getValue()); + bool isElementEqual(const ImutAVLTree* RHS) const { + return isElementEqual(RHS->getValue()); } /// isEqual - Compares two trees for structural equality and returns true @@ -144,12 +143,12 @@ public: while (LItr != LEnd && RItr != REnd) { if (*LItr == *RItr) { - LItr.SkipSubTree(); - RItr.SkipSubTree(); + LItr.skipSubTree(); + RItr.skipSubTree(); continue; } - if (!LItr->ElementEqual(*RItr)) + if (!LItr->isElementEqual(*RItr)) return false; ++LItr; @@ -173,22 +172,24 @@ public: /// Nodes are visited using an inorder traversal. template void foreach(Callback& C) { - if (ImutAVLTree* L = getLeft()) L->foreach(C); + if (ImutAVLTree* L = getLeft()) + L->foreach(C); - C(Value); + C(value); - if (ImutAVLTree* R = getRight()) R->foreach(C); + if (ImutAVLTree* R = getRight()) + R->foreach(C); } - /// verify - A utility method that checks that the balancing and + /// validateTree - A utility method that checks that the balancing and /// ordering invariants of the tree are satisifed. It is a recursive /// method that returns the height of the tree, which is then consumed - /// by the enclosing verify call. External callers should ignore the + /// by the enclosing validateTree call. External callers should ignore the /// return value. An invalid tree will cause an assertion to fire in /// a debug build. - unsigned verify() const { - unsigned HL = getLeft() ? getLeft()->verify() : 0; - unsigned HR = getRight() ? getRight()->verify() : 0; + unsigned validateTree() const { + unsigned HL = getLeft() ? getLeft()->validateTree() : 0; + unsigned HR = getRight() ? getRight()->validateTree() : 0; (void) HL; (void) HR; @@ -198,37 +199,39 @@ public: assert((HL > HR ? HL-HR : HR-HL) <= 2 && "Balancing invariant violated"); - assert(!getLeft() - || ImutInfo::isLess(ImutInfo::KeyOfValue(getLeft()->getValue()), - ImutInfo::KeyOfValue(getValue())) - && "Value in left child is not less that current value"); + assert((!getLeft() || + ImutInfo::isLess(ImutInfo::KeyOfValue(getLeft()->getValue()), + ImutInfo::KeyOfValue(getValue()))) && + "Value in left child is not less that current value"); - assert(!getRight() - || ImutInfo::isLess(ImutInfo::KeyOfValue(getValue()), - ImutInfo::KeyOfValue(getRight()->getValue())) - && "Current value is not less that value of right child"); + assert(!(getRight() || + ImutInfo::isLess(ImutInfo::KeyOfValue(getValue()), + ImutInfo::KeyOfValue(getRight()->getValue()))) && + "Current value is not less that value of right child"); return getHeight(); } - /// Profile - Profiling for ImutAVLTree. - void Profile(llvm::FoldingSetNodeID& ID) { - ID.AddInteger(ComputeDigest()); - } - //===----------------------------------------------------===// - // Internal Values. + // Internal values. //===----------------------------------------------------===// private: - ImutAVLTree* Left; - ImutAVLTree* Right; - unsigned Height : 28; - unsigned Mutable : 1; - unsigned CachedDigest : 1; - value_type Value; - uint32_t Digest; + Factory *factory; + ImutAVLTree *left; + ImutAVLTree *right; + ImutAVLTree *prev; + ImutAVLTree *next; + + unsigned height : 28; + unsigned IsMutable : 1; + unsigned IsDigestCached : 1; + unsigned IsCanonicalized : 1; + + value_type value; + uint32_t digest; + uint32_t refCount; //===----------------------------------------------------===// // Internal methods (node manipulation; used by Factory). @@ -237,10 +240,15 @@ private: private: /// ImutAVLTree - Internal constructor that is only called by /// ImutAVLFactory. - ImutAVLTree(ImutAVLTree* l, ImutAVLTree* r, value_type_ref v, + ImutAVLTree(Factory *f, ImutAVLTree* l, ImutAVLTree* r, value_type_ref v, unsigned height) - : Left(l), Right(r), Height(height), Mutable(true), CachedDigest(false), - Value(v), Digest(0) {} + : factory(f), left(l), right(r), prev(0), next(0), height(height), + IsMutable(true), IsDigestCached(false), IsCanonicalized(0), + value(v), digest(0), refCount(0) + { + if (left) left->retain(); + if (right) right->retain(); + } /// isMutable - Returns true if the left and right subtree references /// (as well as height) can be changed. If this method returns false, @@ -248,11 +256,11 @@ private: /// object should always have this method return true. Further, if this /// method returns false for an instance of ImutAVLTree, all subtrees /// will also have this method return false. The converse is not true. - bool isMutable() const { return Mutable; } + bool isMutable() const { return IsMutable; } /// hasCachedDigest - Returns true if the digest for this tree is cached. /// This can only be true if the tree is immutable. - bool hasCachedDigest() const { return CachedDigest; } + bool hasCachedDigest() const { return IsDigestCached; } //===----------------------------------------------------===// // Mutating operations. A tree root can be manipulated as @@ -265,51 +273,32 @@ private: // immutable. //===----------------------------------------------------===// - /// MarkImmutable - Clears the mutable flag for a tree. After this happens, + /// markImmutable - Clears the mutable flag for a tree. After this happens, /// it is an error to call setLeft(), setRight(), and setHeight(). - void MarkImmutable() { + void markImmutable() { assert(isMutable() && "Mutable flag already removed."); - Mutable = false; + IsMutable = false; } - /// MarkedCachedDigest - Clears the NoCachedDigest flag for a tree. - void MarkedCachedDigest() { + /// markedCachedDigest - Clears the NoCachedDigest flag for a tree. + void markedCachedDigest() { assert(!hasCachedDigest() && "NoCachedDigest flag already removed."); - CachedDigest = true; - } - - /// setLeft - Changes the reference of the left subtree. Used internally - /// by ImutAVLFactory. - void setLeft(ImutAVLTree* NewLeft) { - assert(isMutable() && - "Only a mutable tree can have its left subtree changed."); - Left = NewLeft; - CachedDigest = false; - } - - /// setRight - Changes the reference of the right subtree. Used internally - /// by ImutAVLFactory. - void setRight(ImutAVLTree* NewRight) { - assert(isMutable() && - "Only a mutable tree can have its right subtree changed."); - - Right = NewRight; - CachedDigest = false; + IsDigestCached = true; } /// setHeight - Changes the height of the tree. Used internally by /// ImutAVLFactory. void setHeight(unsigned h) { assert(isMutable() && "Only a mutable tree can have its height changed."); - Height = h; + height = h; } static inline - uint32_t ComputeDigest(ImutAVLTree* L, ImutAVLTree* R, value_type_ref V) { + uint32_t computeDigest(ImutAVLTree* L, ImutAVLTree* R, value_type_ref V) { uint32_t digest = 0; if (L) - digest += L->ComputeDigest(); + digest += L->computeDigest(); // Compute digest of stored data. FoldingSetNodeID ID; @@ -317,22 +306,54 @@ private: digest += ID.ComputeHash(); if (R) - digest += R->ComputeDigest(); + digest += R->computeDigest(); return digest; } - inline uint32_t ComputeDigest() { + inline uint32_t computeDigest() { // Check the lowest bit to determine if digest has actually been // pre-computed. if (hasCachedDigest()) - return Digest; + return digest; - uint32_t X = ComputeDigest(getLeft(), getRight(), getValue()); - Digest = X; - MarkedCachedDigest(); + uint32_t X = computeDigest(getLeft(), getRight(), getValue()); + digest = X; + markedCachedDigest(); return X; } + + //===----------------------------------------------------===// + // Reference count operations. + //===----------------------------------------------------===// + +public: + void retain() { ++refCount; } + void release() { + assert(refCount > 0); + if (--refCount == 0) + destroy(); + } + void destroy() { + if (left) + left->release(); + if (right) + right->release(); + if (IsCanonicalized) { + if (next) + next->prev = prev; + + if (prev) + prev->next = next; + else + factory->Cache[computeDigest()] = next; + } + + // We need to clear the mutability bit in case we are + // destroying the node as part of a sweep in ImutAVLFactory::recoverNodes(). + IsMutable = false; + factory->freeNodes.push_back(this); + } }; //===----------------------------------------------------------------------===// @@ -341,14 +362,17 @@ private: template class ImutAVLFactory { + friend class ImutAVLTree; typedef ImutAVLTree TreeTy; typedef typename TreeTy::value_type_ref value_type_ref; typedef typename TreeTy::key_type_ref key_type_ref; - typedef FoldingSet CacheTy; + typedef DenseMap CacheTy; CacheTy Cache; uintptr_t Allocator; + std::vector createdNodes; + std::vector freeNodes; bool ownsAllocator() const { return Allocator & 0x1 ? false : true; @@ -373,55 +397,56 @@ public: if (ownsAllocator()) delete &getAllocator(); } - TreeTy* Add(TreeTy* T, value_type_ref V) { - T = Add_internal(V,T); - MarkImmutable(T); + TreeTy* add(TreeTy* T, value_type_ref V) { + T = add_internal(V,T); + markImmutable(T); + recoverNodes(); return T; } - TreeTy* Remove(TreeTy* T, key_type_ref V) { - T = Remove_internal(V,T); - MarkImmutable(T); + TreeTy* remove(TreeTy* T, key_type_ref V) { + T = remove_internal(V,T); + markImmutable(T); + recoverNodes(); return T; } - TreeTy* GetEmptyTree() const { return NULL; } + TreeTy* getEmptyTree() const { return NULL; } +protected: + //===--------------------------------------------------===// // A bunch of quick helper functions used for reasoning // about the properties of trees and their children. // These have succinct names so that the balancing code // is as terse (and readable) as possible. //===--------------------------------------------------===// -protected: - bool isEmpty(TreeTy* T) const { return !T; } - unsigned Height(TreeTy* T) const { return T ? T->getHeight() : 0; } - TreeTy* Left(TreeTy* T) const { return T->getLeft(); } - TreeTy* Right(TreeTy* T) const { return T->getRight(); } - value_type_ref Value(TreeTy* T) const { return T->Value; } + bool isEmpty(TreeTy* T) const { return !T; } + unsigned getHeight(TreeTy* T) const { return T ? T->getHeight() : 0; } + TreeTy* getLeft(TreeTy* T) const { return T->getLeft(); } + TreeTy* getRight(TreeTy* T) const { return T->getRight(); } + value_type_ref getValue(TreeTy* T) const { return T->value; } - unsigned IncrementHeight(TreeTy* L, TreeTy* R) const { - unsigned hl = Height(L); - unsigned hr = Height(R); + unsigned incrementHeight(TreeTy* L, TreeTy* R) const { + unsigned hl = getHeight(L); + unsigned hr = getHeight(R); return (hl > hr ? hl : hr) + 1; } - static bool CompareTreeWithSection(TreeTy* T, + static bool compareTreeWithSection(TreeTy* T, typename TreeTy::iterator& TI, typename TreeTy::iterator& TE) { - typename TreeTy::iterator I = T->begin(), E = T->end(); - - for ( ; I!=E ; ++I, ++TI) - if (TI == TE || !I->ElementEqual(*TI)) + for ( ; I!=E ; ++I, ++TI) { + if (TI == TE || !I->isElementEqual(*TI)) return false; - + } return true; } //===--------------------------------------------------===// - // "CreateNode" is used to generate new tree roots that link + // "createNode" is used to generate new tree roots that link // to other trees. The functon may also simply move links // in an existing root if that root is still marked mutable. // This is necessary because otherwise our balancing code @@ -430,181 +455,188 @@ protected: // returned to the caller. //===--------------------------------------------------===// - TreeTy* CreateNode(TreeTy* L, value_type_ref V, TreeTy* R) { + TreeTy* createNode(TreeTy* L, value_type_ref V, TreeTy* R) { BumpPtrAllocator& A = getAllocator(); - TreeTy* T = (TreeTy*) A.Allocate(); - new (T) TreeTy(L, R, V, IncrementHeight(L,R)); + TreeTy* T; + if (!freeNodes.empty()) { + T = freeNodes.back(); + freeNodes.pop_back(); + assert(T != L); + assert(T != R); + } + else { + T = (TreeTy*) A.Allocate(); + } + new (T) TreeTy(this, L, R, V, incrementHeight(L,R)); + createdNodes.push_back(T); return T; } - TreeTy* CreateNode(TreeTy* L, TreeTy* OldTree, TreeTy* R) { - assert(!isEmpty(OldTree)); + TreeTy* createNode(TreeTy* newLeft, TreeTy* oldTree, TreeTy* newRight) { + return createNode(newLeft, getValue(oldTree), newRight); + } - if (OldTree->isMutable()) { - OldTree->setLeft(L); - OldTree->setRight(R); - OldTree->setHeight(IncrementHeight(L, R)); - return OldTree; + void recoverNodes() { + for (unsigned i = 0, n = createdNodes.size(); i < n; ++i) { + TreeTy *N = createdNodes[i]; + if (N->isMutable() && N->refCount == 0) + N->destroy(); } - else - return CreateNode(L, Value(OldTree), R); + createdNodes.clear(); } - /// Balance - Used by Add_internal and Remove_internal to + /// balanceTree - Used by add_internal and remove_internal to /// balance a newly created tree. - TreeTy* Balance(TreeTy* L, value_type_ref V, TreeTy* R) { - - unsigned hl = Height(L); - unsigned hr = Height(R); + TreeTy* balanceTree(TreeTy* L, value_type_ref V, TreeTy* R) { + unsigned hl = getHeight(L); + unsigned hr = getHeight(R); if (hl > hr + 2) { assert(!isEmpty(L) && "Left tree cannot be empty to have a height >= 2"); - TreeTy* LL = Left(L); - TreeTy* LR = Right(L); + TreeTy *LL = getLeft(L); + TreeTy *LR = getRight(L); - if (Height(LL) >= Height(LR)) - return CreateNode(LL, L, CreateNode(LR,V,R)); + if (getHeight(LL) >= getHeight(LR)) + return createNode(LL, L, createNode(LR,V,R)); assert(!isEmpty(LR) && "LR cannot be empty because it has a height >= 1"); - TreeTy* LRL = Left(LR); - TreeTy* LRR = Right(LR); + TreeTy *LRL = getLeft(LR); + TreeTy *LRR = getRight(LR); - return CreateNode(CreateNode(LL,L,LRL), LR, CreateNode(LRR,V,R)); + return createNode(createNode(LL,L,LRL), LR, createNode(LRR,V,R)); } else if (hr > hl + 2) { assert(!isEmpty(R) && "Right tree cannot be empty to have a height >= 2"); - TreeTy* RL = Left(R); - TreeTy* RR = Right(R); + TreeTy *RL = getLeft(R); + TreeTy *RR = getRight(R); - if (Height(RR) >= Height(RL)) - return CreateNode(CreateNode(L,V,RL), R, RR); + if (getHeight(RR) >= getHeight(RL)) + return createNode(createNode(L,V,RL), R, RR); assert(!isEmpty(RL) && "RL cannot be empty because it has a height >= 1"); - TreeTy* RLL = Left(RL); - TreeTy* RLR = Right(RL); + TreeTy *RLL = getLeft(RL); + TreeTy *RLR = getRight(RL); - return CreateNode(CreateNode(L,V,RLL), RL, CreateNode(RLR,R,RR)); + return createNode(createNode(L,V,RLL), RL, createNode(RLR,R,RR)); } else - return CreateNode(L,V,R); + return createNode(L,V,R); } - /// Add_internal - Creates a new tree that includes the specified + /// add_internal - Creates a new tree that includes the specified /// data and the data from the original tree. If the original tree /// already contained the data item, the original tree is returned. - TreeTy* Add_internal(value_type_ref V, TreeTy* T) { + TreeTy* add_internal(value_type_ref V, TreeTy* T) { if (isEmpty(T)) - return CreateNode(T, V, T); - + return createNode(T, V, T); assert(!T->isMutable()); key_type_ref K = ImutInfo::KeyOfValue(V); - key_type_ref KCurrent = ImutInfo::KeyOfValue(Value(T)); + key_type_ref KCurrent = ImutInfo::KeyOfValue(getValue(T)); if (ImutInfo::isEqual(K,KCurrent)) - return CreateNode(Left(T), V, Right(T)); + return createNode(getLeft(T), V, getRight(T)); else if (ImutInfo::isLess(K,KCurrent)) - return Balance(Add_internal(V,Left(T)), Value(T), Right(T)); + return balanceTree(add_internal(V, getLeft(T)), getValue(T), getRight(T)); else - return Balance(Left(T), Value(T), Add_internal(V,Right(T))); + return balanceTree(getLeft(T), getValue(T), add_internal(V, getRight(T))); } - /// Remove_internal - Creates a new tree that includes all the data + /// remove_internal - Creates a new tree that includes all the data /// from the original tree except the specified data. If the /// specified data did not exist in the original tree, the original /// tree is returned. - TreeTy* Remove_internal(key_type_ref K, TreeTy* T) { + TreeTy* remove_internal(key_type_ref K, TreeTy* T) { if (isEmpty(T)) return T; assert(!T->isMutable()); - key_type_ref KCurrent = ImutInfo::KeyOfValue(Value(T)); + key_type_ref KCurrent = ImutInfo::KeyOfValue(getValue(T)); - if (ImutInfo::isEqual(K,KCurrent)) - return CombineLeftRightTrees(Left(T),Right(T)); - else if (ImutInfo::isLess(K,KCurrent)) - return Balance(Remove_internal(K,Left(T)), Value(T), Right(T)); - else - return Balance(Left(T), Value(T), Remove_internal(K,Right(T))); + if (ImutInfo::isEqual(K,KCurrent)) { + return combineTrees(getLeft(T), getRight(T)); + } else if (ImutInfo::isLess(K,KCurrent)) { + return balanceTree(remove_internal(K, getLeft(T)), + getValue(T), getRight(T)); + } else { + return balanceTree(getLeft(T), getValue(T), + remove_internal(K, getRight(T))); + } } - TreeTy* CombineLeftRightTrees(TreeTy* L, TreeTy* R) { - if (isEmpty(L)) return R; - if (isEmpty(R)) return L; - + TreeTy* combineTrees(TreeTy* L, TreeTy* R) { + if (isEmpty(L)) + return R; + if (isEmpty(R)) + return L; TreeTy* OldNode; - TreeTy* NewRight = RemoveMinBinding(R,OldNode); - return Balance(L,Value(OldNode),NewRight); + TreeTy* newRight = removeMinBinding(R,OldNode); + return balanceTree(L, getValue(OldNode), newRight); } - TreeTy* RemoveMinBinding(TreeTy* T, TreeTy*& NodeRemoved) { + TreeTy* removeMinBinding(TreeTy* T, TreeTy*& Noderemoved) { assert(!isEmpty(T)); - - if (isEmpty(Left(T))) { - NodeRemoved = T; - return Right(T); + if (isEmpty(getLeft(T))) { + Noderemoved = T; + return getRight(T); } - - return Balance(RemoveMinBinding(Left(T),NodeRemoved),Value(T),Right(T)); + return balanceTree(removeMinBinding(getLeft(T), Noderemoved), + getValue(T), getRight(T)); } - /// MarkImmutable - Clears the mutable bits of a root and all of its + /// markImmutable - Clears the mutable bits of a root and all of its /// descendants. - void MarkImmutable(TreeTy* T) { + void markImmutable(TreeTy* T) { if (!T || !T->isMutable()) return; - - T->MarkImmutable(); - MarkImmutable(Left(T)); - MarkImmutable(Right(T)); + T->markImmutable(); + markImmutable(getLeft(T)); + markImmutable(getRight(T)); } public: - TreeTy *GetCanonicalTree(TreeTy *TNew) { + TreeTy *getCanonicalTree(TreeTy *TNew) { if (!TNew) - return NULL; - - // Search the FoldingSet bucket for a Tree with the same digest. - FoldingSetNodeID ID; - unsigned digest = TNew->ComputeDigest(); - ID.AddInteger(digest); - unsigned hash = ID.ComputeHash(); - - typename CacheTy::bucket_iterator I = Cache.bucket_begin(hash); - typename CacheTy::bucket_iterator E = Cache.bucket_end(hash); - - for (; I != E; ++I) { - TreeTy *T = &*I; - - if (T->ComputeDigest() != digest) - continue; - - // We found a collision. Perform a comparison of Contents('T') - // with Contents('TNew') - typename TreeTy::iterator TI = T->begin(), TE = T->end(); - - if (!CompareTreeWithSection(TNew, TI, TE)) - continue; - - if (TI != TE) - continue; // T has more contents than TNew. - - // Trees did match! Return 'T'. - return T; + return 0; + + if (TNew->IsCanonicalized) + return TNew; + + // Search the hashtable for another tree with the same digest, and + // if find a collision compare those trees by their contents. + unsigned digest = TNew->computeDigest(); + TreeTy *&entry = Cache[digest]; + do { + if (!entry) + break; + for (TreeTy *T = entry ; T != 0; T = T->next) { + // Compare the Contents('T') with Contents('TNew') + typename TreeTy::iterator TI = T->begin(), TE = T->end(); + if (!compareTreeWithSection(TNew, TI, TE)) + continue; + if (TI != TE) + continue; // T has more contents than TNew. + // Trees did match! Return 'T'. + if (TNew->refCount == 0) + TNew->destroy(); + return T; + } + entry->prev = TNew; + TNew->next = entry; } + while (false); - // 'TNew' is the only tree of its kind. Return it. - Cache.InsertNode(TNew, (void*) &*Cache.bucket_end(hash)); + entry = TNew; + TNew->IsCanonicalized = true; return TNew; } }; - //===----------------------------------------------------------------------===// // Immutable AVL-Tree Iterators. //===----------------------------------------------------------------------===// @@ -635,19 +667,17 @@ public: } - bool AtEnd() const { return stack.empty(); } + bool atEnd() const { return stack.empty(); } - bool AtBeginning() const { + bool atBeginning() const { return stack.size() == 1 && getVisitState() == VisitedNone; } - void SkipToParent() { + void skipToParent() { assert(!stack.empty()); stack.pop_back(); - if (stack.empty()) return; - switch (getVisitState()) { case VisitedNone: stack.back() |= VisitedLeft; @@ -663,11 +693,9 @@ public: inline bool operator==(const _Self& x) const { if (stack.size() != x.stack.size()) return false; - for (unsigned i = 0 ; i < stack.size(); i++) if (stack[i] != x.stack[i]) return false; - return true; } @@ -675,70 +703,52 @@ public: _Self& operator++() { assert(!stack.empty()); - TreeTy* Current = reinterpret_cast(stack.back() & ~Flags); assert(Current); - switch (getVisitState()) { case VisitedNone: if (TreeTy* L = Current->getLeft()) stack.push_back(reinterpret_cast(L)); else stack.back() |= VisitedLeft; - break; - case VisitedLeft: if (TreeTy* R = Current->getRight()) stack.push_back(reinterpret_cast(R)); else stack.back() |= VisitedRight; - break; - case VisitedRight: - SkipToParent(); + skipToParent(); break; - default: assert(false && "Unreachable."); } - return *this; } _Self& operator--() { assert(!stack.empty()); - TreeTy* Current = reinterpret_cast(stack.back() & ~Flags); assert(Current); - switch (getVisitState()) { case VisitedNone: stack.pop_back(); break; - case VisitedLeft: stack.back() &= ~Flags; // Set state to "VisitedNone." - if (TreeTy* L = Current->getLeft()) stack.push_back(reinterpret_cast(L) | VisitedRight); - break; - case VisitedRight: stack.back() &= ~Flags; stack.back() |= VisitedLeft; - if (TreeTy* R = Current->getRight()) stack.push_back(reinterpret_cast(R) | VisitedRight); - break; - default: assert(false && "Unreachable."); } - return *this; } }; @@ -769,7 +779,7 @@ public: inline _Self& operator++() { do ++InternalItr; - while (!InternalItr.AtEnd() && + while (!InternalItr.atEnd() && InternalItr.getVisitState() != InternalIteratorTy::VisitedLeft); return *this; @@ -777,16 +787,16 @@ public: inline _Self& operator--() { do --InternalItr; - while (!InternalItr.AtBeginning() && + while (!InternalItr.atBeginning() && InternalItr.getVisitState() != InternalIteratorTy::VisitedLeft); return *this; } - inline void SkipSubTree() { - InternalItr.SkipToParent(); + inline void skipSubTree() { + InternalItr.skipToParent(); - while (!InternalItr.AtEnd() && + while (!InternalItr.atEnd() && InternalItr.getVisitState() != InternalIteratorTy::VisitedLeft) ++InternalItr; } @@ -927,7 +937,23 @@ public: /// should use a Factory object to create sets instead of directly /// invoking the constructor, but there are cases where make this /// constructor public is useful. - explicit ImmutableSet(TreeTy* R) : Root(R) {} + explicit ImmutableSet(TreeTy* R) : Root(R) { + if (Root) { Root->retain(); } + } + ImmutableSet(const ImmutableSet &X) : Root(X.Root) { + if (Root) { Root->retain(); } + } + ImmutableSet &operator=(const ImmutableSet &X) { + if (Root != X.Root) { + if (X.Root) { X.Root->retain(); } + if (Root) { Root->release(); } + Root = X.Root; + } + return *this; + } + ~ImmutableSet() { + if (Root) { Root->release(); } + } class Factory { typename TreeTy::Factory F; @@ -940,33 +966,33 @@ public: Factory(BumpPtrAllocator& Alloc, bool canonicalize = true) : F(Alloc), Canonicalize(canonicalize) {} - /// GetEmptySet - Returns an immutable set that contains no elements. - ImmutableSet GetEmptySet() { - return ImmutableSet(F.GetEmptyTree()); + /// getEmptySet - Returns an immutable set that contains no elements. + ImmutableSet getEmptySet() { + return ImmutableSet(F.getEmptyTree()); } - /// Add - Creates a new immutable set that contains all of the values + /// add - Creates a new immutable set that contains all of the values /// of the original set with the addition of the specified value. If /// the original set already included the value, then the original set is /// returned and no memory is allocated. The time and space complexity /// of this operation is logarithmic in the size of the original set. /// The memory allocated to represent the set is released when the /// factory object that created the set is destroyed. - ImmutableSet Add(ImmutableSet Old, value_type_ref V) { - TreeTy *NewT = F.Add(Old.Root, V); - return ImmutableSet(Canonicalize ? F.GetCanonicalTree(NewT) : NewT); + ImmutableSet add(ImmutableSet Old, value_type_ref V) { + TreeTy *NewT = F.add(Old.Root, V); + return ImmutableSet(Canonicalize ? F.getCanonicalTree(NewT) : NewT); } - /// Remove - Creates a new immutable set that contains all of the values + /// remove - Creates a new immutable set that contains all of the values /// of the original set with the exception of the specified value. If /// the original set did not contain the value, the original set is /// returned and no memory is allocated. The time and space complexity /// of this operation is logarithmic in the size of the original set. /// The memory allocated to represent the set is released when the /// factory object that created the set is destroyed. - ImmutableSet Remove(ImmutableSet Old, value_type_ref V) { - TreeTy *NewT = F.Remove(Old.Root, V); - return ImmutableSet(Canonicalize ? F.GetCanonicalTree(NewT) : NewT); + ImmutableSet remove(ImmutableSet Old, value_type_ref V) { + TreeTy *NewT = F.remove(Old.Root, V); + return ImmutableSet(Canonicalize ? F.getCanonicalTree(NewT) : NewT); } BumpPtrAllocator& getAllocator() { return F.getAllocator(); } @@ -978,20 +1004,21 @@ public: friend class Factory; - /// contains - Returns true if the set contains the specified value. + /// Returns true if the set contains the specified value. bool contains(value_type_ref V) const { return Root ? Root->contains(V) : false; } - bool operator==(ImmutableSet RHS) const { + bool operator==(const ImmutableSet &RHS) const { return Root && RHS.Root ? Root->isEqual(*RHS.Root) : Root == RHS.Root; } - bool operator!=(ImmutableSet RHS) const { + bool operator!=(const ImmutableSet &RHS) const { return Root && RHS.Root ? Root->isNotEqual(*RHS.Root) : Root != RHS.Root; } TreeTy *getRoot() { + if (Root) { Root->retain(); } return Root; } @@ -1049,7 +1076,7 @@ public: // For testing. //===--------------------------------------------------===// - void verify() const { if (Root) Root->verify(); } + void validateTree() const { if (Root) Root->validateTree(); } }; } // end namespace llvm diff --git a/include/llvm/ADT/InMemoryStruct.h b/include/llvm/ADT/InMemoryStruct.h new file mode 100644 index 000000000000..a56084501a62 --- /dev/null +++ b/include/llvm/ADT/InMemoryStruct.h @@ -0,0 +1,77 @@ +//===- InMemoryStruct.h - Indirect Struct Access Smart Pointer --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_INMEMORYSTRUCT_H +#define LLVM_ADT_INMEMORYSTRUCT_H + +#include + +namespace llvm { + +/// \brief Helper object for abstracting access to an in-memory structure which +/// may require some kind of temporary storage. +/// +/// This class is designed to be used for accessing file data structures which +/// in the common case can be accessed from a direct pointer to a memory mapped +/// object, but which in some cases may require indirect access to a temporary +/// structure (which, for example, may have undergone endianness translation). +template +class InMemoryStruct { + typedef T value_type; + typedef value_type &reference; + typedef value_type *pointer; + typedef const value_type &const_reference; + typedef const value_type *const_pointer; + + /// \brief The smart pointer target. + value_type *Target; + + /// \brief A temporary object which can be used as a target of the smart + /// pointer. + value_type Contents; + +private: + +public: + InMemoryStruct() : Target(0) {} + InMemoryStruct(reference Value) : Target(&Contents), Contents(Value) {} + InMemoryStruct(pointer Value) : Target(Value) {} + InMemoryStruct(const InMemoryStruct &Value) { *this = Value; } + + void operator=(const InMemoryStruct &Value) { + if (Value.Target != &Value.Contents) { + Target = Value.Target; + } else { + Target = &Contents; + Contents = Value.Contents; + } + } + + const_reference operator*() const { + assert(Target && "Cannot dereference null pointer"); + return *Target; + } + reference operator*() { + assert(Target && "Cannot dereference null pointer"); + return *Target; + } + + const_pointer operator->() const { + return Target; + } + pointer operator->() { + return Target; + } + + operator bool() const { return Target != 0; } +}; + +} + +#endif diff --git a/include/llvm/ADT/IndexedMap.h b/include/llvm/ADT/IndexedMap.h index 89f0dfa64e1c..87126ea49187 100644 --- a/include/llvm/ADT/IndexedMap.h +++ b/include/llvm/ADT/IndexedMap.h @@ -55,6 +55,14 @@ namespace llvm { return storage_[toIndex_(n)]; } + void reserve(typename StorageT::size_type s) { + storage_.reserve(s); + } + + void resize(typename StorageT::size_type s) { + storage_.resize(s, nullVal_); + } + void clear() { storage_.clear(); } @@ -62,7 +70,11 @@ namespace llvm { void grow(IndexT n) { unsigned NewSize = toIndex_(n) + 1; if (NewSize > storage_.size()) - storage_.resize(NewSize, nullVal_); + resize(NewSize); + } + + bool inBounds(IndexT n) const { + return toIndex_(n) < storage_.size(); } typename StorageT::size_type size() const { diff --git a/include/llvm/ADT/IntEqClasses.h b/include/llvm/ADT/IntEqClasses.h new file mode 100644 index 000000000000..8e75c48e3764 --- /dev/null +++ b/include/llvm/ADT/IntEqClasses.h @@ -0,0 +1,88 @@ +//===-- llvm/ADT/IntEqClasses.h - Equiv. Classes of Integers ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Equivalence classes for small integers. This is a mapping of the integers +// 0 .. N-1 into M equivalence classes numbered 0 .. M-1. +// +// Initially each integer has its own equivalence class. Classes are joined by +// passing a representative member of each class to join(). +// +// Once the classes are built, compress() will number them 0 .. M-1 and prevent +// further changes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_INTEQCLASSES_H +#define LLVM_ADT_INTEQCLASSES_H + +#include "llvm/ADT/SmallVector.h" + +namespace llvm { + +class IntEqClasses { + /// EC - When uncompressed, map each integer to a smaller member of its + /// equivalence class. The class leader is the smallest member and maps to + /// itself. + /// + /// When compressed, EC[i] is the equivalence class of i. + SmallVector EC; + + /// NumClasses - The number of equivalence classes when compressed, or 0 when + /// uncompressed. + unsigned NumClasses; + +public: + /// IntEqClasses - Create an equivalence class mapping for 0 .. N-1. + IntEqClasses(unsigned N = 0) : NumClasses(0) { grow(N); } + + /// grow - Increase capacity to hold 0 .. N-1, putting new integers in unique + /// equivalence classes. + /// This requires an uncompressed map. + void grow(unsigned N); + + /// clear - Clear all classes so that grow() will assign a unique class to + /// every integer. + void clear() { + EC.clear(); + NumClasses = 0; + } + + /// join - Join the equivalence classes of a and b. After joining classes, + /// findLeader(a) == findLeader(b). + /// This requires an uncompressed map. + void join(unsigned a, unsigned b); + + /// findLeader - Compute the leader of a's equivalence class. This is the + /// smallest member of the class. + /// This requires an uncompressed map. + unsigned findLeader(unsigned a) const; + + /// compress - Compress equivalence classes by numbering them 0 .. M. + /// This makes the equivalence class map immutable. + void compress(); + + /// getNumClasses - Return the number of equivalence classes after compress() + /// was called. + unsigned getNumClasses() const { return NumClasses; } + + /// operator[] - Return a's equivalence class number, 0 .. getNumClasses()-1. + /// This requires a compressed map. + unsigned operator[](unsigned a) const { + assert(NumClasses && "operator[] called before compress()"); + return EC[a]; + } + + /// uncompress - Change back to the uncompressed representation that allows + /// editing. + void uncompress(); +}; + +} // End llvm namespace + +#endif diff --git a/include/llvm/ADT/IntervalMap.h b/include/llvm/ADT/IntervalMap.h new file mode 100644 index 000000000000..79f24d31c068 --- /dev/null +++ b/include/llvm/ADT/IntervalMap.h @@ -0,0 +1,2139 @@ +//===- llvm/ADT/IntervalMap.h - A sorted interval map -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a coalescing interval map for small objects. +// +// KeyT objects are mapped to ValT objects. Intervals of keys that map to the +// same value are represented in a compressed form. +// +// Iterators provide ordered access to the compressed intervals rather than the +// individual keys, and insert and erase operations use key intervals as well. +// +// Like SmallVector, IntervalMap will store the first N intervals in the map +// object itself without any allocations. When space is exhausted it switches to +// a B+-tree representation with very small overhead for small key and value +// objects. +// +// A Traits class specifies how keys are compared. It also allows IntervalMap to +// work with both closed and half-open intervals. +// +// Keys and values are not stored next to each other in a std::pair, so we don't +// provide such a value_type. Dereferencing iterators only returns the mapped +// value. The interval bounds are accessible through the start() and stop() +// iterator methods. +// +// IntervalMap is optimized for small key and value objects, 4 or 8 bytes each +// is the optimal size. For large objects use std::map instead. +// +//===----------------------------------------------------------------------===// +// +// Synopsis: +// +// template +// class IntervalMap { +// public: +// typedef KeyT key_type; +// typedef ValT mapped_type; +// typedef RecyclingAllocator<...> Allocator; +// class iterator; +// class const_iterator; +// +// explicit IntervalMap(Allocator&); +// ~IntervalMap(): +// +// bool empty() const; +// KeyT start() const; +// KeyT stop() const; +// ValT lookup(KeyT x, Value NotFound = Value()) const; +// +// const_iterator begin() const; +// const_iterator end() const; +// iterator begin(); +// iterator end(); +// const_iterator find(KeyT x) const; +// iterator find(KeyT x); +// +// void insert(KeyT a, KeyT b, ValT y); +// void clear(); +// }; +// +// template +// class IntervalMap::const_iterator : +// public std::iterator { +// public: +// bool operator==(const const_iterator &) const; +// bool operator!=(const const_iterator &) const; +// bool valid() const; +// +// const KeyT &start() const; +// const KeyT &stop() const; +// const ValT &value() const; +// const ValT &operator*() const; +// const ValT *operator->() const; +// +// const_iterator &operator++(); +// const_iterator &operator++(int); +// const_iterator &operator--(); +// const_iterator &operator--(int); +// void goToBegin(); +// void goToEnd(); +// void find(KeyT x); +// void advanceTo(KeyT x); +// }; +// +// template +// class IntervalMap::iterator : public const_iterator { +// public: +// void insert(KeyT a, KeyT b, Value y); +// void erase(); +// }; +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_INTERVALMAP_H +#define LLVM_ADT_INTERVALMAP_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/RecyclingAllocator.h" +#include + +namespace llvm { + + +//===----------------------------------------------------------------------===// +//--- Key traits ---// +//===----------------------------------------------------------------------===// +// +// The IntervalMap works with closed or half-open intervals. +// Adjacent intervals that map to the same value are coalesced. +// +// The IntervalMapInfo traits class is used to determine if a key is contained +// in an interval, and if two intervals are adjacent so they can be coalesced. +// The provided implementation works for closed integer intervals, other keys +// probably need a specialized version. +// +// The point x is contained in [a;b] when !startLess(x, a) && !stopLess(b, x). +// +// It is assumed that (a;b] half-open intervals are not used, only [a;b) is +// allowed. This is so that stopLess(a, b) can be used to determine if two +// intervals overlap. +// +//===----------------------------------------------------------------------===// + +template +struct IntervalMapInfo { + + /// startLess - Return true if x is not in [a;b]. + /// This is x < a both for closed intervals and for [a;b) half-open intervals. + static inline bool startLess(const T &x, const T &a) { + return x < a; + } + + /// stopLess - Return true if x is not in [a;b]. + /// This is b < x for a closed interval, b <= x for [a;b) half-open intervals. + static inline bool stopLess(const T &b, const T &x) { + return b < x; + } + + /// adjacent - Return true when the intervals [x;a] and [b;y] can coalesce. + /// This is a+1 == b for closed intervals, a == b for half-open intervals. + static inline bool adjacent(const T &a, const T &b) { + return a+1 == b; + } + +}; + +/// IntervalMapImpl - Namespace used for IntervalMap implementation details. +/// It should be considered private to the implementation. +namespace IntervalMapImpl { + +// Forward declarations. +template class LeafNode; +template class BranchNode; + +typedef std::pair IdxPair; + + +//===----------------------------------------------------------------------===// +//--- IntervalMapImpl::NodeBase ---// +//===----------------------------------------------------------------------===// +// +// Both leaf and branch nodes store vectors of pairs. +// Leaves store ((KeyT, KeyT), ValT) pairs, branches use (NodeRef, KeyT). +// +// Keys and values are stored in separate arrays to avoid padding caused by +// different object alignments. This also helps improve locality of reference +// when searching the keys. +// +// The nodes don't know how many elements they contain - that information is +// stored elsewhere. Omitting the size field prevents padding and allows a node +// to fill the allocated cache lines completely. +// +// These are typical key and value sizes, the node branching factor (N), and +// wasted space when nodes are sized to fit in three cache lines (192 bytes): +// +// T1 T2 N Waste Used by +// 4 4 24 0 Branch<4> (32-bit pointers) +// 8 4 16 0 Leaf<4,4>, Branch<4> +// 8 8 12 0 Leaf<4,8>, Branch<8> +// 16 4 9 12 Leaf<8,4> +// 16 8 8 0 Leaf<8,8> +// +//===----------------------------------------------------------------------===// + +template +class NodeBase { +public: + enum { Capacity = N }; + + T1 first[N]; + T2 second[N]; + + /// copy - Copy elements from another node. + /// @param Other Node elements are copied from. + /// @param i Beginning of the source range in other. + /// @param j Beginning of the destination range in this. + /// @param Count Number of elements to copy. + template + void copy(const NodeBase &Other, unsigned i, + unsigned j, unsigned Count) { + assert(i + Count <= M && "Invalid source range"); + assert(j + Count <= N && "Invalid dest range"); + for (unsigned e = i + Count; i != e; ++i, ++j) { + first[j] = Other.first[i]; + second[j] = Other.second[i]; + } + } + + /// moveLeft - Move elements to the left. + /// @param i Beginning of the source range. + /// @param j Beginning of the destination range. + /// @param Count Number of elements to copy. + void moveLeft(unsigned i, unsigned j, unsigned Count) { + assert(j <= i && "Use moveRight shift elements right"); + copy(*this, i, j, Count); + } + + /// moveRight - Move elements to the right. + /// @param i Beginning of the source range. + /// @param j Beginning of the destination range. + /// @param Count Number of elements to copy. + void moveRight(unsigned i, unsigned j, unsigned Count) { + assert(i <= j && "Use moveLeft shift elements left"); + assert(j + Count <= N && "Invalid range"); + while (Count--) { + first[j + Count] = first[i + Count]; + second[j + Count] = second[i + Count]; + } + } + + /// erase - Erase elements [i;j). + /// @param i Beginning of the range to erase. + /// @param j End of the range. (Exclusive). + /// @param Size Number of elements in node. + void erase(unsigned i, unsigned j, unsigned Size) { + moveLeft(j, i, Size - j); + } + + /// erase - Erase element at i. + /// @param i Index of element to erase. + /// @param Size Number of elements in node. + void erase(unsigned i, unsigned Size) { + erase(i, i+1, Size); + } + + /// shift - Shift elements [i;size) 1 position to the right. + /// @param i Beginning of the range to move. + /// @param Size Number of elements in node. + void shift(unsigned i, unsigned Size) { + moveRight(i, i + 1, Size - i); + } + + /// transferToLeftSib - Transfer elements to a left sibling node. + /// @param Size Number of elements in this. + /// @param Sib Left sibling node. + /// @param SSize Number of elements in sib. + /// @param Count Number of elements to transfer. + void transferToLeftSib(unsigned Size, NodeBase &Sib, unsigned SSize, + unsigned Count) { + Sib.copy(*this, 0, SSize, Count); + erase(0, Count, Size); + } + + /// transferToRightSib - Transfer elements to a right sibling node. + /// @param Size Number of elements in this. + /// @param Sib Right sibling node. + /// @param SSize Number of elements in sib. + /// @param Count Number of elements to transfer. + void transferToRightSib(unsigned Size, NodeBase &Sib, unsigned SSize, + unsigned Count) { + Sib.moveRight(0, Count, SSize); + Sib.copy(*this, Size-Count, 0, Count); + } + + /// adjustFromLeftSib - Adjust the number if elements in this node by moving + /// elements to or from a left sibling node. + /// @param Size Number of elements in this. + /// @param Sib Right sibling node. + /// @param SSize Number of elements in sib. + /// @param Add The number of elements to add to this node, possibly < 0. + /// @return Number of elements added to this node, possibly negative. + int adjustFromLeftSib(unsigned Size, NodeBase &Sib, unsigned SSize, int Add) { + if (Add > 0) { + // We want to grow, copy from sib. + unsigned Count = std::min(std::min(unsigned(Add), SSize), N - Size); + Sib.transferToRightSib(SSize, *this, Size, Count); + return Count; + } else { + // We want to shrink, copy to sib. + unsigned Count = std::min(std::min(unsigned(-Add), Size), N - SSize); + transferToLeftSib(Size, Sib, SSize, Count); + return -Count; + } + } +}; + +/// IntervalMapImpl::adjustSiblingSizes - Move elements between sibling nodes. +/// @param Node Array of pointers to sibling nodes. +/// @param Nodes Number of nodes. +/// @param CurSize Array of current node sizes, will be overwritten. +/// @param NewSize Array of desired node sizes. +template +void adjustSiblingSizes(NodeT *Node[], unsigned Nodes, + unsigned CurSize[], const unsigned NewSize[]) { + // Move elements right. + for (int n = Nodes - 1; n; --n) { + if (CurSize[n] == NewSize[n]) + continue; + for (int m = n - 1; m != -1; --m) { + int d = Node[n]->adjustFromLeftSib(CurSize[n], *Node[m], CurSize[m], + NewSize[n] - CurSize[n]); + CurSize[m] -= d; + CurSize[n] += d; + // Keep going if the current node was exhausted. + if (CurSize[n] >= NewSize[n]) + break; + } + } + + if (Nodes == 0) + return; + + // Move elements left. + for (unsigned n = 0; n != Nodes - 1; ++n) { + if (CurSize[n] == NewSize[n]) + continue; + for (unsigned m = n + 1; m != Nodes; ++m) { + int d = Node[m]->adjustFromLeftSib(CurSize[m], *Node[n], CurSize[n], + CurSize[n] - NewSize[n]); + CurSize[m] += d; + CurSize[n] -= d; + // Keep going if the current node was exhausted. + if (CurSize[n] >= NewSize[n]) + break; + } + } + +#ifndef NDEBUG + for (unsigned n = 0; n != Nodes; n++) + assert(CurSize[n] == NewSize[n] && "Insufficient element shuffle"); +#endif +} + +/// IntervalMapImpl::distribute - Compute a new distribution of node elements +/// after an overflow or underflow. Reserve space for a new element at Position, +/// and compute the node that will hold Position after redistributing node +/// elements. +/// +/// It is required that +/// +/// Elements == sum(CurSize), and +/// Elements + Grow <= Nodes * Capacity. +/// +/// NewSize[] will be filled in such that: +/// +/// sum(NewSize) == Elements, and +/// NewSize[i] <= Capacity. +/// +/// The returned index is the node where Position will go, so: +/// +/// sum(NewSize[0..idx-1]) <= Position +/// sum(NewSize[0..idx]) >= Position +/// +/// The last equality, sum(NewSize[0..idx]) == Position, can only happen when +/// Grow is set and NewSize[idx] == Capacity-1. The index points to the node +/// before the one holding the Position'th element where there is room for an +/// insertion. +/// +/// @param Nodes The number of nodes. +/// @param Elements Total elements in all nodes. +/// @param Capacity The capacity of each node. +/// @param CurSize Array[Nodes] of current node sizes, or NULL. +/// @param NewSize Array[Nodes] to receive the new node sizes. +/// @param Position Insert position. +/// @param Grow Reserve space for a new element at Position. +/// @return (node, offset) for Position. +IdxPair distribute(unsigned Nodes, unsigned Elements, unsigned Capacity, + const unsigned *CurSize, unsigned NewSize[], + unsigned Position, bool Grow); + + +//===----------------------------------------------------------------------===// +//--- IntervalMapImpl::NodeSizer ---// +//===----------------------------------------------------------------------===// +// +// Compute node sizes from key and value types. +// +// The branching factors are chosen to make nodes fit in three cache lines. +// This may not be possible if keys or values are very large. Such large objects +// are handled correctly, but a std::map would probably give better performance. +// +//===----------------------------------------------------------------------===// + +enum { + // Cache line size. Most architectures have 32 or 64 byte cache lines. + // We use 64 bytes here because it provides good branching factors. + Log2CacheLine = 6, + CacheLineBytes = 1 << Log2CacheLine, + DesiredNodeBytes = 3 * CacheLineBytes +}; + +template +struct NodeSizer { + enum { + // Compute the leaf node branching factor that makes a node fit in three + // cache lines. The branching factor must be at least 3, or some B+-tree + // balancing algorithms won't work. + // LeafSize can't be larger than CacheLineBytes. This is required by the + // PointerIntPair used by NodeRef. + DesiredLeafSize = DesiredNodeBytes / + static_cast(2*sizeof(KeyT)+sizeof(ValT)), + MinLeafSize = 3, + LeafSize = DesiredLeafSize > MinLeafSize ? DesiredLeafSize : MinLeafSize + }; + + typedef NodeBase, ValT, LeafSize> LeafBase; + + enum { + // Now that we have the leaf branching factor, compute the actual allocation + // unit size by rounding up to a whole number of cache lines. + AllocBytes = (sizeof(LeafBase) + CacheLineBytes-1) & ~(CacheLineBytes-1), + + // Determine the branching factor for branch nodes. + BranchSize = AllocBytes / + static_cast(sizeof(KeyT) + sizeof(void*)) + }; + + /// Allocator - The recycling allocator used for both branch and leaf nodes. + /// This typedef is very likely to be identical for all IntervalMaps with + /// reasonably sized entries, so the same allocator can be shared among + /// different kinds of maps. + typedef RecyclingAllocator Allocator; + +}; + + +//===----------------------------------------------------------------------===// +//--- IntervalMapImpl::NodeRef ---// +//===----------------------------------------------------------------------===// +// +// B+-tree nodes can be leaves or branches, so we need a polymorphic node +// pointer that can point to both kinds. +// +// All nodes are cache line aligned and the low 6 bits of a node pointer are +// always 0. These bits are used to store the number of elements in the +// referenced node. Besides saving space, placing node sizes in the parents +// allow tree balancing algorithms to run without faulting cache lines for nodes +// that may not need to be modified. +// +// A NodeRef doesn't know whether it references a leaf node or a branch node. +// It is the responsibility of the caller to use the correct types. +// +// Nodes are never supposed to be empty, and it is invalid to store a node size +// of 0 in a NodeRef. The valid range of sizes is 1-64. +// +//===----------------------------------------------------------------------===// + +class NodeRef { + struct CacheAlignedPointerTraits { + static inline void *getAsVoidPointer(void *P) { return P; } + static inline void *getFromVoidPointer(void *P) { return P; } + enum { NumLowBitsAvailable = Log2CacheLine }; + }; + PointerIntPair pip; + +public: + /// NodeRef - Create a null ref. + NodeRef() {} + + /// operator bool - Detect a null ref. + operator bool() const { return pip.getOpaqueValue(); } + + /// NodeRef - Create a reference to the node p with n elements. + template + NodeRef(NodeT *p, unsigned n) : pip(p, n - 1) { + assert(n <= NodeT::Capacity && "Size too big for node"); + } + + /// size - Return the number of elements in the referenced node. + unsigned size() const { return pip.getInt() + 1; } + + /// setSize - Update the node size. + void setSize(unsigned n) { pip.setInt(n - 1); } + + /// subtree - Access the i'th subtree reference in a branch node. + /// This depends on branch nodes storing the NodeRef array as their first + /// member. + NodeRef &subtree(unsigned i) const { + return reinterpret_cast(pip.getPointer())[i]; + } + + /// get - Dereference as a NodeT reference. + template + NodeT &get() const { + return *reinterpret_cast(pip.getPointer()); + } + + bool operator==(const NodeRef &RHS) const { + if (pip == RHS.pip) + return true; + assert(pip.getPointer() != RHS.pip.getPointer() && "Inconsistent NodeRefs"); + return false; + } + + bool operator!=(const NodeRef &RHS) const { + return !operator==(RHS); + } +}; + +//===----------------------------------------------------------------------===// +//--- IntervalMapImpl::LeafNode ---// +//===----------------------------------------------------------------------===// +// +// Leaf nodes store up to N disjoint intervals with corresponding values. +// +// The intervals are kept sorted and fully coalesced so there are no adjacent +// intervals mapping to the same value. +// +// These constraints are always satisfied: +// +// - Traits::stopLess(start(i), stop(i)) - Non-empty, sane intervals. +// +// - Traits::stopLess(stop(i), start(i + 1) - Sorted. +// +// - value(i) != value(i + 1) || !Traits::adjacent(stop(i), start(i + 1)) +// - Fully coalesced. +// +//===----------------------------------------------------------------------===// + +template +class LeafNode : public NodeBase, ValT, N> { +public: + const KeyT &start(unsigned i) const { return this->first[i].first; } + const KeyT &stop(unsigned i) const { return this->first[i].second; } + const ValT &value(unsigned i) const { return this->second[i]; } + + KeyT &start(unsigned i) { return this->first[i].first; } + KeyT &stop(unsigned i) { return this->first[i].second; } + ValT &value(unsigned i) { return this->second[i]; } + + /// findFrom - Find the first interval after i that may contain x. + /// @param i Starting index for the search. + /// @param Size Number of elements in node. + /// @param x Key to search for. + /// @return First index with !stopLess(key[i].stop, x), or size. + /// This is the first interval that can possibly contain x. + unsigned findFrom(unsigned i, unsigned Size, KeyT x) const { + assert(i <= Size && Size <= N && "Bad indices"); + assert((i == 0 || Traits::stopLess(stop(i - 1), x)) && + "Index is past the needed point"); + while (i != Size && Traits::stopLess(stop(i), x)) ++i; + return i; + } + + /// safeFind - Find an interval that is known to exist. This is the same as + /// findFrom except is it assumed that x is at least within range of the last + /// interval. + /// @param i Starting index for the search. + /// @param x Key to search for. + /// @return First index with !stopLess(key[i].stop, x), never size. + /// This is the first interval that can possibly contain x. + unsigned safeFind(unsigned i, KeyT x) const { + assert(i < N && "Bad index"); + assert((i == 0 || Traits::stopLess(stop(i - 1), x)) && + "Index is past the needed point"); + while (Traits::stopLess(stop(i), x)) ++i; + assert(i < N && "Unsafe intervals"); + return i; + } + + /// safeLookup - Lookup mapped value for a safe key. + /// It is assumed that x is within range of the last entry. + /// @param x Key to search for. + /// @param NotFound Value to return if x is not in any interval. + /// @return The mapped value at x or NotFound. + ValT safeLookup(KeyT x, ValT NotFound) const { + unsigned i = safeFind(0, x); + return Traits::startLess(x, start(i)) ? NotFound : value(i); + } + + unsigned insertFrom(unsigned &Pos, unsigned Size, KeyT a, KeyT b, ValT y); +}; + +/// insertFrom - Add mapping of [a;b] to y if possible, coalescing as much as +/// possible. This may cause the node to grow by 1, or it may cause the node +/// to shrink because of coalescing. +/// @param i Starting index = insertFrom(0, size, a) +/// @param Size Number of elements in node. +/// @param a Interval start. +/// @param b Interval stop. +/// @param y Value be mapped. +/// @return (insert position, new size), or (i, Capacity+1) on overflow. +template +unsigned LeafNode:: +insertFrom(unsigned &Pos, unsigned Size, KeyT a, KeyT b, ValT y) { + unsigned i = Pos; + assert(i <= Size && Size <= N && "Invalid index"); + assert(!Traits::stopLess(b, a) && "Invalid interval"); + + // Verify the findFrom invariant. + assert((i == 0 || Traits::stopLess(stop(i - 1), a))); + assert((i == Size || !Traits::stopLess(stop(i), a))); + assert((i == Size || Traits::stopLess(b, start(i))) && "Overlapping insert"); + + // Coalesce with previous interval. + if (i && value(i - 1) == y && Traits::adjacent(stop(i - 1), a)) { + Pos = i - 1; + // Also coalesce with next interval? + if (i != Size && value(i) == y && Traits::adjacent(b, start(i))) { + stop(i - 1) = stop(i); + this->erase(i, Size); + return Size - 1; + } + stop(i - 1) = b; + return Size; + } + + // Detect overflow. + if (i == N) + return N + 1; + + // Add new interval at end. + if (i == Size) { + start(i) = a; + stop(i) = b; + value(i) = y; + return Size + 1; + } + + // Try to coalesce with following interval. + if (value(i) == y && Traits::adjacent(b, start(i))) { + start(i) = a; + return Size; + } + + // We must insert before i. Detect overflow. + if (Size == N) + return N + 1; + + // Insert before i. + this->shift(i, Size); + start(i) = a; + stop(i) = b; + value(i) = y; + return Size + 1; +} + + +//===----------------------------------------------------------------------===// +//--- IntervalMapImpl::BranchNode ---// +//===----------------------------------------------------------------------===// +// +// A branch node stores references to 1--N subtrees all of the same height. +// +// The key array in a branch node holds the rightmost stop key of each subtree. +// It is redundant to store the last stop key since it can be found in the +// parent node, but doing so makes tree balancing a lot simpler. +// +// It is unusual for a branch node to only have one subtree, but it can happen +// in the root node if it is smaller than the normal nodes. +// +// When all of the leaf nodes from all the subtrees are concatenated, they must +// satisfy the same constraints as a single leaf node. They must be sorted, +// sane, and fully coalesced. +// +//===----------------------------------------------------------------------===// + +template +class BranchNode : public NodeBase { +public: + const KeyT &stop(unsigned i) const { return this->second[i]; } + const NodeRef &subtree(unsigned i) const { return this->first[i]; } + + KeyT &stop(unsigned i) { return this->second[i]; } + NodeRef &subtree(unsigned i) { return this->first[i]; } + + /// findFrom - Find the first subtree after i that may contain x. + /// @param i Starting index for the search. + /// @param Size Number of elements in node. + /// @param x Key to search for. + /// @return First index with !stopLess(key[i], x), or size. + /// This is the first subtree that can possibly contain x. + unsigned findFrom(unsigned i, unsigned Size, KeyT x) const { + assert(i <= Size && Size <= N && "Bad indices"); + assert((i == 0 || Traits::stopLess(stop(i - 1), x)) && + "Index to findFrom is past the needed point"); + while (i != Size && Traits::stopLess(stop(i), x)) ++i; + return i; + } + + /// safeFind - Find a subtree that is known to exist. This is the same as + /// findFrom except is it assumed that x is in range. + /// @param i Starting index for the search. + /// @param x Key to search for. + /// @return First index with !stopLess(key[i], x), never size. + /// This is the first subtree that can possibly contain x. + unsigned safeFind(unsigned i, KeyT x) const { + assert(i < N && "Bad index"); + assert((i == 0 || Traits::stopLess(stop(i - 1), x)) && + "Index is past the needed point"); + while (Traits::stopLess(stop(i), x)) ++i; + assert(i < N && "Unsafe intervals"); + return i; + } + + /// safeLookup - Get the subtree containing x, Assuming that x is in range. + /// @param x Key to search for. + /// @return Subtree containing x + NodeRef safeLookup(KeyT x) const { + return subtree(safeFind(0, x)); + } + + /// insert - Insert a new (subtree, stop) pair. + /// @param i Insert position, following entries will be shifted. + /// @param Size Number of elements in node. + /// @param Node Subtree to insert. + /// @param Stop Last key in subtree. + void insert(unsigned i, unsigned Size, NodeRef Node, KeyT Stop) { + assert(Size < N && "branch node overflow"); + assert(i <= Size && "Bad insert position"); + this->shift(i, Size); + subtree(i) = Node; + stop(i) = Stop; + } +}; + +//===----------------------------------------------------------------------===// +//--- IntervalMapImpl::Path ---// +//===----------------------------------------------------------------------===// +// +// A Path is used by iterators to represent a position in a B+-tree, and the +// path to get there from the root. +// +// The Path class also constains the tree navigation code that doesn't have to +// be templatized. +// +//===----------------------------------------------------------------------===// + +class Path { + /// Entry - Each step in the path is a node pointer and an offset into that + /// node. + struct Entry { + void *node; + unsigned size; + unsigned offset; + + Entry(void *Node, unsigned Size, unsigned Offset) + : node(Node), size(Size), offset(Offset) {} + + Entry(NodeRef Node, unsigned Offset) + : node(&Node.subtree(0)), size(Node.size()), offset(Offset) {} + + NodeRef &subtree(unsigned i) const { + return reinterpret_cast(node)[i]; + } + }; + + /// path - The path entries, path[0] is the root node, path.back() is a leaf. + SmallVector path; + +public: + // Node accessors. + template NodeT &node(unsigned Level) const { + return *reinterpret_cast(path[Level].node); + } + unsigned size(unsigned Level) const { return path[Level].size; } + unsigned offset(unsigned Level) const { return path[Level].offset; } + unsigned &offset(unsigned Level) { return path[Level].offset; } + + // Leaf accessors. + template NodeT &leaf() const { + return *reinterpret_cast(path.back().node); + } + unsigned leafSize() const { return path.back().size; } + unsigned leafOffset() const { return path.back().offset; } + unsigned &leafOffset() { return path.back().offset; } + + /// valid - Return true if path is at a valid node, not at end(). + bool valid() const { + return !path.empty() && path.front().offset < path.front().size; + } + + /// height - Return the height of the tree corresponding to this path. + /// This matches map->height in a full path. + unsigned height() const { return path.size() - 1; } + + /// subtree - Get the subtree referenced from Level. When the path is + /// consistent, node(Level + 1) == subtree(Level). + /// @param Level 0..height-1. The leaves have no subtrees. + NodeRef &subtree(unsigned Level) const { + return path[Level].subtree(path[Level].offset); + } + + /// reset - Reset cached information about node(Level) from subtree(Level -1). + /// @param Level 1..height. THe node to update after parent node changed. + void reset(unsigned Level) { + path[Level] = Entry(subtree(Level - 1), offset(Level)); + } + + /// push - Add entry to path. + /// @param Node Node to add, should be subtree(path.size()-1). + /// @param Offset Offset into Node. + void push(NodeRef Node, unsigned Offset) { + path.push_back(Entry(Node, Offset)); + } + + /// pop - Remove the last path entry. + void pop() { + path.pop_back(); + } + + /// setSize - Set the size of a node both in the path and in the tree. + /// @param Level 0..height. Note that setting the root size won't change + /// map->rootSize. + /// @param Size New node size. + void setSize(unsigned Level, unsigned Size) { + path[Level].size = Size; + if (Level) + subtree(Level - 1).setSize(Size); + } + + /// setRoot - Clear the path and set a new root node. + /// @param Node New root node. + /// @param Size New root size. + /// @param Offset Offset into root node. + void setRoot(void *Node, unsigned Size, unsigned Offset) { + path.clear(); + path.push_back(Entry(Node, Size, Offset)); + } + + /// replaceRoot - Replace the current root node with two new entries after the + /// tree height has increased. + /// @param Root The new root node. + /// @param Size Number of entries in the new root. + /// @param Offsets Offsets into the root and first branch nodes. + void replaceRoot(void *Root, unsigned Size, IdxPair Offsets); + + /// getLeftSibling - Get the left sibling node at Level, or a null NodeRef. + /// @param Level Get the sibling to node(Level). + /// @return Left sibling, or NodeRef(). + NodeRef getLeftSibling(unsigned Level) const; + + /// moveLeft - Move path to the left sibling at Level. Leave nodes below Level + /// unaltered. + /// @param Level Move node(Level). + void moveLeft(unsigned Level); + + /// fillLeft - Grow path to Height by taking leftmost branches. + /// @param Height The target height. + void fillLeft(unsigned Height) { + while (height() < Height) + push(subtree(height()), 0); + } + + /// getLeftSibling - Get the left sibling node at Level, or a null NodeRef. + /// @param Level Get the sinbling to node(Level). + /// @return Left sibling, or NodeRef(). + NodeRef getRightSibling(unsigned Level) const; + + /// moveRight - Move path to the left sibling at Level. Leave nodes below + /// Level unaltered. + /// @param Level Move node(Level). + void moveRight(unsigned Level); + + /// atBegin - Return true if path is at begin(). + bool atBegin() const { + for (unsigned i = 0, e = path.size(); i != e; ++i) + if (path[i].offset != 0) + return false; + return true; + } + + /// atLastEntry - Return true if the path is at the last entry of the node at + /// Level. + /// @param Level Node to examine. + bool atLastEntry(unsigned Level) const { + return path[Level].offset == path[Level].size - 1; + } + + /// legalizeForInsert - Prepare the path for an insertion at Level. When the + /// path is at end(), node(Level) may not be a legal node. legalizeForInsert + /// ensures that node(Level) is real by moving back to the last node at Level, + /// and setting offset(Level) to size(Level) if required. + /// @param Level The level where an insertion is about to take place. + void legalizeForInsert(unsigned Level) { + if (valid()) + return; + moveLeft(Level); + ++path[Level].offset; + } +}; + +} // namespace IntervalMapImpl + + +//===----------------------------------------------------------------------===// +//--- IntervalMap ----// +//===----------------------------------------------------------------------===// + +template ::LeafSize, + typename Traits = IntervalMapInfo > +class IntervalMap { + typedef IntervalMapImpl::NodeSizer Sizer; + typedef IntervalMapImpl::LeafNode Leaf; + typedef IntervalMapImpl::BranchNode + Branch; + typedef IntervalMapImpl::LeafNode RootLeaf; + typedef IntervalMapImpl::IdxPair IdxPair; + + // The RootLeaf capacity is given as a template parameter. We must compute the + // corresponding RootBranch capacity. + enum { + DesiredRootBranchCap = (sizeof(RootLeaf) - sizeof(KeyT)) / + (sizeof(KeyT) + sizeof(IntervalMapImpl::NodeRef)), + RootBranchCap = DesiredRootBranchCap ? DesiredRootBranchCap : 1 + }; + + typedef IntervalMapImpl::BranchNode + RootBranch; + + // When branched, we store a global start key as well as the branch node. + struct RootBranchData { + KeyT start; + RootBranch node; + }; + + enum { + RootDataSize = sizeof(RootBranchData) > sizeof(RootLeaf) ? + sizeof(RootBranchData) : sizeof(RootLeaf) + }; + +public: + typedef typename Sizer::Allocator Allocator; + typedef KeyT KeyType; + typedef ValT ValueType; + typedef Traits KeyTraits; + +private: + // The root data is either a RootLeaf or a RootBranchData instance. + // We can't put them in a union since C++03 doesn't allow non-trivial + // constructors in unions. + // Instead, we use a char array with pointer alignment. The alignment is + // ensured by the allocator member in the class, but still verified in the + // constructor. We don't support keys or values that are more aligned than a + // pointer. + char data[RootDataSize]; + + // Tree height. + // 0: Leaves in root. + // 1: Root points to leaf. + // 2: root->branch->leaf ... + unsigned height; + + // Number of entries in the root node. + unsigned rootSize; + + // Allocator used for creating external nodes. + Allocator &allocator; + + /// dataAs - Represent data as a node type without breaking aliasing rules. + template + T &dataAs() const { + union { + const char *d; + T *t; + } u; + u.d = data; + return *u.t; + } + + const RootLeaf &rootLeaf() const { + assert(!branched() && "Cannot acces leaf data in branched root"); + return dataAs(); + } + RootLeaf &rootLeaf() { + assert(!branched() && "Cannot acces leaf data in branched root"); + return dataAs(); + } + RootBranchData &rootBranchData() const { + assert(branched() && "Cannot access branch data in non-branched root"); + return dataAs(); + } + RootBranchData &rootBranchData() { + assert(branched() && "Cannot access branch data in non-branched root"); + return dataAs(); + } + const RootBranch &rootBranch() const { return rootBranchData().node; } + RootBranch &rootBranch() { return rootBranchData().node; } + KeyT rootBranchStart() const { return rootBranchData().start; } + KeyT &rootBranchStart() { return rootBranchData().start; } + + template NodeT *newNode() { + return new(allocator.template Allocate()) NodeT(); + } + + template void deleteNode(NodeT *P) { + P->~NodeT(); + allocator.Deallocate(P); + } + + IdxPair branchRoot(unsigned Position); + IdxPair splitRoot(unsigned Position); + + void switchRootToBranch() { + rootLeaf().~RootLeaf(); + height = 1; + new (&rootBranchData()) RootBranchData(); + } + + void switchRootToLeaf() { + rootBranchData().~RootBranchData(); + height = 0; + new(&rootLeaf()) RootLeaf(); + } + + bool branched() const { return height > 0; } + + ValT treeSafeLookup(KeyT x, ValT NotFound) const; + void visitNodes(void (IntervalMap::*f)(IntervalMapImpl::NodeRef, + unsigned Level)); + void deleteNode(IntervalMapImpl::NodeRef Node, unsigned Level); + +public: + explicit IntervalMap(Allocator &a) : height(0), rootSize(0), allocator(a) { + assert((uintptr_t(data) & (alignOf() - 1)) == 0 && + "Insufficient alignment"); + new(&rootLeaf()) RootLeaf(); + } + + ~IntervalMap() { + clear(); + rootLeaf().~RootLeaf(); + } + + /// empty - Return true when no intervals are mapped. + bool empty() const { + return rootSize == 0; + } + + /// start - Return the smallest mapped key in a non-empty map. + KeyT start() const { + assert(!empty() && "Empty IntervalMap has no start"); + return !branched() ? rootLeaf().start(0) : rootBranchStart(); + } + + /// stop - Return the largest mapped key in a non-empty map. + KeyT stop() const { + assert(!empty() && "Empty IntervalMap has no stop"); + return !branched() ? rootLeaf().stop(rootSize - 1) : + rootBranch().stop(rootSize - 1); + } + + /// lookup - Return the mapped value at x or NotFound. + ValT lookup(KeyT x, ValT NotFound = ValT()) const { + if (empty() || Traits::startLess(x, start()) || Traits::stopLess(stop(), x)) + return NotFound; + return branched() ? treeSafeLookup(x, NotFound) : + rootLeaf().safeLookup(x, NotFound); + } + + /// insert - Add a mapping of [a;b] to y, coalesce with adjacent intervals. + /// It is assumed that no key in the interval is mapped to another value, but + /// overlapping intervals already mapped to y will be coalesced. + void insert(KeyT a, KeyT b, ValT y) { + if (branched() || rootSize == RootLeaf::Capacity) + return find(a).insert(a, b, y); + + // Easy insert into root leaf. + unsigned p = rootLeaf().findFrom(0, rootSize, a); + rootSize = rootLeaf().insertFrom(p, rootSize, a, b, y); + } + + /// clear - Remove all entries. + void clear(); + + class const_iterator; + class iterator; + friend class const_iterator; + friend class iterator; + + const_iterator begin() const { + const_iterator I(*this); + I.goToBegin(); + return I; + } + + iterator begin() { + iterator I(*this); + I.goToBegin(); + return I; + } + + const_iterator end() const { + const_iterator I(*this); + I.goToEnd(); + return I; + } + + iterator end() { + iterator I(*this); + I.goToEnd(); + return I; + } + + /// find - Return an iterator pointing to the first interval ending at or + /// after x, or end(). + const_iterator find(KeyT x) const { + const_iterator I(*this); + I.find(x); + return I; + } + + iterator find(KeyT x) { + iterator I(*this); + I.find(x); + return I; + } +}; + +/// treeSafeLookup - Return the mapped value at x or NotFound, assuming a +/// branched root. +template +ValT IntervalMap:: +treeSafeLookup(KeyT x, ValT NotFound) const { + assert(branched() && "treeLookup assumes a branched root"); + + IntervalMapImpl::NodeRef NR = rootBranch().safeLookup(x); + for (unsigned h = height-1; h; --h) + NR = NR.get().safeLookup(x); + return NR.get().safeLookup(x, NotFound); +} + + +// branchRoot - Switch from a leaf root to a branched root. +// Return the new (root offset, node offset) corresponding to Position. +template +IntervalMapImpl::IdxPair IntervalMap:: +branchRoot(unsigned Position) { + using namespace IntervalMapImpl; + // How many external leaf nodes to hold RootLeaf+1? + const unsigned Nodes = RootLeaf::Capacity / Leaf::Capacity + 1; + + // Compute element distribution among new nodes. + unsigned size[Nodes]; + IdxPair NewOffset(0, Position); + + // Is is very common for the root node to be smaller than external nodes. + if (Nodes == 1) + size[0] = rootSize; + else + NewOffset = distribute(Nodes, rootSize, Leaf::Capacity, NULL, size, + Position, true); + + // Allocate new nodes. + unsigned pos = 0; + NodeRef node[Nodes]; + for (unsigned n = 0; n != Nodes; ++n) { + Leaf *L = newNode(); + L->copy(rootLeaf(), pos, 0, size[n]); + node[n] = NodeRef(L, size[n]); + pos += size[n]; + } + + // Destroy the old leaf node, construct branch node instead. + switchRootToBranch(); + for (unsigned n = 0; n != Nodes; ++n) { + rootBranch().stop(n) = node[n].template get().stop(size[n]-1); + rootBranch().subtree(n) = node[n]; + } + rootBranchStart() = node[0].template get().start(0); + rootSize = Nodes; + return NewOffset; +} + +// splitRoot - Split the current BranchRoot into multiple Branch nodes. +// Return the new (root offset, node offset) corresponding to Position. +template +IntervalMapImpl::IdxPair IntervalMap:: +splitRoot(unsigned Position) { + using namespace IntervalMapImpl; + // How many external leaf nodes to hold RootBranch+1? + const unsigned Nodes = RootBranch::Capacity / Branch::Capacity + 1; + + // Compute element distribution among new nodes. + unsigned Size[Nodes]; + IdxPair NewOffset(0, Position); + + // Is is very common for the root node to be smaller than external nodes. + if (Nodes == 1) + Size[0] = rootSize; + else + NewOffset = distribute(Nodes, rootSize, Leaf::Capacity, NULL, Size, + Position, true); + + // Allocate new nodes. + unsigned Pos = 0; + NodeRef Node[Nodes]; + for (unsigned n = 0; n != Nodes; ++n) { + Branch *B = newNode(); + B->copy(rootBranch(), Pos, 0, Size[n]); + Node[n] = NodeRef(B, Size[n]); + Pos += Size[n]; + } + + for (unsigned n = 0; n != Nodes; ++n) { + rootBranch().stop(n) = Node[n].template get().stop(Size[n]-1); + rootBranch().subtree(n) = Node[n]; + } + rootSize = Nodes; + ++height; + return NewOffset; +} + +/// visitNodes - Visit each external node. +template +void IntervalMap:: +visitNodes(void (IntervalMap::*f)(IntervalMapImpl::NodeRef, unsigned Height)) { + if (!branched()) + return; + SmallVector Refs, NextRefs; + + // Collect level 0 nodes from the root. + for (unsigned i = 0; i != rootSize; ++i) + Refs.push_back(rootBranch().subtree(i)); + + // Visit all branch nodes. + for (unsigned h = height - 1; h; --h) { + for (unsigned i = 0, e = Refs.size(); i != e; ++i) { + for (unsigned j = 0, s = Refs[i].size(); j != s; ++j) + NextRefs.push_back(Refs[i].subtree(j)); + (this->*f)(Refs[i], h); + } + Refs.clear(); + Refs.swap(NextRefs); + } + + // Visit all leaf nodes. + for (unsigned i = 0, e = Refs.size(); i != e; ++i) + (this->*f)(Refs[i], 0); +} + +template +void IntervalMap:: +deleteNode(IntervalMapImpl::NodeRef Node, unsigned Level) { + if (Level) + deleteNode(&Node.get()); + else + deleteNode(&Node.get()); +} + +template +void IntervalMap:: +clear() { + if (branched()) { + visitNodes(&IntervalMap::deleteNode); + switchRootToLeaf(); + } + rootSize = 0; +} + +//===----------------------------------------------------------------------===// +//--- IntervalMap::const_iterator ----// +//===----------------------------------------------------------------------===// + +template +class IntervalMap::const_iterator : + public std::iterator { +protected: + friend class IntervalMap; + + // The map referred to. + IntervalMap *map; + + // We store a full path from the root to the current position. + // The path may be partially filled, but never between iterator calls. + IntervalMapImpl::Path path; + + explicit const_iterator(const IntervalMap &map) : + map(const_cast(&map)) {} + + bool branched() const { + assert(map && "Invalid iterator"); + return map->branched(); + } + + void setRoot(unsigned Offset) { + if (branched()) + path.setRoot(&map->rootBranch(), map->rootSize, Offset); + else + path.setRoot(&map->rootLeaf(), map->rootSize, Offset); + } + + void pathFillFind(KeyT x); + void treeFind(KeyT x); + void treeAdvanceTo(KeyT x); + + /// unsafeStart - Writable access to start() for iterator. + KeyT &unsafeStart() const { + assert(valid() && "Cannot access invalid iterator"); + return branched() ? path.leaf().start(path.leafOffset()) : + path.leaf().start(path.leafOffset()); + } + + /// unsafeStop - Writable access to stop() for iterator. + KeyT &unsafeStop() const { + assert(valid() && "Cannot access invalid iterator"); + return branched() ? path.leaf().stop(path.leafOffset()) : + path.leaf().stop(path.leafOffset()); + } + + /// unsafeValue - Writable access to value() for iterator. + ValT &unsafeValue() const { + assert(valid() && "Cannot access invalid iterator"); + return branched() ? path.leaf().value(path.leafOffset()) : + path.leaf().value(path.leafOffset()); + } + +public: + /// const_iterator - Create an iterator that isn't pointing anywhere. + const_iterator() : map(0) {} + + /// valid - Return true if the current position is valid, false for end(). + bool valid() const { return path.valid(); } + + /// start - Return the beginning of the current interval. + const KeyT &start() const { return unsafeStart(); } + + /// stop - Return the end of the current interval. + const KeyT &stop() const { return unsafeStop(); } + + /// value - Return the mapped value at the current interval. + const ValT &value() const { return unsafeValue(); } + + const ValT &operator*() const { return value(); } + + bool operator==(const const_iterator &RHS) const { + assert(map == RHS.map && "Cannot compare iterators from different maps"); + if (!valid()) + return !RHS.valid(); + if (path.leafOffset() != RHS.path.leafOffset()) + return false; + return &path.template leaf() == &RHS.path.template leaf(); + } + + bool operator!=(const const_iterator &RHS) const { + return !operator==(RHS); + } + + /// goToBegin - Move to the first interval in map. + void goToBegin() { + setRoot(0); + if (branched()) + path.fillLeft(map->height); + } + + /// goToEnd - Move beyond the last interval in map. + void goToEnd() { + setRoot(map->rootSize); + } + + /// preincrement - move to the next interval. + const_iterator &operator++() { + assert(valid() && "Cannot increment end()"); + if (++path.leafOffset() == path.leafSize() && branched()) + path.moveRight(map->height); + return *this; + } + + /// postincrement - Dont do that! + const_iterator operator++(int) { + const_iterator tmp = *this; + operator++(); + return tmp; + } + + /// predecrement - move to the previous interval. + const_iterator &operator--() { + if (path.leafOffset() && (valid() || !branched())) + --path.leafOffset(); + else + path.moveLeft(map->height); + return *this; + } + + /// postdecrement - Dont do that! + const_iterator operator--(int) { + const_iterator tmp = *this; + operator--(); + return tmp; + } + + /// find - Move to the first interval with stop >= x, or end(). + /// This is a full search from the root, the current position is ignored. + void find(KeyT x) { + if (branched()) + treeFind(x); + else + setRoot(map->rootLeaf().findFrom(0, map->rootSize, x)); + } + + /// advanceTo - Move to the first interval with stop >= x, or end(). + /// The search is started from the current position, and no earlier positions + /// can be found. This is much faster than find() for small moves. + void advanceTo(KeyT x) { + if (!valid()) + return; + if (branched()) + treeAdvanceTo(x); + else + path.leafOffset() = + map->rootLeaf().findFrom(path.leafOffset(), map->rootSize, x); + } + +}; + +/// pathFillFind - Complete path by searching for x. +/// @param x Key to search for. +template +void IntervalMap:: +const_iterator::pathFillFind(KeyT x) { + IntervalMapImpl::NodeRef NR = path.subtree(path.height()); + for (unsigned i = map->height - path.height() - 1; i; --i) { + unsigned p = NR.get().safeFind(0, x); + path.push(NR, p); + NR = NR.subtree(p); + } + path.push(NR, NR.get().safeFind(0, x)); +} + +/// treeFind - Find in a branched tree. +/// @param x Key to search for. +template +void IntervalMap:: +const_iterator::treeFind(KeyT x) { + setRoot(map->rootBranch().findFrom(0, map->rootSize, x)); + if (valid()) + pathFillFind(x); +} + +/// treeAdvanceTo - Find position after the current one. +/// @param x Key to search for. +template +void IntervalMap:: +const_iterator::treeAdvanceTo(KeyT x) { + // Can we stay on the same leaf node? + if (!Traits::stopLess(path.leaf().stop(path.leafSize() - 1), x)) { + path.leafOffset() = path.leaf().safeFind(path.leafOffset(), x); + return; + } + + // Drop the current leaf. + path.pop(); + + // Search towards the root for a usable subtree. + if (path.height()) { + for (unsigned l = path.height() - 1; l; --l) { + if (!Traits::stopLess(path.node(l).stop(path.offset(l)), x)) { + // The branch node at l+1 is usable + path.offset(l + 1) = + path.node(l + 1).safeFind(path.offset(l + 1), x); + return pathFillFind(x); + } + path.pop(); + } + // Is the level-1 Branch usable? + if (!Traits::stopLess(map->rootBranch().stop(path.offset(0)), x)) { + path.offset(1) = path.node(1).safeFind(path.offset(1), x); + return pathFillFind(x); + } + } + + // We reached the root. + setRoot(map->rootBranch().findFrom(path.offset(0), map->rootSize, x)); + if (valid()) + pathFillFind(x); +} + +//===----------------------------------------------------------------------===// +//--- IntervalMap::iterator ----// +//===----------------------------------------------------------------------===// + +template +class IntervalMap::iterator : public const_iterator { + friend class IntervalMap; + typedef IntervalMapImpl::IdxPair IdxPair; + + explicit iterator(IntervalMap &map) : const_iterator(map) {} + + void setNodeStop(unsigned Level, KeyT Stop); + bool insertNode(unsigned Level, IntervalMapImpl::NodeRef Node, KeyT Stop); + template bool overflow(unsigned Level); + void treeInsert(KeyT a, KeyT b, ValT y); + void eraseNode(unsigned Level); + void treeErase(bool UpdateRoot = true); + bool canCoalesceLeft(KeyT Start, ValT x); + bool canCoalesceRight(KeyT Stop, ValT x); + +public: + /// iterator - Create null iterator. + iterator() {} + + /// setStart - Move the start of the current interval. + /// This may cause coalescing with the previous interval. + /// @param a New start key, must not overlap the previous interval. + void setStart(KeyT a); + + /// setStop - Move the end of the current interval. + /// This may cause coalescing with the following interval. + /// @param b New stop key, must not overlap the following interval. + void setStop(KeyT b); + + /// setValue - Change the mapped value of the current interval. + /// This may cause coalescing with the previous and following intervals. + /// @param x New value. + void setValue(ValT x); + + /// setStartUnchecked - Move the start of the current interval without + /// checking for coalescing or overlaps. + /// This should only be used when it is known that coalescing is not required. + /// @param a New start key. + void setStartUnchecked(KeyT a) { this->unsafeStart() = a; } + + /// setStopUnchecked - Move the end of the current interval without checking + /// for coalescing or overlaps. + /// This should only be used when it is known that coalescing is not required. + /// @param b New stop key. + void setStopUnchecked(KeyT b) { + this->unsafeStop() = b; + // Update keys in branch nodes as well. + if (this->path.atLastEntry(this->path.height())) + setNodeStop(this->path.height(), b); + } + + /// setValueUnchecked - Change the mapped value of the current interval + /// without checking for coalescing. + /// @param x New value. + void setValueUnchecked(ValT x) { this->unsafeValue() = x; } + + /// insert - Insert mapping [a;b] -> y before the current position. + void insert(KeyT a, KeyT b, ValT y); + + /// erase - Erase the current interval. + void erase(); + + iterator &operator++() { + const_iterator::operator++(); + return *this; + } + + iterator operator++(int) { + iterator tmp = *this; + operator++(); + return tmp; + } + + iterator &operator--() { + const_iterator::operator--(); + return *this; + } + + iterator operator--(int) { + iterator tmp = *this; + operator--(); + return tmp; + } + +}; + +/// canCoalesceLeft - Can the current interval coalesce to the left after +/// changing start or value? +/// @param Start New start of current interval. +/// @param Value New value for current interval. +/// @return True when updating the current interval would enable coalescing. +template +bool IntervalMap:: +iterator::canCoalesceLeft(KeyT Start, ValT Value) { + using namespace IntervalMapImpl; + Path &P = this->path; + if (!this->branched()) { + unsigned i = P.leafOffset(); + RootLeaf &Node = P.leaf(); + return i && Node.value(i-1) == Value && + Traits::adjacent(Node.stop(i-1), Start); + } + // Branched. + if (unsigned i = P.leafOffset()) { + Leaf &Node = P.leaf(); + return Node.value(i-1) == Value && Traits::adjacent(Node.stop(i-1), Start); + } else if (NodeRef NR = P.getLeftSibling(P.height())) { + unsigned i = NR.size() - 1; + Leaf &Node = NR.get(); + return Node.value(i) == Value && Traits::adjacent(Node.stop(i), Start); + } + return false; +} + +/// canCoalesceRight - Can the current interval coalesce to the right after +/// changing stop or value? +/// @param Stop New stop of current interval. +/// @param Value New value for current interval. +/// @return True when updating the current interval would enable coalescing. +template +bool IntervalMap:: +iterator::canCoalesceRight(KeyT Stop, ValT Value) { + using namespace IntervalMapImpl; + Path &P = this->path; + unsigned i = P.leafOffset() + 1; + if (!this->branched()) { + if (i >= P.leafSize()) + return false; + RootLeaf &Node = P.leaf(); + return Node.value(i) == Value && Traits::adjacent(Stop, Node.start(i)); + } + // Branched. + if (i < P.leafSize()) { + Leaf &Node = P.leaf(); + return Node.value(i) == Value && Traits::adjacent(Stop, Node.start(i)); + } else if (NodeRef NR = P.getRightSibling(P.height())) { + Leaf &Node = NR.get(); + return Node.value(0) == Value && Traits::adjacent(Stop, Node.start(0)); + } + return false; +} + +/// setNodeStop - Update the stop key of the current node at level and above. +template +void IntervalMap:: +iterator::setNodeStop(unsigned Level, KeyT Stop) { + // There are no references to the root node, so nothing to update. + if (!Level) + return; + IntervalMapImpl::Path &P = this->path; + // Update nodes pointing to the current node. + while (--Level) { + P.node(Level).stop(P.offset(Level)) = Stop; + if (!P.atLastEntry(Level)) + return; + } + // Update root separately since it has a different layout. + P.node(Level).stop(P.offset(Level)) = Stop; +} + +template +void IntervalMap:: +iterator::setStart(KeyT a) { + assert(Traits::stopLess(a, this->stop()) && "Cannot move start beyond stop"); + KeyT &CurStart = this->unsafeStart(); + if (!Traits::startLess(a, CurStart) || !canCoalesceLeft(a, this->value())) { + CurStart = a; + return; + } + // Coalesce with the interval to the left. + --*this; + a = this->start(); + erase(); + setStartUnchecked(a); +} + +template +void IntervalMap:: +iterator::setStop(KeyT b) { + assert(Traits::stopLess(this->start(), b) && "Cannot move stop beyond start"); + if (Traits::startLess(b, this->stop()) || + !canCoalesceRight(b, this->value())) { + setStopUnchecked(b); + return; + } + // Coalesce with interval to the right. + KeyT a = this->start(); + erase(); + setStartUnchecked(a); +} + +template +void IntervalMap:: +iterator::setValue(ValT x) { + setValueUnchecked(x); + if (canCoalesceRight(this->stop(), x)) { + KeyT a = this->start(); + erase(); + setStartUnchecked(a); + } + if (canCoalesceLeft(this->start(), x)) { + --*this; + KeyT a = this->start(); + erase(); + setStartUnchecked(a); + } +} + +/// insertNode - insert a node before the current path at level. +/// Leave the current path pointing at the new node. +/// @param Level path index of the node to be inserted. +/// @param Node The node to be inserted. +/// @param Stop The last index in the new node. +/// @return True if the tree height was increased. +template +bool IntervalMap:: +iterator::insertNode(unsigned Level, IntervalMapImpl::NodeRef Node, KeyT Stop) { + assert(Level && "Cannot insert next to the root"); + bool SplitRoot = false; + IntervalMap &IM = *this->map; + IntervalMapImpl::Path &P = this->path; + + if (Level == 1) { + // Insert into the root branch node. + if (IM.rootSize < RootBranch::Capacity) { + IM.rootBranch().insert(P.offset(0), IM.rootSize, Node, Stop); + P.setSize(0, ++IM.rootSize); + P.reset(Level); + return SplitRoot; + } + + // We need to split the root while keeping our position. + SplitRoot = true; + IdxPair Offset = IM.splitRoot(P.offset(0)); + P.replaceRoot(&IM.rootBranch(), IM.rootSize, Offset); + + // Fall through to insert at the new higher level. + ++Level; + } + + // When inserting before end(), make sure we have a valid path. + P.legalizeForInsert(--Level); + + // Insert into the branch node at Level-1. + if (P.size(Level) == Branch::Capacity) { + // Branch node is full, handle handle the overflow. + assert(!SplitRoot && "Cannot overflow after splitting the root"); + SplitRoot = overflow(Level); + Level += SplitRoot; + } + P.node(Level).insert(P.offset(Level), P.size(Level), Node, Stop); + P.setSize(Level, P.size(Level) + 1); + if (P.atLastEntry(Level)) + setNodeStop(Level, Stop); + P.reset(Level + 1); + return SplitRoot; +} + +// insert +template +void IntervalMap:: +iterator::insert(KeyT a, KeyT b, ValT y) { + if (this->branched()) + return treeInsert(a, b, y); + IntervalMap &IM = *this->map; + IntervalMapImpl::Path &P = this->path; + + // Try simple root leaf insert. + unsigned Size = IM.rootLeaf().insertFrom(P.leafOffset(), IM.rootSize, a, b, y); + + // Was the root node insert successful? + if (Size <= RootLeaf::Capacity) { + P.setSize(0, IM.rootSize = Size); + return; + } + + // Root leaf node is full, we must branch. + IdxPair Offset = IM.branchRoot(P.leafOffset()); + P.replaceRoot(&IM.rootBranch(), IM.rootSize, Offset); + + // Now it fits in the new leaf. + treeInsert(a, b, y); +} + + +template +void IntervalMap:: +iterator::treeInsert(KeyT a, KeyT b, ValT y) { + using namespace IntervalMapImpl; + Path &P = this->path; + + if (!P.valid()) + P.legalizeForInsert(this->map->height); + + // Check if this insertion will extend the node to the left. + if (P.leafOffset() == 0 && Traits::startLess(a, P.leaf().start(0))) { + // Node is growing to the left, will it affect a left sibling node? + if (NodeRef Sib = P.getLeftSibling(P.height())) { + Leaf &SibLeaf = Sib.get(); + unsigned SibOfs = Sib.size() - 1; + if (SibLeaf.value(SibOfs) == y && + Traits::adjacent(SibLeaf.stop(SibOfs), a)) { + // This insertion will coalesce with the last entry in SibLeaf. We can + // handle it in two ways: + // 1. Extend SibLeaf.stop to b and be done, or + // 2. Extend a to SibLeaf, erase the SibLeaf entry and continue. + // We prefer 1., but need 2 when coalescing to the right as well. + Leaf &CurLeaf = P.leaf(); + P.moveLeft(P.height()); + if (Traits::stopLess(b, CurLeaf.start(0)) && + (y != CurLeaf.value(0) || !Traits::adjacent(b, CurLeaf.start(0)))) { + // Easy, just extend SibLeaf and we're done. + setNodeStop(P.height(), SibLeaf.stop(SibOfs) = b); + return; + } else { + // We have both left and right coalescing. Erase the old SibLeaf entry + // and continue inserting the larger interval. + a = SibLeaf.start(SibOfs); + treeErase(/* UpdateRoot= */false); + } + } + } else { + // No left sibling means we are at begin(). Update cached bound. + this->map->rootBranchStart() = a; + } + } + + // When we are inserting at the end of a leaf node, we must update stops. + unsigned Size = P.leafSize(); + bool Grow = P.leafOffset() == Size; + Size = P.leaf().insertFrom(P.leafOffset(), Size, a, b, y); + + // Leaf insertion unsuccessful? Overflow and try again. + if (Size > Leaf::Capacity) { + overflow(P.height()); + Grow = P.leafOffset() == P.leafSize(); + Size = P.leaf().insertFrom(P.leafOffset(), P.leafSize(), a, b, y); + assert(Size <= Leaf::Capacity && "overflow() didn't make room"); + } + + // Inserted, update offset and leaf size. + P.setSize(P.height(), Size); + + // Insert was the last node entry, update stops. + if (Grow) + setNodeStop(P.height(), b); +} + +/// erase - erase the current interval and move to the next position. +template +void IntervalMap:: +iterator::erase() { + IntervalMap &IM = *this->map; + IntervalMapImpl::Path &P = this->path; + assert(P.valid() && "Cannot erase end()"); + if (this->branched()) + return treeErase(); + IM.rootLeaf().erase(P.leafOffset(), IM.rootSize); + P.setSize(0, --IM.rootSize); +} + +/// treeErase - erase() for a branched tree. +template +void IntervalMap:: +iterator::treeErase(bool UpdateRoot) { + IntervalMap &IM = *this->map; + IntervalMapImpl::Path &P = this->path; + Leaf &Node = P.leaf(); + + // Nodes are not allowed to become empty. + if (P.leafSize() == 1) { + IM.deleteNode(&Node); + eraseNode(IM.height); + // Update rootBranchStart if we erased begin(). + if (UpdateRoot && IM.branched() && P.valid() && P.atBegin()) + IM.rootBranchStart() = P.leaf().start(0); + return; + } + + // Erase current entry. + Node.erase(P.leafOffset(), P.leafSize()); + unsigned NewSize = P.leafSize() - 1; + P.setSize(IM.height, NewSize); + // When we erase the last entry, update stop and move to a legal position. + if (P.leafOffset() == NewSize) { + setNodeStop(IM.height, Node.stop(NewSize - 1)); + P.moveRight(IM.height); + } else if (UpdateRoot && P.atBegin()) + IM.rootBranchStart() = P.leaf().start(0); +} + +/// eraseNode - Erase the current node at Level from its parent and move path to +/// the first entry of the next sibling node. +/// The node must be deallocated by the caller. +/// @param Level 1..height, the root node cannot be erased. +template +void IntervalMap:: +iterator::eraseNode(unsigned Level) { + assert(Level && "Cannot erase root node"); + IntervalMap &IM = *this->map; + IntervalMapImpl::Path &P = this->path; + + if (--Level == 0) { + IM.rootBranch().erase(P.offset(0), IM.rootSize); + P.setSize(0, --IM.rootSize); + // If this cleared the root, switch to height=0. + if (IM.empty()) { + IM.switchRootToLeaf(); + this->setRoot(0); + return; + } + } else { + // Remove node ref from branch node at Level. + Branch &Parent = P.node(Level); + if (P.size(Level) == 1) { + // Branch node became empty, remove it recursively. + IM.deleteNode(&Parent); + eraseNode(Level); + } else { + // Branch node won't become empty. + Parent.erase(P.offset(Level), P.size(Level)); + unsigned NewSize = P.size(Level) - 1; + P.setSize(Level, NewSize); + // If we removed the last branch, update stop and move to a legal pos. + if (P.offset(Level) == NewSize) { + setNodeStop(Level, Parent.stop(NewSize - 1)); + P.moveRight(Level); + } + } + } + // Update path cache for the new right sibling position. + if (P.valid()) { + P.reset(Level + 1); + P.offset(Level + 1) = 0; + } +} + +/// overflow - Distribute entries of the current node evenly among +/// its siblings and ensure that the current node is not full. +/// This may require allocating a new node. +/// @param NodeT The type of node at Level (Leaf or Branch). +/// @param Level path index of the overflowing node. +/// @return True when the tree height was changed. +template +template +bool IntervalMap:: +iterator::overflow(unsigned Level) { + using namespace IntervalMapImpl; + Path &P = this->path; + unsigned CurSize[4]; + NodeT *Node[4]; + unsigned Nodes = 0; + unsigned Elements = 0; + unsigned Offset = P.offset(Level); + + // Do we have a left sibling? + NodeRef LeftSib = P.getLeftSibling(Level); + if (LeftSib) { + Offset += Elements = CurSize[Nodes] = LeftSib.size(); + Node[Nodes++] = &LeftSib.get(); + } + + // Current node. + Elements += CurSize[Nodes] = P.size(Level); + Node[Nodes++] = &P.node(Level); + + // Do we have a right sibling? + NodeRef RightSib = P.getRightSibling(Level); + if (RightSib) { + Elements += CurSize[Nodes] = RightSib.size(); + Node[Nodes++] = &RightSib.get(); + } + + // Do we need to allocate a new node? + unsigned NewNode = 0; + if (Elements + 1 > Nodes * NodeT::Capacity) { + // Insert NewNode at the penultimate position, or after a single node. + NewNode = Nodes == 1 ? 1 : Nodes - 1; + CurSize[Nodes] = CurSize[NewNode]; + Node[Nodes] = Node[NewNode]; + CurSize[NewNode] = 0; + Node[NewNode] = this->map->newNode(); + ++Nodes; + } + + // Compute the new element distribution. + unsigned NewSize[4]; + IdxPair NewOffset = distribute(Nodes, Elements, NodeT::Capacity, + CurSize, NewSize, Offset, true); + adjustSiblingSizes(Node, Nodes, CurSize, NewSize); + + // Move current location to the leftmost node. + if (LeftSib) + P.moveLeft(Level); + + // Elements have been rearranged, now update node sizes and stops. + bool SplitRoot = false; + unsigned Pos = 0; + for (;;) { + KeyT Stop = Node[Pos]->stop(NewSize[Pos]-1); + if (NewNode && Pos == NewNode) { + SplitRoot = insertNode(Level, NodeRef(Node[Pos], NewSize[Pos]), Stop); + Level += SplitRoot; + } else { + P.setSize(Level, NewSize[Pos]); + setNodeStop(Level, Stop); + } + if (Pos + 1 == Nodes) + break; + P.moveRight(Level); + ++Pos; + } + + // Where was I? Find NewOffset. + while(Pos != NewOffset.first) { + P.moveLeft(Level); + --Pos; + } + P.offset(Level) = NewOffset.second; + return SplitRoot; +} + +//===----------------------------------------------------------------------===// +//--- IntervalMapOverlaps ----// +//===----------------------------------------------------------------------===// + +/// IntervalMapOverlaps - Iterate over the overlaps of mapped intervals in two +/// IntervalMaps. The maps may be different, but the KeyT and Traits types +/// should be the same. +/// +/// Typical uses: +/// +/// 1. Test for overlap: +/// bool overlap = IntervalMapOverlaps(a, b).valid(); +/// +/// 2. Enumerate overlaps: +/// for (IntervalMapOverlaps I(a, b); I.valid() ; ++I) { ... } +/// +template +class IntervalMapOverlaps { + typedef typename MapA::KeyType KeyType; + typedef typename MapA::KeyTraits Traits; + typename MapA::const_iterator posA; + typename MapB::const_iterator posB; + + /// advance - Move posA and posB forward until reaching an overlap, or until + /// either meets end. + /// Don't move the iterators if they are already overlapping. + void advance() { + if (!valid()) + return; + + if (Traits::stopLess(posA.stop(), posB.start())) { + // A ends before B begins. Catch up. + posA.advanceTo(posB.start()); + if (!posA.valid() || !Traits::stopLess(posB.stop(), posA.start())) + return; + } else if (Traits::stopLess(posB.stop(), posA.start())) { + // B ends before A begins. Catch up. + posB.advanceTo(posA.start()); + if (!posB.valid() || !Traits::stopLess(posA.stop(), posB.start())) + return; + } else + // Already overlapping. + return; + + for (;;) { + // Make a.end > b.start. + posA.advanceTo(posB.start()); + if (!posA.valid() || !Traits::stopLess(posB.stop(), posA.start())) + return; + // Make b.end > a.start. + posB.advanceTo(posA.start()); + if (!posB.valid() || !Traits::stopLess(posA.stop(), posB.start())) + return; + } + } + +public: + /// IntervalMapOverlaps - Create an iterator for the overlaps of a and b. + IntervalMapOverlaps(const MapA &a, const MapB &b) + : posA(b.empty() ? a.end() : a.find(b.start())), + posB(posA.valid() ? b.find(posA.start()) : b.end()) { advance(); } + + /// valid - Return true if iterator is at an overlap. + bool valid() const { + return posA.valid() && posB.valid(); + } + + /// a - access the left hand side in the overlap. + const typename MapA::const_iterator &a() const { return posA; } + + /// b - access the right hand side in the overlap. + const typename MapB::const_iterator &b() const { return posB; } + + /// start - Beginning of the overlapping interval. + KeyType start() const { + KeyType ak = a().start(); + KeyType bk = b().start(); + return Traits::startLess(ak, bk) ? bk : ak; + } + + /// stop - End of the overlapping interval. + KeyType stop() const { + KeyType ak = a().stop(); + KeyType bk = b().stop(); + return Traits::startLess(ak, bk) ? ak : bk; + } + + /// skipA - Move to the next overlap that doesn't involve a(). + void skipA() { + ++posA; + advance(); + } + + /// skipB - Move to the next overlap that doesn't involve b(). + void skipB() { + ++posB; + advance(); + } + + /// Preincrement - Move to the next overlap. + IntervalMapOverlaps &operator++() { + // Bump the iterator that ends first. The other one may have more overlaps. + if (Traits::startLess(posB.stop(), posA.stop())) + skipB(); + else + skipA(); + return *this; + } + + /// advanceTo - Move to the first overlapping interval with + /// stopLess(x, stop()). + void advanceTo(KeyType x) { + if (!valid()) + return; + // Make sure advanceTo sees monotonic keys. + if (Traits::stopLess(posA.stop(), x)) + posA.advanceTo(x); + if (Traits::stopLess(posB.stop(), x)) + posB.advanceTo(x); + advance(); + } +}; + +} // namespace llvm + +#endif diff --git a/include/llvm/ADT/Optional.h b/include/llvm/ADT/Optional.h index 34e54a07a0ef..ee8b69f3d12f 100644 --- a/include/llvm/ADT/Optional.h +++ b/include/llvm/ADT/Optional.h @@ -61,6 +61,60 @@ template struct simplify_type > : public simplify_type > {}; +/// \brief Poison comparison between two \c Optional objects. Clients needs to +/// explicitly compare the underlying values and account for empty \c Optional +/// objects. +/// +/// This routine will never be defined. It returns \c void to help diagnose +/// errors at compile time. +template +void operator==(const Optional &X, const Optional &Y); + +/// \brief Poison comparison between two \c Optional objects. Clients needs to +/// explicitly compare the underlying values and account for empty \c Optional +/// objects. +/// +/// This routine will never be defined. It returns \c void to help diagnose +/// errors at compile time. +template +void operator!=(const Optional &X, const Optional &Y); + +/// \brief Poison comparison between two \c Optional objects. Clients needs to +/// explicitly compare the underlying values and account for empty \c Optional +/// objects. +/// +/// This routine will never be defined. It returns \c void to help diagnose +/// errors at compile time. +template +void operator<(const Optional &X, const Optional &Y); + +/// \brief Poison comparison between two \c Optional objects. Clients needs to +/// explicitly compare the underlying values and account for empty \c Optional +/// objects. +/// +/// This routine will never be defined. It returns \c void to help diagnose +/// errors at compile time. +template +void operator<=(const Optional &X, const Optional &Y); + +/// \brief Poison comparison between two \c Optional objects. Clients needs to +/// explicitly compare the underlying values and account for empty \c Optional +/// objects. +/// +/// This routine will never be defined. It returns \c void to help diagnose +/// errors at compile time. +template +void operator>=(const Optional &X, const Optional &Y); + +/// \brief Poison comparison between two \c Optional objects. Clients needs to +/// explicitly compare the underlying values and account for empty \c Optional +/// objects. +/// +/// This routine will never be defined. It returns \c void to help diagnose +/// errors at compile time. +template +void operator>(const Optional &X, const Optional &Y); + } // end llvm namespace #endif diff --git a/include/llvm/ADT/PointerIntPair.h b/include/llvm/ADT/PointerIntPair.h index 64f4a7cee4b9..85dbba2b4a4a 100644 --- a/include/llvm/ADT/PointerIntPair.h +++ b/include/llvm/ADT/PointerIntPair.h @@ -91,6 +91,13 @@ public: Value |= IntVal << IntShift; // Set new integer. } + PointerTy const *getAddrOfPointer() const { + assert(Value == reinterpret_cast(getPointer()) && + "Can only return the address if IntBits is cleared and " + "PtrTraits doesn't change the pointer"); + return reinterpret_cast(&Value); + } + void *getOpaqueValue() const { return reinterpret_cast(Value); } void setFromOpaqueValue(void *Val) { Value = reinterpret_cast(Val);} diff --git a/include/llvm/ADT/PointerUnion.h b/include/llvm/ADT/PointerUnion.h index 3a514b562697..61de042b0ff2 100644 --- a/include/llvm/ADT/PointerUnion.h +++ b/include/llvm/ADT/PointerUnion.h @@ -107,6 +107,18 @@ namespace llvm { if (is()) return get(); return T(); } + + /// \brief If the union is set to the first pointer type we can get an + /// address pointing to it. + template + PT1 const *getAddrOf() const { + assert(is() && "Val is not the first pointer"); + assert(get() == Val.getPointer() && + "Can't get the address because PointerLikeTypeTraits changes the ptr"); + T const *can_only_get_address_of_first_pointer_type + = reinterpret_cast(Val.getAddrOfPointer()); + return can_only_get_address_of_first_pointer_type; + } /// Assignment operators - Allow assigning into this union from either /// pointer type, setting the discriminator to remember what it came from. diff --git a/include/llvm/ADT/PostOrderIterator.h b/include/llvm/ADT/PostOrderIterator.h index 47e5b2bd4ad0..e3b499488d0c 100644 --- a/include/llvm/ADT/PostOrderIterator.h +++ b/include/llvm/ADT/PostOrderIterator.h @@ -56,8 +56,7 @@ class po_iterator : public std::iteratorVisited.count(BB)) { // If the block is not visited... - this->Visited.insert(BB); + if (this->Visited.insert(BB)) { // If the block is not visited... VisitStack.push_back(std::make_pair(BB, GT::child_begin(BB))); } } @@ -72,8 +71,7 @@ class po_iterator : public std::iterator(S) { - if(!S.count(BB)) { - this->Visited.insert(BB); + if (this->Visited.insert(BB)) { VisitStack.push_back(std::make_pair(BB, GT::child_begin(BB))); traverseChild(); } diff --git a/include/llvm/ADT/SCCIterator.h b/include/llvm/ADT/SCCIterator.h index c49d599cf38f..3e93cfe914fa 100644 --- a/include/llvm/ADT/SCCIterator.h +++ b/include/llvm/ADT/SCCIterator.h @@ -60,7 +60,7 @@ class scc_iterator // First element is basic block pointer, second is the 'next child' to visit std::vector > VisitStack; - // MinVistNumStack - Stack holding the "min" values for each node in the DFS. + // MinVisitNumStack - Stack holding the "min" values for each node in the DFS. // This is used to track the minimum uplink values for all children of // the corresponding node on the VisitStack. std::vector MinVisitNumStack; diff --git a/include/llvm/ADT/ScopedHashTable.h b/include/llvm/ADT/ScopedHashTable.h index c96ad19707f3..af3c482043b1 100644 --- a/include/llvm/ADT/ScopedHashTable.h +++ b/include/llvm/ADT/ScopedHashTable.h @@ -31,25 +31,23 @@ #ifndef LLVM_ADT_SCOPEDHASHTABLE_H #define LLVM_ADT_SCOPEDHASHTABLE_H -#include #include "llvm/ADT/DenseMap.h" +#include "llvm/Support/Allocator.h" namespace llvm { -template > +template , + typename AllocatorTy = MallocAllocator> class ScopedHashTable; -template > +template class ScopedHashTableVal { ScopedHashTableVal *NextInScope; ScopedHashTableVal *NextForKey; K Key; V Val; + ScopedHashTableVal(const K &key, const V &val) : Key(key), Val(val) {} public: - ScopedHashTableVal(ScopedHashTableVal *nextInScope, - ScopedHashTableVal *nextForKey, const K &key, const V &val) - : NextInScope(nextInScope), NextForKey(nextForKey), Key(key), Val(val) { - } const K &getKey() const { return Key; } const V &getValue() const { return Val; } @@ -57,33 +55,53 @@ public: ScopedHashTableVal *getNextForKey() { return NextForKey; } const ScopedHashTableVal *getNextForKey() const { return NextForKey; } -public: ScopedHashTableVal *getNextInScope() { return NextInScope; } + + template + static ScopedHashTableVal *Create(ScopedHashTableVal *nextInScope, + ScopedHashTableVal *nextForKey, + const K &key, const V &val, + AllocatorTy &Allocator) { + ScopedHashTableVal *New = Allocator.template Allocate(); + // Set up the value. + new (New) ScopedHashTableVal(key, val); + New->NextInScope = nextInScope; + New->NextForKey = nextForKey; + return New; + } + + template + void Destroy(AllocatorTy &Allocator) { + // Free memory referenced by the item. + this->~ScopedHashTableVal(); + Allocator.Deallocate(this); + } }; -template > +template , + typename AllocatorTy = MallocAllocator> class ScopedHashTableScope { /// HT - The hashtable that we are active for. - ScopedHashTable &HT; + ScopedHashTable &HT; /// PrevScope - This is the scope that we are shadowing in HT. ScopedHashTableScope *PrevScope; /// LastValInScope - This is the last value that was inserted for this scope /// or null if none have been inserted yet. - ScopedHashTableVal *LastValInScope; + ScopedHashTableVal *LastValInScope; void operator=(ScopedHashTableScope&); // DO NOT IMPLEMENT ScopedHashTableScope(ScopedHashTableScope&); // DO NOT IMPLEMENT public: - ScopedHashTableScope(ScopedHashTable &HT); + ScopedHashTableScope(ScopedHashTable &HT); ~ScopedHashTableScope(); private: - friend class ScopedHashTable; - ScopedHashTableVal *getLastValInScope() { + friend class ScopedHashTable; + ScopedHashTableVal *getLastValInScope() { return LastValInScope; } - void setLastValInScope(ScopedHashTableVal *Val) { + void setLastValInScope(ScopedHashTableVal *Val) { LastValInScope = Val; } }; @@ -91,9 +109,9 @@ private: template > class ScopedHashTableIterator { - ScopedHashTableVal *Node; + ScopedHashTableVal *Node; public: - ScopedHashTableIterator(ScopedHashTableVal *node) : Node(node) {} + ScopedHashTableIterator(ScopedHashTableVal *node) : Node(node) {} V &operator*() const { assert(Node && "Dereference end()"); @@ -121,26 +139,40 @@ public: }; -template +template class ScopedHashTable { - DenseMap*, KInfo> TopLevelMap; - ScopedHashTableScope *CurScope; + typedef ScopedHashTableVal ValTy; + DenseMap TopLevelMap; + ScopedHashTableScope *CurScope; + + AllocatorTy Allocator; + ScopedHashTable(const ScopedHashTable&); // NOT YET IMPLEMENTED void operator=(const ScopedHashTable&); // NOT YET IMPLEMENTED - friend class ScopedHashTableScope; + friend class ScopedHashTableScope; public: ScopedHashTable() : CurScope(0) {} + ScopedHashTable(AllocatorTy A) : CurScope(0), Allocator(A) {} ~ScopedHashTable() { assert(CurScope == 0 && TopLevelMap.empty() && "Scope imbalance!"); } + + /// ScopeTy - This is a helpful typedef that allows clients to get easy access + /// to the name of the scope for this hash table. + typedef ScopedHashTableScope ScopeTy; + + /// Access to the allocator. + typedef typename ReferenceAdder::result AllocatorRefTy; + typedef typename ReferenceAdder::result AllocatorCRefTy; + AllocatorRefTy getAllocator() { return Allocator; } + AllocatorCRefTy getAllocator() const { return Allocator; } bool count(const K &Key) const { return TopLevelMap.count(Key); } V lookup(const K &Key) { - typename DenseMap*, KInfo>::iterator - I = TopLevelMap.find(Key); + typename DenseMap::iterator I = TopLevelMap.find(Key); if (I != TopLevelMap.end()) return I->second->getValue(); @@ -150,10 +182,10 @@ public: void insert(const K &Key, const V &Val) { assert(CurScope && "No scope active!"); - ScopedHashTableVal *&KeyEntry = TopLevelMap[Key]; + ScopedHashTableVal *&KeyEntry = TopLevelMap[Key]; - KeyEntry= new ScopedHashTableVal(CurScope->getLastValInScope(), - KeyEntry, Key, Val); + KeyEntry = ValTy::Create(CurScope->getLastValInScope(), KeyEntry, Key, Val, + Allocator); CurScope->setLastValInScope(KeyEntry); } @@ -162,7 +194,7 @@ public: iterator end() { return iterator(0); } iterator begin(const K &Key) { - typename DenseMap*, KInfo>::iterator I = + typename DenseMap::iterator I = TopLevelMap.find(Key); if (I == TopLevelMap.end()) return end(); return iterator(I->second); @@ -171,29 +203,28 @@ public: /// ScopedHashTableScope ctor - Install this as the current scope for the hash /// table. -template -ScopedHashTableScope:: - ScopedHashTableScope(ScopedHashTable &ht) : HT(ht) { +template +ScopedHashTableScope:: + ScopedHashTableScope(ScopedHashTable &ht) : HT(ht) { PrevScope = HT.CurScope; HT.CurScope = this; LastValInScope = 0; } -template -ScopedHashTableScope::~ScopedHashTableScope() { +template +ScopedHashTableScope::~ScopedHashTableScope() { assert(HT.CurScope == this && "Scope imbalance!"); HT.CurScope = PrevScope; // Pop and delete all values corresponding to this scope. - while (ScopedHashTableVal *ThisEntry = LastValInScope) { + while (ScopedHashTableVal *ThisEntry = LastValInScope) { // Pop this value out of the TopLevelMap. if (ThisEntry->getNextForKey() == 0) { assert(HT.TopLevelMap[ThisEntry->getKey()] == ThisEntry && "Scope imbalance!"); HT.TopLevelMap.erase(ThisEntry->getKey()); } else { - ScopedHashTableVal *&KeyEntry = - HT.TopLevelMap[ThisEntry->getKey()]; + ScopedHashTableVal *&KeyEntry = HT.TopLevelMap[ThisEntry->getKey()]; assert(KeyEntry == ThisEntry && "Scope imbalance!"); KeyEntry = ThisEntry->getNextForKey(); } @@ -202,7 +233,7 @@ ScopedHashTableScope::~ScopedHashTableScope() { LastValInScope = ThisEntry->getNextInScope(); // Delete this entry. - delete ThisEntry; + ThisEntry->Destroy(HT.getAllocator()); } } diff --git a/include/llvm/ADT/SetVector.h b/include/llvm/ADT/SetVector.h index bf8286c1d840..abe20676d54d 100644 --- a/include/llvm/ADT/SetVector.h +++ b/include/llvm/ADT/SetVector.h @@ -114,13 +114,15 @@ public: } /// @brief Remove an item from the set vector. - void remove(const value_type& X) { + bool remove(const value_type& X) { if (set_.erase(X)) { typename vector_type::iterator I = std::find(vector_.begin(), vector_.end(), X); assert(I != vector_.end() && "Corrupted SetVector instances!"); vector_.erase(I); + return true; } + return false; } diff --git a/include/llvm/ADT/SmallBitVector.h b/include/llvm/ADT/SmallBitVector.h index 3441d0a90c9b..b15b3ee0418f 100644 --- a/include/llvm/ADT/SmallBitVector.h +++ b/include/llvm/ADT/SmallBitVector.h @@ -187,6 +187,13 @@ public: return getPointer()->any(); } + /// all - Returns true if all bits are set. + bool all() const { + if (isSmall()) + return getSmallBits() == (uintptr_t(1) << getSmallSize()) - 1; + return getPointer()->all(); + } + /// none - Returns true if none of the bits are set. bool none() const { if (isSmall()) diff --git a/include/llvm/ADT/SmallPtrSet.h b/include/llvm/ADT/SmallPtrSet.h index 424bdba5a20e..ff32ba87a264 100644 --- a/include/llvm/ADT/SmallPtrSet.h +++ b/include/llvm/ADT/SmallPtrSet.h @@ -16,9 +16,10 @@ #define LLVM_ADT_SMALLPTRSET_H #include +#include #include #include -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/Support/PointerLikeTypeTraits.h" namespace llvm { @@ -56,7 +57,7 @@ protected: /// it, so that the end iterator actually points to valid memory. unsigned CurArraySize; - // If small, this is # elts allocated consequtively + // If small, this is # elts allocated consecutively unsigned NumElements; unsigned NumTombstones; diff --git a/include/llvm/ADT/SmallString.h b/include/llvm/ADT/SmallString.h index 05bd8a42c67f..da264164821f 100644 --- a/include/llvm/ADT/SmallString.h +++ b/include/llvm/ADT/SmallString.h @@ -27,6 +27,9 @@ public: // Default ctor - Initialize to empty. SmallString() {} + // Initialize from a StringRef. + SmallString(StringRef S) : SmallVector(S.begin(), S.end()) {} + // Initialize with a range. template SmallString(ItTy S, ItTy E) : SmallVector(S, E) {} @@ -38,15 +41,16 @@ public: // Extra methods. StringRef str() const { return StringRef(this->begin(), this->size()); } - // Implicit conversion to StringRef. - operator StringRef() const { return str(); } - - const char *c_str() { + // TODO: Make this const, if it's safe... + const char* c_str() { this->push_back(0); this->pop_back(); return this->data(); } + // Implicit conversion to StringRef. + operator StringRef() const { return str(); } + // Extra operators. const SmallString &operator=(StringRef RHS) { this->clear(); diff --git a/include/llvm/ADT/SmallVector.h b/include/llvm/ADT/SmallVector.h index fec6bcd628cc..8b0a13d6ed74 100644 --- a/include/llvm/ADT/SmallVector.h +++ b/include/llvm/ADT/SmallVector.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #ifdef _MSC_VER @@ -57,19 +58,13 @@ protected: // Allocate raw space for N elements of type T. If T has a ctor or dtor, we // don't want it to be automatically run, so we need to represent the space as // something else. An array of char would work great, but might not be - // aligned sufficiently. Instead, we either use GCC extensions, or some - // number of union instances for the space, which guarantee maximal alignment. - struct U { -#ifdef __GNUC__ - char X __attribute__((aligned)); -#else - union { - double D; - long double LD; - long long L; - void *P; - } X; -#endif + // aligned sufficiently. Instead we use some number of union instances for + // the space, which guarantee maximal alignment. + union U { + double D; + long double LD; + long long L; + void *P; } FirstEl; // Space after 'FirstEl' is clobbered, do not add any instance vars after it. @@ -94,7 +89,7 @@ protected: } /// grow_pod - This is an implementation of the grow() method which only works - /// on POD-like datatypes and is out of line to reduce code duplication. + /// on POD-like data types and is out of line to reduce code duplication. void grow_pod(size_t MinSizeInBytes, size_t TSize); public: @@ -269,7 +264,7 @@ public: template class SmallVectorImpl : public SmallVectorTemplateBase::value> { typedef SmallVectorTemplateBase::value > SuperClass; - + SmallVectorImpl(const SmallVectorImpl&); // DISABLED. public: typedef typename SuperClass::iterator iterator; @@ -346,7 +341,6 @@ public: return Result; } - void swap(SmallVectorImpl &RHS); /// append - Add the specified range to the end of the SmallVector. diff --git a/include/llvm/ADT/SparseBitVector.h b/include/llvm/ADT/SparseBitVector.h index 0862981887ab..d977136b2fc1 100644 --- a/include/llvm/ADT/SparseBitVector.h +++ b/include/llvm/ADT/SparseBitVector.h @@ -17,7 +17,7 @@ #include "llvm/ADT/ilist.h" #include "llvm/ADT/ilist_node.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include diff --git a/include/llvm/ADT/Statistic.h b/include/llvm/ADT/Statistic.h index 3a1319f1090c..f137ea21d058 100644 --- a/include/llvm/ADT/Statistic.h +++ b/include/llvm/ADT/Statistic.h @@ -26,7 +26,7 @@ #ifndef LLVM_ADT_STATISTIC_H #define LLVM_ADT_STATISTIC_H -#include "llvm/System/Atomic.h" +#include "llvm/Support/Atomic.h" namespace llvm { class raw_ostream; diff --git a/include/llvm/ADT/StringExtras.h b/include/llvm/ADT/StringExtras.h index 3c53adee63c8..acbed66ef401 100644 --- a/include/llvm/ADT/StringExtras.h +++ b/include/llvm/ADT/StringExtras.h @@ -14,7 +14,7 @@ #ifndef LLVM_ADT_STRINGEXTRAS_H #define LLVM_ADT_STRINGEXTRAS_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/StringRef.h" #include @@ -25,10 +25,11 @@ namespace llvm { template class SmallVectorImpl; -/// hexdigit - Return the (uppercase) hexadecimal character for the +/// hexdigit - Return the hexadecimal character for the /// given number \arg X (which should be less than 16). -static inline char hexdigit(unsigned X) { - return X < 10 ? '0' + X : 'A' + X - 10; +static inline char hexdigit(unsigned X, bool LowerCase = false) { + const char HexChar = LowerCase ? 'a' : 'A'; + return X < 10 ? '0' + X : HexChar + X - 10; } /// utohex_buffer - Emit the specified number into the buffer specified by diff --git a/include/llvm/ADT/StringMap.h b/include/llvm/ADT/StringMap.h index 59ff6aa4f6aa..bad0e6f5136a 100644 --- a/include/llvm/ADT/StringMap.h +++ b/include/llvm/ADT/StringMap.h @@ -137,8 +137,8 @@ public: StringMapEntry(unsigned strLen, const ValueTy &V) : StringMapEntryBase(strLen), second(V) {} - StringRef getKey() const { - return StringRef(getKeyData(), getKeyLength()); + StringRef getKey() const { + return StringRef(getKeyData(), getKeyLength()); } const ValueTy &getValue() const { return second; } @@ -167,7 +167,7 @@ public: unsigned AllocSize = static_cast(sizeof(StringMapEntry))+ KeyLength+1; - unsigned Alignment = alignof(); + unsigned Alignment = alignOf(); StringMapEntry *NewItem = static_cast(Allocator.Allocate(AllocSize,Alignment)); @@ -216,14 +216,14 @@ public: static const StringMapEntry &GetStringMapEntryFromValue(const ValueTy &V) { return GetStringMapEntryFromValue(const_cast(V)); } - + /// GetStringMapEntryFromKeyData - Given key data that is known to be embedded /// into a StringMapEntry, return the StringMapEntry itself. static StringMapEntry &GetStringMapEntryFromKeyData(const char *KeyData) { char *Ptr = const_cast(KeyData) - sizeof(StringMapEntry); return *reinterpret_cast(Ptr); } - + /// Destroy - Destroy this StringMapEntry, releasing memory back to the /// specified allocator. @@ -254,7 +254,7 @@ public: StringMap() : StringMapImpl(static_cast(sizeof(MapEntryTy))) {} explicit StringMap(unsigned InitialSize) : StringMapImpl(InitialSize, static_cast(sizeof(MapEntryTy))) {} - + explicit StringMap(AllocatorTy A) : StringMapImpl(static_cast(sizeof(MapEntryTy))), Allocator(A) {} @@ -262,16 +262,19 @@ public: : StringMapImpl(static_cast(sizeof(MapEntryTy))) { assert(RHS.empty() && "Copy ctor from non-empty stringmap not implemented yet!"); + (void)RHS; } void operator=(const StringMap &RHS) { assert(RHS.empty() && "assignment from non-empty stringmap not implemented yet!"); + (void)RHS; clear(); } - - AllocatorTy &getAllocator() { return Allocator; } - const AllocatorTy &getAllocator() const { return Allocator; } + typedef typename ReferenceAdder::result AllocatorRefTy; + typedef typename ReferenceAdder::result AllocatorCRefTy; + AllocatorRefTy getAllocator() { return Allocator; } + AllocatorCRefTy getAllocator() const { return Allocator; } typedef const char* key_type; typedef ValueTy mapped_type; diff --git a/include/llvm/ADT/StringRef.h b/include/llvm/ADT/StringRef.h index 8386d3ee428b..1766d2b9f2d0 100644 --- a/include/llvm/ADT/StringRef.h +++ b/include/llvm/ADT/StringRef.h @@ -132,7 +132,7 @@ namespace llvm { /// numbers. int compare_numeric(StringRef RHS) const; - /// \brief Determine the edit distance between this string and another + /// \brief Determine the edit distance between this string and another /// string. /// /// \param Other the string to compare this string against. @@ -142,11 +142,16 @@ namespace llvm { /// operation, rather than as two operations (an insertion and a /// removal). /// + /// \param MaxEditDistance If non-zero, the maximum edit distance that + /// this routine is allowed to compute. If the edit distance will exceed + /// that maximum, returns \c MaxEditDistance+1. + /// /// \returns the minimum number of character insertions, removals, /// or (if \p AllowReplacements is \c true) replacements needed to /// transform one of the given strings into the other. If zero, /// the strings are identical. - unsigned edit_distance(StringRef Other, bool AllowReplacements = true); + unsigned edit_distance(StringRef Other, bool AllowReplacements = true, + unsigned MaxEditDistance = 0); /// str - Get the contents as an std::string. std::string str() const { @@ -251,6 +256,18 @@ namespace llvm { /// Note: O(size() + Chars.size()) size_type find_first_not_of(StringRef Chars, size_t From = 0) const; + /// find_last_of - Find the last character in the string that is \arg C, or + /// npos if not found. + size_type find_last_of(char C, size_t From = npos) const { + return rfind(C, From); + } + + /// find_last_of - Find the last character in the string that is in \arg C, + /// or npos if not found. + /// + /// Note: O(size() + Chars.size()) + size_type find_last_of(StringRef Chars, size_t From = npos) const; + /// @} /// @name Helpful Algorithms /// @{ @@ -432,6 +449,10 @@ namespace llvm { /// @} + // StringRefs can be treated like a POD type. + template struct isPodLike; + template <> struct isPodLike { static const bool value = true; }; + } #endif diff --git a/include/llvm/ADT/Triple.h b/include/llvm/ADT/Triple.h index 8dca3c1cfb1b..e6dcc23258f2 100644 --- a/include/llvm/ADT/Triple.h +++ b/include/llvm/ADT/Triple.h @@ -45,7 +45,7 @@ class Triple { public: enum ArchType { UnknownArch, - + alpha, // Alpha: alpha arm, // ARM; arm, armv.*, xscale bfin, // Blackfin: bfin @@ -53,7 +53,6 @@ public: mips, // MIPS: mips, mipsallegrex mipsel, // MIPSEL: mipsel, mipsallegrexel, psp msp430, // MSP430: msp430 - pic16, // PIC16: pic16 ppc, // PPC: powerpc ppc64, // PPC64: powerpc64, ppu sparc, // Sparc: sparc @@ -65,13 +64,14 @@ public: x86_64, // X86-64: amd64, x86_64 xcore, // XCore: xcore mblaze, // MBlaze: mblaze + ptx, // PTX: ptx InvalidArch }; enum VendorType { UnknownVendor, - Apple, + Apple, PC }; enum OSType { @@ -84,8 +84,7 @@ public: FreeBSD, Linux, Lv2, // PS3 - MinGW32, - MinGW64, + MinGW32, // i*86-pc-mingw32, *-w64-mingw32 NetBSD, OpenBSD, Psp, @@ -94,7 +93,15 @@ public: Haiku, Minix }; - + enum EnvironmentType { + UnknownEnvironment, + + GNU, + GNUEABI, + EABI, + MachO + }; + private: std::string Data; @@ -107,16 +114,20 @@ private: /// The parsed OS type. mutable OSType OS; + /// The parsed Environment type. + mutable EnvironmentType Environment; + bool isInitialized() const { return Arch != InvalidArch; } static ArchType ParseArch(StringRef ArchName); static VendorType ParseVendor(StringRef VendorName); static OSType ParseOS(StringRef OSName); + static EnvironmentType ParseEnvironment(StringRef EnvironmentName); void Parse() const; public: /// @name Constructors /// @{ - + Triple() : Data(), Arch(InvalidArch) {} explicit Triple(StringRef Str) : Data(Str), Arch(InvalidArch) {} explicit Triple(StringRef ArchStr, StringRef VendorStr, StringRef OSStr) @@ -127,6 +138,17 @@ public: Data += OSStr; } + explicit Triple(StringRef ArchStr, StringRef VendorStr, StringRef OSStr, + StringRef EnvironmentStr) + : Data(ArchStr), Arch(InvalidArch) { + Data += '-'; + Data += VendorStr; + Data += '-'; + Data += OSStr; + Data += '-'; + Data += EnvironmentStr; + } + /// @} /// @name Normalization /// @{ @@ -140,22 +162,22 @@ public: /// @} /// @name Typed Component Access /// @{ - + /// getArch - Get the parsed architecture type of this triple. - ArchType getArch() const { - if (!isInitialized()) Parse(); + ArchType getArch() const { + if (!isInitialized()) Parse(); return Arch; } - + /// getVendor - Get the parsed vendor type of this triple. - VendorType getVendor() const { - if (!isInitialized()) Parse(); + VendorType getVendor() const { + if (!isInitialized()) Parse(); return Vendor; } - + /// getOS - Get the parsed operating system type of this triple. - OSType getOS() const { - if (!isInitialized()) Parse(); + OSType getOS() const { + if (!isInitialized()) Parse(); return OS; } @@ -165,6 +187,12 @@ public: return getEnvironmentName() != ""; } + /// getEnvironment - Get the parsed environment type of this triple. + EnvironmentType getEnvironment() const { + if (!isInitialized()) Parse(); + return Environment; + } + /// @} /// @name Direct Component Access /// @{ @@ -193,13 +221,13 @@ public: /// if the environment component is present). StringRef getOSAndEnvironmentName() const; - + /// getDarwinNumber - Parse the 'darwin number' out of the specific target /// triple. For example, if we have darwin8.5 return 8,5,0. If any entry is /// not defined, return 0's. This requires that the triple have an OSType of /// darwin before it is called. void getDarwinNumber(unsigned &Maj, unsigned &Min, unsigned &Revision) const; - + /// getDarwinMajorNumber - Return just the major version number, this is /// specialized because it is a common query. unsigned getDarwinMajorNumber() const { @@ -207,7 +235,7 @@ public: getDarwinNumber(Maj, Min, Rev); return Maj; } - + /// @} /// @name Mutators /// @{ @@ -224,6 +252,10 @@ public: /// to a known type. void setOS(OSType Kind); + /// setEnvironment - Set the environment (fourth) component of the triple + /// to a known type. + void setEnvironment(EnvironmentType Kind); + /// setTriple - Set all components to the new triple \arg Str. void setTriple(const Twine &Str); @@ -271,9 +303,14 @@ public: /// vendor. static const char *getVendorTypeName(VendorType Kind); - /// getOSTypeName - Get the canonical name for the \arg Kind vendor. + /// getOSTypeName - Get the canonical name for the \arg Kind operating + /// system. static const char *getOSTypeName(OSType Kind); + /// getEnvironmentTypeName - Get the canonical name for the \arg Kind + /// environment. + static const char *getEnvironmentTypeName(EnvironmentType Kind); + /// @} /// @name Static helpers for converting alternate architecture names. /// @{ diff --git a/include/llvm/ADT/Twine.h b/include/llvm/ADT/Twine.h index b519a3e2ed11..ab8d3653e33f 100644 --- a/include/llvm/ADT/Twine.h +++ b/include/llvm/ADT/Twine.h @@ -11,7 +11,7 @@ #define LLVM_ADT_TWINE_H #include "llvm/ADT/StringRef.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include #include @@ -42,7 +42,7 @@ namespace llvm { /// Twines support a special 'null' value, which always concatenates to form /// itself, and renders as an empty string. This can be returned from APIs to /// effectively nullify any concatenations performed on the result. - /// + /// /// \b Implementation \n /// /// Given the nature of a Twine, it is not possible for the Twine's @@ -99,7 +99,7 @@ namespace llvm { /// A pointer to a StringRef instance. StringRefKind, - /// An unsigned int value reinterpreted as a pointer, to render as an + /// An unsigned int value reinterpreted as a pointer, to render as an /// unsigned decimal integer. DecUIKind, @@ -260,32 +260,32 @@ namespace llvm { } /// Construct a twine to print \arg Val as an unsigned decimal integer. - explicit Twine(unsigned Val) + explicit Twine(unsigned Val) : LHS((void*)(intptr_t)Val), LHSKind(DecUIKind), RHSKind(EmptyKind) { } /// Construct a twine to print \arg Val as a signed decimal integer. - explicit Twine(int Val) + explicit Twine(int Val) : LHS((void*)(intptr_t)Val), LHSKind(DecIKind), RHSKind(EmptyKind) { } /// Construct a twine to print \arg Val as an unsigned decimal integer. - explicit Twine(const unsigned long &Val) + explicit Twine(const unsigned long &Val) : LHS(&Val), LHSKind(DecULKind), RHSKind(EmptyKind) { } /// Construct a twine to print \arg Val as a signed decimal integer. - explicit Twine(const long &Val) + explicit Twine(const long &Val) : LHS(&Val), LHSKind(DecLKind), RHSKind(EmptyKind) { } /// Construct a twine to print \arg Val as an unsigned decimal integer. - explicit Twine(const unsigned long long &Val) + explicit Twine(const unsigned long long &Val) : LHS(&Val), LHSKind(DecULLKind), RHSKind(EmptyKind) { } /// Construct a twine to print \arg Val as a signed decimal integer. - explicit Twine(const long long &Val) + explicit Twine(const long long &Val) : LHS(&Val), LHSKind(DecLLKind), RHSKind(EmptyKind) { } @@ -330,12 +330,12 @@ namespace llvm { bool isTriviallyEmpty() const { return isNullary(); } - + /// isSingleStringRef - Return true if this twine can be dynamically /// accessed as a single StringRef value with getSingleStringRef(). bool isSingleStringRef() const { if (getRHSKind() != EmptyKind) return false; - + switch (getLHSKind()) { case EmptyKind: case CStringKind: @@ -382,6 +382,14 @@ namespace llvm { /// SmallVector and a StringRef to the SmallVector's data is returned. StringRef toStringRef(SmallVectorImpl &Out) const; + /// toNullTerminatedStringRef - This returns the twine as a single null + /// terminated StringRef if it can be represented as such. Otherwise the + /// twine is written into the given SmallVector and a StringRef to the + /// SmallVector's data is returned. + /// + /// The returned StringRef's size does not include the null terminator. + StringRef toNullTerminatedStringRef(SmallVectorImpl &Out) const; + /// print - Write the concatenated string represented by this twine to the /// stream \arg OS. void print(raw_ostream &OS) const; diff --git a/include/llvm/ADT/ValueMap.h b/include/llvm/ADT/ValueMap.h index ded17fc32223..d1f4e5a0dacd 100644 --- a/include/llvm/ADT/ValueMap.h +++ b/include/llvm/ADT/ValueMap.h @@ -29,7 +29,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/Support/ValueHandle.h" #include "llvm/Support/type_traits.h" -#include "llvm/System/Mutex.h" +#include "llvm/Support/Mutex.h" #include diff --git a/include/llvm/ADT/ilist.h b/include/llvm/ADT/ilist.h index 4e3afe171199..865fcb3d8aad 100644 --- a/include/llvm/ADT/ilist.h +++ b/include/llvm/ADT/ilist.h @@ -38,6 +38,7 @@ #ifndef LLVM_ADT_ILIST_H #define LLVM_ADT_ILIST_H +#include #include #include #include diff --git a/include/llvm/Analysis/AliasAnalysis.h b/include/llvm/Analysis/AliasAnalysis.h index ad68d48e531b..71a5982c7d39 100644 --- a/include/llvm/Analysis/AliasAnalysis.h +++ b/include/llvm/Analysis/AliasAnalysis.h @@ -16,11 +16,21 @@ // which automatically provides functionality for the entire suite of client // APIs. // -// This API represents memory as a (Pointer, Size) pair. The Pointer component -// specifies the base memory address of the region, the Size specifies how large -// of an area is being queried, or UnknownSize if the size is not known. -// Pointers that point to two completely different objects in memory never -// alias, regardless of the value of the Size component. +// This API identifies memory regions with the Location class. The pointer +// component specifies the base memory address of the region. The Size specifies +// the maximum size (in address units) of the memory region, or UnknownSize if +// the size is not known. The TBAA tag identifies the "type" of the memory +// reference; see the TypeBasedAliasAnalysis class for details. +// +// Some non-obvious details include: +// - Pointers that point to two completely different objects in memory never +// alias, regardless of the value of the Size component. +// - NoAlias doesn't imply inequal pointers. The most obvious example of this +// is two pointers to constant memory. Even if they are equal, constant +// memory is never stored to, so there will never be any dependencies. +// In this and other situations, the pointers may be both NoAlias and +// MustAlias at the same time. The current API can only return one result, +// though this is rarely a problem in practice. // //===----------------------------------------------------------------------===// @@ -28,7 +38,6 @@ #define LLVM_ANALYSIS_ALIAS_ANALYSIS_H #include "llvm/Support/CallSite.h" -#include "llvm/System/IncludeFile.h" #include namespace llvm { @@ -39,6 +48,8 @@ class VAArgInst; class TargetData; class Pass; class AnalysisUsage; +class MemTransferInst; +class MemIntrinsic; class AliasAnalysis { protected: @@ -67,7 +78,7 @@ public: /// UnknownSize - This is a special value which can be used with the /// size arguments in alias queries to indicate that the caller does not /// know the sizes of the potential memory references. - static unsigned const UnknownSize = ~0u; + static uint64_t const UnknownSize = ~UINT64_C(0); /// getTargetData - Return a pointer to the current TargetData object, or /// null if no TargetData object is available. @@ -77,12 +88,57 @@ public: /// getTypeStoreSize - Return the TargetData store size for the given type, /// if known, or a conservative value otherwise. /// - unsigned getTypeStoreSize(const Type *Ty); + uint64_t getTypeStoreSize(const Type *Ty); //===--------------------------------------------------------------------===// /// Alias Queries... /// + /// Location - A description of a memory location. + struct Location { + /// Ptr - The address of the start of the location. + const Value *Ptr; + /// Size - The maximum size of the location, in address-units, or + /// UnknownSize if the size is not known. Note that an unknown size does + /// not mean the pointer aliases the entire virtual address space, because + /// there are restrictions on stepping out of one object and into another. + /// See http://llvm.org/docs/LangRef.html#pointeraliasing + uint64_t Size; + /// TBAATag - The metadata node which describes the TBAA type of + /// the location, or null if there is no known unique tag. + const MDNode *TBAATag; + + explicit Location(const Value *P = 0, uint64_t S = UnknownSize, + const MDNode *N = 0) + : Ptr(P), Size(S), TBAATag(N) {} + + Location getWithNewPtr(const Value *NewPtr) const { + Location Copy(*this); + Copy.Ptr = NewPtr; + return Copy; + } + + Location getWithNewSize(uint64_t NewSize) const { + Location Copy(*this); + Copy.Size = NewSize; + return Copy; + } + + Location getWithoutTBAATag() const { + Location Copy(*this); + Copy.TBAATag = 0; + return Copy; + } + }; + + /// getLocation - Fill in Loc with information about the memory reference by + /// the given instruction. + Location getLocation(const LoadInst *LI); + Location getLocation(const StoreInst *SI); + Location getLocation(const VAArgInst *VI); + static Location getLocationForSource(const MemTransferInst *MTI); + static Location getLocationForDest(const MemIntrinsic *MI); + /// Alias analysis result - Either we know for sure that it does not alias, we /// know for sure it must alias, or we don't know anything: The two pointers /// _might_ alias. This enum is designed so you can do things like: @@ -92,33 +148,63 @@ public: /// See docs/AliasAnalysis.html for more information on the specific meanings /// of these values. /// - enum AliasResult { NoAlias = 0, MayAlias = 1, MustAlias = 2 }; + enum AliasResult { + NoAlias = 0, ///< No dependencies. + MayAlias, ///< Anything goes. + PartialAlias, ///< Pointers differ, but pointees overlap. + MustAlias ///< Pointers are equal. + }; /// alias - The main low level interface to the alias analysis implementation. - /// Returns a Result indicating whether the two pointers are aliased to each - /// other. This is the interface that must be implemented by specific alias - /// analysis implementations. - /// - virtual AliasResult alias(const Value *V1, unsigned V1Size, - const Value *V2, unsigned V2Size); + /// Returns an AliasResult indicating whether the two pointers are aliased to + /// each other. This is the interface that must be implemented by specific + /// alias analysis implementations. + virtual AliasResult alias(const Location &LocA, const Location &LocB); + + /// alias - A convenience wrapper. + AliasResult alias(const Value *V1, uint64_t V1Size, + const Value *V2, uint64_t V2Size) { + return alias(Location(V1, V1Size), Location(V2, V2Size)); + } - /// alias - A convenience wrapper for the case where the sizes are unknown. + /// alias - A convenience wrapper. AliasResult alias(const Value *V1, const Value *V2) { return alias(V1, UnknownSize, V2, UnknownSize); } /// isNoAlias - A trivial helper function to check to see if the specified /// pointers are no-alias. - bool isNoAlias(const Value *V1, unsigned V1Size, - const Value *V2, unsigned V2Size) { - return alias(V1, V1Size, V2, V2Size) == NoAlias; + bool isNoAlias(const Location &LocA, const Location &LocB) { + return alias(LocA, LocB) == NoAlias; } - /// pointsToConstantMemory - If the specified pointer is known to point into - /// constant global memory, return true. This allows disambiguation of store - /// instructions from constant pointers. - /// - virtual bool pointsToConstantMemory(const Value *P); + /// isNoAlias - A convenience wrapper. + bool isNoAlias(const Value *V1, uint64_t V1Size, + const Value *V2, uint64_t V2Size) { + return isNoAlias(Location(V1, V1Size), Location(V2, V2Size)); + } + + /// isMustAlias - A convenience wrapper. + bool isMustAlias(const Location &LocA, const Location &LocB) { + return alias(LocA, LocB) == MustAlias; + } + + /// isMustAlias - A convenience wrapper. + bool isMustAlias(const Value *V1, const Value *V2) { + return alias(V1, 1, V2, 1) == MustAlias; + } + + /// pointsToConstantMemory - If the specified memory location is + /// known to be constant, return true. If OrLocal is true and the + /// specified memory location is known to be "local" (derived from + /// an alloca), return true. Otherwise return false. + virtual bool pointsToConstantMemory(const Location &Loc, + bool OrLocal = false); + + /// pointsToConstantMemory - A convenient wrapper. + bool pointsToConstantMemory(const Value *P, bool OrLocal = false) { + return pointsToConstantMemory(Location(P), OrLocal); + } //===--------------------------------------------------------------------===// /// Simple mod/ref information... @@ -129,36 +215,48 @@ public: /// enum ModRefResult { NoModRef = 0, Ref = 1, Mod = 2, ModRef = 3 }; + /// These values define additional bits used to define the + /// ModRefBehavior values. + enum { Nowhere = 0, ArgumentPointees = 4, Anywhere = 8 | ArgumentPointees }; /// ModRefBehavior - Summary of how a function affects memory in the program. /// Loads from constant globals are not considered memory accesses for this /// interface. Also, functions may freely modify stack space local to their /// invocation without having to report it through these interfaces. enum ModRefBehavior { - // DoesNotAccessMemory - This function does not perform any non-local loads - // or stores to memory. - // - // This property corresponds to the GCC 'const' attribute. - DoesNotAccessMemory, - - // AccessesArguments - This function accesses function arguments in well - // known (possibly volatile) ways, but does not access any other memory. - AccessesArguments, - - // AccessesArgumentsAndGlobals - This function has accesses function - // arguments and global variables well known (possibly volatile) ways, but - // does not access any other memory. - AccessesArgumentsAndGlobals, - - // OnlyReadsMemory - This function does not perform any non-local stores or - // volatile loads, but may read from any memory location. - // - // This property corresponds to the GCC 'pure' attribute. - OnlyReadsMemory, - - // UnknownModRefBehavior - This indicates that the function could not be - // classified into one of the behaviors above. - UnknownModRefBehavior + /// DoesNotAccessMemory - This function does not perform any non-local loads + /// or stores to memory. + /// + /// This property corresponds to the GCC 'const' attribute. + /// This property corresponds to the LLVM IR 'readnone' attribute. + /// This property corresponds to the IntrNoMem LLVM intrinsic flag. + DoesNotAccessMemory = Nowhere | NoModRef, + + /// OnlyReadsArgumentPointees - The only memory references in this function + /// (if it has any) are non-volatile loads from objects pointed to by its + /// pointer-typed arguments, with arbitrary offsets. + /// + /// This property corresponds to the IntrReadArgMem LLVM intrinsic flag. + OnlyReadsArgumentPointees = ArgumentPointees | Ref, + + /// OnlyAccessesArgumentPointees - The only memory references in this + /// function (if it has any) are non-volatile loads and stores from objects + /// pointed to by its pointer-typed arguments, with arbitrary offsets. + /// + /// This property corresponds to the IntrReadWriteArgMem LLVM intrinsic flag. + OnlyAccessesArgumentPointees = ArgumentPointees | ModRef, + + /// OnlyReadsMemory - This function does not perform any non-local stores or + /// volatile loads, but may read from any memory location. + /// + /// This property corresponds to the GCC 'pure' attribute. + /// This property corresponds to the LLVM IR 'readonly' attribute. + /// This property corresponds to the IntrReadMem LLVM intrinsic flag. + OnlyReadsMemory = Anywhere | Ref, + + /// UnknownModRefBehavior - This indicates that the function could not be + /// classified into one of the behaviors above. + UnknownModRefBehavior = Anywhere | ModRef }; /// getModRefBehavior - Return the behavior when calling the given call site. @@ -168,11 +266,6 @@ public: /// For use when the call site is not known. virtual ModRefBehavior getModRefBehavior(const Function *F); - /// getIntrinsicModRefBehavior - Return the modref behavior of the intrinsic - /// with the given id. Most clients won't need this, because the regular - /// getModRefBehavior incorporates this information. - static ModRefBehavior getIntrinsicModRefBehavior(unsigned iid); - /// doesNotAccessMemory - If the specified call is known to never read or /// write memory, return true. If the call only reads from known-constant /// memory, it is also legal to return true. Calls that unwind the stack @@ -205,8 +298,7 @@ public: /// This property corresponds to the GCC 'pure' attribute. /// bool onlyReadsMemory(ImmutableCallSite CS) { - ModRefBehavior MRB = getModRefBehavior(CS); - return MRB == DoesNotAccessMemory || MRB == OnlyReadsMemory; + return onlyReadsMemory(getModRefBehavior(CS)); } /// onlyReadsMemory - If the specified function is known to only read from @@ -214,21 +306,114 @@ public: /// when the call site is not known. /// bool onlyReadsMemory(const Function *F) { - ModRefBehavior MRB = getModRefBehavior(F); - return MRB == DoesNotAccessMemory || MRB == OnlyReadsMemory; + return onlyReadsMemory(getModRefBehavior(F)); } + /// onlyReadsMemory - Return true if functions with the specified behavior are + /// known to only read from non-volatile memory (or not access memory at all). + /// + static bool onlyReadsMemory(ModRefBehavior MRB) { + return !(MRB & Mod); + } + + /// onlyAccessesArgPointees - Return true if functions with the specified + /// behavior are known to read and write at most from objects pointed to by + /// their pointer-typed arguments (with arbitrary offsets). + /// + static bool onlyAccessesArgPointees(ModRefBehavior MRB) { + return !(MRB & Anywhere & ~ArgumentPointees); + } + + /// doesAccessArgPointees - Return true if functions with the specified + /// behavior are known to potentially read or write from objects pointed + /// to be their pointer-typed arguments (with arbitrary offsets). + /// + static bool doesAccessArgPointees(ModRefBehavior MRB) { + return (MRB & ModRef) && (MRB & ArgumentPointees); + } /// getModRefInfo - Return information about whether or not an instruction may - /// read or write memory specified by the pointer operand. An instruction + /// read or write the specified memory location. An instruction /// that doesn't read or write memory may be trivially LICM'd for example. + ModRefResult getModRefInfo(const Instruction *I, + const Location &Loc) { + switch (I->getOpcode()) { + case Instruction::VAArg: return getModRefInfo((const VAArgInst*)I, Loc); + case Instruction::Load: return getModRefInfo((const LoadInst*)I, Loc); + case Instruction::Store: return getModRefInfo((const StoreInst*)I, Loc); + case Instruction::Call: return getModRefInfo((const CallInst*)I, Loc); + case Instruction::Invoke: return getModRefInfo((const InvokeInst*)I,Loc); + default: return NoModRef; + } + } + + /// getModRefInfo - A convenience wrapper. + ModRefResult getModRefInfo(const Instruction *I, + const Value *P, uint64_t Size) { + return getModRefInfo(I, Location(P, Size)); + } /// getModRefInfo (for call sites) - Return whether information about whether - /// a particular call site modifies or reads the memory specified by the - /// pointer. - /// + /// a particular call site modifies or reads the specified memory location. virtual ModRefResult getModRefInfo(ImmutableCallSite CS, - const Value *P, unsigned Size); + const Location &Loc); + + /// getModRefInfo (for call sites) - A convenience wrapper. + ModRefResult getModRefInfo(ImmutableCallSite CS, + const Value *P, uint64_t Size) { + return getModRefInfo(CS, Location(P, Size)); + } + + /// getModRefInfo (for calls) - Return whether information about whether + /// a particular call modifies or reads the specified memory location. + ModRefResult getModRefInfo(const CallInst *C, const Location &Loc) { + return getModRefInfo(ImmutableCallSite(C), Loc); + } + + /// getModRefInfo (for calls) - A convenience wrapper. + ModRefResult getModRefInfo(const CallInst *C, const Value *P, uint64_t Size) { + return getModRefInfo(C, Location(P, Size)); + } + + /// getModRefInfo (for invokes) - Return whether information about whether + /// a particular invoke modifies or reads the specified memory location. + ModRefResult getModRefInfo(const InvokeInst *I, + const Location &Loc) { + return getModRefInfo(ImmutableCallSite(I), Loc); + } + + /// getModRefInfo (for invokes) - A convenience wrapper. + ModRefResult getModRefInfo(const InvokeInst *I, + const Value *P, uint64_t Size) { + return getModRefInfo(I, Location(P, Size)); + } + + /// getModRefInfo (for loads) - Return whether information about whether + /// a particular load modifies or reads the specified memory location. + ModRefResult getModRefInfo(const LoadInst *L, const Location &Loc); + + /// getModRefInfo (for loads) - A convenience wrapper. + ModRefResult getModRefInfo(const LoadInst *L, const Value *P, uint64_t Size) { + return getModRefInfo(L, Location(P, Size)); + } + + /// getModRefInfo (for stores) - Return whether information about whether + /// a particular store modifies or reads the specified memory location. + ModRefResult getModRefInfo(const StoreInst *S, const Location &Loc); + + /// getModRefInfo (for stores) - A convenience wrapper. + ModRefResult getModRefInfo(const StoreInst *S, const Value *P, uint64_t Size){ + return getModRefInfo(S, Location(P, Size)); + } + + /// getModRefInfo (for va_args) - Return whether information about whether + /// a particular va_arg modifies or reads the specified memory location. + ModRefResult getModRefInfo(const VAArgInst* I, const Location &Loc); + + /// getModRefInfo (for va_args) - A convenience wrapper. + ModRefResult getModRefInfo(const VAArgInst* I, const Value* P, uint64_t Size){ + return getModRefInfo(I, Location(P, Size)); + } /// getModRefInfo - Return information about whether two call sites may refer /// to the same set of memory locations. See @@ -237,46 +422,31 @@ public: virtual ModRefResult getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2); -public: - /// Convenience functions... - ModRefResult getModRefInfo(const LoadInst *L, const Value *P, unsigned Size); - ModRefResult getModRefInfo(const StoreInst *S, const Value *P, unsigned Size); - ModRefResult getModRefInfo(const VAArgInst* I, const Value* P, unsigned Size); - ModRefResult getModRefInfo(const CallInst *C, const Value *P, unsigned Size) { - return getModRefInfo(ImmutableCallSite(C), P, Size); - } - ModRefResult getModRefInfo(const InvokeInst *I, - const Value *P, unsigned Size) { - return getModRefInfo(ImmutableCallSite(I), P, Size); - } - ModRefResult getModRefInfo(const Instruction *I, - const Value *P, unsigned Size) { - switch (I->getOpcode()) { - case Instruction::VAArg: return getModRefInfo((const VAArgInst*)I, P,Size); - case Instruction::Load: return getModRefInfo((const LoadInst*)I, P, Size); - case Instruction::Store: return getModRefInfo((const StoreInst*)I, P,Size); - case Instruction::Call: return getModRefInfo((const CallInst*)I, P, Size); - case Instruction::Invoke: return getModRefInfo((const InvokeInst*)I,P,Size); - default: return NoModRef; - } - } - //===--------------------------------------------------------------------===// /// Higher level methods for querying mod/ref information. /// /// canBasicBlockModify - Return true if it is possible for execution of the /// specified basic block to modify the value pointed to by Ptr. - /// - bool canBasicBlockModify(const BasicBlock &BB, const Value *P, unsigned Size); + bool canBasicBlockModify(const BasicBlock &BB, const Location &Loc); + + /// canBasicBlockModify - A convenience wrapper. + bool canBasicBlockModify(const BasicBlock &BB, const Value *P, uint64_t Size){ + return canBasicBlockModify(BB, Location(P, Size)); + } /// canInstructionRangeModify - Return true if it is possible for the /// execution of the specified instructions to modify the value pointed to by /// Ptr. The instructions to consider are all of the instructions in the /// range of [I1,I2] INCLUSIVE. I1 and I2 must be in the same basic block. - /// bool canInstructionRangeModify(const Instruction &I1, const Instruction &I2, - const Value *Ptr, unsigned Size); + const Location &Loc); + + /// canInstructionRangeModify - A convenience wrapper. + bool canInstructionRangeModify(const Instruction &I1, const Instruction &I2, + const Value *Ptr, uint64_t Size) { + return canInstructionRangeModify(I1, I2, Location(Ptr, Size)); + } //===--------------------------------------------------------------------===// /// Methods that clients should call when they transform the program to allow @@ -299,6 +469,17 @@ public: /// virtual void copyValue(Value *From, Value *To); + /// addEscapingUse - This method should be used whenever an escaping use is + /// added to a pointer value. Analysis implementations may either return + /// conservative responses for that value in the future, or may recompute + /// some or all internal state to continue providing precise responses. + /// + /// Escaping uses are considered by anything _except_ the following: + /// - GEPs or bitcasts of the pointer + /// - Loads through the pointer + /// - Stores through (but not of) the pointer + virtual void addEscapingUse(Use &U); + /// replaceWithNewValue - This method is the obvious combination of the two /// above, and it provided as a helper to simplify client code. /// @@ -323,11 +504,4 @@ bool isIdentifiedObject(const Value *V); } // End llvm namespace -// Because of the way .a files work, we must force the BasicAA implementation to -// be pulled in if the AliasAnalysis header is included. Otherwise we run -// the risk of AliasAnalysis being used, but the default implementation not -// being linked into the tool that uses it. -FORCE_DEFINING_FILE_TO_BE_LINKED(AliasAnalysis) -FORCE_DEFINING_FILE_TO_BE_LINKED(BasicAliasAnalysis) - #endif diff --git a/include/llvm/Analysis/AliasSetTracker.h b/include/llvm/Analysis/AliasSetTracker.h index 8e2f7fd29a31..e844d10dda03 100644 --- a/include/llvm/Analysis/AliasSetTracker.h +++ b/include/llvm/Analysis/AliasSetTracker.h @@ -40,10 +40,12 @@ class AliasSet : public ilist_node { Value *Val; // The pointer this record corresponds to. PointerRec **PrevInList, *NextInList; AliasSet *AS; - unsigned Size; + uint64_t Size; + const MDNode *TBAAInfo; public: PointerRec(Value *V) - : Val(V), PrevInList(0), NextInList(0), AS(0), Size(0) {} + : Val(V), PrevInList(0), NextInList(0), AS(0), Size(0), + TBAAInfo(DenseMapInfo::getEmptyKey()) {} Value *getValue() const { return Val; } @@ -55,11 +57,28 @@ class AliasSet : public ilist_node { return &NextInList; } - void updateSize(unsigned NewSize) { + void updateSizeAndTBAAInfo(uint64_t NewSize, const MDNode *NewTBAAInfo) { if (NewSize > Size) Size = NewSize; + + if (TBAAInfo == DenseMapInfo::getEmptyKey()) + // We don't have a TBAAInfo yet. Set it to NewTBAAInfo. + TBAAInfo = NewTBAAInfo; + else if (TBAAInfo != NewTBAAInfo) + // NewTBAAInfo conflicts with TBAAInfo. + TBAAInfo = DenseMapInfo::getTombstoneKey(); } - unsigned getSize() const { return Size; } + uint64_t getSize() const { return Size; } + + /// getTBAAInfo - Return the TBAAInfo, or null if there is no + /// information or conflicting information. + const MDNode *getTBAAInfo() const { + // If we have missing or conflicting TBAAInfo, return null. + if (TBAAInfo == DenseMapInfo::getEmptyKey() || + TBAAInfo == DenseMapInfo::getTombstoneKey()) + return 0; + return TBAAInfo; + } AliasSet *getAliasSet(AliasSetTracker &AST) { assert(AS && "No AliasSet yet!"); @@ -186,7 +205,8 @@ public: value_type *operator->() const { return &operator*(); } Value *getPointer() const { return CurNode->getValue(); } - unsigned getSize() const { return CurNode->getSize(); } + uint64_t getSize() const { return CurNode->getSize(); } + const MDNode *getTBAAInfo() const { return CurNode->getTBAAInfo(); } iterator& operator++() { // Preincrement assert(CurNode && "Advancing past AliasSet.end()!"); @@ -230,7 +250,8 @@ private: void removeFromTracker(AliasSetTracker &AST); - void addPointer(AliasSetTracker &AST, PointerRec &Entry, unsigned Size, + void addPointer(AliasSetTracker &AST, PointerRec &Entry, uint64_t Size, + const MDNode *TBAAInfo, bool KnownMustAlias = false); void addCallSite(CallSite CS, AliasAnalysis &AA); void removeCallSite(CallSite CS) { @@ -245,7 +266,8 @@ private: /// aliasesPointer - Return true if the specified pointer "may" (or must) /// alias one of the members in the set. /// - bool aliasesPointer(const Value *Ptr, unsigned Size, AliasAnalysis &AA) const; + bool aliasesPointer(const Value *Ptr, uint64_t Size, const MDNode *TBAAInfo, + AliasAnalysis &AA) const; bool aliasesCallSite(CallSite CS, AliasAnalysis &AA) const; }; @@ -298,7 +320,7 @@ public: /// These methods return true if inserting the instruction resulted in the /// addition of a new alias set (i.e., the pointer did not alias anything). /// - bool add(Value *Ptr, unsigned Size); // Add a location + bool add(Value *Ptr, uint64_t Size, const MDNode *TBAAInfo); // Add a location bool add(LoadInst *LI); bool add(StoreInst *SI); bool add(VAArgInst *VAAI); @@ -312,7 +334,8 @@ public: /// remove methods - These methods are used to remove all entries that might /// be aliased by the specified instruction. These methods return true if any /// alias sets were eliminated. - bool remove(Value *Ptr, unsigned Size); // Remove a location + // Remove a location + bool remove(Value *Ptr, uint64_t Size, const MDNode *TBAAInfo); bool remove(LoadInst *LI); bool remove(StoreInst *SI); bool remove(VAArgInst *VAAI); @@ -332,18 +355,21 @@ public: /// lives in. If the New argument is non-null, this method sets the value to /// true if a new alias set is created to contain the pointer (because the /// pointer didn't alias anything). - AliasSet &getAliasSetForPointer(Value *P, unsigned Size, bool *New = 0); + AliasSet &getAliasSetForPointer(Value *P, uint64_t Size, + const MDNode *TBAAInfo, + bool *New = 0); /// getAliasSetForPointerIfExists - Return the alias set containing the /// location specified if one exists, otherwise return null. - AliasSet *getAliasSetForPointerIfExists(Value *P, unsigned Size) { - return findAliasSetForPointer(P, Size); + AliasSet *getAliasSetForPointerIfExists(Value *P, uint64_t Size, + const MDNode *TBAAInfo) { + return findAliasSetForPointer(P, Size, TBAAInfo); } /// containsPointer - Return true if the specified location is represented by /// this alias set, false otherwise. This does not modify the AST object or /// alias sets. - bool containsPointer(Value *P, unsigned Size) const; + bool containsPointer(Value *P, uint64_t Size, const MDNode *TBAAInfo) const; /// getAliasAnalysis - Return the underlying alias analysis object used by /// this tracker. @@ -390,14 +416,16 @@ private: return *Entry; } - AliasSet &addPointer(Value *P, unsigned Size, AliasSet::AccessType E, + AliasSet &addPointer(Value *P, uint64_t Size, const MDNode *TBAAInfo, + AliasSet::AccessType E, bool &NewSet) { NewSet = false; - AliasSet &AS = getAliasSetForPointer(P, Size, &NewSet); + AliasSet &AS = getAliasSetForPointer(P, Size, TBAAInfo, &NewSet); AS.AccessTy |= E; return AS; } - AliasSet *findAliasSetForPointer(const Value *Ptr, unsigned Size); + AliasSet *findAliasSetForPointer(const Value *Ptr, uint64_t Size, + const MDNode *TBAAInfo); AliasSet *findAliasSetForCallSite(CallSite CS); }; diff --git a/include/llvm/Analysis/CallGraph.h b/include/llvm/Analysis/CallGraph.h index a4884edd5bd6..089f322e4a86 100644 --- a/include/llvm/Analysis/CallGraph.h +++ b/include/llvm/Analysis/CallGraph.h @@ -57,7 +57,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/Support/CallSite.h" #include "llvm/Support/ValueHandle.h" -#include "llvm/System/IncludeFile.h" +#include "llvm/Support/IncludeFile.h" #include namespace llvm { @@ -138,6 +138,13 @@ public: /// not already exist. CallGraphNode *getOrInsertFunction(const Function *F); + /// spliceFunction - Replace the function represented by this node by another. + /// This does not rescan the body of the function, so it is suitable when + /// splicing the body of one function to another while also updating all + /// callers from the old function to the new. + /// + void spliceFunction(const Function *From, const Function *To); + //===--------------------------------------------------------------------- // Pass infrastructure interface glue code. // @@ -163,8 +170,10 @@ protected: // CallGraphNode class definition. // class CallGraphNode { - AssertingVH F; + friend class CallGraph; + AssertingVH F; + // CallRecord - This is a pair of the calling instruction (a call or invoke) // and the callgraph node being called. public: diff --git a/include/llvm/Analysis/CodeMetrics.h b/include/llvm/Analysis/CodeMetrics.h index 58096f1f15b1..75edfbbed2e3 100644 --- a/include/llvm/Analysis/CodeMetrics.h +++ b/include/llvm/Analysis/CodeMetrics.h @@ -7,15 +7,16 @@ // //===----------------------------------------------------------------------===// // -// This file implements various weight measurements for a function, helping -// the Inliner and PartialSpecialization decide whether to duplicate its -// contents. +// This file implements various weight measurements for code, helping +// the Inliner and other passes decide whether to duplicate its contents. // //===----------------------------------------------------------------------===// #ifndef LLVM_ANALYSIS_CODEMETRICS_H #define LLVM_ANALYSIS_CODEMETRICS_H +#include "llvm/ADT/DenseMap.h" + namespace llvm { // CodeMetrics - Calculate size and a few similar metrics for a set of // basic blocks. @@ -45,6 +46,11 @@ namespace llvm { /// NumCalls - Keep track of the number of calls to 'big' functions. unsigned NumCalls; + + /// NumInlineCandidates - Keep track of the number of calls to internal + /// functions with only a single caller. These are likely targets for + /// future inlining, likely exposed by interleaved devirtualization. + unsigned NumInlineCandidates; /// NumVectorInsts - Keep track of how many instructions produce vector /// values. The inliner is being more aggressive with inlining vector @@ -56,7 +62,8 @@ namespace llvm { CodeMetrics() : callsSetJmp(false), isRecursive(false), containsIndirectBr(false), usesDynamicAlloca(false), - NumInsts(0), NumBlocks(0), NumCalls(0), NumVectorInsts(0), + NumInsts(0), NumBlocks(0), NumCalls(0), + NumInlineCandidates(0), NumVectorInsts(0), NumRets(0) {} /// analyzeBasicBlock - Add information about the specified basic block @@ -66,6 +73,22 @@ namespace llvm { /// analyzeFunction - Add information about the specified function /// to the current structure. void analyzeFunction(Function *F); + + /// CountCodeReductionForConstant - Figure out an approximation for how + /// many instructions will be constant folded if the specified value is + /// constant. + unsigned CountCodeReductionForConstant(Value *V); + + /// CountBonusForConstant - Figure out an approximation for how much + /// per-call performance boost we can expect if the specified value is + /// constant. + unsigned CountBonusForConstant(Value *V); + + /// CountCodeReductionForAlloca - Figure out an approximation of how much + /// smaller the function will be if it is inlined into a context where an + /// argument becomes an alloca. + /// + unsigned CountCodeReductionForAlloca(Value *V); }; } diff --git a/include/llvm/Analysis/ConstantFolding.h b/include/llvm/Analysis/ConstantFolding.h index e2675eb2d4f0..f6b1f5ab9915 100644 --- a/include/llvm/Analysis/ConstantFolding.h +++ b/include/llvm/Analysis/ConstantFolding.h @@ -7,7 +7,8 @@ // //===----------------------------------------------------------------------===// // -// This file declares routines for folding instructions into constants. +// This file declares routines for folding instructions into constants when all +// operands are constants, for example "sub i32 1, 0" -> "1". // // Also, to supplement the basic VMCore ConstantExpr simplifications, // this file declares some additional folding routines that can make use of @@ -27,11 +28,11 @@ namespace llvm { class Function; class Type; -/// ConstantFoldInstruction - Attempt to constant fold the specified -/// instruction. If successful, the constant result is returned, if not, null -/// is returned. Note that this function can only fail when attempting to fold -/// instructions like loads and stores, which have no constant expression form. -/// +/// ConstantFoldInstruction - Try to constant fold the specified instruction. +/// If successful, the constant result is returned, if not, null is returned. +/// Note that this fails if not all of the operands are constant. Otherwise, +/// this function can only fail when attempting to fold instructions like loads +/// and stores, which have no constant expression form. Constant *ConstantFoldInstruction(Instruction *I, const TargetData *TD = 0); /// ConstantFoldConstantExpression - Attempt to fold the constant expression diff --git a/include/llvm/Analysis/DIBuilder.h b/include/llvm/Analysis/DIBuilder.h new file mode 100644 index 000000000000..bd221344e5fa --- /dev/null +++ b/include/llvm/Analysis/DIBuilder.h @@ -0,0 +1,459 @@ +//===--- llvm/Analysis/DIBuilder.h - Debug Information Builder --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a DIBuilder that is useful for creating debugging +// information entries in LLVM IR form. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_DIBUILDER_H +#define LLVM_ANALYSIS_DIBUILDER_H + +#include "llvm/Support/DataTypes.h" +#include "llvm/ADT/StringRef.h" + +namespace llvm { + class BasicBlock; + class Instruction; + class Function; + class Module; + class Value; + class LLVMContext; + class MDNode; + class StringRef; + class DIDescriptor; + class DIFile; + class DIEnumerator; + class DIType; + class DIArray; + class DIGlobalVariable; + class DINameSpace; + class DIVariable; + class DISubrange; + class DILexicalBlock; + class DISubprogram; + class DITemplateTypeParameter; + class DITemplateValueParameter; + + class DIBuilder { + private: + Module &M; + LLVMContext & VMContext; + MDNode *TheCU; + + Function *DeclareFn; // llvm.dbg.declare + Function *ValueFn; // llvm.dbg.value + + DIBuilder(const DIBuilder &); // DO NOT IMPLEMENT + void operator=(const DIBuilder &); // DO NOT IMPLEMENT + + public: + explicit DIBuilder(Module &M); + const MDNode *getCU() { return TheCU; } + enum ComplexAddrKind { OpPlus=1, OpDeref }; + + /// CreateCompileUnit - A CompileUnit provides an anchor for all debugging + /// information generated during this instance of compilation. + /// @param Lang Source programming language, eg. dwarf::DW_LANG_C99 + /// @param File File name + /// @param Dir Directory + /// @param Producer String identify producer of debugging information. + /// Usuall this is a compiler version string. + /// @param isOptimized A boolean flag which indicates whether optimization + /// is ON or not. + /// @param Flags This string lists command line options. This string is + /// directly embedded in debug info output which may be used + /// by a tool analyzing generated debugging information. + /// @param RV This indicates runtime version for languages like + /// Objective-C. + void CreateCompileUnit(unsigned Lang, StringRef File, StringRef Dir, + StringRef Producer, + bool isOptimized, StringRef Flags, unsigned RV); + + /// CreateFile - Create a file descriptor to hold debugging information + /// for a file. + DIFile CreateFile(StringRef Filename, StringRef Directory); + + /// CreateEnumerator - Create a single enumerator value. + DIEnumerator CreateEnumerator(StringRef Name, uint64_t Val); + + /// CreateBasicType - Create debugging information entry for a basic + /// type. + /// @param Name Type name. + /// @param SizeInBits Size of the type. + /// @param AlignInBits Type alignment. + /// @param Encoding DWARF encoding code, e.g. dwarf::DW_ATE_float. + DIType CreateBasicType(StringRef Name, uint64_t SizeInBits, + uint64_t AlignInBits, unsigned Encoding); + + /// CreateQualifiedType - Create debugging information entry for a qualified + /// type, e.g. 'const int'. + /// @param Tag Tag identifing type, e.g. dwarf::TAG_volatile_type + /// @param FromTy Base Type. + DIType CreateQualifiedType(unsigned Tag, DIType FromTy); + + /// CreatePointerType - Create debugging information entry for a pointer. + /// @param PointeeTy Type pointed by this pointer. + /// @param SizeInBits Size. + /// @param AlignInBits Alignment. (optional) + /// @param Name Pointer type name. (optional) + DIType CreatePointerType(DIType PointeeTy, uint64_t SizeInBits, + uint64_t AlignInBits = 0, + StringRef Name = StringRef()); + + /// CreateReferenceType - Create debugging information entry for a c++ + /// style reference. + DIType CreateReferenceType(DIType RTy); + + /// CreateTypedef - Create debugging information entry for a typedef. + /// @param Ty Original type. + /// @param Name Typedef name. + /// @param File File where this type is defined. + /// @param LineNo Line number. + DIType CreateTypedef(DIType Ty, StringRef Name, DIFile File, + unsigned LineNo); + + /// CreateFriend - Create debugging information entry for a 'friend'. + DIType CreateFriend(DIType Ty, DIType FriendTy); + + /// CreateInheritance - Create debugging information entry to establish + /// inheritance relationship between two types. + /// @param Ty Original type. + /// @param BaseTy Base type. Ty is inherits from base. + /// @param BaseOffset Base offset. + /// @param Flags Flags to describe inheritance attribute, + /// e.g. private + DIType CreateInheritance(DIType Ty, DIType BaseTy, uint64_t BaseOffset, + unsigned Flags); + + /// CreateMemberType - Create debugging information entry for a member. + /// @param Name Member name. + /// @param File File where this member is defined. + /// @param LineNo Line number. + /// @param SizeInBits Member size. + /// @param AlignInBits Member alignment. + /// @param OffsetInBits Member offset. + /// @param Flags Flags to encode member attribute, e.g. private + /// @param Ty Parent type. + DIType CreateMemberType(StringRef Name, DIFile File, + unsigned LineNo, uint64_t SizeInBits, + uint64_t AlignInBits, uint64_t OffsetInBits, + unsigned Flags, DIType Ty); + + /// CreateClassType - Create debugging information entry for a class. + /// @param Scope Scope in which this class is defined. + /// @param Name class name. + /// @param File File where this member is defined. + /// @param LineNo Line number. + /// @param SizeInBits Member size. + /// @param AlignInBits Member alignment. + /// @param OffsetInBits Member offset. + /// @param Flags Flags to encode member attribute, e.g. private + /// @param Elements class members. + /// @param VTableHolder Debug info of the base class that contains vtable + /// for this type. This is used in + /// DW_AT_containing_type. See DWARF documentation + /// for more info. + /// @param TemplateParms Template type parameters. + DIType CreateClassType(DIDescriptor Scope, StringRef Name, DIFile File, + unsigned LineNumber, uint64_t SizeInBits, + uint64_t AlignInBits, uint64_t OffsetInBits, + unsigned Flags, DIType DerivedFrom, + DIArray Elements, MDNode *VTableHolder = 0, + MDNode *TemplateParms = 0); + + /// CreateStructType - Create debugging information entry for a struct. + /// @param Scope Scope in which this struct is defined. + /// @param Name Struct name. + /// @param File File where this member is defined. + /// @param LineNo Line number. + /// @param SizeInBits Member size. + /// @param AlignInBits Member alignment. + /// @param Flags Flags to encode member attribute, e.g. private + /// @param Elements Struct elements. + /// @param RunTimeLang Optional parameter, Objective-C runtime version. + DIType CreateStructType(DIDescriptor Scope, StringRef Name, DIFile File, + unsigned LineNumber, uint64_t SizeInBits, + uint64_t AlignInBits, unsigned Flags, + DIArray Elements, unsigned RunTimeLang = 0); + + /// CreateUnionType - Create debugging information entry for an union. + /// @param Scope Scope in which this union is defined. + /// @param Name Union name. + /// @param File File where this member is defined. + /// @param LineNo Line number. + /// @param SizeInBits Member size. + /// @param AlignInBits Member alignment. + /// @param Flags Flags to encode member attribute, e.g. private + /// @param Elements Union elements. + /// @param RunTimeLang Optional parameter, Objective-C runtime version. + DIType CreateUnionType(DIDescriptor Scope, StringRef Name, DIFile File, + unsigned LineNumber, uint64_t SizeInBits, + uint64_t AlignInBits, unsigned Flags, + DIArray Elements, unsigned RunTimeLang = 0); + + /// CreateTemplateTypeParameter - Create debugging information for template + /// type parameter. + /// @param Scope Scope in which this type is defined. + /// @param Name Type parameter name. + /// @param Ty Parameter type. + /// @param File File where this type parameter is defined. + /// @param LineNo Line number. + /// @param ColumnNo Column Number. + DITemplateTypeParameter + CreateTemplateTypeParameter(DIDescriptor Scope, StringRef Name, DIType Ty, + MDNode *File = 0, unsigned LineNo = 0, + unsigned ColumnNo = 0); + + /// CreateTemplateValueParameter - Create debugging information for template + /// value parameter. + /// @param Scope Scope in which this type is defined. + /// @param Name Value parameter name. + /// @param Ty Parameter type. + /// @param Value Constant parameter value. + /// @param File File where this type parameter is defined. + /// @param LineNo Line number. + /// @param ColumnNo Column Number. + DITemplateValueParameter + CreateTemplateValueParameter(DIDescriptor Scope, StringRef Name, DIType Ty, + uint64_t Value, + MDNode *File = 0, unsigned LineNo = 0, + unsigned ColumnNo = 0); + + /// CreateArrayType - Create debugging information entry for an array. + /// @param Size Array size. + /// @param AlignInBits Alignment. + /// @param Ty Element type. + /// @param Subscripts Subscripts. + DIType CreateArrayType(uint64_t Size, uint64_t AlignInBits, + DIType Ty, DIArray Subscripts); + + /// CreateVectorType - Create debugging information entry for a vector type. + /// @param Size Array size. + /// @param AlignInBits Alignment. + /// @param Ty Element type. + /// @param Subscripts Subscripts. + DIType CreateVectorType(uint64_t Size, uint64_t AlignInBits, + DIType Ty, DIArray Subscripts); + + /// CreateEnumerationType - Create debugging information entry for an + /// enumeration. + /// @param Scope Scope in which this enumeration is defined. + /// @param Name Union name. + /// @param File File where this member is defined. + /// @param LineNo Line number. + /// @param SizeInBits Member size. + /// @param AlignInBits Member alignment. + /// @param Elements Enumeration elements. + DIType CreateEnumerationType(DIDescriptor Scope, StringRef Name, + DIFile File, unsigned LineNumber, + uint64_t SizeInBits, + uint64_t AlignInBits, DIArray Elements); + + /// CreateSubroutineType - Create subroutine type. + /// @param File File in which this subroutine is defined. + /// @param ParamterTypes An array of subroutine parameter types. This + /// includes return type at 0th index. + DIType CreateSubroutineType(DIFile File, DIArray ParameterTypes); + + /// CreateArtificialType - Create a new DIType with "artificial" flag set. + DIType CreateArtificialType(DIType Ty); + + /// CreateTemporaryType - Create a temporary forward-declared type. + DIType CreateTemporaryType(); + DIType CreateTemporaryType(DIFile F); + + /// RetainType - Retain DIType in a module even if it is not referenced + /// through debug info anchors. + void RetainType(DIType T); + + /// CreateUnspecifiedParameter - Create unspeicified type descriptor + /// for a subroutine type. + DIDescriptor CreateUnspecifiedParameter(); + + /// GetOrCreateArray - Get a DIArray, create one if required. + DIArray GetOrCreateArray(Value *const *Elements, unsigned NumElements); + + /// GetOrCreateSubrange - Create a descriptor for a value range. This + /// implicitly uniques the values returned. + DISubrange GetOrCreateSubrange(int64_t Lo, int64_t Hi); + + /// CreateGlobalVariable - Create a new descriptor for the specified global. + /// @param Name Name of the variable. + /// @param File File where this variable is defined. + /// @param LineNo Line number. + /// @param Ty Variable Type. + /// @param isLocalToUnit Boolean flag indicate whether this variable is + /// externally visible or not. + /// @param Val llvm::Value of the variable. + DIGlobalVariable + CreateGlobalVariable(StringRef Name, DIFile File, unsigned LineNo, + DIType Ty, bool isLocalToUnit, llvm::Value *Val); + + + /// CreateStaticVariable - Create a new descriptor for the specified + /// variable. + /// @param Conext Variable scope. + /// @param Name Name of the variable. + /// @param LinakgeName Mangled name of the variable. + /// @param File File where this variable is defined. + /// @param LineNo Line number. + /// @param Ty Variable Type. + /// @param isLocalToUnit Boolean flag indicate whether this variable is + /// externally visible or not. + /// @param Val llvm::Value of the variable. + DIGlobalVariable + CreateStaticVariable(DIDescriptor Context, StringRef Name, + StringRef LinkageName, DIFile File, unsigned LineNo, + DIType Ty, bool isLocalToUnit, llvm::Value *Val); + + + /// CreateLocalVariable - Create a new descriptor for the specified + /// local variable. + /// @param Tag Dwarf TAG. Usually DW_TAG_auto_variable or + /// DW_TAG_arg_variable. + /// @param Scope Variable scope. + /// @param Name Variable name. + /// @param File File where this variable is defined. + /// @param LineNo Line number. + /// @param Ty Variable Type + /// @param AlwaysPreserve Boolean. Set to true if debug info for this + /// variable should be preserved in optimized build. + /// @param Flags Flags, e.g. artificial variable. + DIVariable CreateLocalVariable(unsigned Tag, DIDescriptor Scope, + StringRef Name, + DIFile File, unsigned LineNo, + DIType Ty, bool AlwaysPreserve = false, + unsigned Flags = 0); + + + /// CreateComplexVariable - Create a new descriptor for the specified + /// variable which has a complex address expression for its address. + /// @param Tag Dwarf TAG. Usually DW_TAG_auto_variable or + /// DW_TAG_arg_variable. + /// @param Scope Variable scope. + /// @param Name Variable name. + /// @param File File where this variable is defined. + /// @param LineNo Line number. + /// @param Ty Variable Type + /// @param Addr A pointer to a vector of complex address operations. + /// @param NumAddr Num of address operations in the vector. + DIVariable CreateComplexVariable(unsigned Tag, DIDescriptor Scope, + StringRef Name, DIFile F, unsigned LineNo, + DIType Ty, Value *const *Addr, + unsigned NumAddr); + + /// CreateFunction - Create a new descriptor for the specified subprogram. + /// See comments in DISubprogram for descriptions of these fields. + /// @param Scope Function scope. + /// @param Name Function name. + /// @param LinkageName Mangled function name. + /// @param File File where this variable is defined. + /// @param LineNo Line number. + /// @param Ty Function type. + /// @param isLocalToUnit True if this function is not externally visible.. + /// @param isDefinition True if this is a function definition. + /// @param Flags e.g. is this function prototyped or not. + /// This flags are used to emit dwarf attributes. + /// @param isOptimized True if optimization is ON. + /// @param Fn llvm::Function pointer. + DISubprogram CreateFunction(DIDescriptor Scope, StringRef Name, + StringRef LinkageName, + DIFile File, unsigned LineNo, + DIType Ty, bool isLocalToUnit, + bool isDefinition, + unsigned Flags = 0, + bool isOptimized = false, + Function *Fn = 0); + + /// CreateMethod - Create a new descriptor for the specified C++ method. + /// See comments in DISubprogram for descriptions of these fields. + /// @param Scope Function scope. + /// @param Name Function name. + /// @param LinkageName Mangled function name. + /// @param File File where this variable is defined. + /// @param LineNo Line number. + /// @param Ty Function type. + /// @param isLocalToUnit True if this function is not externally visible.. + /// @param isDefinition True if this is a function definition. + /// @param Virtuality Attributes describing virutallness. e.g. pure + /// virtual function. + /// @param VTableIndex Index no of this method in virtual table. + /// @param VTableHolder Type that holds vtable. + /// @param Flags e.g. is this function prototyped or not. + /// This flags are used to emit dwarf attributes. + /// @param isOptimized True if optimization is ON. + /// @param Fn llvm::Function pointer. + DISubprogram CreateMethod(DIDescriptor Scope, StringRef Name, + StringRef LinkageName, + DIFile File, unsigned LineNo, + DIType Ty, bool isLocalToUnit, + bool isDefinition, + unsigned Virtuality = 0, unsigned VTableIndex = 0, + MDNode *VTableHolder = 0, + unsigned Flags = 0, + bool isOptimized = false, + Function *Fn = 0); + + /// CreateNameSpace - This creates new descriptor for a namespace + /// with the specified parent scope. + /// @param Scope Namespace scope + /// @param Name Name of this namespace + /// @param File Source file + /// @param LineNo Line number + DINameSpace CreateNameSpace(DIDescriptor Scope, StringRef Name, + DIFile File, unsigned LineNo); + + + /// CreateLexicalBlock - This creates a descriptor for a lexical block + /// with the specified parent context. + /// @param Scope Parent lexical scope. + /// @param File Source file + /// @param Line Line number + /// @param Col Column number + DILexicalBlock CreateLexicalBlock(DIDescriptor Scope, DIFile File, + unsigned Line, unsigned Col); + + /// InsertDeclare - Insert a new llvm.dbg.declare intrinsic call. + /// @param Storage llvm::Value of the variable + /// @param VarInfo Variable's debug info descriptor. + /// @param InsertAtEnd Location for the new intrinsic. + Instruction *InsertDeclare(llvm::Value *Storage, DIVariable VarInfo, + BasicBlock *InsertAtEnd); + + /// InsertDeclare - Insert a new llvm.dbg.declare intrinsic call. + /// @param Storage llvm::Value of the variable + /// @param VarInfo Variable's debug info descriptor. + /// @param InsertBefore Location for the new intrinsic. + Instruction *InsertDeclare(llvm::Value *Storage, DIVariable VarInfo, + Instruction *InsertBefore); + + + /// InsertDbgValueIntrinsic - Insert a new llvm.dbg.value intrinsic call. + /// @param Val llvm::Value of the variable + /// @param Offset Offset + /// @param VarInfo Variable's debug info descriptor. + /// @param InsertAtEnd Location for the new intrinsic. + Instruction *InsertDbgValueIntrinsic(llvm::Value *Val, uint64_t Offset, + DIVariable VarInfo, + BasicBlock *InsertAtEnd); + + /// InsertDbgValueIntrinsic - Insert a new llvm.dbg.value intrinsic call. + /// @param Val llvm::Value of the variable + /// @param Offset Offset + /// @param VarInfo Variable's debug info descriptor. + /// @param InsertBefore Location for the new intrinsic. + Instruction *InsertDbgValueIntrinsic(llvm::Value *Val, uint64_t Offset, + DIVariable VarInfo, + Instruction *InsertBefore); + + }; +} // end namespace llvm + +#endif diff --git a/include/llvm/Analysis/DOTGraphTraitsPass.h b/include/llvm/Analysis/DOTGraphTraitsPass.h index d8daf5196fca..30741c4970ab 100644 --- a/include/llvm/Analysis/DOTGraphTraitsPass.h +++ b/include/llvm/Analysis/DOTGraphTraitsPass.h @@ -67,7 +67,7 @@ struct DOTGraphTraitsPrinter : public FunctionPass { Title = GraphName + " for '" + F.getNameStr() + "' function"; if (ErrorInfo.empty()) - WriteGraph(File, Graph, Simple, Name, Title); + WriteGraph(File, Graph, Simple, Title); else errs() << " error opening file for writing!"; errs() << "\n"; diff --git a/include/llvm/Analysis/DebugInfo.h b/include/llvm/Analysis/DebugInfo.h index 2d1418da64d8..aa69088b425b 100644 --- a/include/llvm/Analysis/DebugInfo.h +++ b/include/llvm/Analysis/DebugInfo.h @@ -33,6 +33,7 @@ namespace llvm { class DbgDeclareInst; class Instruction; class MDNode; + class NamedMDNode; class LLVMContext; class raw_ostream; @@ -46,6 +47,18 @@ namespace llvm { /// This should not be stored in a container, because underly MDNode may /// change in certain situations. class DIDescriptor { + public: + enum { + FlagPrivate = 1 << 0, + FlagProtected = 1 << 1, + FlagFwdDecl = 1 << 2, + FlagAppleBlock = 1 << 3, + FlagBlockByrefStruct = 1 << 4, + FlagVirtual = 1 << 5, + FlagArtificial = 1 << 6, + FlagExplicit = 1 << 7, + FlagPrototyped = 1 << 8 + }; protected: const MDNode *DbgNode; @@ -108,6 +121,9 @@ namespace llvm { bool isEnumerator() const; bool isType() const; bool isGlobal() const; + bool isUnspecifiedParameter() const; + bool isTemplateTypeParameter() const; + bool isTemplateValueParameter() const; }; /// DISubrange - This is used to represent ranges, for array bounds. @@ -160,8 +176,8 @@ namespace llvm { /// module does not contain any main compile unit then the code generator /// will emit multiple compile units in the output object file. - bool isMain() const { return getUnsignedField(6); } - bool isOptimized() const { return getUnsignedField(7); } + bool isMain() const { return getUnsignedField(6) != 0; } + bool isOptimized() const { return getUnsignedField(7) != 0; } StringRef getFlags() const { return getStringField(8); } unsigned getRunTimeVersion() const { return getUnsignedField(9); } @@ -203,17 +219,6 @@ namespace llvm { /// others do not require a huge and empty descriptor full of zeros. class DIType : public DIScope { public: - enum { - FlagPrivate = 1 << 0, - FlagProtected = 1 << 1, - FlagFwdDecl = 1 << 2, - FlagAppleBlock = 1 << 3, - FlagBlockByrefStruct = 1 << 4, - FlagVirtual = 1 << 5, - FlagArtificial = 1 << 6 // To identify artificial arguments in - // a subroutine type. e.g. "this" in c++. - }; - protected: // This ctor is used when the Tag has already been validated by a derived // ctor. @@ -231,12 +236,12 @@ namespace llvm { DIScope getContext() const { return getFieldAs(1); } StringRef getName() const { return getStringField(2); } DICompileUnit getCompileUnit() const{ - if (getVersion() == llvm::LLVMDebugVersion7) - return getFieldAs(3); - - DIFile F = getFieldAs(3); - return F.getCompileUnit(); + if (getVersion() == llvm::LLVMDebugVersion7) + return getFieldAs(3); + + return getFieldAs(3).getCompileUnit(); } + DIFile getFile() const { return getFieldAs(3); } unsigned getLineNumber() const { return getUnsignedField(4); } uint64_t getSizeInBits() const { return getUInt64Field(5); } uint64_t getAlignInBits() const { return getUInt64Field(6); } @@ -269,12 +274,23 @@ namespace llvm { bool isValid() const { return DbgNode && (isBasicType() || isDerivedType() || isCompositeType()); } - StringRef getFilename() const { return getCompileUnit().getFilename();} - StringRef getDirectory() const { return getCompileUnit().getDirectory();} + StringRef getDirectory() const { + if (getVersion() == llvm::LLVMDebugVersion7) + return getCompileUnit().getDirectory(); + + return getFieldAs(3).getDirectory(); + } + StringRef getFilename() const { + if (getVersion() == llvm::LLVMDebugVersion7) + return getCompileUnit().getFilename(); + + return getFieldAs(3).getFilename(); + } /// replaceAllUsesWith - Replace all uses of debug info referenced by /// this descriptor. void replaceAllUsesWith(DIDescriptor &D); + void replaceAllUsesWith(MDNode *D); /// print - print type. void print(raw_ostream &OS) const; @@ -342,6 +358,7 @@ namespace llvm { DICompositeType getContainingType() const { return getFieldAs(12); } + DIArray getTemplateParams() const { return getFieldAs(13); } /// Verify - Verify that a composite type descriptor is well formed. bool Verify() const; @@ -353,6 +370,43 @@ namespace llvm { void dump() const; }; + /// DITemplateTypeParameter - This is a wrapper for template type parameter. + class DITemplateTypeParameter : public DIDescriptor { + public: + explicit DITemplateTypeParameter(const MDNode *N = 0) : DIDescriptor(N) {} + + DIScope getContext() const { return getFieldAs(1); } + StringRef getName() const { return getStringField(2); } + DIType getType() const { return getFieldAs(3); } + StringRef getFilename() const { + return getFieldAs(4).getFilename(); + } + StringRef getDirectory() const { + return getFieldAs(4).getDirectory(); + } + unsigned getLineNumber() const { return getUnsignedField(5); } + unsigned getColumnNumber() const { return getUnsignedField(6); } + }; + + /// DITemplateValueParameter - This is a wrapper for template value parameter. + class DITemplateValueParameter : public DIDescriptor { + public: + explicit DITemplateValueParameter(const MDNode *N = 0) : DIDescriptor(N) {} + + DIScope getContext() const { return getFieldAs(1); } + StringRef getName() const { return getStringField(2); } + DIType getType() const { return getFieldAs(3); } + uint64_t getValue() const { return getUInt64Field(4); } + StringRef getFilename() const { + return getFieldAs(5).getFilename(); + } + StringRef getDirectory() const { + return getFieldAs(5).getDirectory(); + } + unsigned getLineNumber() const { return getUnsignedField(6); } + unsigned getColumnNumber() const { return getUnsignedField(7); } + }; + /// DISubprogram - This is a wrapper for a subprogram (e.g. a function). class DISubprogram : public DIScope { public: @@ -366,8 +420,7 @@ namespace llvm { if (getVersion() == llvm::LLVMDebugVersion7) return getFieldAs(6); - DIFile F = getFieldAs(6); - return F.getCompileUnit(); + return getFieldAs(6).getCompileUnit(); } unsigned getLineNumber() const { return getUnsignedField(7); } DICompositeType getType() const { return getFieldAs(8); } @@ -396,23 +449,52 @@ namespace llvm { DICompositeType getContainingType() const { return getFieldAs(13); } - unsigned isArtificial() const { return getUnsignedField(14); } + unsigned isArtificial() const { + if (getVersion() <= llvm::LLVMDebugVersion8) + return getUnsignedField(14); + return (getUnsignedField(14) & FlagArtificial) != 0; + } + /// isPrivate - Return true if this subprogram has "private" + /// access specifier. + bool isPrivate() const { + if (getVersion() <= llvm::LLVMDebugVersion8) + return false; + return (getUnsignedField(14) & FlagPrivate) != 0; + } + /// isProtected - Return true if this subprogram has "protected" + /// access specifier. + bool isProtected() const { + if (getVersion() <= llvm::LLVMDebugVersion8) + return false; + return (getUnsignedField(14) & FlagProtected) != 0; + } + /// isExplicit - Return true if this subprogram is marked as explicit. + bool isExplicit() const { + if (getVersion() <= llvm::LLVMDebugVersion8) + return false; + return (getUnsignedField(14) & FlagExplicit) != 0; + } + /// isPrototyped - Return true if this subprogram is prototyped. + bool isPrototyped() const { + if (getVersion() <= llvm::LLVMDebugVersion8) + return false; + return (getUnsignedField(14) & FlagPrototyped) != 0; + } + unsigned isOptimized() const; StringRef getFilename() const { if (getVersion() == llvm::LLVMDebugVersion7) return getCompileUnit().getFilename(); - DIFile F = getFieldAs(6); - return F.getFilename(); + return getFieldAs(6).getFilename(); } StringRef getDirectory() const { if (getVersion() == llvm::LLVMDebugVersion7) return getCompileUnit().getFilename(); - DIFile F = getFieldAs(6); - return F.getDirectory(); + return getFieldAs(6).getDirectory(); } /// Verify - Verify that a subprogram descriptor is well formed. @@ -484,6 +566,13 @@ namespace llvm { } unsigned getLineNumber() const { return getUnsignedField(4); } DIType getType() const { return getFieldAs(5); } + + /// isArtificial - Return true if this variable is marked as "artificial". + bool isArtificial() const { + if (getVersion() <= llvm::LLVMDebugVersion8) + return false; + return (getUnsignedField(6) & FlagArtificial) != 0; + } /// Verify - Verify that a variable descriptor is well formed. @@ -525,13 +614,11 @@ namespace llvm { unsigned getLineNumber() const { return getUnsignedField(2); } unsigned getColumnNumber() const { return getUnsignedField(3); } StringRef getDirectory() const { - DIFile F = getFieldAs(4); - StringRef dir = F.getDirectory(); + StringRef dir = getFieldAs(4).getDirectory(); return !dir.empty() ? dir : getContext().getDirectory(); } StringRef getFilename() const { - DIFile F = getFieldAs(4); - StringRef filename = F.getFilename(); + StringRef filename = getFieldAs(4).getFilename(); return !filename.empty() ? filename : getContext().getFilename(); } }; @@ -542,14 +629,17 @@ namespace llvm { explicit DINameSpace(const MDNode *N = 0) : DIScope(N) {} DIScope getContext() const { return getFieldAs(1); } StringRef getName() const { return getStringField(2); } - StringRef getDirectory() const { return getContext().getDirectory(); } - StringRef getFilename() const { return getContext().getFilename(); } + StringRef getDirectory() const { + return getFieldAs(3).getDirectory(); + } + StringRef getFilename() const { + return getFieldAs(3).getFilename(); + } DICompileUnit getCompileUnit() const{ if (getVersion() == llvm::LLVMDebugVersion7) return getFieldAs(3); - DIFile F = getFieldAs(3); - return F.getCompileUnit(); + return getFieldAs(3).getCompileUnit(); } unsigned getLineNumber() const { return getUnsignedField(4); } bool Verify() const; @@ -594,6 +684,10 @@ namespace llvm { /// implicitly uniques the values returned. DISubrange GetOrCreateSubrange(int64_t Lo, int64_t Hi); + /// CreateUnspecifiedParameter - Create unspeicified type descriptor + /// for a subroutine type. + DIDescriptor CreateUnspecifiedParameter(); + /// CreateCompileUnit - Create a new descriptor for the specified compile /// unit. DICompileUnit CreateCompileUnit(unsigned LangID, @@ -662,6 +756,7 @@ namespace llvm { /// CreateTemporaryType - Create a temporary forward-declared type. DIType CreateTemporaryType(); + DIType CreateTemporaryType(DIFile F); /// CreateArtificialType - Create a new DIType with "artificial" flag set. DIType CreateArtificialType(DIType Ty); @@ -690,8 +785,8 @@ namespace llvm { bool isDefinition, unsigned VK = 0, unsigned VIndex = 0, - DIType = DIType(), - bool isArtificial = 0, + DIType ContainingType = DIType(), + unsigned Flags = 0, bool isOptimized = false, Function *Fn = 0); @@ -721,15 +816,15 @@ namespace llvm { DIVariable CreateVariable(unsigned Tag, DIDescriptor Context, StringRef Name, DIFile F, unsigned LineNo, - DIType Ty, bool AlwaysPreserve = false); + DIType Ty, bool AlwaysPreserve = false, + unsigned Flags = 0); /// CreateComplexVariable - Create a new descriptor for the specified /// variable which has a complex address expression for its address. DIVariable CreateComplexVariable(unsigned Tag, DIDescriptor Context, - const std::string &Name, - DIFile F, unsigned LineNo, - DIType Ty, - SmallVector &addr); + StringRef Name, DIFile F, unsigned LineNo, + DIType Ty, Value *const *Addr, + unsigned NumAddr); /// CreateLexicalBlock - This creates a descriptor for a lexical block /// with the specified parent context. @@ -764,20 +859,29 @@ namespace llvm { /// InsertDbgValueIntrinsic - Insert a new llvm.dbg.value intrinsic call. Instruction *InsertDbgValueIntrinsic(llvm::Value *V, uint64_t Offset, DIVariable D, Instruction *InsertBefore); + + // RecordType - Record DIType in a module such that it is not lost even if + // it is not referenced through debug info anchors. + void RecordType(DIType T); + private: Constant *GetTagConstant(unsigned TAG); }; - bool getLocationInfo(const Value *V, std::string &DisplayName, - std::string &Type, unsigned &LineNo, std::string &File, - std::string &Dir); - /// getDISubprogram - Find subprogram that is enclosing this scope. DISubprogram getDISubprogram(const MDNode *Scope); /// getDICompositeType - Find underlying composite type. DICompositeType getDICompositeType(DIType T); + /// getOrInsertFnSpecificMDNode - Return a NameMDNode that is suitable + /// to hold function specific information. + NamedMDNode *getOrInsertFnSpecificMDNode(Module &M, StringRef Name); + + /// getFnSpecificMDNode - Return a NameMDNode, if available, that is + /// suitable to hold function specific information. + NamedMDNode *getFnSpecificMDNode(const Module &M, StringRef Name); + class DebugInfoFinder { public: /// processModule - Process entire module and collect debug info diff --git a/include/llvm/Analysis/DominanceFrontier.h b/include/llvm/Analysis/DominanceFrontier.h new file mode 100644 index 000000000000..d7f74af1c65c --- /dev/null +++ b/include/llvm/Analysis/DominanceFrontier.h @@ -0,0 +1,189 @@ +//===- llvm/Analysis/DominanceFrontier.h - Dominator Frontiers --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the DominanceFrontier class, which calculate and holds the +// dominance frontier for a function. +// +// This should be considered deprecated, don't add any more uses of this data +// structure. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ANALYSIS_DOMINANCEFRONTIER_H +#define LLVM_ANALYSIS_DOMINANCEFRONTIER_H + +#include "llvm/Analysis/Dominators.h" +#include +#include + +namespace llvm { + +//===----------------------------------------------------------------------===// +/// DominanceFrontierBase - Common base class for computing forward and inverse +/// dominance frontiers for a function. +/// +class DominanceFrontierBase : public FunctionPass { +public: + typedef std::set DomSetType; // Dom set for a bb + typedef std::map DomSetMapType; // Dom set map +protected: + DomSetMapType Frontiers; + std::vector Roots; + const bool IsPostDominators; + +public: + DominanceFrontierBase(char &ID, bool isPostDom) + : FunctionPass(ID), IsPostDominators(isPostDom) {} + + /// getRoots - Return the root blocks of the current CFG. This may include + /// multiple blocks if we are computing post dominators. For forward + /// dominators, this will always be a single block (the entry node). + /// + inline const std::vector &getRoots() const { return Roots; } + + /// isPostDominator - Returns true if analysis based of postdoms + /// + bool isPostDominator() const { return IsPostDominators; } + + virtual void releaseMemory() { Frontiers.clear(); } + + // Accessor interface: + typedef DomSetMapType::iterator iterator; + typedef DomSetMapType::const_iterator const_iterator; + iterator begin() { return Frontiers.begin(); } + const_iterator begin() const { return Frontiers.begin(); } + iterator end() { return Frontiers.end(); } + const_iterator end() const { return Frontiers.end(); } + iterator find(BasicBlock *B) { return Frontiers.find(B); } + const_iterator find(BasicBlock *B) const { return Frontiers.find(B); } + + iterator addBasicBlock(BasicBlock *BB, const DomSetType &frontier) { + assert(find(BB) == end() && "Block already in DominanceFrontier!"); + return Frontiers.insert(std::make_pair(BB, frontier)).first; + } + + /// removeBlock - Remove basic block BB's frontier. + void removeBlock(BasicBlock *BB) { + assert(find(BB) != end() && "Block is not in DominanceFrontier!"); + for (iterator I = begin(), E = end(); I != E; ++I) + I->second.erase(BB); + Frontiers.erase(BB); + } + + void addToFrontier(iterator I, BasicBlock *Node) { + assert(I != end() && "BB is not in DominanceFrontier!"); + I->second.insert(Node); + } + + void removeFromFrontier(iterator I, BasicBlock *Node) { + assert(I != end() && "BB is not in DominanceFrontier!"); + assert(I->second.count(Node) && "Node is not in DominanceFrontier of BB"); + I->second.erase(Node); + } + + /// compareDomSet - Return false if two domsets match. Otherwise + /// return true; + bool compareDomSet(DomSetType &DS1, const DomSetType &DS2) const { + std::set tmpSet; + for (DomSetType::const_iterator I = DS2.begin(), + E = DS2.end(); I != E; ++I) + tmpSet.insert(*I); + + for (DomSetType::const_iterator I = DS1.begin(), + E = DS1.end(); I != E; ) { + BasicBlock *Node = *I++; + + if (tmpSet.erase(Node) == 0) + // Node is in DS1 but not in DS2. + return true; + } + + if (!tmpSet.empty()) + // There are nodes that are in DS2 but not in DS1. + return true; + + // DS1 and DS2 matches. + return false; + } + + /// compare - Return true if the other dominance frontier base matches + /// this dominance frontier base. Otherwise return false. + bool compare(DominanceFrontierBase &Other) const { + DomSetMapType tmpFrontiers; + for (DomSetMapType::const_iterator I = Other.begin(), + E = Other.end(); I != E; ++I) + tmpFrontiers.insert(std::make_pair(I->first, I->second)); + + for (DomSetMapType::iterator I = tmpFrontiers.begin(), + E = tmpFrontiers.end(); I != E; ) { + BasicBlock *Node = I->first; + const_iterator DFI = find(Node); + if (DFI == end()) + return true; + + if (compareDomSet(I->second, DFI->second)) + return true; + + ++I; + tmpFrontiers.erase(Node); + } + + if (!tmpFrontiers.empty()) + return true; + + return false; + } + + /// print - Convert to human readable form + /// + virtual void print(raw_ostream &OS, const Module* = 0) const; + + /// dump - Dump the dominance frontier to dbgs(). + void dump() const; +}; + + +//===------------------------------------- +/// DominanceFrontier Class - Concrete subclass of DominanceFrontierBase that is +/// used to compute a forward dominator frontiers. +/// +class DominanceFrontier : public DominanceFrontierBase { +public: + static char ID; // Pass ID, replacement for typeid + DominanceFrontier() : + DominanceFrontierBase(ID, false) { + initializeDominanceFrontierPass(*PassRegistry::getPassRegistry()); + } + + BasicBlock *getRoot() const { + assert(Roots.size() == 1 && "Should always have entry node!"); + return Roots[0]; + } + + virtual bool runOnFunction(Function &) { + Frontiers.clear(); + DominatorTree &DT = getAnalysis(); + Roots = DT.getRoots(); + assert(Roots.size() == 1 && "Only one entry block for forward domfronts!"); + calculate(DT, DT[Roots[0]]); + return false; + } + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + AU.addRequired(); + } + + const DomSetType &calculate(const DominatorTree &DT, + const DomTreeNode *Node); +}; + +} // End llvm namespace + +#endif diff --git a/include/llvm/Analysis/DominatorInternals.h b/include/llvm/Analysis/DominatorInternals.h index 0419688a53bd..ae552b05abff 100644 --- a/include/llvm/Analysis/DominatorInternals.h +++ b/include/llvm/Analysis/DominatorInternals.h @@ -22,13 +22,9 @@ // A Fast Algorithm for Finding Dominators in a Flowgraph // T. Lengauer & R. Tarjan, ACM TOPLAS July 1979, pgs 121-141. // -// This implements both the O(n*ack(n)) and the O(n*log(n)) versions of EVAL and -// LINK, but it turns out that the theoretically slower O(n*log(n)) -// implementation is actually faster than the "efficient" algorithm (even for -// large CFGs) because the constant overheads are substantially smaller. The -// lower-complexity version can be enabled with the following #define: -// -#define BALANCE_IDOM_TREE 0 +// This implements the O(n*log(n)) versions of EVAL and LINK, because it turns +// out that the theoretically slower O(n*log(n)) implementation is actually +// faster than the almost-linear O(n*alpha(n)) version, even for large CFGs. // //===----------------------------------------------------------------------===// @@ -46,9 +42,6 @@ unsigned DFSPass(DominatorTreeBase& DT, VInfo.Label = V; Vertex.push_back(V); // Vertex[n] = V; - //Info[V].Ancestor = 0; // Ancestor[n] = 0 - //Info[V].Child = 0; // Child[v] = 0 - VInfo.Size = 1; // Size[v] = 1 for (succ_iterator SI = succ_begin(V), E = succ_end(V); SI != E; ++SI) { InfoRec &SuccVInfo = DT.Info[*SI]; @@ -58,10 +51,10 @@ unsigned DFSPass(DominatorTreeBase& DT, } } #else - bool IsChilOfArtificialExit = (N != 0); + bool IsChildOfArtificialExit = (N != 0); - std::vector > Worklist; + SmallVector, 32> Worklist; Worklist.push_back(std::make_pair(V, GraphT::child_begin(V))); while (!Worklist.empty()) { typename GraphT::NodeType* BB = Worklist.back().first; @@ -76,14 +69,11 @@ unsigned DFSPass(DominatorTreeBase& DT, BBInfo.Label = BB; DT.Vertex.push_back(BB); // Vertex[n] = V; - //BBInfo[V].Ancestor = 0; // Ancestor[n] = 0 - //BBInfo[V].Child = 0; // Child[v] = 0 - BBInfo.Size = 1; // Size[v] = 1 - if (IsChilOfArtificialExit) + if (IsChildOfArtificialExit) BBInfo.Parent = 1; - IsChilOfArtificialExit = false; + IsChildOfArtificialExit = false; } // store the DFS number of the current BB - the reference to BBInfo might @@ -114,118 +104,47 @@ unsigned DFSPass(DominatorTreeBase& DT, } template -void Compress(DominatorTreeBase& DT, - typename GraphT::NodeType *VIn) { - std::vector Work; +typename GraphT::NodeType* +Eval(DominatorTreeBase& DT, + typename GraphT::NodeType *VIn, unsigned LastLinked) { + typename DominatorTreeBase::InfoRec &VInInfo = + DT.Info[VIn]; + if (VInInfo.DFSNum < LastLinked) + return VIn; + + SmallVector Work; SmallPtrSet Visited; - typename DominatorTreeBase::InfoRec &VInVAInfo = - DT.Info[DT.Vertex[DT.Info[VIn].Ancestor]]; - if (VInVAInfo.Ancestor != 0) + if (VInInfo.Parent >= LastLinked) Work.push_back(VIn); while (!Work.empty()) { typename GraphT::NodeType* V = Work.back(); typename DominatorTreeBase::InfoRec &VInfo = DT.Info[V]; - typename GraphT::NodeType* VAncestor = DT.Vertex[VInfo.Ancestor]; - typename DominatorTreeBase::InfoRec &VAInfo = - DT.Info[VAncestor]; + typename GraphT::NodeType* VAncestor = DT.Vertex[VInfo.Parent]; // Process Ancestor first - if (Visited.insert(VAncestor) && - VAInfo.Ancestor != 0) { + if (Visited.insert(VAncestor) && VInfo.Parent >= LastLinked) { Work.push_back(VAncestor); continue; } Work.pop_back(); // Update VInfo based on Ancestor info - if (VAInfo.Ancestor == 0) + if (VInfo.Parent < LastLinked) continue; + + typename DominatorTreeBase::InfoRec &VAInfo = + DT.Info[VAncestor]; typename GraphT::NodeType* VAncestorLabel = VAInfo.Label; typename GraphT::NodeType* VLabel = VInfo.Label; if (DT.Info[VAncestorLabel].Semi < DT.Info[VLabel].Semi) VInfo.Label = VAncestorLabel; - VInfo.Ancestor = VAInfo.Ancestor; - } -} - -template -typename GraphT::NodeType* -Eval(DominatorTreeBase& DT, - typename GraphT::NodeType *V) { - typename DominatorTreeBase::InfoRec &VInfo = - DT.Info[V]; -#if !BALANCE_IDOM_TREE - // Higher-complexity but faster implementation - if (VInfo.Ancestor == 0) - return V; - Compress(DT, V); - return VInfo.Label; -#else - // Lower-complexity but slower implementation - if (VInfo.Ancestor == 0) - return VInfo.Label; - Compress(DT, V); - GraphT::NodeType* VLabel = VInfo.Label; - - GraphT::NodeType* VAncestorLabel = DT.Info[VInfo.Ancestor].Label; - if (DT.Info[VAncestorLabel].Semi >= DT.Info[VLabel].Semi) - return VLabel; - else - return VAncestorLabel; -#endif -} - -template -void Link(DominatorTreeBase& DT, - unsigned DFSNumV, typename GraphT::NodeType* W, - typename DominatorTreeBase::InfoRec &WInfo) { -#if !BALANCE_IDOM_TREE - // Higher-complexity but faster implementation - WInfo.Ancestor = DFSNumV; -#else - // Lower-complexity but slower implementation - GraphT::NodeType* WLabel = WInfo.Label; - unsigned WLabelSemi = DT.Info[WLabel].Semi; - GraphT::NodeType* S = W; - InfoRec *SInfo = &DT.Info[S]; - - GraphT::NodeType* SChild = SInfo->Child; - InfoRec *SChildInfo = &DT.Info[SChild]; - - while (WLabelSemi < DT.Info[SChildInfo->Label].Semi) { - GraphT::NodeType* SChildChild = SChildInfo->Child; - if (SInfo->Size+DT.Info[SChildChild].Size >= 2*SChildInfo->Size) { - SChildInfo->Ancestor = S; - SInfo->Child = SChild = SChildChild; - SChildInfo = &DT.Info[SChild]; - } else { - SChildInfo->Size = SInfo->Size; - S = SInfo->Ancestor = SChild; - SInfo = SChildInfo; - SChild = SChildChild; - SChildInfo = &DT.Info[SChild]; - } + VInfo.Parent = VAInfo.Parent; } - DominatorTreeBase::InfoRec &VInfo = DT.Info[V]; - SInfo->Label = WLabel; - - assert(V != W && "The optimization here will not work in this case!"); - unsigned WSize = WInfo.Size; - unsigned VSize = (VInfo.Size += WSize); - - if (VSize < 2*WSize) - std::swap(S, VInfo.Child); - - while (S) { - SInfo = &DT.Info[S]; - SInfo->Ancestor = V; - S = SInfo->Child; - } -#endif + return VInInfo.Label; } template @@ -242,9 +161,6 @@ void Calculate(DominatorTreeBase::NodeType>& DT, BBInfo.Label = NULL; DT.Vertex.push_back(NULL); // Vertex[n] = V; - //BBInfo[V].Ancestor = 0; // Ancestor[n] = 0 - //BBInfo[V].Child = 0; // Child[v] = 0 - BBInfo.Size = 1; // Size[v] = 1 } // Step #1: Number blocks in depth-first order and initialize variables used @@ -257,12 +173,34 @@ void Calculate(DominatorTreeBase::NodeType>& DT, // infinite loops). In these cases an artificial exit node is required. MultipleRoots |= (DT.isPostDominator() && N != F.size()); + // When naively implemented, the Lengauer-Tarjan algorithm requires a separate + // bucket for each vertex. However, this is unnecessary, because each vertex + // is only placed into a single bucket (that of its semidominator), and each + // vertex's bucket is processed before it is added to any bucket itself. + // + // Instead of using a bucket per vertex, we use a single array Buckets that + // has two purposes. Before the vertex V with preorder number i is processed, + // Buckets[i] stores the index of the first element in V's bucket. After V's + // bucket is processed, Buckets[i] stores the index of the next element in the + // bucket containing V, if any. + SmallVector Buckets; + Buckets.resize(N + 1); + for (unsigned i = 1; i <= N; ++i) + Buckets[i] = i; + for (unsigned i = N; i >= 2; --i) { typename GraphT::NodeType* W = DT.Vertex[i]; typename DominatorTreeBase::InfoRec &WInfo = DT.Info[W]; - // Step #2: Calculate the semidominators of all vertices + // Step #2: Implicitly define the immediate dominator of vertices + for (unsigned j = i; Buckets[j] != i; j = Buckets[j]) { + typename GraphT::NodeType* V = DT.Vertex[Buckets[j]]; + typename GraphT::NodeType* U = Eval(DT, V, i + 1); + DT.IDoms[V] = DT.Info[U].Semi < i ? U : W; + } + + // Step #3: Calculate the semidominators of all vertices // initialize the semi dominator to point to the parent node WInfo.Semi = WInfo.Parent; @@ -272,25 +210,28 @@ void Calculate(DominatorTreeBase::NodeType>& DT, E = InvTraits::child_end(W); CI != E; ++CI) { typename InvTraits::NodeType *N = *CI; if (DT.Info.count(N)) { // Only if this predecessor is reachable! - unsigned SemiU = DT.Info[Eval(DT, N)].Semi; + unsigned SemiU = DT.Info[Eval(DT, N, i + 1)].Semi; if (SemiU < WInfo.Semi) WInfo.Semi = SemiU; } } - DT.Info[DT.Vertex[WInfo.Semi]].Bucket.push_back(W); - - typename GraphT::NodeType* WParent = DT.Vertex[WInfo.Parent]; - Link(DT, WInfo.Parent, W, WInfo); + // If V is a non-root vertex and sdom(V) = parent(V), then idom(V) is + // necessarily parent(V). In this case, set idom(V) here and avoid placing + // V into a bucket. + if (WInfo.Semi == WInfo.Parent) { + DT.IDoms[W] = DT.Vertex[WInfo.Parent]; + } else { + Buckets[i] = Buckets[WInfo.Semi]; + Buckets[WInfo.Semi] = i; + } + } - // Step #3: Implicitly define the immediate dominator of vertices - std::vector &WParentBucket = - DT.Info[WParent].Bucket; - while (!WParentBucket.empty()) { - typename GraphT::NodeType* V = WParentBucket.back(); - WParentBucket.pop_back(); - typename GraphT::NodeType* U = Eval(DT, V); - DT.IDoms[V] = DT.Info[U].Semi < DT.Info[V].Semi ? U : WParent; + if (N >= 1) { + typename GraphT::NodeType* Root = DT.Vertex[1]; + for (unsigned j = 1; Buckets[j] != 1; j = Buckets[j]) { + typename GraphT::NodeType* V = DT.Vertex[Buckets[j]]; + DT.IDoms[V] = Root; } } diff --git a/include/llvm/Analysis/Dominators.h b/include/llvm/Analysis/Dominators.h index 73c6e6286b5b..230e83d30121 100644 --- a/include/llvm/Analysis/Dominators.h +++ b/include/llvm/Analysis/Dominators.h @@ -7,14 +7,8 @@ // //===----------------------------------------------------------------------===// // -// This file defines the following classes: -// 1. DominatorTree: Represent dominators as an explicit tree structure. -// 2. DominanceFrontier: Calculate and hold the dominance frontier for a -// function. -// -// These data structures are listed in increasing order of complexity. It -// takes longer to calculate the dominator frontier, for example, than the -// DominatorTree mapping. +// This file defines the DominatorTree class, which provides fast and efficient +// dominance queries. // //===----------------------------------------------------------------------===// @@ -23,19 +17,15 @@ #include "llvm/Pass.h" #include "llvm/Function.h" -#include "llvm/Instructions.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Assembly/Writer.h" #include "llvm/Support/CFG.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include -#include -#include namespace llvm { @@ -205,15 +195,11 @@ protected: // Information record used during immediate dominators computation. struct InfoRec { unsigned DFSNum; + unsigned Parent; unsigned Semi; - unsigned Size; - NodeT *Label, *Child; - unsigned Parent, Ancestor; - - std::vector Bucket; + NodeT *Label; - InfoRec() : DFSNum(0), Semi(0), Size(0), Label(0), Child(0), Parent(0), - Ancestor(0) {} + InfoRec() : DFSNum(0), Parent(0), Semi(0), Label(0) {} }; DenseMap IDoms; @@ -303,9 +289,6 @@ public: : DominatorBase(isPostDom), DFSInfoValid(false), SlowQueries(0) {} virtual ~DominatorTreeBase() { reset(); } - // FIXME: Should remove this - virtual bool runOnFunction(Function &F) { return false; } - /// compare - Return false if the other dominator tree base matches this /// dominator tree base. Otherwise return true. bool compare(DominatorTreeBase &Other) const { @@ -361,8 +344,15 @@ public: return dominatedBySlowTreeWalk(A, B); } - inline bool properlyDominates(NodeT *A, NodeT *B) { - return properlyDominates(getNode(A), getNode(B)); + inline bool properlyDominates(const NodeT *A, const NodeT *B) { + if (A == B) + return false; + + // Cast away the const qualifiers here. This is ok since + // this function doesn't actually return the values returned + // from getNode. + return properlyDominates(getNode(const_cast(A)), + getNode(const_cast(B))); } bool dominatedBySlowTreeWalk(const DomTreeNodeBase *A, @@ -377,7 +367,7 @@ public: /// isReachableFromEntry - Return true if A is dominated by the entry /// block of the function containing it. - bool isReachableFromEntry(NodeT* A) { + bool isReachableFromEntry(const NodeT* A) { assert(!this->isPostDominator() && "This is not implemented for post dominators"); return dominates(&A->getParent()->front(), A); @@ -478,6 +468,13 @@ public: return NULL; } + const NodeT *findNearestCommonDominator(const NodeT *A, const NodeT *B) { + // Cast away the const qualifiers here. This is ok since + // const is re-introduced on the return type. + return findNearestCommonDominator(const_cast(A), + const_cast(B)); + } + //===--------------------------------------------------------------------===// // API to update (Post)DominatorTree information based on modifications to // the CFG... @@ -509,7 +506,7 @@ public: } /// eraseNode - Removes a node from the dominator tree. Block must not - /// domiante any other blocks. Removes node from its immediate dominator's + /// dominate any other blocks. Removes node from its immediate dominator's /// children list. Deletes dominator node associated with basic block BB. void eraseNode(NodeT *BB) { DomTreeNodeBase *Node = getNode(BB); @@ -556,7 +553,7 @@ public: o << "Inorder PostDominator Tree: "; else o << "Inorder Dominator Tree: "; - if (this->DFSInfoValid) + if (!this->DFSInfoValid) o << "DFSNumbers invalid: " << SlowQueries << " slow queries."; o << "\n"; @@ -566,19 +563,11 @@ public: } protected: - template - friend void Compress(DominatorTreeBase& DT, - typename GraphT::NodeType* VIn); - template friend typename GraphT::NodeType* Eval( DominatorTreeBase& DT, - typename GraphT::NodeType* V); - - template - friend void Link(DominatorTreeBase& DT, - unsigned DFSNumV, typename GraphT::NodeType* W, - typename DominatorTreeBase::InfoRec &WInfo); + typename GraphT::NodeType* V, + unsigned LastLinked); template friend unsigned DFSPass(DominatorTreeBase& DT, @@ -703,6 +692,7 @@ public: DominatorTreeBase* DT; DominatorTree() : FunctionPass(ID) { + initializeDominatorTreePass(*PassRegistry::getPassRegistry()); DT = new DominatorTreeBase(false); } @@ -751,7 +741,7 @@ public: AU.setPreservesAll(); } - inline bool dominates(DomTreeNode* A, DomTreeNode* B) const { + inline bool dominates(const DomTreeNode* A, const DomTreeNode* B) const { return DT->dominates(A, B); } @@ -767,7 +757,7 @@ public: return DT->properlyDominates(A, B); } - bool properlyDominates(BasicBlock *A, BasicBlock *B) const { + bool properlyDominates(const BasicBlock *A, const BasicBlock *B) const { return DT->properlyDominates(A, B); } @@ -777,6 +767,11 @@ public: return DT->findNearestCommonDominator(A, B); } + inline const BasicBlock *findNearestCommonDominator(const BasicBlock *A, + const BasicBlock *B) { + return DT->findNearestCommonDominator(A, B); + } + inline DomTreeNode *operator[](BasicBlock *BB) const { return DT->getNode(BB); } @@ -807,7 +802,7 @@ public: } /// eraseNode - Removes a node from the dominator tree. Block must not - /// domiante any other blocks. Removes node from its immediate dominator's + /// dominate any other blocks. Removes node from its immediate dominator's /// children list. Deletes dominator node associated with basic block BB. inline void eraseNode(BasicBlock *BB) { DT->eraseNode(BB); @@ -819,7 +814,7 @@ public: DT->splitBlock(NewBB); } - bool isReachableFromEntry(BasicBlock* A) { + bool isReachableFromEntry(const BasicBlock* A) { return DT->isReachableFromEntry(A); } @@ -876,194 +871,6 @@ template <> struct GraphTraits }; -//===----------------------------------------------------------------------===// -/// DominanceFrontierBase - Common base class for computing forward and inverse -/// dominance frontiers for a function. -/// -class DominanceFrontierBase : public FunctionPass { -public: - typedef std::set DomSetType; // Dom set for a bb - typedef std::map DomSetMapType; // Dom set map -protected: - DomSetMapType Frontiers; - std::vector Roots; - const bool IsPostDominators; - -public: - DominanceFrontierBase(char &ID, bool isPostDom) - : FunctionPass(ID), IsPostDominators(isPostDom) {} - - /// getRoots - Return the root blocks of the current CFG. This may include - /// multiple blocks if we are computing post dominators. For forward - /// dominators, this will always be a single block (the entry node). - /// - inline const std::vector &getRoots() const { return Roots; } - - /// isPostDominator - Returns true if analysis based of postdoms - /// - bool isPostDominator() const { return IsPostDominators; } - - virtual void releaseMemory() { Frontiers.clear(); } - - // Accessor interface: - typedef DomSetMapType::iterator iterator; - typedef DomSetMapType::const_iterator const_iterator; - iterator begin() { return Frontiers.begin(); } - const_iterator begin() const { return Frontiers.begin(); } - iterator end() { return Frontiers.end(); } - const_iterator end() const { return Frontiers.end(); } - iterator find(BasicBlock *B) { return Frontiers.find(B); } - const_iterator find(BasicBlock *B) const { return Frontiers.find(B); } - - iterator addBasicBlock(BasicBlock *BB, const DomSetType &frontier) { - assert(find(BB) == end() && "Block already in DominanceFrontier!"); - return Frontiers.insert(std::make_pair(BB, frontier)).first; - } - - /// removeBlock - Remove basic block BB's frontier. - void removeBlock(BasicBlock *BB) { - assert(find(BB) != end() && "Block is not in DominanceFrontier!"); - for (iterator I = begin(), E = end(); I != E; ++I) - I->second.erase(BB); - Frontiers.erase(BB); - } - - void addToFrontier(iterator I, BasicBlock *Node) { - assert(I != end() && "BB is not in DominanceFrontier!"); - I->second.insert(Node); - } - - void removeFromFrontier(iterator I, BasicBlock *Node) { - assert(I != end() && "BB is not in DominanceFrontier!"); - assert(I->second.count(Node) && "Node is not in DominanceFrontier of BB"); - I->second.erase(Node); - } - - /// compareDomSet - Return false if two domsets match. Otherwise - /// return true; - bool compareDomSet(DomSetType &DS1, const DomSetType &DS2) const { - std::set tmpSet; - for (DomSetType::const_iterator I = DS2.begin(), - E = DS2.end(); I != E; ++I) - tmpSet.insert(*I); - - for (DomSetType::const_iterator I = DS1.begin(), - E = DS1.end(); I != E; ) { - BasicBlock *Node = *I++; - - if (tmpSet.erase(Node) == 0) - // Node is in DS1 but not in DS2. - return true; - } - - if (!tmpSet.empty()) - // There are nodes that are in DS2 but not in DS1. - return true; - - // DS1 and DS2 matches. - return false; - } - - /// compare - Return true if the other dominance frontier base matches - /// this dominance frontier base. Otherwise return false. - bool compare(DominanceFrontierBase &Other) const { - DomSetMapType tmpFrontiers; - for (DomSetMapType::const_iterator I = Other.begin(), - E = Other.end(); I != E; ++I) - tmpFrontiers.insert(std::make_pair(I->first, I->second)); - - for (DomSetMapType::iterator I = tmpFrontiers.begin(), - E = tmpFrontiers.end(); I != E; ) { - BasicBlock *Node = I->first; - const_iterator DFI = find(Node); - if (DFI == end()) - return true; - - if (compareDomSet(I->second, DFI->second)) - return true; - - ++I; - tmpFrontiers.erase(Node); - } - - if (!tmpFrontiers.empty()) - return true; - - return false; - } - - /// print - Convert to human readable form - /// - virtual void print(raw_ostream &OS, const Module* = 0) const; - - /// dump - Dump the dominance frontier to dbgs(). - void dump() const; -}; - - -//===------------------------------------- -/// DominanceFrontier Class - Concrete subclass of DominanceFrontierBase that is -/// used to compute a forward dominator frontiers. -/// -class DominanceFrontier : public DominanceFrontierBase { -public: - static char ID; // Pass ID, replacement for typeid - DominanceFrontier() : - DominanceFrontierBase(ID, false) {} - - BasicBlock *getRoot() const { - assert(Roots.size() == 1 && "Should always have entry node!"); - return Roots[0]; - } - - virtual bool runOnFunction(Function &) { - Frontiers.clear(); - DominatorTree &DT = getAnalysis(); - Roots = DT.getRoots(); - assert(Roots.size() == 1 && "Only one entry block for forward domfronts!"); - calculate(DT, DT[Roots[0]]); - return false; - } - - virtual void verifyAnalysis() const; - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesAll(); - AU.addRequired(); - } - - /// splitBlock - BB is split and now it has one successor. Update dominance - /// frontier to reflect this change. - void splitBlock(BasicBlock *BB); - - /// BasicBlock BB's new dominator is NewBB. Update BB's dominance frontier - /// to reflect this change. - void changeImmediateDominator(BasicBlock *BB, BasicBlock *NewBB, - DominatorTree *DT) { - // NewBB is now dominating BB. Which means BB's dominance - // frontier is now part of NewBB's dominance frontier. However, BB - // itself is not member of NewBB's dominance frontier. - DominanceFrontier::iterator NewDFI = find(NewBB); - DominanceFrontier::iterator DFI = find(BB); - // If BB was an entry block then its frontier is empty. - if (DFI == end()) - return; - DominanceFrontier::DomSetType BBSet = DFI->second; - for (DominanceFrontier::DomSetType::iterator BBSetI = BBSet.begin(), - BBSetE = BBSet.end(); BBSetI != BBSetE; ++BBSetI) { - BasicBlock *DFMember = *BBSetI; - // Insert only if NewBB dominates DFMember. - if (!DT->dominates(NewBB, DFMember)) - NewDFI->second.insert(DFMember); - } - NewDFI->second.erase(BB); - } - - const DomSetType &calculate(const DominatorTree &DT, - const DomTreeNode *Node); -}; - - } // End llvm namespace #endif diff --git a/include/llvm/Analysis/FindUsedTypes.h b/include/llvm/Analysis/FindUsedTypes.h index 8a78eb624973..fc57e1a04690 100644 --- a/include/llvm/Analysis/FindUsedTypes.h +++ b/include/llvm/Analysis/FindUsedTypes.h @@ -26,7 +26,9 @@ class FindUsedTypes : public ModulePass { std::set UsedTypes; public: static char ID; // Pass identification, replacement for typeid - FindUsedTypes() : ModulePass(ID) {} + FindUsedTypes() : ModulePass(ID) { + initializeFindUsedTypesPass(*PassRegistry::getPassRegistry()); + } /// getTypes - After the pass has been run, return the set containing all of /// the types used in the module. diff --git a/include/llvm/Analysis/InlineCost.h b/include/llvm/Analysis/InlineCost.h index 462bddd53307..b08bf57ace96 100644 --- a/include/llvm/Analysis/InlineCost.h +++ b/include/llvm/Analysis/InlineCost.h @@ -33,7 +33,7 @@ namespace llvm { namespace InlineConstants { // Various magic constants used to adjust heuristics. const int InstrCost = 5; - const int IndirectCallBonus = 500; + const int IndirectCallBonus = -100; const int CallPenalty = 25; const int LastCallToStaticBonus = -15000; const int ColdccPenalty = 2000; @@ -98,7 +98,8 @@ namespace llvm { unsigned AllocaWeight; ArgInfo(unsigned CWeight, unsigned AWeight) - : ConstantWeight(CWeight), AllocaWeight(AWeight) {} + : ConstantWeight(CWeight), AllocaWeight(AWeight) + {} }; struct FunctionInfo { @@ -110,17 +111,6 @@ namespace llvm { /// entry here. std::vector ArgumentWeights; - /// CountCodeReductionForConstant - Figure out an approximation for how - /// many instructions will be constant folded if the specified value is - /// constant. - unsigned CountCodeReductionForConstant(Value *V); - - /// CountCodeReductionForAlloca - Figure out an approximation of how much - /// smaller the function will be if it is inlined into a context where an - /// argument becomes an alloca. - /// - unsigned CountCodeReductionForAlloca(Value *V); - /// analyzeFunction - Add information about the specified function /// to the current structure. void analyzeFunction(Function *F); @@ -134,6 +124,10 @@ namespace llvm { // the ValueMap will update itself when this happens. ValueMap CachedFunctionInfo; + int CountBonusForConstant(Value *V, Constant *C = NULL); + int ConstantFunctionBonus(CallSite CS, Constant *C); + int getInlineSize(CallSite CS, Function *Callee); + int getInlineBonuses(CallSite CS, Function *Callee); public: /// getInlineCost - The heuristic used to determine if we should inline the @@ -150,6 +144,18 @@ namespace llvm { Function *Callee, SmallPtrSet &NeverInline); + /// getSpecializationBonus - The heuristic used to determine the per-call + /// performance boost for using a specialization of Callee with argument + /// SpecializedArgNos replaced by a constant. + int getSpecializationBonus(Function *Callee, + SmallVectorImpl &SpecializedArgNo); + + /// getSpecializationCost - The heuristic used to determine the code-size + /// impact of creating a specialized version of Callee with argument + /// SpecializedArgNo replaced by a constant. + InlineCost getSpecializationCost(Function *Callee, + SmallVectorImpl &SpecializedArgNo); + /// getInlineFudgeFactor - Return a > 1.0 factor if the inliner should use a /// higher threshold to determine if the function call should be inlined. float getInlineFudgeFactor(CallSite CS); diff --git a/include/llvm/Analysis/InstructionSimplify.h b/include/llvm/Analysis/InstructionSimplify.h index f47e740a741f..dff1ba2f7beb 100644 --- a/include/llvm/Analysis/InstructionSimplify.h +++ b/include/llvm/Analysis/InstructionSimplify.h @@ -7,9 +7,12 @@ // //===----------------------------------------------------------------------===// // -// This file declares routines for folding instructions into simpler forms that -// do not require creating new instructions. For example, this does constant -// folding, and can handle identities like (X&0)->0. +// This file declares routines for folding instructions into simpler forms +// that do not require creating new instructions. This does constant folding +// ("add i32 1, 1" -> "2") but can also handle non-constant operands, either +// returning a constant ("and i32 %x, 0" -> "0") or an already existing value +// ("and i32 %x, %x" -> "%x"). If the simplification is also an instruction +// then it dominates the original instruction. // //===----------------------------------------------------------------------===// @@ -17,6 +20,7 @@ #define LLVM_ANALYSIS_INSTRUCTIONSIMPLIFY_H namespace llvm { + class DominatorTree; class Instruction; class Value; class TargetData; @@ -24,56 +28,106 @@ namespace llvm { /// SimplifyAddInst - Given operands for an Add, see if we can /// fold the result. If not, this returns null. Value *SimplifyAddInst(Value *LHS, Value *RHS, bool isNSW, bool isNUW, - const TargetData *TD = 0); - + const TargetData *TD = 0, const DominatorTree *DT = 0); + + /// SimplifySubInst - Given operands for a Sub, see if we can + /// fold the result. If not, this returns null. + Value *SimplifySubInst(Value *LHS, Value *RHS, bool isNSW, bool isNUW, + const TargetData *TD = 0, const DominatorTree *DT = 0); + + /// SimplifyMulInst - Given operands for a Mul, see if we can + /// fold the result. If not, this returns null. + Value *SimplifyMulInst(Value *LHS, Value *RHS, const TargetData *TD = 0, + const DominatorTree *DT = 0); + + /// SimplifySDivInst - Given operands for an SDiv, see if we can + /// fold the result. If not, this returns null. + Value *SimplifySDivInst(Value *LHS, Value *RHS, const TargetData *TD = 0, + const DominatorTree *DT = 0); + + /// SimplifyUDivInst - Given operands for a UDiv, see if we can + /// fold the result. If not, this returns null. + Value *SimplifyUDivInst(Value *LHS, Value *RHS, const TargetData *TD = 0, + const DominatorTree *DT = 0); + + /// SimplifyFDivInst - Given operands for an FDiv, see if we can + /// fold the result. If not, this returns null. + Value *SimplifyFDivInst(Value *LHS, Value *RHS, const TargetData *TD = 0, + const DominatorTree *DT = 0); + + /// SimplifyShlInst - Given operands for a Shl, see if we can + /// fold the result. If not, this returns null. + Value *SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW, + const TargetData *TD = 0, const DominatorTree *DT = 0); + + /// SimplifyLShrInst - Given operands for a LShr, see if we can + /// fold the result. If not, this returns null. + Value *SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact, + const TargetData *TD = 0, const DominatorTree *DT=0); + + /// SimplifyAShrInst - Given operands for a AShr, see if we can + /// fold the result. If not, this returns null. + Value *SimplifyAShrInst(Value *Op0, Value *Op1, bool isExact, + const TargetData *TD = 0, + const DominatorTree *DT = 0); + /// SimplifyAndInst - Given operands for an And, see if we can /// fold the result. If not, this returns null. - Value *SimplifyAndInst(Value *LHS, Value *RHS, - const TargetData *TD = 0); + Value *SimplifyAndInst(Value *LHS, Value *RHS, const TargetData *TD = 0, + const DominatorTree *DT = 0); /// SimplifyOrInst - Given operands for an Or, see if we can /// fold the result. If not, this returns null. - Value *SimplifyOrInst(Value *LHS, Value *RHS, - const TargetData *TD = 0); - + Value *SimplifyOrInst(Value *LHS, Value *RHS, const TargetData *TD = 0, + const DominatorTree *DT = 0); + + /// SimplifyXorInst - Given operands for a Xor, see if we can + /// fold the result. If not, this returns null. + Value *SimplifyXorInst(Value *LHS, Value *RHS, const TargetData *TD = 0, + const DominatorTree *DT = 0); + /// SimplifyICmpInst - Given operands for an ICmpInst, see if we can /// fold the result. If not, this returns null. Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS, - const TargetData *TD = 0); - + const TargetData *TD = 0, + const DominatorTree *DT = 0); + /// SimplifyFCmpInst - Given operands for an FCmpInst, see if we can /// fold the result. If not, this returns null. Value *SimplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS, - const TargetData *TD = 0); - + const TargetData *TD = 0, + const DominatorTree *DT = 0); + /// SimplifySelectInst - Given operands for a SelectInst, see if we can fold /// the result. If not, this returns null. Value *SimplifySelectInst(Value *Cond, Value *TrueVal, Value *FalseVal, - const TargetData *TD = 0); + const TargetData *TD = 0, + const DominatorTree *DT = 0); /// SimplifyGEPInst - Given operands for an GetElementPtrInst, see if we can /// fold the result. If not, this returns null. Value *SimplifyGEPInst(Value * const *Ops, unsigned NumOps, - const TargetData *TD = 0); - + const TargetData *TD = 0, const DominatorTree *DT = 0); + //=== Helper functions for higher up the class hierarchy. - - + + /// SimplifyCmpInst - Given operands for a CmpInst, see if we can /// fold the result. If not, this returns null. Value *SimplifyCmpInst(unsigned Predicate, Value *LHS, Value *RHS, - const TargetData *TD = 0); - + const TargetData *TD = 0, const DominatorTree *DT = 0); + /// SimplifyBinOp - Given operands for a BinaryOperator, see if we can /// fold the result. If not, this returns null. - Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS, - const TargetData *TD = 0); - + Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS, + const TargetData *TD = 0, const DominatorTree *DT = 0); + /// SimplifyInstruction - See if we can compute a simplified version of this /// instruction. If not, this returns null. - Value *SimplifyInstruction(Instruction *I, const TargetData *TD = 0); - - + Value *SimplifyInstruction(Instruction *I, const TargetData *TD = 0, + const DominatorTree *DT = 0); + + /// ReplaceAndSimplifyAllUses - Perform From->replaceAllUsesWith(To) and then /// delete the From instruction. In addition to a basic RAUW, this does a /// recursive simplification of the updated instructions. This catches @@ -81,7 +135,8 @@ namespace llvm { /// simplifies and deletes scalar operations, it does not change the CFG. /// void ReplaceAndSimplifyAllUses(Instruction *From, Value *To, - const TargetData *TD = 0); + const TargetData *TD = 0, + const DominatorTree *DT = 0); } // end namespace llvm #endif diff --git a/include/llvm/Analysis/IntervalPartition.h b/include/llvm/Analysis/IntervalPartition.h index 75a5cdf1f99d..df7313f18f3d 100644 --- a/include/llvm/Analysis/IntervalPartition.h +++ b/include/llvm/Analysis/IntervalPartition.h @@ -48,7 +48,9 @@ class IntervalPartition : public FunctionPass { public: static char ID; // Pass identification, replacement for typeid - IntervalPartition() : FunctionPass(ID), RootInterval(0) {} + IntervalPartition() : FunctionPass(ID), RootInterval(0) { + initializeIntervalPartitionPass(*PassRegistry::getPassRegistry()); + } // run - Calculate the interval partition for this function virtual bool runOnFunction(Function &F); diff --git a/include/llvm/Analysis/LazyValueInfo.h b/include/llvm/Analysis/LazyValueInfo.h index b2a3afbc986a..fc4d0af920e9 100644 --- a/include/llvm/Analysis/LazyValueInfo.h +++ b/include/llvm/Analysis/LazyValueInfo.h @@ -31,7 +31,9 @@ class LazyValueInfo : public FunctionPass { void operator=(const LazyValueInfo&); // DO NOT IMPLEMENT. public: static char ID; - LazyValueInfo() : FunctionPass(ID), PImpl(0) {} + LazyValueInfo() : FunctionPass(ID), PImpl(0) { + initializeLazyValueInfoPass(*PassRegistry::getPassRegistry()); + } ~LazyValueInfo() { assert(PImpl == 0 && "releaseMemory not called"); } /// Tristate - This is used to return true/false/dunno results. diff --git a/include/llvm/Analysis/LibCallAliasAnalysis.h b/include/llvm/Analysis/LibCallAliasAnalysis.h index c9adf3f36ad7..243234b75635 100644 --- a/include/llvm/Analysis/LibCallAliasAnalysis.h +++ b/include/llvm/Analysis/LibCallAliasAnalysis.h @@ -28,15 +28,17 @@ namespace llvm { LibCallInfo *LCI; explicit LibCallAliasAnalysis(LibCallInfo *LC = 0) - : FunctionPass(ID), LCI(LC) { + : FunctionPass(ID), LCI(LC) { + initializeLibCallAliasAnalysisPass(*PassRegistry::getPassRegistry()); } explicit LibCallAliasAnalysis(char &ID, LibCallInfo *LC) - : FunctionPass(ID), LCI(LC) { + : FunctionPass(ID), LCI(LC) { + initializeLibCallAliasAnalysisPass(*PassRegistry::getPassRegistry()); } ~LibCallAliasAnalysis(); ModRefResult getModRefInfo(ImmutableCallSite CS, - const Value *P, unsigned Size); + const Location &Loc); ModRefResult getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2) { @@ -64,7 +66,7 @@ namespace llvm { private: ModRefResult AnalyzeLibCallDetails(const LibCallFunctionInfo *FI, ImmutableCallSite CS, - const Value *P, unsigned Size); + const Location &Loc); }; } // End of llvm namespace diff --git a/include/llvm/Analysis/LibCallSemantics.h b/include/llvm/Analysis/LibCallSemantics.h index 31d7cc56ce53..f5a9e96cbdd0 100644 --- a/include/llvm/Analysis/LibCallSemantics.h +++ b/include/llvm/Analysis/LibCallSemantics.h @@ -48,7 +48,7 @@ namespace llvm { Yes, No, Unknown }; LocResult (*isLocation)(ImmutableCallSite CS, - const Value *Ptr, unsigned Size); + const AliasAnalysis::Location &Loc); }; /// LibCallFunctionInfo - Each record in the array of FunctionInfo structs diff --git a/include/llvm/Analysis/LoopDependenceAnalysis.h b/include/llvm/Analysis/LoopDependenceAnalysis.h index 94fd9907090d..f195d2782418 100644 --- a/include/llvm/Analysis/LoopDependenceAnalysis.h +++ b/include/llvm/Analysis/LoopDependenceAnalysis.h @@ -91,7 +91,9 @@ class LoopDependenceAnalysis : public LoopPass { public: static char ID; // Class identification, replacement for typeinfo - LoopDependenceAnalysis() : LoopPass(ID) {} + LoopDependenceAnalysis() : LoopPass(ID) { + initializeLoopDependenceAnalysisPass(*PassRegistry::getPassRegistry()); + } /// isDependencePair - Check whether two values can possibly give rise to /// a data dependence: that is the case if both are instructions accessing diff --git a/include/llvm/Analysis/LoopInfo.h b/include/llvm/Analysis/LoopInfo.h index 462620f7e3cb..392bdad5ab02 100644 --- a/include/llvm/Analysis/LoopInfo.h +++ b/include/llvm/Analysis/LoopInfo.h @@ -32,6 +32,7 @@ #define LLVM_ANALYSIS_LOOP_INFO_H #include "llvm/Pass.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/SmallVector.h" @@ -40,6 +41,7 @@ #include "llvm/Support/CFG.h" #include "llvm/Support/raw_ostream.h" #include +#include namespace llvm { @@ -53,6 +55,7 @@ static void RemoveFromVector(std::vector &V, T *N) { class DominatorTree; class LoopInfo; class Loop; +class PHINode; template class LoopInfoBase; template class LoopBase; @@ -523,10 +526,9 @@ public: /// bool isLoopInvariant(Value *V) const; - /// isLoopInvariant - Return true if the specified instruction is - /// loop-invariant. - /// - bool isLoopInvariant(Instruction *I) const; + /// hasLoopInvariantOperands - Return true if all the operands of the + /// specified instruction are loop invariant. + bool hasLoopInvariantOperands(Instruction *I) const; /// makeLoopInvariant - If the given value is an instruction inside of the /// loop and it can be hoisted, do so to make it trivially loop-invariant. @@ -630,7 +632,7 @@ private: template class LoopInfoBase { // BBMap - Mapping of basic blocks to the inner most loop they occur in - std::map BBMap; + DenseMap BBMap; std::vector TopLevelLoops; friend class LoopBase; @@ -661,7 +663,7 @@ public: /// block is in no loop (for example the entry node), null is returned. /// LoopT *getLoopFor(const BlockT *BB) const { - typename std::map::const_iterator I= + typename DenseMap::const_iterator I= BBMap.find(const_cast(BB)); return I != BBMap.end() ? I->second : 0; } @@ -729,7 +731,7 @@ public: /// including all of the Loop objects it is nested in and our mapping from /// BasicBlocks to loops. void removeBlock(BlockT *BB) { - typename std::map::iterator I = BBMap.find(BB); + typename DenseMap::iterator I = BBMap.find(BB); if (I != BBMap.end()) { for (LoopT *L = I->second; L; L = L->getParentLoop()) L->removeBlockFromLoop(BB); @@ -923,7 +925,7 @@ public: for (unsigned i = 0; i < TopLevelLoops.size(); ++i) TopLevelLoops[i]->print(OS); #if 0 - for (std::map::const_iterator I = BBMap.begin(), + for (DenseMap::const_iterator I = BBMap.begin(), E = BBMap.end(); I != E; ++I) OS << "BB '" << I->first->getName() << "' level = " << I->second->getLoopDepth() << "\n"; @@ -940,7 +942,9 @@ class LoopInfo : public FunctionPass { public: static char ID; // Pass identification, replacement for typeid - LoopInfo() : FunctionPass(ID) {} + LoopInfo() : FunctionPass(ID) { + initializeLoopInfoPass(*PassRegistry::getPassRegistry()); + } LoopInfoBase& getBase() { return LI; } @@ -1019,6 +1023,27 @@ public: void removeBlock(BasicBlock *BB) { LI.removeBlock(BB); } + + /// replacementPreservesLCSSAForm - Returns true if replacing From with To + /// everywhere is guaranteed to preserve LCSSA form. + bool replacementPreservesLCSSAForm(Instruction *From, Value *To) { + // Preserving LCSSA form is only problematic if the replacing value is an + // instruction. + Instruction *I = dyn_cast(To); + if (!I) return true; + // If both instructions are defined in the same basic block then replacement + // cannot break LCSSA form. + if (I->getParent() == From->getParent()) + return true; + // If the instruction is not defined in a loop then it can safely replace + // anything. + Loop *ToLoop = getLoopFor(I->getParent()); + if (!ToLoop) return true; + // If the replacing instruction is defined in the same loop as the original + // instruction, or in a loop that contains it as an inner loop, then using + // it as a replacement will not break LCSSA form. + return ToLoop->contains(getLoopFor(From->getParent())); + } }; diff --git a/include/llvm/Analysis/MemoryBuiltins.h b/include/llvm/Analysis/MemoryBuiltins.h index a4f916227b8b..22493f6f8b9e 100644 --- a/include/llvm/Analysis/MemoryBuiltins.h +++ b/include/llvm/Analysis/MemoryBuiltins.h @@ -74,6 +74,10 @@ Value *getMallocArraySize(CallInst *CI, const TargetData *TD, /// isFreeCall - Returns non-null if the value is a call to the builtin free() const CallInst *isFreeCall(const Value *I); + +static inline CallInst *isFreeCall(Value *I) { + return const_cast(isFreeCall((const Value*)I)); +} } // End llvm namespace diff --git a/include/llvm/Analysis/MemoryDependenceAnalysis.h b/include/llvm/Analysis/MemoryDependenceAnalysis.h index f6aab03690ff..4d5dd1987f28 100644 --- a/include/llvm/Analysis/MemoryDependenceAnalysis.h +++ b/include/llvm/Analysis/MemoryDependenceAnalysis.h @@ -17,6 +17,7 @@ #include "llvm/BasicBlock.h" #include "llvm/Pass.h" #include "llvm/Support/ValueHandle.h" +#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/OwningPtr.h" @@ -46,6 +47,9 @@ namespace llvm { /// pair holds the instruction that clobbers the memory. For example, /// this occurs when we see a may-aliased store to the memory location we /// care about. + /// + /// A dependence query on the first instruction of the entry block will + /// return a clobber(self) result. Clobber, /// Def - This is a dependence on the specified instruction which @@ -132,26 +136,49 @@ namespace llvm { } }; + /// NonLocalDepEntry - This is an entry in the NonLocalDepInfo cache. For + /// each BasicBlock (the BB entry) it keeps a MemDepResult. + class NonLocalDepEntry { + BasicBlock *BB; + MemDepResult Result; + public: + NonLocalDepEntry(BasicBlock *bb, MemDepResult result) + : BB(bb), Result(result) {} + + // This is used for searches. + NonLocalDepEntry(BasicBlock *bb) : BB(bb) {} + + // BB is the sort key, it can't be changed. + BasicBlock *getBB() const { return BB; } + + void setResult(const MemDepResult &R) { Result = R; } + + const MemDepResult &getResult() const { return Result; } + + bool operator<(const NonLocalDepEntry &RHS) const { + return BB < RHS.BB; + } + }; + /// NonLocalDepResult - This is a result from a NonLocal dependence query. /// For each BasicBlock (the BB entry) it keeps a MemDepResult and the /// (potentially phi translated) address that was live in the block. class NonLocalDepResult { - BasicBlock *BB; - MemDepResult Result; + NonLocalDepEntry Entry; Value *Address; public: NonLocalDepResult(BasicBlock *bb, MemDepResult result, Value *address) - : BB(bb), Result(result), Address(address) {} + : Entry(bb, result), Address(address) {} // BB is the sort key, it can't be changed. - BasicBlock *getBB() const { return BB; } + BasicBlock *getBB() const { return Entry.getBB(); } void setResult(const MemDepResult &R, Value *Addr) { - Result = R; + Entry.setResult(R); Address = Addr; } - const MemDepResult &getResult() const { return Result; } + const MemDepResult &getResult() const { return Entry.getResult(); } /// getAddress - Return the address of this pointer in this block. This can /// be different than the address queried for the non-local result because @@ -163,30 +190,6 @@ namespace llvm { Value *getAddress() const { return Address; } }; - /// NonLocalDepEntry - This is an entry in the NonLocalDepInfo cache. For - /// each BasicBlock (the BB entry) it keeps a MemDepResult. - class NonLocalDepEntry { - BasicBlock *BB; - MemDepResult Result; - public: - NonLocalDepEntry(BasicBlock *bb, MemDepResult result) - : BB(bb), Result(result) {} - - // This is used for searches. - NonLocalDepEntry(BasicBlock *bb) : BB(bb) {} - - // BB is the sort key, it can't be changed. - BasicBlock *getBB() const { return BB; } - - void setResult(const MemDepResult &R) { Result = R; } - - const MemDepResult &getResult() const { return Result; } - - bool operator<(const NonLocalDepEntry &RHS) const { - return BB < RHS.BB; - } - }; - /// MemoryDependenceAnalysis - This is an analysis that determines, for a /// given memory operation, what preceding memory operations it depends on. /// It builds on alias analysis information, and tries to provide a lazy, @@ -212,7 +215,7 @@ namespace llvm { private: /// ValueIsLoadPair - This is a pair where the bool is true if /// the dependence is a read only dependence, false if read/write. - typedef PointerIntPair ValueIsLoadPair; + typedef PointerIntPair ValueIsLoadPair; /// BBSkipFirstBlockPair - This pair is used when caching information for a /// block. If the pointer is null, the cache value is not a full query that @@ -220,11 +223,28 @@ namespace llvm { /// or not the contents of the block was skipped. typedef PointerIntPair BBSkipFirstBlockPair; + /// NonLocalPointerInfo - This record is the information kept for each + /// (value, is load) pair. + struct NonLocalPointerInfo { + /// Pair - The pair of the block and the skip-first-block flag. + BBSkipFirstBlockPair Pair; + /// NonLocalDeps - The results of the query for each relevant block. + NonLocalDepInfo NonLocalDeps; + /// Size - The maximum size of the dereferences of the + /// pointer. May be UnknownSize if the sizes are unknown. + uint64_t Size; + /// TBAATag - The TBAA tag associated with dereferences of the + /// pointer. May be null if there are no tags or conflicting tags. + const MDNode *TBAATag; + + NonLocalPointerInfo() : Size(AliasAnalysis::UnknownSize), TBAATag(0) {} + }; + /// CachedNonLocalPointerInfo - This map stores the cached results of doing /// a pointer lookup at the bottom of a block. The key of this map is the /// pointer+isload bit, the value is a list of result> mappings. - typedef DenseMap > CachedNonLocalPointerInfo; + typedef DenseMap CachedNonLocalPointerInfo; CachedNonLocalPointerInfo NonLocalPointerDeps; // A map from instructions to their non-local pointer dependencies. @@ -297,10 +317,10 @@ namespace llvm { /// set of instructions that either define or clobber the value. /// /// This method assumes the pointer has a "NonLocal" dependency within BB. - void getNonLocalPointerDependency(Value *Pointer, bool isLoad, - BasicBlock *BB, + void getNonLocalPointerDependency(const AliasAnalysis::Location &Loc, + bool isLoad, BasicBlock *BB, SmallVectorImpl &Result); - + /// removeInstruction - Remove an instruction from the dependence analysis, /// updating the dependence of instructions that previously depended on it. void removeInstruction(Instruction *InstToRemove); @@ -318,20 +338,29 @@ namespace llvm { /// critical edges. void invalidateCachedPredecessors(); - private: - MemDepResult getPointerDependencyFrom(Value *Pointer, uint64_t MemSize, + /// getPointerDependencyFrom - Return the instruction on which a memory + /// location depends. If isLoad is true, this routine ignores may-aliases + /// with read-only operations. If isLoad is false, this routine ignores + /// may-aliases with reads from read-only locations. + /// + /// Note that this is an uncached query, and thus may be inefficient. + /// + MemDepResult getPointerDependencyFrom(const AliasAnalysis::Location &Loc, bool isLoad, BasicBlock::iterator ScanIt, BasicBlock *BB); + + private: MemDepResult getCallSiteDependencyFrom(CallSite C, bool isReadOnlyCall, BasicBlock::iterator ScanIt, BasicBlock *BB); - bool getNonLocalPointerDepFromBB(const PHITransAddr &Pointer, uint64_t Size, + bool getNonLocalPointerDepFromBB(const PHITransAddr &Pointer, + const AliasAnalysis::Location &Loc, bool isLoad, BasicBlock *BB, SmallVectorImpl &Result, DenseMap &Visited, bool SkipFirstBlock = false); - MemDepResult GetNonLocalInfoForBlock(Value *Pointer, uint64_t PointeeSize, + MemDepResult GetNonLocalInfoForBlock(const AliasAnalysis::Location &Loc, bool isLoad, BasicBlock *BB, NonLocalDepInfo *Cache, unsigned NumSortedEntries); diff --git a/include/llvm/Analysis/Passes.h b/include/llvm/Analysis/Passes.h index 37425ebe8358..5b0c5b1e6bec 100644 --- a/include/llvm/Analysis/Passes.h +++ b/include/llvm/Analysis/Passes.h @@ -59,7 +59,7 @@ namespace llvm { //===--------------------------------------------------------------------===// // - // createBasicAliasAnalysisPass - This pass implements the default alias + // createBasicAliasAnalysisPass - This pass implements the stateless alias // analysis. // ImmutablePass *createBasicAliasAnalysisPass(); @@ -114,6 +114,28 @@ namespace llvm { // FunctionPass *createProfileVerifierPass(); + //===--------------------------------------------------------------------===// + // + // createPathProfileLoaderPass - This pass loads information from a path + // profile dump file. + // + ModulePass *createPathProfileLoaderPass(); + extern char &PathProfileLoaderPassID; + + //===--------------------------------------------------------------------===// + // + // createNoPathProfileInfoPass - This pass implements the default + // "no path profile". + // + ImmutablePass *createNoPathProfileInfoPass(); + + //===--------------------------------------------------------------------===// + // + // createPathProfileVerifierPass - This pass verifies path profiling + // information. + // + ModulePass *createPathProfileVerifierPass(); + //===--------------------------------------------------------------------===// // // createDSAAPass - This pass implements simple context sensitive alias @@ -140,7 +162,7 @@ namespace llvm { // createLiveValuesPass - This creates an instance of the LiveValues pass. // FunctionPass *createLiveValuesPass(); - + //===--------------------------------------------------------------------===// // /// createLazyValueInfoPass - This creates an instance of the LazyValueInfo @@ -153,7 +175,7 @@ namespace llvm { // LoopDependenceAnalysis pass. // LoopPass *createLoopDependenceAnalysisPass(); - + // Minor pass prototypes, allowing us to expose them through bugpoint and // analyze. FunctionPass *createInstCountPass(); @@ -170,6 +192,13 @@ namespace llvm { // Print module-level debug info metadata in human-readable form. ModulePass *createModuleDebugInfoPrinterPass(); + + //===--------------------------------------------------------------------===// + // + // createMemDepPrinter - This pass exhaustively collects all memdep + // information and prints it with -analyze. + // + FunctionPass *createMemDepPrinter(); } #endif diff --git a/include/llvm/Analysis/PathNumbering.h b/include/llvm/Analysis/PathNumbering.h new file mode 100644 index 000000000000..7025e28484cc --- /dev/null +++ b/include/llvm/Analysis/PathNumbering.h @@ -0,0 +1,304 @@ +//===- PathNumbering.h ----------------------------------------*- C++ -*---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Ball-Larus path numbers uniquely identify paths through a directed acyclic +// graph (DAG) [Ball96]. For a CFG backedges are removed and replaced by phony +// edges to obtain a DAG, and thus the unique path numbers [Ball96]. +// +// The purpose of this analysis is to enumerate the edges in a CFG in order +// to obtain paths from path numbers in a convenient manner. As described in +// [Ball96] edges can be enumerated such that given a path number by following +// the CFG and updating the path number, the path is obtained. +// +// [Ball96] +// T. Ball and J. R. Larus. "Efficient Path Profiling." +// International Symposium on Microarchitecture, pages 46-57, 1996. +// http://portal.acm.org/citation.cfm?id=243857 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_PATH_NUMBERING_H +#define LLVM_PATH_NUMBERING_H + +#include "llvm/BasicBlock.h" +#include "llvm/Instructions.h" +#include "llvm/Pass.h" +#include "llvm/Support/CFG.h" +#include "llvm/Analysis/ProfileInfoTypes.h" +#include +#include +#include + +namespace llvm { +class BallLarusNode; +class BallLarusEdge; +class BallLarusDag; + +// typedefs for storage/ interators of various DAG components +typedef std::vector BLNodeVector; +typedef std::vector::iterator BLNodeIterator; +typedef std::vector BLEdgeVector; +typedef std::vector::iterator BLEdgeIterator; +typedef std::map BLBlockNodeMap; +typedef std::stack BLNodeStack; + +// Represents a basic block with information necessary for the BallLarus +// algorithms. +class BallLarusNode { +public: + enum NodeColor { WHITE, GRAY, BLACK }; + + // Constructor: Initializes a new Node for the given BasicBlock + BallLarusNode(BasicBlock* BB) : + _basicBlock(BB), _numberPaths(0), _color(WHITE) { + static unsigned nextUID = 0; + _uid = nextUID++; + } + + // Returns the basic block for the BallLarusNode + BasicBlock* getBlock(); + + // Get/set the number of paths to the exit starting at the node. + unsigned getNumberPaths(); + void setNumberPaths(unsigned numberPaths); + + // Get/set the NodeColor used in graph algorithms. + NodeColor getColor(); + void setColor(NodeColor color); + + // Iterator information for predecessor edges. Includes phony and + // backedges. + BLEdgeIterator predBegin(); + BLEdgeIterator predEnd(); + unsigned getNumberPredEdges(); + + // Iterator information for successor edges. Includes phony and + // backedges. + BLEdgeIterator succBegin(); + BLEdgeIterator succEnd(); + unsigned getNumberSuccEdges(); + + // Add an edge to the predecessor list. + void addPredEdge(BallLarusEdge* edge); + + // Remove an edge from the predecessor list. + void removePredEdge(BallLarusEdge* edge); + + // Add an edge to the successor list. + void addSuccEdge(BallLarusEdge* edge); + + // Remove an edge from the successor list. + void removeSuccEdge(BallLarusEdge* edge); + + // Returns the name of the BasicBlock being represented. If BasicBlock + // is null then returns "". If BasicBlock has no name, then + // "" is returned. Intended for use with debug output. + std::string getName(); + +private: + // The corresponding underlying BB. + BasicBlock* _basicBlock; + + // Holds the predecessor edges of this node. + BLEdgeVector _predEdges; + + // Holds the successor edges of this node. + BLEdgeVector _succEdges; + + // The number of paths from the node to the exit. + unsigned _numberPaths; + + // 'Color' used by graph algorithms to mark the node. + NodeColor _color; + + // Unique ID to ensure naming difference with dotgraphs + unsigned _uid; + + // Removes an edge from an edgeVector. Used by removePredEdge and + // removeSuccEdge. + void removeEdge(BLEdgeVector& v, BallLarusEdge* e); +}; + +// Represents an edge in the Dag. For an edge, v -> w, v is the source, and +// w is the target. +class BallLarusEdge { +public: + enum EdgeType { NORMAL, BACKEDGE, SPLITEDGE, + BACKEDGE_PHONY, SPLITEDGE_PHONY, CALLEDGE_PHONY }; + + // Constructor: Initializes an BallLarusEdge with a source and target. + BallLarusEdge(BallLarusNode* source, BallLarusNode* target, + unsigned duplicateNumber) + : _source(source), _target(target), _weight(0), _edgeType(NORMAL), + _realEdge(NULL), _duplicateNumber(duplicateNumber) {} + + // Returns the source/ target node of this edge. + BallLarusNode* getSource() const; + BallLarusNode* getTarget() const; + + // Sets the type of the edge. + EdgeType getType() const; + + // Gets the type of the edge. + void setType(EdgeType type); + + // Returns the weight of this edge. Used to decode path numbers to + // sequences of basic blocks. + unsigned getWeight(); + + // Sets the weight of the edge. Used during path numbering. + void setWeight(unsigned weight); + + // Gets/sets the phony edge originating at the root. + BallLarusEdge* getPhonyRoot(); + void setPhonyRoot(BallLarusEdge* phonyRoot); + + // Gets/sets the phony edge terminating at the exit. + BallLarusEdge* getPhonyExit(); + void setPhonyExit(BallLarusEdge* phonyExit); + + // Gets/sets the associated real edge if this is a phony edge. + BallLarusEdge* getRealEdge(); + void setRealEdge(BallLarusEdge* realEdge); + + // Returns the duplicate number of the edge. + unsigned getDuplicateNumber(); + +protected: + // Source node for this edge. + BallLarusNode* _source; + + // Target node for this edge. + BallLarusNode* _target; + +private: + // Edge weight cooresponding to path number increments before removing + // increments along a spanning tree. The sum over the edge weights gives + // the path number. + unsigned _weight; + + // Type to represent for what this edge is intended + EdgeType _edgeType; + + // For backedges and split-edges, the phony edge which is linked to the + // root node of the DAG. This contains a path number initialization. + BallLarusEdge* _phonyRoot; + + // For backedges and split-edges, the phony edge which is linked to the + // exit node of the DAG. This contains a path counter increment, and + // potentially a path number increment. + BallLarusEdge* _phonyExit; + + // If this is a phony edge, _realEdge is a link to the back or split + // edge. Otherwise, this is null. + BallLarusEdge* _realEdge; + + // An ID to differentiate between those edges which have the same source + // and destination blocks. + unsigned _duplicateNumber; +}; + +// Represents the Ball Larus DAG for a given Function. Can calculate +// various properties required for instrumentation or analysis. E.g. the +// edge weights that determine the path number. +class BallLarusDag { +public: + // Initializes a BallLarusDag from the CFG of a given function. Must + // call init() after creation, since some initialization requires + // virtual functions. + BallLarusDag(Function &F) + : _root(NULL), _exit(NULL), _function(F) {} + + // Initialization that requires virtual functions which are not fully + // functional in the constructor. + void init(); + + // Frees all memory associated with the DAG. + virtual ~BallLarusDag(); + + // Calculate the path numbers by assigning edge increments as prescribed + // in Ball-Larus path profiling. + void calculatePathNumbers(); + + // Returns the number of paths for the DAG. + unsigned getNumberOfPaths(); + + // Returns the root (i.e. entry) node for the DAG. + BallLarusNode* getRoot(); + + // Returns the exit node for the DAG. + BallLarusNode* getExit(); + + // Returns the function for the DAG. + Function& getFunction(); + + // Clears the node colors. + void clearColors(BallLarusNode::NodeColor color); + +protected: + // All nodes in the DAG. + BLNodeVector _nodes; + + // All edges in the DAG. + BLEdgeVector _edges; + + // All backedges in the DAG. + BLEdgeVector _backEdges; + + // Allows subclasses to determine which type of Node is created. + // Override this method to produce subclasses of BallLarusNode if + // necessary. The destructor of BallLarusDag will call free on each pointer + // created. + virtual BallLarusNode* createNode(BasicBlock* BB); + + // Allows subclasses to determine which type of Edge is created. + // Override this method to produce subclasses of BallLarusEdge if + // necessary. Parameters source and target will have been created by + // createNode and can be cast to the subclass of BallLarusNode* + // returned by createNode. The destructor of BallLarusDag will call free + // on each pointer created. + virtual BallLarusEdge* createEdge(BallLarusNode* source, BallLarusNode* + target, unsigned duplicateNumber); + + // Proxy to node's constructor. Updates the DAG state. + BallLarusNode* addNode(BasicBlock* BB); + + // Proxy to edge's constructor. Updates the DAG state. + BallLarusEdge* addEdge(BallLarusNode* source, BallLarusNode* target, + unsigned duplicateNumber); + +private: + // The root (i.e. entry) node for this DAG. + BallLarusNode* _root; + + // The exit node for this DAG. + BallLarusNode* _exit; + + // The function represented by this DAG. + Function& _function; + + // Processes one node and its imediate edges for building the DAG. + void buildNode(BLBlockNodeMap& inDag, std::stack& dfsStack); + + // Process an edge in the CFG for DAG building. + void buildEdge(BLBlockNodeMap& inDag, std::stack& dfsStack, + BallLarusNode* currentNode, BasicBlock* succBB, + unsigned duplicateNumber); + + // The weight on each edge is the increment required along any path that + // contains that edge. + void calculatePathNumbersFrom(BallLarusNode* node); + + // Adds a backedge with its phony edges. Updates the DAG state. + void addBackedge(BallLarusNode* source, BallLarusNode* target, + unsigned duplicateCount); +}; +} // end namespace llvm + +#endif diff --git a/include/llvm/Analysis/PathProfileInfo.h b/include/llvm/Analysis/PathProfileInfo.h new file mode 100644 index 000000000000..263763f7a8db --- /dev/null +++ b/include/llvm/Analysis/PathProfileInfo.h @@ -0,0 +1,113 @@ +//===- PathProfileInfo.h --------------------------------------*- C++ -*---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file outlines the interface used by optimizers to load path profiles. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_PATHPROFILEINFO_H +#define LLVM_PATHPROFILEINFO_H + +#include "llvm/BasicBlock.h" +#include "llvm/Analysis/PathNumbering.h" +#include + +namespace llvm { + +class ProfilePath; +class ProfilePathEdge; +class PathProfileInfo; + +typedef std::vector ProfilePathEdgeVector; +typedef std::vector::iterator ProfilePathEdgeIterator; + +typedef std::vector ProfilePathBlockVector; +typedef std::vector::iterator ProfilePathBlockIterator; + +typedef std::map ProfilePathMap; +typedef std::map::iterator ProfilePathIterator; + +typedef std::map FunctionPathCountMap; +typedef std::map FunctionPathMap; +typedef std::map::iterator FunctionPathIterator; + +class ProfilePathEdge { +public: + ProfilePathEdge(BasicBlock* source, BasicBlock* target, + unsigned duplicateNumber); + + inline unsigned getDuplicateNumber() { return _duplicateNumber; } + inline BasicBlock* getSource() { return _source; } + inline BasicBlock* getTarget() { return _target; } + +protected: + BasicBlock* _source; + BasicBlock* _target; + unsigned _duplicateNumber; +}; + +class ProfilePath { +public: + ProfilePath(unsigned int number, unsigned int count, + double countStdDev, PathProfileInfo* ppi); + + double getFrequency() const; + + inline unsigned int getNumber() const { return _number; } + inline unsigned int getCount() const { return _count; } + inline double getCountStdDev() const { return _countStdDev; } + + ProfilePathEdgeVector* getPathEdges() const; + ProfilePathBlockVector* getPathBlocks() const; + + BasicBlock* getFirstBlockInPath() const; + +private: + unsigned int _number; + unsigned int _count; + double _countStdDev; + + // double pointer back to the profiling info + PathProfileInfo* _ppi; +}; + +// TODO: overload [] operator for getting path +// Add: getFunctionCallCount() +class PathProfileInfo { + public: + PathProfileInfo(); + ~PathProfileInfo(); + + void setCurrentFunction(Function* F); + Function* getCurrentFunction() const; + BasicBlock* getCurrentFunctionEntry(); + + ProfilePath* getPath(unsigned int number); + unsigned int getPotentialPathCount(); + + ProfilePathIterator pathBegin(); + ProfilePathIterator pathEnd(); + unsigned int pathsRun(); + + static char ID; // Pass identification + std::string argList; + +protected: + FunctionPathMap _functionPaths; + FunctionPathCountMap _functionPathCounts; + +private: + BallLarusDag* _currentDag; + Function* _currentFunction; + + friend class ProfilePath; +}; +} // end namespace llvm + +#endif diff --git a/include/llvm/Analysis/PointerTracking.h b/include/llvm/Analysis/PointerTracking.h deleted file mode 100644 index 6b49e18c1b63..000000000000 --- a/include/llvm/Analysis/PointerTracking.h +++ /dev/null @@ -1,132 +0,0 @@ -//===- PointerTracking.h - Pointer Bounds Tracking --------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements tracking of pointer bounds. -// It knows that the libc functions "calloc" and "realloc" allocate memory, thus -// you should avoid using this pass if they mean something else for your -// language. -// -// All methods assume that the pointer is not NULL, if it is then the returned -// allocation size is wrong, and the result from checkLimits is wrong too. -// It also assumes that pointers are valid, and that it is not analyzing a -// use-after-free scenario. -// Due to these limitations the "size" returned by these methods should be -// considered as either 0 or the returned size. -// -// Another analysis pass should be used to find use-after-free/NULL dereference -// bugs. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_ANALYSIS_POINTERTRACKING_H -#define LLVM_ANALYSIS_POINTERTRACKING_H - -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/Analysis/Dominators.h" -#include "llvm/Instructions.h" -#include "llvm/Pass.h" -#include "llvm/Support/PredIteratorCache.h" - -namespace llvm { - class DominatorTree; - class ScalarEvolution; - class SCEV; - class Loop; - class LoopInfo; - class TargetData; - - // Result from solver, assuming pointer is not NULL, - // and it is not a use-after-free situation. - enum SolverResult { - AlwaysFalse,// always false with above constraints - AlwaysTrue,// always true with above constraints - Unknown // it can sometimes be true, sometimes false, or it is undecided - }; - - class PointerTracking : public FunctionPass { - public: - typedef ICmpInst::Predicate Predicate; - static char ID; - PointerTracking(); - - virtual bool doInitialization(Module &M); - - // If this pointer directly points to an allocation, return - // the number of elements of type Ty allocated. - // Otherwise return CouldNotCompute. - // Since allocations can fail by returning NULL, the real element count - // for every allocation is either 0 or the value returned by this function. - const SCEV *getAllocationElementCount(Value *P) const; - - // Same as getAllocationSize() but returns size in bytes. - // We consider one byte as 8 bits. - const SCEV *getAllocationSizeInBytes(Value *V) const; - - // Given a Pointer, determine a base pointer of known size, and an offset - // therefrom. - // When unable to determine, sets Base to NULL, and Limit/Offset to - // CouldNotCompute. - // BaseSize, and Offset are in bytes: Pointer == Base + Offset - void getPointerOffset(Value *Pointer, Value *&Base, const SCEV *& BaseSize, - const SCEV *&Offset) const; - - // Compares the 2 scalar evolution expressions according to predicate, - // and if it can prove that the result is always true or always false - // return AlwaysTrue/AlwaysFalse. Otherwise it returns Unknown. - enum SolverResult compareSCEV(const SCEV *A, Predicate Pred, const SCEV *B, - const Loop *L); - - // Determines whether the condition LHS RHS is sufficient - // for the condition A B to hold. - // Currently only ULT/ULE is supported. - // This errs on the side of returning false. - bool conditionSufficient(const SCEV *LHS, Predicate Pred1, const SCEV *RHS, - const SCEV *A, Predicate Pred2, const SCEV *B, - const Loop *L); - - // Determines whether Offset is known to be always in [0, Limit) bounds. - // This errs on the side of returning Unknown. - enum SolverResult checkLimits(const SCEV *Offset, const SCEV *Limit, - BasicBlock *BB); - - virtual bool runOnFunction(Function &F); - virtual void getAnalysisUsage(AnalysisUsage &AU) const; - void print(raw_ostream &OS, const Module* = 0) const; - Value *computeAllocationCountValue(Value *P, const Type *&Ty) const; - private: - Function *FF; - TargetData *TD; - ScalarEvolution *SE; - LoopInfo *LI; - DominatorTree *DT; - - Function *callocFunc; - Function *reallocFunc; - PredIteratorCache predCache; - - SmallPtrSet analyzing; - - enum SolverResult isLoopGuardedBy(const Loop *L, Predicate Pred, - const SCEV *A, const SCEV *B) const; - static bool isMonotonic(const SCEV *S); - bool scevPositive(const SCEV *A, const Loop *L, bool strict=true) const; - bool conditionSufficient(Value *Cond, bool negated, - const SCEV *A, Predicate Pred, const SCEV *B); - Value *getConditionToReach(BasicBlock *A, - DomTreeNodeBase *B, - bool &negated); - Value *getConditionToReach(BasicBlock *A, - BasicBlock *B, - bool &negated); - const SCEV *computeAllocationCount(Value *P, const Type *&Ty) const; - const SCEV *computeAllocationCountForType(Value *P, const Type *Ty) const; - }; -} -#endif - diff --git a/include/llvm/Analysis/PostDominators.h b/include/llvm/Analysis/PostDominators.h index 46ce8200f966..2cd6ae346eeb 100644 --- a/include/llvm/Analysis/PostDominators.h +++ b/include/llvm/Analysis/PostDominators.h @@ -14,7 +14,7 @@ #ifndef LLVM_ANALYSIS_POST_DOMINATORS_H #define LLVM_ANALYSIS_POST_DOMINATORS_H -#include "llvm/Analysis/Dominators.h" +#include "llvm/Analysis/DominanceFrontier.h" namespace llvm { @@ -26,6 +26,7 @@ struct PostDominatorTree : public FunctionPass { DominatorTreeBase* DT; PostDominatorTree() : FunctionPass(ID) { + initializePostDominatorTreePass(*PassRegistry::getPassRegistry()); DT = new DominatorTreeBase(true); } @@ -106,7 +107,9 @@ template <> struct GraphTraits struct PostDominanceFrontier : public DominanceFrontierBase { static char ID; PostDominanceFrontier() - : DominanceFrontierBase(ID, true) {} + : DominanceFrontierBase(ID, true) { + initializePostDominanceFrontierPass(*PassRegistry::getPassRegistry()); + } virtual bool runOnFunction(Function &) { Frontiers.clear(); diff --git a/include/llvm/Analysis/ProfileInfoTypes.h b/include/llvm/Analysis/ProfileInfoTypes.h index 0d531d5c5f88..6b4ac85082b0 100644 --- a/include/llvm/Analysis/ProfileInfoTypes.h +++ b/include/llvm/Analysis/ProfileInfoTypes.h @@ -1,4 +1,4 @@ -/*===-- ProfileInfoTypes.h - Profiling info shared constants ------*- C -*-===*\ +/*===-- ProfileInfoTypes.h - Profiling info shared constants --------------===*\ |* |* The LLVM Compiler Infrastructure |* @@ -16,6 +16,17 @@ #ifndef LLVM_ANALYSIS_PROFILEINFOTYPES_H #define LLVM_ANALYSIS_PROFILEINFOTYPES_H +/* Included by libprofile. */ +#if defined(__cplusplus) +extern "C" { +#endif + +/* IDs to distinguish between those path counters stored in hashses vs arrays */ +enum ProfilingStorageType { + ProfilingArray = 1, + ProfilingHash = 2 +}; + enum ProfilingType { ArgumentInfo = 1, /* The command line argument block */ FunctionInfo = 2, /* Function profiling information */ @@ -26,4 +37,24 @@ enum ProfilingType { OptEdgeInfo = 7 /* Edge profiling information, optimal version */ }; +/* + * The header for tables that map path numbers to path counters. + */ +typedef struct { + unsigned fnNumber; /* function number for these counters */ + unsigned numEntries; /* number of entries stored */ +} PathProfileHeader; + +/* + * Describes an entry in a tagged table for path counters. + */ +typedef struct { + unsigned pathNumber; + unsigned pathCounter; +} PathProfileTableEntry; + +#if defined(__cplusplus) +} +#endif + #endif /* LLVM_ANALYSIS_PROFILEINFOTYPES_H */ diff --git a/include/llvm/Analysis/RegionInfo.h b/include/llvm/Analysis/RegionInfo.h index 7a2670f2c08c..a36ca110d8c0 100644 --- a/include/llvm/Analysis/RegionInfo.h +++ b/include/llvm/Analysis/RegionInfo.h @@ -58,6 +58,7 @@ class RegionNode { // DO NOT IMPLEMENT const RegionNode &operator=(const RegionNode &); +protected: /// This is the entry basic block that starts this region node. If this is a /// BasicBlock RegionNode, then entry is just the basic block, that this /// RegionNode represents. Otherwise it is the entry of this (Sub)RegionNode. @@ -70,7 +71,6 @@ class RegionNode { /// RegionNode. PointerIntPair entry; -protected: /// @brief The parent Region of this RegionNode. /// @see getParent() Region* parent; @@ -257,6 +257,18 @@ public: /// @return The entry BasicBlock of the region. BasicBlock *getEntry() const { return RegionNode::getEntry(); } + /// @brief Replace the entry basic block of the region with the new basic + /// block. + /// + /// @param BB The new entry basic block of the region. + void replaceEntry(BasicBlock *BB); + + /// @brief Replace the exit basic block of the region with the new basic + /// block. + /// + /// @param BB The new exit basic block of the region. + void replaceExit(BasicBlock *BB); + /// @brief Get the exit BasicBlock of the Region. /// @return The exit BasicBlock of the Region, NULL if this is the TopLevel /// Region. @@ -280,6 +292,33 @@ public: /// @return The depth of the region. unsigned getDepth() const; + /// @brief Check if a Region is the TopLevel region. + /// + /// The toplevel region represents the whole function. + bool isTopLevelRegion() const { return exit == NULL; } + + /// @brief Return a new (non canonical) region, that is obtained by joining + /// this region with its predecessors. + /// + /// @return A region also starting at getEntry(), but reaching to the next + /// basic block that forms with getEntry() a (non canonical) region. + /// NULL if such a basic block does not exist. + Region *getExpandedRegion() const; + + /// @brief Return the first block of this region's single entry edge, + /// if existing. + /// + /// @return The BasicBlock starting this region's single entry edge, + /// else NULL. + BasicBlock *getEnteringBlock() const; + + /// @brief Return the first block of this region's single exit edge, + /// if existing. + /// + /// @return The BasicBlock starting this region's single exit edge, + /// else NULL. + BasicBlock *getExitingBlock() const; + /// @brief Is this a simple region? /// /// A region is simple if it has exactly one exit and one entry edge. @@ -386,7 +425,9 @@ public: /// @brief Add a new subregion to this Region. /// /// @param SubRegion The new subregion that will be added. - void addSubRegion(Region *SubRegion); + /// @param moveChildren Move the children of this region, that are also + /// contained in SubRegion into SubRegion. + void addSubRegion(Region *SubRegion, bool moveChildren = false); /// @brief Remove a subregion from this Region. /// @@ -565,6 +606,12 @@ public: /// region containing BB. Region *getRegionFor(BasicBlock *BB) const; + /// @brief Set the smallest region that surrounds a basic block. + /// + /// @param BB The basic block surrounded by a region. + /// @param R The smallest region that surrounds BB. + void setRegionFor(BasicBlock *BB, Region *R); + /// @brief A shortcut for getRegionFor(). /// /// @param BB The basic block. @@ -610,6 +657,12 @@ public: return TopLevelRegion; } + /// @brief Update RegionInfo after a basic block was split. + /// + /// @param NewBB The basic block that was created before OldBB. + /// @param OldBB The old basic block. + void splitBlock(BasicBlock* NewBB, BasicBlock *OldBB); + /// @brief Clear the Node Cache for all Regions. /// /// @see Region::clearNodeCache() diff --git a/include/llvm/Analysis/RegionPass.h b/include/llvm/Analysis/RegionPass.h new file mode 100644 index 000000000000..aedc06aa6cf3 --- /dev/null +++ b/include/llvm/Analysis/RegionPass.h @@ -0,0 +1,126 @@ +//===- RegionPass.h - RegionPass class ------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the RegionPass class. All region based analysis, +// optimization and transformation passes are derived from RegionPass. +// This class is implemented following the some ideas of the LoopPass.h class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_REGION_PASS_H +#define LLVM_REGION_PASS_H + +#include "llvm/Analysis/RegionInfo.h" + +#include "llvm/Pass.h" +#include "llvm/PassManagers.h" +#include "llvm/Function.h" + +#include + +namespace llvm { + +class RGPassManager; +class Function; + +//===----------------------------------------------------------------------===// +/// @brief A pass that runs on each Region in a function. +/// +/// RegionPass is managed by RGPassManager. +class RegionPass : public Pass { +public: + explicit RegionPass(char &pid) : Pass(PT_Region, pid) {} + + //===--------------------------------------------------------------------===// + /// @name To be implemented by every RegionPass + /// + //@{ + /// @brief Run the pass on a specific Region + /// + /// Accessing regions not contained in the current region is not allowed. + /// + /// @param R The region this pass is run on. + /// @param RGM The RegionPassManager that manages this Pass. + /// + /// @return True if the pass modifies this Region. + virtual bool runOnRegion(Region *R, RGPassManager &RGM) = 0; + + /// @brief Get a pass to print the LLVM IR in the region. + /// + /// @param O The ouput stream to print the Region. + /// @param Banner The banner to seperate different printed passes. + /// + /// @return The pass to print the LLVM IR in the region. + Pass *createPrinterPass(raw_ostream &O, const std::string &Banner) const; + + virtual bool doInitialization(Region *R, RGPassManager &RGM) { return false; } + virtual bool doFinalization() { return false; } + //@} + + //===--------------------------------------------------------------------===// + /// @name PassManager API + /// + //@{ + void preparePassManager(PMStack &PMS); + + virtual void assignPassManager(PMStack &PMS, + PassManagerType PMT = PMT_RegionPassManager); + + virtual PassManagerType getPotentialPassManagerType() const { + return PMT_RegionPassManager; + } + //@} +}; + +/// @brief The pass manager to schedule RegionPasses. +class RGPassManager : public FunctionPass, public PMDataManager { + std::deque RQ; + bool skipThisRegion; + bool redoThisRegion; + RegionInfo *RI; + Region *CurrentRegion; + +public: + static char ID; + explicit RGPassManager(int Depth); + + /// @brief Execute all of the passes scheduled for execution. + /// + /// @return True if any of the passes modifies the function. + bool runOnFunction(Function &F); + + /// Pass Manager itself does not invalidate any analysis info. + /// RGPassManager needs RegionInfo. + void getAnalysisUsage(AnalysisUsage &Info) const; + + virtual const char *getPassName() const { + return "Region Pass Manager"; + } + + virtual PMDataManager *getAsPMDataManager() { return this; } + virtual Pass *getAsPass() { return this; } + + /// @brief Print passes managed by this manager. + void dumpPassStructure(unsigned Offset); + + /// @brief Print passes contained by this manager. + Pass *getContainedPass(unsigned N) { + assert(N < PassVector.size() && "Pass number out of range!"); + Pass *FP = static_cast(PassVector[N]); + return FP; + } + + virtual PassManagerType getPassManagerType() const { + return PMT_RegionPassManager; + } +}; + +} // End llvm namespace + +#endif diff --git a/include/llvm/Analysis/ScalarEvolution.h b/include/llvm/Analysis/ScalarEvolution.h index 1fa94e9c311c..d1938061bef6 100644 --- a/include/llvm/Analysis/ScalarEvolution.h +++ b/include/llvm/Analysis/ScalarEvolution.h @@ -24,7 +24,7 @@ #include "llvm/Pass.h" #include "llvm/Instructions.h" #include "llvm/Function.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/Support/ValueHandle.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/ConstantRange.h" @@ -70,27 +70,16 @@ namespace llvm { private: SCEV(const SCEV &); // DO NOT IMPLEMENT void operator=(const SCEV &); // DO NOT IMPLEMENT - protected: - virtual ~SCEV(); + public: explicit SCEV(const FoldingSetNodeIDRef ID, unsigned SCEVTy) : FastID(ID), SCEVType(SCEVTy), SubclassData(0) {} unsigned getSCEVType() const { return SCEVType; } - /// isLoopInvariant - Return true if the value of this SCEV is unchanging in - /// the specified loop. - virtual bool isLoopInvariant(const Loop *L) const = 0; - - /// hasComputableLoopEvolution - Return true if this SCEV changes value in a - /// known way in the specified loop. This property being true implies that - /// the value is variant in the loop AND that we can emit an expression to - /// compute the value of the expression at any particular loop iteration. - virtual bool hasComputableLoopEvolution(const Loop *L) const = 0; - /// getType - Return the LLVM type of this SCEV expression. /// - virtual const Type *getType() const = 0; + const Type *getType() const; /// isZero - Return true if the expression is a constant zero. /// @@ -105,22 +94,10 @@ namespace llvm { /// bool isAllOnesValue() const; - /// hasOperand - Test whether this SCEV has Op as a direct or - /// indirect operand. - virtual bool hasOperand(const SCEV *Op) const = 0; - - /// dominates - Return true if elements that makes up this SCEV dominates - /// the specified basic block. - virtual bool dominates(BasicBlock *BB, DominatorTree *DT) const = 0; - - /// properlyDominates - Return true if elements that makes up this SCEV - /// properly dominate the specified basic block. - virtual bool properlyDominates(BasicBlock *BB, DominatorTree *DT) const = 0; - /// print - Print out the internal representation of this scalar to the /// specified stream. This should really only be used for debugging /// purposes. - virtual void print(raw_ostream &OS) const = 0; + void print(raw_ostream &OS) const; /// dump - This method is used for debugging. /// @@ -155,21 +132,6 @@ namespace llvm { struct SCEVCouldNotCompute : public SCEV { SCEVCouldNotCompute(); - // None of these methods are valid for this object. - virtual bool isLoopInvariant(const Loop *L) const; - virtual const Type *getType() const; - virtual bool hasComputableLoopEvolution(const Loop *L) const; - virtual void print(raw_ostream &OS) const; - virtual bool hasOperand(const SCEV *Op) const; - - virtual bool dominates(BasicBlock *BB, DominatorTree *DT) const { - return true; - } - - virtual bool properlyDominates(BasicBlock *BB, DominatorTree *DT) const { - return true; - } - /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const SCEVCouldNotCompute *S) { return true; } static bool classof(const SCEV *S); @@ -180,6 +142,24 @@ namespace llvm { /// they must ask this class for services. /// class ScalarEvolution : public FunctionPass { + public: + /// LoopDisposition - An enum describing the relationship between a + /// SCEV and a loop. + enum LoopDisposition { + LoopVariant, ///< The SCEV is loop-variant (unknown). + LoopInvariant, ///< The SCEV is loop-invariant. + LoopComputable ///< The SCEV varies predictably with the loop. + }; + + /// BlockDisposition - An enum describing the relationship between a + /// SCEV and a basic block. + enum BlockDisposition { + DoesNotDominateBlock, ///< The SCEV does not dominate the block. + DominatesBlock, ///< The SCEV dominates the block. + ProperlyDominatesBlock ///< The SCEV properly dominates the block. + }; + + private: /// SCEVCallbackVH - A CallbackVH to arrange for ScalarEvolution to be /// notified whenever a Value is deleted. class SCEVCallbackVH : public CallbackVH { @@ -267,6 +247,46 @@ namespace llvm { std::map > ValuesAtScopes; + /// LoopDispositions - Memoized computeLoopDisposition results. + std::map > LoopDispositions; + + /// computeLoopDisposition - Compute a LoopDisposition value. + LoopDisposition computeLoopDisposition(const SCEV *S, const Loop *L); + + /// BlockDispositions - Memoized computeBlockDisposition results. + std::map > BlockDispositions; + + /// computeBlockDisposition - Compute a BlockDisposition value. + BlockDisposition computeBlockDisposition(const SCEV *S, const BasicBlock *BB); + + /// UnsignedRanges - Memoized results from getUnsignedRange + DenseMap UnsignedRanges; + + /// SignedRanges - Memoized results from getSignedRange + DenseMap SignedRanges; + + /// setUnsignedRange - Set the memoized unsigned range for the given SCEV. + const ConstantRange &setUnsignedRange(const SCEV *S, + const ConstantRange &CR) { + std::pair::iterator, bool> Pair = + UnsignedRanges.insert(std::make_pair(S, CR)); + if (!Pair.second) + Pair.first->second = CR; + return Pair.first->second; + } + + /// setUnsignedRange - Set the memoized signed range for the given SCEV. + const ConstantRange &setSignedRange(const SCEV *S, + const ConstantRange &CR) { + std::pair::iterator, bool> Pair = + SignedRanges.insert(std::make_pair(S, CR)); + if (!Pair.second) + Pair.first->second = CR; + return Pair.first->second; + } + /// createSCEV - We know that there is no SCEV for the specified value. /// Analyze the expression. const SCEV *createSCEV(Value *V); @@ -408,6 +428,9 @@ namespace llvm { bool isKnownPredicateWithRanges(ICmpInst::Predicate Pred, const SCEV *LHS, const SCEV *RHS); + /// forgetMemoizedResults - Drop memoized information computed for S. + void forgetMemoizedResults(const SCEV *S); + public: static char ID; // Pass identification, replacement for typeid ScalarEvolution(); @@ -514,10 +537,11 @@ namespace llvm { /// const SCEV *getNotSCEV(const SCEV *V); - /// getMinusSCEV - Return LHS-RHS. - /// - const SCEV *getMinusSCEV(const SCEV *LHS, - const SCEV *RHS); + /// getMinusSCEV - Return LHS-RHS. Minus is represented in SCEV as A+B*-1, + /// and thus the HasNUW and HasNSW bits apply to the resultant add, not + /// whether the sub would have overflowed. + const SCEV *getMinusSCEV(const SCEV *LHS, const SCEV *RHS, + bool HasNUW = false, bool HasNSW = false); /// getTruncateOrZeroExtend - Return a SCEV corresponding to a conversion /// of the input value to the specified type. If the type must be @@ -675,6 +699,36 @@ namespace llvm { const SCEV *&LHS, const SCEV *&RHS); + /// getLoopDisposition - Return the "disposition" of the given SCEV with + /// respect to the given loop. + LoopDisposition getLoopDisposition(const SCEV *S, const Loop *L); + + /// isLoopInvariant - Return true if the value of the given SCEV is + /// unchanging in the specified loop. + bool isLoopInvariant(const SCEV *S, const Loop *L); + + /// hasComputableLoopEvolution - Return true if the given SCEV changes value + /// in a known way in the specified loop. This property being true implies + /// that the value is variant in the loop AND that we can emit an expression + /// to compute the value of the expression at any particular loop iteration. + bool hasComputableLoopEvolution(const SCEV *S, const Loop *L); + + /// getLoopDisposition - Return the "disposition" of the given SCEV with + /// respect to the given block. + BlockDisposition getBlockDisposition(const SCEV *S, const BasicBlock *BB); + + /// dominates - Return true if elements that makes up the given SCEV + /// dominate the specified basic block. + bool dominates(const SCEV *S, const BasicBlock *BB); + + /// properlyDominates - Return true if elements that makes up the given SCEV + /// properly dominate the specified basic block. + bool properlyDominates(const SCEV *S, const BasicBlock *BB); + + /// hasOperand - Test whether the given SCEV has Op as a direct or + /// indirect operand. + bool hasOperand(const SCEV *S, const SCEV *Op) const; + virtual bool runOnFunction(Function &F); virtual void releaseMemory(); virtual void getAnalysisUsage(AnalysisUsage &AU) const; diff --git a/include/llvm/Analysis/ScalarEvolutionExpander.h b/include/llvm/Analysis/ScalarEvolutionExpander.h index 4b02f82035fe..39d378ed9bec 100644 --- a/include/llvm/Analysis/ScalarEvolutionExpander.h +++ b/include/llvm/Analysis/ScalarEvolutionExpander.h @@ -35,6 +35,9 @@ namespace llvm { std::set > InsertedValues; std::set > InsertedPostIncValues; + /// RelevantLoops - A memoization of the "relevant" loop for a given SCEV. + DenseMap RelevantLoops; + /// PostIncLoops - Addrecs referring to any of the given loops are expanded /// in post-inc mode. For example, expanding {1,+,1} in post-inc mode /// returns the add instruction that adds one to the phi for {0,+,1}, @@ -168,6 +171,9 @@ namespace llvm { return InsertedValues.count(I) || InsertedPostIncValues.count(I); } + /// getRelevantLoop - Determine the most "relevant" loop for the given SCEV. + const Loop *getRelevantLoop(const SCEV *); + Value *visitConstant(const SCEVConstant *S) { return S->getValue(); } diff --git a/include/llvm/Analysis/ScalarEvolutionExpressions.h b/include/llvm/Analysis/ScalarEvolutionExpressions.h index 4213a287011b..db432c8173dd 100644 --- a/include/llvm/Analysis/ScalarEvolutionExpressions.h +++ b/include/llvm/Analysis/ScalarEvolutionExpressions.h @@ -42,29 +42,7 @@ namespace llvm { public: ConstantInt *getValue() const { return V; } - virtual bool isLoopInvariant(const Loop *L) const { - return true; - } - - virtual bool hasComputableLoopEvolution(const Loop *L) const { - return false; // Not loop variant - } - - virtual const Type *getType() const; - - virtual bool hasOperand(const SCEV *) const { - return false; - } - - bool dominates(BasicBlock *BB, DominatorTree *DT) const { - return true; - } - - bool properlyDominates(BasicBlock *BB, DominatorTree *DT) const { - return true; - } - - virtual void print(raw_ostream &OS) const; + const Type *getType() const { return V->getType(); } /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const SCEVConstant *S) { return true; } @@ -86,23 +64,7 @@ namespace llvm { public: const SCEV *getOperand() const { return Op; } - virtual const Type *getType() const { return Ty; } - - virtual bool isLoopInvariant(const Loop *L) const { - return Op->isLoopInvariant(L); - } - - virtual bool hasComputableLoopEvolution(const Loop *L) const { - return Op->hasComputableLoopEvolution(L); - } - - virtual bool hasOperand(const SCEV *O) const { - return Op == O || Op->hasOperand(O); - } - - virtual bool dominates(BasicBlock *BB, DominatorTree *DT) const; - - virtual bool properlyDominates(BasicBlock *BB, DominatorTree *DT) const; + const Type *getType() const { return Ty; } /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const SCEVCastExpr *S) { return true; } @@ -124,8 +86,6 @@ namespace llvm { const SCEV *op, const Type *ty); public: - virtual void print(raw_ostream &OS) const; - /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const SCEVTruncateExpr *S) { return true; } static inline bool classof(const SCEV *S) { @@ -144,8 +104,6 @@ namespace llvm { const SCEV *op, const Type *ty); public: - virtual void print(raw_ostream &OS) const; - /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const SCEVZeroExtendExpr *S) { return true; } static inline bool classof(const SCEV *S) { @@ -164,8 +122,6 @@ namespace llvm { const SCEV *op, const Type *ty); public: - virtual void print(raw_ostream &OS) const; - /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const SCEVSignExtendExpr *S) { return true; } static inline bool classof(const SCEV *S) { @@ -202,20 +158,7 @@ namespace llvm { op_iterator op_begin() const { return Operands; } op_iterator op_end() const { return Operands + NumOperands; } - virtual bool isLoopInvariant(const Loop *L) const; - - // hasComputableLoopEvolution - N-ary expressions have computable loop - // evolutions iff they have at least one operand that varies with the loop, - // but that all varying operands are computable. - virtual bool hasComputableLoopEvolution(const Loop *L) const; - - virtual bool hasOperand(const SCEV *O) const; - - bool dominates(BasicBlock *BB, DominatorTree *DT) const; - - bool properlyDominates(BasicBlock *BB, DominatorTree *DT) const; - - virtual const Type *getType() const { return getOperand(0)->getType(); } + const Type *getType() const { return getOperand(0)->getType(); } bool hasNoUnsignedWrap() const { return SubclassData & (1 << 0); } void setHasNoUnsignedWrap(bool B) { @@ -248,10 +191,6 @@ namespace llvm { : SCEVNAryExpr(ID, T, O, N) {} public: - virtual const char *getOperationStr() const = 0; - - virtual void print(raw_ostream &OS) const; - /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const SCEVCommutativeExpr *S) { return true; } static inline bool classof(const SCEV *S) { @@ -275,9 +214,7 @@ namespace llvm { } public: - virtual const char *getOperationStr() const { return " + "; } - - virtual const Type *getType() const { + const Type *getType() const { // Use the type of the last operand, which is likely to be a pointer // type, if there is one. This doesn't usually matter, but it can help // reduce casts when the expressions are expanded. @@ -303,8 +240,6 @@ namespace llvm { } public: - virtual const char *getOperationStr() const { return " * "; } - /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const SCEVMulExpr *S) { return true; } static inline bool classof(const SCEV *S) { @@ -328,27 +263,15 @@ namespace llvm { const SCEV *getLHS() const { return LHS; } const SCEV *getRHS() const { return RHS; } - virtual bool isLoopInvariant(const Loop *L) const { - return LHS->isLoopInvariant(L) && RHS->isLoopInvariant(L); - } - - virtual bool hasComputableLoopEvolution(const Loop *L) const { - return LHS->hasComputableLoopEvolution(L) && - RHS->hasComputableLoopEvolution(L); - } - - virtual bool hasOperand(const SCEV *O) const { - return O == LHS || O == RHS || LHS->hasOperand(O) || RHS->hasOperand(O); + const Type *getType() const { + // In most cases the types of LHS and RHS will be the same, but in some + // crazy cases one or the other may be a pointer. ScalarEvolution doesn't + // depend on the type for correctness, but handling types carefully can + // avoid extra casts in the SCEVExpander. The LHS is more likely to be + // a pointer type than the RHS, so use the RHS' type here. + return getRHS()->getType(); } - bool dominates(BasicBlock *BB, DominatorTree *DT) const; - - bool properlyDominates(BasicBlock *BB, DominatorTree *DT) const; - - virtual const Type *getType() const; - - void print(raw_ostream &OS) const; - /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const SCEVUDivExpr *S) { return true; } static inline bool classof(const SCEV *S) { @@ -373,11 +296,7 @@ namespace llvm { SCEVAddRecExpr(const FoldingSetNodeIDRef ID, const SCEV *const *O, size_t N, const Loop *l) - : SCEVNAryExpr(ID, scAddRecExpr, O, N), L(l) { - for (size_t i = 0, e = NumOperands; i != e; ++i) - assert(Operands[i]->isLoopInvariant(l) && - "Operands of AddRec must be loop-invariant!"); - } + : SCEVNAryExpr(ID, scAddRecExpr, O, N), L(l) {} public: const SCEV *getStart() const { return Operands[0]; } @@ -393,16 +312,6 @@ namespace llvm { getLoop()); } - virtual bool hasComputableLoopEvolution(const Loop *QL) const { - return L == QL; - } - - virtual bool isLoopInvariant(const Loop *QueryLoop) const; - - bool dominates(BasicBlock *BB, DominatorTree *DT) const; - - bool properlyDominates(BasicBlock *BB, DominatorTree *DT) const; - /// isAffine - Return true if this is an affine AddRec (i.e., it represents /// an expressions A+B*x where A and B are loop invariant values. bool isAffine() const { @@ -437,8 +346,6 @@ namespace llvm { return cast(SE.getAddExpr(this, getStepRecurrence(SE))); } - virtual void print(raw_ostream &OS) const; - /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const SCEVAddRecExpr *S) { return true; } static inline bool classof(const SCEV *S) { @@ -462,8 +369,6 @@ namespace llvm { } public: - virtual const char *getOperationStr() const { return " smax "; } - /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const SCEVSMaxExpr *S) { return true; } static inline bool classof(const SCEV *S) { @@ -487,8 +392,6 @@ namespace llvm { } public: - virtual const char *getOperationStr() const { return " umax "; } - /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const SCEVUMaxExpr *S) { return true; } static inline bool classof(const SCEV *S) { @@ -534,22 +437,7 @@ namespace llvm { bool isAlignOf(const Type *&AllocTy) const; bool isOffsetOf(const Type *&STy, Constant *&FieldNo) const; - virtual bool isLoopInvariant(const Loop *L) const; - virtual bool hasComputableLoopEvolution(const Loop *QL) const { - return false; // not computable - } - - virtual bool hasOperand(const SCEV *) const { - return false; - } - - bool dominates(BasicBlock *BB, DominatorTree *DT) const; - - bool properlyDominates(BasicBlock *BB, DominatorTree *DT) const; - - virtual const Type *getType() const; - - virtual void print(raw_ostream &OS) const; + const Type *getType() const { return getValPtr()->getType(); } /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const SCEVUnknown *S) { return true; } diff --git a/include/llvm/Analysis/ValueTracking.h b/include/llvm/Analysis/ValueTracking.h index 7b6026fea0a6..6df1693c78e6 100644 --- a/include/llvm/Analysis/ValueTracking.h +++ b/include/llvm/Analysis/ValueTracking.h @@ -15,7 +15,7 @@ #ifndef LLVM_ANALYSIS_VALUETRACKING_H #define LLVM_ANALYSIS_VALUETRACKING_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include namespace llvm { @@ -39,6 +39,23 @@ namespace llvm { APInt &KnownOne, const TargetData *TD = 0, unsigned Depth = 0); + /// ComputeSignBit - Determine whether the sign bit is known to be zero or + /// one. Convenience wrapper around ComputeMaskedBits. + void ComputeSignBit(Value *V, bool &KnownZero, bool &KnownOne, + const TargetData *TD = 0, unsigned Depth = 0); + + /// isPowerOfTwo - Return true if the given value is known to have exactly one + /// bit set when defined. For vectors return true if every element is known to + /// be a power of two when defined. Supports values with integer or pointer + /// type and vectors of integers. + bool isPowerOfTwo(Value *V, const TargetData *TD = 0, unsigned Depth = 0); + + /// isKnownNonZero - Return true if the given value is known to be non-zero + /// when defined. For vectors return true if every element is known to be + /// non-zero when defined. Supports values with integer or pointer type and + /// vectors of integers. + bool isKnownNonZero(Value *V, const TargetData *TD = 0, unsigned Depth = 0); + /// MaskedValueIsZero - Return true if 'V & Mask' is known to be zero. We use /// this predicate to simplify operations downstream. Mask is known to be /// zero for bits that V cannot have. @@ -77,7 +94,13 @@ namespace llvm { /// bool CannotBeNegativeZero(const Value *V, unsigned Depth = 0); - + /// isBytewiseValue - If the specified value can be set by repeating the same + /// byte in memory, return the i8 value that it is represented with. This is + /// true for all i8 values obviously, but is also true for i32 0, i32 -1, + /// i16 0xF0F0, double 0.0 etc. If the value can't be handled with a repeated + /// byte store (e.g. i16 0x1234), return null. + Value *isBytewiseValue(Value *V); + /// FindInsertedValue - Given an aggregrate and an sequence of indices, see if /// the scalar value indexed is already around as a register, for example if /// it were inserted directly into the aggregrate. @@ -97,6 +120,17 @@ namespace llvm { return FindInsertedValue(V, &Idxs[0], &Idxs[1], InsertBefore); } + /// GetPointerBaseWithConstantOffset - Analyze the specified pointer to see if + /// it can be expressed as a base pointer plus a constant offset. Return the + /// base and offset to the caller. + Value *GetPointerBaseWithConstantOffset(Value *Ptr, int64_t &Offset, + const TargetData &TD); + static inline const Value * + GetPointerBaseWithConstantOffset(const Value *Ptr, int64_t &Offset, + const TargetData &TD) { + return GetPointerBaseWithConstantOffset(const_cast(Ptr), Offset,TD); + } + /// GetConstantStringInfo - This function computes the length of a /// null-terminated C string pointed to by V. If successful, it returns true /// and returns the string in Str. If unsuccessful, it returns false. If @@ -110,6 +144,20 @@ namespace llvm { /// GetStringLength - If we can compute the length of the string pointed to by /// the specified pointer, return 'len+1'. If we can't, return 0. uint64_t GetStringLength(Value *V); + + /// GetUnderlyingObject - This method strips off any GEP address adjustments + /// and pointer casts from the specified value, returning the original object + /// being addressed. Note that the returned value has pointer type if the + /// specified value does. If the MaxLookup value is non-zero, it limits the + /// number of instructions to be stripped off. + Value *GetUnderlyingObject(Value *V, const TargetData *TD = 0, + unsigned MaxLookup = 6); + static inline const Value * + GetUnderlyingObject(const Value *V, const TargetData *TD = 0, + unsigned MaxLookup = 6) { + return GetUnderlyingObject(const_cast(V), TD, MaxLookup); + } + } // end namespace llvm #endif diff --git a/include/llvm/Attributes.h b/include/llvm/Attributes.h index 1296d67d5258..da6188b1a8ea 100644 --- a/include/llvm/Attributes.h +++ b/include/llvm/Attributes.h @@ -65,6 +65,8 @@ const Attributes StackAlignment = 7<<26; ///< Alignment of stack for ///of alignment with +1 bias ///0 means unaligned (different from ///alignstack(1)) +const Attributes Hotpatch = 1<<29; ///< Function should have special + ///'hotpatch' sequence in prologue /// @brief Attributes that only apply to function parameters. const Attributes ParameterOnly = ByVal | Nest | StructRet | NoCapture; @@ -73,7 +75,8 @@ const Attributes ParameterOnly = ByVal | Nest | StructRet | NoCapture; /// be used on return values or function parameters. const Attributes FunctionOnly = NoReturn | NoUnwind | ReadNone | ReadOnly | NoInline | AlwaysInline | OptimizeForSize | StackProtect | StackProtectReq | - NoRedZone | NoImplicitFloat | Naked | InlineHint | StackAlignment; + NoRedZone | NoImplicitFloat | Naked | InlineHint | StackAlignment | + Hotpatch; /// @brief Parameter attributes that do not apply to vararg call arguments. const Attributes VarArgsIncompatible = StructRet; @@ -223,7 +226,7 @@ public: /// paramHasAttr - Return true if the specified parameter index has the /// specified attribute set. bool paramHasAttr(unsigned Idx, Attributes Attr) const { - return getAttributes(Idx) & Attr; + return (getAttributes(Idx) & Attr) != 0; } /// getParamAlignment - Return the alignment for the specified function diff --git a/include/llvm/BasicBlock.h b/include/llvm/BasicBlock.h index bf5874f6824a..7e7c9e76943d 100644 --- a/include/llvm/BasicBlock.h +++ b/include/llvm/BasicBlock.h @@ -18,7 +18,7 @@ #include "llvm/SymbolTableListTraits.h" #include "llvm/ADT/ilist.h" #include "llvm/ADT/Twine.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { @@ -58,9 +58,9 @@ private: /// tables. The type of a BasicBlock is "Type::LabelTy" because the basic block /// represents a label to which a branch can jump. /// -/// A well formed basic block is formed of a list of non-terminating -/// instructions followed by a single TerminatorInst instruction. -/// TerminatorInst's may not occur in the middle of basic blocks, and must +/// A well formed basic block is formed of a list of non-terminating +/// instructions followed by a single TerminatorInst instruction. +/// TerminatorInst's may not occur in the middle of basic blocks, and must /// terminate the blocks. The BasicBlock class allows malformed basic blocks to /// occur because it may be useful in the intermediate stage of constructing or /// modifying a program. However, the verifier will ensure that basic blocks @@ -90,7 +90,7 @@ private: public: /// getContext - Get the context in which this basic block lives. LLVMContext &getContext() const; - + /// Instruction iterators... typedef InstListType::iterator iterator; typedef InstListType::const_iterator const_iterator; @@ -98,7 +98,7 @@ public: /// Create - Creates a new BasicBlock. If the Parent parameter is specified, /// the basic block is automatically inserted at either the end of the /// function (if InsertBefore is 0), or before the specified basic block. - static BasicBlock *Create(LLVMContext &Context, const Twine &Name = "", + static BasicBlock *Create(LLVMContext &Context, const Twine &Name = "", Function *Parent = 0,BasicBlock *InsertBefore = 0) { return new BasicBlock(Context, Name, Parent, InsertBefore); } @@ -114,15 +114,15 @@ public: /// and BlockAddress's). User *use_back() { return cast(*use_begin());} const User *use_back() const { return cast(*use_begin());} - + /// getTerminator() - If this is a well formed basic block, then this returns /// a pointer to the terminator instruction. If it is not, then you get a /// null pointer back. /// TerminatorInst *getTerminator(); const TerminatorInst *getTerminator() const; - - /// Returns a pointer to the first instructon in this block that is not a + + /// Returns a pointer to the first instructon in this block that is not a /// PHINode instruction. When adding instruction to the beginning of the /// basic block, they should be added before the returned value, not before /// the first instruction, which might be PHI. @@ -137,7 +137,7 @@ public: const Instruction* getFirstNonPHIOrDbg() const { return const_cast(this)->getFirstNonPHIOrDbg(); } - + /// removeFromParent - This method unlinks 'this' from the containing /// function, but does not delete it. /// @@ -147,15 +147,15 @@ public: /// and deletes it. /// void eraseFromParent(); - + /// moveBefore - Unlink this basic block from its current function and /// insert it into the function that MovePos lives in, right before MovePos. void moveBefore(BasicBlock *MovePos); - + /// moveAfter - Unlink this basic block from its current function and /// insert it into the function that MovePos lives in, right after MovePos. void moveAfter(BasicBlock *MovePos); - + /// getSinglePredecessor - If this basic block has a single predecessor block, /// return the block, otherwise return a null pointer. @@ -166,8 +166,8 @@ public: /// getUniquePredecessor - If this basic block has a unique predecessor block, /// return the block, otherwise return a null pointer. - /// Note that unique predecessor doesn't mean single edge, there can be - /// multiple edges from the unique predecessor to this block (for example + /// Note that unique predecessor doesn't mean single edge, there can be + /// multiple edges from the unique predecessor to this block (for example /// a switch statement with multiple cases having the same destination). BasicBlock *getUniquePredecessor(); const BasicBlock *getUniquePredecessor() const { @@ -247,7 +247,7 @@ public: /// hasAddressTaken - returns true if there are any uses of this basic block /// other than direct branches, switches, etc. to it. bool hasAddressTaken() const { return getSubclassDataFromValue() != 0; } - + private: /// AdjustBlockAddressRefCount - BasicBlock stores the number of BlockAddress /// objects using it. This is almost always 0, sometimes one, possibly but diff --git a/include/llvm/Bitcode/Archive.h b/include/llvm/Bitcode/Archive.h index 934e764b6587..c3c07d8588a3 100644 --- a/include/llvm/Bitcode/Archive.h +++ b/include/llvm/Bitcode/Archive.h @@ -19,12 +19,13 @@ #include "llvm/ADT/ilist.h" #include "llvm/ADT/ilist_node.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Path.h" #include #include namespace llvm { class MemoryBuffer; + class raw_ostream; // Forward declare classes class Module; // From VMCore @@ -82,7 +83,7 @@ class ArchiveMember : public ilist_node { unsigned getGroup() const { return info.getGroup(); } /// The "mode" specifies the access permissions for the file per Unix - /// security. This may not have any applicabiity on non-Unix systems but is + /// security. This may not have any applicability on non-Unix systems but is /// a required component of the "ar" file format. /// @brief Get the permission mode associated with this archive member. unsigned getMode() const { return info.getMode(); } @@ -144,7 +145,7 @@ class ArchiveMember : public ilist_node { /// allowed that doesn't have this restriction. This method determines if /// that "long format" is used for this member. /// @returns true iff the file name uses the long form - /// @brief Determin if the member has a long file name + /// @brief Determine if the member has a long file name bool hasLongFilename() const { return flags&HasLongFilenameFlag; } /// This method returns the status info (like Unix stat(2)) for the archive @@ -402,7 +403,7 @@ class Archive { /// bitcode archive. It first makes sure the symbol table has been loaded /// and has a non-zero size. If it does, then it is an archive. If not, /// then it tries to load all the bitcode modules of the archive. Finally, - /// it returns whether it was successfull. + /// it returns whether it was successful. /// @returns true if the archive is a proper llvm bitcode archive /// @brief Determine whether the archive is a proper llvm bitcode archive. bool isBitcodeArchive(); @@ -482,7 +483,7 @@ class Archive { bool loadSymbolTable(std::string* ErrMessage); /// @brief Write the symbol table to an ofstream. - void writeSymbolTable(std::ofstream& ARFile); + void writeSymbolTable(raw_ostream& ARFile); /// Writes one ArchiveMember to an ofstream. If an error occurs, returns /// false, otherwise true. If an error occurs and error is non-null then @@ -491,7 +492,7 @@ class Archive { /// @returns true Writing member failed, \p error set to error message bool writeMember( const ArchiveMember& member, ///< The member to be written - std::ofstream& ARFile, ///< The file to write member onto + raw_ostream& ARFile, ///< The file to write member onto bool CreateSymbolTable, ///< Should symbol table be created? bool TruncateNames, ///< Should names be truncated to 11 chars? bool ShouldCompress, ///< Should the member be compressed? diff --git a/include/llvm/Bitcode/BitCodes.h b/include/llvm/Bitcode/BitCodes.h index ada2e65ee642..449dc35d7de2 100644 --- a/include/llvm/Bitcode/BitCodes.h +++ b/include/llvm/Bitcode/BitCodes.h @@ -19,7 +19,7 @@ #define LLVM_BITCODE_BITCODES_H #include "llvm/ADT/SmallVector.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include namespace llvm { diff --git a/include/llvm/Bitcode/LLVMBitCodes.h b/include/llvm/Bitcode/LLVMBitCodes.h index 4f9b783aa97b..7692bd28720b 100644 --- a/include/llvm/Bitcode/LLVMBitCodes.h +++ b/include/llvm/Bitcode/LLVMBitCodes.h @@ -94,7 +94,9 @@ namespace bitc { TYPE_CODE_FP128 = 14, // LONG DOUBLE (112 bit mantissa) TYPE_CODE_PPC_FP128= 15, // PPC LONG DOUBLE (2 doubles) - TYPE_CODE_METADATA = 16 // METADATA + TYPE_CODE_METADATA = 16, // METADATA + + TYPE_CODE_X86_MMX = 17 // X86 MMX }; // The type symbol table only has one code (TST_ENTRY_CODE). @@ -197,10 +199,10 @@ namespace bitc { OBO_NO_SIGNED_WRAP = 1 }; - /// SDivOperatorOptionalFlags - Flags for serializing SDivOperator's - /// SubclassOptionalData contents. - enum SDivOperatorOptionalFlags { - SDIV_EXACT = 0 + /// PossiblyExactOperatorOptionalFlags - Flags for serializing + /// PossiblyExactOperator's SubclassOptionalData contents. + enum PossiblyExactOperatorOptionalFlags { + PEO_EXACT = 0 }; // The function body block (FUNCTION_BLOCK_ID) describes function bodies. It diff --git a/include/llvm/Bitcode/ReaderWriter.h b/include/llvm/Bitcode/ReaderWriter.h index a186964743dc..fa754c014621 100644 --- a/include/llvm/Bitcode/ReaderWriter.h +++ b/include/llvm/Bitcode/ReaderWriter.h @@ -33,6 +33,15 @@ namespace llvm { LLVMContext& Context, std::string *ErrMsg = 0); + /// getBitcodeTargetTriple - Read the header of the specified bitcode + /// buffer and extract just the triple information. If successful, + /// this returns a string and *does not* take ownership + /// of 'buffer'. On error, this returns "", and fills in *ErrMsg + /// if ErrMsg is non-null. + std::string getBitcodeTargetTriple(MemoryBuffer *Buffer, + LLVMContext& Context, + std::string *ErrMsg = 0); + /// ParseBitcodeFile - Read the specified bitcode file, returning the module. /// If an error occurs, this returns null and fills in *ErrMsg if it is /// non-null. This method *never* takes ownership of Buffer. diff --git a/include/llvm/CallingConv.h b/include/llvm/CallingConv.h index b0481b92baea..4c5ee626709a 100644 --- a/include/llvm/CallingConv.h +++ b/include/llvm/CallingConv.h @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file defines LLVM's set of calling conventions. +// This file defines LLVM's set of calling conventions. // //===----------------------------------------------------------------------===// @@ -20,21 +20,21 @@ namespace llvm { /// the well-known calling conventions. /// namespace CallingConv { - /// A set of enums which specify the assigned numeric values for known llvm + /// A set of enums which specify the assigned numeric values for known llvm /// calling conventions. /// @brief LLVM Calling Convention Representation enum ID { /// C - The default llvm calling convention, compatible with C. This /// convention is the only calling convention that supports varargs calls. - /// As with typical C calling conventions, the callee/caller have to + /// As with typical C calling conventions, the callee/caller have to /// tolerate certain amounts of prototype mismatch. C = 0, - + // Generic LLVM calling conventions. None of these calling conventions // support varargs calls, and all assume that the caller and callee // prototype exactly match. - /// Fast - This calling convention attempts to make calls as fast as + /// Fast - This calling convention attempts to make calls as fast as /// possible (e.g. by passing things in registers). Fast = 8, @@ -79,7 +79,22 @@ namespace CallingConv { /// X86_ThisCall - Similar to X86_StdCall. Passes first argument in ECX, /// others via stack. Callee is responsible for stack cleaning. MSVC uses /// this by default for methods in its ABI. - X86_ThisCall = 70 + X86_ThisCall = 70, + + /// PTX_Kernel - Call to a PTX kernel. + /// Passes all arguments in parameter space. + PTX_Kernel = 71, + + /// PTX_Device - Call to a PTX device function. + /// Passes all arguments in register or parameter space. + PTX_Device = 72, + + /// MBLAZE_INTR - Calling convention used for MBlaze interrupt routines. + MBLAZE_INTR = 73, + + /// MBLAZE_INTR - Calling convention used for MBlaze interrupt support + /// routines (i.e. GCC's save_volatiles attribute). + MBLAZE_SVOL = 74 }; } // End CallingConv namespace diff --git a/include/llvm/CodeGen/Analysis.h b/include/llvm/CodeGen/Analysis.h index f33a9dbcae73..78bf9fc11aa8 100644 --- a/include/llvm/CodeGen/Analysis.h +++ b/include/llvm/CodeGen/Analysis.h @@ -23,14 +23,16 @@ namespace llvm { -class TargetLowering; class GlobalVariable; +class TargetLowering; +class SDNode; +class SelectionDAG; /// ComputeLinearIndex - Given an LLVM IR aggregate type and a sequence /// of insertvalue or extractvalue indices that identify a member, return /// the linearized index of the start of the member. /// -unsigned ComputeLinearIndex(const TargetLowering &TLI, const Type *Ty, +unsigned ComputeLinearIndex(const Type *Ty, const unsigned *Indices, const unsigned *IndicesEnd, unsigned CurIndex = 0); @@ -52,7 +54,7 @@ GlobalVariable *ExtractTypeInfo(Value *V); /// hasInlineAsmMemConstraint - Return true if the inline asm instruction being /// processed uses a memory 'm' constraint. -bool hasInlineAsmMemConstraint(std::vector &CInfos, +bool hasInlineAsmMemConstraint(InlineAsm::ConstraintInfoVector &CInfos, const TargetLowering &TLI); /// getFCmpCondCode - Return the ISD condition code corresponding to @@ -75,6 +77,9 @@ ISD::CondCode getICmpCondCode(ICmpInst::Predicate Pred); bool isInTailCallPosition(ImmutableCallSite CS, Attributes CalleeRetAttr, const TargetLowering &TLI); +bool isInTailCallPosition(SelectionDAG &DAG, SDNode *Node, + const TargetLowering &TLI); + } // End llvm namespace #endif diff --git a/include/llvm/CodeGen/AsmPrinter.h b/include/llvm/CodeGen/AsmPrinter.h index b018603b314e..357b933db54c 100644 --- a/include/llvm/CodeGen/AsmPrinter.h +++ b/include/llvm/CodeGen/AsmPrinter.h @@ -17,7 +17,7 @@ #define LLVM_CODEGEN_ASMPRINTER_H #include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/Support/DebugLoc.h" +#include "llvm/Support/DataTypes.h" namespace llvm { class BlockAddress; @@ -49,6 +49,7 @@ namespace llvm { class MCSection; class MCStreamer; class MCSymbol; + class MDNode; class DwarfDebug; class DwarfException; class Mangler; @@ -388,7 +389,7 @@ namespace llvm { /// frame. void EmitFrameMoves(const std::vector &Moves, MCSymbol *BaseLabel, bool isEH) const; - + void EmitCFIFrameMoves(const std::vector &Moves) const; //===------------------------------------------------------------------===// // Inline Asm Support @@ -432,7 +433,7 @@ namespace llvm { mutable unsigned SetCounter; /// EmitInlineAsm - Emit a blob of inline asm to the output streamer. - void EmitInlineAsm(StringRef Str, unsigned LocCookie) const; + void EmitInlineAsm(StringRef Str, const MDNode *LocMDNode = 0) const; /// EmitInlineAsm - This method formats and emits the specified machine /// instruction that is an inline asm. diff --git a/include/llvm/CodeGen/BinaryObject.h b/include/llvm/CodeGen/BinaryObject.h index 3ade7c9e47cd..8c1431ffbeed 100644 --- a/include/llvm/CodeGen/BinaryObject.h +++ b/include/llvm/CodeGen/BinaryObject.h @@ -16,7 +16,7 @@ #define LLVM_CODEGEN_BINARYOBJECT_H #include "llvm/CodeGen/MachineRelocation.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include #include diff --git a/include/llvm/CodeGen/CalcSpillWeights.h b/include/llvm/CodeGen/CalcSpillWeights.h index 240734fb2e5e..853ebf99a87b 100644 --- a/include/llvm/CodeGen/CalcSpillWeights.h +++ b/include/llvm/CodeGen/CalcSpillWeights.h @@ -20,6 +20,26 @@ namespace llvm { class LiveIntervals; class MachineLoopInfo; + /// normalizeSpillWeight - The spill weight of a live interval is computed as: + /// + /// (sum(use freq) + sum(def freq)) / (K + size) + /// + /// @param UseDefFreq Expected number of executed use and def instructions + /// per function call. Derived from block frequencies. + /// @param Size Size of live interval as returnexd by getSize() + /// + static inline float normalizeSpillWeight(float UseDefFreq, unsigned Size) { + // The magic constant 200 corresponds to approx. 25 instructions since + // SlotIndexes allocate 8 slots per instruction. + // + // The constant is added to avoid depending too much on accidental SlotIndex + // gaps for small intervals. The effect is that small intervals have a spill + // weight that is mostly proportional to the number of uses, while large + // intervals get a spill weight that is closer to a use density. + // + return UseDefFreq / (Size + 200); + } + /// VirtRegAuxInfo - Calculate auxiliary information for a virtual /// register such as its spill weight and allocation hint. class VirtRegAuxInfo { @@ -48,7 +68,9 @@ namespace llvm { public: static char ID; - CalculateSpillWeights() : MachineFunctionPass(ID) {} + CalculateSpillWeights() : MachineFunctionPass(ID) { + initializeCalculateSpillWeightsPass(*PassRegistry::getPassRegistry()); + } virtual void getAnalysisUsage(AnalysisUsage &au) const; diff --git a/include/llvm/CodeGen/CallingConvLower.h b/include/llvm/CodeGen/CallingConvLower.h index 6fb843641dcd..2a9bbdfb7ceb 100644 --- a/include/llvm/CodeGen/CallingConvLower.h +++ b/include/llvm/CodeGen/CallingConvLower.h @@ -57,14 +57,14 @@ private: LocInfo HTP : 6; /// ValVT - The type of the value being assigned. - EVT ValVT; + MVT ValVT; /// LocVT - The type of the location being assigned to. - EVT LocVT; + MVT LocVT; public: - static CCValAssign getReg(unsigned ValNo, EVT ValVT, - unsigned RegNo, EVT LocVT, + static CCValAssign getReg(unsigned ValNo, MVT ValVT, + unsigned RegNo, MVT LocVT, LocInfo HTP) { CCValAssign Ret; Ret.ValNo = ValNo; @@ -77,8 +77,8 @@ public: return Ret; } - static CCValAssign getCustomReg(unsigned ValNo, EVT ValVT, - unsigned RegNo, EVT LocVT, + static CCValAssign getCustomReg(unsigned ValNo, MVT ValVT, + unsigned RegNo, MVT LocVT, LocInfo HTP) { CCValAssign Ret; Ret = getReg(ValNo, ValVT, RegNo, LocVT, HTP); @@ -86,8 +86,8 @@ public: return Ret; } - static CCValAssign getMem(unsigned ValNo, EVT ValVT, - unsigned Offset, EVT LocVT, + static CCValAssign getMem(unsigned ValNo, MVT ValVT, + unsigned Offset, MVT LocVT, LocInfo HTP) { CCValAssign Ret; Ret.ValNo = ValNo; @@ -100,8 +100,8 @@ public: return Ret; } - static CCValAssign getCustomMem(unsigned ValNo, EVT ValVT, - unsigned Offset, EVT LocVT, + static CCValAssign getCustomMem(unsigned ValNo, MVT ValVT, + unsigned Offset, MVT LocVT, LocInfo HTP) { CCValAssign Ret; Ret = getMem(ValNo, ValVT, Offset, LocVT, HTP); @@ -110,7 +110,7 @@ public: } unsigned getValNo() const { return ValNo; } - EVT getValVT() const { return ValVT; } + MVT getValVT() const { return ValVT; } bool isRegLoc() const { return !isMem; } bool isMemLoc() const { return isMem; } @@ -119,7 +119,7 @@ public: unsigned getLocReg() const { assert(isRegLoc()); return Loc; } unsigned getLocMemOffset() const { assert(isMemLoc()); return Loc; } - EVT getLocVT() const { return LocVT; } + MVT getLocVT() const { return LocVT; } LocInfo getLocInfo() const { return HTP; } bool isExtInLoc() const { @@ -129,16 +129,16 @@ public: }; /// CCAssignFn - This function assigns a location for Val, updating State to -/// reflect the change. -typedef bool CCAssignFn(unsigned ValNo, EVT ValVT, - EVT LocVT, CCValAssign::LocInfo LocInfo, +/// reflect the change. It returns 'true' if it failed to handle Val. +typedef bool CCAssignFn(unsigned ValNo, MVT ValVT, + MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State); /// CCCustomFn - This function assigns a location for Val, possibly updating /// all args to reflect changes and indicates if it handled it. It must set /// isCustom if it handles the arg and returns true. -typedef bool CCCustomFn(unsigned &ValNo, EVT &ValVT, - EVT &LocVT, CCValAssign::LocInfo &LocInfo, +typedef bool CCCustomFn(unsigned &ValNo, MVT &ValVT, + MVT &LocVT, CCValAssign::LocInfo &LocInfo, ISD::ArgFlagsTy &ArgFlags, CCState &State); /// CCState - This class holds information needed while lowering arguments and @@ -198,7 +198,7 @@ public: /// AnalyzeCallOperands - Same as above except it takes vectors of types /// and argument flags. - void AnalyzeCallOperands(SmallVectorImpl &ArgVTs, + void AnalyzeCallOperands(SmallVectorImpl &ArgVTs, SmallVectorImpl &Flags, CCAssignFn Fn); @@ -209,7 +209,7 @@ public: /// AnalyzeCallResult - Same as above except it's specialized for calls which /// produce a single value. - void AnalyzeCallResult(EVT VT, CCAssignFn Fn); + void AnalyzeCallResult(MVT VT, CCAssignFn Fn); /// getFirstUnallocated - Return the first unallocated register in the set, or /// NumRegs if they are all allocated. @@ -284,8 +284,8 @@ public: // HandleByVal - Allocate a stack slot large enough to pass an argument by // value. The size and alignment information of the argument is encoded in its // parameter attribute. - void HandleByVal(unsigned ValNo, EVT ValVT, - EVT LocVT, CCValAssign::LocInfo LocInfo, + void HandleByVal(unsigned ValNo, MVT ValVT, + MVT LocVT, CCValAssign::LocInfo LocInfo, int MinSize, int MinAlign, ISD::ArgFlagsTy ArgFlags); private: diff --git a/include/llvm/CodeGen/EdgeBundles.h b/include/llvm/CodeGen/EdgeBundles.h new file mode 100644 index 000000000000..2c5215a7927a --- /dev/null +++ b/include/llvm/CodeGen/EdgeBundles.h @@ -0,0 +1,61 @@ +//===-------- EdgeBundles.h - Bundles of CFG edges --------------*- c++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// The EdgeBundles analysis forms equivalence classes of CFG edges such that all +// edges leaving a machine basic block are in the same bundle, and all edges +// leaving a basic block are in the same bundle. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_EDGEBUNDLES_H +#define LLVM_CODEGEN_EDGEBUNDLES_H + +#include "llvm/ADT/IntEqClasses.h" +#include "llvm/CodeGen/MachineFunctionPass.h" + +namespace llvm { + +class EdgeBundles : public MachineFunctionPass { + const MachineFunction *MF; + + /// EC - Each edge bundle is an equivalence class. The keys are: + /// 2*BB->getNumber() -> Ingoing bundle. + /// 2*BB->getNumber()+1 -> Outgoing bundle. + IntEqClasses EC; + +public: + static char ID; + EdgeBundles() : MachineFunctionPass(ID) {} + + /// getBundle - Return the ingoing (Out = false) or outgoing (Out = true) + /// bundle number for basic block #N + unsigned getBundle(unsigned N, bool Out) const { return EC[2 * N + Out]; } + + /// getNumBundles - Return the total number of bundles in the CFG. + unsigned getNumBundles() const { return EC.getNumClasses(); } + + /// getMachineFunction - Return the last machine function computed. + const MachineFunction *getMachineFunction() const { return MF; } + + /// view - Visualize the annotated bipartite CFG with Graphviz. + void view() const; + +private: + virtual bool runOnMachineFunction(MachineFunction&); + virtual void getAnalysisUsage(AnalysisUsage&) const; +}; + +/// Specialize WriteGraph, the standard implementation won't work. +raw_ostream &WriteGraph(raw_ostream &O, const EdgeBundles &G, + bool ShortNames = false, + const std::string &Title = ""); + +} // end namespace llvm + +#endif diff --git a/include/llvm/CodeGen/FastISel.h b/include/llvm/CodeGen/FastISel.h index 79b1554e22ac..fbb12005444f 100644 --- a/include/llvm/CodeGen/FastISel.h +++ b/include/llvm/CodeGen/FastISel.h @@ -15,9 +15,6 @@ #define LLVM_CODEGEN_FASTISEL_H #include "llvm/ADT/DenseMap.h" -#ifndef NDEBUG -#include "llvm/ADT/SmallSet.h" -#endif #include "llvm/CodeGen/ValueTypes.h" #include "llvm/CodeGen/MachineBasicBlock.h" @@ -39,6 +36,7 @@ class TargetLowering; class TargetMachine; class TargetRegisterClass; class TargetRegisterInfo; +class LoadInst; /// FastISel - This is a fast-path instruction selection class that /// generates poor code and doesn't support illegal types or non-trivial @@ -102,7 +100,16 @@ public: /// index value. std::pair getRegForGEPIndex(const Value *V); - /// recomputeInsertPt - Reset InsertPt to prepare for insterting instructions + /// TryToFoldLoad - The specified machine instr operand is a vreg, and that + /// vreg is being provided by the specified load instruction. If possible, + /// try to fold the load as an operand to the instruction, returning true if + /// possible. + virtual bool TryToFoldLoad(MachineInstr * /*MI*/, unsigned /*OpNo*/, + const LoadInst * /*LI*/) { + return false; + } + + /// recomputeInsertPt - Reset InsertPt to prepare for inserting instructions /// into the current block. void recomputeInsertPt(); diff --git a/include/llvm/CodeGen/FunctionLoweringInfo.h b/include/llvm/CodeGen/FunctionLoweringInfo.h index f17fe5a146fc..27631b7ea12f 100644 --- a/include/llvm/CodeGen/FunctionLoweringInfo.h +++ b/include/llvm/CodeGen/FunctionLoweringInfo.h @@ -19,6 +19,7 @@ #include "llvm/Instructions.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IndexedMap.h" #include "llvm/ADT/SmallVector.h" #ifndef NDEBUG #include "llvm/ADT/SmallSet.h" @@ -27,6 +28,7 @@ #include "llvm/CodeGen/ISDOpcodes.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/Support/CallSite.h" +#include "llvm/Target/TargetRegisterInfo.h" #include namespace llvm { @@ -104,9 +106,8 @@ public: LiveOutInfo() : NumSignBits(0), KnownOne(1, 0), KnownZero(1, 0) {} }; - /// LiveOutRegInfo - Information about live out vregs, indexed by their - /// register number offset by 'FirstVirtualRegister'. - std::vector LiveOutRegInfo; + /// LiveOutRegInfo - Information about live out vregs. + IndexedMap LiveOutRegInfo; /// PHINodesToUpdate - A list of phi instructions whose operand list will /// be updated after processing the current basic block. diff --git a/include/llvm/CodeGen/GCMetadata.h b/include/llvm/CodeGen/GCMetadata.h index b401068140b0..45469ed7de80 100644 --- a/include/llvm/CodeGen/GCMetadata.h +++ b/include/llvm/CodeGen/GCMetadata.h @@ -36,6 +36,7 @@ #include "llvm/Pass.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" +#include "llvm/Support/DebugLoc.h" namespace llvm { class AsmPrinter; @@ -59,8 +60,10 @@ namespace llvm { struct GCPoint { GC::PointKind Kind; //< The kind of the safe point. MCSymbol *Label; //< A label. + DebugLoc Loc; - GCPoint(GC::PointKind K, MCSymbol *L) : Kind(K), Label(L) {} + GCPoint(GC::PointKind K, MCSymbol *L, DebugLoc DL) + : Kind(K), Label(L), Loc(DL) {} }; /// GCRoot - Metadata for a pointer to an object managed by the garbage @@ -121,8 +124,8 @@ namespace llvm { /// addSafePoint - Notes the existence of a safe point. Num is the ID of the /// label just prior to the safe point (if the code generator is using /// MachineModuleInfo). - void addSafePoint(GC::PointKind Kind, MCSymbol *Label) { - SafePoints.push_back(GCPoint(Kind, Label)); + void addSafePoint(GC::PointKind Kind, MCSymbol *Label, DebugLoc DL) { + SafePoints.push_back(GCPoint(Kind, Label, DL)); } /// getFrameSize/setFrameSize - Records the function's frame size. diff --git a/include/llvm/CodeGen/ISDOpcodes.h b/include/llvm/CodeGen/ISDOpcodes.h index 2e23f4e44e32..3da11c4a0e0f 100644 --- a/include/llvm/CodeGen/ISDOpcodes.h +++ b/include/llvm/CodeGen/ISDOpcodes.h @@ -107,6 +107,13 @@ namespace ISD { // and returns an outchain. EH_SJLJ_LONGJMP, + // OUTCHAIN = EH_SJLJ_DISPATCHSETUP(INCHAIN, context) + // This corresponds to the eh.sjlj.dispatchsetup intrinsic. It takes an + // input chain and a pointer to the sjlj function context as inputs and + // returns an outchain. By default, this does nothing. Targets can lower + // this to unwind setup code if needed. + EH_SJLJ_DISPATCHSETUP, + // TargetConstant* - Like Constant*, but the DAG does not do any folding, // simplification, or lowering of the constant. They are used for constants // which are known to fit in the immediate fields of their users, or for @@ -262,16 +269,24 @@ namespace ISD { /// lengths of the input vectors. CONCAT_VECTORS, + /// INSERT_SUBVECTOR(VECTOR1, VECTOR2, IDX) - Returns a vector + /// with VECTOR2 inserted into VECTOR1 at the (potentially + /// variable) element number IDX, which must be a multiple of the + /// VECTOR2 vector length. The elements of VECTOR1 starting at + /// IDX are overwritten with VECTOR2. Elements IDX through + /// vector_length(VECTOR2) must be valid VECTOR1 indices. + INSERT_SUBVECTOR, + /// EXTRACT_SUBVECTOR(VECTOR, IDX) - Returns a subvector from VECTOR (an - /// vector value) starting with the (potentially variable) element number - /// IDX, which must be a multiple of the result vector length. + /// vector value) starting with the element number IDX, which must be a + /// constant multiple of the result vector length. EXTRACT_SUBVECTOR, - /// VECTOR_SHUFFLE(VEC1, VEC2) - Returns a vector, of the same type as + /// VECTOR_SHUFFLE(VEC1, VEC2) - Returns a vector, of the same type as /// VEC1/VEC2. A VECTOR_SHUFFLE node also contains an array of constant int /// values that indicate which value (or undef) each result element will - /// get. These constant ints are accessible through the - /// ShuffleVectorSDNode class. This is quite similar to the Altivec + /// get. These constant ints are accessible through the + /// ShuffleVectorSDNode class. This is quite similar to the Altivec /// 'vperm' instruction, except that the indices must be constants and are /// in terms of the element size of VEC1/VEC2, not in terms of bytes. VECTOR_SHUFFLE, @@ -288,13 +303,21 @@ namespace ISD { // an unsigned/signed value of type i[2*N], then return the top part. MULHU, MULHS, - // Bitwise operators - logical and, logical or, logical xor, shift left, - // shift right algebraic (shift in sign bits), shift right logical (shift in - // zeroes), rotate left, rotate right, and byteswap. - AND, OR, XOR, SHL, SRA, SRL, ROTL, ROTR, BSWAP, + /// Bitwise operators - logical and, logical or, logical xor. + AND, OR, XOR, + + /// Shift and rotation operations. After legalization, the type of the + /// shift amount is known to be TLI.getShiftAmountTy(). Before legalization + /// the shift amount can be any type, but care must be taken to ensure it is + /// large enough. TLI.getShiftAmountTy() is i8 on some targets, but before + /// legalization, types like i1024 can occur and i8 doesn't have enough bits + /// to represent the shift amount. By convention, DAGCombine and + /// SelectionDAGBuilder forces these shift amounts to i32 for simplicity. + /// + SHL, SRA, SRL, ROTL, ROTR, - // Counting operators - CTTZ, CTLZ, CTPOP, + /// Byte Swap and Counting operators. + BSWAP, CTTZ, CTLZ, CTPOP, // Select(COND, TRUEVAL, FALSEVAL). If the type of the boolean COND is not // i1 then the high bits must conform to getBooleanContents. @@ -392,14 +415,14 @@ namespace ISD { /// X = FP_EXTEND(Y) - Extend a smaller FP type into a larger FP type. FP_EXTEND, - // BIT_CONVERT - This operator converts between integer, vector and FP + // BITCAST - This operator converts between integer, vector and FP // values, as if the value was stored to memory with one type and loaded // from the same address with the other type (or equivalently for vector // format conversions, etc). The source and result are required to have // the same bit size (e.g. f32 <-> i32). This can also be used for // int-to-int or fp-to-fp conversions, but that is a noop, deleted by // getNode(). - BIT_CONVERT, + BITCAST, // CONVERT_RNDSAT - This operator is used to support various conversions // between various types (float, signed, unsigned and vectors of those @@ -475,6 +498,7 @@ namespace ISD { // Operand #0 : Input chain. // Operand #1 : a ExternalSymbolSDNode with a pointer to the asm string. // Operand #2 : a MDNodeSDNode with the !srcloc metadata. + // Operand #3 : HasSideEffect, IsAlignStack bits. // After this, it is followed by a list of operands with this format: // ConstantSDNode: Flags that encode whether it is a mem or not, the // of operands that follow, etc. See InlineAsm.h. @@ -525,7 +549,7 @@ namespace ISD { // SRCVALUE - This is a node type that holds a Value* that is used to // make reference to a value in the LLVM IR. SRCVALUE, - + // MDNODE_SDNODE - This is a node that holdes an MDNode*, which is used to // reference metadata in the IR. MDNODE_SDNODE, diff --git a/include/llvm/CodeGen/IntrinsicLowering.h b/include/llvm/CodeGen/IntrinsicLowering.h index eefbc45cb266..767b66622549 100644 --- a/include/llvm/CodeGen/IntrinsicLowering.h +++ b/include/llvm/CodeGen/IntrinsicLowering.h @@ -48,6 +48,11 @@ namespace llvm { /// be capable of handling this kind of change. /// void LowerIntrinsicCall(CallInst *CI); + + /// LowerToByteSwap - Replace a call instruction into a call to bswap + /// intrinsic. Return false if it has determined the call is not a + /// simple integer bswap. + static bool LowerToByteSwap(CallInst *CI); }; } diff --git a/include/llvm/CodeGen/JITCodeEmitter.h b/include/llvm/CodeGen/JITCodeEmitter.h index eb373fb145e8..fea852305158 100644 --- a/include/llvm/CodeGen/JITCodeEmitter.h +++ b/include/llvm/CodeGen/JITCodeEmitter.h @@ -18,7 +18,7 @@ #define LLVM_CODEGEN_JITCODEEMITTER_H #include -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/Support/MathExtras.h" #include "llvm/CodeGen/MachineCodeEmitter.h" #include "llvm/ADT/DenseMap.h" diff --git a/include/llvm/CodeGen/LatencyPriorityQueue.h b/include/llvm/CodeGen/LatencyPriorityQueue.h index 13cebeaf42f4..1ed2547ca6cf 100644 --- a/include/llvm/CodeGen/LatencyPriorityQueue.h +++ b/include/llvm/CodeGen/LatencyPriorityQueue.h @@ -20,25 +20,25 @@ namespace llvm { class LatencyPriorityQueue; - + /// Sorting functions for the Available queue. struct latency_sort : public std::binary_function { LatencyPriorityQueue *PQ; explicit latency_sort(LatencyPriorityQueue *pq) : PQ(pq) {} - + bool operator()(const SUnit* left, const SUnit* right) const; }; class LatencyPriorityQueue : public SchedulingPriorityQueue { // SUnits - The SUnits for the current graph. std::vector *SUnits; - + /// NumNodesSolelyBlocking - This vector contains, for every node in the /// Queue, the number of nodes that the node is the sole unscheduled /// predecessor for. This is used as a tie-breaker heuristic for better /// mobility. std::vector NumNodesSolelyBlocking; - + /// Queue - The queue. std::vector Queue; latency_sort Picker; @@ -47,6 +47,8 @@ namespace llvm { LatencyPriorityQueue() : Picker(this) { } + bool isBottomUp() const { return false; } + void initNodes(std::vector &sunits) { SUnits = &sunits; NumNodesSolelyBlocking.resize(SUnits->size(), 0); @@ -62,25 +64,27 @@ namespace llvm { void releaseState() { SUnits = 0; } - + unsigned getLatency(unsigned NodeNum) const { assert(NodeNum < (*SUnits).size()); return (*SUnits)[NodeNum].getHeight(); } - + unsigned getNumSolelyBlockNodes(unsigned NodeNum) const { assert(NodeNum < NumNodesSolelyBlocking.size()); return NumNodesSolelyBlocking[NodeNum]; } - + bool empty() const { return Queue.empty(); } - + virtual void push(SUnit *U); - + virtual SUnit *pop(); virtual void remove(SUnit *SU); + virtual void dump(ScheduleDAG* DAG) const; + // ScheduledNode - As nodes are scheduled, we look to see if there are any // successor nodes that have a single unscheduled predecessor. If so, that // single predecessor has a higher priority, since scheduling it will make diff --git a/include/llvm/CodeGen/LinkAllCodegenComponents.h b/include/llvm/CodeGen/LinkAllCodegenComponents.h index cd8293de5069..c931261f6332 100644 --- a/include/llvm/CodeGen/LinkAllCodegenComponents.h +++ b/include/llvm/CodeGen/LinkAllCodegenComponents.h @@ -34,8 +34,10 @@ namespace { (void) llvm::createDeadMachineInstructionElimPass(); (void) llvm::createFastRegisterAllocator(); + (void) llvm::createBasicRegisterAllocator(); (void) llvm::createLinearScanRegisterAllocator(); - (void) llvm::createPBQPRegisterAllocator(); + (void) llvm::createGreedyRegisterAllocator(); + (void) llvm::createDefaultPBQPRegisterAllocator(); (void) llvm::createSimpleRegisterCoalescer(); diff --git a/include/llvm/CodeGen/LiveInterval.h b/include/llvm/CodeGen/LiveInterval.h index 29e689a52145..88131fbc40ff 100644 --- a/include/llvm/CodeGen/LiveInterval.h +++ b/include/llvm/CodeGen/LiveInterval.h @@ -21,7 +21,7 @@ #ifndef LLVM_CODEGEN_LIVEINTERVAL_H #define LLVM_CODEGEN_LIVEINTERVAL_H -#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/IntEqClasses.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/AlignOf.h" #include "llvm/CodeGen/SlotIndexes.h" @@ -39,32 +39,17 @@ namespace llvm { /// This class holds information about a machine level values, including /// definition and use points. /// - /// Care must be taken in interpreting the def index of the value. The - /// following rules apply: - /// - /// If the isDefAccurate() method returns false then def does not contain the - /// index of the defining MachineInstr, or even (necessarily) to a - /// MachineInstr at all. In general such a def index is not meaningful - /// and should not be used. The exception is that, for values originally - /// defined by PHI instructions, after PHI elimination def will contain the - /// index of the MBB in which the PHI originally existed. This can be used - /// to insert code (spills or copies) which deals with the value, which will - /// be live in to the block. class VNInfo { private: enum { HAS_PHI_KILL = 1, REDEF_BY_EC = 1 << 1, IS_PHI_DEF = 1 << 2, - IS_UNUSED = 1 << 3, - IS_DEF_ACCURATE = 1 << 4 + IS_UNUSED = 1 << 3 }; + MachineInstr *copy; unsigned char flags; - union { - MachineInstr *copy; - unsigned reg; - } cr; public: typedef BumpPtrAllocator Allocator; @@ -76,20 +61,19 @@ namespace llvm { SlotIndex def; /// VNInfo constructor. - /// d is presumed to point to the actual defining instr. If it doesn't - /// setIsDefAccurate(false) should be called after construction. VNInfo(unsigned i, SlotIndex d, MachineInstr *c) - : flags(IS_DEF_ACCURATE), id(i), def(d) { cr.copy = c; } + : copy(c), flags(0), id(i), def(d) + { } /// VNInfo construtor, copies values from orig, except for the value number. VNInfo(unsigned i, const VNInfo &orig) - : flags(orig.flags), cr(orig.cr), id(i), def(orig.def) + : copy(orig.copy), flags(orig.flags), id(i), def(orig.def) { } /// Copy from the parameter into this VNInfo. void copyFrom(VNInfo &src) { flags = src.flags; - cr = src.cr; + copy = src.copy; def = src.def; } @@ -97,23 +81,23 @@ namespace llvm { unsigned getFlags() const { return flags; } void setFlags(unsigned flags) { this->flags = flags; } + /// Merge flags from another VNInfo + void mergeFlags(const VNInfo *VNI) { + flags = (flags | VNI->flags) & ~IS_UNUSED; + } + /// For a register interval, if this VN was definied by a copy instr /// getCopy() returns a pointer to it, otherwise returns 0. /// For a stack interval the behaviour of this method is undefined. - MachineInstr* getCopy() const { return cr.copy; } + MachineInstr* getCopy() const { return copy; } /// For a register interval, set the copy member. /// This method should not be called on stack intervals as it may lead to /// undefined behavior. - void setCopy(MachineInstr *c) { cr.copy = c; } + void setCopy(MachineInstr *c) { copy = c; } - /// For a stack interval, returns the reg which this stack interval was - /// defined from. - /// For a register interval the behaviour of this method is undefined. - unsigned getReg() const { return cr.reg; } - /// For a stack interval, set the defining register. - /// This method should not be called on register intervals as it may lead - /// to undefined behaviour. - void setReg(unsigned reg) { cr.reg = reg; } + /// isDefByCopy - Return true when this value was defined by a copy-like + /// instruction as determined by MachineInstr::isCopyLike. + bool isDefByCopy() const { return copy != 0; } /// Returns true if one or more kills are PHI nodes. bool hasPHIKill() const { return flags & HAS_PHI_KILL; } @@ -156,16 +140,6 @@ namespace llvm { else flags &= ~IS_UNUSED; } - - /// Returns true if the def is accurate. - bool isDefAccurate() const { return flags & IS_DEF_ACCURATE; } - /// Set the "is def accurate" flag on this value. - void setIsDefAccurate(bool defAccurate) { - if (defAccurate) - flags |= IS_DEF_ACCURATE; - else - flags &= ~IS_DEF_ACCURATE; - } }; /// LiveRange structure - This represents a simple register range in the @@ -231,8 +205,7 @@ namespace llvm { typedef SmallVector Ranges; typedef SmallVector VNInfoList; - unsigned reg; // the register or stack slot of this interval - // if the top bits is set, it represents a stack slot. + const unsigned reg; // the register or stack slot of this interval. float weight; // weight of this interval Ranges ranges; // the ranges in which this register is live VNInfoList valnos; // value#'s @@ -248,11 +221,8 @@ namespace llvm { }; - LiveInterval(unsigned Reg, float Weight, bool IsSS = false) - : reg(Reg), weight(Weight) { - if (IsSS) - reg = reg | (1U << (sizeof(unsigned)*CHAR_BIT-1)); - } + LiveInterval(unsigned Reg, float Weight) + : reg(Reg), weight(Weight) {} typedef Ranges::iterator iterator; iterator begin() { return ranges.begin(); } @@ -276,28 +246,29 @@ namespace llvm { /// position is in a hole, this method returns an iterator pointing to the /// LiveRange immediately after the hole. iterator advanceTo(iterator I, SlotIndex Pos) { + assert(I != end()); if (Pos >= endIndex()) return end(); while (I->end <= Pos) ++I; return I; } - void clear() { - valnos.clear(); - ranges.clear(); - } - - /// isStackSlot - Return true if this is a stack slot interval. + /// find - Return an iterator pointing to the first range that ends after + /// Pos, or end(). This is the same as advanceTo(begin(), Pos), but faster + /// when searching large intervals. /// - bool isStackSlot() const { - return reg & (1U << (sizeof(unsigned)*CHAR_BIT-1)); + /// If Pos is contained in a LiveRange, that range is returned. + /// If Pos is in a hole, the following LiveRange is returned. + /// If Pos is beyond endIndex, end() is returned. + iterator find(SlotIndex Pos); + + const_iterator find(SlotIndex Pos) const { + return const_cast(this)->find(Pos); } - /// getStackSlotIndex - Return stack slot index if this is a stack slot - /// interval. - int getStackSlotIndex() const { - assert(isStackSlot() && "Interval is not a stack slot interval!"); - return reg & ~(1U << (sizeof(unsigned)*CHAR_BIT-1)); + void clear() { + valnos.clear(); + ranges.clear(); } bool hasAtLeastOneValue() const { return !valnos.empty(); } @@ -318,10 +289,9 @@ namespace llvm { /// getNextValue - Create a new value number and return it. MIIdx specifies /// the instruction that defines the value number. VNInfo *getNextValue(SlotIndex def, MachineInstr *CopyMI, - bool isDefAccurate, VNInfo::Allocator &VNInfoAllocator) { + VNInfo::Allocator &VNInfoAllocator) { VNInfo *VNI = new (VNInfoAllocator) VNInfo((unsigned)valnos.size(), def, CopyMI); - VNI->setIsDefAccurate(isDefAccurate); valnos.push_back(VNI); return VNI; } @@ -358,21 +328,6 @@ namespace llvm { /// cause merging of V1/V2 values numbers and compaction of the value space. VNInfo* MergeValueNumberInto(VNInfo *V1, VNInfo *V2); - /// MergeInClobberRanges - For any live ranges that are not defined in the - /// current interval, but are defined in the Clobbers interval, mark them - /// used with an unknown definition value. Caller must pass in reference to - /// VNInfoAllocator since it will create a new val#. - void MergeInClobberRanges(LiveIntervals &li_, - const LiveInterval &Clobbers, - VNInfo::Allocator &VNInfoAllocator); - - /// MergeInClobberRange - Same as MergeInClobberRanges except it merge in a - /// single LiveRange only. - void MergeInClobberRange(LiveIntervals &li_, - SlotIndex Start, - SlotIndex End, - VNInfo::Allocator &VNInfoAllocator); - /// MergeValueInAsValue - Merge all of the live ranges of a specific val# /// in RHS into this live interval as the specified value number. /// The LiveRanges in RHS are allowed to overlap with LiveRanges in the @@ -412,17 +367,18 @@ namespace llvm { return index >= endIndex(); } - bool liveAt(SlotIndex index) const; - - // liveBeforeAndAt - Check if the interval is live at the index and the - // index just before it. If index is liveAt, check if it starts a new live - // range.If it does, then check if the previous live range ends at index-1. - bool liveBeforeAndAt(SlotIndex index) const; + bool liveAt(SlotIndex index) const { + const_iterator r = find(index); + return r != end() && r->start <= index; + } /// killedAt - Return true if a live range ends at index. Note that the kill /// point is not contained in the half-open live range. It is usually the /// getDefIndex() slot following its last use. - bool killedAt(SlotIndex index) const; + bool killedAt(SlotIndex index) const { + const_iterator r = find(index.getUseIndex()); + return r != end() && r->end == index; + } /// killedInRange - Return true if the interval has kills in [Start,End). /// Note that the kill point is considered the end of a live range, so it is @@ -452,20 +408,20 @@ namespace llvm { /// FindLiveRangeContaining - Return an iterator to the live range that /// contains the specified index, or end() if there is none. - const_iterator FindLiveRangeContaining(SlotIndex Idx) const; + iterator FindLiveRangeContaining(SlotIndex Idx) { + iterator I = find(Idx); + return I != end() && I->start <= Idx ? I : end(); + } - /// FindLiveRangeContaining - Return an iterator to the live range that - /// contains the specified index, or end() if there is none. - iterator FindLiveRangeContaining(SlotIndex Idx); + const_iterator FindLiveRangeContaining(SlotIndex Idx) const { + const_iterator I = find(Idx); + return I != end() && I->start <= Idx ? I : end(); + } /// findDefinedVNInfo - Find the by the specified /// index (register interval) or defined VNInfo *findDefinedVNInfoForRegInt(SlotIndex Idx) const; - /// findDefinedVNInfo - Find the VNInfo that's defined by the specified - /// register (stack inteval only). - VNInfo *findDefinedVNInfoForStackInt(unsigned Reg) const; - /// overlaps - Return true if the intersection of the two live intervals is /// not empty. @@ -502,7 +458,10 @@ namespace llvm { /// isInOneLiveRange - Return true if the range specified is entirely in the /// a single LiveRange of the live interval. - bool isInOneLiveRange(SlotIndex Start, SlotIndex End); + bool isInOneLiveRange(SlotIndex Start, SlotIndex End) const { + const_iterator r = find(Start); + return r != end() && r->containsRange(Start, End); + } /// removeRange - Remove the specified range from this interval. Note that /// the range must be a single LiveRange in its entirety. @@ -569,6 +528,46 @@ namespace llvm { LI.print(OS); return OS; } -} + /// ConnectedVNInfoEqClasses - Helper class that can divide VNInfos in a + /// LiveInterval into equivalence clases of connected components. A + /// LiveInterval that has multiple connected components can be broken into + /// multiple LiveIntervals. + /// + /// Given a LiveInterval that may have multiple connected components, run: + /// + /// unsigned numComps = ConEQ.Classify(LI); + /// if (numComps > 1) { + /// // allocate numComps-1 new LiveIntervals into LIS[1..] + /// ConEQ.Distribute(LIS); + /// } + + class ConnectedVNInfoEqClasses { + LiveIntervals &lis_; + IntEqClasses eqClass_; + + // Note that values a and b are connected. + void Connect(unsigned a, unsigned b); + + unsigned Renumber(); + + public: + explicit ConnectedVNInfoEqClasses(LiveIntervals &lis) : lis_(lis) {} + + /// Classify - Classify the values in LI into connected components. + /// Return the number of connected components. + unsigned Classify(const LiveInterval *LI); + + /// getEqClass - Classify creates equivalence classes numbered 0..N. Return + /// the equivalence class assigned the VNI. + unsigned getEqClass(const VNInfo *VNI) const { return eqClass_[VNI->id]; } + + /// Distribute - Distribute values in LIV[0] into a separate LiveInterval + /// for each connected component. LIV must have a LiveInterval for each + /// connected component. The LiveIntervals in Liv[1..] must be empty. + void Distribute(LiveInterval *LIV[]); + + }; + +} #endif diff --git a/include/llvm/CodeGen/LiveIntervalAnalysis.h b/include/llvm/CodeGen/LiveIntervalAnalysis.h index 2918c3c2abe8..b09f8d111066 100644 --- a/include/llvm/CodeGen/LiveIntervalAnalysis.h +++ b/include/llvm/CodeGen/LiveIntervalAnalysis.h @@ -68,19 +68,13 @@ namespace llvm { public: static char ID; // Pass identification, replacement for typeid - LiveIntervals() : MachineFunctionPass(ID) {} + LiveIntervals() : MachineFunctionPass(ID) { + initializeLiveIntervalsPass(*PassRegistry::getPassRegistry()); + } // Calculate the spill weight to assign to a single instruction. static float getSpillWeight(bool isDef, bool isUse, unsigned loopDepth); - // After summing the spill weights of all defs and uses, the final weight - // should be normalized, dividing the weight of the interval by its size. - // This encourages spilling of intervals that are large and have few uses, - // and discourages spilling of small intervals with many uses. - void normalizeSpillWeight(LiveInterval &li) { - li.weight /= getApproximateInstructionCount(li) + 25; - } - typedef Reg2IntervalMap::iterator iterator; typedef Reg2IntervalMap::const_iterator const_iterator; const_iterator begin() const { return r2iMap_.begin(); } @@ -161,6 +155,12 @@ namespace llvm { LiveRange addLiveRangeToEndOfBlock(unsigned reg, MachineInstr* startInst); + /// shrinkToUses - After removing some uses of a register, shrink its live + /// range to just the remaining uses. This method does not compute reaching + /// defs for new uses, and it doesn't remove dead defs. + /// Dead PHIDef values are marked as unused. + void shrinkToUses(LiveInterval *li); + // Interval removal void removeInterval(unsigned Reg) { @@ -169,6 +169,10 @@ namespace llvm { r2iMap_.erase(I); } + SlotIndexes *getSlotIndexes() const { + return indexes_; + } + SlotIndex getZeroIndex() const { return indexes_->getZeroIndex(); } @@ -227,10 +231,6 @@ namespace llvm { return indexes_->getMBBFromIndex(index); } - SlotIndex getMBBTerminatorGap(const MachineBasicBlock *mbb) { - return indexes_->getTerminatorGap(mbb); - } - SlotIndex InsertMachineInstrInMaps(MachineInstr *MI) { return indexes_->insertMachineInstrInMaps(MI); } @@ -272,7 +272,7 @@ namespace llvm { /// (if any is created) by reference. This is temporary. std::vector addIntervalsForSpills(const LiveInterval& i, - SmallVectorImpl &SpillIs, + const SmallVectorImpl &SpillIs, const MachineLoopInfo *loopInfo, VirtRegMap& vrm); /// spillPhysRegAroundRegDefsUses - Spill the specified physical register @@ -285,7 +285,7 @@ namespace llvm { /// val# of the specified interval is re-materializable. Also returns true /// by reference if all of the defs are load instructions. bool isReMaterializable(const LiveInterval &li, - SmallVectorImpl &SpillIs, + const SmallVectorImpl &SpillIs, bool &isLoad); /// isReMaterializable - Returns true if the definition MI of the specified @@ -306,6 +306,16 @@ namespace llvm { /// within a single basic block. bool intervalIsInOneMBB(const LiveInterval &li) const; + /// getLastSplitPoint - Return the last possible insertion point in mbb for + /// spilling and splitting code. This is the first terminator, or the call + /// instruction if li is live into a landing pad successor. + MachineBasicBlock::iterator getLastSplitPoint(const LiveInterval &li, + MachineBasicBlock *mbb) const; + + /// addKillFlags - Add kill flags to any instruction that kills a virtual + /// register. + void addKillFlags(); + private: /// computeIntervals - Compute live intervals. void computeIntervals(); @@ -362,7 +372,7 @@ namespace llvm { /// by reference if the def is a load. bool isReMaterializable(const LiveInterval &li, const VNInfo *ValNo, MachineInstr *MI, - SmallVectorImpl &SpillIs, + const SmallVectorImpl &SpillIs, bool &isLoad); /// tryFoldMemoryOperand - Attempts to fold either a spill / restore from @@ -443,9 +453,6 @@ namespace llvm { DenseMap &MBBVRegsMap, std::vector &NewLIs); - // Normalize the spill weight of all the intervals in NewLIs. - void normalizeSpillWeights(std::vector &NewLIs); - static LiveInterval* createInterval(unsigned Reg); void printInstrs(raw_ostream &O) const; diff --git a/include/llvm/CodeGen/LiveStackAnalysis.h b/include/llvm/CodeGen/LiveStackAnalysis.h index ad984db1899e..8a8dcaf5728f 100644 --- a/include/llvm/CodeGen/LiveStackAnalysis.h +++ b/include/llvm/CodeGen/LiveStackAnalysis.h @@ -39,7 +39,9 @@ namespace llvm { public: static char ID; // Pass identification, replacement for typeid - LiveStacks() : MachineFunctionPass(ID) {} + LiveStacks() : MachineFunctionPass(ID) { + initializeLiveStacksPass(*PassRegistry::getPassRegistry()); + } typedef SS2IntervalMap::iterator iterator; typedef SS2IntervalMap::const_iterator const_iterator; @@ -50,19 +52,7 @@ namespace llvm { unsigned getNumIntervals() const { return (unsigned)S2IMap.size(); } - LiveInterval &getOrCreateInterval(int Slot, const TargetRegisterClass *RC) { - assert(Slot >= 0 && "Spill slot indice must be >= 0"); - SS2IntervalMap::iterator I = S2IMap.find(Slot); - if (I == S2IMap.end()) { - I = S2IMap.insert(I,std::make_pair(Slot, LiveInterval(Slot,0.0F,true))); - S2RCMap.insert(std::make_pair(Slot, RC)); - } else { - // Use the largest common subclass register class. - const TargetRegisterClass *OldRC = S2RCMap[Slot]; - S2RCMap[Slot] = getCommonSubClass(OldRC, RC); - } - return I->second; - } + LiveInterval &getOrCreateInterval(int Slot, const TargetRegisterClass *RC); LiveInterval &getInterval(int Slot) { assert(Slot >= 0 && "Spill slot indice must be >= 0"); diff --git a/include/llvm/CodeGen/LiveVariables.h b/include/llvm/CodeGen/LiveVariables.h index c8182e073b9c..f9b81b1ea7d6 100644 --- a/include/llvm/CodeGen/LiveVariables.h +++ b/include/llvm/CodeGen/LiveVariables.h @@ -32,8 +32,10 @@ #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" +#include "llvm/Target/TargetRegisterInfo.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IndexedMap.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SparseBitVector.h" @@ -46,7 +48,9 @@ class TargetRegisterInfo; class LiveVariables : public MachineFunctionPass { public: static char ID; // Pass identification, replacement for typeid - LiveVariables() : MachineFunctionPass(ID) {} + LiveVariables() : MachineFunctionPass(ID) { + initializeLiveVariablesPass(*PassRegistry::getPassRegistry()); + } /// VarInfo - This represents the regions where a virtual register is live in /// the program. We represent this with three different pieces of @@ -119,10 +123,9 @@ public: private: /// VirtRegInfo - This list is a mapping from virtual register number to - /// variable information. FirstVirtualRegister is subtracted from the virtual - /// register number before indexing into this list. + /// variable information. /// - std::vector VirtRegInfo; + IndexedMap VirtRegInfo; /// PHIJoins - list of virtual registers that are PHI joins. These registers /// may have multiple definitions, and they require special handling when diff --git a/include/llvm/CodeGen/MachORelocation.h b/include/llvm/CodeGen/MachORelocation.h index 27306c62d888..21fe74f8e1cd 100644 --- a/include/llvm/CodeGen/MachORelocation.h +++ b/include/llvm/CodeGen/MachORelocation.h @@ -15,7 +15,7 @@ #ifndef LLVM_CODEGEN_MACHO_RELOCATION_H #define LLVM_CODEGEN_MACHO_RELOCATION_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { diff --git a/include/llvm/CodeGen/MachineBasicBlock.h b/include/llvm/CodeGen/MachineBasicBlock.h index 3cfc47ac4d84..1785451c7ec5 100644 --- a/include/llvm/CodeGen/MachineBasicBlock.h +++ b/include/llvm/CodeGen/MachineBasicBlock.h @@ -23,6 +23,7 @@ class Pass; class BasicBlock; class MachineFunction; class MCSymbol; +class SlotIndexes; class StringRef; class raw_ostream; @@ -223,6 +224,10 @@ public: /// this basic block is entered via an exception handler. void setIsLandingPad() { IsLandingPad = true; } + /// getLandingPadSuccessor - If this block has a successor that is a landing + /// pad, return it. Otherwise return NULL. + const MachineBasicBlock *getLandingPadSuccessor() const; + // Code Layout methods. /// moveBefore/moveAfter - move 'this' block before or after the specified @@ -289,11 +294,20 @@ public: /// Returns end() is there's no non-PHI instruction. iterator getFirstNonPHI(); + /// SkipPHIsAndLabels - Return the first instruction in MBB after I that is + /// not a PHI or a label. This is the correct point to insert copies at the + /// beginning of a basic block. + iterator SkipPHIsAndLabels(iterator I); + /// getFirstTerminator - returns an iterator to the first terminator /// instruction of this basic block. If a terminator does not exist, /// it returns end() iterator getFirstTerminator(); + /// getLastNonDebugInstr - returns an iterator to the last non-debug + /// instruction in the basic block, or end() + iterator getLastNonDebugInstr(); + /// SplitCriticalEdge - Split the critical edge from this block to the /// given successor block, and return the newly created block, or null /// if splitting is not possible. @@ -308,6 +322,9 @@ public: template void insert(iterator I, IT S, IT E) { Insts.insert(I, S, E); } iterator insert(iterator I, MachineInstr *M) { return Insts.insert(I, M); } + iterator insertAfter(iterator I, MachineInstr *M) { + return Insts.insertAfter(I, M); + } // erase - Remove the specified element or range from the instruction list. // These functions delete any instructions removed. @@ -358,7 +375,7 @@ public: // Debugging methods. void dump() const; - void print(raw_ostream &OS) const; + void print(raw_ostream &OS, SlotIndexes* = 0) const; /// getNumber - MachineBasicBlocks are uniquely numbered at the function /// level, unless they're not in a MachineFunction yet, in which case this diff --git a/include/llvm/CodeGen/MachineCodeEmitter.h b/include/llvm/CodeGen/MachineCodeEmitter.h index 7abb49a219ef..8fc80adf7fb8 100644 --- a/include/llvm/CodeGen/MachineCodeEmitter.h +++ b/include/llvm/CodeGen/MachineCodeEmitter.h @@ -17,7 +17,7 @@ #ifndef LLVM_CODEGEN_MACHINECODEEMITTER_H #define LLVM_CODEGEN_MACHINECODEEMITTER_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/Support/DebugLoc.h" namespace llvm { diff --git a/include/llvm/CodeGen/MachineCodeInfo.h b/include/llvm/CodeGen/MachineCodeInfo.h index a75c02a052e7..c5c0c4450454 100644 --- a/include/llvm/CodeGen/MachineCodeInfo.h +++ b/include/llvm/CodeGen/MachineCodeInfo.h @@ -17,7 +17,7 @@ #ifndef EE_MACHINE_CODE_INFO_H #define EE_MACHINE_CODE_INFO_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { diff --git a/include/llvm/CodeGen/MachineDominators.h b/include/llvm/CodeGen/MachineDominators.h index 48695d500b19..ab944a2335f7 100644 --- a/include/llvm/CodeGen/MachineDominators.h +++ b/include/llvm/CodeGen/MachineDominators.h @@ -145,7 +145,7 @@ public: } /// eraseNode - Removes a node from the dominator tree. Block must not - /// domiante any other blocks. Removes node from its immediate dominator's + /// dominate any other blocks. Removes node from its immediate dominator's /// children list. Deletes dominator node associated with basic block BB. inline void eraseNode(MachineBasicBlock *BB) { DT->eraseNode(BB); diff --git a/include/llvm/CodeGen/MachineFrameInfo.h b/include/llvm/CodeGen/MachineFrameInfo.h index dca65ef6d407..22a82a9d6e75 100644 --- a/include/llvm/CodeGen/MachineFrameInfo.h +++ b/include/llvm/CodeGen/MachineFrameInfo.h @@ -16,7 +16,7 @@ #include "llvm/ADT/SmallVector.h" //#include "llvm/ADT/IndexedMap.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include #include @@ -27,7 +27,7 @@ class TargetRegisterClass; class Type; class MachineFunction; class MachineBasicBlock; -class TargetFrameInfo; +class TargetFrameLowering; class BitVector; /// The CalleeSavedInfo class tracks the information need to locate where a @@ -192,13 +192,9 @@ class MachineFrameInfo { /// CSIValid - Has CSInfo been set yet? bool CSIValid; - /// SpillObjects - A vector indicating which frame indices refer to - /// spill slots. - SmallVector SpillObjects; - - /// TargetFrameInfo - Target information about frame layout. + /// TargetFrameLowering - Target information about frame layout. /// - const TargetFrameInfo &TFI; + const TargetFrameLowering &TFI; /// LocalFrameObjects - References to frame indices which are mapped /// into the local frame allocation block. @@ -217,7 +213,7 @@ class MachineFrameInfo { bool UseLocalStackAllocationBlock; public: - explicit MachineFrameInfo(const TargetFrameInfo &tfi) : TFI(tfi) { + explicit MachineFrameInfo(const TargetFrameLowering &tfi) : TFI(tfi) { StackSize = NumFixedObjects = OffsetAdjustment = MaxAlignment = 0; HasVarSizedObjects = false; FrameAddressTaken = false; diff --git a/include/llvm/CodeGen/MachineFunction.h b/include/llvm/CodeGen/MachineFunction.h index 5bb453dd50fa..abeaa4f58d3d 100644 --- a/include/llvm/CodeGen/MachineFunction.h +++ b/include/llvm/CodeGen/MachineFunction.h @@ -28,6 +28,7 @@ namespace llvm { class Value; class Function; +class GCModuleInfo; class MachineRegisterInfo; class MachineFrameInfo; class MachineConstantPool; @@ -37,6 +38,7 @@ class MCContext; class Pass; class TargetMachine; class TargetRegisterClass; +struct MachinePointerInfo; template <> struct ilist_traits @@ -74,6 +76,7 @@ class MachineFunction { const TargetMachine &Target; MCContext &Ctx; MachineModuleInfo &MMI; + GCModuleInfo *GMI; // RegInfo - Information about each register in use in the function. MachineRegisterInfo *RegInfo; @@ -126,10 +129,12 @@ class MachineFunction { void operator=(const MachineFunction&); // DO NOT IMPLEMENT public: MachineFunction(const Function *Fn, const TargetMachine &TM, - unsigned FunctionNum, MachineModuleInfo &MMI); + unsigned FunctionNum, MachineModuleInfo &MMI, + GCModuleInfo* GMI); ~MachineFunction(); MachineModuleInfo &getMMI() const { return MMI; } + GCModuleInfo *getGMI() const { return GMI; } MCContext &getContext() const { return Ctx; } /// getFunction - Return the LLVM function that this machine code represents @@ -243,7 +248,7 @@ public: /// print - Print out the MachineFunction in a format suitable for debugging /// to the specified stream. /// - void print(raw_ostream &OS) const; + void print(raw_ostream &OS, SlotIndexes* = 0) const; /// viewCFG - This function is meant for use from the debugger. You can just /// say 'call F->viewCFG()' and a ghostview window should pop up from the @@ -266,7 +271,7 @@ public: /// verify - Run the current MachineFunction through the machine code /// verifier, useful for debugger use. - void verify(Pass *p=NULL) const; + void verify(Pass *p = NULL, const char *Banner = NULL) const; // Provide accessors for the MachineBasicBlock list... typedef BasicBlockListType::iterator iterator; @@ -276,7 +281,7 @@ public: /// addLiveIn - Add the specified physical register as a live-in value and /// create a corresponding virtual register for it. - unsigned addLiveIn(unsigned PReg, const TargetRegisterClass *RC); + unsigned addLiveIn(unsigned PReg, const TargetRegisterClass *RC, DebugLoc DL); //===--------------------------------------------------------------------===// // BasicBlock accessor functions. @@ -368,10 +373,11 @@ public: /// getMachineMemOperand - Allocate a new MachineMemOperand. /// MachineMemOperands are owned by the MachineFunction and need not be /// explicitly deallocated. - MachineMemOperand *getMachineMemOperand(const Value *v, unsigned f, - int64_t o, uint64_t s, - unsigned base_alignment); - + MachineMemOperand *getMachineMemOperand(MachinePointerInfo PtrInfo, + unsigned f, uint64_t s, + unsigned base_alignment, + const MDNode *TBAAInfo = 0); + /// getMachineMemOperand - Allocate a new MachineMemOperand by copying /// an existing one, adjusting by an offset and using the given size. /// MachineMemOperands are owned by the MachineFunction and need not be @@ -406,6 +412,10 @@ public: /// normal 'L' label is returned. MCSymbol *getJTISymbol(unsigned JTI, MCContext &Ctx, bool isLinkerPrivate = false) const; + + /// getPICBaseSymbol - Return a function-local symbol to represent the PIC + /// base. + MCSymbol *getPICBaseSymbol() const; }; //===--------------------------------------------------------------------===// diff --git a/include/llvm/CodeGen/MachineFunctionAnalysis.h b/include/llvm/CodeGen/MachineFunctionAnalysis.h index 75dbaab973d8..50676ad4ad49 100644 --- a/include/llvm/CodeGen/MachineFunctionAnalysis.h +++ b/include/llvm/CodeGen/MachineFunctionAnalysis.h @@ -37,6 +37,10 @@ public: MachineFunction &getMF() const { return *MF; } CodeGenOpt::Level getOptLevel() const { return OptLevel; } + + virtual const char* getPassName() const { + return "Machine Function Analysis"; + } private: virtual bool doInitialization(Module &M); diff --git a/include/llvm/CodeGen/MachineInstr.h b/include/llvm/CodeGen/MachineInstr.h index f843196105dd..82c5332ccd9f 100644 --- a/include/llvm/CodeGen/MachineInstr.h +++ b/include/llvm/CodeGen/MachineInstr.h @@ -127,6 +127,10 @@ public: /// unsigned short getAsmPrinterFlags() const { return AsmPrinterFlags; } + /// clearAsmPrinterFlags - clear the AsmPrinter bitvector + /// + void clearAsmPrinterFlags() { AsmPrinterFlags = 0; } + /// getAsmPrinterFlag - Return whether an AsmPrinter flag is set. /// bool getAsmPrinterFlag(CommentFlag Flag) const { @@ -138,6 +142,12 @@ public: void setAsmPrinterFlag(CommentFlag Flag) { AsmPrinterFlags |= (unsigned short)Flag; } + + /// clearAsmPrinterFlag - clear specific AsmPrinter flags + /// + void clearAsmPrinterFlag(CommentFlag Flag) { + AsmPrinterFlags &= ~Flag; + } /// getDebugLoc - Returns the debug location id of this MachineInstr. /// @@ -167,7 +177,17 @@ public: /// getNumExplicitOperands - Returns the number of non-implicit operands. /// unsigned getNumExplicitOperands() const; - + + /// iterator/begin/end - Iterate over all operands of a machine instruction. + typedef std::vector::iterator mop_iterator; + typedef std::vector::const_iterator const_mop_iterator; + + mop_iterator operands_begin() { return Operands.begin(); } + mop_iterator operands_end() { return Operands.end(); } + + const_mop_iterator operands_begin() const { return Operands.begin(); } + const_mop_iterator operands_end() const { return Operands.end(); } + /// Access to memory operands of the instruction mmo_iterator memoperands_begin() const { return MemRefs; } mmo_iterator memoperands_end() const { return MemRefsEnd; } @@ -217,6 +237,7 @@ public: bool isKill() const { return getOpcode() == TargetOpcode::KILL; } bool isImplicitDef() const { return getOpcode()==TargetOpcode::IMPLICIT_DEF; } bool isInlineAsm() const { return getOpcode() == TargetOpcode::INLINEASM; } + bool isStackAligningInlineAsm() const; bool isInsertSubreg() const { return getOpcode() == TargetOpcode::INSERT_SUBREG; } @@ -412,10 +433,23 @@ public: /// return 0. unsigned isConstantValuePHI() const; + /// hasUnmodeledSideEffects - Return true if this instruction has side + /// effects that are not modeled by mayLoad / mayStore, etc. + /// For all instructions, the property is encoded in TargetInstrDesc::Flags + /// (see TargetInstrDesc::hasUnmodeledSideEffects(). The only exception is + /// INLINEASM instruction, in which case the side effect property is encoded + /// in one of its operands (see InlineAsm::Extra_HasSideEffect). + /// + bool hasUnmodeledSideEffects() const; + /// allDefsAreDead - Return true if all the defs of this instruction are dead. /// bool allDefsAreDead() const; + /// copyImplicitOps - Copy implicit register operands from specified + /// instruction to this instruction. + void copyImplicitOps(const MachineInstr *MI); + // // Debugging support // diff --git a/include/llvm/CodeGen/MachineInstrBuilder.h b/include/llvm/CodeGen/MachineInstrBuilder.h index 37ac24cab841..1eb97353088f 100644 --- a/include/llvm/CodeGen/MachineInstrBuilder.h +++ b/include/llvm/CodeGen/MachineInstrBuilder.h @@ -18,6 +18,7 @@ #define LLVM_CODEGEN_MACHINEINSTRBUILDER_H #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/Support/ErrorHandling.h" namespace llvm { @@ -122,6 +123,13 @@ public: return *this; } + const MachineInstrBuilder &setMemRefs(MachineInstr::mmo_iterator b, + MachineInstr::mmo_iterator e) const { + MI->setMemRefs(b, e); + return *this; + } + + const MachineInstrBuilder &addOperand(const MachineOperand &MO) const { MI->addOperand(MO); return *this; @@ -136,6 +144,19 @@ public: MI->addOperand(MachineOperand::CreateMCSymbol(Sym)); return *this; } + + // Add a displacement from an existing MachineOperand with an added offset. + const MachineInstrBuilder &addDisp(const MachineOperand &Disp, + int64_t off) const { + switch (Disp.getType()) { + default: + llvm_unreachable("Unhandled operand type in addDisp()"); + case MachineOperand::MO_Immediate: + return addImm(Disp.getImm() + off); + case MachineOperand::MO_GlobalAddress: + return addGlobalAddress(Disp.getGlobal(), Disp.getOffset() + off); + } + } }; /// BuildMI - Builder interface. Specify how to create the initial instruction diff --git a/include/llvm/CodeGen/MachineLocation.h b/include/llvm/CodeGen/MachineLocation.h index a1fcb9fe7576..21951b6680b6 100644 --- a/include/llvm/CodeGen/MachineLocation.h +++ b/include/llvm/CodeGen/MachineLocation.h @@ -32,7 +32,7 @@ private: public: enum { // The target register number for an abstract frame pointer. The value is - // an arbitrary value greater than TargetRegisterInfo::FirstVirtualRegister. + // an arbitrary value that doesn't collide with any real target register. VirtualFP = ~0U }; MachineLocation() @@ -41,6 +41,11 @@ public: : IsRegister(true), Register(R), Offset(0) {} MachineLocation(unsigned R, int O) : IsRegister(false), Register(R), Offset(O) {} + + bool operator==(const MachineLocation &Other) const { + return IsRegister == Other.IsRegister && Register == Other.Register && + Offset == Other.Offset; + } // Accessors bool isReg() const { return IsRegister; } diff --git a/include/llvm/CodeGen/MachineLoopInfo.h b/include/llvm/CodeGen/MachineLoopInfo.h index 9760eba7b86e..6dd9440500bf 100644 --- a/include/llvm/CodeGen/MachineLoopInfo.h +++ b/include/llvm/CodeGen/MachineLoopInfo.h @@ -67,7 +67,9 @@ class MachineLoopInfo : public MachineFunctionPass { public: static char ID; // Pass identification, replacement for typeid - MachineLoopInfo() : MachineFunctionPass(ID) {} + MachineLoopInfo() : MachineFunctionPass(ID) { + initializeMachineLoopInfoPass(*PassRegistry::getPassRegistry()); + } LoopInfoBase& getBase() { return LI; } diff --git a/include/llvm/CodeGen/MachineLoopRanges.h b/include/llvm/CodeGen/MachineLoopRanges.h new file mode 100644 index 000000000000..6a30e8b53c09 --- /dev/null +++ b/include/llvm/CodeGen/MachineLoopRanges.h @@ -0,0 +1,112 @@ +//===- MachineLoopRanges.h - Ranges of machine loops -----------*- c++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the interface to the MachineLoopRanges analysis. +// +// Provide on-demand information about the ranges of machine instructions +// covered by a loop. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_MACHINELOOPRANGES_H +#define LLVM_CODEGEN_MACHINELOOPRANGES_H + +#include "llvm/ADT/IntervalMap.h" +#include "llvm/CodeGen/SlotIndexes.h" + +namespace llvm { + +class MachineLoop; +class MachineLoopInfo; +class raw_ostream; + +/// MachineLoopRange - Range information for a single loop. +class MachineLoopRange { + friend class MachineLoopRanges; + +public: + typedef IntervalMap Map; + typedef Map::Allocator Allocator; + +private: + /// The mapped loop. + const MachineLoop *const Loop; + + /// Map intervals to a bit mask. + /// Bit 0 = inside loop block. + Map Intervals; + + /// Loop area as measured by SlotIndex::distance. + unsigned Area; + + /// Create a MachineLoopRange, only accessible to MachineLoopRanges. + MachineLoopRange(const MachineLoop*, Allocator&, SlotIndexes&); + +public: + /// getLoop - Return the mapped machine loop. + const MachineLoop *getLoop() const { return Loop; } + + /// overlaps - Return true if this loop overlaps the given range of machine + /// inteructions. + bool overlaps(SlotIndex Start, SlotIndex Stop); + + /// getNumber - Return the loop number. This is the same as the number of the + /// header block. + unsigned getNumber() const; + + /// getArea - Return the loop area. This number is approximately proportional + /// to the number of instructions in the loop. + unsigned getArea() const { return Area; } + + /// getMap - Allow public read-only access for IntervalMapOverlaps. + const Map &getMap() { return Intervals; } + + /// print - Print loop ranges on OS. + void print(raw_ostream&) const; + + /// byNumber - Comparator for array_pod_sort that sorts a list of + /// MachineLoopRange pointers by number. + static int byNumber(const void*, const void*); + + /// byAreaDesc - Comparator for array_pod_sort that sorts a list of + /// MachineLoopRange pointers by descending area, then by number. + static int byAreaDesc(const void*, const void*); +}; + +raw_ostream &operator<<(raw_ostream&, const MachineLoopRange&); + +/// MachineLoopRanges - Analysis pass that provides on-demand per-loop range +/// information. +class MachineLoopRanges : public MachineFunctionPass { + typedef DenseMap CacheMap; + typedef MachineLoopRange::Allocator MapAllocator; + + MapAllocator Allocator; + SlotIndexes *Indexes; + CacheMap Cache; + +public: + static char ID; // Pass identification, replacement for typeid + + MachineLoopRanges() : MachineFunctionPass(ID), Indexes(0) {} + ~MachineLoopRanges() { releaseMemory(); } + + /// getLoopRange - Return the range of loop. + MachineLoopRange *getLoopRange(const MachineLoop *Loop); + +private: + virtual bool runOnMachineFunction(MachineFunction&); + virtual void releaseMemory(); + virtual void getAnalysisUsage(AnalysisUsage&) const; +}; + + +} // end namespace llvm + +#endif // LLVM_CODEGEN_MACHINELOOPRANGES_H diff --git a/include/llvm/CodeGen/MachineMemOperand.h b/include/llvm/CodeGen/MachineMemOperand.h index 7272aa5fc127..768ce47f8b39 100644 --- a/include/llvm/CodeGen/MachineMemOperand.h +++ b/include/llvm/CodeGen/MachineMemOperand.h @@ -16,7 +16,7 @@ #ifndef LLVM_CODEGEN_MACHINEMEMOPERAND_H #define LLVM_CODEGEN_MACHINEMEMOPERAND_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { @@ -24,6 +24,52 @@ class Value; class FoldingSetNodeID; class raw_ostream; +/// MachinePointerInfo - This class contains a discriminated union of +/// information about pointers in memory operands, relating them back to LLVM IR +/// or to virtual locations (such as frame indices) that are exposed during +/// codegen. +struct MachinePointerInfo { + /// V - This is the IR pointer value for the access, or it is null if unknown. + /// If this is null, then the access is to a pointer in the default address + /// space. + const Value *V; + + /// Offset - This is an offset from the base Value*. + int64_t Offset; + + explicit MachinePointerInfo(const Value *v = 0, int64_t offset = 0) + : V(v), Offset(offset) {} + + MachinePointerInfo getWithOffset(int64_t O) const { + if (V == 0) return MachinePointerInfo(0, 0); + return MachinePointerInfo(V, Offset+O); + } + + /// getAddrSpace - Return the LLVM IR address space number that this pointer + /// points into. + unsigned getAddrSpace() const; + + /// getConstantPool - Return a MachinePointerInfo record that refers to the + /// constant pool. + static MachinePointerInfo getConstantPool(); + + /// getFixedStack - Return a MachinePointerInfo record that refers to the + /// the specified FrameIndex. + static MachinePointerInfo getFixedStack(int FI, int64_t offset = 0); + + /// getJumpTable - Return a MachinePointerInfo record that refers to a + /// jump table entry. + static MachinePointerInfo getJumpTable(); + + /// getGOT - Return a MachinePointerInfo record that refers to a + /// GOT entry. + static MachinePointerInfo getGOT(); + + /// getStack - stack pointer relative access. + static MachinePointerInfo getStack(int64_t Offset); +}; + + //===----------------------------------------------------------------------===// /// MachineMemOperand - A description of a memory reference used in the backend. /// Instead of holding a StoreInst or LoadInst, this class holds the address @@ -33,10 +79,10 @@ class raw_ostream; /// that aren't explicit in the regular LLVM IR. /// class MachineMemOperand { - int64_t Offset; + MachinePointerInfo PtrInfo; uint64_t Size; - const Value *V; - unsigned int Flags; + unsigned Flags; + const MDNode *TBAAInfo; public: /// Flags values. These may be or'd together. @@ -54,10 +100,12 @@ public: }; /// MachineMemOperand - Construct an MachineMemOperand object with the - /// specified address Value, flags, offset, size, and base alignment. - MachineMemOperand(const Value *v, unsigned int f, int64_t o, uint64_t s, - unsigned int base_alignment); + /// specified PtrInfo, flags, size, and base alignment. + MachineMemOperand(MachinePointerInfo PtrInfo, unsigned flags, uint64_t s, + unsigned base_alignment, const MDNode *TBAAInfo = 0); + const MachinePointerInfo &getPointerInfo() const { return PtrInfo; } + /// getValue - Return the base address of the memory access. This may either /// be a normal LLVM IR Value, or one of the special values used in CodeGen. /// Special values are those obtained via @@ -65,7 +113,7 @@ public: /// other PseudoSourceValue member functions which return objects which stand /// for frame/stack pointer relative references and other special references /// which are not representable in the high-level IR. - const Value *getValue() const { return V; } + const Value *getValue() const { return PtrInfo.V; } /// getFlags - Return the raw flags of the source value, \see MemOperandFlags. unsigned int getFlags() const { return Flags & ((1 << MOMaxBits) - 1); } @@ -73,7 +121,7 @@ public: /// getOffset - For normal values, this is a byte offset added to the base /// address. For PseudoSourceValue::FPRel values, this is the FrameIndex /// number. - int64_t getOffset() const { return Offset; } + int64_t getOffset() const { return PtrInfo.Offset; } /// getSize - Return the size in bytes of the memory reference. uint64_t getSize() const { return Size; } @@ -86,6 +134,9 @@ public: /// base address, without the offset. uint64_t getBaseAlignment() const { return (1u << (Flags >> MOMaxBits)) >> 1; } + /// getTBAAInfo - Return the TBAA tag for the memory reference. + const MDNode *getTBAAInfo() const { return TBAAInfo; } + bool isLoad() const { return Flags & MOLoad; } bool isStore() const { return Flags & MOStore; } bool isVolatile() const { return Flags & MOVolatile; } @@ -99,7 +150,8 @@ public: /// setValue - Change the SourceValue for this MachineMemOperand. This /// should only be used when an object is being relocated and all references /// to it are being updated. - void setValue(const Value *NewSV) { V = NewSV; } + void setValue(const Value *NewSV) { PtrInfo.V = NewSV; } + void setOffset(int64_t NewOffset) { PtrInfo.Offset = NewOffset; } /// Profile - Gather unique data for the object. /// diff --git a/include/llvm/CodeGen/MachineModuleInfo.h b/include/llvm/CodeGen/MachineModuleInfo.h index 0e719c86c18e..6bc80b099fd9 100644 --- a/include/llvm/CodeGen/MachineModuleInfo.h +++ b/include/llvm/CodeGen/MachineModuleInfo.h @@ -39,7 +39,7 @@ #include "llvm/Support/Dwarf.h" #include "llvm/Support/DebugLoc.h" #include "llvm/Support/ValueHandle.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallPtrSet.h" @@ -57,7 +57,7 @@ class MachineFunction; class Module; class PointerType; class StructType; - + /// MachineModuleInfoImpl - This class can be derived from and used by targets /// to hold private target-specific information for each Module. Objects of /// type are accessed/created with MMI::getInfo and destroyed when the @@ -70,8 +70,8 @@ public: protected: static SymbolListTy GetSortedStubs(const DenseMap&); }; - - + + //===----------------------------------------------------------------------===// /// LandingPadInfo - This structure is used to retain landing pad info for @@ -90,19 +90,19 @@ struct LandingPadInfo { }; class MMIAddrLabelMap; - + //===----------------------------------------------------------------------===// /// MachineModuleInfo - This class contains meta information specific to a -/// module. Queries can be made by different debugging and exception handling +/// module. Queries can be made by different debugging and exception handling /// schemes and reformated for specific use. /// class MachineModuleInfo : public ImmutablePass { /// Context - This is the MCContext used for the entire code generator. MCContext Context; - + /// TheModule - This is the LLVM Module being worked on. const Module *TheModule; - + /// ObjFileMMI - This is the object-file-format-specific implementation of /// MachineModuleInfoImpl, which lets targets accumulate whatever info they /// want. @@ -111,7 +111,7 @@ class MachineModuleInfo : public ImmutablePass { // FrameMoves - List of moves done by a function's prolog. Used to construct // frame maps by debug and exception handling consumers. std::vector FrameMoves; - + // LandingPads - List of LandingPadInfo describing the landing pad information // in the current function. std::vector LandingPads; @@ -145,18 +145,22 @@ class MachineModuleInfo : public ImmutablePass { /// llvm.compiler.used. SmallPtrSet UsedFunctions; - + /// AddrLabelSymbols - This map keeps track of which symbol is being used for /// the specified basic block's address of label. MMIAddrLabelMap *AddrLabelSymbols; - + bool CallsEHReturn; bool CallsUnwindInit; - + /// DbgInfoAvailable - True if debugging information is available /// in this module. bool DbgInfoAvailable; + /// True if this module calls VarArg function with floating point arguments. + /// This is used to emit an undefined reference to fltused on Windows targets. + bool CallsExternalVAFunctionWithFloatingPointArguments; + public: static char ID; // Pass identification, replacement for typeid @@ -166,22 +170,23 @@ public: VariableDbgInfoMapTy VariableDbgInfo; MachineModuleInfo(); // DUMMY CONSTRUCTOR, DO NOT CALL. - MachineModuleInfo(const MCAsmInfo &MAI); // Real constructor. + // Real constructor. + MachineModuleInfo(const MCAsmInfo &MAI, const TargetAsmInfo *TAI); ~MachineModuleInfo(); - + bool doInitialization(); bool doFinalization(); /// EndFunction - Discard function meta information. /// void EndFunction(); - + const MCContext &getContext() const { return Context; } MCContext &getContext() { return Context; } void setModule(const Module *M) { TheModule = M; } const Module *getModule() const { return TheModule; } - + /// getInfo - Keep track of various per-function pieces of information for /// backends that would like to do so. /// @@ -191,32 +196,40 @@ public: ObjFileMMI = new Ty(*this); return *static_cast(ObjFileMMI); } - + template const Ty &getObjFileInfo() const { return const_cast(this)->getObjFileInfo(); } - + /// AnalyzeModule - Scan the module for global debug information. /// void AnalyzeModule(const Module &M); - + /// hasDebugInfo - Returns true if valid debug info is present. /// bool hasDebugInfo() const { return DbgInfoAvailable; } - void setDebugInfoAvailability(bool avail) { DbgInfoAvailable = true; } + void setDebugInfoAvailability(bool avail) { DbgInfoAvailable = avail; } bool callsEHReturn() const { return CallsEHReturn; } void setCallsEHReturn(bool b) { CallsEHReturn = b; } bool callsUnwindInit() const { return CallsUnwindInit; } void setCallsUnwindInit(bool b) { CallsUnwindInit = b; } - + + bool callsExternalVAFunctionWithFloatingPointArguments() const { + return CallsExternalVAFunctionWithFloatingPointArguments; + } + + void setCallsExternalVAFunctionWithFloatingPointArguments(bool b) { + CallsExternalVAFunctionWithFloatingPointArguments = b; + } + /// getFrameMoves - Returns a reference to a list of moves done in the current /// function's prologue. Used to construct frame maps for debug and exception /// handling comsumers. std::vector &getFrameMoves() { return FrameMoves; } - + /// getAddrLabelSymbol - Return the symbol to be used for the specified basic /// block when its address is taken. This cannot be its normal LBB label /// because the block may be accessed outside its containing function. @@ -226,15 +239,15 @@ public: /// basic block when its address is taken. If other blocks were RAUW'd to /// this one, we may have to emit them as well, return the whole set. std::vector getAddrLabelSymbolToEmit(const BasicBlock *BB); - + /// takeDeletedSymbolsForFunction - If the specified function has had any /// references to address-taken blocks generated, but the block got deleted, /// return the symbol now so we can emit it. This prevents emitting a /// reference to a symbol that has no definition. - void takeDeletedSymbolsForFunction(const Function *F, + void takeDeletedSymbolsForFunction(const Function *F, std::vector &Result); - + //===- EH ---------------------------------------------------------------===// /// getOrCreateLandingPadInfo - Find or create an LandingPadInfo for the @@ -245,11 +258,11 @@ public: /// associate it with a try landing pad block. void addInvoke(MachineBasicBlock *LandingPad, MCSymbol *BeginLabel, MCSymbol *EndLabel); - - /// addLandingPad - Add a new panding pad. Returns the label ID for the + + /// addLandingPad - Add a new panding pad. Returns the label ID for the /// landing pad entry. MCSymbol *addLandingPad(MachineBasicBlock *LandingPad); - + /// addPersonality - Provide the personality function for the exception /// information. void addPersonality(MachineBasicBlock *LandingPad, @@ -285,7 +298,7 @@ public: /// void addCleanup(MachineBasicBlock *LandingPad); - /// getTypeIDFor - Return the type id for the specified typeinfo. This is + /// getTypeIDFor - Return the type id for the specified typeinfo. This is /// function wide. unsigned getTypeIDFor(const GlobalVariable *TI); @@ -296,7 +309,7 @@ public: /// TidyLandingPads - Remap landing pad labels and remove any deleted landing /// pads. void TidyLandingPads(DenseMap *LPMap = 0); - + /// getLandingPads - Return a reference to the landing pad info for the /// current function. const std::vector &getLandingPads() const { diff --git a/include/llvm/CodeGen/MachineOperand.h b/include/llvm/CodeGen/MachineOperand.h index afa2c298a273..8acc9490d8db 100644 --- a/include/llvm/CodeGen/MachineOperand.h +++ b/include/llvm/CodeGen/MachineOperand.h @@ -14,11 +14,11 @@ #ifndef LLVM_CODEGEN_MACHINEOPERAND_H #define LLVM_CODEGEN_MACHINEOPERAND_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include namespace llvm { - + class BlockAddress; class ConstantFP; class GlobalValue; @@ -30,7 +30,7 @@ class TargetMachine; class TargetRegisterInfo; class raw_ostream; class MCSymbol; - + /// MachineOperand class - Representation of each machine instruction operand. /// class MachineOperand { @@ -54,21 +54,21 @@ private: /// OpKind - Specify what kind of operand this is. This discriminates the /// union. unsigned char OpKind; // MachineOperandType - + /// SubReg - Subregister number, only valid for MO_Register. A value of 0 /// indicates the MO_Register has no subReg. unsigned char SubReg; - + /// TargetFlags - This is a set of target-specific operand flags. unsigned char TargetFlags; - + /// IsDef/IsImp/IsKill/IsDead flags - These are only valid for MO_Register /// operands. - + /// IsDef - True if this is a def, false if this is a use of the register. /// bool IsDef : 1; - + /// IsImp - True if this is an implicit def or use, false if it is explicit. /// bool IsImp : 1; @@ -94,7 +94,16 @@ private: /// not a real instruction. Such uses should be ignored during codegen. bool IsDebug : 1; - /// ParentMI - This is the instruction that this operand is embedded into. + /// SmallContents - Thisreally should be part of the Contents union, but lives + /// out here so we can get a better packed struct. + /// MO_Register: Register number. + /// OffsetedInfo: Low bits of offset. + union { + unsigned RegNo; // For MO_Register. + unsigned OffsetLo; // Matches Contents.OffsetedInfo.OffsetHi. + } SmallContents; + + /// ParentMI - This is the instruction that this operand is embedded into. /// This is valid for all operand types, when the operand is in an instr. MachineInstr *ParentMI; @@ -107,11 +116,11 @@ private: MCSymbol *Sym; // For MO_MCSymbol struct { // For MO_Register. - unsigned RegNo; + // Register number is in SmallContents.RegNo. MachineOperand **Prev; // Access list for register. MachineOperand *Next; } Reg; - + /// OffsetedInfo - This struct contains the offset and an object identifier. /// this represent the object as with an optional offset from it. struct { @@ -121,10 +130,11 @@ private: const GlobalValue *GV; // For MO_GlobalAddress. const BlockAddress *BA; // For MO_BlockAddress. } Val; - int64_t Offset; // An offset from the object. + // Low bits of offset are in SmallContents.OffsetLo. + int OffsetHi; // An offset from the object, high 32 bits. } OffsetedInfo; } Contents; - + explicit MachineOperand(MachineOperandType K) : OpKind(K), ParentMI(0) { TargetFlags = 0; } @@ -132,17 +142,27 @@ public: /// getType - Returns the MachineOperandType for this operand. /// MachineOperandType getType() const { return (MachineOperandType)OpKind; } - + unsigned char getTargetFlags() const { return TargetFlags; } void setTargetFlags(unsigned char F) { TargetFlags = F; } void addTargetFlag(unsigned char F) { TargetFlags |= F; } - + /// getParent - Return the instruction that this operand belongs to. /// MachineInstr *getParent() { return ParentMI; } const MachineInstr *getParent() const { return ParentMI; } - + + /// clearParent - Reset the parent pointer. + /// + /// The MachineOperand copy constructor also copies ParentMI, expecting the + /// original to be deleted. If a MachineOperand is ever stored outside a + /// MachineInstr, the parent pointer must be cleared. + /// + /// Never call clearParent() on an operand in a MachineInstr. + /// + void clearParent() { ParentMI = 0; } + void print(raw_ostream &os, const TargetMachine *TM = 0) const; //===--------------------------------------------------------------------===// @@ -180,44 +200,44 @@ public: /// getReg - Returns the register number. unsigned getReg() const { assert(isReg() && "This is not a register operand!"); - return Contents.Reg.RegNo; + return SmallContents.RegNo; } - + unsigned getSubReg() const { assert(isReg() && "Wrong MachineOperand accessor"); return (unsigned)SubReg; } - - bool isUse() const { + + bool isUse() const { assert(isReg() && "Wrong MachineOperand accessor"); return !IsDef; } - + bool isDef() const { assert(isReg() && "Wrong MachineOperand accessor"); return IsDef; } - - bool isImplicit() const { + + bool isImplicit() const { assert(isReg() && "Wrong MachineOperand accessor"); return IsImp; } - + bool isDead() const { assert(isReg() && "Wrong MachineOperand accessor"); return IsDead; } - + bool isKill() const { assert(isReg() && "Wrong MachineOperand accessor"); return IsKill; } - + bool isUndef() const { assert(isReg() && "Wrong MachineOperand accessor"); return IsUndef; } - + bool isEarlyClobber() const { assert(isReg() && "Wrong MachineOperand accessor"); return IsEarlyClobber; @@ -238,11 +258,11 @@ public: //===--------------------------------------------------------------------===// // Mutators for Register Operands //===--------------------------------------------------------------------===// - + /// Change the register this operand corresponds to. /// void setReg(unsigned Reg); - + void setSubReg(unsigned subReg) { assert(isReg() && "Wrong MachineOperand accessor"); SubReg = (unsigned char)subReg; @@ -266,14 +286,14 @@ public: assert((Val || !isDebug()) && "Marking a debug operation as def"); IsDef = !Val; } - + void setIsDef(bool Val = true) { assert(isReg() && "Wrong MachineOperand accessor"); assert((!Val || !isDebug()) && "Marking a debug operation as def"); IsDef = Val; } - void setImplicit(bool Val = true) { + void setImplicit(bool Val = true) { assert(isReg() && "Wrong MachineOperand accessor"); IsImp = Val; } @@ -283,7 +303,7 @@ public: assert((!Val || !isDebug()) && "Marking a debug operation as kill"); IsKill = Val; } - + void setIsDead(bool Val = true) { assert(isReg() && IsDef && "Wrong MachineOperand accessor"); IsDead = Val; @@ -293,7 +313,7 @@ public: assert(isReg() && "Wrong MachineOperand accessor"); IsUndef = Val; } - + void setIsEarlyClobber(bool Val = true) { assert(isReg() && IsDef && "Wrong MachineOperand accessor"); IsEarlyClobber = Val; @@ -307,17 +327,17 @@ public: //===--------------------------------------------------------------------===// // Accessors for various operand types. //===--------------------------------------------------------------------===// - + int64_t getImm() const { assert(isImm() && "Wrong MachineOperand accessor"); return Contents.ImmVal; } - + const ConstantFP *getFPImm() const { assert(isFPImm() && "Wrong MachineOperand accessor"); return Contents.CFP; } - + MachineBasicBlock *getMBB() const { assert(isMBB() && "Wrong MachineOperand accessor"); return Contents.MBB; @@ -328,7 +348,7 @@ public: "Wrong MachineOperand accessor"); return Contents.OffsetedInfo.Val.Index; } - + const GlobalValue *getGlobal() const { assert(isGlobal() && "Wrong MachineOperand accessor"); return Contents.OffsetedInfo.Val.GV; @@ -343,15 +363,16 @@ public: assert(isMCSymbol() && "Wrong MachineOperand accessor"); return Contents.Sym; } - + /// getOffset - Return the offset from the symbol in this operand. This always /// returns 0 for ExternalSymbol operands. int64_t getOffset() const { assert((isGlobal() || isSymbol() || isCPI() || isBlockAddress()) && "Wrong MachineOperand accessor"); - return Contents.OffsetedInfo.Offset; + return (int64_t(Contents.OffsetedInfo.OffsetHi) << 32) | + SmallContents.OffsetLo; } - + const char *getSymbolName() const { assert(isSymbol() && "Wrong MachineOperand accessor"); return Contents.OffsetedInfo.Val.SymbolName; @@ -361,11 +382,11 @@ public: assert(isMetadata() && "Wrong MachineOperand accessor"); return Contents.MD; } - + //===--------------------------------------------------------------------===// // Mutators for various operand types. //===--------------------------------------------------------------------===// - + void setImm(int64_t immVal) { assert(isImm() && "Wrong MachineOperand mutator"); Contents.ImmVal = immVal; @@ -374,56 +395,57 @@ public: void setOffset(int64_t Offset) { assert((isGlobal() || isSymbol() || isCPI() || isBlockAddress()) && "Wrong MachineOperand accessor"); - Contents.OffsetedInfo.Offset = Offset; + SmallContents.OffsetLo = unsigned(Offset); + Contents.OffsetedInfo.OffsetHi = int(Offset >> 32); } - + void setIndex(int Idx) { assert((isFI() || isCPI() || isJTI()) && "Wrong MachineOperand accessor"); Contents.OffsetedInfo.Val.Index = Idx; } - + void setMBB(MachineBasicBlock *MBB) { assert(isMBB() && "Wrong MachineOperand accessor"); Contents.MBB = MBB; } - + //===--------------------------------------------------------------------===// // Other methods. //===--------------------------------------------------------------------===// - + /// isIdenticalTo - Return true if this operand is identical to the specified /// operand. Note: This method ignores isKill and isDead properties. bool isIdenticalTo(const MachineOperand &Other) const; - + /// ChangeToImmediate - Replace this operand with a new immediate operand of /// the specified value. If an operand is known to be an immediate already, /// the setImm method should be used. void ChangeToImmediate(int64_t ImmVal); - + /// ChangeToRegister - Replace this operand with a new register operand of /// the specified value. If an operand is known to be an register already, /// the setReg method should be used. void ChangeToRegister(unsigned Reg, bool isDef, bool isImp = false, bool isKill = false, bool isDead = false, bool isUndef = false, bool isDebug = false); - + //===--------------------------------------------------------------------===// // Construction methods. //===--------------------------------------------------------------------===// - + static MachineOperand CreateImm(int64_t Val) { MachineOperand Op(MachineOperand::MO_Immediate); Op.setImm(Val); return Op; } - + static MachineOperand CreateFPImm(const ConstantFP *CFP) { MachineOperand Op(MachineOperand::MO_FPImmediate); Op.Contents.CFP = CFP; return Op; } - + static MachineOperand CreateReg(unsigned Reg, bool isDef, bool isImp = false, bool isKill = false, bool isDead = false, bool isUndef = false, @@ -438,7 +460,7 @@ public: Op.IsUndef = isUndef; Op.IsEarlyClobber = isEarlyClobber; Op.IsDebug = isDebug; - Op.Contents.Reg.RegNo = Reg; + Op.SmallContents.RegNo = Reg; Op.Contents.Reg.Prev = 0; Op.Contents.Reg.Next = 0; Op.SubReg = SubReg; @@ -506,7 +528,7 @@ public: Op.Contents.Sym = Sym; return Op; } - + friend class MachineInstr; friend class MachineRegisterInfo; private: @@ -521,7 +543,7 @@ private: assert(isReg() && "Can only add reg operand to use lists"); return Contents.Reg.Prev != 0; } - + /// AddRegOperandToRegInfo - Add this register operand to the specified /// MachineRegisterInfo. If it is null, then the next/prev fields should be /// explicitly nulled out. diff --git a/include/llvm/CodeGen/MachineRegisterInfo.h b/include/llvm/CodeGen/MachineRegisterInfo.h index 066c91b36cf5..79ff714df63d 100644 --- a/include/llvm/CodeGen/MachineRegisterInfo.h +++ b/include/llvm/CodeGen/MachineRegisterInfo.h @@ -16,6 +16,9 @@ #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/ADT/BitVector.h" +#include "llvm/ADT/IndexedMap.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/DebugLoc.h" #include namespace llvm { @@ -24,13 +27,12 @@ namespace llvm { /// registers, including vreg register classes, use/def chains for registers, /// etc. class MachineRegisterInfo { - /// VRegInfo - Information we keep for each virtual register. The entries in - /// this vector are actually converted to vreg numbers by adding the - /// TargetRegisterInfo::FirstVirtualRegister delta to their index. + /// VRegInfo - Information we keep for each virtual register. /// /// Each element in this list contains the register class of the vreg and the /// start of the use/def list for the register. - std::vector > VRegInfo; + IndexedMap, + VirtReg2IndexFunctor> VRegInfo; /// RegClassVRegMap - This vector acts as a map from TargetRegisterClass to /// virtual registers. For each target register class, it keeps a list of @@ -44,7 +46,7 @@ class MachineRegisterInfo { /// register for allocation. For example, if the hint is <0, 1024>, it means /// the allocator should prefer the physical register allocated to the virtual /// register of the hint. - std::vector > RegAllocHints; + IndexedMap, VirtReg2IndexFunctor> RegAllocHints; /// PhysRegUseDefLists - This is an array of the head of the use/def list for /// physical registers. @@ -64,7 +66,10 @@ class MachineRegisterInfo { /// stored in the second element. std::vector > LiveIns; std::vector LiveOuts; - + + /// LiveInLocs - Keep track of location livein registers. + DenseMap LiveInLocs; + MachineRegisterInfo(const MachineRegisterInfo&); // DO NOT IMPLEMENT void operator=(const MachineRegisterInfo&); // DO NOT IMPLEMENT public: @@ -159,17 +164,15 @@ public: /// getRegUseDefListHead - Return the head pointer for the register use/def /// list for the specified virtual or physical register. MachineOperand *&getRegUseDefListHead(unsigned RegNo) { - if (RegNo < TargetRegisterInfo::FirstVirtualRegister) - return PhysRegUseDefLists[RegNo]; - RegNo -= TargetRegisterInfo::FirstVirtualRegister; - return VRegInfo[RegNo].second; + if (TargetRegisterInfo::isVirtualRegister(RegNo)) + return VRegInfo[RegNo].second; + return PhysRegUseDefLists[RegNo]; } MachineOperand *getRegUseDefListHead(unsigned RegNo) const { - if (RegNo < TargetRegisterInfo::FirstVirtualRegister) - return PhysRegUseDefLists[RegNo]; - RegNo -= TargetRegisterInfo::FirstVirtualRegister; - return VRegInfo[RegNo].second; + if (TargetRegisterInfo::isVirtualRegister(RegNo)) + return VRegInfo[RegNo].second; + return PhysRegUseDefLists[RegNo]; } /// getVRegDef - Return the machine instr that defines the specified virtual @@ -194,8 +197,6 @@ public: /// getRegClass - Return the register class of the specified virtual register. /// const TargetRegisterClass *getRegClass(unsigned Reg) const { - Reg -= TargetRegisterInfo::FirstVirtualRegister; - assert(Reg < VRegInfo.size() && "Invalid vreg!"); return VRegInfo[Reg].first; } @@ -203,16 +204,22 @@ public: /// void setRegClass(unsigned Reg, const TargetRegisterClass *RC); + /// constrainRegClass - Constrain the register class of the specified virtual + /// register to be a common subclass of RC and the current register class. + /// Return the new register class, or NULL if no such class exists. + /// This should only be used when the constraint is known to be trivial, like + /// GR32 -> GR32_NOSP. Beware of increasing register pressure. + const TargetRegisterClass *constrainRegClass(unsigned Reg, + const TargetRegisterClass *RC); + /// createVirtualRegister - Create and return a new virtual register in the /// function with the specified register class. /// unsigned createVirtualRegister(const TargetRegisterClass *RegClass); - /// getLastVirtReg - Return the highest currently assigned virtual register. + /// getNumVirtRegs - Return the number of virtual registers created. /// - unsigned getLastVirtReg() const { - return (unsigned)VRegInfo.size()+TargetRegisterInfo::FirstVirtualRegister-1; - } + unsigned getNumVirtRegs() const { return VRegInfo.size(); } /// getRegClassVirtRegs - Return the list of virtual registers of the given /// target register class. @@ -224,8 +231,6 @@ public: /// setRegAllocationHint - Specify a register allocation hint for the /// specified virtual register. void setRegAllocationHint(unsigned Reg, unsigned Type, unsigned PrefReg) { - Reg -= TargetRegisterInfo::FirstVirtualRegister; - assert(Reg < VRegInfo.size() && "Invalid vreg!"); RegAllocHints[Reg].first = Type; RegAllocHints[Reg].second = PrefReg; } @@ -234,8 +239,6 @@ public: /// specified virtual register. std::pair getRegAllocationHint(unsigned Reg) const { - Reg -= TargetRegisterInfo::FirstVirtualRegister; - assert(Reg < VRegInfo.size() && "Invalid vreg!"); return RegAllocHints[Reg]; } @@ -273,7 +276,12 @@ public: LiveIns.push_back(std::make_pair(Reg, vreg)); } void addLiveOut(unsigned Reg) { LiveOuts.push_back(Reg); } - + + /// addLiveInLoc - Keep track of location info for live in reg. + void addLiveInLoc(unsigned VReg, DebugLoc DL) { + LiveInLocs[VReg] = DL; + } + // Iteration support for live in/out sets. These sets are kept in sorted // order by their register number. typedef std::vector >::const_iterator diff --git a/include/llvm/CodeGen/MachineRelocation.h b/include/llvm/CodeGen/MachineRelocation.h index c316785dd112..244b466e1728 100644 --- a/include/llvm/CodeGen/MachineRelocation.h +++ b/include/llvm/CodeGen/MachineRelocation.h @@ -14,7 +14,7 @@ #ifndef LLVM_CODEGEN_MACHINERELOCATION_H #define LLVM_CODEGEN_MACHINERELOCATION_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include namespace llvm { diff --git a/include/llvm/CodeGen/PBQP/Graph.h b/include/llvm/CodeGen/PBQP/Graph.h new file mode 100644 index 000000000000..b2224cb051dc --- /dev/null +++ b/include/llvm/CodeGen/PBQP/Graph.h @@ -0,0 +1,425 @@ +//===-------------------- Graph.h - PBQP Graph ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// PBQP Graph class. +// +//===----------------------------------------------------------------------===// + + +#ifndef LLVM_CODEGEN_PBQP_GRAPH_H +#define LLVM_CODEGEN_PBQP_GRAPH_H + +#include "Math.h" + +#include +#include +#include + +namespace PBQP { + + /// PBQP Graph class. + /// Instances of this class describe PBQP problems. + class Graph { + private: + + // ----- TYPEDEFS ----- + class NodeEntry; + class EdgeEntry; + + typedef std::list NodeList; + typedef std::list EdgeList; + + public: + + typedef NodeList::iterator NodeItr; + typedef NodeList::const_iterator ConstNodeItr; + + typedef EdgeList::iterator EdgeItr; + typedef EdgeList::const_iterator ConstEdgeItr; + + private: + + typedef std::list AdjEdgeList; + + public: + + typedef AdjEdgeList::iterator AdjEdgeItr; + + private: + + class NodeEntry { + private: + Vector costs; + AdjEdgeList adjEdges; + unsigned degree; + void *data; + public: + NodeEntry(const Vector &costs) : costs(costs), degree(0) {} + Vector& getCosts() { return costs; } + const Vector& getCosts() const { return costs; } + unsigned getDegree() const { return degree; } + AdjEdgeItr edgesBegin() { return adjEdges.begin(); } + AdjEdgeItr edgesEnd() { return adjEdges.end(); } + AdjEdgeItr addEdge(EdgeItr e) { + ++degree; + return adjEdges.insert(adjEdges.end(), e); + } + void removeEdge(AdjEdgeItr ae) { + --degree; + adjEdges.erase(ae); + } + void setData(void *data) { this->data = data; } + void* getData() { return data; } + }; + + class EdgeEntry { + private: + NodeItr node1, node2; + Matrix costs; + AdjEdgeItr node1AEItr, node2AEItr; + void *data; + public: + EdgeEntry(NodeItr node1, NodeItr node2, const Matrix &costs) + : node1(node1), node2(node2), costs(costs) {} + NodeItr getNode1() const { return node1; } + NodeItr getNode2() const { return node2; } + Matrix& getCosts() { return costs; } + const Matrix& getCosts() const { return costs; } + void setNode1AEItr(AdjEdgeItr ae) { node1AEItr = ae; } + AdjEdgeItr getNode1AEItr() { return node1AEItr; } + void setNode2AEItr(AdjEdgeItr ae) { node2AEItr = ae; } + AdjEdgeItr getNode2AEItr() { return node2AEItr; } + void setData(void *data) { this->data = data; } + void *getData() { return data; } + }; + + // ----- MEMBERS ----- + + NodeList nodes; + unsigned numNodes; + + EdgeList edges; + unsigned numEdges; + + // ----- INTERNAL METHODS ----- + + NodeEntry& getNode(NodeItr nItr) { return *nItr; } + const NodeEntry& getNode(ConstNodeItr nItr) const { return *nItr; } + + EdgeEntry& getEdge(EdgeItr eItr) { return *eItr; } + const EdgeEntry& getEdge(ConstEdgeItr eItr) const { return *eItr; } + + NodeItr addConstructedNode(const NodeEntry &n) { + ++numNodes; + return nodes.insert(nodes.end(), n); + } + + EdgeItr addConstructedEdge(const EdgeEntry &e) { + assert(findEdge(e.getNode1(), e.getNode2()) == edges.end() && + "Attempt to add duplicate edge."); + ++numEdges; + EdgeItr edgeItr = edges.insert(edges.end(), e); + EdgeEntry &ne = getEdge(edgeItr); + NodeEntry &n1 = getNode(ne.getNode1()); + NodeEntry &n2 = getNode(ne.getNode2()); + // Sanity check on matrix dimensions: + assert((n1.getCosts().getLength() == ne.getCosts().getRows()) && + (n2.getCosts().getLength() == ne.getCosts().getCols()) && + "Edge cost dimensions do not match node costs dimensions."); + ne.setNode1AEItr(n1.addEdge(edgeItr)); + ne.setNode2AEItr(n2.addEdge(edgeItr)); + return edgeItr; + } + + inline void copyFrom(const Graph &other); + public: + + /// \brief Construct an empty PBQP graph. + Graph() : numNodes(0), numEdges(0) {} + + /// \brief Copy construct this graph from "other". Note: Does not copy node + /// and edge data, only graph structure and costs. + /// @param other Source graph to copy from. + Graph(const Graph &other) : numNodes(0), numEdges(0) { + copyFrom(other); + } + + /// \brief Make this graph a copy of "other". Note: Does not copy node and + /// edge data, only graph structure and costs. + /// @param other The graph to copy from. + /// @return A reference to this graph. + /// + /// This will clear the current graph, erasing any nodes and edges added, + /// before copying from other. + Graph& operator=(const Graph &other) { + clear(); + copyFrom(other); + return *this; + } + + /// \brief Add a node with the given costs. + /// @param costs Cost vector for the new node. + /// @return Node iterator for the added node. + NodeItr addNode(const Vector &costs) { + return addConstructedNode(NodeEntry(costs)); + } + + /// \brief Add an edge between the given nodes with the given costs. + /// @param n1Itr First node. + /// @param n2Itr Second node. + /// @return Edge iterator for the added edge. + EdgeItr addEdge(Graph::NodeItr n1Itr, Graph::NodeItr n2Itr, + const Matrix &costs) { + assert(getNodeCosts(n1Itr).getLength() == costs.getRows() && + getNodeCosts(n2Itr).getLength() == costs.getCols() && + "Matrix dimensions mismatch."); + return addConstructedEdge(EdgeEntry(n1Itr, n2Itr, costs)); + } + + /// \brief Get the number of nodes in the graph. + /// @return Number of nodes in the graph. + unsigned getNumNodes() const { return numNodes; } + + /// \brief Get the number of edges in the graph. + /// @return Number of edges in the graph. + unsigned getNumEdges() const { return numEdges; } + + /// \brief Get a node's cost vector. + /// @param nItr Node iterator. + /// @return Node cost vector. + Vector& getNodeCosts(NodeItr nItr) { return getNode(nItr).getCosts(); } + + /// \brief Get a node's cost vector (const version). + /// @param nItr Node iterator. + /// @return Node cost vector. + const Vector& getNodeCosts(ConstNodeItr nItr) const { + return getNode(nItr).getCosts(); + } + + /// \brief Set a node's data pointer. + /// @param nItr Node iterator. + /// @param data Pointer to node data. + /// + /// Typically used by a PBQP solver to attach data to aid in solution. + void setNodeData(NodeItr nItr, void *data) { getNode(nItr).setData(data); } + + /// \brief Get the node's data pointer. + /// @param nItr Node iterator. + /// @return Pointer to node data. + void* getNodeData(NodeItr nItr) { return getNode(nItr).getData(); } + + /// \brief Get an edge's cost matrix. + /// @param eItr Edge iterator. + /// @return Edge cost matrix. + Matrix& getEdgeCosts(EdgeItr eItr) { return getEdge(eItr).getCosts(); } + + /// \brief Get an edge's cost matrix (const version). + /// @param eItr Edge iterator. + /// @return Edge cost matrix. + const Matrix& getEdgeCosts(ConstEdgeItr eItr) const { + return getEdge(eItr).getCosts(); + } + + /// \brief Set an edge's data pointer. + /// @param eItr Edge iterator. + /// @param data Pointer to edge data. + /// + /// Typically used by a PBQP solver to attach data to aid in solution. + void setEdgeData(EdgeItr eItr, void *data) { getEdge(eItr).setData(data); } + + /// \brief Get an edge's data pointer. + /// @param eItr Edge iterator. + /// @return Pointer to edge data. + void* getEdgeData(EdgeItr eItr) { return getEdge(eItr).getData(); } + + /// \brief Get a node's degree. + /// @param nItr Node iterator. + /// @return The degree of the node. + unsigned getNodeDegree(NodeItr nItr) const { + return getNode(nItr).getDegree(); + } + + /// \brief Begin iterator for node set. + NodeItr nodesBegin() { return nodes.begin(); } + + /// \brief Begin const iterator for node set. + ConstNodeItr nodesBegin() const { return nodes.begin(); } + + /// \brief End iterator for node set. + NodeItr nodesEnd() { return nodes.end(); } + + /// \brief End const iterator for node set. + ConstNodeItr nodesEnd() const { return nodes.end(); } + + /// \brief Begin iterator for edge set. + EdgeItr edgesBegin() { return edges.begin(); } + + /// \brief End iterator for edge set. + EdgeItr edgesEnd() { return edges.end(); } + + /// \brief Get begin iterator for adjacent edge set. + /// @param nItr Node iterator. + /// @return Begin iterator for the set of edges connected to the given node. + AdjEdgeItr adjEdgesBegin(NodeItr nItr) { + return getNode(nItr).edgesBegin(); + } + + /// \brief Get end iterator for adjacent edge set. + /// @param nItr Node iterator. + /// @return End iterator for the set of edges connected to the given node. + AdjEdgeItr adjEdgesEnd(NodeItr nItr) { + return getNode(nItr).edgesEnd(); + } + + /// \brief Get the first node connected to this edge. + /// @param eItr Edge iterator. + /// @return The first node connected to the given edge. + NodeItr getEdgeNode1(EdgeItr eItr) { + return getEdge(eItr).getNode1(); + } + + /// \brief Get the second node connected to this edge. + /// @param eItr Edge iterator. + /// @return The second node connected to the given edge. + NodeItr getEdgeNode2(EdgeItr eItr) { + return getEdge(eItr).getNode2(); + } + + /// \brief Get the "other" node connected to this edge. + /// @param eItr Edge iterator. + /// @param nItr Node iterator for the "given" node. + /// @return The iterator for the "other" node connected to this edge. + NodeItr getEdgeOtherNode(EdgeItr eItr, NodeItr nItr) { + EdgeEntry &e = getEdge(eItr); + if (e.getNode1() == nItr) { + return e.getNode2(); + } // else + return e.getNode1(); + } + + /// \brief Get the edge connecting two nodes. + /// @param n1Itr First node iterator. + /// @param n2Itr Second node iterator. + /// @return An iterator for edge (n1Itr, n2Itr) if such an edge exists, + /// otherwise returns edgesEnd(). + EdgeItr findEdge(NodeItr n1Itr, NodeItr n2Itr) { + for (AdjEdgeItr aeItr = adjEdgesBegin(n1Itr), aeEnd = adjEdgesEnd(n1Itr); + aeItr != aeEnd; ++aeItr) { + if ((getEdgeNode1(*aeItr) == n2Itr) || + (getEdgeNode2(*aeItr) == n2Itr)) { + return *aeItr; + } + } + return edges.end(); + } + + /// \brief Remove a node from the graph. + /// @param nItr Node iterator. + void removeNode(NodeItr nItr) { + NodeEntry &n = getNode(nItr); + for (AdjEdgeItr itr = n.edgesBegin(), end = n.edgesEnd(); itr != end;) { + EdgeItr eItr = *itr; + ++itr; + removeEdge(eItr); + } + nodes.erase(nItr); + --numNodes; + } + + /// \brief Remove an edge from the graph. + /// @param eItr Edge iterator. + void removeEdge(EdgeItr eItr) { + EdgeEntry &e = getEdge(eItr); + NodeEntry &n1 = getNode(e.getNode1()); + NodeEntry &n2 = getNode(e.getNode2()); + n1.removeEdge(e.getNode1AEItr()); + n2.removeEdge(e.getNode2AEItr()); + edges.erase(eItr); + --numEdges; + } + + /// \brief Remove all nodes and edges from the graph. + void clear() { + nodes.clear(); + edges.clear(); + numNodes = numEdges = 0; + } + + /// \brief Print a representation of this graph in DOT format. + /// @param os Output stream to print on. + template + void printDot(OStream &os) { + + os << "graph {\n"; + + for (NodeItr nodeItr = nodesBegin(), nodeEnd = nodesEnd(); + nodeItr != nodeEnd; ++nodeItr) { + + os << " node" << nodeItr << " [ label=\"" + << nodeItr << ": " << getNodeCosts(nodeItr) << "\" ]\n"; + } + + os << " edge [ len=" << getNumNodes() << " ]\n"; + + for (EdgeItr edgeItr = edgesBegin(), edgeEnd = edgesEnd(); + edgeItr != edgeEnd; ++edgeItr) { + + os << " node" << getEdgeNode1(edgeItr) + << " -- node" << getEdgeNode2(edgeItr) + << " [ label=\""; + + const Matrix &edgeCosts = getEdgeCosts(edgeItr); + + for (unsigned i = 0; i < edgeCosts.getRows(); ++i) { + os << edgeCosts.getRowAsVector(i) << "\\n"; + } + os << "\" ]\n"; + } + os << "}\n"; + } + + }; + + class NodeItrComparator { + public: + bool operator()(Graph::NodeItr n1, Graph::NodeItr n2) const { + return &*n1 < &*n2; + } + + bool operator()(Graph::ConstNodeItr n1, Graph::ConstNodeItr n2) const { + return &*n1 < &*n2; + } + }; + + class EdgeItrCompartor { + public: + bool operator()(Graph::EdgeItr e1, Graph::EdgeItr e2) const { + return &*e1 < &*e2; + } + + bool operator()(Graph::ConstEdgeItr e1, Graph::ConstEdgeItr e2) const { + return &*e1 < &*e2; + } + }; + + void Graph::copyFrom(const Graph &other) { + std::map nodeMap; + + for (Graph::ConstNodeItr nItr = other.nodesBegin(), + nEnd = other.nodesEnd(); + nItr != nEnd; ++nItr) { + nodeMap[nItr] = addNode(other.getNodeCosts(nItr)); + } + + } + +} + +#endif // LLVM_CODEGEN_PBQP_GRAPH_HPP diff --git a/include/llvm/CodeGen/PBQP/HeuristicBase.h b/include/llvm/CodeGen/PBQP/HeuristicBase.h new file mode 100644 index 000000000000..791c227f0d07 --- /dev/null +++ b/include/llvm/CodeGen/PBQP/HeuristicBase.h @@ -0,0 +1,246 @@ +//===-- HeuristcBase.h --- Heuristic base class for PBQP --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_PBQP_HEURISTICBASE_H +#define LLVM_CODEGEN_PBQP_HEURISTICBASE_H + +#include "HeuristicSolver.h" + +namespace PBQP { + + /// \brief Abstract base class for heuristic implementations. + /// + /// This class provides a handy base for heuristic implementations with common + /// solver behaviour implemented for a number of methods. + /// + /// To implement your own heuristic using this class as a base you'll have to + /// implement, as a minimum, the following methods: + ///
        + ///
      • void addToHeuristicList(Graph::NodeItr) : Add a node to the + /// heuristic reduction list. + ///
      • void heuristicReduce() : Perform a single heuristic reduction. + ///
      • void preUpdateEdgeCosts(Graph::EdgeItr) : Handle the (imminent) + /// change to the cost matrix on the given edge (by R2). + ///
      • void postUpdateEdgeCostts(Graph::EdgeItr) : Handle the new + /// costs on the given edge. + ///
      • void handleAddEdge(Graph::EdgeItr) : Handle the addition of a new + /// edge into the PBQP graph (by R2). + ///
      • void handleRemoveEdge(Graph::EdgeItr, Graph::NodeItr) : Handle the + /// disconnection of the given edge from the given node. + ///
      • A constructor for your derived class : to pass back a reference to + /// the solver which is using this heuristic. + ///
      + /// + /// These methods are implemented in this class for documentation purposes, + /// but will assert if called. + /// + /// Note that this class uses the curiously recursive template idiom to + /// forward calls to the derived class. These methods need not be made + /// virtual, and indeed probably shouldn't for performance reasons. + /// + /// You'll also need to provide NodeData and EdgeData structs in your class. + /// These can be used to attach data relevant to your heuristic to each + /// node/edge in the PBQP graph. + + template + class HeuristicBase { + private: + + typedef std::list OptimalList; + + HeuristicSolverImpl &s; + Graph &g; + OptimalList optimalList; + + // Return a reference to the derived heuristic. + HImpl& impl() { return static_cast(*this); } + + // Add the given node to the optimal reductions list. Keep an iterator to + // its location for fast removal. + void addToOptimalReductionList(Graph::NodeItr nItr) { + optimalList.insert(optimalList.end(), nItr); + } + + public: + + /// \brief Construct an instance with a reference to the given solver. + /// @param solver The solver which is using this heuristic instance. + HeuristicBase(HeuristicSolverImpl &solver) + : s(solver), g(s.getGraph()) { } + + /// \brief Get the solver which is using this heuristic instance. + /// @return The solver which is using this heuristic instance. + /// + /// You can use this method to get access to the solver in your derived + /// heuristic implementation. + HeuristicSolverImpl& getSolver() { return s; } + + /// \brief Get the graph representing the problem to be solved. + /// @return The graph representing the problem to be solved. + Graph& getGraph() { return g; } + + /// \brief Tell the solver to simplify the graph before the reduction phase. + /// @return Whether or not the solver should run a simplification phase + /// prior to the main setup and reduction. + /// + /// HeuristicBase returns true from this method as it's a sensible default, + /// however you can over-ride it in your derived class if you want different + /// behaviour. + bool solverRunSimplify() const { return true; } + + /// \brief Decide whether a node should be optimally or heuristically + /// reduced. + /// @return Whether or not the given node should be listed for optimal + /// reduction (via R0, R1 or R2). + /// + /// HeuristicBase returns true for any node with degree less than 3. This is + /// sane and sensible for many situations, but not all. You can over-ride + /// this method in your derived class if you want a different selection + /// criteria. Note however that your criteria for selecting optimal nodes + /// should be at least as strong as this. I.e. Nodes of degree 3 or + /// higher should not be selected under any circumstances. + bool shouldOptimallyReduce(Graph::NodeItr nItr) { + if (g.getNodeDegree(nItr) < 3) + return true; + // else + return false; + } + + /// \brief Add the given node to the list of nodes to be optimally reduced. + /// @return nItr Node iterator to be added. + /// + /// You probably don't want to over-ride this, except perhaps to record + /// statistics before calling this implementation. HeuristicBase relies on + /// its behaviour. + void addToOptimalReduceList(Graph::NodeItr nItr) { + optimalList.push_back(nItr); + } + + /// \brief Initialise the heuristic. + /// + /// HeuristicBase iterates over all nodes in the problem and adds them to + /// the appropriate list using addToOptimalReduceList or + /// addToHeuristicReduceList based on the result of shouldOptimallyReduce. + /// + /// This behaviour should be fine for most situations. + void setup() { + for (Graph::NodeItr nItr = g.nodesBegin(), nEnd = g.nodesEnd(); + nItr != nEnd; ++nItr) { + if (impl().shouldOptimallyReduce(nItr)) { + addToOptimalReduceList(nItr); + } else { + impl().addToHeuristicReduceList(nItr); + } + } + } + + /// \brief Optimally reduce one of the nodes in the optimal reduce list. + /// @return True if a reduction takes place, false if the optimal reduce + /// list is empty. + /// + /// Selects a node from the optimal reduce list and removes it, applying + /// R0, R1 or R2 as appropriate based on the selected node's degree. + bool optimalReduce() { + if (optimalList.empty()) + return false; + + Graph::NodeItr nItr = optimalList.front(); + optimalList.pop_front(); + + switch (s.getSolverDegree(nItr)) { + case 0: s.applyR0(nItr); break; + case 1: s.applyR1(nItr); break; + case 2: s.applyR2(nItr); break; + default: assert(false && + "Optimal reductions of degree > 2 nodes is invalid."); + } + + return true; + } + + /// \brief Perform the PBQP reduction process. + /// + /// Reduces the problem to the empty graph by repeated application of the + /// reduction rules R0, R1, R2 and RN. + /// R0, R1 or R2 are always applied if possible before RN is used. + void reduce() { + bool finished = false; + + while (!finished) { + if (!optimalReduce()) { + if (impl().heuristicReduce()) { + getSolver().recordRN(); + } else { + finished = true; + } + } + } + } + + /// \brief Add a node to the heuristic reduce list. + /// @param nItr Node iterator to add to the heuristic reduce list. + void addToHeuristicList(Graph::NodeItr nItr) { + assert(false && "Must be implemented in derived class."); + } + + /// \brief Heuristically reduce one of the nodes in the heuristic + /// reduce list. + /// @return True if a reduction takes place, false if the heuristic reduce + /// list is empty. + void heuristicReduce() { + assert(false && "Must be implemented in derived class."); + } + + /// \brief Prepare a change in the costs on the given edge. + /// @param eItr Edge iterator. + void preUpdateEdgeCosts(Graph::EdgeItr eItr) { + assert(false && "Must be implemented in derived class."); + } + + /// \brief Handle the change in the costs on the given edge. + /// @param eItr Edge iterator. + void postUpdateEdgeCostts(Graph::EdgeItr eItr) { + assert(false && "Must be implemented in derived class."); + } + + /// \brief Handle the addition of a new edge into the PBQP graph. + /// @param eItr Edge iterator for the added edge. + void handleAddEdge(Graph::EdgeItr eItr) { + assert(false && "Must be implemented in derived class."); + } + + /// \brief Handle disconnection of an edge from a node. + /// @param eItr Edge iterator for edge being disconnected. + /// @param nItr Node iterator for the node being disconnected from. + /// + /// Edges are frequently removed due to the removal of a node. This + /// method allows for the effect to be computed only for the remaining + /// node in the graph. + void handleRemoveEdge(Graph::EdgeItr eItr, Graph::NodeItr nItr) { + assert(false && "Must be implemented in derived class."); + } + + /// \brief Clean up any structures used by HeuristicBase. + /// + /// At present this just performs a sanity check: that the optimal reduce + /// list is empty now that reduction has completed. + /// + /// If your derived class has more complex structures which need tearing + /// down you should over-ride this method but include a call back to this + /// implementation. + void cleanup() { + assert(optimalList.empty() && "Nodes left over in optimal reduce list?"); + } + + }; + +} + + +#endif // LLVM_CODEGEN_PBQP_HEURISTICBASE_H diff --git a/include/llvm/CodeGen/PBQP/HeuristicSolver.h b/include/llvm/CodeGen/PBQP/HeuristicSolver.h new file mode 100644 index 000000000000..35514f967478 --- /dev/null +++ b/include/llvm/CodeGen/PBQP/HeuristicSolver.h @@ -0,0 +1,616 @@ +//===-- HeuristicSolver.h - Heuristic PBQP Solver --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Heuristic PBQP solver. This solver is able to perform optimal reductions for +// nodes of degree 0, 1 or 2. For nodes of degree >2 a plugable heuristic is +// used to select a node for reduction. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_PBQP_HEURISTICSOLVER_H +#define LLVM_CODEGEN_PBQP_HEURISTICSOLVER_H + +#include "Graph.h" +#include "Solution.h" +#include +#include + +namespace PBQP { + + /// \brief Heuristic PBQP solver implementation. + /// + /// This class should usually be created (and destroyed) indirectly via a call + /// to HeuristicSolver::solve(Graph&). + /// See the comments for HeuristicSolver. + /// + /// HeuristicSolverImpl provides the R0, R1 and R2 reduction rules, + /// backpropagation phase, and maintains the internal copy of the graph on + /// which the reduction is carried out (the original being kept to facilitate + /// backpropagation). + template + class HeuristicSolverImpl { + private: + + typedef typename HImpl::NodeData HeuristicNodeData; + typedef typename HImpl::EdgeData HeuristicEdgeData; + + typedef std::list SolverEdges; + + public: + + /// \brief Iterator type for edges in the solver graph. + typedef SolverEdges::iterator SolverEdgeItr; + + private: + + class NodeData { + public: + NodeData() : solverDegree(0) {} + + HeuristicNodeData& getHeuristicData() { return hData; } + + SolverEdgeItr addSolverEdge(Graph::EdgeItr eItr) { + ++solverDegree; + return solverEdges.insert(solverEdges.end(), eItr); + } + + void removeSolverEdge(SolverEdgeItr seItr) { + --solverDegree; + solverEdges.erase(seItr); + } + + SolverEdgeItr solverEdgesBegin() { return solverEdges.begin(); } + SolverEdgeItr solverEdgesEnd() { return solverEdges.end(); } + unsigned getSolverDegree() const { return solverDegree; } + void clearSolverEdges() { + solverDegree = 0; + solverEdges.clear(); + } + + private: + HeuristicNodeData hData; + unsigned solverDegree; + SolverEdges solverEdges; + }; + + class EdgeData { + public: + HeuristicEdgeData& getHeuristicData() { return hData; } + + void setN1SolverEdgeItr(SolverEdgeItr n1SolverEdgeItr) { + this->n1SolverEdgeItr = n1SolverEdgeItr; + } + + SolverEdgeItr getN1SolverEdgeItr() { return n1SolverEdgeItr; } + + void setN2SolverEdgeItr(SolverEdgeItr n2SolverEdgeItr){ + this->n2SolverEdgeItr = n2SolverEdgeItr; + } + + SolverEdgeItr getN2SolverEdgeItr() { return n2SolverEdgeItr; } + + private: + + HeuristicEdgeData hData; + SolverEdgeItr n1SolverEdgeItr, n2SolverEdgeItr; + }; + + Graph &g; + HImpl h; + Solution s; + std::vector stack; + + typedef std::list NodeDataList; + NodeDataList nodeDataList; + + typedef std::list EdgeDataList; + EdgeDataList edgeDataList; + + public: + + /// \brief Construct a heuristic solver implementation to solve the given + /// graph. + /// @param g The graph representing the problem instance to be solved. + HeuristicSolverImpl(Graph &g) : g(g), h(*this) {} + + /// \brief Get the graph being solved by this solver. + /// @return The graph representing the problem instance being solved by this + /// solver. + Graph& getGraph() { return g; } + + /// \brief Get the heuristic data attached to the given node. + /// @param nItr Node iterator. + /// @return The heuristic data attached to the given node. + HeuristicNodeData& getHeuristicNodeData(Graph::NodeItr nItr) { + return getSolverNodeData(nItr).getHeuristicData(); + } + + /// \brief Get the heuristic data attached to the given edge. + /// @param eItr Edge iterator. + /// @return The heuristic data attached to the given node. + HeuristicEdgeData& getHeuristicEdgeData(Graph::EdgeItr eItr) { + return getSolverEdgeData(eItr).getHeuristicData(); + } + + /// \brief Begin iterator for the set of edges adjacent to the given node in + /// the solver graph. + /// @param nItr Node iterator. + /// @return Begin iterator for the set of edges adjacent to the given node + /// in the solver graph. + SolverEdgeItr solverEdgesBegin(Graph::NodeItr nItr) { + return getSolverNodeData(nItr).solverEdgesBegin(); + } + + /// \brief End iterator for the set of edges adjacent to the given node in + /// the solver graph. + /// @param nItr Node iterator. + /// @return End iterator for the set of edges adjacent to the given node in + /// the solver graph. + SolverEdgeItr solverEdgesEnd(Graph::NodeItr nItr) { + return getSolverNodeData(nItr).solverEdgesEnd(); + } + + /// \brief Remove a node from the solver graph. + /// @param eItr Edge iterator for edge to be removed. + /// + /// Does not notify the heuristic of the removal. That should be + /// done manually if necessary. + void removeSolverEdge(Graph::EdgeItr eItr) { + EdgeData &eData = getSolverEdgeData(eItr); + NodeData &n1Data = getSolverNodeData(g.getEdgeNode1(eItr)), + &n2Data = getSolverNodeData(g.getEdgeNode2(eItr)); + + n1Data.removeSolverEdge(eData.getN1SolverEdgeItr()); + n2Data.removeSolverEdge(eData.getN2SolverEdgeItr()); + } + + /// \brief Compute a solution to the PBQP problem instance with which this + /// heuristic solver was constructed. + /// @return A solution to the PBQP problem. + /// + /// Performs the full PBQP heuristic solver algorithm, including setup, + /// calls to the heuristic (which will call back to the reduction rules in + /// this class), and cleanup. + Solution computeSolution() { + setup(); + h.setup(); + h.reduce(); + backpropagate(); + h.cleanup(); + cleanup(); + return s; + } + + /// \brief Add to the end of the stack. + /// @param nItr Node iterator to add to the reduction stack. + void pushToStack(Graph::NodeItr nItr) { + getSolverNodeData(nItr).clearSolverEdges(); + stack.push_back(nItr); + } + + /// \brief Returns the solver degree of the given node. + /// @param nItr Node iterator for which degree is requested. + /// @return Node degree in the solver graph (not the original graph). + unsigned getSolverDegree(Graph::NodeItr nItr) { + return getSolverNodeData(nItr).getSolverDegree(); + } + + /// \brief Set the solution of the given node. + /// @param nItr Node iterator to set solution for. + /// @param selection Selection for node. + void setSolution(const Graph::NodeItr &nItr, unsigned selection) { + s.setSelection(nItr, selection); + + for (Graph::AdjEdgeItr aeItr = g.adjEdgesBegin(nItr), + aeEnd = g.adjEdgesEnd(nItr); + aeItr != aeEnd; ++aeItr) { + Graph::EdgeItr eItr(*aeItr); + Graph::NodeItr anItr(g.getEdgeOtherNode(eItr, nItr)); + getSolverNodeData(anItr).addSolverEdge(eItr); + } + } + + /// \brief Apply rule R0. + /// @param nItr Node iterator for node to apply R0 to. + /// + /// Node will be automatically pushed to the solver stack. + void applyR0(Graph::NodeItr nItr) { + assert(getSolverNodeData(nItr).getSolverDegree() == 0 && + "R0 applied to node with degree != 0."); + + // Nothing to do. Just push the node onto the reduction stack. + pushToStack(nItr); + + s.recordR0(); + } + + /// \brief Apply rule R1. + /// @param xnItr Node iterator for node to apply R1 to. + /// + /// Node will be automatically pushed to the solver stack. + void applyR1(Graph::NodeItr xnItr) { + NodeData &nd = getSolverNodeData(xnItr); + assert(nd.getSolverDegree() == 1 && + "R1 applied to node with degree != 1."); + + Graph::EdgeItr eItr = *nd.solverEdgesBegin(); + + const Matrix &eCosts = g.getEdgeCosts(eItr); + const Vector &xCosts = g.getNodeCosts(xnItr); + + // Duplicate a little to avoid transposing matrices. + if (xnItr == g.getEdgeNode1(eItr)) { + Graph::NodeItr ynItr = g.getEdgeNode2(eItr); + Vector &yCosts = g.getNodeCosts(ynItr); + for (unsigned j = 0; j < yCosts.getLength(); ++j) { + PBQPNum min = eCosts[0][j] + xCosts[0]; + for (unsigned i = 1; i < xCosts.getLength(); ++i) { + PBQPNum c = eCosts[i][j] + xCosts[i]; + if (c < min) + min = c; + } + yCosts[j] += min; + } + h.handleRemoveEdge(eItr, ynItr); + } else { + Graph::NodeItr ynItr = g.getEdgeNode1(eItr); + Vector &yCosts = g.getNodeCosts(ynItr); + for (unsigned i = 0; i < yCosts.getLength(); ++i) { + PBQPNum min = eCosts[i][0] + xCosts[0]; + for (unsigned j = 1; j < xCosts.getLength(); ++j) { + PBQPNum c = eCosts[i][j] + xCosts[j]; + if (c < min) + min = c; + } + yCosts[i] += min; + } + h.handleRemoveEdge(eItr, ynItr); + } + removeSolverEdge(eItr); + assert(nd.getSolverDegree() == 0 && + "Degree 1 with edge removed should be 0."); + pushToStack(xnItr); + s.recordR1(); + } + + /// \brief Apply rule R2. + /// @param xnItr Node iterator for node to apply R2 to. + /// + /// Node will be automatically pushed to the solver stack. + void applyR2(Graph::NodeItr xnItr) { + assert(getSolverNodeData(xnItr).getSolverDegree() == 2 && + "R2 applied to node with degree != 2."); + + NodeData &nd = getSolverNodeData(xnItr); + const Vector &xCosts = g.getNodeCosts(xnItr); + + SolverEdgeItr aeItr = nd.solverEdgesBegin(); + Graph::EdgeItr yxeItr = *aeItr, + zxeItr = *(++aeItr); + + Graph::NodeItr ynItr = g.getEdgeOtherNode(yxeItr, xnItr), + znItr = g.getEdgeOtherNode(zxeItr, xnItr); + + bool flipEdge1 = (g.getEdgeNode1(yxeItr) == xnItr), + flipEdge2 = (g.getEdgeNode1(zxeItr) == xnItr); + + const Matrix *yxeCosts = flipEdge1 ? + new Matrix(g.getEdgeCosts(yxeItr).transpose()) : + &g.getEdgeCosts(yxeItr); + + const Matrix *zxeCosts = flipEdge2 ? + new Matrix(g.getEdgeCosts(zxeItr).transpose()) : + &g.getEdgeCosts(zxeItr); + + unsigned xLen = xCosts.getLength(), + yLen = yxeCosts->getRows(), + zLen = zxeCosts->getRows(); + + Matrix delta(yLen, zLen); + + for (unsigned i = 0; i < yLen; ++i) { + for (unsigned j = 0; j < zLen; ++j) { + PBQPNum min = (*yxeCosts)[i][0] + (*zxeCosts)[j][0] + xCosts[0]; + for (unsigned k = 1; k < xLen; ++k) { + PBQPNum c = (*yxeCosts)[i][k] + (*zxeCosts)[j][k] + xCosts[k]; + if (c < min) { + min = c; + } + } + delta[i][j] = min; + } + } + + if (flipEdge1) + delete yxeCosts; + + if (flipEdge2) + delete zxeCosts; + + Graph::EdgeItr yzeItr = g.findEdge(ynItr, znItr); + bool addedEdge = false; + + if (yzeItr == g.edgesEnd()) { + yzeItr = g.addEdge(ynItr, znItr, delta); + addedEdge = true; + } else { + Matrix &yzeCosts = g.getEdgeCosts(yzeItr); + h.preUpdateEdgeCosts(yzeItr); + if (ynItr == g.getEdgeNode1(yzeItr)) { + yzeCosts += delta; + } else { + yzeCosts += delta.transpose(); + } + } + + bool nullCostEdge = tryNormaliseEdgeMatrix(yzeItr); + + if (!addedEdge) { + // If we modified the edge costs let the heuristic know. + h.postUpdateEdgeCosts(yzeItr); + } + + if (nullCostEdge) { + // If this edge ended up null remove it. + if (!addedEdge) { + // We didn't just add it, so we need to notify the heuristic + // and remove it from the solver. + h.handleRemoveEdge(yzeItr, ynItr); + h.handleRemoveEdge(yzeItr, znItr); + removeSolverEdge(yzeItr); + } + g.removeEdge(yzeItr); + } else if (addedEdge) { + // If the edge was added, and non-null, finish setting it up, add it to + // the solver & notify heuristic. + edgeDataList.push_back(EdgeData()); + g.setEdgeData(yzeItr, &edgeDataList.back()); + addSolverEdge(yzeItr); + h.handleAddEdge(yzeItr); + } + + h.handleRemoveEdge(yxeItr, ynItr); + removeSolverEdge(yxeItr); + h.handleRemoveEdge(zxeItr, znItr); + removeSolverEdge(zxeItr); + + pushToStack(xnItr); + s.recordR2(); + } + + /// \brief Record an application of the RN rule. + /// + /// For use by the HeuristicBase. + void recordRN() { s.recordRN(); } + + private: + + NodeData& getSolverNodeData(Graph::NodeItr nItr) { + return *static_cast(g.getNodeData(nItr)); + } + + EdgeData& getSolverEdgeData(Graph::EdgeItr eItr) { + return *static_cast(g.getEdgeData(eItr)); + } + + void addSolverEdge(Graph::EdgeItr eItr) { + EdgeData &eData = getSolverEdgeData(eItr); + NodeData &n1Data = getSolverNodeData(g.getEdgeNode1(eItr)), + &n2Data = getSolverNodeData(g.getEdgeNode2(eItr)); + + eData.setN1SolverEdgeItr(n1Data.addSolverEdge(eItr)); + eData.setN2SolverEdgeItr(n2Data.addSolverEdge(eItr)); + } + + void setup() { + if (h.solverRunSimplify()) { + simplify(); + } + + // Create node data objects. + for (Graph::NodeItr nItr = g.nodesBegin(), nEnd = g.nodesEnd(); + nItr != nEnd; ++nItr) { + nodeDataList.push_back(NodeData()); + g.setNodeData(nItr, &nodeDataList.back()); + } + + // Create edge data objects. + for (Graph::EdgeItr eItr = g.edgesBegin(), eEnd = g.edgesEnd(); + eItr != eEnd; ++eItr) { + edgeDataList.push_back(EdgeData()); + g.setEdgeData(eItr, &edgeDataList.back()); + addSolverEdge(eItr); + } + } + + void simplify() { + disconnectTrivialNodes(); + eliminateIndependentEdges(); + } + + // Eliminate trivial nodes. + void disconnectTrivialNodes() { + unsigned numDisconnected = 0; + + for (Graph::NodeItr nItr = g.nodesBegin(), nEnd = g.nodesEnd(); + nItr != nEnd; ++nItr) { + + if (g.getNodeCosts(nItr).getLength() == 1) { + + std::vector edgesToRemove; + + for (Graph::AdjEdgeItr aeItr = g.adjEdgesBegin(nItr), + aeEnd = g.adjEdgesEnd(nItr); + aeItr != aeEnd; ++aeItr) { + + Graph::EdgeItr eItr = *aeItr; + + if (g.getEdgeNode1(eItr) == nItr) { + Graph::NodeItr otherNodeItr = g.getEdgeNode2(eItr); + g.getNodeCosts(otherNodeItr) += + g.getEdgeCosts(eItr).getRowAsVector(0); + } + else { + Graph::NodeItr otherNodeItr = g.getEdgeNode1(eItr); + g.getNodeCosts(otherNodeItr) += + g.getEdgeCosts(eItr).getColAsVector(0); + } + + edgesToRemove.push_back(eItr); + } + + if (!edgesToRemove.empty()) + ++numDisconnected; + + while (!edgesToRemove.empty()) { + g.removeEdge(edgesToRemove.back()); + edgesToRemove.pop_back(); + } + } + } + } + + void eliminateIndependentEdges() { + std::vector edgesToProcess; + unsigned numEliminated = 0; + + for (Graph::EdgeItr eItr = g.edgesBegin(), eEnd = g.edgesEnd(); + eItr != eEnd; ++eItr) { + edgesToProcess.push_back(eItr); + } + + while (!edgesToProcess.empty()) { + if (tryToEliminateEdge(edgesToProcess.back())) + ++numEliminated; + edgesToProcess.pop_back(); + } + } + + bool tryToEliminateEdge(Graph::EdgeItr eItr) { + if (tryNormaliseEdgeMatrix(eItr)) { + g.removeEdge(eItr); + return true; + } + return false; + } + + bool tryNormaliseEdgeMatrix(Graph::EdgeItr &eItr) { + + const PBQPNum infinity = std::numeric_limits::infinity(); + + Matrix &edgeCosts = g.getEdgeCosts(eItr); + Vector &uCosts = g.getNodeCosts(g.getEdgeNode1(eItr)), + &vCosts = g.getNodeCosts(g.getEdgeNode2(eItr)); + + for (unsigned r = 0; r < edgeCosts.getRows(); ++r) { + PBQPNum rowMin = infinity; + + for (unsigned c = 0; c < edgeCosts.getCols(); ++c) { + if (vCosts[c] != infinity && edgeCosts[r][c] < rowMin) + rowMin = edgeCosts[r][c]; + } + + uCosts[r] += rowMin; + + if (rowMin != infinity) { + edgeCosts.subFromRow(r, rowMin); + } + else { + edgeCosts.setRow(r, 0); + } + } + + for (unsigned c = 0; c < edgeCosts.getCols(); ++c) { + PBQPNum colMin = infinity; + + for (unsigned r = 0; r < edgeCosts.getRows(); ++r) { + if (uCosts[r] != infinity && edgeCosts[r][c] < colMin) + colMin = edgeCosts[r][c]; + } + + vCosts[c] += colMin; + + if (colMin != infinity) { + edgeCosts.subFromCol(c, colMin); + } + else { + edgeCosts.setCol(c, 0); + } + } + + return edgeCosts.isZero(); + } + + void backpropagate() { + while (!stack.empty()) { + computeSolution(stack.back()); + stack.pop_back(); + } + } + + void computeSolution(Graph::NodeItr nItr) { + + NodeData &nodeData = getSolverNodeData(nItr); + + Vector v(g.getNodeCosts(nItr)); + + // Solve based on existing solved edges. + for (SolverEdgeItr solvedEdgeItr = nodeData.solverEdgesBegin(), + solvedEdgeEnd = nodeData.solverEdgesEnd(); + solvedEdgeItr != solvedEdgeEnd; ++solvedEdgeItr) { + + Graph::EdgeItr eItr(*solvedEdgeItr); + Matrix &edgeCosts = g.getEdgeCosts(eItr); + + if (nItr == g.getEdgeNode1(eItr)) { + Graph::NodeItr adjNode(g.getEdgeNode2(eItr)); + unsigned adjSolution = s.getSelection(adjNode); + v += edgeCosts.getColAsVector(adjSolution); + } + else { + Graph::NodeItr adjNode(g.getEdgeNode1(eItr)); + unsigned adjSolution = s.getSelection(adjNode); + v += edgeCosts.getRowAsVector(adjSolution); + } + + } + + setSolution(nItr, v.minIndex()); + } + + void cleanup() { + h.cleanup(); + nodeDataList.clear(); + edgeDataList.clear(); + } + }; + + /// \brief PBQP heuristic solver class. + /// + /// Given a PBQP Graph g representing a PBQP problem, you can find a solution + /// by calling + /// Solution s = HeuristicSolver::solve(g); + /// + /// The choice of heuristic for the H parameter will affect both the solver + /// speed and solution quality. The heuristic should be chosen based on the + /// nature of the problem being solved. + /// Currently the only solver included with LLVM is the Briggs heuristic for + /// register allocation. + template + class HeuristicSolver { + public: + static Solution solve(Graph &g) { + HeuristicSolverImpl hs(g); + return hs.computeSolution(); + } + }; + +} + +#endif // LLVM_CODEGEN_PBQP_HEURISTICSOLVER_H diff --git a/include/llvm/CodeGen/PBQP/Heuristics/Briggs.h b/include/llvm/CodeGen/PBQP/Heuristics/Briggs.h new file mode 100644 index 000000000000..47a287ccf2f6 --- /dev/null +++ b/include/llvm/CodeGen/PBQP/Heuristics/Briggs.h @@ -0,0 +1,464 @@ +//===-- Briggs.h --- Briggs Heuristic for PBQP ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class implements the Briggs test for "allocability" of nodes in a +// PBQP graph representing a register allocation problem. Nodes which can be +// proven allocable (by a safe and relatively accurate test) are removed from +// the PBQP graph first. If no provably allocable node is present in the graph +// then the node with the minimal spill-cost to degree ratio is removed. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H +#define LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H + +#include "../HeuristicSolver.h" +#include "../HeuristicBase.h" + +#include +#include + +namespace PBQP { + namespace Heuristics { + + /// \brief PBQP Heuristic which applies an allocability test based on + /// Briggs. + /// + /// This heuristic assumes that the elements of cost vectors in the PBQP + /// problem represent storage options, with the first being the spill + /// option and subsequent elements representing legal registers for the + /// corresponding node. Edge cost matrices are likewise assumed to represent + /// register constraints. + /// If one or more nodes can be proven allocable by this heuristic (by + /// inspection of their constraint matrices) then the allocable node of + /// highest degree is selected for the next reduction and pushed to the + /// solver stack. If no nodes can be proven allocable then the node with + /// the lowest estimated spill cost is selected and push to the solver stack + /// instead. + /// + /// This implementation is built on top of HeuristicBase. + class Briggs : public HeuristicBase { + private: + + class LinkDegreeComparator { + public: + LinkDegreeComparator(HeuristicSolverImpl &s) : s(&s) {} + bool operator()(Graph::NodeItr n1Itr, Graph::NodeItr n2Itr) const { + if (s->getSolverDegree(n1Itr) > s->getSolverDegree(n2Itr)) + return true; + return false; + } + private: + HeuristicSolverImpl *s; + }; + + class SpillCostComparator { + public: + SpillCostComparator(HeuristicSolverImpl &s) + : s(&s), g(&s.getGraph()) {} + bool operator()(Graph::NodeItr n1Itr, Graph::NodeItr n2Itr) const { + const PBQP::Vector &cv1 = g->getNodeCosts(n1Itr); + const PBQP::Vector &cv2 = g->getNodeCosts(n2Itr); + + PBQPNum cost1 = cv1[0] / s->getSolverDegree(n1Itr); + PBQPNum cost2 = cv2[0] / s->getSolverDegree(n2Itr); + + if (cost1 < cost2) + return true; + return false; + } + + private: + HeuristicSolverImpl *s; + Graph *g; + }; + + typedef std::list RNAllocableList; + typedef RNAllocableList::iterator RNAllocableListItr; + + typedef std::list RNUnallocableList; + typedef RNUnallocableList::iterator RNUnallocableListItr; + + public: + + struct NodeData { + typedef std::vector UnsafeDegreesArray; + bool isHeuristic, isAllocable, isInitialized; + unsigned numDenied, numSafe; + UnsafeDegreesArray unsafeDegrees; + RNAllocableListItr rnaItr; + RNUnallocableListItr rnuItr; + + NodeData() + : isHeuristic(false), isAllocable(false), isInitialized(false), + numDenied(0), numSafe(0) { } + }; + + struct EdgeData { + typedef std::vector UnsafeArray; + unsigned worst, reverseWorst; + UnsafeArray unsafe, reverseUnsafe; + bool isUpToDate; + + EdgeData() : worst(0), reverseWorst(0), isUpToDate(false) {} + }; + + /// \brief Construct an instance of the Briggs heuristic. + /// @param solver A reference to the solver which is using this heuristic. + Briggs(HeuristicSolverImpl &solver) : + HeuristicBase(solver) {} + + /// \brief Determine whether a node should be reduced using optimal + /// reduction. + /// @param nItr Node iterator to be considered. + /// @return True if the given node should be optimally reduced, false + /// otherwise. + /// + /// Selects nodes of degree 0, 1 or 2 for optimal reduction, with one + /// exception. Nodes whose spill cost (element 0 of their cost vector) is + /// infinite are checked for allocability first. Allocable nodes may be + /// optimally reduced, but nodes whose allocability cannot be proven are + /// selected for heuristic reduction instead. + bool shouldOptimallyReduce(Graph::NodeItr nItr) { + if (getSolver().getSolverDegree(nItr) < 3) { + return true; + } + // else + return false; + } + + /// \brief Add a node to the heuristic reduce list. + /// @param nItr Node iterator to add to the heuristic reduce list. + void addToHeuristicReduceList(Graph::NodeItr nItr) { + NodeData &nd = getHeuristicNodeData(nItr); + initializeNode(nItr); + nd.isHeuristic = true; + if (nd.isAllocable) { + nd.rnaItr = rnAllocableList.insert(rnAllocableList.end(), nItr); + } else { + nd.rnuItr = rnUnallocableList.insert(rnUnallocableList.end(), nItr); + } + } + + /// \brief Heuristically reduce one of the nodes in the heuristic + /// reduce list. + /// @return True if a reduction takes place, false if the heuristic reduce + /// list is empty. + /// + /// If the list of allocable nodes is non-empty a node is selected + /// from it and pushed to the stack. Otherwise if the non-allocable list + /// is non-empty a node is selected from it and pushed to the stack. + /// If both lists are empty the method simply returns false with no action + /// taken. + bool heuristicReduce() { + if (!rnAllocableList.empty()) { + RNAllocableListItr rnaItr = + min_element(rnAllocableList.begin(), rnAllocableList.end(), + LinkDegreeComparator(getSolver())); + Graph::NodeItr nItr = *rnaItr; + rnAllocableList.erase(rnaItr); + handleRemoveNode(nItr); + getSolver().pushToStack(nItr); + return true; + } else if (!rnUnallocableList.empty()) { + RNUnallocableListItr rnuItr = + min_element(rnUnallocableList.begin(), rnUnallocableList.end(), + SpillCostComparator(getSolver())); + Graph::NodeItr nItr = *rnuItr; + rnUnallocableList.erase(rnuItr); + handleRemoveNode(nItr); + getSolver().pushToStack(nItr); + return true; + } + // else + return false; + } + + /// \brief Prepare a change in the costs on the given edge. + /// @param eItr Edge iterator. + void preUpdateEdgeCosts(Graph::EdgeItr eItr) { + Graph &g = getGraph(); + Graph::NodeItr n1Itr = g.getEdgeNode1(eItr), + n2Itr = g.getEdgeNode2(eItr); + NodeData &n1 = getHeuristicNodeData(n1Itr), + &n2 = getHeuristicNodeData(n2Itr); + + if (n1.isHeuristic) + subtractEdgeContributions(eItr, getGraph().getEdgeNode1(eItr)); + if (n2.isHeuristic) + subtractEdgeContributions(eItr, getGraph().getEdgeNode2(eItr)); + + EdgeData &ed = getHeuristicEdgeData(eItr); + ed.isUpToDate = false; + } + + /// \brief Handle the change in the costs on the given edge. + /// @param eItr Edge iterator. + void postUpdateEdgeCosts(Graph::EdgeItr eItr) { + // This is effectively the same as adding a new edge now, since + // we've factored out the costs of the old one. + handleAddEdge(eItr); + } + + /// \brief Handle the addition of a new edge into the PBQP graph. + /// @param eItr Edge iterator for the added edge. + /// + /// Updates allocability of any nodes connected by this edge which are + /// being managed by the heuristic. If allocability changes they are + /// moved to the appropriate list. + void handleAddEdge(Graph::EdgeItr eItr) { + Graph &g = getGraph(); + Graph::NodeItr n1Itr = g.getEdgeNode1(eItr), + n2Itr = g.getEdgeNode2(eItr); + NodeData &n1 = getHeuristicNodeData(n1Itr), + &n2 = getHeuristicNodeData(n2Itr); + + // If neither node is managed by the heuristic there's nothing to be + // done. + if (!n1.isHeuristic && !n2.isHeuristic) + return; + + // Ok - we need to update at least one node. + computeEdgeContributions(eItr); + + // Update node 1 if it's managed by the heuristic. + if (n1.isHeuristic) { + bool n1WasAllocable = n1.isAllocable; + addEdgeContributions(eItr, n1Itr); + updateAllocability(n1Itr); + if (n1WasAllocable && !n1.isAllocable) { + rnAllocableList.erase(n1.rnaItr); + n1.rnuItr = + rnUnallocableList.insert(rnUnallocableList.end(), n1Itr); + } + } + + // Likewise for node 2. + if (n2.isHeuristic) { + bool n2WasAllocable = n2.isAllocable; + addEdgeContributions(eItr, n2Itr); + updateAllocability(n2Itr); + if (n2WasAllocable && !n2.isAllocable) { + rnAllocableList.erase(n2.rnaItr); + n2.rnuItr = + rnUnallocableList.insert(rnUnallocableList.end(), n2Itr); + } + } + } + + /// \brief Handle disconnection of an edge from a node. + /// @param eItr Edge iterator for edge being disconnected. + /// @param nItr Node iterator for the node being disconnected from. + /// + /// Updates allocability of the given node and, if appropriate, moves the + /// node to a new list. + void handleRemoveEdge(Graph::EdgeItr eItr, Graph::NodeItr nItr) { + NodeData &nd = getHeuristicNodeData(nItr); + + // If the node is not managed by the heuristic there's nothing to be + // done. + if (!nd.isHeuristic) + return; + + EdgeData &ed = getHeuristicEdgeData(eItr); + (void)ed; + assert(ed.isUpToDate && "Edge data is not up to date."); + + // Update node. + bool ndWasAllocable = nd.isAllocable; + subtractEdgeContributions(eItr, nItr); + updateAllocability(nItr); + + // If the node has gone optimal... + if (shouldOptimallyReduce(nItr)) { + nd.isHeuristic = false; + addToOptimalReduceList(nItr); + if (ndWasAllocable) { + rnAllocableList.erase(nd.rnaItr); + } else { + rnUnallocableList.erase(nd.rnuItr); + } + } else { + // Node didn't go optimal, but we might have to move it + // from "unallocable" to "allocable". + if (!ndWasAllocable && nd.isAllocable) { + rnUnallocableList.erase(nd.rnuItr); + nd.rnaItr = rnAllocableList.insert(rnAllocableList.end(), nItr); + } + } + } + + private: + + NodeData& getHeuristicNodeData(Graph::NodeItr nItr) { + return getSolver().getHeuristicNodeData(nItr); + } + + EdgeData& getHeuristicEdgeData(Graph::EdgeItr eItr) { + return getSolver().getHeuristicEdgeData(eItr); + } + + // Work out what this edge will contribute to the allocability of the + // nodes connected to it. + void computeEdgeContributions(Graph::EdgeItr eItr) { + EdgeData &ed = getHeuristicEdgeData(eItr); + + if (ed.isUpToDate) + return; // Edge data is already up to date. + + Matrix &eCosts = getGraph().getEdgeCosts(eItr); + + unsigned numRegs = eCosts.getRows() - 1, + numReverseRegs = eCosts.getCols() - 1; + + std::vector rowInfCounts(numRegs, 0), + colInfCounts(numReverseRegs, 0); + + ed.worst = 0; + ed.reverseWorst = 0; + ed.unsafe.clear(); + ed.unsafe.resize(numRegs, 0); + ed.reverseUnsafe.clear(); + ed.reverseUnsafe.resize(numReverseRegs, 0); + + for (unsigned i = 0; i < numRegs; ++i) { + for (unsigned j = 0; j < numReverseRegs; ++j) { + if (eCosts[i + 1][j + 1] == + std::numeric_limits::infinity()) { + ed.unsafe[i] = 1; + ed.reverseUnsafe[j] = 1; + ++rowInfCounts[i]; + ++colInfCounts[j]; + + if (colInfCounts[j] > ed.worst) { + ed.worst = colInfCounts[j]; + } + + if (rowInfCounts[i] > ed.reverseWorst) { + ed.reverseWorst = rowInfCounts[i]; + } + } + } + } + + ed.isUpToDate = true; + } + + // Add the contributions of the given edge to the given node's + // numDenied and safe members. No action is taken other than to update + // these member values. Once updated these numbers can be used by clients + // to update the node's allocability. + void addEdgeContributions(Graph::EdgeItr eItr, Graph::NodeItr nItr) { + EdgeData &ed = getHeuristicEdgeData(eItr); + + assert(ed.isUpToDate && "Using out-of-date edge numbers."); + + NodeData &nd = getHeuristicNodeData(nItr); + unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1; + + bool nIsNode1 = nItr == getGraph().getEdgeNode1(eItr); + EdgeData::UnsafeArray &unsafe = + nIsNode1 ? ed.unsafe : ed.reverseUnsafe; + nd.numDenied += nIsNode1 ? ed.worst : ed.reverseWorst; + + for (unsigned r = 0; r < numRegs; ++r) { + if (unsafe[r]) { + if (nd.unsafeDegrees[r]==0) { + --nd.numSafe; + } + ++nd.unsafeDegrees[r]; + } + } + } + + // Subtract the contributions of the given edge to the given node's + // numDenied and safe members. No action is taken other than to update + // these member values. Once updated these numbers can be used by clients + // to update the node's allocability. + void subtractEdgeContributions(Graph::EdgeItr eItr, Graph::NodeItr nItr) { + EdgeData &ed = getHeuristicEdgeData(eItr); + + assert(ed.isUpToDate && "Using out-of-date edge numbers."); + + NodeData &nd = getHeuristicNodeData(nItr); + unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1; + + bool nIsNode1 = nItr == getGraph().getEdgeNode1(eItr); + EdgeData::UnsafeArray &unsafe = + nIsNode1 ? ed.unsafe : ed.reverseUnsafe; + nd.numDenied -= nIsNode1 ? ed.worst : ed.reverseWorst; + + for (unsigned r = 0; r < numRegs; ++r) { + if (unsafe[r]) { + if (nd.unsafeDegrees[r] == 1) { + ++nd.numSafe; + } + --nd.unsafeDegrees[r]; + } + } + } + + void updateAllocability(Graph::NodeItr nItr) { + NodeData &nd = getHeuristicNodeData(nItr); + unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1; + nd.isAllocable = nd.numDenied < numRegs || nd.numSafe > 0; + } + + void initializeNode(Graph::NodeItr nItr) { + NodeData &nd = getHeuristicNodeData(nItr); + + if (nd.isInitialized) + return; // Node data is already up to date. + + unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1; + + nd.numDenied = 0; + nd.numSafe = numRegs; + nd.unsafeDegrees.resize(numRegs, 0); + + typedef HeuristicSolverImpl::SolverEdgeItr SolverEdgeItr; + + for (SolverEdgeItr aeItr = getSolver().solverEdgesBegin(nItr), + aeEnd = getSolver().solverEdgesEnd(nItr); + aeItr != aeEnd; ++aeItr) { + + Graph::EdgeItr eItr = *aeItr; + computeEdgeContributions(eItr); + addEdgeContributions(eItr, nItr); + } + + updateAllocability(nItr); + nd.isInitialized = true; + } + + void handleRemoveNode(Graph::NodeItr xnItr) { + typedef HeuristicSolverImpl::SolverEdgeItr SolverEdgeItr; + std::vector edgesToRemove; + for (SolverEdgeItr aeItr = getSolver().solverEdgesBegin(xnItr), + aeEnd = getSolver().solverEdgesEnd(xnItr); + aeItr != aeEnd; ++aeItr) { + Graph::NodeItr ynItr = getGraph().getEdgeOtherNode(*aeItr, xnItr); + handleRemoveEdge(*aeItr, ynItr); + edgesToRemove.push_back(*aeItr); + } + while (!edgesToRemove.empty()) { + getSolver().removeSolverEdge(edgesToRemove.back()); + edgesToRemove.pop_back(); + } + } + + RNAllocableList rnAllocableList; + RNUnallocableList rnUnallocableList; + }; + + } +} + + +#endif // LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H diff --git a/include/llvm/CodeGen/PBQP/Math.h b/include/llvm/CodeGen/PBQP/Math.h new file mode 100644 index 000000000000..e7598bf3e3f1 --- /dev/null +++ b/include/llvm/CodeGen/PBQP/Math.h @@ -0,0 +1,288 @@ +//===------ Math.h - PBQP Vector and Matrix classes -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_PBQP_MATH_H +#define LLVM_CODEGEN_PBQP_MATH_H + +#include +#include +#include + +namespace PBQP { + +typedef float PBQPNum; + +/// \brief PBQP Vector class. +class Vector { + public: + + /// \brief Construct a PBQP vector of the given size. + explicit Vector(unsigned length) : + length(length), data(new PBQPNum[length]) { + } + + /// \brief Construct a PBQP vector with initializer. + Vector(unsigned length, PBQPNum initVal) : + length(length), data(new PBQPNum[length]) { + std::fill(data, data + length, initVal); + } + + /// \brief Copy construct a PBQP vector. + Vector(const Vector &v) : + length(v.length), data(new PBQPNum[length]) { + std::copy(v.data, v.data + length, data); + } + + /// \brief Destroy this vector, return its memory. + ~Vector() { delete[] data; } + + /// \brief Assignment operator. + Vector& operator=(const Vector &v) { + delete[] data; + length = v.length; + data = new PBQPNum[length]; + std::copy(v.data, v.data + length, data); + return *this; + } + + /// \brief Return the length of the vector + unsigned getLength() const { + return length; + } + + /// \brief Element access. + PBQPNum& operator[](unsigned index) { + assert(index < length && "Vector element access out of bounds."); + return data[index]; + } + + /// \brief Const element access. + const PBQPNum& operator[](unsigned index) const { + assert(index < length && "Vector element access out of bounds."); + return data[index]; + } + + /// \brief Add another vector to this one. + Vector& operator+=(const Vector &v) { + assert(length == v.length && "Vector length mismatch."); + std::transform(data, data + length, v.data, data, std::plus()); + return *this; + } + + /// \brief Subtract another vector from this one. + Vector& operator-=(const Vector &v) { + assert(length == v.length && "Vector length mismatch."); + std::transform(data, data + length, v.data, data, std::minus()); + return *this; + } + + /// \brief Returns the index of the minimum value in this vector + unsigned minIndex() const { + return std::min_element(data, data + length) - data; + } + + private: + unsigned length; + PBQPNum *data; +}; + +/// \brief Output a textual representation of the given vector on the given +/// output stream. +template +OStream& operator<<(OStream &os, const Vector &v) { + assert((v.getLength() != 0) && "Zero-length vector badness."); + + os << "[ " << v[0]; + for (unsigned i = 1; i < v.getLength(); ++i) { + os << ", " << v[i]; + } + os << " ]"; + + return os; +} + + +/// \brief PBQP Matrix class +class Matrix { + public: + + /// \brief Construct a PBQP Matrix with the given dimensions. + Matrix(unsigned rows, unsigned cols) : + rows(rows), cols(cols), data(new PBQPNum[rows * cols]) { + } + + /// \brief Construct a PBQP Matrix with the given dimensions and initial + /// value. + Matrix(unsigned rows, unsigned cols, PBQPNum initVal) : + rows(rows), cols(cols), data(new PBQPNum[rows * cols]) { + std::fill(data, data + (rows * cols), initVal); + } + + /// \brief Copy construct a PBQP matrix. + Matrix(const Matrix &m) : + rows(m.rows), cols(m.cols), data(new PBQPNum[rows * cols]) { + std::copy(m.data, m.data + (rows * cols), data); + } + + /// \brief Destroy this matrix, return its memory. + ~Matrix() { delete[] data; } + + /// \brief Assignment operator. + Matrix& operator=(const Matrix &m) { + delete[] data; + rows = m.rows; cols = m.cols; + data = new PBQPNum[rows * cols]; + std::copy(m.data, m.data + (rows * cols), data); + return *this; + } + + /// \brief Return the number of rows in this matrix. + unsigned getRows() const { return rows; } + + /// \brief Return the number of cols in this matrix. + unsigned getCols() const { return cols; } + + /// \brief Matrix element access. + PBQPNum* operator[](unsigned r) { + assert(r < rows && "Row out of bounds."); + return data + (r * cols); + } + + /// \brief Matrix element access. + const PBQPNum* operator[](unsigned r) const { + assert(r < rows && "Row out of bounds."); + return data + (r * cols); + } + + /// \brief Returns the given row as a vector. + Vector getRowAsVector(unsigned r) const { + Vector v(cols); + for (unsigned c = 0; c < cols; ++c) + v[c] = (*this)[r][c]; + return v; + } + + /// \brief Returns the given column as a vector. + Vector getColAsVector(unsigned c) const { + Vector v(rows); + for (unsigned r = 0; r < rows; ++r) + v[r] = (*this)[r][c]; + return v; + } + + /// \brief Reset the matrix to the given value. + Matrix& reset(PBQPNum val = 0) { + std::fill(data, data + (rows * cols), val); + return *this; + } + + /// \brief Set a single row of this matrix to the given value. + Matrix& setRow(unsigned r, PBQPNum val) { + assert(r < rows && "Row out of bounds."); + std::fill(data + (r * cols), data + ((r + 1) * cols), val); + return *this; + } + + /// \brief Set a single column of this matrix to the given value. + Matrix& setCol(unsigned c, PBQPNum val) { + assert(c < cols && "Column out of bounds."); + for (unsigned r = 0; r < rows; ++r) + (*this)[r][c] = val; + return *this; + } + + /// \brief Matrix transpose. + Matrix transpose() const { + Matrix m(cols, rows); + for (unsigned r = 0; r < rows; ++r) + for (unsigned c = 0; c < cols; ++c) + m[c][r] = (*this)[r][c]; + return m; + } + + /// \brief Returns the diagonal of the matrix as a vector. + /// + /// Matrix must be square. + Vector diagonalize() const { + assert(rows == cols && "Attempt to diagonalize non-square matrix."); + + Vector v(rows); + for (unsigned r = 0; r < rows; ++r) + v[r] = (*this)[r][r]; + return v; + } + + /// \brief Add the given matrix to this one. + Matrix& operator+=(const Matrix &m) { + assert(rows == m.rows && cols == m.cols && + "Matrix dimensions mismatch."); + std::transform(data, data + (rows * cols), m.data, data, + std::plus()); + return *this; + } + + /// \brief Returns the minimum of the given row + PBQPNum getRowMin(unsigned r) const { + assert(r < rows && "Row out of bounds"); + return *std::min_element(data + (r * cols), data + ((r + 1) * cols)); + } + + /// \brief Returns the minimum of the given column + PBQPNum getColMin(unsigned c) const { + PBQPNum minElem = (*this)[0][c]; + for (unsigned r = 1; r < rows; ++r) + if ((*this)[r][c] < minElem) minElem = (*this)[r][c]; + return minElem; + } + + /// \brief Subtracts the given scalar from the elements of the given row. + Matrix& subFromRow(unsigned r, PBQPNum val) { + assert(r < rows && "Row out of bounds"); + std::transform(data + (r * cols), data + ((r + 1) * cols), + data + (r * cols), + std::bind2nd(std::minus(), val)); + return *this; + } + + /// \brief Subtracts the given scalar from the elements of the given column. + Matrix& subFromCol(unsigned c, PBQPNum val) { + for (unsigned r = 0; r < rows; ++r) + (*this)[r][c] -= val; + return *this; + } + + /// \brief Returns true if this is a zero matrix. + bool isZero() const { + return find_if(data, data + (rows * cols), + std::bind2nd(std::not_equal_to(), 0)) == + data + (rows * cols); + } + + private: + unsigned rows, cols; + PBQPNum *data; +}; + +/// \brief Output a textual representation of the given matrix on the given +/// output stream. +template +OStream& operator<<(OStream &os, const Matrix &m) { + + assert((m.getRows() != 0) && "Zero-row matrix badness."); + + for (unsigned i = 0; i < m.getRows(); ++i) { + os << m.getRowAsVector(i); + } + + return os; +} + +} + +#endif // LLVM_CODEGEN_PBQP_MATH_H diff --git a/include/llvm/CodeGen/PBQP/Solution.h b/include/llvm/CodeGen/PBQP/Solution.h new file mode 100644 index 000000000000..57d9b95fc3b1 --- /dev/null +++ b/include/llvm/CodeGen/PBQP/Solution.h @@ -0,0 +1,94 @@ +//===-- Solution.h ------- PBQP Solution ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// PBQP Solution class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_PBQP_SOLUTION_H +#define LLVM_CODEGEN_PBQP_SOLUTION_H + +#include "Math.h" +#include "Graph.h" + +#include + +namespace PBQP { + + /// \brief Represents a solution to a PBQP problem. + /// + /// To get the selection for each node in the problem use the getSelection method. + class Solution { + private: + + typedef std::map SelectionsMap; + SelectionsMap selections; + + unsigned r0Reductions, r1Reductions, r2Reductions, rNReductions; + + public: + + /// \brief Initialise an empty solution. + Solution() + : r0Reductions(0), r1Reductions(0), r2Reductions(0), rNReductions(0) {} + + /// \brief Number of nodes for which selections have been made. + /// @return Number of nodes for which selections have been made. + unsigned numNodes() const { return selections.size(); } + + /// \brief Records a reduction via the R0 rule. Should be called from the + /// solver only. + void recordR0() { ++r0Reductions; } + + /// \brief Returns the number of R0 reductions applied to solve the problem. + unsigned numR0Reductions() const { return r0Reductions; } + + /// \brief Records a reduction via the R1 rule. Should be called from the + /// solver only. + void recordR1() { ++r1Reductions; } + + /// \brief Returns the number of R1 reductions applied to solve the problem. + unsigned numR1Reductions() const { return r1Reductions; } + + /// \brief Records a reduction via the R2 rule. Should be called from the + /// solver only. + void recordR2() { ++r2Reductions; } + + /// \brief Returns the number of R2 reductions applied to solve the problem. + unsigned numR2Reductions() const { return r2Reductions; } + + /// \brief Records a reduction via the RN rule. Should be called from the + /// solver only. + void recordRN() { ++ rNReductions; } + + /// \brief Returns the number of RN reductions applied to solve the problem. + unsigned numRNReductions() const { return rNReductions; } + + /// \brief Set the selection for a given node. + /// @param nItr Node iterator. + /// @param selection Selection for nItr. + void setSelection(Graph::NodeItr nItr, unsigned selection) { + selections[nItr] = selection; + } + + /// \brief Get a node's selection. + /// @param nItr Node iterator. + /// @return The selection for nItr; + unsigned getSelection(Graph::ConstNodeItr nItr) const { + SelectionsMap::const_iterator sItr = selections.find(nItr); + assert(sItr != selections.end() && "No selection for node."); + return sItr->second; + } + + }; + +} + +#endif // LLVM_CODEGEN_PBQP_SOLUTION_H diff --git a/include/llvm/CodeGen/Passes.h b/include/llvm/CodeGen/Passes.h index 4762a39cc669..53aee7a9c9f6 100644 --- a/include/llvm/CodeGen/Passes.h +++ b/include/llvm/CodeGen/Passes.h @@ -45,10 +45,19 @@ namespace llvm { /// extern char &MachineLoopInfoID; + /// MachineLoopRanges pass - This pass is an on-demand loop coverage + /// analysis pass. + /// + extern char &MachineLoopRangesID; + /// MachineDominators pass - This pass is a machine dominators analysis pass. /// extern char &MachineDominatorsID; + /// EdgeBundles analysis - Bundle machine CFG edges. + /// + extern char &EdgeBundlesID; + /// PHIElimination pass - This pass eliminates machine instruction PHI nodes /// by inserting copy instructions. This destroys SSA information, but is the /// desired input for some register allocators. This pass is "required" by @@ -66,6 +75,9 @@ namespace llvm { extern char &PreAllocSplittingID; + /// LiveStacks pass. An analysis keeping track of the liveness of stack slots. + extern char &LiveStacksID; + /// SimpleRegisterCoalescing pass. Aggressively coalesces every register /// copy it can. /// @@ -76,6 +88,11 @@ namespace llvm { /// register allocators. extern char &TwoAddressInstructionPassID; + /// SpillPlacement analysis. Suggest optimal placement of spill code between + /// basic blocks. + /// + extern char &SpillPlacementID; + /// UnreachableMachineBlockElimination pass - This pass removes unreachable /// machine basic blocks. extern char &UnreachableMachineBlockElimID; @@ -95,6 +112,16 @@ namespace llvm { /// FunctionPass *createFastRegisterAllocator(); + /// BasicRegisterAllocation Pass - This pass implements a degenerate global + /// register allocator using the basic regalloc framework. + /// + FunctionPass *createBasicRegisterAllocator(); + + /// Greedy register allocation pass - This pass implements a global register + /// allocator for optimized builds. + /// + FunctionPass *createGreedyRegisterAllocator(); + /// LinearScanRegisterAllocation Pass - This pass implements the linear scan /// register allocation algorithm, a global register allocator. /// @@ -103,7 +130,7 @@ namespace llvm { /// PBQPRegisterAllocation Pass - This pass implements the Partitioned Boolean /// Quadratic Prograaming (PBQP) based register allocator. /// - FunctionPass *createPBQPRegisterAllocator(); + FunctionPass *createDefaultPBQPRegisterAllocator(); /// SimpleRegisterCoalescing Pass - Coalesce all copies possible. Can run /// independently of the register allocator. @@ -188,7 +215,7 @@ namespace llvm { /// createMachineVerifierPass - This pass verifies cenerated machine code /// instructions for correctness. - FunctionPass *createMachineVerifierPass(); + FunctionPass *createMachineVerifierPass(const char *Banner = 0); /// createDwarfEHPass - This pass mulches exception handling code into a form /// adapted to code generation. Required if using dwarf exception handling. @@ -205,6 +232,10 @@ namespace llvm { /// addressing. FunctionPass *createLocalStackSlotAllocationPass(); + /// createExpandISelPseudosPass - This pass expands pseudo-instructions. + /// + FunctionPass *createExpandISelPseudosPass(); + } // End llvm namespace #endif diff --git a/include/llvm/CodeGen/PostRAHazardRecognizer.h b/include/llvm/CodeGen/PostRAHazardRecognizer.h deleted file mode 100644 index 24d73cb7860d..000000000000 --- a/include/llvm/CodeGen/PostRAHazardRecognizer.h +++ /dev/null @@ -1,94 +0,0 @@ -//=- llvm/CodeGen/PostRAHazardRecognizer.h - Scheduling Support -*- C++ -*-=// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the PostRAHazardRecognizer class, which -// implements hazard-avoidance heuristics for scheduling, based on the -// scheduling itineraries specified for the target. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CODEGEN_EXACTHAZARDRECOGNIZER_H -#define LLVM_CODEGEN_EXACTHAZARDRECOGNIZER_H - -#include "llvm/CodeGen/ScheduleHazardRecognizer.h" -#include "llvm/System/DataTypes.h" - -#include -#include -#include - -namespace llvm { - -class InstrItineraryData; -class SUnit; - -class PostRAHazardRecognizer : public ScheduleHazardRecognizer { - // ScoreBoard to track function unit usage. ScoreBoard[0] is a - // mask of the FUs in use in the cycle currently being - // schedule. ScoreBoard[1] is a mask for the next cycle. The - // ScoreBoard is used as a circular buffer with the current cycle - // indicated by Head. - class ScoreBoard { - unsigned *Data; - - // The maximum number of cycles monitored by the Scoreboard. This - // value is determined based on the target itineraries to ensure - // that all hazards can be tracked. - size_t Depth; - // Indices into the Scoreboard that represent the current cycle. - size_t Head; - public: - ScoreBoard():Data(NULL), Depth(0), Head(0) { } - ~ScoreBoard() { - delete[] Data; - } - - size_t getDepth() const { return Depth; } - unsigned& operator[](size_t idx) const { - assert(Depth && "ScoreBoard was not initialized properly!"); - - return Data[(Head + idx) % Depth]; - } - - void reset(size_t d = 1) { - if (Data == NULL) { - Depth = d; - Data = new unsigned[Depth]; - } - - memset(Data, 0, Depth * sizeof(Data[0])); - Head = 0; - } - - void advance() { - Head = (Head + 1) % Depth; - } - - // Print the scoreboard. - void dump() const; - }; - - // Itinerary data for the target. - const InstrItineraryData &ItinData; - - ScoreBoard ReservedScoreboard; - ScoreBoard RequiredScoreboard; - -public: - PostRAHazardRecognizer(const InstrItineraryData &ItinData); - - virtual HazardType getHazardType(SUnit *SU); - virtual void Reset(); - virtual void EmitInstruction(SUnit *SU); - virtual void AdvanceCycle(); -}; - -} - -#endif diff --git a/include/llvm/CodeGen/ProcessImplicitDefs.h b/include/llvm/CodeGen/ProcessImplicitDefs.h index 1d743c1cba24..e2ab899f183f 100644 --- a/include/llvm/CodeGen/ProcessImplicitDefs.h +++ b/include/llvm/CodeGen/ProcessImplicitDefs.h @@ -31,7 +31,9 @@ namespace llvm { public: static char ID; - ProcessImplicitDefs() : MachineFunctionPass(ID) {} + ProcessImplicitDefs() : MachineFunctionPass(ID) { + initializeProcessImplicitDefsPass(*PassRegistry::getPassRegistry()); + } virtual void getAnalysisUsage(AnalysisUsage &au) const; diff --git a/include/llvm/CodeGen/RegAllocPBQP.h b/include/llvm/CodeGen/RegAllocPBQP.h new file mode 100644 index 000000000000..7e8745eddef8 --- /dev/null +++ b/include/llvm/CodeGen/RegAllocPBQP.h @@ -0,0 +1,167 @@ +//===-- RegAllocPBQP.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PBQPBuilder interface, for classes which build PBQP +// instances to represent register allocation problems, and the RegAllocPBQP +// interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_REGALLOCPBQP_H +#define LLVM_CODEGEN_REGALLOCPBQP_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/PBQP/Graph.h" +#include "llvm/CodeGen/PBQP/Solution.h" + +#include +#include + +namespace llvm { + + class LiveIntervals; + class MachineFunction; + class MachineLoopInfo; + + /// This class wraps up a PBQP instance representing a register allocation + /// problem, plus the structures necessary to map back from the PBQP solution + /// to a register allocation solution. (i.e. The PBQP-node <--> vreg map, + /// and the PBQP option <--> storage location map). + + class PBQPRAProblem { + public: + + typedef SmallVector AllowedSet; + + PBQP::Graph& getGraph() { return graph; } + + const PBQP::Graph& getGraph() const { return graph; } + + /// Record the mapping between the given virtual register and PBQP node, + /// and the set of allowed pregs for the vreg. + /// + /// If you are extending + /// PBQPBuilder you are unlikely to need this: Nodes and options for all + /// vregs will already have been set up for you by the base class. + template + void recordVReg(unsigned vreg, PBQP::Graph::NodeItr node, + AllowedRegsItr arBegin, AllowedRegsItr arEnd) { + assert(node2VReg.find(node) == node2VReg.end() && "Re-mapping node."); + assert(vreg2Node.find(vreg) == vreg2Node.end() && "Re-mapping vreg."); + assert(allowedSets[vreg].empty() && "vreg already has pregs."); + + node2VReg[node] = vreg; + vreg2Node[vreg] = node; + std::copy(arBegin, arEnd, std::back_inserter(allowedSets[vreg])); + } + + /// Get the virtual register corresponding to the given PBQP node. + unsigned getVRegForNode(PBQP::Graph::ConstNodeItr node) const; + + /// Get the PBQP node corresponding to the given virtual register. + PBQP::Graph::NodeItr getNodeForVReg(unsigned vreg) const; + + /// Returns true if the given PBQP option represents a physical register, + /// false otherwise. + bool isPRegOption(unsigned vreg, unsigned option) const { + // At present we only have spills or pregs, so anything that's not a + // spill is a preg. (This might be extended one day to support remat). + return !isSpillOption(vreg, option); + } + + /// Returns true if the given PBQP option represents spilling, false + /// otherwise. + bool isSpillOption(unsigned vreg, unsigned option) const { + // We hardcode option zero as the spill option. + return option == 0; + } + + /// Returns the allowed set for the given virtual register. + const AllowedSet& getAllowedSet(unsigned vreg) const; + + /// Get PReg for option. + unsigned getPRegForOption(unsigned vreg, unsigned option) const; + + private: + + typedef std::map Node2VReg; + typedef DenseMap VReg2Node; + typedef std::map AllowedSetMap; + + PBQP::Graph graph; + Node2VReg node2VReg; + VReg2Node vreg2Node; + + AllowedSetMap allowedSets; + + }; + + /// Builds PBQP instances to represent register allocation problems. Includes + /// spill, interference and coalescing costs by default. You can extend this + /// class to support additional constraints for your architecture. + class PBQPBuilder { + private: + PBQPBuilder(const PBQPBuilder&) {} + void operator=(const PBQPBuilder&) {} + public: + + typedef std::set RegSet; + + /// Default constructor. + PBQPBuilder() {} + + /// Clean up a PBQPBuilder. + virtual ~PBQPBuilder() {} + + /// Build a PBQP instance to represent the register allocation problem for + /// the given MachineFunction. + virtual std::auto_ptr build( + MachineFunction *mf, + const LiveIntervals *lis, + const MachineLoopInfo *loopInfo, + const RegSet &vregs); + private: + + void addSpillCosts(PBQP::Vector &costVec, PBQP::PBQPNum spillCost); + + void addInterferenceCosts(PBQP::Matrix &costMat, + const PBQPRAProblem::AllowedSet &vr1Allowed, + const PBQPRAProblem::AllowedSet &vr2Allowed, + const TargetRegisterInfo *tri); + }; + + /// Extended builder which adds coalescing constraints to a problem. + class PBQPBuilderWithCoalescing : public PBQPBuilder { + public: + + /// Build a PBQP instance to represent the register allocation problem for + /// the given MachineFunction. + virtual std::auto_ptr build( + MachineFunction *mf, + const LiveIntervals *lis, + const MachineLoopInfo *loopInfo, + const RegSet &vregs); + + private: + + void addPhysRegCoalesce(PBQP::Vector &costVec, unsigned pregOption, + PBQP::PBQPNum benefit); + + void addVirtRegCoalesce(PBQP::Matrix &costMat, + const PBQPRAProblem::AllowedSet &vr1Allowed, + const PBQPRAProblem::AllowedSet &vr2Allowed, + PBQP::PBQPNum benefit); + }; + + FunctionPass* createPBQPRegisterAllocator(std::auto_ptr builder); +} + +#endif /* LLVM_CODEGEN_REGALLOCPBQP_H */ diff --git a/include/llvm/CodeGen/RegisterCoalescer.h b/include/llvm/CodeGen/RegisterCoalescer.h index 7644433a33a1..af0b3946912b 100644 --- a/include/llvm/CodeGen/RegisterCoalescer.h +++ b/include/llvm/CodeGen/RegisterCoalescer.h @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm/System/IncludeFile.h" +#include "llvm/Support/IncludeFile.h" #include "llvm/CodeGen/LiveInterval.h" #include "llvm/ADT/SmallPtrSet.h" diff --git a/include/llvm/CodeGen/ScheduleDAG.h b/include/llvm/CodeGen/ScheduleDAG.h index 076268b99c20..3864ffd50a19 100644 --- a/include/llvm/CodeGen/ScheduleDAG.h +++ b/include/llvm/CodeGen/ScheduleDAG.h @@ -221,6 +221,9 @@ namespace llvm { } }; + template <> + struct isPodLike { static const bool value = true; }; + /// SUnit - Scheduling unit. This is a node in the scheduling DAG. class SUnit { private: @@ -229,9 +232,8 @@ namespace llvm { public: SUnit *OrigNode; // If not this, the node from which // this node was cloned. - - // Preds/Succs - The SUnits before/after us in the graph. The boolean value - // is true if the edge is a token chain edge, false if it is a value edge. + + // Preds/Succs - The SUnits before/after us in the graph. SmallVector Preds; // All sunit predecessors. SmallVector Succs; // All sunit successors. @@ -242,11 +244,13 @@ namespace llvm { unsigned NodeNum; // Entry # of node in the node vector. unsigned NodeQueueId; // Queue id of node. - unsigned short Latency; // Node latency. unsigned NumPreds; // # of SDep::Data preds. unsigned NumSuccs; // # of SDep::Data sucss. unsigned NumPredsLeft; // # of preds not scheduled. unsigned NumSuccsLeft; // # of succs not scheduled. + unsigned short NumRegDefsLeft; // # of reg defs with no scheduled use. + unsigned short Latency; // Node latency. + bool isCall : 1; // Is a function call. bool isTwoAddress : 1; // Is a two-address instruction. bool isCommutable : 1; // Is a commutable instruction. bool hasPhysRegDefs : 1; // Has physreg defs that are being used. @@ -267,13 +271,14 @@ namespace llvm { public: const TargetRegisterClass *CopyDstRC; // Is a special copy node if not null. const TargetRegisterClass *CopySrcRC; - + /// SUnit - Construct an SUnit for pre-regalloc scheduling to represent /// an SDNode and any nodes flagged to it. SUnit(SDNode *node, unsigned nodenum) : Node(node), Instr(0), OrigNode(0), NodeNum(nodenum), - NodeQueueId(0), Latency(0), NumPreds(0), NumSuccs(0), NumPredsLeft(0), - NumSuccsLeft(0), isTwoAddress(false), isCommutable(false), + NodeQueueId(0), NumPreds(0), NumSuccs(0), NumPredsLeft(0), + NumSuccsLeft(0), NumRegDefsLeft(0), Latency(0), + isCall(false), isTwoAddress(false), isCommutable(false), hasPhysRegDefs(false), hasPhysRegClobbers(false), isPending(false), isAvailable(false), isScheduled(false), isScheduleHigh(false), isCloned(false), @@ -285,8 +290,9 @@ namespace llvm { /// a MachineInstr. SUnit(MachineInstr *instr, unsigned nodenum) : Node(0), Instr(instr), OrigNode(0), NodeNum(nodenum), - NodeQueueId(0), Latency(0), NumPreds(0), NumSuccs(0), NumPredsLeft(0), - NumSuccsLeft(0), isTwoAddress(false), isCommutable(false), + NodeQueueId(0), NumPreds(0), NumSuccs(0), NumPredsLeft(0), + NumSuccsLeft(0), NumRegDefsLeft(0), Latency(0), + isCall(false), isTwoAddress(false), isCommutable(false), hasPhysRegDefs(false), hasPhysRegClobbers(false), isPending(false), isAvailable(false), isScheduled(false), isScheduleHigh(false), isCloned(false), @@ -297,8 +303,9 @@ namespace llvm { /// SUnit - Construct a placeholder SUnit. SUnit() : Node(0), Instr(0), OrigNode(0), NodeNum(~0u), - NodeQueueId(0), Latency(0), NumPreds(0), NumSuccs(0), NumPredsLeft(0), - NumSuccsLeft(0), isTwoAddress(false), isCommutable(false), + NodeQueueId(0), NumPreds(0), NumSuccs(0), NumPredsLeft(0), + NumSuccsLeft(0), NumRegDefsLeft(0), Latency(0), + isCall(false), isTwoAddress(false), isCommutable(false), hasPhysRegDefs(false), hasPhysRegClobbers(false), isPending(false), isAvailable(false), isScheduled(false), isScheduleHigh(false), isCloned(false), @@ -320,6 +327,10 @@ namespace llvm { return Node; } + /// isInstr - Return true if this SUnit refers to a machine instruction as + /// opposed to an SDNode. + bool isInstr() const { return Instr; } + /// setInstr - Assign the instruction for the SUnit. /// This may be used during post-regalloc scheduling. void setInstr(MachineInstr *MI) { @@ -337,7 +348,7 @@ namespace llvm { /// addPred - This adds the specified edge as a pred of the current node if /// not already. It also adds the current node as a successor of the /// specified node. - void addPred(const SDep &D); + bool addPred(const SDep &D); /// removePred - This removes the specified edge as a pred of the current /// node if it exists. It also removes the current node as a successor of @@ -347,7 +358,7 @@ namespace llvm { /// getDepth - Return the depth of this node, which is the length of the /// maximum path up to any node with has no predecessors. unsigned getDepth() const { - if (!isDepthCurrent) + if (!isDepthCurrent) const_cast(this)->ComputeDepth(); return Depth; } @@ -355,7 +366,7 @@ namespace llvm { /// getHeight - Return the height of this node, which is the length of the /// maximum path down to any node with has no successors. unsigned getHeight() const { - if (!isHeightCurrent) + if (!isHeightCurrent) const_cast(this)->ComputeHeight(); return Height; } @@ -387,7 +398,7 @@ namespace llvm { return true; return false; } - + /// isSucc - Test if node N is a successor of this node. bool isSucc(SUnit *N) { for (unsigned i = 0, e = (unsigned)Succs.size(); i != e; ++i) @@ -408,25 +419,38 @@ namespace llvm { //===--------------------------------------------------------------------===// /// SchedulingPriorityQueue - This interface is used to plug different /// priorities computation algorithms into the list scheduler. It implements - /// the interface of a standard priority queue, where nodes are inserted in + /// the interface of a standard priority queue, where nodes are inserted in /// arbitrary order and returned in priority order. The computation of the /// priority and the representation of the queue are totally up to the /// implementation to decide. - /// + /// class SchedulingPriorityQueue { unsigned CurCycle; + bool HasReadyFilter; public: - SchedulingPriorityQueue() : CurCycle(0) {} + SchedulingPriorityQueue(bool rf = false): + CurCycle(0), HasReadyFilter(rf) {} virtual ~SchedulingPriorityQueue() {} - + + virtual bool isBottomUp() const = 0; + virtual void initNodes(std::vector &SUnits) = 0; virtual void addNode(const SUnit *SU) = 0; virtual void updateNode(const SUnit *SU) = 0; virtual void releaseState() = 0; virtual bool empty() const = 0; + + bool hasReadyFilter() const { return HasReadyFilter; } + + virtual bool tracksRegPressure() const { return false; } + + virtual bool isReady(SUnit *) const { + assert(!HasReadyFilter && "The ready filter must override isReady()"); + return true; + } virtual void push(SUnit *U) = 0; - + void push_all(const std::vector &Nodes) { for (std::vector::const_iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) @@ -437,6 +461,8 @@ namespace llvm { virtual void remove(SUnit *SU) = 0; + virtual void dump(ScheduleDAG *) const {} + /// ScheduledNode - As each node is scheduled, this method is invoked. This /// allows the priority function to adjust the priority of related /// unscheduled nodes, for example. @@ -451,7 +477,7 @@ namespace llvm { unsigned getCurCycle() const { return CurCycle; - } + } }; class ScheduleDAG { @@ -473,11 +499,18 @@ namespace llvm { virtual ~ScheduleDAG(); + /// getInstrDesc - Return the TargetInstrDesc of this SUnit. + /// Return NULL for SDNodes without a machine opcode. + const TargetInstrDesc *getInstrDesc(const SUnit *SU) const { + if (SU->isInstr()) return &SU->getInstr()->getDesc(); + return getNodeDesc(SU->getNode()); + } + /// viewGraph - Pop up a GraphViz/gv window with the ScheduleDAG rendered /// using 'dot'. /// void viewGraph(); - + /// EmitSchedule - Insert MachineInstrs into the MachineBasicBlock /// according to the order specified in Sequence. /// @@ -536,6 +569,10 @@ namespace llvm { void EmitNoop(); void EmitPhysRegCopy(SUnit *SU, DenseMap &VRBaseMap); + + private: + // Return the TargetInstrDesc of this SDNode or NULL. + const TargetInstrDesc *getNodeDesc(const SDNode *Node) const; }; class SUnitIterator : public std::iterator &SUnits); - /// InitDAGTopologicalSorting - create the initial topological + /// InitDAGTopologicalSorting - create the initial topological /// ordering from the DAG to be scheduled. void InitDAGTopologicalSorting(); diff --git a/include/llvm/CodeGen/ScheduleHazardRecognizer.h b/include/llvm/CodeGen/ScheduleHazardRecognizer.h index 09e3e8861316..2f53baa1c7e6 100644 --- a/include/llvm/CodeGen/ScheduleHazardRecognizer.h +++ b/include/llvm/CodeGen/ScheduleHazardRecognizer.h @@ -23,7 +23,15 @@ class SUnit; /// issued this cycle, and whether or not a noop needs to be inserted to handle /// the hazard. class ScheduleHazardRecognizer { +protected: + /// MaxLookAhead - Indicate the number of cycles in the scoreboard + /// state. Important to restore the state after backtracking. Additionally, + /// MaxLookAhead=0 identifies a fake recognizer, allowing the client to + /// bypass virtual calls. Currently the PostRA scheduler ignores it. + unsigned MaxLookAhead; + public: + ScheduleHazardRecognizer(): MaxLookAhead(0) {} virtual ~ScheduleHazardRecognizer(); enum HazardType { @@ -32,6 +40,14 @@ public: NoopHazard // This instruction can't be emitted, and needs noops. }; + unsigned getMaxLookAhead() const { return MaxLookAhead; } + + bool isEnabled() const { return MaxLookAhead != 0; } + + /// atIssueLimit - Return true if no more instructions may be issued in this + /// cycle. + virtual bool atIssueLimit() const { return false; } + /// getHazardType - Return the hazard type of emitting this node. There are /// three possible results. Either: /// * NoHazard: it is legal to issue this instruction on this cycle. @@ -39,7 +55,7 @@ public: /// other instruction is available, issue it first. /// * NoopHazard: issuing this instruction would break the program. If /// some other instruction can be issued, do so, otherwise issue a noop. - virtual HazardType getHazardType(SUnit *) { + virtual HazardType getHazardType(SUnit *m, int Stalls) { return NoHazard; } @@ -52,12 +68,18 @@ public: /// emitted, to advance the hazard state. virtual void EmitInstruction(SUnit *) {} - /// AdvanceCycle - This callback is invoked when no instructions can be - /// issued on this cycle without a hazard. This should increment the + /// AdvanceCycle - This callback is invoked whenever the next top-down + /// instruction to be scheduled cannot issue in the current cycle, either + /// because of latency or resource conflicts. This should increment the /// internal state of the hazard recognizer so that previously "Hazard" /// instructions will now not be hazards. virtual void AdvanceCycle() {} + /// RecedeCycle - This callback is invoked whenever the next bottom-up + /// instruction to be scheduled cannot issue in the current cycle, either + /// because of latency or resource conflicts. + virtual void RecedeCycle() {} + /// EmitNoop - This callback is invoked when a noop was added to the /// instruction stream. virtual void EmitNoop() { diff --git a/include/llvm/CodeGen/ScoreboardHazardRecognizer.h b/include/llvm/CodeGen/ScoreboardHazardRecognizer.h new file mode 100644 index 000000000000..8850006df84c --- /dev/null +++ b/include/llvm/CodeGen/ScoreboardHazardRecognizer.h @@ -0,0 +1,129 @@ +//=- llvm/CodeGen/ScoreboardHazardRecognizer.h - Schedule Support -*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ScoreboardHazardRecognizer class, which +// encapsulates hazard-avoidance heuristics for scheduling, based on the +// scheduling itineraries specified for the target. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_SCOREBOARDHAZARDRECOGNIZER_H +#define LLVM_CODEGEN_SCOREBOARDHAZARDRECOGNIZER_H + +#include "llvm/CodeGen/ScheduleHazardRecognizer.h" +#include "llvm/Support/DataTypes.h" + +#include +#include +#include + +namespace llvm { + +class InstrItineraryData; +class TargetInstrDesc; +class ScheduleDAG; +class SUnit; + +class ScoreboardHazardRecognizer : public ScheduleHazardRecognizer { + // Scoreboard to track function unit usage. Scoreboard[0] is a + // mask of the FUs in use in the cycle currently being + // schedule. Scoreboard[1] is a mask for the next cycle. The + // Scoreboard is used as a circular buffer with the current cycle + // indicated by Head. + // + // Scoreboard always counts cycles in forward execution order. If used by a + // bottom-up scheduler, then the scoreboard cycles are the inverse of the + // scheduler's cycles. + class Scoreboard { + unsigned *Data; + + // The maximum number of cycles monitored by the Scoreboard. This + // value is determined based on the target itineraries to ensure + // that all hazards can be tracked. + size_t Depth; + // Indices into the Scoreboard that represent the current cycle. + size_t Head; + public: + Scoreboard():Data(NULL), Depth(0), Head(0) { } + ~Scoreboard() { + delete[] Data; + } + + size_t getDepth() const { return Depth; } + unsigned& operator[](size_t idx) const { + // Depth is expected to be a power-of-2. + assert(Depth && !(Depth & (Depth - 1)) && + "Scoreboard was not initialized properly!"); + + return Data[(Head + idx) & (Depth-1)]; + } + + void reset(size_t d = 1) { + if (Data == NULL) { + Depth = d; + Data = new unsigned[Depth]; + } + + memset(Data, 0, Depth * sizeof(Data[0])); + Head = 0; + } + + void advance() { + Head = (Head + 1) & (Depth-1); + } + + void recede() { + Head = (Head - 1) & (Depth-1); + } + + // Print the scoreboard. + void dump() const; + }; + +#ifndef NDEBUG + // Support for tracing ScoreboardHazardRecognizer as a component within + // another module. Follows the current thread-unsafe model of tracing. + static const char *DebugType; +#endif + + // Itinerary data for the target. + const InstrItineraryData *ItinData; + + const ScheduleDAG *DAG; + + /// IssueWidth - Max issue per cycle. 0=Unknown. + unsigned IssueWidth; + + /// IssueCount - Count instructions issued in this cycle. + unsigned IssueCount; + + Scoreboard ReservedScoreboard; + Scoreboard RequiredScoreboard; + +public: + ScoreboardHazardRecognizer(const InstrItineraryData *ItinData, + const ScheduleDAG *DAG, + const char *ParentDebugType = ""); + + /// atIssueLimit - Return true if no more instructions may be issued in this + /// cycle. + virtual bool atIssueLimit() const; + + // Stalls provides an cycle offset at which SU will be scheduled. It will be + // negative for bottom-up scheduling. + virtual HazardType getHazardType(SUnit *SU, int Stalls); + virtual void Reset(); + virtual void EmitInstruction(SUnit *SU); + virtual void AdvanceCycle(); + virtual void RecedeCycle(); +}; + +} + +#endif //!LLVM_CODEGEN_SCOREBOARDHAZARDRECOGNIZER_H diff --git a/include/llvm/CodeGen/SelectionDAG.h b/include/llvm/CodeGen/SelectionDAG.h index 7723fa00e90d..c9de95bebd54 100644 --- a/include/llvm/CodeGen/SelectionDAG.h +++ b/include/llvm/CodeGen/SelectionDAG.h @@ -171,9 +171,6 @@ class SelectionDAG { /// DbgInfo - Tracks dbg_value information through SDISel. SDDbgInfo *DbgInfo; - /// VerifyNode - Sanity check the given node. Aborts if it is invalid. - void VerifyNode(SDNode *N); - /// setGraphColorHelper - Implementation of setSubgraphColor. /// Return whether we had to truncate the search. /// @@ -401,21 +398,21 @@ public: } // This version of the getCopyToReg method takes an extra operand, which - // indicates that there is potentially an incoming flag value (if Flag is not - // null) and that there should be a flag result. + // indicates that there is potentially an incoming glue value (if Glue is not + // null) and that there should be a glue result. SDValue getCopyToReg(SDValue Chain, DebugLoc dl, unsigned Reg, SDValue N, - SDValue Flag) { - SDVTList VTs = getVTList(MVT::Other, MVT::Flag); - SDValue Ops[] = { Chain, getRegister(Reg, N.getValueType()), N, Flag }; - return getNode(ISD::CopyToReg, dl, VTs, Ops, Flag.getNode() ? 4 : 3); + SDValue Glue) { + SDVTList VTs = getVTList(MVT::Other, MVT::Glue); + SDValue Ops[] = { Chain, getRegister(Reg, N.getValueType()), N, Glue }; + return getNode(ISD::CopyToReg, dl, VTs, Ops, Glue.getNode() ? 4 : 3); } // Similar to last getCopyToReg() except parameter Reg is a SDValue SDValue getCopyToReg(SDValue Chain, DebugLoc dl, SDValue Reg, SDValue N, - SDValue Flag) { - SDVTList VTs = getVTList(MVT::Other, MVT::Flag); - SDValue Ops[] = { Chain, Reg, N, Flag }; - return getNode(ISD::CopyToReg, dl, VTs, Ops, Flag.getNode() ? 4 : 3); + SDValue Glue) { + SDVTList VTs = getVTList(MVT::Other, MVT::Glue); + SDValue Ops[] = { Chain, Reg, N, Glue }; + return getNode(ISD::CopyToReg, dl, VTs, Ops, Glue.getNode() ? 4 : 3); } SDValue getCopyFromReg(SDValue Chain, DebugLoc dl, unsigned Reg, EVT VT) { @@ -425,13 +422,13 @@ public: } // This version of the getCopyFromReg method takes an extra operand, which - // indicates that there is potentially an incoming flag value (if Flag is not - // null) and that there should be a flag result. + // indicates that there is potentially an incoming glue value (if Glue is not + // null) and that there should be a glue result. SDValue getCopyFromReg(SDValue Chain, DebugLoc dl, unsigned Reg, EVT VT, - SDValue Flag) { - SDVTList VTs = getVTList(VT, MVT::Other, MVT::Flag); - SDValue Ops[] = { Chain, getRegister(Reg, VT), Flag }; - return getNode(ISD::CopyFromReg, dl, VTs, Ops, Flag.getNode() ? 3 : 2); + SDValue Glue) { + SDVTList VTs = getVTList(VT, MVT::Other, MVT::Glue); + SDValue Ops[] = { Chain, getRegister(Reg, VT), Glue }; + return getNode(ISD::CopyFromReg, dl, VTs, Ops, Glue.getNode() ? 3 : 2); } SDValue getCondCode(ISD::CondCode Cond); @@ -465,27 +462,27 @@ public: SDValue getNOT(DebugLoc DL, SDValue Val, EVT VT); /// getCALLSEQ_START - Return a new CALLSEQ_START node, which always must have - /// a flag result (to ensure it's not CSE'd). CALLSEQ_START does not have a + /// a glue result (to ensure it's not CSE'd). CALLSEQ_START does not have a /// useful DebugLoc. SDValue getCALLSEQ_START(SDValue Chain, SDValue Op) { - SDVTList VTs = getVTList(MVT::Other, MVT::Flag); + SDVTList VTs = getVTList(MVT::Other, MVT::Glue); SDValue Ops[] = { Chain, Op }; return getNode(ISD::CALLSEQ_START, DebugLoc(), VTs, Ops, 2); } /// getCALLSEQ_END - Return a new CALLSEQ_END node, which always must have a - /// flag result (to ensure it's not CSE'd). CALLSEQ_END does not have + /// glue result (to ensure it's not CSE'd). CALLSEQ_END does not have /// a useful DebugLoc. SDValue getCALLSEQ_END(SDValue Chain, SDValue Op1, SDValue Op2, - SDValue InFlag) { - SDVTList NodeTys = getVTList(MVT::Other, MVT::Flag); + SDValue InGlue) { + SDVTList NodeTys = getVTList(MVT::Other, MVT::Glue); SmallVector Ops; Ops.push_back(Chain); Ops.push_back(Op1); Ops.push_back(Op2); - Ops.push_back(InFlag); + Ops.push_back(InGlue); return getNode(ISD::CALLSEQ_END, DebugLoc(), NodeTys, &Ops[0], - (unsigned)Ops.size() - (InFlag.getNode() == 0 ? 1 : 0)); + (unsigned)Ops.size() - (InGlue.getNode() == 0 ? 1 : 0)); } /// getUNDEF - Return an UNDEF node. UNDEF does not have a useful DebugLoc. @@ -542,17 +539,17 @@ public: SDValue getMemcpy(SDValue Chain, DebugLoc dl, SDValue Dst, SDValue Src, SDValue Size, unsigned Align, bool isVol, bool AlwaysInline, - const Value *DstSV, uint64_t DstSVOff, - const Value *SrcSV, uint64_t SrcSVOff); + MachinePointerInfo DstPtrInfo, + MachinePointerInfo SrcPtrInfo); SDValue getMemmove(SDValue Chain, DebugLoc dl, SDValue Dst, SDValue Src, SDValue Size, unsigned Align, bool isVol, - const Value *DstSV, uint64_t DstOSVff, - const Value *SrcSV, uint64_t SrcSVOff); + MachinePointerInfo DstPtrInfo, + MachinePointerInfo SrcPtrInfo); SDValue getMemset(SDValue Chain, DebugLoc dl, SDValue Dst, SDValue Src, SDValue Size, unsigned Align, bool isVol, - const Value *DstSV, uint64_t DstSVOff); + MachinePointerInfo DstPtrInfo); /// getSetCC - Helper function to make it easier to build SetCC's if you just /// have an ISD::CondCode instead of an SDValue. @@ -587,8 +584,8 @@ public: /// getAtomic - Gets a node for an atomic op, produces result and chain and /// takes 3 operands SDValue getAtomic(unsigned Opcode, DebugLoc dl, EVT MemVT, SDValue Chain, - SDValue Ptr, SDValue Cmp, SDValue Swp, const Value* PtrVal, - unsigned Alignment=0); + SDValue Ptr, SDValue Cmp, SDValue Swp, + MachinePointerInfo PtrInfo, unsigned Alignment=0); SDValue getAtomic(unsigned Opcode, DebugLoc dl, EVT MemVT, SDValue Chain, SDValue Ptr, SDValue Cmp, SDValue Swp, MachineMemOperand *MMO); @@ -609,13 +606,13 @@ public: SDValue getMemIntrinsicNode(unsigned Opcode, DebugLoc dl, const EVT *VTs, unsigned NumVTs, const SDValue *Ops, unsigned NumOps, - EVT MemVT, const Value *srcValue, int SVOff, + EVT MemVT, MachinePointerInfo PtrInfo, unsigned Align = 0, bool Vol = false, bool ReadMem = true, bool WriteMem = true); SDValue getMemIntrinsicNode(unsigned Opcode, DebugLoc dl, SDVTList VTList, const SDValue *Ops, unsigned NumOps, - EVT MemVT, const Value *srcValue, int SVOff, + EVT MemVT, MachinePointerInfo PtrInfo, unsigned Align = 0, bool Vol = false, bool ReadMem = true, bool WriteMem = true); @@ -630,19 +627,22 @@ public: /// determined by their operands, and they produce a value AND a token chain. /// SDValue getLoad(EVT VT, DebugLoc dl, SDValue Chain, SDValue Ptr, - const Value *SV, int SVOffset, bool isVolatile, - bool isNonTemporal, unsigned Alignment); - SDValue getExtLoad(ISD::LoadExtType ExtType, EVT VT, DebugLoc dl, - SDValue Chain, SDValue Ptr, const Value *SV, - int SVOffset, EVT MemVT, bool isVolatile, - bool isNonTemporal, unsigned Alignment); + MachinePointerInfo PtrInfo, bool isVolatile, + bool isNonTemporal, unsigned Alignment, + const MDNode *TBAAInfo = 0); + SDValue getExtLoad(ISD::LoadExtType ExtType, DebugLoc dl, EVT VT, + SDValue Chain, SDValue Ptr, MachinePointerInfo PtrInfo, + EVT MemVT, bool isVolatile, + bool isNonTemporal, unsigned Alignment, + const MDNode *TBAAInfo = 0); SDValue getIndexedLoad(SDValue OrigLoad, DebugLoc dl, SDValue Base, SDValue Offset, ISD::MemIndexedMode AM); SDValue getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, EVT VT, DebugLoc dl, SDValue Chain, SDValue Ptr, SDValue Offset, - const Value *SV, int SVOffset, EVT MemVT, - bool isVolatile, bool isNonTemporal, unsigned Alignment); + MachinePointerInfo PtrInfo, EVT MemVT, + bool isVolatile, bool isNonTemporal, unsigned Alignment, + const MDNode *TBAAInfo = 0); SDValue getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, EVT VT, DebugLoc dl, SDValue Chain, SDValue Ptr, SDValue Offset, @@ -651,14 +651,16 @@ public: /// getStore - Helper function to build ISD::STORE nodes. /// SDValue getStore(SDValue Chain, DebugLoc dl, SDValue Val, SDValue Ptr, - const Value *SV, int SVOffset, bool isVolatile, - bool isNonTemporal, unsigned Alignment); + MachinePointerInfo PtrInfo, bool isVolatile, + bool isNonTemporal, unsigned Alignment, + const MDNode *TBAAInfo = 0); SDValue getStore(SDValue Chain, DebugLoc dl, SDValue Val, SDValue Ptr, MachineMemOperand *MMO); SDValue getTruncStore(SDValue Chain, DebugLoc dl, SDValue Val, SDValue Ptr, - const Value *SV, int SVOffset, EVT TVT, + MachinePointerInfo PtrInfo, EVT TVT, bool isNonTemporal, bool isVolatile, - unsigned Alignment); + unsigned Alignment, + const MDNode *TBAAInfo = 0); SDValue getTruncStore(SDValue Chain, DebugLoc dl, SDValue Val, SDValue Ptr, EVT TVT, MachineMemOperand *MMO); SDValue getIndexedStore(SDValue OrigStoe, DebugLoc dl, SDValue Base, @@ -899,6 +901,9 @@ public: SmallVector &GetDbgValues(const SDNode* SD) { return DbgInfo->getSDDbgValues(SD); } + + /// TransferDbgValues - Transfer SDDbgValues. + void TransferDbgValues(SDValue From, SDValue To); /// hasDebugValues - Return true if there are any SDDbgValue nodes associated /// with this SelectionDAG. @@ -961,6 +966,13 @@ public: /// class to allow target nodes to be understood. unsigned ComputeNumSignBits(SDValue Op, unsigned Depth = 0) const; + /// isBaseWithConstantOffset - Return true if the specified operand is an + /// ISD::ADD with a ConstantSDNode on the right-hand side, or if it is an + /// ISD::OR with a ConstantSDNode that is guaranteed to have the same + /// semantics as an ADD. This handles the equivalence: + /// X|Cst == X+Cst iff X&Cst = 0. + bool isBaseWithConstantOffset(SDValue Op) const; + /// isKnownNeverNan - Test whether the given SDValue is known to never be NaN. bool isKnownNeverNaN(SDValue Op) const; diff --git a/include/llvm/CodeGen/SelectionDAGISel.h b/include/llvm/CodeGen/SelectionDAGISel.h index 01d05ddac11a..62358e7639ee 100644 --- a/include/llvm/CodeGen/SelectionDAGISel.h +++ b/include/llvm/CodeGen/SelectionDAGISel.h @@ -34,7 +34,8 @@ namespace llvm { class ScheduleHazardRecognizer; class GCFunctionInfo; class ScheduleDAGSDNodes; - + class LoadInst; + /// SelectionDAGISel - This is the common base class used for SelectionDAG-based /// pattern-matching instruction selectors. class SelectionDAGISel : public MachineFunctionPass { @@ -54,7 +55,7 @@ public: explicit SelectionDAGISel(const TargetMachine &tm, CodeGenOpt::Level OL = CodeGenOpt::Default); virtual ~SelectionDAGISel(); - + const TargetLowering &getTargetLowering() { return TLI; } virtual void getAnalysisUsage(AnalysisUsage &AU) const; @@ -62,18 +63,18 @@ public: virtual bool runOnMachineFunction(MachineFunction &MF); virtual void EmitFunctionEntryCode() {} - + /// PreprocessISelDAG - This hook allows targets to hack on the graph before /// instruction selection starts. virtual void PreprocessISelDAG() {} - + /// PostprocessISelDAG() - This hook allows the target to hack on the graph /// right after selection. virtual void PostprocessISelDAG() {} - + /// Select - Main hook targets implement to select a node. virtual SDNode *Select(SDNode *N) = 0; - + /// SelectInlineAsmMemoryOperand - Select the specified address as a target /// addressing mode, according to the specified constraint code. If this does /// not match or is not implemented, return true. The resultant operands @@ -91,25 +92,20 @@ public: /// IsLegalToFold - Returns true if the specific operand node N of /// U can be folded during instruction selection that starts at Root. - /// FIXME: This is a static member function because the PIC16 target, - /// which uses it during lowering. + /// FIXME: This is a static member function because the MSP430/SystemZ/X86 + /// targets, which uses it during isel. This could become a proper member. static bool IsLegalToFold(SDValue N, SDNode *U, SDNode *Root, CodeGenOpt::Level OptLevel, bool IgnoreChains = false); - /// CreateTargetHazardRecognizer - Return a newly allocated hazard recognizer - /// to use for this target when scheduling the DAG. - virtual ScheduleHazardRecognizer *CreateTargetHazardRecognizer(); - - // Opcodes used by the DAG state machine: enum BuiltinOpcodes { OPC_Scope, OPC_RecordNode, - OPC_RecordChild0, OPC_RecordChild1, OPC_RecordChild2, OPC_RecordChild3, + OPC_RecordChild0, OPC_RecordChild1, OPC_RecordChild2, OPC_RecordChild3, OPC_RecordChild4, OPC_RecordChild5, OPC_RecordChild6, OPC_RecordChild7, OPC_RecordMemRef, - OPC_CaptureFlagInput, + OPC_CaptureGlueInput, OPC_MoveChild, OPC_MoveParent, OPC_CheckSame, @@ -128,7 +124,7 @@ public: OPC_CheckComplexPat, OPC_CheckAndImm, OPC_CheckOrImm, OPC_CheckFoldableChainNode, - + OPC_EmitInteger, OPC_EmitRegister, OPC_EmitConvertToTarget, @@ -139,15 +135,15 @@ public: OPC_EmitNodeXForm, OPC_EmitNode, OPC_MorphNodeTo, - OPC_MarkFlagResults, + OPC_MarkGlueResults, OPC_CompleteMatch }; - + enum { - OPFL_None = 0, // Node has no chain or flag input and isn't variadic. + OPFL_None = 0, // Node has no chain or glue input and isn't variadic. OPFL_Chain = 1, // Node has a chain input. - OPFL_FlagInput = 2, // Node has a flag input. - OPFL_FlagOutput = 4, // Node has a flag output. + OPFL_GlueInput = 2, // Node has a glue input. + OPFL_GlueOutput = 4, // Node has a glue output. OPFL_MemRefs = 8, // Node gets accumulated MemRefs. OPFL_Variadic0 = 1<<4, // Node is variadic, root has 0 fixed inputs. OPFL_Variadic1 = 2<<4, // Node is variadic, root has 1 fixed inputs. @@ -156,37 +152,37 @@ public: OPFL_Variadic4 = 5<<4, // Node is variadic, root has 4 fixed inputs. OPFL_Variadic5 = 6<<4, // Node is variadic, root has 5 fixed inputs. OPFL_Variadic6 = 7<<4, // Node is variadic, root has 6 fixed inputs. - + OPFL_VariadicInfo = OPFL_Variadic6 }; - + /// getNumFixedFromVariadicInfo - Transform an EmitNode flags word into the /// number of fixed arity values that should be skipped when copying from the /// root. static inline int getNumFixedFromVariadicInfo(unsigned Flags) { return ((Flags&OPFL_VariadicInfo) >> 4)-1; } - - + + protected: /// DAGSize - Size of DAG being instruction selected. /// unsigned DAGSize; - + /// ISelPosition - Node iterator marking the current position of /// instruction selection as it procedes through the topologically-sorted /// node list. SelectionDAG::allnodes_iterator ISelPosition; - - /// ISelUpdater - helper class to handle updates of the + + /// ISelUpdater - helper class to handle updates of the /// instruction selection graph. class ISelUpdater : public SelectionDAG::DAGUpdateListener { SelectionDAG::allnodes_iterator &ISelPosition; public: explicit ISelUpdater(SelectionDAG::allnodes_iterator &isp) : ISelPosition(isp) {} - + /// NodeDeleted - Handle nodes deleted from the graph. If the /// node being deleted is the current ISelPosition node, update /// ISelPosition. @@ -195,46 +191,46 @@ protected: if (ISelPosition == SelectionDAG::allnodes_iterator(N)) ++ISelPosition; } - + /// NodeUpdated - Ignore updates for now. virtual void NodeUpdated(SDNode *N) {} }; - + /// ReplaceUses - replace all uses of the old node F with the use /// of the new node T. void ReplaceUses(SDValue F, SDValue T) { ISelUpdater ISU(ISelPosition); CurDAG->ReplaceAllUsesOfValueWith(F, T, &ISU); } - + /// ReplaceUses - replace all uses of the old nodes F with the use /// of the new nodes T. void ReplaceUses(const SDValue *F, const SDValue *T, unsigned Num) { ISelUpdater ISU(ISelPosition); CurDAG->ReplaceAllUsesOfValuesWith(F, T, Num, &ISU); } - + /// ReplaceUses - replace all uses of the old node F with the use /// of the new node T. void ReplaceUses(SDNode *F, SDNode *T) { ISelUpdater ISU(ISelPosition); CurDAG->ReplaceAllUsesWith(F, T, &ISU); } - + /// SelectInlineAsmMemoryOperands - Calls to this are automatically generated /// by tblgen. Others should not call it. void SelectInlineAsmMemoryOperands(std::vector &Ops); - + public: // Calls to these predicates are generated by tblgen. bool CheckAndMask(SDValue LHS, ConstantSDNode *RHS, int64_t DesiredMaskS) const; bool CheckOrMask(SDValue LHS, ConstantSDNode *RHS, int64_t DesiredMaskS) const; - - + + /// CheckPatternPredicate - This function is generated by tblgen in the /// target. It runs the specified pattern predicate and returns true if it /// succeeds or false if it fails. The number is a private implementation @@ -252,13 +248,14 @@ public: assert(0 && "Tblgen should generate the implementation of this!"); return 0; } - - virtual bool CheckComplexPattern(SDNode *Root, SDValue N, unsigned PatternNo, - SmallVectorImpl &Result) { + + virtual bool CheckComplexPattern(SDNode *Root, SDNode *Parent, SDValue N, + unsigned PatternNo, + SmallVectorImpl > &Result) { assert(0 && "Tblgen should generate the implementation of this!"); return false; } - + virtual SDValue RunSDNodeXForm(SDValue V, unsigned XFormNo) { assert(0 && "Tblgen shoudl generate this!"); return SDValue(); @@ -267,9 +264,9 @@ public: SDNode *SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, unsigned TableSize); - + private: - + // Calls to these functions are generated by tblgen. SDNode *Select_INLINEASM(SDNode *N); SDNode *Select_UNDEF(SDNode *N); @@ -279,9 +276,10 @@ private: void DoInstructionSelection(); SDNode *MorphNode(SDNode *Node, unsigned TargetOpc, SDVTList VTs, const SDValue *Ops, unsigned NumOps, unsigned EmitNodeInfo); - + void PrepareEHLandingPad(); void SelectAllBasicBlocks(const Function &Fn); + bool TryToFoldFastISelLoad(const LoadInst *LI, FastISel *FastIS); void FinishBasicBlock(); void SelectBasicBlock(BasicBlock::const_iterator Begin, @@ -289,7 +287,7 @@ private: bool &HadTailCall); void CodeGenAndEmitDAG(); void LowerArguments(const BasicBlock *BB); - + void ComputeLiveOutVRegInfo(); /// Create the scheduler. If a specific scheduler was specified @@ -297,16 +295,16 @@ private: /// one preferred by the target. /// ScheduleDAGSDNodes *CreateScheduler(); - + /// OpcodeOffset - This is a cache used to dispatch efficiently into isel /// state machines that start with a OPC_SwitchOpcode node. std::vector OpcodeOffset; - - void UpdateChainsAndFlags(SDNode *NodeToMatch, SDValue InputChain, - const SmallVectorImpl &ChainNodesMatched, - SDValue InputFlag,const SmallVectorImpl &F, - bool isMorphNodeTo); - + + void UpdateChainsAndGlue(SDNode *NodeToMatch, SDValue InputChain, + const SmallVectorImpl &ChainNodesMatched, + SDValue InputGlue, const SmallVectorImpl &F, + bool isMorphNodeTo); + }; } diff --git a/include/llvm/CodeGen/SelectionDAGNodes.h b/include/llvm/CodeGen/SelectionDAGNodes.h index 4cf6f367edfb..64546394ce91 100644 --- a/include/llvm/CodeGen/SelectionDAGNodes.h +++ b/include/llvm/CodeGen/SelectionDAGNodes.h @@ -29,7 +29,7 @@ #include "llvm/CodeGen/ValueTypes.h" #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/Support/MathExtras.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/Support/DebugLoc.h" #include @@ -524,24 +524,24 @@ public: return X; } - /// getFlaggedNode - If this node has a flag operand, return the node - /// to which the flag operand points. Otherwise return NULL. - SDNode *getFlaggedNode() const { + /// getGluedNode - If this node has a glue operand, return the node + /// to which the glue operand points. Otherwise return NULL. + SDNode *getGluedNode() const { if (getNumOperands() != 0 && - getOperand(getNumOperands()-1).getValueType().getSimpleVT() == MVT::Flag) + getOperand(getNumOperands()-1).getValueType() == MVT::Glue) return getOperand(getNumOperands()-1).getNode(); return 0; } // If this is a pseudo op, like copyfromreg, look to see if there is a - // real target node flagged to it. If so, return the target node. - const SDNode *getFlaggedMachineNode() const { + // real target node glued to it. If so, return the target node. + const SDNode *getGluedMachineNode() const { const SDNode *FoundNode = this; - // Climb up flag edges until a machine-opcode node is found, or the + // Climb up glue edges until a machine-opcode node is found, or the // end of the chain is reached. while (!FoundNode->isMachineOpcode()) { - const SDNode *N = FoundNode->getFlaggedNode(); + const SDNode *N = FoundNode->getGluedNode(); if (!N) break; FoundNode = N; } @@ -549,11 +549,11 @@ public: return FoundNode; } - /// getFlaggedUser - If this node has a flag value with a user, return + /// getGluedUser - If this node has a glue value with a user, return /// the user (there is at most one). Otherwise return NULL. - SDNode *getFlaggedUser() const { + SDNode *getGluedUser() const { for (use_iterator UI = use_begin(), UE = use_end(); UI != UE; ++UI) - if (UI.getUse().get().getValueType() == MVT::Flag) + if (UI.getUse().get().getValueType() == MVT::Glue) return *UI; return 0; } @@ -902,6 +902,9 @@ public: const Value *getSrcValue() const { return MMO->getValue(); } int64_t getSrcValueOffset() const { return MMO->getOffset(); } + /// Returns the TBAAInfo that describes the dereference. + const MDNode *getTBAAInfo() const { return MMO->getTBAAInfo(); } + /// getMemoryVT - Return the type of the in-memory value. EVT getMemoryVT() const { return MemoryVT; } @@ -909,6 +912,10 @@ public: /// reference performed by operation. MachineMemOperand *getMemOperand() const { return MMO; } + const MachinePointerInfo &getPointerInfo() const { + return MMO->getPointerInfo(); + } + /// refineAlignment - Update this MemSDNode's MachineMemOperand information /// to reflect the alignment of NewMMO, if it has a greater alignment. /// This must only be used when the new alignment applies to all users of @@ -929,6 +936,7 @@ public: // with either an intrinsic or a target opcode. return N->getOpcode() == ISD::LOAD || N->getOpcode() == ISD::STORE || + N->getOpcode() == ISD::PREFETCH || N->getOpcode() == ISD::ATOMIC_CMP_SWAP || N->getOpcode() == ISD::ATOMIC_SWAP || N->getOpcode() == ISD::ATOMIC_LOAD_ADD || @@ -1004,8 +1012,8 @@ public: /// MemIntrinsicSDNode - This SDNode is used for target intrinsics that touch /// memory and need an associated MachineMemOperand. Its opcode may be -/// INTRINSIC_VOID, INTRINSIC_W_CHAIN, or a target-specific opcode with a -/// value not less than FIRST_TARGET_MEMORY_OPCODE. +/// INTRINSIC_VOID, INTRINSIC_W_CHAIN, PREFETCH, or a target-specific opcode +/// with a value not less than FIRST_TARGET_MEMORY_OPCODE. class MemIntrinsicSDNode : public MemSDNode { public: MemIntrinsicSDNode(unsigned Opc, DebugLoc dl, SDVTList VTs, @@ -1021,6 +1029,7 @@ public: // early a node with a target opcode can be of this class return N->getOpcode() == ISD::INTRINSIC_W_CHAIN || N->getOpcode() == ISD::INTRINSIC_VOID || + N->getOpcode() == ISD::PREFETCH || N->isTargetMemoryOpcode(); } }; diff --git a/include/llvm/CodeGen/SlotIndexes.h b/include/llvm/CodeGen/SlotIndexes.h index 88044c7242c9..1da1e91be14a 100644 --- a/include/llvm/CodeGen/SlotIndexes.h +++ b/include/llvm/CodeGen/SlotIndexes.h @@ -13,10 +13,7 @@ // // SlotIndex is mostly a proxy for entries of the SlotIndexList, a class which // is held is LiveIntervals and provides the real numbering. This allows -// LiveIntervals to perform largely transparent renumbering. The SlotIndex -// class does hold a PHI bit, which determines whether the index relates to a -// PHI use or def point, or an actual instruction. See the SlotIndex class -// description for futher information. +// LiveIntervals to perform largely transparent renumbering. //===----------------------------------------------------------------------===// #ifndef LLVM_CODEGEN_SLOTINDEXES_H @@ -130,12 +127,10 @@ namespace llvm { enum Slot { LOAD, USE, DEF, STORE, NUM }; - static const unsigned PHI_BIT = 1 << 2; + PointerIntPair lie; - PointerIntPair lie; - - SlotIndex(IndexListEntry *entry, unsigned phiAndSlot) - : lie(entry, phiAndSlot) { + SlotIndex(IndexListEntry *entry, unsigned slot) + : lie(entry, slot) { assert(entry != 0 && "Attempt to construct index with 0 pointer."); } @@ -149,7 +144,7 @@ namespace llvm { /// Returns the slot for this SlotIndex. Slot getSlot() const { - return static_cast(lie.getInt() & ~PHI_BIT); + return static_cast(lie.getInt()); } static inline unsigned getHashValue(const SlotIndex &v) { @@ -166,22 +161,13 @@ namespace llvm { static inline SlotIndex getTombstoneKey() { return SlotIndex(IndexListEntry::getTombstoneKeyEntry(), 0); } - + /// Construct an invalid index. SlotIndex() : lie(IndexListEntry::getEmptyKeyEntry(), 0) {} - // Construct a new slot index from the given one, set the phi flag on the - // new index to the value of the phi parameter. - SlotIndex(const SlotIndex &li, bool phi) - : lie(&li.entry(), phi ? PHI_BIT | li.getSlot() : (unsigned)li.getSlot()){ - assert(lie.getPointer() != 0 && - "Attempt to construct index with 0 pointer."); - } - - // Construct a new slot index from the given one, set the phi flag on the - // new index to the value of the phi parameter, and the slot to the new slot. - SlotIndex(const SlotIndex &li, bool phi, Slot s) - : lie(&li.entry(), phi ? PHI_BIT | s : (unsigned)s) { + // Construct a new slot index from the given one, and set the slot. + SlotIndex(const SlotIndex &li, Slot s) + : lie(&li.entry(), unsigned(s)) { assert(lie.getPointer() != 0 && "Attempt to construct index with 0 pointer."); } @@ -236,11 +222,6 @@ namespace llvm { return other.getIndex() - getIndex(); } - /// Returns the state of the PHI bit. - bool isPHI() const { - return lie.getInt() & PHI_BIT; - } - /// isLoad - Return true if this is a LOAD slot. bool isLoad() const { return getSlot() == LOAD; @@ -405,9 +386,6 @@ namespace llvm { /// and MBB id. std::vector idx2MBBMap; - typedef DenseMap TerminatorGapsMap; - TerminatorGapsMap terminatorGaps; - // IndexListEntry allocator. BumpPtrAllocator ileAllocator; @@ -415,7 +393,7 @@ namespace llvm { IndexListEntry *entry = static_cast( ileAllocator.Allocate(sizeof(IndexListEntry), - alignof())); + alignOf())); new (entry) IndexListEntry(mi, index); @@ -491,7 +469,9 @@ namespace llvm { public: static char ID; - SlotIndexes() : MachineFunctionPass(ID), indexListHead(0) {} + SlotIndexes() : MachineFunctionPass(ID), indexListHead(0) { + initializeSlotIndexesPass(*PassRegistry::getPassRegistry()); + } virtual void getAnalysisUsage(AnalysisUsage &au) const; virtual void releaseMemory(); @@ -565,26 +545,22 @@ namespace llvm { return nextNonNull; } - /// Returns the first index in the given basic block. - SlotIndex getMBBStartIdx(const MachineBasicBlock *mbb) const { + /// Return the (start,end) range of the given basic block. + const std::pair & + getMBBRange(const MachineBasicBlock *mbb) const { MBB2IdxMap::const_iterator itr = mbb2IdxMap.find(mbb); assert(itr != mbb2IdxMap.end() && "MBB not found in maps."); - return itr->second.first; + return itr->second; } - /// Returns the last index in the given basic block. - SlotIndex getMBBEndIdx(const MachineBasicBlock *mbb) const { - MBB2IdxMap::const_iterator itr = mbb2IdxMap.find(mbb); - assert(itr != mbb2IdxMap.end() && "MBB not found in maps."); - return itr->second.second; + /// Returns the first index in the given basic block. + SlotIndex getMBBStartIdx(const MachineBasicBlock *mbb) const { + return getMBBRange(mbb).first; } - /// Returns the terminator gap for the given index. - SlotIndex getTerminatorGap(const MachineBasicBlock *mbb) { - TerminatorGapsMap::iterator itr = terminatorGaps.find(mbb); - assert(itr != terminatorGaps.end() && - "All MBBs should have terminator gaps in their indexes."); - return itr->second; + /// Returns the last index in the given basic block. + SlotIndex getMBBEndIdx(const MachineBasicBlock *mbb) const { + return getMBBRange(mbb).second; } /// Returns the basic block which the given index falls in. @@ -618,29 +594,6 @@ namespace llvm { return resVal; } - /// Return a list of MBBs that can be reach via any branches or - /// fall-throughs. - bool findReachableMBBs(SlotIndex start, SlotIndex end, - SmallVectorImpl &mbbs) const { - std::vector::const_iterator itr = - std::lower_bound(idx2MBBMap.begin(), idx2MBBMap.end(), start); - - bool resVal = false; - while (itr != idx2MBBMap.end()) { - if (itr->first > end) - break; - MachineBasicBlock *mbb = itr->second; - if (getMBBEndIdx(mbb) > end) - break; - for (MachineBasicBlock::succ_iterator si = mbb->succ_begin(), - se = mbb->succ_end(); si != se; ++si) - mbbs.push_back(*si); - resVal = true; - ++itr; - } - return resVal; - } - /// Returns the MBB covering the given range, or null if the range covers /// more than one basic block. MachineBasicBlock* getMBBCoveringRange(SlotIndex start, SlotIndex end) const { @@ -672,6 +625,9 @@ namespace llvm { SlotIndex insertMachineInstrInMaps(MachineInstr *mi, bool *deferredRenumber = 0) { assert(mi2iMap.find(mi) == mi2iMap.end() && "Instr already indexed."); + // Numbering DBG_VALUE instructions could cause code generation to be + // affected by debug information. + assert(!mi->isDebugValue() && "Cannot number DBG_VALUE instructions."); MachineBasicBlock *mbb = mi->getParent(); @@ -789,7 +745,7 @@ namespace llvm { MachineFunction::iterator nextMBB = llvm::next(MachineFunction::iterator(mbb)); IndexListEntry *startEntry = createEntry(0, 0); - IndexListEntry *terminatorEntry = createEntry(0, 0); + IndexListEntry *stopEntry = createEntry(0, 0); IndexListEntry *nextEntry = 0; if (nextMBB == mbb->getParent()->end()) { @@ -799,15 +755,11 @@ namespace llvm { } insert(nextEntry, startEntry); - insert(nextEntry, terminatorEntry); + insert(nextEntry, stopEntry); SlotIndex startIdx(startEntry, SlotIndex::LOAD); - SlotIndex terminatorIdx(terminatorEntry, SlotIndex::PHI_BIT); SlotIndex endIdx(nextEntry, SlotIndex::LOAD); - terminatorGaps.insert( - std::make_pair(mbb, terminatorIdx)); - mbb2IdxMap.insert( std::make_pair(mbb, std::make_pair(startIdx, endIdx))); @@ -828,6 +780,20 @@ namespace llvm { }; + // Specialize IntervalMapInfo for half-open slot index intervals. + template struct IntervalMapInfo; + template <> struct IntervalMapInfo { + static inline bool startLess(const SlotIndex &x, const SlotIndex &a) { + return x < a; + } + static inline bool stopLess(const SlotIndex &b, const SlotIndex &x) { + return b <= x; + } + static inline bool adjacent(const SlotIndex &a, const SlotIndex &b) { + return a == b; + } + }; + } #endif // LLVM_CODEGEN_LIVEINDEX_H diff --git a/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h b/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h index d8f037385957..fba3e48c475e 100644 --- a/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h +++ b/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h @@ -57,6 +57,8 @@ public: virtual void Initialize(MCContext &Ctx, const TargetMachine &TM); + virtual const MCSection *getEHFrameSection() const; + const MCSection *getDataRelSection() const { return DataRelSection; } /// getSectionForConstant - Given a constant with the SectionKind, return a @@ -121,6 +123,8 @@ public: virtual void Initialize(MCContext &Ctx, const TargetMachine &TM); + virtual const MCSection *getEHFrameSection() const; + virtual const MCSection * SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, Mangler *Mang, const TargetMachine &TM) const; @@ -184,6 +188,8 @@ public: virtual void Initialize(MCContext &Ctx, const TargetMachine &TM); + virtual const MCSection *getEHFrameSection() const; + virtual const MCSection *getDrectveSection() const { return DrectveSection; } virtual const MCSection * diff --git a/include/llvm/CodeGen/ValueTypes.h b/include/llvm/CodeGen/ValueTypes.h index 51f324c959c0..22d16222078d 100644 --- a/include/llvm/CodeGen/ValueTypes.h +++ b/include/llvm/CodeGen/ValueTypes.h @@ -18,7 +18,7 @@ #include #include -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/Support/MathExtras.h" namespace llvm { @@ -26,7 +26,10 @@ namespace llvm { class LLVMContext; struct EVT; - class MVT { // MVT = Machine Value Type + /// MVT - Machine Value Type. Every type that is supported natively by some + /// processor targeted by LLVM occurs here. This means that any legal value + /// type can be represented by a MVT. + class MVT { public: enum SimpleValueType { // If you change this numbering, you must change the values in @@ -74,14 +77,16 @@ namespace llvm { FIRST_VECTOR_VALUETYPE = v2i8, LAST_VECTOR_VALUETYPE = v4f64, - Flag = 33, // This glues nodes together during pre-RA sched + x86mmx = 33, // This is an X86 MMX value - isVoid = 34, // This has no value + Glue = 34, // This glues nodes together during pre-RA sched - LAST_VALUETYPE = 35, // This always remains at the end of the list. + isVoid = 35, // This has no value + + LAST_VALUETYPE = 36, // This always remains at the end of the list. // This is the current maximum for LAST_VALUETYPE. - // EVT::MAX_ALLOWED_VALUETYPE is used for asserts and to size bit vectors + // MVT::MAX_ALLOWED_VALUETYPE is used for asserts and to size bit vectors // This value must be a multiple of 32. MAX_ALLOWED_VALUETYPE = 64, @@ -124,13 +129,14 @@ namespace llvm { MVT() : SimpleTy((SimpleValueType)(INVALID_SIMPLE_VALUE_TYPE)) {} MVT(SimpleValueType SVT) : SimpleTy(SVT) { } - + bool operator>(const MVT& S) const { return SimpleTy > S.SimpleTy; } bool operator<(const MVT& S) const { return SimpleTy < S.SimpleTy; } bool operator==(const MVT& S) const { return SimpleTy == S.SimpleTy; } + bool operator!=(const MVT& S) const { return SimpleTy != S.SimpleTy; } bool operator>=(const MVT& S) const { return SimpleTy >= S.SimpleTy; } bool operator<=(const MVT& S) const { return SimpleTy <= S.SimpleTy; } - + /// isFloatingPoint - Return true if this is a FP, or a vector FP type. bool isFloatingPoint() const { return ((SimpleTy >= MVT::f32 && SimpleTy <= MVT::ppcf128) || @@ -149,14 +155,14 @@ namespace llvm { return (SimpleTy >= MVT::FIRST_VECTOR_VALUETYPE && SimpleTy <= MVT::LAST_VECTOR_VALUETYPE); } - + /// isPow2VectorType - Returns true if the given vector is a power of 2. bool isPow2VectorType() const { unsigned NElts = getVectorNumElements(); return !(NElts & (NElts - 1)); } - /// getPow2VectorType - Widens the length of the given vector EVT up to + /// getPow2VectorType - Widens the length of the given vector MVT up to /// the nearest power of 2 and returns that type. MVT getPow2VectorType() const { if (isPow2VectorType()) @@ -172,7 +178,7 @@ namespace llvm { MVT getScalarType() const { return isVector() ? getVectorElementType() : *this; } - + MVT getVectorElementType() const { switch (SimpleTy) { default: @@ -200,7 +206,7 @@ namespace llvm { case v4f64: return f64; } } - + unsigned getVectorNumElements() const { switch (SimpleTy) { default: @@ -228,7 +234,7 @@ namespace llvm { case v1i64: return 1; } } - + unsigned getSizeInBits() const { switch (SimpleTy) { case iPTR: @@ -247,6 +253,7 @@ namespace llvm { case i32 : case v4i8: case v2i16: return 32; + case x86mmx: case f64 : case i64 : case v8i8: @@ -273,7 +280,19 @@ namespace llvm { case v8i64: return 512; } } - + + /// getStoreSize - Return the number of bytes overwritten by a store + /// of the specified value type. + unsigned getStoreSize() const { + return (getSizeInBits() + 7) / 8; + } + + /// getStoreSizeInBits - Return the number of bits overwritten by a store + /// of the specified value type. + unsigned getStoreSizeInBits() const { + return getStoreSize() * 8; + } + static MVT getFloatingPointVT(unsigned BitWidth) { switch (BitWidth) { default: @@ -288,7 +307,7 @@ namespace llvm { return MVT::f128; } } - + static MVT getIntegerVT(unsigned BitWidth) { switch (BitWidth) { default: @@ -307,7 +326,7 @@ namespace llvm { return MVT::i128; } } - + static MVT getVectorVT(MVT VT, unsigned NumElements) { switch (VT.SimpleTy) { default: @@ -350,7 +369,11 @@ namespace llvm { } }; - struct EVT { // EVT = Extended Value Type + + /// EVT - Extended Value Type. Capable of holding value types which are not + /// native for any processor (such as the i12345 type), as well as the types + /// a MVT can represent. + struct EVT { private: MVT V; const Type *LLVMTy; @@ -527,7 +550,7 @@ namespace llvm { EVT getScalarType() const { return isVector() ? getVectorElementType() : *this; } - + /// getVectorElementType - Given a vector type, return the type of /// each element. EVT getVectorElementType() const { diff --git a/include/llvm/CodeGen/ValueTypes.td b/include/llvm/CodeGen/ValueTypes.td index 8151c0be3664..a1163f7a2f98 100644 --- a/include/llvm/CodeGen/ValueTypes.td +++ b/include/llvm/CodeGen/ValueTypes.td @@ -46,17 +46,18 @@ def v4i32 : ValueType<128, 22>; // 4 x i32 vector value def v8i32 : ValueType<256, 23>; // 8 x i32 vector value def v1i64 : ValueType<64 , 24>; // 1 x i64 vector value def v2i64 : ValueType<128, 25>; // 2 x i64 vector value -def v4i64 : ValueType<256, 26>; // 4 x f64 vector value -def v8i64 : ValueType<512, 27>; // 4 x f64 vector value +def v4i64 : ValueType<256, 26>; // 4 x i64 vector value +def v8i64 : ValueType<512, 27>; // 8 x i64 vector value -def v2f32 : ValueType<64, 28>; // 2 x f32 vector value +def v2f32 : ValueType<64 , 28>; // 2 x f32 vector value def v4f32 : ValueType<128, 29>; // 4 x f32 vector value def v8f32 : ValueType<256, 30>; // 8 x f32 vector value def v2f64 : ValueType<128, 31>; // 2 x f64 vector value def v4f64 : ValueType<256, 32>; // 4 x f64 vector value -def FlagVT : ValueType<0 , 33>; // Pre-RA sched glue -def isVoid : ValueType<0 , 34>; // Produces no value +def x86mmx : ValueType<64 , 33>; // X86 MMX value +def FlagVT : ValueType<0 , 34>; // Pre-RA sched glue +def isVoid : ValueType<0 , 35>; // Produces no value def MetadataVT: ValueType<0, 250>; // Metadata diff --git a/include/llvm/CompilerDriver/CompilationGraph.h b/include/llvm/CompilerDriver/CompilationGraph.h index 619c904f15d6..e1eea325e348 100644 --- a/include/llvm/CompilerDriver/CompilationGraph.h +++ b/include/llvm/CompilerDriver/CompilationGraph.h @@ -21,7 +21,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSet.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Path.h" #include #include diff --git a/include/llvm/CompilerDriver/Tool.h b/include/llvm/CompilerDriver/Tool.h index 45ef50d0b5af..d0926ba98312 100644 --- a/include/llvm/CompilerDriver/Tool.h +++ b/include/llvm/CompilerDriver/Tool.h @@ -18,7 +18,7 @@ #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/StringSet.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Path.h" #include #include @@ -58,7 +58,7 @@ namespace llvmc { virtual const char* Name() const = 0; virtual const char** InputLanguages() const = 0; - virtual const char* OutputLanguage() const = 0; + virtual const char** OutputLanguages() const = 0; virtual bool IsJoin() const = 0; virtual bool WorksOnEmpty() const = 0; diff --git a/include/llvm/Config/config.h.cmake b/include/llvm/Config/config.h.cmake index e8feabffdaf7..bf69375ff562 100644 --- a/include/llvm/Config/config.h.cmake +++ b/include/llvm/Config/config.h.cmake @@ -1,4 +1,3 @@ - /************************************** ** Created by Kevin from config.h.in ** ***************************************/ @@ -6,50 +5,35 @@ #ifndef CONFIG_H #define CONFIG_H -/* Define if dlopen(0) will open the symbols of the program */ -#undef CAN_DLOPEN_SELF - /* Define if CBE is enabled for printf %a output */ -#undef ENABLE_CBE_PRINTF_A - -/* Directories clang will search for headers */ -#define C_INCLUDE_DIRS "${C_INCLUDE_DIRS}" - -/* Directory clang will search for libstdc++ headers */ -#define CXX_INCLUDE_ROOT "${CXX_INCLUDE_ROOT}" - -/* Architecture of libstdc++ headers */ -#define CXX_INCLUDE_ARCH "${CXX_INCLUDE_ARCH}" - -/* 32 bit multilib directory */ -#define CXX_INCLUDE_32BIT_DIR "${CXX_INCLUDE_32BIT_DIR}" - -/* 64 bit multilib directory */ -#define CXX_INCLUDE_64BIT_DIR "${CXX_INCLUDE_64BIT_DIR}" +#cmakedefine ENABLE_CBE_PRINTF_A ${ENABLE_CBE_PRINTF_A} /* Define if position independent code is enabled */ -#cmakedefine ENABLE_PIC ${ENABLE_PIC} +#cmakedefine ENABLE_PIC /* Define if threads enabled */ #cmakedefine ENABLE_THREADS ${ENABLE_THREADS} +/* Define if timestamp information (e.g., __DATE___) is allowed */ +#cmakedefine ENABLE_TIMESTAMPS ${ENABLE_TIMESTAMPS} + /* Define to 1 if you have the `argz_append' function. */ -#undef HAVE_ARGZ_APPEND +#cmakedefine HAVE_ARGZ_APPEND ${HAVE_ARGZ_APPEND} /* Define to 1 if you have the `argz_create_sep' function. */ -#undef HAVE_ARGZ_CREATE_SEP +#cmakedefine HAVE_ARGZ_CREATE_SEP ${HAVE_ARGZ_CREATE_SEP} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_ARGZ_H ${HAVE_ARGZ_H} /* Define to 1 if you have the `argz_insert' function. */ -#undef HAVE_ARGZ_INSERT +#cmakedefine HAVE_ARGZ_INSERT ${HAVE_ARGZ_INSERT} /* Define to 1 if you have the `argz_next' function. */ -#undef HAVE_ARGZ_NEXT +#cmakedefine HAVE_ARGZ_NEXT ${HAVE_ARGZ_NEXT} /* Define to 1 if you have the `argz_stringify' function. */ -#undef HAVE_ARGZ_STRINGIFY +#cmakedefine HAVE_ARGZ_STRINGIFY ${HAVE_ARGZ_STRINGIFY} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_ASSERT_H ${HAVE_ASSERT_H} @@ -60,9 +44,6 @@ /* Define to 1 if you have the `bcopy' function. */ #undef HAVE_BCOPY -/* Does not have bi-directional iterator */ -#undef HAVE_BI_ITERATOR - /* Define to 1 if you have the `ceilf' function. */ #cmakedefine HAVE_CEILF ${HAVE_CEILF} @@ -70,10 +51,20 @@ #cmakedefine HAVE_CIRCO ${HAVE_CIRCO} /* Define to 1 if you have the `closedir' function. */ -#undef HAVE_CLOSEDIR +#cmakedefine HAVE_CLOSEDIR ${HAVE_CLOSEDIR} + +/* Define to 1 if you have the header file. */ +#undef HAVE_CRASHREPORTERCLIENT_H + +/* Define if __crashreporter_info__ exists. */ +#undef HAVE_CRASHREPORTER_INFO /* Define to 1 if you have the header file. */ -#undef HAVE_CTYPE_H +#cmakedefine HAVE_CTYPE_H ${HAVE_CTYPE_H} + +/* Define to 1 if you have the declaration of `strerror_s', and to 0 if you + don't. */ +#cmakedefine01 HAVE_DECL_STRERROR_S /* Define to 1 if you have the header file, and it defines `DIR'. */ @@ -86,13 +77,13 @@ #cmakedefine HAVE_DLD_H ${HAVE_DLD_H} /* Define to 1 if you have the `dlerror' function. */ -#undef HAVE_DLERROR +#cmakedefine HAVE_DLERROR ${HAVE_DLERROR} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_DLFCN_H ${HAVE_DLFCN_H} /* Define if dlopen() is available on this platform. */ -#undef HAVE_DLOPEN +#cmakedefine HAVE_DLOPEN ${HAVE_DLOPEN} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_DL_H ${HAVE_DL_H} @@ -110,7 +101,7 @@ #cmakedefine HAVE_ERRNO_H ${HAVE_ERRNO_H} /* Define to 1 if the system has the type `error_t'. */ -#undef HAVE_ERROR_T +#cmakedefine HAVE_ERROR_T ${HAVE_ERROR_T} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_EXECINFO_H ${HAVE_EXECINFO_H} @@ -121,41 +112,41 @@ /* Define if the neat program is available */ #cmakedefine HAVE_FDP ${HAVE_FDP} +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_FENV_H ${HAVE_FENV_H} + +/* Define if libffi is available on this platform. */ +#cmakedefine HAVE_FFI_CALL ${HAVE_FFI_CALL} + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_FFI_FFI_H ${HAVE_FFI_FFI_H} + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_FFI_H ${HAVE_FFI_H} + /* Set to 1 if the finite function is found in */ #cmakedefine HAVE_FINITE_IN_IEEEFP_H ${HAVE_FINITE_IN_IEEEFP_H} /* Define to 1 if you have the `floorf' function. */ #cmakedefine HAVE_FLOORF ${HAVE_FLOORF} -/* Does not have forward iterator */ -#undef HAVE_FWD_ITERATOR +/* Define to 1 if you have the `fmodf' function. */ +#cmakedefine HAVE_FMODF ${HAVE_FMODF} /* Define to 1 if you have the `getcwd' function. */ -#undef HAVE_GETCWD +#cmakedefine HAVE_GETCWD ${HAVE_GETCWD} /* Define to 1 if you have the `getpagesize' function. */ #cmakedefine HAVE_GETPAGESIZE ${HAVE_GETPAGESIZE} /* Define to 1 if you have the `getrlimit' function. */ -#undef HAVE_GETRLIMIT +#cmakedefine HAVE_GETRLIMIT ${HAVE_GETRLIMIT} /* Define to 1 if you have the `getrusage' function. */ #cmakedefine HAVE_GETRUSAGE ${HAVE_GETRUSAGE} /* Define to 1 if you have the `gettimeofday' function. */ -#undef HAVE_GETTIMEOFDAY - -/* Does not have */ -#undef HAVE_GLOBAL_HASH_MAP - -/* Does not have hash_set in global namespace */ -#undef HAVE_GLOBAL_HASH_SET - -/* Does not have ext/hash_map */ -#undef HAVE_GNU_EXT_HASH_MAP - -/* Does not have hash_set in gnu namespace */ -#undef HAVE_GNU_EXT_HASH_SET +#cmakedefine HAVE_GETTIMEOFDAY ${HAVE_GETTIMEOFDAY} /* Define if the Graphviz program is available */ #undef HAVE_GRAPHVIZ @@ -164,10 +155,10 @@ #cmakedefine HAVE_GV ${HAVE_GV} /* Define to 1 if you have the `index' function. */ -#undef HAVE_INDEX +#cmakedefine HAVE_INDEX ${HAVE_INDEX} /* Define to 1 if the system has the type `int64_t'. */ -#undef HAVE_INT64_T +#cmakedefine HAVE_INT64_T ${HAVE_INT64_T} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_INTTYPES_H ${HAVE_INTTYPES_H} @@ -188,7 +179,7 @@ #cmakedefine HAVE_ISNAN_IN_MATH_H ${HAVE_ISNAN_IN_MATH_H} /* Define if you have the libdl library or equivalent. */ -#undef HAVE_LIBDL +#cmakedefine HAVE_LIBDL ${HAVE_LIBDL} /* Define to 1 if you have the `imagehlp' library (-limagehlp). */ #cmakedefine HAVE_LIBIMAGEHLP ${HAVE_LIBIMAGEHLP} @@ -208,6 +199,9 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LIMITS_H ${HAVE_LIMITS_H} +/* Define if you can use -Wl,-export-dynamic. */ +#define HAVE_LINK_EXPORT_DYNAMIC 1 + /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LINK_H ${HAVE_LINK_H} @@ -216,13 +210,13 @@ #undef HAVE_LINK_R /* Define to 1 if you have the `longjmp' function. */ -#undef HAVE_LONGJMP +#cmakedefine HAVE_LONGJMP ${HAVE_LONGJMP} /* Define to 1 if you have the header file. */ -#undef HAVE_MACH_MACH_H +#cmakedefine HAVE_MACH_MACH_H ${HAVE_MACH_MACH_H} /* Define to 1 if you have the header file. */ -#undef HAVE_MACH_O_DYLD_H +#cmakedefine HAVE_MACH_O_DYLD_H ${HAVE_MACH_O_DYLD_H} /* Define if mallinfo() is available on this platform. */ #cmakedefine HAVE_MALLINFO ${HAVE_MALLINFO} @@ -237,10 +231,10 @@ #cmakedefine HAVE_MALLOC_ZONE_STATISTICS ${HAVE_MALLOC_ZONE_STATISTICS} /* Define to 1 if you have the `memcpy' function. */ -#undef HAVE_MEMCPY +#cmakedefine HAVE_MEMCPY ${HAVE_MEMCPY} /* Define to 1 if you have the `memmove' function. */ -#undef HAVE_MEMMOVE +#cmakedefine HAVE_MEMMOVE ${HAVE_MEMMOVE} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_MEMORY_H ${HAVE_MEMORY_H} @@ -264,9 +258,6 @@ /* Define if mmap() can map files into memory */ #undef HAVE_MMAP_FILE -/* define if the compiler implements namespaces */ -#undef HAVE_NAMESPACES - /* Define to 1 if you have the header file, and it defines `DIR'. */ #cmakedefine HAVE_NDIR_H ${HAVE_NDIR_H} @@ -277,7 +268,13 @@ #cmakedefine HAVE_NEATO ${HAVE_NEATO} /* Define to 1 if you have the `opendir' function. */ -#undef HAVE_OPENDIR +#cmakedefine HAVE_OPENDIR ${HAVE_OPENDIR} + +/* Define to 1 if you have the `posix_spawn' function. */ +#cmakedefine HAVE_POSIX_SPAWN ${HAVE_POSIX_SPAWN} + +/* Define to 1 if you have the `powf' function. */ +#cmakedefine HAVE_POWF ${HAVE_POWF} /* Define if libtool can extract symbol lists from object files. */ #undef HAVE_PRELOADED_SYMBOLS @@ -285,7 +282,10 @@ /* Define to have the %a format string */ #undef HAVE_PRINTF_A -/* Have pthread.h */ +/* Have pthread_getspecific */ +#cmakedefine HAVE_PTHREAD_GETSPECIFIC ${HAVE_PTHREAD_GETSPECIFIC} + +/* Define to 1 if you have the header file. */ #cmakedefine HAVE_PTHREAD_H ${HAVE_PTHREAD_H} /* Have pthread_mutex_lock */ @@ -294,30 +294,27 @@ /* Have pthread_rwlock_init */ #cmakedefine HAVE_PTHREAD_RWLOCK_INIT ${HAVE_PTHREAD_RWLOCK_INIT} -/* Have pthread_getspecific */ -#cmakedefine HAVE_PTHREAD_GETSPECIFIC ${HAVE_PTHREAD_GETSPECIFIC} - /* Define to 1 if srand48/lrand48/drand48 exist in */ -#undef HAVE_RAND48 +#cmakedefine HAVE_RAND48 ${HAVE_RAND48} /* Define to 1 if you have the `readdir' function. */ -#undef HAVE_READDIR +#cmakedefine HAVE_READDIR ${HAVE_READDIR} /* Define to 1 if you have the `realpath' function. */ #undef HAVE_REALPATH /* Define to 1 if you have the `rindex' function. */ -#undef HAVE_RINDEX +#cmakedefine HAVE_RINDEX ${HAVE_RINDEX} /* Define to 1 if you have the `rintf' function. */ #undef HAVE_RINTF -/* Define to 1 if you have the `roundf' function. */ -#undef HAVE_ROUNDF - /* Define to 1 if you have the `round' function. */ #cmakedefine HAVE_ROUND ${HAVE_ROUND} +/* Define to 1 if you have the `roundf' function. */ +#undef HAVE_ROUNDF + /* Define to 1 if you have the `sbrk' function. */ #cmakedefine HAVE_SBRK ${HAVE_SBRK} @@ -325,7 +322,7 @@ #cmakedefine HAVE_SETENV ${HAVE_SETENV} /* Define to 1 if you have the `setjmp' function. */ -#undef HAVE_SETJMP +#cmakedefine HAVE_SETJMP ${HAVE_SETJMP} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SETJMP_H ${HAVE_SETJMP_H} @@ -337,13 +334,13 @@ #undef HAVE_SHL_LOAD /* Define to 1 if you have the `siglongjmp' function. */ -#undef HAVE_SIGLONGJMP +#cmakedefine HAVE_SIGLONGJMP ${HAVE_SIGLONGJMP} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SIGNAL_H ${HAVE_SIGNAL_H} /* Define to 1 if you have the `sigsetjmp' function. */ -#undef HAVE_SIGSETJMP +#cmakedefine HAVE_SIGSETJMP ${HAVE_SIGSETJMP} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STDINT_H ${HAVE_STDINT_H} @@ -354,29 +351,20 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STDLIB_H ${HAVE_STDLIB_H} -/* Does not have ext/hash_map> */ -#undef HAVE_STD_EXT_HASH_MAP - -/* Does not have hash_set in std namespace */ -#undef HAVE_STD_EXT_HASH_SET - /* Set to 1 if the std::isinf function is found in */ #undef HAVE_STD_ISINF_IN_CMATH /* Set to 1 if the std::isnan function is found in */ #undef HAVE_STD_ISNAN_IN_CMATH -/* Does not have std namespace iterator */ -#undef HAVE_STD_ITERATOR - /* Define to 1 if you have the `strchr' function. */ -#undef HAVE_STRCHR +#cmakedefine HAVE_STRCHR ${HAVE_STRCHR} /* Define to 1 if you have the `strcmp' function. */ -#undef HAVE_STRCMP +#cmakedefine HAVE_STRCMP ${HAVE_STRCMP} /* Define to 1 if you have the `strdup' function. */ -#undef HAVE_STRDUP +#cmakedefine HAVE_STRDUP ${HAVE_STRDUP} /* Define to 1 if you have the `strerror' function. */ #cmakedefine HAVE_STRERROR ${HAVE_STRERROR} @@ -384,23 +372,23 @@ /* Define to 1 if you have the `strerror_r' function. */ #cmakedefine HAVE_STRERROR_R ${HAVE_STRERROR_R} -/* Define to 1 if you have the `strerror_s' function. */ -#cmakedefine HAVE_STRERROR_S ${HAVE_STRERROR_S} - /* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H +#cmakedefine HAVE_STRINGS_H ${HAVE_STRINGS_H} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STRING_H ${HAVE_STRING_H} /* Define to 1 if you have the `strrchr' function. */ -#undef HAVE_STRRCHR +#cmakedefine HAVE_STRRCHR ${HAVE_STRRCHR} + +/* Define to 1 if you have the `strtof' function. */ +#cmakedefine HAVE_STRTOF ${HAVE_STRTOF} /* Define to 1 if you have the `strtoll' function. */ #cmakedefine HAVE_STRTOLL ${HAVE_STRTOLL} /* Define to 1 if you have the `strtoq' function. */ -#undef HAVE_STRTOQ +#cmakedefine HAVE_STRTOQ ${HAVE_STRTOQ} /* Define to 1 if you have the `sysconf' function. */ #undef HAVE_SYSCONF @@ -437,15 +425,12 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_TYPES_H ${HAVE_SYS_TYPES_H} +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_UIO_H ${HAVE_SYS_UIO_H} + /* Define to 1 if you have that is POSIX.1 compatible. */ #cmakedefine HAVE_SYS_WAIT_H ${HAVE_SYS_WAIT_H} -/* Define if the neat program is available */ -#cmakedefine HAVE_TWOPI ${HAVE_TWOPI} - -/* Define to 1 if the system has the type `uint64_t'. */ -#undef HAVE_UINT64_T - /* Define to 1 if you have the header file. */ #cmakedefine HAVE_TERMIOS_H ${HAVE_TERMIOS_H} @@ -456,7 +441,7 @@ #cmakedefine HAVE_UTIME_H ${HAVE_UTIME_H} /* Define to 1 if the system has the type `u_int64_t'. */ -#undef HAVE_U_INT64_T +#cmakedefine HAVE_U_INT64_T ${HAVE_U_INT64_T} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_VALGRIND_VALGRIND_H ${HAVE_VALGRIND_VALGRIND_H} @@ -464,6 +449,66 @@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_WINDOWS_H ${HAVE_WINDOWS_H} +/* Define to 1 if you have the `writev' function. */ +#cmakedefine HAVE_WRITEV ${HAVE_WRITEV} + +/* Define if the xdot.py program is available */ +#undef HAVE_XDOT_PY + +/* Have host's _alloca */ +#cmakedefine HAVE__ALLOCA ${HAVE__ALLOCA} + +/* Have host's __alloca */ +#cmakedefine HAVE___ALLOCA ${HAVE___ALLOCA} + +/* Have host's __ashldi3 */ +#cmakedefine HAVE___ASHLDI3 ${HAVE___ASHLDI3} + +/* Have host's __ashrdi3 */ +#cmakedefine HAVE___ASHRDI3 ${HAVE___ASHRDI3} + +/* Have host's __chkstk */ +#cmakedefine HAVE___CHKSTK ${HAVE___CHKSTK} + +/* Have host's __cmpdi2 */ +#cmakedefine HAVE___CMPDI2 ${HAVE___CMPDI2} + +/* Have host's __divdi3 */ +#cmakedefine HAVE___DIVDI3 ${HAVE___DIVDI3} + +/* Define to 1 if you have the `__dso_handle' function. */ +#undef HAVE___DSO_HANDLE + +/* Have host's __fixdfdi */ +#cmakedefine HAVE___FIXDFDI ${HAVE___FIXDFDI} + +/* Have host's __fixsfdi */ +#cmakedefine HAVE___FIXSFDI ${HAVE___FIXSFDI} + +/* Have host's __floatdidf */ +#cmakedefine HAVE___FLOATDIDF ${HAVE___FLOATDIDF} + +/* Have host's __lshrdi3 */ +#cmakedefine HAVE___LSHRDI3 ${HAVE___LSHRDI3} + +/* Have host's __main */ +#cmakedefine HAVE___MAIN ${HAVE___MAIN} + +/* Have host's __moddi3 */ +#cmakedefine HAVE___MODDI3 ${HAVE___MODDI3} + +/* Have host's __udivdi3 */ +#cmakedefine HAVE___UDIVDI3 ${HAVE___UDIVDI3} + +/* Have host's __umoddi3 */ +#cmakedefine HAVE___UMODDI3 ${HAVE___UMODDI3} + +/* Have host's ___chkstk */ +#cmakedefine HAVE____CHKSTK ${HAVE____CHKSTK} + +/* Linker version detected at compile time. */ +#undef HOST_LINK_VERSION + /* Installation directory for binary executables */ #undef LLVM_BINDIR @@ -473,6 +518,9 @@ /* Installation directory for documentation */ #undef LLVM_DATADIR +/* Installation directory for documentation */ +#undef LLVM_DOCSDIR + /* Installation directory for config files */ #undef LLVM_ETCDIR @@ -494,15 +542,24 @@ /* Build multithreading support into LLVM */ #cmakedefine LLVM_MULTITHREADED ${LLVM_MULTITHREADED} +/* LLVM architecture name for the native architecture, if available */ +#cmakedefine LLVM_NATIVE_ARCH ${LLVM_NATIVE_ARCH} + +/* LLVM name for the native AsmPrinter init function, if available */ +#cmakedefine LLVM_NATIVE_ASMPRINTER LLVMInitialize${LLVM_NATIVE_ARCH}AsmPrinter + +/* LLVM name for the native Target init function, if available */ +#cmakedefine LLVM_NATIVE_TARGET LLVMInitialize${LLVM_NATIVE_ARCH}Target + +/* LLVM name for the native TargetInfo init function, if available */ +#cmakedefine LLVM_NATIVE_TARGETINFO LLVMInitialize${LLVM_NATIVE_ARCH}TargetInfo + /* Define if this is Unixish platform */ #cmakedefine LLVM_ON_UNIX ${LLVM_ON_UNIX} /* Define if this is Win32ish platform */ #cmakedefine LLVM_ON_WIN32 ${LLVM_ON_WIN32} -/* Added by Kevin -- Maximum path length */ -#cmakedefine MAXPATHLEN ${MAXPATHLEN} - /* Define to path to circo program if found or 'echo circo' otherwise */ #cmakedefine LLVM_PATH_CIRCO "${LLVM_PATH_CIRCO}" @@ -527,6 +584,9 @@ /* Define to path to twopi program if found or 'echo twopi' otherwise */ #cmakedefine LLVM_PATH_TWOPI "${LLVM_PATH_TWOPI}" +/* Define to path to xdot.py program if found or 'echo xdot.py' otherwise */ +#undef LLVM_PATH_XDOT_PY + /* Installation prefix directory */ #cmakedefine LLVM_PREFIX "${LLVM_PREFIX}" @@ -572,6 +632,9 @@ /* Define as the return type of signal handlers (`int' or `void'). */ #cmakedefine RETSIGTYPE ${RETSIGTYPE} +/* Define to 1 if the `S_IS*' macros in do not work properly. */ +#undef STAT_MACROS_BROKEN + /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at runtime. @@ -592,28 +655,37 @@ /* Define to 1 if your declares `struct tm'. */ #undef TM_IN_SYS_TIME +/* Define if we have the oprofile JIT-support library */ +#undef USE_OPROFILE + /* Define if use udis86 library */ #undef USE_UDIS86 -/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a - `char[]'. */ -#undef YYTEXT_POINTER - /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define to a type to use for `error_t' if it is not otherwise available. */ #cmakedefine error_t ${error_t} -/* Define to a type to use for `mode_t' if it is not otherwise available. */ -#cmakedefine mode_t ${mode_t} - /* Define to `int' if does not define. */ #undef pid_t /* Define to `unsigned int' if does not define. */ #undef size_t +/* Define if the neat program is available */ +#cmakedefine HAVE_TWOPI ${HAVE_TWOPI} + +/* Define to 1 if the system has the type `uint64_t'. */ +#cmakedefine HAVE_UINT64_T ${HAVE_UINT64_T} + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#undef YYTEXT_POINTER + +/* Define to a type to use for `mode_t' if it is not otherwise available. */ +#cmakedefine mode_t ${mode_t} + /* Define to a function replacing strtoll */ #cmakedefine strtoll ${strtoll} @@ -626,16 +698,40 @@ /* Define to a function implementing strdup */ #cmakedefine strdup ${strdup} -/* LLVM architecture name for the native architecture, if available */ -#cmakedefine LLVM_NATIVE_ARCH ${LLVM_NATIVE_ARCH} - -/* LLVM name for the native Target init function, if available */ -#cmakedefine LLVM_NATIVE_TARGET LLVMInitialize${LLVM_NATIVE_ARCH}Target - -/* LLVM name for the native TargetInfo init function, if available */ -#cmakedefine LLVM_NATIVE_TARGETINFO LLVMInitialize${LLVM_NATIVE_ARCH}TargetInfo - -/* LLVM name for the native AsmPrinter init function, if available */ -#cmakedefine LLVM_NATIVE_ASMPRINTER LLVMInitialize${LLVM_NATIVE_ARCH}AsmPrinter +/* Define to 1 if you have the `_chsize_s' function. */ +#cmakedefine HAVE__CHSIZE_S ${HAVE__CHSIZE_S} + +/* define if the compiler implements namespaces */ +#undef HAVE_NAMESPACES + +/* Does not have std namespace iterator */ +#undef HAVE_STD_ITERATOR + +/* Does not have forward iterator */ +#undef HAVE_FWD_ITERATOR + +/* Does not have bi-directional iterator */ +#undef HAVE_BI_ITERATOR + +/* Does not have */ +#undef HAVE_GLOBAL_HASH_MAP + +/* Does not have hash_set in global namespace */ +#undef HAVE_GLOBAL_HASH_SET + +/* Does not have ext/hash_map */ +#undef HAVE_GNU_EXT_HASH_MAP + +/* Does not have hash_set in gnu namespace */ +#undef HAVE_GNU_EXT_HASH_SET + +/* Does not have ext/hash_map> */ +#undef HAVE_STD_EXT_HASH_MAP + +/* Does not have hash_set in std namespace */ +#undef HAVE_STD_EXT_HASH_SET + +/* Added by Kevin -- Maximum path length */ +#cmakedefine MAXPATHLEN ${MAXPATHLEN} #endif diff --git a/include/llvm/Config/config.h.in b/include/llvm/Config/config.h.in index d62da1ab0377..14c44b4b1e20 100644 --- a/include/llvm/Config/config.h.in +++ b/include/llvm/Config/config.h.in @@ -3,6 +3,9 @@ #ifndef CONFIG_H #define CONFIG_H +/* Relative directory for resource files */ +#undef CLANG_RESOURCE_DIR + /* 32 bit multilib directory. */ #undef CXX_INCLUDE_32BIT_DIR @@ -69,9 +72,16 @@ /* Define to 1 if you have the header file. */ #undef HAVE_CRASHREPORTERCLIENT_H +/* Define if __crashreporter_info__ exists. */ +#undef HAVE_CRASHREPORTER_INFO + /* Define to 1 if you have the header file. */ #undef HAVE_CTYPE_H +/* Define to 1 if you have the declaration of `strerror_s', and to 0 if you + don't. */ +#undef HAVE_DECL_STRERROR_S + /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_DIRENT_H @@ -118,6 +128,9 @@ /* Define if the neat program is available */ #undef HAVE_FDP +/* Define to 1 if you have the header file. */ +#undef HAVE_FENV_H + /* Define if libffi is available on this platform. */ #undef HAVE_FFI_CALL @@ -375,9 +388,6 @@ /* Define to 1 if you have the `strerror_r' function. */ #undef HAVE_STRERROR_R -/* Define to 1 if you have the `strerror_s' function. */ -#undef HAVE_STRERROR_S - /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H @@ -431,6 +441,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_UIO_H + /* Define to 1 if you have that is POSIX.1 compatible. */ #undef HAVE_SYS_WAIT_H @@ -458,9 +471,63 @@ /* Define to 1 if you have the header file. */ #undef HAVE_WINDOWS_H +/* Define to 1 if you have the `writev' function. */ +#undef HAVE_WRITEV + +/* Define if the xdot.py program is available */ +#undef HAVE_XDOT_PY + +/* Have host's _alloca */ +#undef HAVE__ALLOCA + +/* Have host's __alloca */ +#undef HAVE___ALLOCA + +/* Have host's __ashldi3 */ +#undef HAVE___ASHLDI3 + +/* Have host's __ashrdi3 */ +#undef HAVE___ASHRDI3 + +/* Have host's __chkstk */ +#undef HAVE___CHKSTK + +/* Have host's __cmpdi2 */ +#undef HAVE___CMPDI2 + +/* Have host's __divdi3 */ +#undef HAVE___DIVDI3 + /* Define to 1 if you have the `__dso_handle' function. */ #undef HAVE___DSO_HANDLE +/* Have host's __fixdfdi */ +#undef HAVE___FIXDFDI + +/* Have host's __fixsfdi */ +#undef HAVE___FIXSFDI + +/* Have host's __floatdidf */ +#undef HAVE___FLOATDIDF + +/* Have host's __lshrdi3 */ +#undef HAVE___LSHRDI3 + +/* Have host's __main */ +#undef HAVE___MAIN + +/* Have host's __moddi3 */ +#undef HAVE___MODDI3 + +/* Have host's __udivdi3 */ +#undef HAVE___UDIVDI3 + +/* Have host's __umoddi3 */ +#undef HAVE___UMODDI3 + +/* Have host's ___chkstk */ +#undef HAVE____CHKSTK + /* Linker version detected at compile time. */ #undef HOST_LINK_VERSION @@ -539,6 +606,9 @@ /* Define to path to twopi program if found or 'echo twopi' otherwise */ #undef LLVM_PATH_TWOPI +/* Define to path to xdot.py program if found or 'echo xdot.py' otherwise */ +#undef LLVM_PATH_XDOT_PY + /* Installation prefix directory */ #undef LLVM_PREFIX diff --git a/include/llvm/Config/llvm-config.h.cmake b/include/llvm/Config/llvm-config.h.cmake index 8469bcc60674..a679b956b373 100644 --- a/include/llvm/Config/llvm-config.h.cmake +++ b/include/llvm/Config/llvm-config.h.cmake @@ -47,7 +47,7 @@ #cmakedefine LLVM_MANDIR "${LLVM_MANDIR}" /* Build multithreading support into LLVM */ -#cmakedefine LLVM_MULTITHREADED +#cmakedefine LLVM_MULTITHREADED ${LLVM_MULTITHREADED} /* LLVM architecture name for the native architecture, if available */ #cmakedefine LLVM_NATIVE_ARCH ${LLVM_NATIVE_ARCH} @@ -62,10 +62,10 @@ #cmakedefine LLVM_NATIVE_ASMPRINTER LLVMInitialize${LLVM_NATIVE_ARCH}AsmPrinter /* Define if this is Unixish platform */ -#cmakedefine LLVM_ON_UNIX +#cmakedefine LLVM_ON_UNIX ${LLVM_ON_UNIX} /* Define if this is Win32ish platform */ -#cmakedefine LLVM_ON_WIN32 +#cmakedefine LLVM_ON_WIN32 ${LLVM_ON_WIN32} /* Define to path to circo program if found or 'echo circo' otherwise */ #cmakedefine LLVM_PATH_CIRCO "${LLVM_PATH_CIRCO}" diff --git a/include/llvm/Constant.h b/include/llvm/Constant.h index 864729929982..38045fc0c1d6 100644 --- a/include/llvm/Constant.h +++ b/include/llvm/Constant.h @@ -20,7 +20,6 @@ namespace llvm { class APInt; template class SmallVectorImpl; - class LLVMContext; /// This is an important base class in LLVM. It provides the common facilities /// of all constant values in an LLVM program. A constant is a value that is @@ -142,16 +141,22 @@ public: assert(0 && "Constants that do not have operands cannot be using 'From'!"); } - static Constant* getNullValue(const Type* Ty); + static Constant *getNullValue(const Type* Ty); /// @returns the value for an integer constant of the given type that has all /// its bits set to true. /// @brief Get the all ones value - static Constant* getAllOnesValue(const Type* Ty); + static Constant *getAllOnesValue(const Type* Ty); /// getIntegerValue - Return the value for an integer or pointer constant, /// or a vector thereof, with the given scalar value. - static Constant* getIntegerValue(const Type* Ty, const APInt &V); + static Constant *getIntegerValue(const Type* Ty, const APInt &V); + + /// removeDeadConstantUsers - If there are any dead constant users dangling + /// off of this constant, remove them. This method is useful for clients + /// that want to check to see if a global is unused, but don't want to deal + /// with potentially dead constants hanging off of the globals. + void removeDeadConstantUsers() const; }; } // End llvm namespace diff --git a/include/llvm/Constants.h b/include/llvm/Constants.h index a7deae0451bc..c4768f842345 100644 --- a/include/llvm/Constants.h +++ b/include/llvm/Constants.h @@ -25,8 +25,7 @@ #include "llvm/OperandTraits.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/APFloat.h" -#include "llvm/ADT/SmallVector.h" -#include +#include "llvm/ADT/ArrayRef.h" namespace llvm { @@ -265,8 +264,8 @@ public: inline const APFloat& getValueAPF() const { return Val; } /// isNullValue - Return true if this is the value that would be returned by - /// getNullValue. Don't depend on == for doubles to tell us it's zero, it - /// considers -0.0 to be null as well as 0.0. :( + /// getNullValue. For ConstantFP, this is +0.0, but not -0.0. To handle the + /// two the same, use isZero(). virtual bool isNullValue() const; /// isNegativeZeroValue - Return true if the value is what would be returned @@ -404,7 +403,8 @@ public: }; template <> -struct OperandTraits : public VariadicOperandTraits<> { +struct OperandTraits : + public VariadicOperandTraits { }; DEFINE_TRANSPARENT_CASTED_OPERAND_ACCESSORS(ConstantArray, Constant) @@ -453,7 +453,8 @@ public: }; template <> -struct OperandTraits : public VariadicOperandTraits<> { +struct OperandTraits : + public VariadicOperandTraits { }; DEFINE_TRANSPARENT_CASTED_OPERAND_ACCESSORS(ConstantStruct, Constant) @@ -470,9 +471,9 @@ protected: ConstantVector(const VectorType *T, const std::vector &Val); public: // ConstantVector accessors + static Constant *get(ArrayRef V); + // FIXME: Eliminate this constructor form. static Constant *get(const VectorType *T, const std::vector &V); - static Constant *get(const std::vector &V); - static Constant *get(Constant *const *Vals, unsigned NumVals); /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); @@ -497,7 +498,7 @@ public: /// getSplatValue - If this is a splat constant, meaning that all of the /// elements have the same value, return that value. Otherwise return NULL. - Constant *getSplatValue(); + Constant *getSplatValue() const; virtual void destroyConstant(); virtual void replaceUsesOfWithOnConstant(Value *From, Value *To, Use *U); @@ -510,7 +511,8 @@ public: }; template <> -struct OperandTraits : public VariadicOperandTraits<> { +struct OperandTraits : + public VariadicOperandTraits { }; DEFINE_TRANSPARENT_CASTED_OPERAND_ACCESSORS(ConstantVector, Constant) @@ -591,7 +593,8 @@ public: }; template <> -struct OperandTraits : public FixedNumOperandTraits<2> { +struct OperandTraits : + public FixedNumOperandTraits { }; DEFINE_TRANSPARENT_CASTED_OPERAND_ACCESSORS(BlockAddress, Value) @@ -624,11 +627,10 @@ protected: Constant *C2); static Constant *getSelectTy(const Type *Ty, Constant *C1, Constant *C2, Constant *C3); + template static Constant *getGetElementPtrTy(const Type *Ty, Constant *C, - Value* const *Idxs, unsigned NumIdxs); - static Constant *getInBoundsGetElementPtrTy(const Type *Ty, Constant *C, - Value* const *Idxs, - unsigned NumIdxs); + IndexTy const *Idxs, unsigned NumIdxs, + bool InBounds); static Constant *getExtractElementTy(const Type *Ty, Constant *Val, Constant *Idx); static Constant *getInsertElementTy(const Type *Ty, Constant *Val, @@ -640,6 +642,10 @@ protected: static Constant *getInsertValueTy(const Type *Ty, Constant *Agg, Constant *Val, const unsigned *Idxs, unsigned NumIdxs); + template + static Constant *getGetElementPtrImpl(Constant *C, + IndexTy const *IdxList, + unsigned NumIdx, bool InBounds); public: // Static methods to construct a ConstantExpr of different kinds. Note that @@ -649,35 +655,38 @@ public: /// getAlignOf constant expr - computes the alignment of a type in a target /// independent way (Note: the return type is an i64). - static Constant *getAlignOf(const Type* Ty); + static Constant *getAlignOf(const Type *Ty); /// getSizeOf constant expr - computes the (alloc) size of a type (in /// address-units, not bits) in a target independent way (Note: the return /// type is an i64). /// - static Constant *getSizeOf(const Type* Ty); + static Constant *getSizeOf(const Type *Ty); /// getOffsetOf constant expr - computes the offset of a struct field in a /// target independent way (Note: the return type is an i64). /// - static Constant *getOffsetOf(const StructType* STy, unsigned FieldNo); + static Constant *getOffsetOf(const StructType *STy, unsigned FieldNo); /// getOffsetOf constant expr - This is a generalized form of getOffsetOf, /// which supports any aggregate type, and any Constant index. /// - static Constant *getOffsetOf(const Type* Ty, Constant *FieldNo); + static Constant *getOffsetOf(const Type *Ty, Constant *FieldNo); - static Constant *getNeg(Constant *C); + static Constant *getNeg(Constant *C, bool HasNUW = false, bool HasNSW =false); static Constant *getFNeg(Constant *C); static Constant *getNot(Constant *C); - static Constant *getAdd(Constant *C1, Constant *C2); + static Constant *getAdd(Constant *C1, Constant *C2, + bool HasNUW = false, bool HasNSW = false); static Constant *getFAdd(Constant *C1, Constant *C2); - static Constant *getSub(Constant *C1, Constant *C2); + static Constant *getSub(Constant *C1, Constant *C2, + bool HasNUW = false, bool HasNSW = false); static Constant *getFSub(Constant *C1, Constant *C2); - static Constant *getMul(Constant *C1, Constant *C2); + static Constant *getMul(Constant *C1, Constant *C2, + bool HasNUW = false, bool HasNSW = false); static Constant *getFMul(Constant *C1, Constant *C2); - static Constant *getUDiv(Constant *C1, Constant *C2); - static Constant *getSDiv(Constant *C1, Constant *C2); + static Constant *getUDiv(Constant *C1, Constant *C2, bool isExact = false); + static Constant *getSDiv(Constant *C1, Constant *C2, bool isExact = false); static Constant *getFDiv(Constant *C1, Constant *C2); static Constant *getURem(Constant *C1, Constant *C2); static Constant *getSRem(Constant *C1, Constant *C2); @@ -685,9 +694,10 @@ public: static Constant *getAnd(Constant *C1, Constant *C2); static Constant *getOr(Constant *C1, Constant *C2); static Constant *getXor(Constant *C1, Constant *C2); - static Constant *getShl(Constant *C1, Constant *C2); - static Constant *getLShr(Constant *C1, Constant *C2); - static Constant *getAShr(Constant *C1, Constant *C2); + static Constant *getShl(Constant *C1, Constant *C2, + bool HasNUW = false, bool HasNSW = false); + static Constant *getLShr(Constant *C1, Constant *C2, bool isExact = false); + static Constant *getAShr(Constant *C1, Constant *C2, bool isExact = false); static Constant *getTrunc (Constant *C, const Type *Ty); static Constant *getSExt (Constant *C, const Type *Ty); static Constant *getZExt (Constant *C, const Type *Ty); @@ -701,15 +711,44 @@ public: static Constant *getIntToPtr(Constant *C, const Type *Ty); static Constant *getBitCast (Constant *C, const Type *Ty); - static Constant *getNSWNeg(Constant *C); - static Constant *getNUWNeg(Constant *C); - static Constant *getNSWAdd(Constant *C1, Constant *C2); - static Constant *getNUWAdd(Constant *C1, Constant *C2); - static Constant *getNSWSub(Constant *C1, Constant *C2); - static Constant *getNUWSub(Constant *C1, Constant *C2); - static Constant *getNSWMul(Constant *C1, Constant *C2); - static Constant *getNUWMul(Constant *C1, Constant *C2); - static Constant *getExactSDiv(Constant *C1, Constant *C2); + static Constant *getNSWNeg(Constant *C) { return getNeg(C, false, true); } + static Constant *getNUWNeg(Constant *C) { return getNeg(C, true, false); } + static Constant *getNSWAdd(Constant *C1, Constant *C2) { + return getAdd(C1, C2, false, true); + } + static Constant *getNUWAdd(Constant *C1, Constant *C2) { + return getAdd(C1, C2, true, false); + } + static Constant *getNSWSub(Constant *C1, Constant *C2) { + return getSub(C1, C2, false, true); + } + static Constant *getNUWSub(Constant *C1, Constant *C2) { + return getSub(C1, C2, true, false); + } + static Constant *getNSWMul(Constant *C1, Constant *C2) { + return getMul(C1, C2, false, true); + } + static Constant *getNUWMul(Constant *C1, Constant *C2) { + return getMul(C1, C2, true, false); + } + static Constant *getNSWShl(Constant *C1, Constant *C2) { + return getShl(C1, C2, false, true); + } + static Constant *getNUWShl(Constant *C1, Constant *C2) { + return getShl(C1, C2, true, false); + } + static Constant *getExactSDiv(Constant *C1, Constant *C2) { + return getSDiv(C1, C2, true); + } + static Constant *getExactUDiv(Constant *C1, Constant *C2) { + return getUDiv(C1, C2, true); + } + static Constant *getExactAShr(Constant *C1, Constant *C2) { + return getAShr(C1, C2, true); + } + static Constant *getExactLShr(Constant *C1, Constant *C2) { + return getLShr(C1, C2, true); + } /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); @@ -801,18 +840,24 @@ public: /// all elements must be Constant's. /// static Constant *getGetElementPtr(Constant *C, - Constant *const *IdxList, unsigned NumIdx); + Constant *const *IdxList, unsigned NumIdx, + bool InBounds = false); static Constant *getGetElementPtr(Constant *C, - Value* const *IdxList, unsigned NumIdx); + Value *const *IdxList, unsigned NumIdx, + bool InBounds = false); /// Create an "inbounds" getelementptr. See the documentation for the /// "inbounds" flag in LangRef.html for details. static Constant *getInBoundsGetElementPtr(Constant *C, Constant *const *IdxList, - unsigned NumIdx); + unsigned NumIdx) { + return getGetElementPtr(C, IdxList, NumIdx, true); + } static Constant *getInBoundsGetElementPtr(Constant *C, Value* const *IdxList, - unsigned NumIdx); + unsigned NumIdx) { + return getGetElementPtr(C, IdxList, NumIdx, true); + } static Constant *getExtractElement(Constant *Vec, Constant *Idx); static Constant *getInsertElement(Constant *Vec, Constant *Elt,Constant *Idx); @@ -870,7 +915,8 @@ private: }; template <> -struct OperandTraits : public VariadicOperandTraits<1> { +struct OperandTraits : + public VariadicOperandTraits { }; DEFINE_TRANSPARENT_CASTED_OPERAND_ACCESSORS(ConstantExpr, Constant) diff --git a/include/llvm/DerivedTypes.h b/include/llvm/DerivedTypes.h index 9b6b19f15466..56d1e3e237d6 100644 --- a/include/llvm/DerivedTypes.h +++ b/include/llvm/DerivedTypes.h @@ -9,7 +9,7 @@ // // This file contains the declarations of classes that represent "derived // types". These are things like "arrays of x" or "structure of x, y, z" or -// "method returning x taking (y,z) as parameters", etc... +// "function returning x taking (y,z) as parameters", etc... // // The implementations of these classes live in the Type.cpp file. // @@ -19,6 +19,7 @@ #define LLVM_DERIVED_TYPES_H #include "llvm/Type.h" +#include "llvm/Support/DataTypes.h" namespace llvm { diff --git a/include/llvm/ExecutionEngine/ExecutionEngine.h b/include/llvm/ExecutionEngine/ExecutionEngine.h index 3287b39a3c95..71698fa00874 100644 --- a/include/llvm/ExecutionEngine/ExecutionEngine.h +++ b/include/llvm/ExecutionEngine/ExecutionEngine.h @@ -22,7 +22,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/ValueMap.h" #include "llvm/Support/ValueHandle.h" -#include "llvm/System/Mutex.h" +#include "llvm/Support/Mutex.h" #include "llvm/Target/TargetMachine.h" namespace llvm { @@ -41,6 +41,8 @@ class MutexGuard; class TargetData; class Type; +/// \brief Helper class for helping synchronize access to the global address map +/// table. class ExecutionEngineState { public: struct AddressMapConfig : public ValueMapConfig { @@ -70,8 +72,7 @@ private: public: ExecutionEngineState(ExecutionEngine &EE); - GlobalAddressMapTy & - getGlobalAddressMap(const MutexGuard &) { + GlobalAddressMapTy &getGlobalAddressMap(const MutexGuard &) { return GlobalAddressMap; } @@ -80,23 +81,41 @@ public: return GlobalAddressReverseMap; } - // Returns the address ToUnmap was mapped to. + /// \brief Erase an entry from the mapping table. + /// + /// \returns The address that \arg ToUnmap was happed to. void *RemoveMapping(const MutexGuard &, const GlobalValue *ToUnmap); }; - +/// \brief Abstract interface for implementation execution of LLVM modules, +/// designed to support both interpreter and just-in-time (JIT) compiler +/// implementations. class ExecutionEngine { - const TargetData *TD; + /// The state object holding the global address mapping, which must be + /// accessed synchronously. + // + // FIXME: There is no particular need the entire map needs to be + // synchronized. Wouldn't a reader-writer design be better here? ExecutionEngineState EEState; + + /// The target data for the platform for which execution is being performed. + const TargetData *TD; + + /// Whether lazy JIT compilation is enabled. bool CompilingLazily; + + /// Whether JIT compilation of external global variables is allowed. bool GVCompilationDisabled; + + /// Whether the JIT should perform lookups of external symbols (e.g., + /// using dlsym). bool SymbolSearchingDisabled; friend class EngineBuilder; // To allow access to JITCtor and InterpCtor. protected: - /// Modules - This is a list of Modules that we are JIT'ing from. We use a - /// smallvector to optimize for the case where there is only one module. + /// The list of Modules that we are JIT'ing from. We use a SmallVector to + /// optimize for the case where there is only one module. SmallVector Modules; void setTargetData(const TargetData *td) { @@ -104,11 +123,11 @@ protected: } /// getMemoryforGV - Allocate memory for a global variable. - virtual char* getMemoryForGV(const GlobalVariable* GV); + virtual char *getMemoryForGV(const GlobalVariable *GV); // To avoid having libexecutionengine depend on the JIT and interpreter - // libraries, the JIT and Interpreter set these functions to ctor pointers - // at startup time if they are linked in. + // libraries, the execution engine implementations set these functions to ctor + // pointers at startup time if they are linked in. static ExecutionEngine *(*JITCtor)( Module *M, std::string *ErrorStr, @@ -119,23 +138,36 @@ protected: StringRef MArch, StringRef MCPU, const SmallVectorImpl& MAttrs); + static ExecutionEngine *(*MCJITCtor)( + Module *M, + std::string *ErrorStr, + JITMemoryManager *JMM, + CodeGenOpt::Level OptLevel, + bool GVsWithCode, + CodeModel::Model CMM, + StringRef MArch, + StringRef MCPU, + const SmallVectorImpl& MAttrs); static ExecutionEngine *(*InterpCtor)(Module *M, std::string *ErrorStr); /// LazyFunctionCreator - If an unknown function is needed, this function - /// pointer is invoked to create it. If this returns null, the JIT will abort. - void* (*LazyFunctionCreator)(const std::string &); + /// pointer is invoked to create it. If this returns null, the JIT will + /// abort. + void *(*LazyFunctionCreator)(const std::string &); - /// ExceptionTableRegister - If Exception Handling is set, the JIT will - /// register dwarf tables with this function + /// ExceptionTableRegister - If Exception Handling is set, the JIT will + /// register dwarf tables with this function. typedef void (*EERegisterFn)(void*); - static EERegisterFn ExceptionTableRegister; + EERegisterFn ExceptionTableRegister; + EERegisterFn ExceptionTableDeregister; + std::vector AllExceptionTables; public: - /// lock - This lock is protects the ExecutionEngine, JIT, JITResolver and + /// lock - This lock protects the ExecutionEngine, JIT, JITResolver and /// JITEmitter classes. It must be held while changing the internal state of /// any of those classes. - sys::Mutex lock; // Used to make this class and subclasses thread-safe + sys::Mutex lock; //===--------------------------------------------------------------------===// // ExecutionEngine Startup @@ -146,20 +178,18 @@ public: /// create - This is the factory method for creating an execution engine which /// is appropriate for the current machine. This takes ownership of the /// module. + /// + /// \param GVsWithCode - Allocating globals with code breaks + /// freeMachineCodeForFunction and is probably unsafe and bad for performance. + /// However, we have clients who depend on this behavior, so we must support + /// it. Eventually, when we're willing to break some backwards compatability, + /// this flag should be flipped to false, so that by default + /// freeMachineCodeForFunction works. static ExecutionEngine *create(Module *M, bool ForceInterpreter = false, std::string *ErrorStr = 0, CodeGenOpt::Level OptLevel = CodeGenOpt::Default, - // Allocating globals with code breaks - // freeMachineCodeForFunction and is probably - // unsafe and bad for performance. However, - // we have clients who depend on this - // behavior, so we must support it. - // Eventually, when we're willing to break - // some backwards compatability, this flag - // should be flipped to false, so that by - // default freeMachineCodeForFunction works. bool GVsWithCode = true); /// createJIT - This is the factory method for creating a JIT for the current @@ -184,11 +214,10 @@ public: Modules.push_back(M); } - //===----------------------------------------------------------------------===// + //===--------------------------------------------------------------------===// const TargetData *getTargetData() const { return TD; } - /// removeModule - Remove a Module from the list of modules. Returns true if /// M is found. virtual bool removeModule(Module *M); @@ -200,17 +229,19 @@ public: /// runFunction - Execute the specified function with the specified arguments, /// and return the result. - /// virtual GenericValue runFunction(Function *F, const std::vector &ArgValues) = 0; /// runStaticConstructorsDestructors - This method is used to execute all of - /// the static constructors or destructors for a program, depending on the - /// value of isDtors. + /// the static constructors or destructors for a program. + /// + /// \param isDtors - Run the destructors instead of constructors. void runStaticConstructorsDestructors(bool isDtors); + /// runStaticConstructorsDestructors - This method is used to execute all of - /// the static constructors or destructors for a module, depending on the - /// value of isDtors. + /// the static constructors or destructors for a particular module. + /// + /// \param isDtors - Run the destructors instead of constructors. void runStaticConstructorsDestructors(Module *module, bool isDtors); @@ -229,8 +260,8 @@ public: /// GlobalValue is destroyed. void addGlobalMapping(const GlobalValue *GV, void *Addr); - /// clearAllGlobalMappings - Clear all global mappings and start over again - /// use in dynamic compilation scenarios when you want to move globals + /// clearAllGlobalMappings - Clear all global mappings and start over again, + /// for use in dynamic compilation scenarios to move globals. void clearAllGlobalMappings(); /// clearGlobalMappingsFromModule - Clear all global mappings that came from a @@ -246,12 +277,10 @@ public: /// getPointerToGlobalIfAvailable - This returns the address of the specified /// global value if it is has already been codegen'd, otherwise it returns /// null. - /// void *getPointerToGlobalIfAvailable(const GlobalValue *GV); /// getPointerToGlobal - This returns the address of the specified global - /// value. This may involve code generation if it's a function. - /// + /// value. This may involve code generation if it's a function. void *getPointerToGlobal(const GlobalValue *GV); /// getPointerToFunction - The different EE's represent function bodies in @@ -259,20 +288,17 @@ public: /// pointer should look like. When F is destroyed, the ExecutionEngine will /// remove its global mapping and free any machine code. Be sure no threads /// are running inside F when that happens. - /// virtual void *getPointerToFunction(Function *F) = 0; /// getPointerToBasicBlock - The different EE's represent basic blocks in /// different ways. Return the representation for a blockaddress of the /// specified block. - /// virtual void *getPointerToBasicBlock(BasicBlock *BB) = 0; /// getPointerToFunctionOrStub - If the specified function has been /// code-gen'd, return a pointer to the function. If not, compile it, or use /// a stub to implement lazy compilation if available. See /// getPointerToFunction for the requirements on destroying F. - /// virtual void *getPointerToFunctionOrStub(Function *F) { // Default implementation, just codegen the function. return getPointerToFunction(F); @@ -286,23 +312,25 @@ public: /// const GlobalValue *getGlobalValueAtAddress(void *Addr); - + /// StoreValueToMemory - Stores the data in Val of type Ty at address Ptr. + /// Ptr is the address of the memory at which to store Val, cast to + /// GenericValue *. It is not a pointer to a GenericValue containing the + /// address at which to store Val. void StoreValueToMemory(const GenericValue &Val, GenericValue *Ptr, const Type *Ty); + void InitializeMemory(const Constant *Init, void *Addr); - /// recompileAndRelinkFunction - This method is used to force a function - /// which has already been compiled to be compiled again, possibly - /// after it has been modified. Then the entry to the old copy is overwritten - /// with a branch to the new copy. If there was no old copy, this acts - /// just like VM::getPointerToFunction(). - /// + /// recompileAndRelinkFunction - This method is used to force a function which + /// has already been compiled to be compiled again, possibly after it has been + /// modified. Then the entry to the old copy is overwritten with a branch to + /// the new copy. If there was no old copy, this acts just like + /// VM::getPointerToFunction(). virtual void *recompileAndRelinkFunction(Function *F) = 0; /// freeMachineCodeForFunction - Release memory in the ExecutionEngine /// corresponding to the machine code emitted to execute this function, useful /// for garbage-collecting generated code. - /// virtual void freeMachineCodeForFunction(Function *F) = 0; /// getOrEmitGlobalVariable - Return the address of the specified global @@ -373,25 +401,31 @@ public: /// InstallExceptionTableRegister - The JIT will use the given function /// to register the exception tables it generates. - static void InstallExceptionTableRegister(void (*F)(void*)) { + void InstallExceptionTableRegister(EERegisterFn F) { ExceptionTableRegister = F; } + void InstallExceptionTableDeregister(EERegisterFn F) { + ExceptionTableDeregister = F; + } - /// RegisterTable - Registers the given pointer as an exception table. It uses - /// the ExceptionTableRegister function. - static void RegisterTable(void* res) { - if (ExceptionTableRegister) + /// RegisterTable - Registers the given pointer as an exception table. It + /// uses the ExceptionTableRegister function. + void RegisterTable(void* res) { + if (ExceptionTableRegister) { ExceptionTableRegister(res); + AllExceptionTables.push_back(res); + } } + /// DeregisterAllTables - Deregisters all previously registered pointers to an + /// exception tables. It uses the ExceptionTableoDeregister function. + void DeregisterAllTables(); + protected: explicit ExecutionEngine(Module *M); void emitGlobals(); - // EmitGlobalVariable - This method emits the specified global variable to the - // address specified in GlobalAddresses, or allocates new memory if it's not - // already in the map. void EmitGlobalVariable(const GlobalVariable *GV); GenericValue getConstantValue(const Constant *C); @@ -412,8 +446,7 @@ namespace EngineKind { /// stack-allocating a builder, chaining the various set* methods, and /// terminating it with a .create() call. class EngineBuilder { - - private: +private: Module *M; EngineKind::Kind WhichEngine; std::string *ErrorStr; @@ -424,9 +457,9 @@ class EngineBuilder { std::string MArch; std::string MCPU; SmallVector MAttrs; + bool UseMCJIT; /// InitEngine - Does the common initialization of default options. - /// void InitEngine() { WhichEngine = EngineKind::Either; ErrorStr = NULL; @@ -434,9 +467,10 @@ class EngineBuilder { JMM = NULL; AllocateGVsWithCode = false; CMModel = CodeModel::Default; + UseMCJIT = false; } - public: +public: /// EngineBuilder - Constructor for EngineBuilder. If create() is called and /// is successful, the created engine takes ownership of the module. EngineBuilder(Module *m) : M(m) { @@ -504,6 +538,12 @@ class EngineBuilder { return *this; } + /// setUseMCJIT - Set whether the MC-JIT implementation should be used + /// (experimental). + void setUseMCJIT(bool Value) { + UseMCJIT = Value; + } + /// setMAttrs - Set cpu-specific attributes. template EngineBuilder &setMAttrs(const StringSequence &mattrs) { diff --git a/include/llvm/ExecutionEngine/GenericValue.h b/include/llvm/ExecutionEngine/GenericValue.h index 1301320c1435..a2fed98c150e 100644 --- a/include/llvm/ExecutionEngine/GenericValue.h +++ b/include/llvm/ExecutionEngine/GenericValue.h @@ -16,7 +16,7 @@ #define GENERIC_VALUE_H #include "llvm/ADT/APInt.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { diff --git a/include/llvm/ExecutionEngine/JITEventListener.h b/include/llvm/ExecutionEngine/JITEventListener.h index dcc66b2a089f..abc063b07038 100644 --- a/include/llvm/ExecutionEngine/JITEventListener.h +++ b/include/llvm/ExecutionEngine/JITEventListener.h @@ -15,7 +15,7 @@ #ifndef LLVM_EXECUTION_ENGINE_JIT_EVENTLISTENER_H #define LLVM_EXECUTION_ENGINE_JIT_EVENTLISTENER_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/Support/DebugLoc.h" #include @@ -24,35 +24,38 @@ namespace llvm { class Function; class MachineFunction; -/// Empty for now, but this object will contain all details about the -/// generated machine code that a Listener might care about. +/// JITEvent_EmittedFunctionDetails - Helper struct for containing information +/// about a generated machine code function. struct JITEvent_EmittedFunctionDetails { - const MachineFunction *MF; - struct LineStart { - // The address at which the current line changes. + /// The address at which the current line changes. uintptr_t Address; - // The new location information. These can be translated to - // DebugLocTuples using MF->getDebugLocTuple(). + + /// The new location information. These can be translated to DebugLocTuples + /// using MF->getDebugLocTuple(). DebugLoc Loc; }; - // This holds line boundary information sorted by address. + + /// The machine function the struct contains information for. + const MachineFunction *MF; + + /// The list of line boundary information, sorted by address. std::vector LineStarts; }; -/// JITEventListener - This interface is used by the JIT to notify clients about -/// significant events during compilation. For example, we could have -/// implementations for profilers and debuggers that need to know where -/// functions have been emitted. +/// JITEventListener - Abstract interface for use by the JIT to notify clients +/// about significant events during compilation. For example, to notify +/// profilers and debuggers that need to know where functions have been emitted. /// -/// Each method defaults to doing nothing, so you only need to override the ones -/// you care about. +/// The default implementation of each method does nothing. class JITEventListener { +public: + typedef JITEvent_EmittedFunctionDetails EmittedFunctionDetails; + public: JITEventListener() {} - virtual ~JITEventListener(); // Defined in JIT.cpp. + virtual ~JITEventListener(); - typedef JITEvent_EmittedFunctionDetails EmittedFunctionDetails; /// NotifyFunctionEmitted - Called after a function has been successfully /// emitted to memory. The function still has its MachineFunction attached, /// if you should happen to need that. @@ -60,13 +63,14 @@ public: void *Code, size_t Size, const EmittedFunctionDetails &Details) {} - /// NotifyFreeingMachineCode - This is called inside of - /// freeMachineCodeForFunction(), after the global mapping is removed, but - /// before the machine code is returned to the allocator. OldPtr is the - /// address of the machine code and will be the same as the Code parameter to - /// a previous NotifyFunctionEmitted call. The Function passed to - /// NotifyFunctionEmitted may have been destroyed by the time of the matching - /// NotifyFreeingMachineCode call. + /// NotifyFreeingMachineCode - Called from freeMachineCodeForFunction(), after + /// the global mapping is removed, but before the machine code is returned to + /// the allocator. + /// + /// OldPtr is the address of the machine code and will be the same as the Code + /// parameter to a previous NotifyFunctionEmitted call. The Function passed + /// to NotifyFunctionEmitted may have been destroyed by the time of the + /// matching NotifyFreeingMachineCode call. virtual void NotifyFreeingMachineCode(void *OldPtr) {} }; diff --git a/include/llvm/ExecutionEngine/JITMemoryManager.h b/include/llvm/ExecutionEngine/JITMemoryManager.h index e0159309ce5c..384141801667 100644 --- a/include/llvm/ExecutionEngine/JITMemoryManager.h +++ b/include/llvm/ExecutionEngine/JITMemoryManager.h @@ -6,15 +6,11 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -// -// This file defines the JITMemoryManagerInterface -// -//===----------------------------------------------------------------------===// #ifndef LLVM_EXECUTION_ENGINE_JIT_MEMMANAGER_H #define LLVM_EXECUTION_ENGINE_JIT_MEMMANAGER_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include namespace llvm { @@ -29,8 +25,8 @@ namespace llvm { class JITMemoryManager { protected: bool HasGOT; -public: +public: JITMemoryManager() : HasGOT(false) {} virtual ~JITMemoryManager(); @@ -48,7 +44,7 @@ public: /// setPoisonMemory - Setting this flag to true makes the memory manager /// garbage values over freed memory. This is useful for testing and - /// debugging, and is be turned on by default in debug mode. + /// debugging, and may be turned on by default in debug mode. virtual void setPoisonMemory(bool poison) = 0; //===--------------------------------------------------------------------===// @@ -61,7 +57,6 @@ public: virtual void AllocateGOT() = 0; /// isManagingGOT - Return true if the AllocateGOT method is called. - /// bool isManagingGOT() const { return HasGOT; } @@ -111,7 +106,6 @@ public: virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) = 0; /// allocateGlobal - Allocate memory for a global. - /// virtual uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) = 0; /// deallocateFunctionBody - Free the specified function body. The argument diff --git a/include/llvm/ExecutionEngine/MCJIT.h b/include/llvm/ExecutionEngine/MCJIT.h new file mode 100644 index 000000000000..f956a5029b17 --- /dev/null +++ b/include/llvm/ExecutionEngine/MCJIT.h @@ -0,0 +1,38 @@ +//===-- MCJIT.h - MC-Based Just-In-Time Execution Engine --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file forces the MCJIT to link in on certain operating systems. +// (Windows). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EXECUTION_ENGINE_MCJIT_H +#define LLVM_EXECUTION_ENGINE_MCJIT_H + +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include + +extern "C" void LLVMLinkInMCJIT(); + +namespace { + struct ForceMCJITLinking { + ForceMCJITLinking() { + // We must reference the passes in such a way that compilers will not + // delete it all as dead code, even with whole program optimization, + // yet is effectively a NO-OP. As the compiler isn't smart enough + // to know that getenv() never returns -1, this will do the job. + if (std::getenv("bar") != (char*) -1) + return; + + LLVMLinkInMCJIT(); + } + } ForceMCJITLinking; +} + +#endif diff --git a/include/llvm/Function.h b/include/llvm/Function.h index 2b19fa5a7f38..9a0825ab4a96 100644 --- a/include/llvm/Function.h +++ b/include/llvm/Function.h @@ -152,7 +152,7 @@ public: /// The particular intrinsic functions which correspond to this value are /// defined in llvm/Intrinsics.h. /// - unsigned getIntrinsicID() const ATTRIBUTE_READONLY; + unsigned getIntrinsicID() const LLVM_ATTRIBUTE_READONLY; bool isIntrinsic() const { return getIntrinsicID() != 0; } /// getCallingConv()/setCallingConv(CC) - These method get and set the diff --git a/include/llvm/GlobalAlias.h b/include/llvm/GlobalAlias.h index 9867c518c890..f4af5b1202c5 100644 --- a/include/llvm/GlobalAlias.h +++ b/include/llvm/GlobalAlias.h @@ -89,7 +89,8 @@ public: }; template <> -struct OperandTraits : public FixedNumOperandTraits<1> { +struct OperandTraits : + public FixedNumOperandTraits { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GlobalAlias, Value) diff --git a/include/llvm/GlobalValue.h b/include/llvm/GlobalValue.h index 62e84f833510..b184b8e44971 100644 --- a/include/llvm/GlobalValue.h +++ b/include/llvm/GlobalValue.h @@ -60,7 +60,8 @@ protected: GlobalValue(const Type *ty, ValueTy vty, Use *Ops, unsigned NumOps, LinkageTypes linkage, const Twine &Name) : Constant(ty, vty, Ops, NumOps), Parent(0), - Linkage(linkage), Visibility(DefaultVisibility), Alignment(0) { + Linkage(linkage), Visibility(DefaultVisibility), Alignment(0), + UnnamedAddr(0) { setName(Name); } @@ -70,6 +71,7 @@ protected: LinkageTypes Linkage : 5; // The linkage of this global unsigned Visibility : 2; // The visibility style of this global unsigned Alignment : 16; // Alignment of this symbol, must be power of two + unsigned UnnamedAddr : 1; // This value's address is not significant std::string Section; // Section to emit this into, empty mean default public: ~GlobalValue() { @@ -81,6 +83,9 @@ public: } void setAlignment(unsigned Align); + bool hasUnnamedAddr() const { return UnnamedAddr; } + void setUnnamedAddr(bool Val) { UnnamedAddr = Val; } + VisibilityTypes getVisibility() const { return VisibilityTypes(Visibility); } bool hasDefaultVisibility() const { return Visibility == DefaultVisibility; } bool hasHiddenVisibility() const { return Visibility == HiddenVisibility; } @@ -173,7 +178,9 @@ public: } /// isWeakForLinker - Whether the definition of this global may be replaced at - /// link time. + /// link time. NB: Using this method outside of the code generators is almost + /// always a mistake: when working at the IR level use mayBeOverridden instead + /// as it knows about ODR semantics. static bool isWeakForLinker(LinkageTypes Linkage) { return Linkage == AvailableExternallyLinkage || Linkage == WeakAnyLinkage || @@ -275,12 +282,6 @@ public: inline Module *getParent() { return Parent; } inline const Module *getParent() const { return Parent; } - /// removeDeadConstantUsers - If there are any dead constant users dangling - /// off of this global value, remove them. This method is useful for clients - /// that want to check to see if a global is unused, but don't want to deal - /// with potentially dead constants hanging off of the globals. - void removeDeadConstantUsers() const; - // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const GlobalValue *) { return true; } static inline bool classof(const Value *V) { diff --git a/include/llvm/GlobalVariable.h b/include/llvm/GlobalVariable.h index 633e8b4dc335..1769c665d062 100644 --- a/include/llvm/GlobalVariable.h +++ b/include/llvm/GlobalVariable.h @@ -68,7 +68,7 @@ public: /// Provide fast operand accessors DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); - /// isDeclaration - Is this global variable lacking an initializer? If so, + /// isDeclaration - Is this global variable lacking an initializer? If so, /// the global variable is defined in some other translation unit, and is thus /// only a declaration here. virtual bool isDeclaration() const { return getNumOperands() == 0; } @@ -80,7 +80,21 @@ public: inline bool hasInitializer() const { return !isDeclaration(); } /// hasDefinitiveInitializer - Whether the global variable has an initializer, - /// and this is the initializer that will be used in the final executable. + /// and any other instances of the global (this can happen due to weak + /// linkage) are guaranteed to have the same initializer. + /// + /// Note that if you want to transform a global, you must use + /// hasUniqueInitializer() instead, because of the *_odr linkage type. + /// + /// Example: + /// + /// @a = global SomeType* null - Initializer is both definitive and unique. + /// + /// @b = global weak SomeType* null - Initializer is neither definitive nor + /// unique. + /// + /// @c = global weak_odr SomeType* null - Initializer is definitive, but not + /// unique. inline bool hasDefinitiveInitializer() const { return hasInitializer() && // The initializer of a global variable with weak linkage may change at @@ -88,6 +102,19 @@ public: !mayBeOverridden(); } + /// hasUniqueInitializer - Whether the global variable has an initializer, and + /// any changes made to the initializer will turn up in the final executable. + inline bool hasUniqueInitializer() const { + return hasInitializer() && + // It's not safe to modify initializers of global variables with weak + // linkage, because the linker might choose to discard the initializer and + // use the initializer from another instance of the global variable + // instead. It is wrong to modify the initializer of a global variable + // with *_odr linkage because then different instances of the global may + // have different initializers, breaking the One Definition Rule. + !isWeakForLinker(); + } + /// getInitializer - Return the initializer for this global variable. It is /// illegal to call this method if the global is external, because we cannot /// tell what the value is initialized to! @@ -142,7 +169,8 @@ public: }; template <> -struct OperandTraits : public OptionalOperandTraits<> { +struct OperandTraits : + public OptionalOperandTraits { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GlobalVariable, Value) diff --git a/include/llvm/InitializePasses.h b/include/llvm/InitializePasses.h new file mode 100644 index 000000000000..02dbfbd26d58 --- /dev/null +++ b/include/llvm/InitializePasses.h @@ -0,0 +1,235 @@ +//===- llvm/InitializePasses.h -------- Initialize All Passes ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declarations for the pass initialization routines +// for the entire LLVM project. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_INITIALIZEPASSES_H +#define LLVM_INITIALIZEPASSES_H + +namespace llvm { + +class PassRegistry; + +/// initializeCore - Initialize all passes linked into the +/// TransformUtils library. +void initializeCore(PassRegistry&); + +/// initializeTransformUtils - Initialize all passes linked into the +/// TransformUtils library. +void initializeTransformUtils(PassRegistry&); + +/// initializeScalarOpts - Initialize all passes linked into the +/// ScalarOpts library. +void initializeScalarOpts(PassRegistry&); + +/// initializeInstCombine - Initialize all passes linked into the +/// ScalarOpts library. +void initializeInstCombine(PassRegistry&); + +/// initializeIPO - Initialize all passes linked into the IPO library. +void initializeIPO(PassRegistry&); + +/// initializeInstrumentation - Initialize all passes linked into the +/// Instrumentation library. +void initializeInstrumentation(PassRegistry&); + +/// initializeAnalysis - Initialize all passes linked into the Analysis library. +void initializeAnalysis(PassRegistry&); + +/// initializeIPA - Initialize all passes linked into the IPA library. +void initializeIPA(PassRegistry&); + +/// initializeCodeGen - Initialize all passes linked into the CodeGen library. +void initializeCodeGen(PassRegistry&); + +/// initializeCodeGen - Initialize all passes linked into the CodeGen library. +void initializeTarget(PassRegistry&); + +void initializeAAEvalPass(PassRegistry&); +void initializeADCEPass(PassRegistry&); +void initializeAliasAnalysisAnalysisGroup(PassRegistry&); +void initializeAliasAnalysisCounterPass(PassRegistry&); +void initializeAliasDebuggerPass(PassRegistry&); +void initializeAliasSetPrinterPass(PassRegistry&); +void initializeAlwaysInlinerPass(PassRegistry&); +void initializeArgPromotionPass(PassRegistry&); +void initializeBasicAliasAnalysisPass(PassRegistry&); +void initializeBasicCallGraphPass(PassRegistry&); +void initializeBlockExtractorPassPass(PassRegistry&); +void initializeBlockPlacementPass(PassRegistry&); +void initializeBreakCriticalEdgesPass(PassRegistry&); +void initializeCFGOnlyPrinterPass(PassRegistry&); +void initializeCFGOnlyViewerPass(PassRegistry&); +void initializeCFGPrinterPass(PassRegistry&); +void initializeCFGSimplifyPassPass(PassRegistry&); +void initializeCFGViewerPass(PassRegistry&); +void initializeCalculateSpillWeightsPass(PassRegistry&); +void initializeCallGraphAnalysisGroup(PassRegistry&); +void initializeCodeGenPreparePass(PassRegistry&); +void initializeConstantMergePass(PassRegistry&); +void initializeConstantPropagationPass(PassRegistry&); +void initializeCorrelatedValuePropagationPass(PassRegistry&); +void initializeDAEPass(PassRegistry&); +void initializeDAHPass(PassRegistry&); +void initializeDCEPass(PassRegistry&); +void initializeDSEPass(PassRegistry&); +void initializeDTEPass(PassRegistry&); +void initializeDeadInstEliminationPass(PassRegistry&); +void initializeDeadMachineInstructionElimPass(PassRegistry&); +void initializeDomOnlyPrinterPass(PassRegistry&); +void initializeDomOnlyViewerPass(PassRegistry&); +void initializeDomPrinterPass(PassRegistry&); +void initializeDomViewerPass(PassRegistry&); +void initializeDominanceFrontierPass(PassRegistry&); +void initializeDominatorTreePass(PassRegistry&); +void initializeEdgeBundlesPass(PassRegistry&); +void initializeEdgeProfilerPass(PassRegistry&); +void initializePathProfilerPass(PassRegistry&); +void initializeEarlyCSEPass(PassRegistry&); +void initializeExpandISelPseudosPass(PassRegistry&); +void initializeFindUsedTypesPass(PassRegistry&); +void initializeFunctionAttrsPass(PassRegistry&); +void initializeGCModuleInfoPass(PassRegistry&); +void initializeGEPSplitterPass(PassRegistry&); +void initializeGVNPass(PassRegistry&); +void initializeGlobalDCEPass(PassRegistry&); +void initializeGlobalOptPass(PassRegistry&); +void initializeGlobalsModRefPass(PassRegistry&); +void initializeIPCPPass(PassRegistry&); +void initializeIPSCCPPass(PassRegistry&); +void initializeIVUsersPass(PassRegistry&); +void initializeIfConverterPass(PassRegistry&); +void initializeIndVarSimplifyPass(PassRegistry&); +void initializeInstCombinerPass(PassRegistry&); +void initializeInstCountPass(PassRegistry&); +void initializeInstNamerPass(PassRegistry&); +void initializeInternalizePassPass(PassRegistry&); +void initializeIntervalPartitionPass(PassRegistry&); +void initializeJumpThreadingPass(PassRegistry&); +void initializeLCSSAPass(PassRegistry&); +void initializeLICMPass(PassRegistry&); +void initializeLazyValueInfoPass(PassRegistry&); +void initializeLibCallAliasAnalysisPass(PassRegistry&); +void initializeLintPass(PassRegistry&); +void initializeLiveDebugVariablesPass(PassRegistry&); +void initializeLiveIntervalsPass(PassRegistry&); +void initializeLiveStacksPass(PassRegistry&); +void initializeLiveValuesPass(PassRegistry&); +void initializeLiveVariablesPass(PassRegistry&); +void initializeLoaderPassPass(PassRegistry&); +void initializePathProfileLoaderPassPass(PassRegistry&); +void initializeLoopDeletionPass(PassRegistry&); +void initializeLoopDependenceAnalysisPass(PassRegistry&); +void initializeLoopExtractorPass(PassRegistry&); +void initializeLoopInfoPass(PassRegistry&); +void initializeLoopInstSimplifyPass(PassRegistry&); +void initializeLoopRotatePass(PassRegistry&); +void initializeLoopSimplifyPass(PassRegistry&); +void initializeLoopSplitterPass(PassRegistry&); +void initializeLoopStrengthReducePass(PassRegistry&); +void initializeLoopUnrollPass(PassRegistry&); +void initializeLoopUnswitchPass(PassRegistry&); +void initializeLoopIdiomRecognizePass(PassRegistry&); +void initializeLowerAtomicPass(PassRegistry&); +void initializeLowerIntrinsicsPass(PassRegistry&); +void initializeLowerInvokePass(PassRegistry&); +void initializeLowerSetJmpPass(PassRegistry&); +void initializeLowerSwitchPass(PassRegistry&); +void initializeMachineCSEPass(PassRegistry&); +void initializeMachineDominatorTreePass(PassRegistry&); +void initializeMachineLICMPass(PassRegistry&); +void initializeMachineLoopInfoPass(PassRegistry&); +void initializeMachineLoopRangesPass(PassRegistry&); +void initializeMachineModuleInfoPass(PassRegistry&); +void initializeMachineSinkingPass(PassRegistry&); +void initializeMachineVerifierPassPass(PassRegistry&); +void initializeMemCpyOptPass(PassRegistry&); +void initializeMemDepPrinterPass(PassRegistry&); +void initializeMemoryDependenceAnalysisPass(PassRegistry&); +void initializeMergeFunctionsPass(PassRegistry&); +void initializeModuleDebugInfoPrinterPass(PassRegistry&); +void initializeNoAAPass(PassRegistry&); +void initializeNoProfileInfoPass(PassRegistry&); +void initializeNoPathProfileInfoPass(PassRegistry&); +void initializeOptimalEdgeProfilerPass(PassRegistry&); +void initializeOptimizePHIsPass(PassRegistry&); +void initializePEIPass(PassRegistry&); +void initializePHIEliminationPass(PassRegistry&); +void initializePartialInlinerPass(PassRegistry&); +void initializePeepholeOptimizerPass(PassRegistry&); +void initializePostDomOnlyPrinterPass(PassRegistry&); +void initializePostDomOnlyViewerPass(PassRegistry&); +void initializePostDomPrinterPass(PassRegistry&); +void initializePostDomViewerPass(PassRegistry&); +void initializePostDominanceFrontierPass(PassRegistry&); +void initializePostDominatorTreePass(PassRegistry&); +void initializePreAllocSplittingPass(PassRegistry&); +void initializePreVerifierPass(PassRegistry&); +void initializePrintDbgInfoPass(PassRegistry&); +void initializePrintFunctionPassPass(PassRegistry&); +void initializePrintModulePassPass(PassRegistry&); +void initializeProcessImplicitDefsPass(PassRegistry&); +void initializeProfileEstimatorPassPass(PassRegistry&); +void initializeProfileInfoAnalysisGroup(PassRegistry&); +void initializePathProfileInfoAnalysisGroup(PassRegistry&); +void initializePathProfileVerifierPass(PassRegistry&); +void initializeProfileVerifierPassPass(PassRegistry&); +void initializePromotePassPass(PassRegistry&); +void initializePruneEHPass(PassRegistry&); +void initializeRALinScanPass(PassRegistry&); +void initializeReassociatePass(PassRegistry&); +void initializeRegToMemPass(PassRegistry&); +void initializeRegionInfoPass(PassRegistry&); +void initializeRegionOnlyPrinterPass(PassRegistry&); +void initializeRegionOnlyViewerPass(PassRegistry&); +void initializeRegionPrinterPass(PassRegistry&); +void initializeRegionViewerPass(PassRegistry&); +void initializeRegisterCoalescerAnalysisGroup(PassRegistry&); +void initializeRenderMachineFunctionPass(PassRegistry&); +void initializeSCCPPass(PassRegistry&); +void initializeSRETPromotionPass(PassRegistry&); +void initializeSROA_DTPass(PassRegistry&); +void initializeSROA_SSAUpPass(PassRegistry&); +void initializeScalarEvolutionAliasAnalysisPass(PassRegistry&); +void initializeScalarEvolutionPass(PassRegistry&); +void initializeSimpleInlinerPass(PassRegistry&); +void initializeSimpleRegisterCoalescingPass(PassRegistry&); +void initializeSimplifyHalfPowrLibCallsPass(PassRegistry&); +void initializeSimplifyLibCallsPass(PassRegistry&); +void initializeSingleLoopExtractorPass(PassRegistry&); +void initializeSinkingPass(PassRegistry&); +void initializeSlotIndexesPass(PassRegistry&); +void initializeSpillPlacementPass(PassRegistry&); +void initializeStackProtectorPass(PassRegistry&); +void initializeStackSlotColoringPass(PassRegistry&); +void initializeStripDeadDebugInfoPass(PassRegistry&); +void initializeStripDeadPrototypesPassPass(PassRegistry&); +void initializeStripDebugDeclarePass(PassRegistry&); +void initializeStripNonDebugSymbolsPass(PassRegistry&); +void initializeStripSymbolsPass(PassRegistry&); +void initializeStrongPHIEliminationPass(PassRegistry&); +void initializeTailCallElimPass(PassRegistry&); +void initializeTailDupPass(PassRegistry&); +void initializeTargetDataPass(PassRegistry&); +void initializeTargetLibraryInfoPass(PassRegistry&); +void initializeTwoAddressInstructionPassPass(PassRegistry&); +void initializeTypeBasedAliasAnalysisPass(PassRegistry&); +void initializeUnifyFunctionExitNodesPass(PassRegistry&); +void initializeUnreachableBlockElimPass(PassRegistry&); +void initializeUnreachableMachineBlockElimPass(PassRegistry&); +void initializeVerifierPass(PassRegistry&); +void initializeVirtRegMapPass(PassRegistry&); +void initializeInstSimplifierPass(PassRegistry&); + +} + +#endif diff --git a/include/llvm/InlineAsm.h b/include/llvm/InlineAsm.h index 105b1bcd94c5..ed8f0f7f615e 100644 --- a/include/llvm/InlineAsm.h +++ b/include/llvm/InlineAsm.h @@ -87,6 +87,25 @@ public: isClobber // '~x' }; + typedef std::vector ConstraintCodeVector; + + struct SubConstraintInfo { + /// MatchingInput - If this is not -1, this is an output constraint where an + /// input constraint is required to match it (e.g. "0"). The value is the + /// constraint number that matches this one (for example, if this is + /// constraint #0 and constraint #4 has the value "0", this will be 4). + signed char MatchingInput; + /// Code - The constraint code, either the register name (in braces) or the + /// constraint letter/number. + ConstraintCodeVector Codes; + /// Default constructor. + SubConstraintInfo() : MatchingInput(-1) {} + }; + + typedef std::vector SubConstraintInfoVector; + struct ConstraintInfo; + typedef std::vector ConstraintInfoVector; + struct ConstraintInfo { /// Type - The basic type of the constraint: input/output/clobber /// @@ -118,25 +137,42 @@ public: /// Code - The constraint code, either the register name (in braces) or the /// constraint letter/number. - std::vector Codes; + ConstraintCodeVector Codes; + + /// isMultipleAlternative - '|': has multiple-alternative constraints. + bool isMultipleAlternative; + + /// multipleAlternatives - If there are multiple alternative constraints, + /// this array will contain them. Otherwise it will be empty. + SubConstraintInfoVector multipleAlternatives; + + /// The currently selected alternative constraint index. + unsigned currentAlternativeIndex; + + ///Default constructor. + ConstraintInfo(); + + /// Copy constructor. + ConstraintInfo(const ConstraintInfo &other); /// Parse - Analyze the specified string (e.g. "=*&{eax}") and fill in the /// fields in this structure. If the constraint string is not understood, /// return true, otherwise return false. - bool Parse(StringRef Str, - std::vector &ConstraintsSoFar); + bool Parse(StringRef Str, ConstraintInfoVector &ConstraintsSoFar); + + /// selectAlternative - Point this constraint to the alternative constraint + /// indicated by the index. + void selectAlternative(unsigned index); }; /// ParseConstraints - Split up the constraint string into the specific /// constraints and their prefixes. If this returns an empty vector, and if /// the constraint string itself isn't empty, there was an error parsing. - static std::vector - ParseConstraints(StringRef ConstraintString); + static ConstraintInfoVector ParseConstraints(StringRef ConstraintString); /// ParseConstraints - Parse the constraints of this inlineasm object, /// returning them the same way that ParseConstraints(str) does. - std::vector - ParseConstraints() const { + ConstraintInfoVector ParseConstraints() const { return ParseConstraints(Constraints); } @@ -154,8 +190,15 @@ public: Op_InputChain = 0, Op_AsmString = 1, Op_MDNode = 2, - Op_IsAlignStack = 3, + Op_ExtraInfo = 3, // HasSideEffects, IsAlignStack Op_FirstOperand = 4, + + MIOp_AsmString = 0, + MIOp_ExtraInfo = 1, // HasSideEffects, IsAlignStack + MIOp_FirstOperand = 2, + + Extra_HasSideEffects = 1, + Extra_IsAlignStack = 2, Kind_RegUse = 1, Kind_RegDef = 2, diff --git a/include/llvm/InstrTypes.h b/include/llvm/InstrTypes.h index 6715416afa1c..a166956e1a64 100644 --- a/include/llvm/InstrTypes.h +++ b/include/llvm/InstrTypes.h @@ -128,7 +128,8 @@ public: }; template <> -struct OperandTraits : public FixedNumOperandTraits<1> { +struct OperandTraits : + public FixedNumOperandTraits { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(UnaryInstruction, Value) @@ -193,154 +194,93 @@ public: } #include "llvm/Instruction.def" - - /// CreateNSWAdd - Create an Add operator with the NSW flag set. - /// - static BinaryOperator *CreateNSWAdd(Value *V1, Value *V2, - const Twine &Name = "") { - BinaryOperator *BO = CreateAdd(V1, V2, Name); + static BinaryOperator *CreateNSW(BinaryOps Opc, Value *V1, Value *V2, + const Twine &Name = "") { + BinaryOperator *BO = Create(Opc, V1, V2, Name); BO->setHasNoSignedWrap(true); return BO; } - static BinaryOperator *CreateNSWAdd(Value *V1, Value *V2, - const Twine &Name, BasicBlock *BB) { - BinaryOperator *BO = CreateAdd(V1, V2, Name, BB); + static BinaryOperator *CreateNSW(BinaryOps Opc, Value *V1, Value *V2, + const Twine &Name, BasicBlock *BB) { + BinaryOperator *BO = Create(Opc, V1, V2, Name, BB); BO->setHasNoSignedWrap(true); return BO; } - static BinaryOperator *CreateNSWAdd(Value *V1, Value *V2, - const Twine &Name, Instruction *I) { - BinaryOperator *BO = CreateAdd(V1, V2, Name, I); + static BinaryOperator *CreateNSW(BinaryOps Opc, Value *V1, Value *V2, + const Twine &Name, Instruction *I) { + BinaryOperator *BO = Create(Opc, V1, V2, Name, I); BO->setHasNoSignedWrap(true); return BO; } - - /// CreateNUWAdd - Create an Add operator with the NUW flag set. - /// - static BinaryOperator *CreateNUWAdd(Value *V1, Value *V2, - const Twine &Name = "") { - BinaryOperator *BO = CreateAdd(V1, V2, Name); - BO->setHasNoUnsignedWrap(true); - return BO; - } - static BinaryOperator *CreateNUWAdd(Value *V1, Value *V2, - const Twine &Name, BasicBlock *BB) { - BinaryOperator *BO = CreateAdd(V1, V2, Name, BB); - BO->setHasNoUnsignedWrap(true); - return BO; - } - static BinaryOperator *CreateNUWAdd(Value *V1, Value *V2, - const Twine &Name, Instruction *I) { - BinaryOperator *BO = CreateAdd(V1, V2, Name, I); - BO->setHasNoUnsignedWrap(true); - return BO; - } - - /// CreateNSWSub - Create an Sub operator with the NSW flag set. - /// - static BinaryOperator *CreateNSWSub(Value *V1, Value *V2, - const Twine &Name = "") { - BinaryOperator *BO = CreateSub(V1, V2, Name); - BO->setHasNoSignedWrap(true); - return BO; - } - static BinaryOperator *CreateNSWSub(Value *V1, Value *V2, - const Twine &Name, BasicBlock *BB) { - BinaryOperator *BO = CreateSub(V1, V2, Name, BB); - BO->setHasNoSignedWrap(true); - return BO; - } - static BinaryOperator *CreateNSWSub(Value *V1, Value *V2, - const Twine &Name, Instruction *I) { - BinaryOperator *BO = CreateSub(V1, V2, Name, I); - BO->setHasNoSignedWrap(true); - return BO; - } - - /// CreateNUWSub - Create an Sub operator with the NUW flag set. - /// - static BinaryOperator *CreateNUWSub(Value *V1, Value *V2, - const Twine &Name = "") { - BinaryOperator *BO = CreateSub(V1, V2, Name); - BO->setHasNoUnsignedWrap(true); - return BO; - } - static BinaryOperator *CreateNUWSub(Value *V1, Value *V2, - const Twine &Name, BasicBlock *BB) { - BinaryOperator *BO = CreateSub(V1, V2, Name, BB); - BO->setHasNoUnsignedWrap(true); - return BO; - } - static BinaryOperator *CreateNUWSub(Value *V1, Value *V2, - const Twine &Name, Instruction *I) { - BinaryOperator *BO = CreateSub(V1, V2, Name, I); - BO->setHasNoUnsignedWrap(true); - return BO; - } - - /// CreateNSWMul - Create a Mul operator with the NSW flag set. - /// - static BinaryOperator *CreateNSWMul(Value *V1, Value *V2, - const Twine &Name = "") { - BinaryOperator *BO = CreateMul(V1, V2, Name); - BO->setHasNoSignedWrap(true); - return BO; - } - static BinaryOperator *CreateNSWMul(Value *V1, Value *V2, - const Twine &Name, BasicBlock *BB) { - BinaryOperator *BO = CreateMul(V1, V2, Name, BB); - BO->setHasNoSignedWrap(true); - return BO; - } - static BinaryOperator *CreateNSWMul(Value *V1, Value *V2, - const Twine &Name, Instruction *I) { - BinaryOperator *BO = CreateMul(V1, V2, Name, I); - BO->setHasNoSignedWrap(true); - return BO; - } - - /// CreateNUWMul - Create a Mul operator with the NUW flag set. - /// - static BinaryOperator *CreateNUWMul(Value *V1, Value *V2, - const Twine &Name = "") { - BinaryOperator *BO = CreateMul(V1, V2, Name); + + static BinaryOperator *CreateNUW(BinaryOps Opc, Value *V1, Value *V2, + const Twine &Name = "") { + BinaryOperator *BO = Create(Opc, V1, V2, Name); BO->setHasNoUnsignedWrap(true); return BO; } - static BinaryOperator *CreateNUWMul(Value *V1, Value *V2, - const Twine &Name, BasicBlock *BB) { - BinaryOperator *BO = CreateMul(V1, V2, Name, BB); + static BinaryOperator *CreateNUW(BinaryOps Opc, Value *V1, Value *V2, + const Twine &Name, BasicBlock *BB) { + BinaryOperator *BO = Create(Opc, V1, V2, Name, BB); BO->setHasNoUnsignedWrap(true); return BO; } - static BinaryOperator *CreateNUWMul(Value *V1, Value *V2, - const Twine &Name, Instruction *I) { - BinaryOperator *BO = CreateMul(V1, V2, Name, I); + static BinaryOperator *CreateNUW(BinaryOps Opc, Value *V1, Value *V2, + const Twine &Name, Instruction *I) { + BinaryOperator *BO = Create(Opc, V1, V2, Name, I); BO->setHasNoUnsignedWrap(true); return BO; } - - /// CreateExactSDiv - Create an SDiv operator with the exact flag set. - /// - static BinaryOperator *CreateExactSDiv(Value *V1, Value *V2, - const Twine &Name = "") { - BinaryOperator *BO = CreateSDiv(V1, V2, Name); + + static BinaryOperator *CreateExact(BinaryOps Opc, Value *V1, Value *V2, + const Twine &Name = "") { + BinaryOperator *BO = Create(Opc, V1, V2, Name); BO->setIsExact(true); return BO; } - static BinaryOperator *CreateExactSDiv(Value *V1, Value *V2, - const Twine &Name, BasicBlock *BB) { - BinaryOperator *BO = CreateSDiv(V1, V2, Name, BB); + static BinaryOperator *CreateExact(BinaryOps Opc, Value *V1, Value *V2, + const Twine &Name, BasicBlock *BB) { + BinaryOperator *BO = Create(Opc, V1, V2, Name, BB); BO->setIsExact(true); return BO; } - static BinaryOperator *CreateExactSDiv(Value *V1, Value *V2, - const Twine &Name, Instruction *I) { - BinaryOperator *BO = CreateSDiv(V1, V2, Name, I); + static BinaryOperator *CreateExact(BinaryOps Opc, Value *V1, Value *V2, + const Twine &Name, Instruction *I) { + BinaryOperator *BO = Create(Opc, V1, V2, Name, I); BO->setIsExact(true); return BO; } - + +#define DEFINE_HELPERS(OPC, NUWNSWEXACT) \ + static BinaryOperator *Create ## NUWNSWEXACT ## OPC \ + (Value *V1, Value *V2, const Twine &Name = "") { \ + return Create ## NUWNSWEXACT(Instruction::OPC, V1, V2, Name); \ + } \ + static BinaryOperator *Create ## NUWNSWEXACT ## OPC \ + (Value *V1, Value *V2, const Twine &Name, BasicBlock *BB) { \ + return Create ## NUWNSWEXACT(Instruction::OPC, V1, V2, Name, BB); \ + } \ + static BinaryOperator *Create ## NUWNSWEXACT ## OPC \ + (Value *V1, Value *V2, const Twine &Name, Instruction *I) { \ + return Create ## NUWNSWEXACT(Instruction::OPC, V1, V2, Name, I); \ + } + + DEFINE_HELPERS(Add, NSW) // CreateNSWAdd + DEFINE_HELPERS(Add, NUW) // CreateNUWAdd + DEFINE_HELPERS(Sub, NSW) // CreateNSWSub + DEFINE_HELPERS(Sub, NUW) // CreateNUWSub + DEFINE_HELPERS(Mul, NSW) // CreateNSWMul + DEFINE_HELPERS(Mul, NUW) // CreateNUWMul + DEFINE_HELPERS(Shl, NSW) // CreateNSWShl + DEFINE_HELPERS(Shl, NUW) // CreateNUWShl + + DEFINE_HELPERS(SDiv, Exact) // CreateExactSDiv + DEFINE_HELPERS(UDiv, Exact) // CreateExactUDiv + DEFINE_HELPERS(AShr, Exact) // CreateExactAShr + DEFINE_HELPERS(LShr, Exact) // CreateExactLShr + +#undef DEFINE_HELPERS + /// Helper functions to construct and inspect unary operations (NEG and NOT) /// via binary operators SUB and XOR: /// @@ -432,7 +372,8 @@ public: }; template <> -struct OperandTraits : public FixedNumOperandTraits<2> { +struct OperandTraits : + public FixedNumOperandTraits { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(BinaryOperator, Value) @@ -824,11 +765,11 @@ public: /// This is just a convenience that dispatches to the subclasses. /// @brief Determine if this CmpInst is commutative. - bool isCommutative(); + bool isCommutative() const; /// This is just a convenience that dispatches to the subclasses. /// @brief Determine if this is an equals/not equals predicate. - bool isEquality(); + bool isEquality() const; /// @returns true if the comparison is signed, false otherwise. /// @brief Determine if this instruction is using a signed comparison. @@ -903,7 +844,7 @@ private: // FIXME: these are redundant if CmpInst < BinaryOperator template <> -struct OperandTraits : public FixedNumOperandTraits<2> { +struct OperandTraits : public FixedNumOperandTraits { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CmpInst, Value) diff --git a/include/llvm/Instruction.h b/include/llvm/Instruction.h index 88f5ce1b2622..89bb9fdf423d 100644 --- a/include/llvm/Instruction.h +++ b/include/llvm/Instruction.h @@ -200,11 +200,10 @@ public: /// /// Associative operators satisfy: x op (y op z) === (x op y) op z /// - /// In LLVM, the Add, Mul, And, Or, and Xor operators are associative, when - /// not applied to floating point types. + /// In LLVM, the Add, Mul, And, Or, and Xor operators are associative. /// - bool isAssociative() const { return isAssociative(getOpcode(), getType()); } - static bool isAssociative(unsigned op, const Type *Ty); + bool isAssociative() const { return isAssociative(getOpcode()); } + static bool isAssociative(unsigned op); /// isCommutative - Return true if the instruction is commutative: /// diff --git a/include/llvm/Instructions.h b/include/llvm/Instructions.h index bd1e889de076..17ff763c52bf 100644 --- a/include/llvm/Instructions.h +++ b/include/llvm/Instructions.h @@ -29,7 +29,6 @@ class ConstantInt; class ConstantRange; class APInt; class LLVMContext; -class DominatorTree; //===----------------------------------------------------------------------===// // AllocaInst Class @@ -43,7 +42,7 @@ protected: public: explicit AllocaInst(const Type *Ty, Value *ArraySize = 0, const Twine &Name = "", Instruction *InsertBefore = 0); - AllocaInst(const Type *Ty, Value *ArraySize, + AllocaInst(const Type *Ty, Value *ArraySize, const Twine &Name, BasicBlock *InsertAtEnd); AllocaInst(const Type *Ty, const Twine &Name, Instruction *InsertBefore = 0); @@ -166,8 +165,8 @@ public: unsigned getPointerAddressSpace() const { return cast(getPointerOperand()->getType())->getAddressSpace(); } - - + + // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const LoadInst *) { return true; } static inline bool classof(const Instruction *I) { @@ -237,7 +236,7 @@ public: Value *getValueOperand() { return getOperand(0); } const Value *getValueOperand() const { return getOperand(0); } - + Value *getPointerOperand() { return getOperand(1); } const Value *getPointerOperand() const { return getOperand(1); } static unsigned getPointerOperandIndex() { return 1U; } @@ -245,7 +244,7 @@ public: unsigned getPointerAddressSpace() const { return cast(getPointerOperand()->getType())->getAddressSpace(); } - + // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const StoreInst *) { return true; } static inline bool classof(const Instruction *I) { @@ -263,7 +262,7 @@ private: }; template <> -struct OperandTraits : public FixedNumOperandTraits<2> { +struct OperandTraits : public FixedNumOperandTraits { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(StoreInst, Value) @@ -289,8 +288,10 @@ class GetElementPtrInst : public Instruction { const Twine &NameStr); void init(Value *Ptr, Value *Idx, const Twine &NameStr); - template - void init(Value *Ptr, InputIterator IdxBegin, InputIterator IdxEnd, + template + void init(Value *Ptr, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, const Twine &NameStr, // This argument ensures that we have an iterator we can // do arithmetic on in constant time @@ -313,10 +314,10 @@ class GetElementPtrInst : public Instruction { /// Null is returned if the indices are invalid for the specified /// pointer type. /// - template + template static const Type *getIndexedType(const Type *Ptr, - InputIterator IdxBegin, - InputIterator IdxEnd, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, // This argument ensures that we // have an iterator we can do // arithmetic on in constant time @@ -331,18 +332,19 @@ class GetElementPtrInst : public Instruction { } /// Constructors - Create a getelementptr instruction with a base pointer an - /// list of indices. The first ctor can optionally insert before an existing + /// list of indices. The first ctor can optionally insert before an existing /// instruction, the second appends the new instruction to the specified /// BasicBlock. - template - inline GetElementPtrInst(Value *Ptr, InputIterator IdxBegin, - InputIterator IdxEnd, + template + inline GetElementPtrInst(Value *Ptr, RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, unsigned Values, const Twine &NameStr, Instruction *InsertBefore); - template + template inline GetElementPtrInst(Value *Ptr, - InputIterator IdxBegin, InputIterator IdxEnd, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, unsigned Values, const Twine &NameStr, BasicBlock *InsertAtEnd); @@ -355,23 +357,24 @@ class GetElementPtrInst : public Instruction { protected: virtual GetElementPtrInst *clone_impl() const; public: - template - static GetElementPtrInst *Create(Value *Ptr, InputIterator IdxBegin, - InputIterator IdxEnd, + template + static GetElementPtrInst *Create(Value *Ptr, RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, const Twine &NameStr = "", Instruction *InsertBefore = 0) { - typename std::iterator_traits::difference_type Values = - 1 + std::distance(IdxBegin, IdxEnd); + typename std::iterator_traits::difference_type + Values = 1 + std::distance(IdxBegin, IdxEnd); return new(Values) GetElementPtrInst(Ptr, IdxBegin, IdxEnd, Values, NameStr, InsertBefore); } - template + template static GetElementPtrInst *Create(Value *Ptr, - InputIterator IdxBegin, InputIterator IdxEnd, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, const Twine &NameStr, BasicBlock *InsertAtEnd) { - typename std::iterator_traits::difference_type Values = - 1 + std::distance(IdxBegin, IdxEnd); + typename std::iterator_traits::difference_type + Values = 1 + std::distance(IdxBegin, IdxEnd); return new(Values) GetElementPtrInst(Ptr, IdxBegin, IdxEnd, Values, NameStr, InsertAtEnd); } @@ -391,9 +394,10 @@ public: /// Create an "inbounds" getelementptr. See the documentation for the /// "inbounds" flag in LangRef.html for details. - template - static GetElementPtrInst *CreateInBounds(Value *Ptr, InputIterator IdxBegin, - InputIterator IdxEnd, + template + static GetElementPtrInst *CreateInBounds(Value *Ptr, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, const Twine &NameStr = "", Instruction *InsertBefore = 0) { GetElementPtrInst *GEP = Create(Ptr, IdxBegin, IdxEnd, @@ -401,10 +405,10 @@ public: GEP->setIsInBounds(true); return GEP; } - template + template static GetElementPtrInst *CreateInBounds(Value *Ptr, - InputIterator IdxBegin, - InputIterator IdxEnd, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, const Twine &NameStr, BasicBlock *InsertAtEnd) { GetElementPtrInst *GEP = Create(Ptr, IdxBegin, IdxEnd, @@ -441,18 +445,21 @@ public: /// Null is returned if the indices are invalid for the specified /// pointer type. /// - template + template static const Type *getIndexedType(const Type *Ptr, - InputIterator IdxBegin, - InputIterator IdxEnd) { + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd) { return getIndexedType(Ptr, IdxBegin, IdxEnd, - typename std::iterator_traits:: + typename std::iterator_traits:: iterator_category()); } static const Type *getIndexedType(const Type *Ptr, Value* const *Idx, unsigned NumIdx); + static const Type *getIndexedType(const Type *Ptr, + Constant* const *Idx, unsigned NumIdx); + static const Type *getIndexedType(const Type *Ptr, uint64_t const *Idx, unsigned NumIdx); @@ -472,7 +479,7 @@ public: static unsigned getPointerOperandIndex() { return 0U; // get index for modifying correct operand } - + unsigned getPointerAddressSpace() const { return cast(getType())->getAddressSpace(); } @@ -520,13 +527,14 @@ public: }; template <> -struct OperandTraits : public VariadicOperandTraits<1> { +struct OperandTraits : + public VariadicOperandTraits { }; -template +template GetElementPtrInst::GetElementPtrInst(Value *Ptr, - InputIterator IdxBegin, - InputIterator IdxEnd, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, unsigned Values, const Twine &NameStr, Instruction *InsertBefore) @@ -539,12 +547,13 @@ GetElementPtrInst::GetElementPtrInst(Value *Ptr, OperandTraits::op_end(this) - Values, Values, InsertBefore) { init(Ptr, IdxBegin, IdxEnd, NameStr, - typename std::iterator_traits::iterator_category()); + typename std::iterator_traits + ::iterator_category()); } -template +template GetElementPtrInst::GetElementPtrInst(Value *Ptr, - InputIterator IdxBegin, - InputIterator IdxEnd, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, unsigned Values, const Twine &NameStr, BasicBlock *InsertAtEnd) @@ -557,7 +566,8 @@ GetElementPtrInst::GetElementPtrInst(Value *Ptr, OperandTraits::op_end(this) - Values, Values, InsertAtEnd) { init(Ptr, IdxBegin, IdxEnd, NameStr, - typename std::iterator_traits::iterator_category()); + typename std::iterator_traits + ::iterator_category()); } @@ -575,7 +585,7 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GetElementPtrInst, Value) class ICmpInst: public CmpInst { protected: /// @brief Clone an indentical ICmpInst - virtual ICmpInst *clone_impl() const; + virtual ICmpInst *clone_impl() const; public: /// @brief Constructor with insert-before-instruction semantics. ICmpInst( @@ -746,7 +756,7 @@ public: assert(getOperand(0)->getType()->isFPOrFPVectorTy() && "Invalid operand types for FCmp instruction"); } - + /// @brief Constructor with insert-at-end semantics. FCmpInst( BasicBlock &InsertAtEnd, ///< Block to insert into. @@ -838,8 +848,10 @@ class CallInst : public Instruction { void init(Value *Func, Value *Actual); void init(Value *Func); - template - void init(Value *Func, InputIterator ArgBegin, InputIterator ArgEnd, + template + void init(Value *Func, + RandomAccessIterator ArgBegin, + RandomAccessIterator ArgEnd, const Twine &NameStr, // This argument ensures that we have an iterator we can // do arithmetic on in constant time @@ -851,24 +863,26 @@ class CallInst : public Instruction { setName(NameStr); } - /// Construct a CallInst given a range of arguments. InputIterator + /// Construct a CallInst given a range of arguments. RandomAccessIterator /// must be a random-access iterator pointing to contiguous storage - /// (e.g. a std::vector<>::iterator). Checks are made for + /// (e.g. a std::vector<>::iterator). Checks are made for /// random-accessness but not for contiguous storage as that would /// incur runtime overhead. /// @brief Construct a CallInst from a range of arguments - template - CallInst(Value *Func, InputIterator ArgBegin, InputIterator ArgEnd, + template + CallInst(Value *Func, + RandomAccessIterator ArgBegin, RandomAccessIterator ArgEnd, const Twine &NameStr, Instruction *InsertBefore); - /// Construct a CallInst given a range of arguments. InputIterator + /// Construct a CallInst given a range of arguments. RandomAccessIterator /// must be a random-access iterator pointing to contiguous storage /// (e.g. a std::vector<>::iterator). Checks are made for /// random-accessness but not for contiguous storage as that would /// incur runtime overhead. /// @brief Construct a CallInst from a range of arguments - template - inline CallInst(Value *Func, InputIterator ArgBegin, InputIterator ArgEnd, + template + inline CallInst(Value *Func, + RandomAccessIterator ArgBegin, RandomAccessIterator ArgEnd, const Twine &NameStr, BasicBlock *InsertAtEnd); CallInst(Value *F, Value *Actual, const Twine &NameStr, @@ -881,17 +895,19 @@ class CallInst : public Instruction { protected: virtual CallInst *clone_impl() const; public: - template + template static CallInst *Create(Value *Func, - InputIterator ArgBegin, InputIterator ArgEnd, + RandomAccessIterator ArgBegin, + RandomAccessIterator ArgEnd, const Twine &NameStr = "", Instruction *InsertBefore = 0) { return new(unsigned(ArgEnd - ArgBegin + 1)) CallInst(Func, ArgBegin, ArgEnd, NameStr, InsertBefore); } - template + template static CallInst *Create(Value *Func, - InputIterator ArgBegin, InputIterator ArgEnd, + RandomAccessIterator ArgBegin, + RandomAccessIterator ArgEnd, const Twine &NameStr, BasicBlock *InsertAtEnd) { return new(unsigned(ArgEnd - ArgBegin + 1)) CallInst(Func, ArgBegin, ArgEnd, NameStr, InsertAtEnd); @@ -984,7 +1000,7 @@ public: unsigned getParamAlignment(unsigned i) const { return AttributeList.getParamAlignment(i); } - + /// @brief Return true if the call should not be inlined. bool isNoInline() const { return paramHasAttr(~0, Attribute::NoInline); } void setIsNoInline(bool Value = true) { @@ -1052,7 +1068,7 @@ public: void setCalledFunction(Value* Fn) { Op<-1>() = Fn; } - + /// isInlineAsm - Check if this call is an inline asm statement. bool isInlineAsm() const { return isa(Op<-1>()); @@ -1075,11 +1091,12 @@ private: }; template <> -struct OperandTraits : public VariadicOperandTraits<1> { +struct OperandTraits : public VariadicOperandTraits { }; -template -CallInst::CallInst(Value *Func, InputIterator ArgBegin, InputIterator ArgEnd, +template +CallInst::CallInst(Value *Func, + RandomAccessIterator ArgBegin, RandomAccessIterator ArgEnd, const Twine &NameStr, BasicBlock *InsertAtEnd) : Instruction(cast(cast(Func->getType()) ->getElementType())->getReturnType(), @@ -1087,11 +1104,13 @@ CallInst::CallInst(Value *Func, InputIterator ArgBegin, InputIterator ArgEnd, OperandTraits::op_end(this) - (ArgEnd - ArgBegin + 1), unsigned(ArgEnd - ArgBegin + 1), InsertAtEnd) { init(Func, ArgBegin, ArgEnd, NameStr, - typename std::iterator_traits::iterator_category()); + typename std::iterator_traits + ::iterator_category()); } -template -CallInst::CallInst(Value *Func, InputIterator ArgBegin, InputIterator ArgEnd, +template +CallInst::CallInst(Value *Func, + RandomAccessIterator ArgBegin, RandomAccessIterator ArgEnd, const Twine &NameStr, Instruction *InsertBefore) : Instruction(cast(cast(Func->getType()) ->getElementType())->getReturnType(), @@ -1099,7 +1118,8 @@ CallInst::CallInst(Value *Func, InputIterator ArgBegin, InputIterator ArgEnd, OperandTraits::op_end(this) - (ArgEnd - ArgBegin + 1), unsigned(ArgEnd - ArgBegin + 1), InsertBefore) { init(Func, ArgBegin, ArgEnd, NameStr, - typename std::iterator_traits::iterator_category()); + typename std::iterator_traits + ::iterator_category()); } @@ -1156,7 +1176,7 @@ public: Value *getCondition() { return Op<0>(); } Value *getTrueValue() { return Op<1>(); } Value *getFalseValue() { return Op<2>(); } - + /// areInvalidOperands - Return a string if the specified operands are invalid /// for a select operation, otherwise return null. static const char *areInvalidOperands(Value *Cond, Value *True, Value *False); @@ -1179,7 +1199,7 @@ public: }; template <> -struct OperandTraits : public FixedNumOperandTraits<3> { +struct OperandTraits : public FixedNumOperandTraits { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(SelectInst, Value) @@ -1207,6 +1227,10 @@ public: setName(NameStr); } + Value *getPointerOperand() { return getOperand(0); } + const Value *getPointerOperand() const { return getOperand(0); } + static unsigned getPointerOperandIndex() { return 0U; } + // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const VAArgInst *) { return true; } static inline bool classof(const Instruction *I) { @@ -1252,12 +1276,12 @@ public: Value *getIndexOperand() { return Op<1>(); } const Value *getVectorOperand() const { return Op<0>(); } const Value *getIndexOperand() const { return Op<1>(); } - + const VectorType *getVectorOperandType() const { return reinterpret_cast(getVectorOperand()->getType()); } - - + + /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); @@ -1272,7 +1296,8 @@ public: }; template <> -struct OperandTraits : public FixedNumOperandTraits<2> { +struct OperandTraits : + public FixedNumOperandTraits { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ExtractElementInst, Value) @@ -1330,7 +1355,8 @@ public: }; template <> -struct OperandTraits : public FixedNumOperandTraits<3> { +struct OperandTraits : + public FixedNumOperandTraits { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(InsertElementInst, Value) @@ -1387,7 +1413,8 @@ public: }; template <> -struct OperandTraits : public FixedNumOperandTraits<3> { +struct OperandTraits : + public FixedNumOperandTraits { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ShuffleVectorInst, Value) @@ -1407,8 +1434,9 @@ class ExtractValueInst : public UnaryInstruction { const Twine &NameStr); void init(unsigned Idx, const Twine &NameStr); - template - void init(InputIterator IdxBegin, InputIterator IdxEnd, + template + void init(RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, const Twine &NameStr, // This argument ensures that we have an iterator we can // do arithmetic on in constant time @@ -1429,16 +1457,15 @@ class ExtractValueInst : public UnaryInstruction { /// getIndexedType - Returns the type of the element that would be extracted /// with an extractvalue instruction with the specified parameters. /// - /// Null is returned if the indices are invalid for the specified - /// pointer type. + /// Null is returned if the indices are invalid for the specified type. /// static const Type *getIndexedType(const Type *Agg, const unsigned *Idx, unsigned NumIdx); - template + template static const Type *getIndexedType(const Type *Ptr, - InputIterator IdxBegin, - InputIterator IdxEnd, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, // This argument ensures that we // have an iterator we can do // arithmetic on in constant time @@ -1456,14 +1483,16 @@ class ExtractValueInst : public UnaryInstruction { /// value and a list of indices. The first ctor can optionally insert before /// an existing instruction, the second appends the new instruction to the /// specified BasicBlock. - template - inline ExtractValueInst(Value *Agg, InputIterator IdxBegin, - InputIterator IdxEnd, + template + inline ExtractValueInst(Value *Agg, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, const Twine &NameStr, Instruction *InsertBefore); - template + template inline ExtractValueInst(Value *Agg, - InputIterator IdxBegin, InputIterator IdxEnd, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, const Twine &NameStr, BasicBlock *InsertAtEnd); // allocate space for exactly one operand @@ -1474,17 +1503,19 @@ protected: virtual ExtractValueInst *clone_impl() const; public: - template - static ExtractValueInst *Create(Value *Agg, InputIterator IdxBegin, - InputIterator IdxEnd, + template + static ExtractValueInst *Create(Value *Agg, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, const Twine &NameStr = "", Instruction *InsertBefore = 0) { return new ExtractValueInst(Agg, IdxBegin, IdxEnd, NameStr, InsertBefore); } - template + template static ExtractValueInst *Create(Value *Agg, - InputIterator IdxBegin, InputIterator IdxEnd, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, const Twine &NameStr, BasicBlock *InsertAtEnd) { return new ExtractValueInst(Agg, IdxBegin, IdxEnd, NameStr, InsertAtEnd); @@ -1509,15 +1540,14 @@ public: /// getIndexedType - Returns the type of the element that would be extracted /// with an extractvalue instruction with the specified parameters. /// - /// Null is returned if the indices are invalid for the specified - /// pointer type. + /// Null is returned if the indices are invalid for the specified type. /// - template + template static const Type *getIndexedType(const Type *Ptr, - InputIterator IdxBegin, - InputIterator IdxEnd) { + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd) { return getIndexedType(Ptr, IdxBegin, IdxEnd, - typename std::iterator_traits:: + typename std::iterator_traits:: iterator_category()); } static const Type *getIndexedType(const Type *Ptr, unsigned Idx); @@ -1554,29 +1584,31 @@ public: } }; -template +template ExtractValueInst::ExtractValueInst(Value *Agg, - InputIterator IdxBegin, - InputIterator IdxEnd, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, const Twine &NameStr, Instruction *InsertBefore) : UnaryInstruction(checkType(getIndexedType(Agg->getType(), IdxBegin, IdxEnd)), ExtractValue, Agg, InsertBefore) { init(IdxBegin, IdxEnd, NameStr, - typename std::iterator_traits::iterator_category()); + typename std::iterator_traits + ::iterator_category()); } -template +template ExtractValueInst::ExtractValueInst(Value *Agg, - InputIterator IdxBegin, - InputIterator IdxEnd, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, const Twine &NameStr, BasicBlock *InsertAtEnd) : UnaryInstruction(checkType(getIndexedType(Agg->getType(), IdxBegin, IdxEnd)), ExtractValue, Agg, InsertAtEnd) { init(IdxBegin, IdxEnd, NameStr, - typename std::iterator_traits::iterator_category()); + typename std::iterator_traits + ::iterator_category()); } @@ -1596,9 +1628,9 @@ class InsertValueInst : public Instruction { const Twine &NameStr); void init(Value *Agg, Value *Val, unsigned Idx, const Twine &NameStr); - template + template void init(Value *Agg, Value *Val, - InputIterator IdxBegin, InputIterator IdxEnd, + RandomAccessIterator IdxBegin, RandomAccessIterator IdxEnd, const Twine &NameStr, // This argument ensures that we have an iterator we can // do arithmetic on in constant time @@ -1620,14 +1652,16 @@ class InsertValueInst : public Instruction { /// value, a value to insert, and a list of indices. The first ctor can /// optionally insert before an existing instruction, the second appends /// the new instruction to the specified BasicBlock. - template - inline InsertValueInst(Value *Agg, Value *Val, InputIterator IdxBegin, - InputIterator IdxEnd, + template + inline InsertValueInst(Value *Agg, Value *Val, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, const Twine &NameStr, Instruction *InsertBefore); - template + template inline InsertValueInst(Value *Agg, Value *Val, - InputIterator IdxBegin, InputIterator IdxEnd, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, const Twine &NameStr, BasicBlock *InsertAtEnd); /// Constructors - These two constructors are convenience methods because one @@ -1645,17 +1679,19 @@ public: return User::operator new(s, 2); } - template - static InsertValueInst *Create(Value *Agg, Value *Val, InputIterator IdxBegin, - InputIterator IdxEnd, + template + static InsertValueInst *Create(Value *Agg, Value *Val, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, const Twine &NameStr = "", Instruction *InsertBefore = 0) { return new InsertValueInst(Agg, Val, IdxBegin, IdxEnd, NameStr, InsertBefore); } - template + template static InsertValueInst *Create(Value *Agg, Value *Val, - InputIterator IdxBegin, InputIterator IdxEnd, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, const Twine &NameStr, BasicBlock *InsertAtEnd) { return new InsertValueInst(Agg, Val, IdxBegin, IdxEnd, @@ -1722,34 +1758,37 @@ public: }; template <> -struct OperandTraits : public FixedNumOperandTraits<2> { +struct OperandTraits : + public FixedNumOperandTraits { }; -template +template InsertValueInst::InsertValueInst(Value *Agg, Value *Val, - InputIterator IdxBegin, - InputIterator IdxEnd, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, const Twine &NameStr, Instruction *InsertBefore) : Instruction(Agg->getType(), InsertValue, OperandTraits::op_begin(this), 2, InsertBefore) { init(Agg, Val, IdxBegin, IdxEnd, NameStr, - typename std::iterator_traits::iterator_category()); + typename std::iterator_traits + ::iterator_category()); } -template +template InsertValueInst::InsertValueInst(Value *Agg, Value *Val, - InputIterator IdxBegin, - InputIterator IdxEnd, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, const Twine &NameStr, BasicBlock *InsertAtEnd) : Instruction(Agg->getType(), InsertValue, OperandTraits::op_begin(this), 2, InsertAtEnd) { init(Agg, Val, IdxBegin, IdxEnd, NameStr, - typename std::iterator_traits::iterator_category()); + typename std::iterator_traits + ::iterator_category()); } DEFINE_TRANSPARENT_OPERAND_ACCESSORS(InsertValueInst, Value) @@ -1835,7 +1874,7 @@ public: BasicBlock *getIncomingBlock(unsigned i) const { return cast(getOperand(i*2+1)); } - + /// getIncomingBlock - Return incoming basic block corresponding /// to an operand of the PHI. /// @@ -1843,7 +1882,7 @@ public: assert(this == U.getUser() && "Iterator doesn't point to PHI's Uses?"); return cast((&U + 1)->get()); } - + /// getIncomingBlock - Return incoming basic block corresponding /// to value use iterator. /// @@ -1851,8 +1890,8 @@ public: BasicBlock *getIncomingBlock(value_use_iterator I) const { return getIncomingBlock(I.getUse()); } - - + + void setIncomingBlock(unsigned i, BasicBlock *BB) { setOperand(i*2+1, (Value*)BB); } @@ -1912,13 +1951,7 @@ public: /// hasConstantValue - If the specified PHI node always merges together the /// same value, return the value, otherwise return null. - /// - /// If the PHI has undef operands, but all the rest of the operands are - /// some unique value, return that value if it can be proved that the - /// value dominates the PHI. If DT is null, use a conservative check, - /// otherwise use DT to test for dominance. - /// - Value *hasConstantValue(DominatorTree *DT = 0) const; + Value *hasConstantValue() const; /// Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const PHINode *) { return true; } @@ -1985,11 +2018,9 @@ public: /// Provide fast operand accessors DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); - /// Convenience accessor - Value *getReturnValue(unsigned n = 0) const { - return n < getNumOperands() - ? getOperand(n) - : 0; + /// Convenience accessor. Returns null if there is no return value. + Value *getReturnValue() const { + return getNumOperands() != 0 ? getOperand(0) : 0; } unsigned getNumSuccessors() const { return 0; } @@ -2009,7 +2040,7 @@ public: }; template <> -struct OperandTraits : public VariadicOperandTraits<> { +struct OperandTraits : public VariadicOperandTraits { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ReturnInst, Value) @@ -2045,22 +2076,20 @@ protected: virtual BranchInst *clone_impl() const; public: static BranchInst *Create(BasicBlock *IfTrue, Instruction *InsertBefore = 0) { - return new(1, true) BranchInst(IfTrue, InsertBefore); + return new(1) BranchInst(IfTrue, InsertBefore); } static BranchInst *Create(BasicBlock *IfTrue, BasicBlock *IfFalse, Value *Cond, Instruction *InsertBefore = 0) { return new(3) BranchInst(IfTrue, IfFalse, Cond, InsertBefore); } static BranchInst *Create(BasicBlock *IfTrue, BasicBlock *InsertAtEnd) { - return new(1, true) BranchInst(IfTrue, InsertAtEnd); + return new(1) BranchInst(IfTrue, InsertAtEnd); } static BranchInst *Create(BasicBlock *IfTrue, BasicBlock *IfFalse, Value *Cond, BasicBlock *InsertAtEnd) { return new(3) BranchInst(IfTrue, IfFalse, Cond, InsertAtEnd); } - ~BranchInst(); - /// Transparently provide more efficient getOperand methods. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); @@ -2077,19 +2106,6 @@ public: Op<-3>() = V; } - // setUnconditionalDest - Change the current branch to an unconditional branch - // targeting the specified block. - // FIXME: Eliminate this ugly method. - void setUnconditionalDest(BasicBlock *Dest) { - Op<-1>() = (Value*)Dest; - if (isConditional()) { // Convert this to an uncond branch. - Op<-2>() = 0; - Op<-3>() = 0; - NumOperands = 1; - OperandList = op_begin(); - } - } - unsigned getNumSuccessors() const { return 1+isConditional(); } BasicBlock *getSuccessor(unsigned i) const { @@ -2117,7 +2133,8 @@ private: }; template <> -struct OperandTraits : public VariadicOperandTraits<1> {}; +struct OperandTraits : public VariadicOperandTraits { +}; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(BranchInst, Value) @@ -2136,7 +2153,7 @@ class SwitchInst : public TerminatorInst { // Operand[2n ] = Value to match // Operand[2n+1] = BasicBlock to go to on match SwitchInst(const SwitchInst &SI); - void init(Value *Value, BasicBlock *Default, unsigned NumCases); + void init(Value *Value, BasicBlock *Default, unsigned NumReserved); void resizeOperands(unsigned No); // allocate space for exactly zero operands void *operator new(size_t s) { @@ -2230,7 +2247,8 @@ public: /// removeCase - This method removes the specified successor from the switch /// instruction. Note that this cannot be used to remove the default - /// destination (successor #0). + /// destination (successor #0). Also note that this operation may reorder the + /// remaining cases at index idx and above. /// void removeCase(unsigned idx); @@ -2298,7 +2316,7 @@ class IndirectBrInst : public TerminatorInst { /// here to make memory allocation more efficient. This constructor can also /// autoinsert before another instruction. IndirectBrInst(Value *Address, unsigned NumDests, Instruction *InsertBefore); - + /// IndirectBrInst ctor - Create a new indirectbr instruction, specifying an /// Address to jump to. The number of expected destinations can be specified /// here to make memory allocation more efficient. This constructor also @@ -2316,32 +2334,32 @@ public: return new IndirectBrInst(Address, NumDests, InsertAtEnd); } ~IndirectBrInst(); - + /// Provide fast operand accessors. DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); - + // Accessor Methods for IndirectBrInst instruction. Value *getAddress() { return getOperand(0); } const Value *getAddress() const { return getOperand(0); } void setAddress(Value *V) { setOperand(0, V); } - - + + /// getNumDestinations - return the number of possible destinations in this /// indirectbr instruction. unsigned getNumDestinations() const { return getNumOperands()-1; } - + /// getDestination - Return the specified destination. BasicBlock *getDestination(unsigned i) { return getSuccessor(i); } const BasicBlock *getDestination(unsigned i) const { return getSuccessor(i); } - + /// addDestination - Add a destination. /// void addDestination(BasicBlock *Dest); - + /// removeDestination - This method removes the specified successor from the /// indirectbr instruction. void removeDestination(unsigned i); - + unsigned getNumSuccessors() const { return getNumOperands()-1; } BasicBlock *getSuccessor(unsigned i) const { return cast(getOperand(i+1)); @@ -2349,7 +2367,7 @@ public: void setSuccessor(unsigned i, BasicBlock *NewSucc) { setOperand(i+1, (Value*)NewSucc); } - + // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const IndirectBrInst *) { return true; } static inline bool classof(const Instruction *I) { @@ -2369,8 +2387,8 @@ struct OperandTraits : public HungoffOperandTraits<1> { }; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(IndirectBrInst, Value) - - + + //===----------------------------------------------------------------------===// // InvokeInst Class //===----------------------------------------------------------------------===// @@ -2384,9 +2402,9 @@ class InvokeInst : public TerminatorInst { void init(Value *Fn, BasicBlock *IfNormal, BasicBlock *IfException, Value* const *Args, unsigned NumArgs); - template + template void init(Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, - InputIterator ArgBegin, InputIterator ArgEnd, + RandomAccessIterator ArgBegin, RandomAccessIterator ArgEnd, const Twine &NameStr, // This argument ensures that we have an iterator we can // do arithmetic on in constant time @@ -2399,47 +2417,49 @@ class InvokeInst : public TerminatorInst { } /// Construct an InvokeInst given a range of arguments. - /// InputIterator must be a random-access iterator pointing to + /// RandomAccessIterator must be a random-access iterator pointing to /// contiguous storage (e.g. a std::vector<>::iterator). Checks are /// made for random-accessness but not for contiguous storage as /// that would incur runtime overhead. /// /// @brief Construct an InvokeInst from a range of arguments - template + template inline InvokeInst(Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, - InputIterator ArgBegin, InputIterator ArgEnd, + RandomAccessIterator ArgBegin, RandomAccessIterator ArgEnd, unsigned Values, const Twine &NameStr, Instruction *InsertBefore); /// Construct an InvokeInst given a range of arguments. - /// InputIterator must be a random-access iterator pointing to + /// RandomAccessIterator must be a random-access iterator pointing to /// contiguous storage (e.g. a std::vector<>::iterator). Checks are /// made for random-accessness but not for contiguous storage as /// that would incur runtime overhead. /// /// @brief Construct an InvokeInst from a range of arguments - template + template inline InvokeInst(Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, - InputIterator ArgBegin, InputIterator ArgEnd, + RandomAccessIterator ArgBegin, RandomAccessIterator ArgEnd, unsigned Values, const Twine &NameStr, BasicBlock *InsertAtEnd); protected: virtual InvokeInst *clone_impl() const; public: - template + template static InvokeInst *Create(Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, - InputIterator ArgBegin, InputIterator ArgEnd, + RandomAccessIterator ArgBegin, + RandomAccessIterator ArgEnd, const Twine &NameStr = "", Instruction *InsertBefore = 0) { unsigned Values(ArgEnd - ArgBegin + 3); return new(Values) InvokeInst(Func, IfNormal, IfException, ArgBegin, ArgEnd, Values, NameStr, InsertBefore); } - template + template static InvokeInst *Create(Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, - InputIterator ArgBegin, InputIterator ArgEnd, + RandomAccessIterator ArgBegin, + RandomAccessIterator ArgEnd, const Twine &NameStr, BasicBlock *InsertAtEnd) { unsigned Values(ArgEnd - ArgBegin + 3); @@ -2606,13 +2626,14 @@ private: }; template <> -struct OperandTraits : public VariadicOperandTraits<3> { +struct OperandTraits : public VariadicOperandTraits { }; -template +template InvokeInst::InvokeInst(Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, - InputIterator ArgBegin, InputIterator ArgEnd, + RandomAccessIterator ArgBegin, + RandomAccessIterator ArgEnd, unsigned Values, const Twine &NameStr, Instruction *InsertBefore) : TerminatorInst(cast(cast(Func->getType()) @@ -2621,12 +2642,14 @@ InvokeInst::InvokeInst(Value *Func, OperandTraits::op_end(this) - Values, Values, InsertBefore) { init(Func, IfNormal, IfException, ArgBegin, ArgEnd, NameStr, - typename std::iterator_traits::iterator_category()); + typename std::iterator_traits + ::iterator_category()); } -template +template InvokeInst::InvokeInst(Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, - InputIterator ArgBegin, InputIterator ArgEnd, + RandomAccessIterator ArgBegin, + RandomAccessIterator ArgEnd, unsigned Values, const Twine &NameStr, BasicBlock *InsertAtEnd) : TerminatorInst(cast(cast(Func->getType()) @@ -2635,7 +2658,8 @@ InvokeInst::InvokeInst(Value *Func, OperandTraits::op_end(this) - Values, Values, InsertAtEnd) { init(Func, IfNormal, IfException, ArgBegin, ArgEnd, NameStr, - typename std::iterator_traits::iterator_category()); + typename std::iterator_traits + ::iterator_category()); } DEFINE_TRANSPARENT_OPERAND_ACCESSORS(InvokeInst, Value) diff --git a/include/llvm/IntrinsicInst.h b/include/llvm/IntrinsicInst.h index a17fa9cc5bdd..74c30fbddd72 100644 --- a/include/llvm/IntrinsicInst.h +++ b/include/llvm/IntrinsicInst.h @@ -55,7 +55,7 @@ namespace llvm { return isa(V) && classof(cast(V)); } }; - + /// DbgInfoIntrinsic - This is the common base class for debug info intrinsics /// class DbgInfoIntrinsic : public IntrinsicInst { @@ -139,6 +139,10 @@ namespace llvm { return !getVolatileCst()->isZero(); } + unsigned getAddressSpace() const { + return cast(getRawDest()->getType())->getAddressSpace(); + } + /// getDest - This is just like getRawDest, but it strips off any cast /// instructions that feed it, giving the original input. The returned /// value is guaranteed to be a pointer. @@ -297,29 +301,6 @@ namespace llvm { } }; - /// MemoryUseIntrinsic - This is the common base class for the memory use - /// marker intrinsics. - /// - class MemoryUseIntrinsic : public IntrinsicInst { - public: - - // Methods for support type inquiry through isa, cast, and dyn_cast: - static inline bool classof(const MemoryUseIntrinsic *) { return true; } - static inline bool classof(const IntrinsicInst *I) { - switch (I->getIntrinsicID()) { - case Intrinsic::lifetime_start: - case Intrinsic::lifetime_end: - case Intrinsic::invariant_start: - case Intrinsic::invariant_end: - return true; - default: return false; - } - } - static inline bool classof(const Value *V) { - return isa(V) && classof(cast(V)); - } - }; - } #endif diff --git a/include/llvm/Intrinsics.td b/include/llvm/Intrinsics.td index fb4f750f87b5..0c9be78b0d10 100644 --- a/include/llvm/Intrinsics.td +++ b/include/llvm/Intrinsics.td @@ -109,6 +109,9 @@ def llvm_empty_ty : LLVMType; // { } def llvm_descriptor_ty : LLVMPointerType; // { }* def llvm_metadata_ty : LLVMType; // !{...} +def llvm_x86mmx_ty : LLVMType; +def llvm_ptrx86mmx_ty : LLVMPointerType; // <1 x i64>* + def llvm_v2i8_ty : LLVMType; // 2 x i8 def llvm_v4i8_ty : LLVMType; // 4 x i8 def llvm_v8i8_ty : LLVMType; // 8 x i8 @@ -256,7 +259,7 @@ def int_siglongjmp : Intrinsic<[], [llvm_ptr_ty, llvm_i32_ty]>; // Internal interface for object size checking def int_objectsize : Intrinsic<[llvm_anyint_ty], [llvm_ptr_ty, llvm_i1_ty], - [IntrReadArgMem]>, + [IntrNoMem]>, GCCBuiltin<"__builtin_object_size">; //===-------------------- Bit Manipulation Intrinsics ---------------------===// @@ -304,6 +307,7 @@ let Properties = [IntrNoMem] in { def int_eh_sjlj_lsda : Intrinsic<[llvm_ptr_ty]>; def int_eh_sjlj_callsite: Intrinsic<[], [llvm_i32_ty]>; } +def int_eh_sjlj_dispatch_setup : Intrinsic<[], [llvm_ptr_ty]>; def int_eh_sjlj_setjmp : Intrinsic<[llvm_i32_ty], [llvm_ptr_ty]>; def int_eh_sjlj_longjmp : Intrinsic<[], [llvm_ptr_ty]>; @@ -432,7 +436,7 @@ def int_lifetime_end : Intrinsic<[], [IntrReadWriteArgMem, NoCapture<1>]>; def int_invariant_start : Intrinsic<[llvm_descriptor_ty], [llvm_i64_ty, llvm_ptr_ty], - [IntrReadArgMem, NoCapture<1>]>; + [IntrReadWriteArgMem, NoCapture<1>]>; def int_invariant_end : Intrinsic<[], [llvm_descriptor_ty, llvm_i64_ty, llvm_ptr_ty], diff --git a/include/llvm/IntrinsicsARM.td b/include/llvm/IntrinsicsARM.td index 6c047718e6f6..546538a57abd 100644 --- a/include/llvm/IntrinsicsARM.td +++ b/include/llvm/IntrinsicsARM.td @@ -286,6 +286,12 @@ def int_arm_neon_vcvtfp2fxu : Neon_CvtFPToFx_Intrinsic; def int_arm_neon_vcvtfxs2fp : Neon_CvtFxToFP_Intrinsic; def int_arm_neon_vcvtfxu2fp : Neon_CvtFxToFP_Intrinsic; +// Vector Conversions Between Half-Precision and Single-Precision. +def int_arm_neon_vcvtfp2hf + : Intrinsic<[llvm_v4i16_ty], [llvm_v4f32_ty], [IntrNoMem]>; +def int_arm_neon_vcvthf2fp + : Intrinsic<[llvm_v4f32_ty], [llvm_v4i16_ty], [IntrNoMem]>; + // Narrowing Saturating Vector Moves. def int_arm_neon_vqmovns : Neon_1Arg_Narrow_Intrinsic; def int_arm_neon_vqmovnu : Neon_1Arg_Narrow_Intrinsic; diff --git a/include/llvm/IntrinsicsX86.td b/include/llvm/IntrinsicsX86.td index 06ea3ae3b518..49462200f093 100644 --- a/include/llvm/IntrinsicsX86.td +++ b/include/llvm/IntrinsicsX86.td @@ -130,12 +130,12 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, llvm_i64_ty], [IntrNoMem]>; def int_x86_sse_cvtps2pi : GCCBuiltin<"__builtin_ia32_cvtps2pi">, - Intrinsic<[llvm_v2i32_ty], [llvm_v4f32_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_v4f32_ty], [IntrNoMem]>; def int_x86_sse_cvttps2pi: GCCBuiltin<"__builtin_ia32_cvttps2pi">, - Intrinsic<[llvm_v2i32_ty], [llvm_v4f32_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_v4f32_ty], [IntrNoMem]>; def int_x86_sse_cvtpi2ps : GCCBuiltin<"__builtin_ia32_cvtpi2ps">, Intrinsic<[llvm_v4f32_ty], [llvm_v4f32_ty, - llvm_v2i32_ty], [IntrNoMem]>; + llvm_x86mmx_ty], [IntrNoMem]>; } // SIMD load ops @@ -445,11 +445,11 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". Intrinsic<[llvm_v2f64_ty], [llvm_v2f64_ty, llvm_v4f32_ty], [IntrNoMem]>; def int_x86_sse_cvtpd2pi : GCCBuiltin<"__builtin_ia32_cvtpd2pi">, - Intrinsic<[llvm_v2i32_ty], [llvm_v2f64_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_v2f64_ty], [IntrNoMem]>; def int_x86_sse_cvttpd2pi: GCCBuiltin<"__builtin_ia32_cvttpd2pi">, - Intrinsic<[llvm_v2i32_ty], [llvm_v2f64_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_v2f64_ty], [IntrNoMem]>; def int_x86_sse_cvtpi2pd : GCCBuiltin<"__builtin_ia32_cvtpi2pd">, - Intrinsic<[llvm_v2f64_ty], [llvm_v2i32_ty], [IntrNoMem]>; + Intrinsic<[llvm_v2f64_ty], [llvm_x86mmx_ty], [IntrNoMem]>; } // SIMD load ops @@ -563,50 +563,50 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". // Horizontal arithmetic ops let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_ssse3_phadd_w : GCCBuiltin<"__builtin_ia32_phaddw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, - llvm_v4i16_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_ssse3_phadd_w_128 : GCCBuiltin<"__builtin_ia32_phaddw128">, Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty], [IntrNoMem]>; def int_x86_ssse3_phadd_d : GCCBuiltin<"__builtin_ia32_phaddd">, - Intrinsic<[llvm_v2i32_ty], [llvm_v2i32_ty, - llvm_v2i32_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_ssse3_phadd_d_128 : GCCBuiltin<"__builtin_ia32_phaddd128">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty], [IntrNoMem]>; def int_x86_ssse3_phadd_sw : GCCBuiltin<"__builtin_ia32_phaddsw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, - llvm_v4i16_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_ssse3_phadd_sw_128 : GCCBuiltin<"__builtin_ia32_phaddsw128">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty], [IntrNoMem]>; def int_x86_ssse3_phsub_w : GCCBuiltin<"__builtin_ia32_phsubw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, - llvm_v4i16_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_ssse3_phsub_w_128 : GCCBuiltin<"__builtin_ia32_phsubw128">, Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty], [IntrNoMem]>; def int_x86_ssse3_phsub_d : GCCBuiltin<"__builtin_ia32_phsubd">, - Intrinsic<[llvm_v2i32_ty], [llvm_v2i32_ty, - llvm_v2i32_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_ssse3_phsub_d_128 : GCCBuiltin<"__builtin_ia32_phsubd128">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty], [IntrNoMem]>; def int_x86_ssse3_phsub_sw : GCCBuiltin<"__builtin_ia32_phsubsw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, - llvm_v4i16_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_ssse3_phsub_sw_128 : GCCBuiltin<"__builtin_ia32_phsubsw128">, Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty], [IntrNoMem]>; def int_x86_ssse3_pmadd_ub_sw : GCCBuiltin<"__builtin_ia32_pmaddubsw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, - llvm_v4i16_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_ssse3_pmadd_ub_sw_128 : GCCBuiltin<"__builtin_ia32_pmaddubsw128">, Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty], [IntrNoMem]>; @@ -615,8 +615,8 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". // Packed multiply high with round and scale let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_ssse3_pmul_hr_sw : GCCBuiltin<"__builtin_ia32_pmulhrsw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, - llvm_v4i16_ty], [IntrNoMem, Commutative]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem, Commutative]>; def int_x86_ssse3_pmul_hr_sw_128 : GCCBuiltin<"__builtin_ia32_pmulhrsw128">, Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty], [IntrNoMem, Commutative]>; @@ -625,35 +625,35 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". // Shuffle ops let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_ssse3_pshuf_b : GCCBuiltin<"__builtin_ia32_pshufb">, - Intrinsic<[llvm_v8i8_ty], [llvm_v8i8_ty, - llvm_v8i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_ssse3_pshuf_b_128 : GCCBuiltin<"__builtin_ia32_pshufb128">, Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty], [IntrNoMem]>; - def int_x86_ssse3_pshuf_w : GCCBuiltin<"__builtin_ia32_pshufw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, llvm_i32_ty], + def int_x86_sse_pshuf_w : GCCBuiltin<"__builtin_ia32_pshufw">, + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_i8_ty], [IntrNoMem]>; } // Sign ops let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_ssse3_psign_b : GCCBuiltin<"__builtin_ia32_psignb">, - Intrinsic<[llvm_v8i8_ty], [llvm_v8i8_ty, - llvm_v8i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_ssse3_psign_b_128 : GCCBuiltin<"__builtin_ia32_psignb128">, Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty, llvm_v16i8_ty], [IntrNoMem]>; def int_x86_ssse3_psign_w : GCCBuiltin<"__builtin_ia32_psignw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, - llvm_v4i16_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_ssse3_psign_w_128 : GCCBuiltin<"__builtin_ia32_psignw128">, Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty, llvm_v8i16_ty], [IntrNoMem]>; def int_x86_ssse3_psign_d : GCCBuiltin<"__builtin_ia32_psignd">, - Intrinsic<[llvm_v2i32_ty], [llvm_v2i32_ty, - llvm_v2i32_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_ssse3_psign_d_128 : GCCBuiltin<"__builtin_ia32_psignd128">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty, llvm_v4i32_ty], [IntrNoMem]>; @@ -662,17 +662,17 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". // Absolute value ops let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_ssse3_pabs_b : GCCBuiltin<"__builtin_ia32_pabsb">, - Intrinsic<[llvm_v8i8_ty], [llvm_v8i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_ssse3_pabs_b_128 : GCCBuiltin<"__builtin_ia32_pabsb128">, Intrinsic<[llvm_v16i8_ty], [llvm_v16i8_ty], [IntrNoMem]>; def int_x86_ssse3_pabs_w : GCCBuiltin<"__builtin_ia32_pabsw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_ssse3_pabs_w_128 : GCCBuiltin<"__builtin_ia32_pabsw128">, Intrinsic<[llvm_v8i16_ty], [llvm_v8i16_ty], [IntrNoMem]>; def int_x86_ssse3_pabs_d : GCCBuiltin<"__builtin_ia32_pabsd">, - Intrinsic<[llvm_v2i32_ty], [llvm_v2i32_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_ssse3_pabs_d_128 : GCCBuiltin<"__builtin_ia32_pabsd128">, Intrinsic<[llvm_v4i32_ty], [llvm_v4i32_ty], [IntrNoMem]>; } @@ -1328,281 +1328,257 @@ let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". // Addition def int_x86_mmx_padd_b : GCCBuiltin<"__builtin_ia32_paddb">, - Intrinsic<[llvm_v8i8_ty], [llvm_v8i8_ty, llvm_v8i8_ty], + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_padd_w : GCCBuiltin<"__builtin_ia32_paddw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, llvm_v4i16_ty], + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_padd_d : GCCBuiltin<"__builtin_ia32_paddd">, - Intrinsic<[llvm_v2i32_ty], [llvm_v2i32_ty, llvm_v2i32_ty], + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_padd_q : GCCBuiltin<"__builtin_ia32_paddq">, - Intrinsic<[llvm_v1i64_ty], [llvm_v1i64_ty, llvm_v1i64_ty], + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_padds_b : GCCBuiltin<"__builtin_ia32_paddsb">, - Intrinsic<[llvm_v8i8_ty], [llvm_v8i8_ty, - llvm_v8i8_ty], [IntrNoMem, Commutative]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem, Commutative]>; def int_x86_mmx_padds_w : GCCBuiltin<"__builtin_ia32_paddsw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, - llvm_v4i16_ty], [IntrNoMem, Commutative]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem, Commutative]>; def int_x86_mmx_paddus_b : GCCBuiltin<"__builtin_ia32_paddusb">, - Intrinsic<[llvm_v8i8_ty], [llvm_v8i8_ty, - llvm_v8i8_ty], [IntrNoMem, Commutative]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem, Commutative]>; def int_x86_mmx_paddus_w : GCCBuiltin<"__builtin_ia32_paddusw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, - llvm_v4i16_ty], [IntrNoMem, Commutative]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem, Commutative]>; // Subtraction def int_x86_mmx_psub_b : GCCBuiltin<"__builtin_ia32_psubb">, - Intrinsic<[llvm_v8i8_ty], [llvm_v8i8_ty, llvm_v8i8_ty], + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_psub_w : GCCBuiltin<"__builtin_ia32_psubw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, llvm_v4i16_ty], + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_psub_d : GCCBuiltin<"__builtin_ia32_psubd">, - Intrinsic<[llvm_v2i32_ty], [llvm_v2i32_ty, llvm_v2i32_ty], + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_psub_q : GCCBuiltin<"__builtin_ia32_psubq">, - Intrinsic<[llvm_v1i64_ty], [llvm_v1i64_ty, llvm_v1i64_ty], + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_psubs_b : GCCBuiltin<"__builtin_ia32_psubsb">, - Intrinsic<[llvm_v8i8_ty], [llvm_v8i8_ty, - llvm_v8i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_psubs_w : GCCBuiltin<"__builtin_ia32_psubsw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, - llvm_v4i16_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_psubus_b : GCCBuiltin<"__builtin_ia32_psubusb">, - Intrinsic<[llvm_v8i8_ty], [llvm_v8i8_ty, - llvm_v8i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_psubus_w : GCCBuiltin<"__builtin_ia32_psubusw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, - llvm_v4i16_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; // Multiplication def int_x86_mmx_pmulh_w : GCCBuiltin<"__builtin_ia32_pmulhw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, - llvm_v4i16_ty], [IntrNoMem, Commutative]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem, Commutative]>; def int_x86_mmx_pmull_w : GCCBuiltin<"__builtin_ia32_pmullw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, - llvm_v4i16_ty], [IntrNoMem, Commutative]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem, Commutative]>; def int_x86_mmx_pmulhu_w : GCCBuiltin<"__builtin_ia32_pmulhuw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, - llvm_v4i16_ty], [IntrNoMem, Commutative]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem, Commutative]>; def int_x86_mmx_pmulu_dq : GCCBuiltin<"__builtin_ia32_pmuludq">, - Intrinsic<[llvm_v2i32_ty], [llvm_v2i32_ty, - llvm_v2i32_ty], [IntrNoMem, Commutative]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem, Commutative]>; def int_x86_mmx_pmadd_wd : GCCBuiltin<"__builtin_ia32_pmaddwd">, - Intrinsic<[llvm_v2i32_ty], [llvm_v4i16_ty, - llvm_v4i16_ty], [IntrNoMem, Commutative]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem, Commutative]>; // Bitwise operations def int_x86_mmx_pand : GCCBuiltin<"__builtin_ia32_pand">, - Intrinsic<[llvm_v1i64_ty], [llvm_v1i64_ty, llvm_v1i64_ty], + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_pandn : GCCBuiltin<"__builtin_ia32_pandn">, - Intrinsic<[llvm_v1i64_ty], [llvm_v1i64_ty, llvm_v1i64_ty], + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_por : GCCBuiltin<"__builtin_ia32_por">, - Intrinsic<[llvm_v1i64_ty], [llvm_v1i64_ty, llvm_v1i64_ty], + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_pxor : GCCBuiltin<"__builtin_ia32_pxor">, - Intrinsic<[llvm_v1i64_ty], [llvm_v1i64_ty, llvm_v1i64_ty], + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_x86mmx_ty], [IntrNoMem]>; // Averages def int_x86_mmx_pavg_b : GCCBuiltin<"__builtin_ia32_pavgb">, - Intrinsic<[llvm_v8i8_ty], [llvm_v8i8_ty, - llvm_v8i8_ty], [IntrNoMem, Commutative]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem, Commutative]>; def int_x86_mmx_pavg_w : GCCBuiltin<"__builtin_ia32_pavgw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, - llvm_v4i16_ty], [IntrNoMem, Commutative]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem, Commutative]>; // Maximum def int_x86_mmx_pmaxu_b : GCCBuiltin<"__builtin_ia32_pmaxub">, - Intrinsic<[llvm_v8i8_ty], [llvm_v8i8_ty, - llvm_v8i8_ty], [IntrNoMem, Commutative]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem, Commutative]>; def int_x86_mmx_pmaxs_w : GCCBuiltin<"__builtin_ia32_pmaxsw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, - llvm_v4i16_ty], [IntrNoMem, Commutative]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem, Commutative]>; // Minimum def int_x86_mmx_pminu_b : GCCBuiltin<"__builtin_ia32_pminub">, - Intrinsic<[llvm_v8i8_ty], [llvm_v8i8_ty, - llvm_v8i8_ty], [IntrNoMem, Commutative]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem, Commutative]>; def int_x86_mmx_pmins_w : GCCBuiltin<"__builtin_ia32_pminsw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, - llvm_v4i16_ty], [IntrNoMem, Commutative]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem, Commutative]>; // Packed sum of absolute differences def int_x86_mmx_psad_bw : GCCBuiltin<"__builtin_ia32_psadbw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v8i8_ty, - llvm_v8i8_ty], [IntrNoMem, Commutative]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem, Commutative]>; } // Integer shift ops. let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". // Shift left logical def int_x86_mmx_psll_w : GCCBuiltin<"__builtin_ia32_psllw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, - llvm_v1i64_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_psll_d : GCCBuiltin<"__builtin_ia32_pslld">, - Intrinsic<[llvm_v2i32_ty], [llvm_v2i32_ty, - llvm_v1i64_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_psll_q : GCCBuiltin<"__builtin_ia32_psllq">, - Intrinsic<[llvm_v1i64_ty], [llvm_v1i64_ty, - llvm_v1i64_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_psrl_w : GCCBuiltin<"__builtin_ia32_psrlw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, - llvm_v1i64_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_psrl_d : GCCBuiltin<"__builtin_ia32_psrld">, - Intrinsic<[llvm_v2i32_ty], [llvm_v2i32_ty, - llvm_v1i64_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_psrl_q : GCCBuiltin<"__builtin_ia32_psrlq">, - Intrinsic<[llvm_v1i64_ty], [llvm_v1i64_ty, - llvm_v1i64_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_psra_w : GCCBuiltin<"__builtin_ia32_psraw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, - llvm_v1i64_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_psra_d : GCCBuiltin<"__builtin_ia32_psrad">, - Intrinsic<[llvm_v2i32_ty], [llvm_v2i32_ty, - llvm_v1i64_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_pslli_w : GCCBuiltin<"__builtin_ia32_psllwi">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_mmx_pslli_d : GCCBuiltin<"__builtin_ia32_pslldi">, - Intrinsic<[llvm_v2i32_ty], [llvm_v2i32_ty, + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_mmx_pslli_q : GCCBuiltin<"__builtin_ia32_psllqi">, - Intrinsic<[llvm_v1i64_ty], [llvm_v1i64_ty, + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_mmx_psrli_w : GCCBuiltin<"__builtin_ia32_psrlwi">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_mmx_psrli_d : GCCBuiltin<"__builtin_ia32_psrldi">, - Intrinsic<[llvm_v2i32_ty], [llvm_v2i32_ty, + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_mmx_psrli_q : GCCBuiltin<"__builtin_ia32_psrlqi">, - Intrinsic<[llvm_v1i64_ty], [llvm_v1i64_ty, + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_mmx_psrai_w : GCCBuiltin<"__builtin_ia32_psrawi">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_i32_ty], [IntrNoMem]>; def int_x86_mmx_psrai_d : GCCBuiltin<"__builtin_ia32_psradi">, - Intrinsic<[llvm_v2i32_ty], [llvm_v2i32_ty, + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_i32_ty], [IntrNoMem]>; } // Pack ops. let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_mmx_packsswb : GCCBuiltin<"__builtin_ia32_packsswb">, - Intrinsic<[llvm_v8i8_ty], [llvm_v4i16_ty, - llvm_v4i16_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_packssdw : GCCBuiltin<"__builtin_ia32_packssdw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v2i32_ty, - llvm_v2i32_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_packuswb : GCCBuiltin<"__builtin_ia32_packuswb">, - Intrinsic<[llvm_v8i8_ty], [llvm_v4i16_ty, - llvm_v4i16_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; } // Unpacking ops. let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_mmx_punpckhbw : GCCBuiltin<"__builtin_ia32_punpckhbw">, - Intrinsic<[llvm_v8i8_ty], [llvm_v8i8_ty, llvm_v8i8_ty], + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_punpckhwd : GCCBuiltin<"__builtin_ia32_punpckhwd">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, llvm_v4i16_ty], + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_punpckhdq : GCCBuiltin<"__builtin_ia32_punpckhdq">, - Intrinsic<[llvm_v2i32_ty], [llvm_v2i32_ty, llvm_v2i32_ty], + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_punpcklbw : GCCBuiltin<"__builtin_ia32_punpcklbw">, - Intrinsic<[llvm_v8i8_ty], [llvm_v8i8_ty, llvm_v8i8_ty], + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_punpcklwd : GCCBuiltin<"__builtin_ia32_punpcklwd">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, llvm_v4i16_ty], + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_punpckldq : GCCBuiltin<"__builtin_ia32_punpckldq">, - Intrinsic<[llvm_v2i32_ty], [llvm_v2i32_ty, llvm_v2i32_ty], + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_x86mmx_ty], [IntrNoMem]>; } // Integer comparison ops let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_mmx_pcmpeq_b : GCCBuiltin<"__builtin_ia32_pcmpeqb">, - Intrinsic<[llvm_v8i8_ty], [llvm_v8i8_ty, - llvm_v8i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_pcmpeq_w : GCCBuiltin<"__builtin_ia32_pcmpeqw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, - llvm_v4i16_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_pcmpeq_d : GCCBuiltin<"__builtin_ia32_pcmpeqd">, - Intrinsic<[llvm_v2i32_ty], [llvm_v2i32_ty, - llvm_v2i32_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_pcmpgt_b : GCCBuiltin<"__builtin_ia32_pcmpgtb">, - Intrinsic<[llvm_v8i8_ty], [llvm_v8i8_ty, - llvm_v8i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_pcmpgt_w : GCCBuiltin<"__builtin_ia32_pcmpgtw">, - Intrinsic<[llvm_v4i16_ty], [llvm_v4i16_ty, - llvm_v4i16_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_pcmpgt_d : GCCBuiltin<"__builtin_ia32_pcmpgtd">, - Intrinsic<[llvm_v2i32_ty], [llvm_v2i32_ty, - llvm_v2i32_ty], [IntrNoMem]>; + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty], [IntrNoMem]>; } // Misc. let TargetPrefix = "x86" in { // All intrinsics start with "llvm.x86.". def int_x86_mmx_maskmovq : GCCBuiltin<"__builtin_ia32_maskmovq">, - Intrinsic<[], [llvm_v8i8_ty, llvm_v8i8_ty, llvm_ptr_ty], []>; + Intrinsic<[], [llvm_x86mmx_ty, llvm_x86mmx_ty, llvm_ptr_ty], []>; def int_x86_mmx_pmovmskb : GCCBuiltin<"__builtin_ia32_pmovmskb">, - Intrinsic<[llvm_i32_ty], [llvm_v8i8_ty], [IntrNoMem]>; + Intrinsic<[llvm_i32_ty], [llvm_x86mmx_ty], [IntrNoMem]>; def int_x86_mmx_movnt_dq : GCCBuiltin<"__builtin_ia32_movntq">, - Intrinsic<[], [llvm_ptr_ty, llvm_v1i64_ty], []>; + Intrinsic<[], [llvm_ptrx86mmx_ty, llvm_x86mmx_ty], []>; -// def int_x86_mmx_palignr_b : GCCBuiltin<"__builtin_ia32_palignr">, -// Intrinsic<[llvm_v1i64_ty], [llvm_1i64_ty, -// llvm_v1i64_ty, llvm_i8_ty], [IntrNoMem]>; + def int_x86_mmx_palignr_b : GCCBuiltin<"__builtin_ia32_palignr">, + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, + llvm_x86mmx_ty, llvm_i8_ty], [IntrNoMem]>; - def int_x86_mmx_pextr_w : - Intrinsic<[llvm_i32_ty], [llvm_v1i64_ty, llvm_i32_ty], + def int_x86_mmx_pextr_w : GCCBuiltin<"__builtin_ia32_vec_ext_v4hi">, + Intrinsic<[llvm_i32_ty], [llvm_x86mmx_ty, llvm_i32_ty], [IntrNoMem]>; - def int_x86_mmx_pinsr_w : - Intrinsic<[llvm_v1i64_ty], [llvm_v1i64_ty, + def int_x86_mmx_pinsr_w : GCCBuiltin<"__builtin_ia32_vec_set_v4hi">, + Intrinsic<[llvm_x86mmx_ty], [llvm_x86mmx_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem]>; - - def int_x86_mmx_cvtsi32_si64 : - Intrinsic<[llvm_v1i64_ty], [llvm_i32_ty], [IntrNoMem]>; - def int_x86_mmx_cvtsi64_si32 : - Intrinsic<[llvm_i32_ty], [llvm_v1i64_ty], [IntrNoMem]>; - - def int_x86_mmx_vec_init_b : GCCBuiltin<"__builtin_ia32_vec_init_v8qi">, - Intrinsic<[llvm_v8i8_ty], - [llvm_i8_ty, llvm_i8_ty, llvm_i8_ty, llvm_i8_ty, - llvm_i8_ty, llvm_i8_ty, llvm_i8_ty, llvm_i8_ty], - [IntrNoMem]>; - def int_x86_mmx_vec_init_w : GCCBuiltin<"__builtin_ia32_vec_init_v4hi">, - Intrinsic<[llvm_v4i16_ty], - [llvm_i16_ty, llvm_i16_ty, llvm_i16_ty, llvm_i16_ty], - [IntrNoMem]>; - def int_x86_mmx_vec_init_d : GCCBuiltin<"__builtin_ia32_vec_init_v2si">, - Intrinsic<[llvm_v2i32_ty], - [llvm_i32_ty, llvm_i32_ty], - [IntrNoMem]>; - - def int_x86_mmx_vec_ext_d : GCCBuiltin<"__builtin_ia32_vec_ext_v2si">, - Intrinsic<[llvm_v2i32_ty], - [llvm_v2i32_ty, llvm_i32_ty], - [IntrNoMem]>; } diff --git a/include/llvm/IntrinsicsXCore.td b/include/llvm/IntrinsicsXCore.td index a86cda28a5eb..97bac1d2daaf 100644 --- a/include/llvm/IntrinsicsXCore.td +++ b/include/llvm/IntrinsicsXCore.td @@ -11,4 +11,26 @@ let TargetPrefix = "xcore" in { // All intrinsics start with "llvm.xcore.". def int_xcore_bitrev : Intrinsic<[llvm_i32_ty],[llvm_i32_ty],[IntrNoMem]>; def int_xcore_getid : Intrinsic<[llvm_i32_ty],[],[IntrNoMem]>; + + // Resource instructions. + def int_xcore_getr : Intrinsic<[llvm_anyptr_ty],[llvm_i32_ty]>; + def int_xcore_freer : Intrinsic<[],[llvm_anyptr_ty], + [NoCapture<0>]>; + def int_xcore_in : Intrinsic<[llvm_i32_ty],[llvm_anyptr_ty],[NoCapture<0>]>; + def int_xcore_int : Intrinsic<[llvm_i32_ty],[llvm_anyptr_ty], + [NoCapture<0>]>; + def int_xcore_inct : Intrinsic<[llvm_i32_ty],[llvm_anyptr_ty], + [NoCapture<0>]>; + def int_xcore_out : Intrinsic<[],[llvm_anyptr_ty, llvm_i32_ty], + [NoCapture<0>]>; + def int_xcore_outt : Intrinsic<[],[llvm_anyptr_ty, llvm_i32_ty], + [NoCapture<0>]>; + def int_xcore_outct : Intrinsic<[],[llvm_anyptr_ty, llvm_i32_ty], + [NoCapture<0>]>; + def int_xcore_chkct : Intrinsic<[],[llvm_anyptr_ty, llvm_i32_ty], + [NoCapture<0>]>; + def int_xcore_setd : Intrinsic<[],[llvm_anyptr_ty, llvm_i32_ty], + [NoCapture<0>]>; + def int_xcore_setc : Intrinsic<[],[llvm_anyptr_ty, llvm_i32_ty], + [NoCapture<0>]>; } diff --git a/include/llvm/LLVMContext.h b/include/llvm/LLVMContext.h index 7cb6579aef66..3502ff73c19f 100644 --- a/include/llvm/LLVMContext.h +++ b/include/llvm/LLVMContext.h @@ -20,6 +20,8 @@ namespace llvm { class LLVMContextImpl; class StringRef; class Instruction; +class Module; +class SMDiagnostic; template class SmallVectorImpl; /// This is an important class for using LLVM in a threaded context. It @@ -28,10 +30,6 @@ template class SmallVectorImpl; /// LLVMContext itself provides no locking guarantees, so you should be careful /// to have one context per thread. class LLVMContext { - // DO NOT IMPLEMENT - LLVMContext(LLVMContext&); - void operator=(LLVMContext&); - public: LLVMContextImpl *const pImpl; LLVMContext(); @@ -40,7 +38,8 @@ public: // Pinned metadata names, which always have the same value. This is a // compile-time performance optimization, not a correctness optimization. enum { - MD_dbg = 0 // "dbg" + MD_dbg = 0, // "dbg" + MD_tbaa = 1 // "tbaa" }; /// getMDKindID - Return a unique non-zero ID for the specified metadata kind. @@ -51,18 +50,23 @@ public: /// custom metadata IDs registered in this LLVMContext. void getMDKindNames(SmallVectorImpl &Result) const; + + typedef void (*InlineAsmDiagHandlerTy)(const SMDiagnostic&, void *Context, + unsigned LocCookie); + /// setInlineAsmDiagnosticHandler - This method sets a handler that is invoked /// when problems with inline asm are detected by the backend. The first - /// argument is a function pointer (of type SourceMgr::DiagHandlerTy) and the - /// second is a context pointer that gets passed into the DiagHandler. + /// argument is a function pointer and the second is a context pointer that + /// gets passed into the DiagHandler. /// - /// LLVMContext doesn't take ownership or interpreter either of these + /// LLVMContext doesn't take ownership or interpret either of these /// pointers. - void setInlineAsmDiagnosticHandler(void *DiagHandler, void *DiagContext = 0); + void setInlineAsmDiagnosticHandler(InlineAsmDiagHandlerTy DiagHandler, + void *DiagContext = 0); /// getInlineAsmDiagnosticHandler - Return the diagnostic handler set by /// setInlineAsmDiagnosticHandler. - void *getInlineAsmDiagnosticHandler() const; + InlineAsmDiagHandlerTy getInlineAsmDiagnosticHandler() const; /// getInlineAsmDiagnosticContext - Return the diagnostic context set by /// setInlineAsmDiagnosticHandler. @@ -77,6 +81,21 @@ public: void emitError(unsigned LocCookie, StringRef ErrorStr); void emitError(const Instruction *I, StringRef ErrorStr); void emitError(StringRef ErrorStr); + +private: + // DO NOT IMPLEMENT + LLVMContext(LLVMContext&); + void operator=(LLVMContext&); + + /// addModule - Register a module as being instantiated in this context. If + /// the context is deleted, the module will be deleted as well. + void addModule(Module*); + + /// removeModule - Unregister a module from this context. + void removeModule(Module*); + + // Module needs access to the add/removeModule methods. + friend class Module; }; /// getGlobalContext - Returns a global context. This is for LLVM clients that diff --git a/include/llvm/LinkAllPasses.h b/include/llvm/LinkAllPasses.h index 35dab62143df..69e1bd919f74 100644 --- a/include/llvm/LinkAllPasses.h +++ b/include/llvm/LinkAllPasses.h @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This header file pulls in all transformation and analysis passes for tools +// This header file pulls in all transformation and analysis passes for tools // like opt and bugpoint that need this functionality. // //===----------------------------------------------------------------------===// @@ -20,8 +20,8 @@ #include "llvm/Analysis/FindUsedTypes.h" #include "llvm/Analysis/IntervalPartition.h" #include "llvm/Analysis/Passes.h" -#include "llvm/Analysis/PointerTracking.h" #include "llvm/Analysis/PostDominators.h" +#include "llvm/Analysis/RegionPass.h" #include "llvm/Analysis/RegionPrinter.h" #include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Analysis/Lint.h" @@ -70,6 +70,7 @@ namespace { (void) llvm::createDomViewerPass(); (void) llvm::createEdgeProfilerPass(); (void) llvm::createOptimalEdgeProfilerPass(); + (void) llvm::createPathProfilerPass(); (void) llvm::createFunctionInliningPass(); (void) llvm::createAlwaysInlinerPass(); (void) llvm::createGlobalDCEPass(); @@ -90,8 +91,8 @@ namespace { (void) llvm::createLoopStrengthReducePass(); (void) llvm::createLoopUnrollPass(); (void) llvm::createLoopUnswitchPass(); + (void) llvm::createLoopIdiomPass(); (void) llvm::createLoopRotatePass(); - (void) llvm::createLoopIndexSplitPass(); (void) llvm::createLowerInvokePass(); (void) llvm::createLowerSetJmpPass(); (void) llvm::createLowerSwitchPass(); @@ -99,7 +100,9 @@ namespace { (void) llvm::createNoProfileInfoPass(); (void) llvm::createProfileEstimatorPass(); (void) llvm::createProfileVerifierPass(); + (void) llvm::createPathProfileVerifierPass(); (void) llvm::createProfileLoaderPass(); + (void) llvm::createPathProfileLoaderPass(); (void) llvm::createPromoteMemoryToRegisterPass(); (void) llvm::createDemoteRegisterToMemoryPass(); (void) llvm::createPruneEHPass(); @@ -128,13 +131,13 @@ namespace { (void) llvm::createUnifyFunctionExitNodesPass(); (void) llvm::createInstCountPass(); (void) llvm::createCodeGenPreparePass(); + (void) llvm::createEarlyCSEPass(); (void) llvm::createGVNPass(); (void) llvm::createMemCpyOptPass(); (void) llvm::createLoopDeletionPass(); (void) llvm::createPostDomTree(); (void) llvm::createPostDomFrontier(); (void) llvm::createInstructionNamerPass(); - (void) llvm::createPartialSpecializationPass(); (void) llvm::createFunctionAttrsPass(); (void) llvm::createMergeFunctionsPass(); (void) llvm::createPrintModulePass(0); @@ -147,14 +150,17 @@ namespace { (void) llvm::createSinkingPass(); (void) llvm::createLowerAtomicPass(); (void) llvm::createCorrelatedValuePropagationPass(); + (void) llvm::createMemDepPrinter(); + (void) llvm::createInstructionSimplifierPass(); (void)new llvm::IntervalPartition(); (void)new llvm::FindUsedTypes(); (void)new llvm::ScalarEvolution(); - (void)new llvm::PointerTracking(); ((llvm::Function*)0)->viewCFGOnly(); + llvm::RGPassManager RGM(0); + ((llvm::RegionPass*)0)->runOnRegion((llvm::Region*)0, RGM); llvm::AliasSetTracker X(*(llvm::AliasAnalysis*)0); - X.add((llvm::Value*)0, 0); // for -print-alias-sets + X.add((llvm::Value*)0, 0, 0); // for -print-alias-sets } } ForcePassLinking; // Force link by creating a global definition. } diff --git a/include/llvm/LinkAllVMCore.h b/include/llvm/LinkAllVMCore.h index 6959cb6d1efc..83684c0fb65d 100644 --- a/include/llvm/LinkAllVMCore.h +++ b/include/llvm/LinkAllVMCore.h @@ -22,15 +22,14 @@ #include "llvm/IntrinsicInst.h" #include "llvm/InlineAsm.h" #include "llvm/Analysis/Verifier.h" -#include "llvm/System/Alarm.h" -#include "llvm/System/DynamicLibrary.h" -#include "llvm/System/Memory.h" -#include "llvm/System/Mutex.h" -#include "llvm/System/Path.h" -#include "llvm/System/Process.h" -#include "llvm/System/Program.h" -#include "llvm/System/Signals.h" -#include "llvm/System/TimeValue.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/Memory.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/TimeValue.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/MathExtras.h" #include diff --git a/include/llvm/MC/EDInstInfo.h b/include/llvm/MC/EDInstInfo.h index dded25521a27..83d9e780feb7 100644 --- a/include/llvm/MC/EDInstInfo.h +++ b/include/llvm/MC/EDInstInfo.h @@ -9,7 +9,7 @@ #ifndef EDINSTINFO_H #define EDINSTINFO_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { diff --git a/include/llvm/MC/ELFObjectWriter.h b/include/llvm/MC/ELFObjectWriter.h deleted file mode 100644 index 3b9951f4e7ab..000000000000 --- a/include/llvm/MC/ELFObjectWriter.h +++ /dev/null @@ -1,46 +0,0 @@ -//===-- llvm/MC/ELFObjectWriter.h - ELF File Writer ---------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_MC_ELFOBJECTWRITER_H -#define LLVM_MC_ELFOBJECTWRITER_H - -#include "llvm/MC/MCObjectWriter.h" -#include "llvm/Support/raw_ostream.h" -#include - -namespace llvm { -class MCAsmFixup; -class MCAssembler; -class MCFragment; -class MCValue; -class raw_ostream; - -class ELFObjectWriter : public MCObjectWriter { - void *Impl; - -public: - ELFObjectWriter(raw_ostream &OS, bool Is64Bit, bool IsLittleEndian = true, - bool HasRelocationAddend = true); - - virtual ~ELFObjectWriter(); - - virtual void ExecutePostLayoutBinding(MCAssembler &Asm); - - virtual void RecordRelocation(const MCAssembler &Asm, - const MCAsmLayout &Layout, - const MCFragment *Fragment, - const MCFixup &Fixup, MCValue Target, - uint64_t &FixedValue); - - virtual void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout); -}; - -} // End llvm namespace - -#endif diff --git a/include/llvm/MC/MCAsmInfo.h b/include/llvm/MC/MCAsmInfo.h index 43952e0845da..9cfd0048a607 100644 --- a/include/llvm/MC/MCAsmInfo.h +++ b/include/llvm/MC/MCAsmInfo.h @@ -22,10 +22,12 @@ namespace llvm { class MCSection; class MCContext; - + /// MCAsmInfo - This class is intended to be used as a base class for asm /// properties and features specific to the target. - namespace ExceptionHandling { enum ExceptionsType { None, Dwarf, SjLj }; } + namespace ExceptionHandling { + enum ExceptionsType { None, DwarfTable, DwarfCFI, SjLj }; + } class MCAsmInfo { protected: @@ -36,25 +38,30 @@ namespace llvm { /// HasSubsectionsViaSymbols - True if this target has the MachO /// .subsections_via_symbols directive. bool HasSubsectionsViaSymbols; // Default is false. - + /// HasMachoZeroFillDirective - True if this is a MachO target that supports /// the macho-specific .zerofill directive for emitting BSS Symbols. bool HasMachoZeroFillDirective; // Default is false. - + /// HasMachoTBSSDirective - True if this is a MachO target that supports /// the macho-specific .tbss directive for emitting thread local BSS Symbols bool HasMachoTBSSDirective; // Default is false. - + /// HasStaticCtorDtorReferenceInStaticMode - True if the compiler should /// emit a ".reference .constructors_used" or ".reference .destructors_used" /// directive after the a static ctor/dtor list. This directive is only /// emitted in Static relocation model. bool HasStaticCtorDtorReferenceInStaticMode; // Default is false. - + + /// LinkerRequiresNonEmptyDwarfLines - True if the linker has a bug and + /// requires that the debug_line section be of a minimum size. In practice + /// such a linker requires a non empty line sequence if a file is present. + bool LinkerRequiresNonEmptyDwarfLines; // Default to false. + /// MaxInstLength - This is the maximum possible length of an instruction, /// which is needed to compute the size of an inline asm. unsigned MaxInstLength; // Defaults to 4. - + /// PCSymbol - The symbol used to represent the current PC. Used in PC /// relative expressions. const char *PCSymbol; // Defaults to "$". @@ -72,6 +79,9 @@ namespace llvm { /// assembler. const char *CommentString; // Defaults to "#" + /// LabelSuffix - This is appended to emitted labels. + const char *LabelSuffix; // Defaults to ":" + /// GlobalPrefix - If this is set to a non-empty string, it is prepended /// onto all global symbols. This is often used for "_" or ".". const char *GlobalPrefix; // Defaults to "" @@ -80,12 +90,12 @@ namespace llvm { /// pool entries that are completely private to the .s file and should not /// have names in the .o file. This is often "." or "L". const char *PrivateGlobalPrefix; // Defaults to "." - + /// LinkerPrivateGlobalPrefix - This prefix is used for symbols that should /// be passed through the assembler but be removed by the linker. This /// is "l" on Darwin, currently used for some ObjC metadata. const char *LinkerPrivateGlobalPrefix; // Defaults to "" - + /// InlineAsmStart/End - If these are nonempty, they contain a directive to /// emit before and after an inline assembly statement. const char *InlineAsmStart; // Defaults to "#APP\n" @@ -117,7 +127,7 @@ namespace llvm { /// AsciiDirective - This directive allows emission of an ascii string with /// the standard C escape characters embedded into it. const char *AsciiDirective; // Defaults to "\t.ascii\t" - + /// AscizDirective - If not null, this allows for special handling of /// zero terminated strings on this target. This is commonly supported as /// ".asciz". If a target doesn't support this, it can be set to null. @@ -135,7 +145,7 @@ namespace llvm { /// which should be relocated as a 32-bit GP-relative offset, e.g. .gpword /// on Mips or .gprel32 on Alpha. const char *GPRel32Directive; // Defaults to NULL. - + /// getDataASDirective - Return the directive that should be used to emit /// data of the specified size to the specified numeric address space. virtual const char *getDataASDirective(unsigned Size, unsigned AS) const { @@ -149,15 +159,15 @@ namespace llvm { bool SunStyleELFSectionSwitchSyntax; // Defaults to false. /// UsesELFSectionDirectiveForBSS - This is true if this target uses ELF - /// '.section' directive before the '.bss' one. It's used for PPC/Linux + /// '.section' directive before the '.bss' one. It's used for PPC/Linux /// which doesn't support the '.bss' directive only. bool UsesELFSectionDirectiveForBSS; // Defaults to false. - + /// HasMicrosoftFastStdCallMangling - True if this target uses microsoft /// style mangling for functions with X86_StdCall/X86_FastCall calling /// convention. bool HasMicrosoftFastStdCallMangling; // Defaults to false. - + //===--- Alignment Information ----------------------------------------===// /// AlignDirective - The directive used to emit round up to an alignment @@ -176,27 +186,34 @@ namespace llvm { unsigned TextAlignFillValue; // Defaults to 0 //===--- Global Variable Emission Directives --------------------------===// - + /// GlobalDirective - This is the directive used to declare a global entity. /// const char *GlobalDirective; // Defaults to NULL. - /// ExternDirective - This is the directive used to declare external + /// ExternDirective - This is the directive used to declare external /// globals. /// const char *ExternDirective; // Defaults to NULL. - + /// HasSetDirective - True if the assembler supports the .set directive. bool HasSetDirective; // Defaults to true. - + + /// HasAggressiveSymbolFolding - False if the assembler requires that we use + /// Lc = a - b + /// .long Lc + /// instead of + /// .long a - b + bool HasAggressiveSymbolFolding; // Defaults to true. + /// HasLCOMMDirective - This is true if the target supports the .lcomm /// directive. bool HasLCOMMDirective; // Defaults to false. - + /// COMMDirectiveAlignmentIsInBytes - True is COMMDirective's optional /// alignment is to be specified in bytes instead of log2(n). bool COMMDirectiveAlignmentIsInBytes; // Defaults to true; - + /// HasDotTypeDotSizeDirective - True if the target has .type and .size /// directives, this is true for most ELF targets. bool HasDotTypeDotSizeDirective; // Defaults to true. @@ -209,10 +226,14 @@ namespace llvm { /// directive. bool HasNoDeadStrip; // Defaults to false. + /// HasSymbolResolver - True if this target supports the MachO + /// .symbol_resolver directive. + bool HasSymbolResolver; // Defaults to false. + /// WeakRefDirective - This directive, if non-null, is used to declare a /// global as being a weak undefined symbol. const char *WeakRefDirective; // Defaults to NULL. - + /// WeakDefDirective - This directive, if non-null, is used to declare a /// global as being a weak defined symbol. const char *WeakDefDirective; // Defaults to NULL. @@ -220,7 +241,7 @@ namespace llvm { /// LinkOnceDirective - This directive, if non-null is used to declare a /// global as being a weak defined symbol. This is used on cygwin/mingw. const char *LinkOnceDirective; // Defaults to NULL. - + /// HiddenVisibilityAttr - This attribute, if not MCSA_Invalid, is used to /// declare a symbol as having hidden visibility. MCSymbolAttr HiddenVisibilityAttr; // Defaults to MCSA_Hidden. @@ -234,10 +255,6 @@ namespace llvm { /// HasLEB128 - True if target asm supports leb128 directives. bool HasLEB128; // Defaults to false. - /// hasDotLocAndDotFile - True if target asm supports .loc and .file - /// directives for emitting debugging information. - bool HasDotLocAndDotFile; // Defaults to false. - /// SupportsDebugInformation - True if target supports emission of debugging /// information. bool SupportsDebugInformation; // Defaults to false. @@ -254,8 +271,8 @@ namespace llvm { /// DwarfSectionOffsetDirective - Special section offset directive. const char* DwarfSectionOffsetDirective; // Defaults to NULL - - /// DwarfUsesAbsoluteLabelForStmtList - True if DW_AT_stmt_list needs + + /// DwarfUsesAbsoluteLabelForStmtList - True if DW_AT_stmt_list needs /// absolute label instead of offset. bool DwarfUsesAbsoluteLabelForStmtList; // Defaults to true; @@ -276,7 +293,7 @@ namespace llvm { static unsigned getULEB128Size(unsigned Value); bool hasSubsectionsViaSymbols() const { return HasSubsectionsViaSymbols; } - + // Data directive accessors. // const char *getData8bitsDirective(unsigned AS = 0) const { @@ -299,11 +316,11 @@ namespace llvm { virtual const MCSection *getNonexecutableStackSection(MCContext &Ctx) const{ return 0; } - + bool usesSunStyleELFSectionSwitchSyntax() const { return SunStyleELFSectionSwitchSyntax; } - + bool usesELFSectionDirectiveForBSS() const { return UsesELFSectionDirectiveForBSS; } @@ -311,7 +328,7 @@ namespace llvm { bool hasMicrosoftFastStdCallMangling() const { return HasMicrosoftFastStdCallMangling; } - + // Accessors. // bool hasMachoZeroFillDirective() const { return HasMachoZeroFillDirective; } @@ -319,6 +336,9 @@ namespace llvm { bool hasStaticCtorDtorReferenceInStaticMode() const { return HasStaticCtorDtorReferenceInStaticMode; } + bool getLinkerRequiresNonEmptyDwarfLines() const { + return LinkerRequiresNonEmptyDwarfLines; + } unsigned getMaxInstLength() const { return MaxInstLength; } @@ -334,6 +354,9 @@ namespace llvm { const char *getCommentString() const { return CommentString; } + const char *getLabelSuffix() const { + return LabelSuffix; + } const char *getGlobalPrefix() const { return GlobalPrefix; } @@ -386,6 +409,9 @@ namespace llvm { return ExternDirective; } bool hasSetDirective() const { return HasSetDirective; } + bool hasAggressiveSymbolFolding() const { + return HasAggressiveSymbolFolding; + } bool hasLCOMMDirective() const { return HasLCOMMDirective; } bool hasDotTypeDotSizeDirective() const {return HasDotTypeDotSizeDirective;} bool getCOMMDirectiveAlignmentIsInBytes() const { @@ -393,10 +419,11 @@ namespace llvm { } bool hasSingleParameterDotFile() const { return HasSingleParameterDotFile; } bool hasNoDeadStrip() const { return HasNoDeadStrip; } + bool hasSymbolResolver() const { return HasSymbolResolver; } const char *getWeakRefDirective() const { return WeakRefDirective; } const char *getWeakDefDirective() const { return WeakDefDirective; } const char *getLinkOnceDirective() const { return LinkOnceDirective; } - + MCSymbolAttr getHiddenVisibilityAttr() const { return HiddenVisibilityAttr;} MCSymbolAttr getProtectedVisibilityAttr() const { return ProtectedVisibilityAttr; @@ -404,9 +431,6 @@ namespace llvm { bool hasLEB128() const { return HasLEB128; } - bool hasDotLocAndDotFile() const { - return HasDotLocAndDotFile; - } bool doesSupportDebugInformation() const { return SupportsDebugInformation; } @@ -416,6 +440,12 @@ namespace llvm { ExceptionHandling::ExceptionsType getExceptionHandlingType() const { return ExceptionsType; } + bool isExceptionHandlingDwarf() const { + return + (ExceptionsType == ExceptionHandling::DwarfTable || + ExceptionsType == ExceptionHandling::DwarfCFI); + } + bool doesDwarfRequireFrameSection() const { return DwarfRequiresFrameSection; } diff --git a/include/llvm/MC/MCAsmLayout.h b/include/llvm/MC/MCAsmLayout.h index b9565ba06197..01cb0006b362 100644 --- a/include/llvm/MC/MCAsmLayout.h +++ b/include/llvm/MC/MCAsmLayout.h @@ -39,13 +39,12 @@ private: /// The last fragment which was layed out, or 0 if nothing has been layed /// out. Fragments are always layed out in order, so all fragments with a /// lower ordinal will be up to date. - mutable MCFragment *LastValidFragment; + mutable DenseMap LastValidFragment; /// \brief Make sure that the layout for the given fragment is valid, lazily /// computing it if necessary. void EnsureValid(const MCFragment *F) const; - bool isSectionUpToDate(const MCSectionData *SD) const; bool isFragmentUpToDate(const MCFragment *F) const; public: @@ -54,27 +53,15 @@ public: /// Get the assembler object this is a layout for. MCAssembler &getAssembler() const { return Assembler; } - /// \brief Update the layout because a fragment has been resized. The - /// fragments size should have already been updated, the \arg SlideAmount is - /// the delta from the old size. - void UpdateForSlide(MCFragment *F, int SlideAmount); - - /// \brief Update the layout because a fragment has been replaced. - void FragmentReplaced(MCFragment *Src, MCFragment *Dst); - - /// \brief Perform a full layout. - void LayoutFile(); + /// \brief Invalidate all following fragments because a fragment has been + /// resized. The fragments size should have already been updated. + void Invalidate(MCFragment *F); /// \brief Perform layout for a single fragment, assuming that the previous /// fragment has already been layed out correctly, and the parent section has /// been initialized. void LayoutFragment(MCFragment *Fragment); - /// \brief Performs initial layout for a single section, assuming that the - /// previous section (including its fragments) has already been layed out - /// correctly. - void LayoutSection(MCSectionData *SD); - /// @name Section Access (in layout order) /// @{ @@ -89,28 +76,13 @@ public: /// @name Fragment Layout Data /// @{ - /// \brief Get the effective size of the given fragment, as computed in the - /// current layout. - uint64_t getFragmentEffectiveSize(const MCFragment *F) const; - /// \brief Get the offset of the given fragment inside its containing section. uint64_t getFragmentOffset(const MCFragment *F) const; - /// @} - /// @name Section Layout Data - /// @{ - - /// \brief Get the computed address of the given section. - uint64_t getSectionAddress(const MCSectionData *SD) const; - /// @} /// @name Utility Functions /// @{ - /// \brief Get the address of the given fragment, as computed in the current - /// layout. - uint64_t getFragmentAddress(const MCFragment *F) const; - /// \brief Get the address space size of the given section, as it effects /// layout. This may differ from the size reported by \see getSectionSize() by /// not including section tail padding. @@ -120,12 +92,9 @@ public: /// file. This may include additional padding, or be 0 for virtual sections. uint64_t getSectionFileSize(const MCSectionData *SD) const; - /// \brief Get the logical data size of the given section. - uint64_t getSectionSize(const MCSectionData *SD) const; - - /// \brief Get the address of the given symbol, as computed in the current + /// \brief Get the offset of the given symbol, as computed in the current /// layout. - uint64_t getSymbolAddress(const MCSymbolData *SD) const; + uint64_t getSymbolOffset(const MCSymbolData *SD) const; /// @} }; diff --git a/include/llvm/MC/MCAssembler.h b/include/llvm/MC/MCAssembler.h index d193b986a934..30971c62a97e 100644 --- a/include/llvm/MC/MCAssembler.h +++ b/include/llvm/MC/MCAssembler.h @@ -11,13 +11,14 @@ #define LLVM_MC_MCASSEMBLER_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/ilist.h" #include "llvm/ADT/ilist_node.h" #include "llvm/Support/Casting.h" #include "llvm/MC/MCFixup.h" #include "llvm/MC/MCInst.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include // FIXME: Shouldn't be needed. namespace llvm { @@ -49,7 +50,10 @@ public: FT_Data, FT_Fill, FT_Inst, - FT_Org + FT_Org, + FT_Dwarf, + FT_DwarfFrame, + FT_LEB }; private: @@ -72,12 +76,7 @@ private: /// initialized. uint64_t Offset; - /// EffectiveSize - The compute size of this section. This is ~0 until - /// initialized. - uint64_t EffectiveSize; - - /// LayoutOrder - The global layout order of this fragment. This is the index - /// across all fragments in the file, not just within the section. + /// LayoutOrder - The layout order of this fragment. unsigned LayoutOrder; /// @} @@ -234,19 +233,12 @@ class MCAlignFragment : public MCFragment { /// target dependent. bool EmitNops : 1; - /// OnlyAlignAddress - Flag to indicate that this align is only used to adjust - /// the address space size of a section and that it should not be included as - /// part of the section size. This flag can only be used on the last fragment - /// in a section. - bool OnlyAlignAddress : 1; - public: MCAlignFragment(unsigned _Alignment, int64_t _Value, unsigned _ValueSize, unsigned _MaxBytesToEmit, MCSectionData *SD = 0) : MCFragment(FT_Align, SD), Alignment(_Alignment), Value(_Value),ValueSize(_ValueSize), - MaxBytesToEmit(_MaxBytesToEmit), EmitNops(false), - OnlyAlignAddress(false) {} + MaxBytesToEmit(_MaxBytesToEmit), EmitNops(false) {} /// @name Accessors /// @{ @@ -262,9 +254,6 @@ public: bool hasEmitNops() const { return EmitNops; } void setEmitNops(bool Value) { EmitNops = Value; } - bool hasOnlyAlignAddress() const { return OnlyAlignAddress; } - void setOnlyAlignAddress(bool Value) { OnlyAlignAddress = Value; } - /// @} static bool classof(const MCFragment *F) { @@ -337,6 +326,100 @@ public: static bool classof(const MCOrgFragment *) { return true; } }; +class MCLEBFragment : public MCFragment { + /// Value - The value this fragment should contain. + const MCExpr *Value; + + /// IsSigned - True if this is a sleb128, false if uleb128. + bool IsSigned; + + SmallString<8> Contents; +public: + MCLEBFragment(const MCExpr &Value_, bool IsSigned_, MCSectionData *SD) + : MCFragment(FT_LEB, SD), + Value(&Value_), IsSigned(IsSigned_) { Contents.push_back(0); } + + /// @name Accessors + /// @{ + + const MCExpr &getValue() const { return *Value; } + + bool isSigned() const { return IsSigned; } + + SmallString<8> &getContents() { return Contents; } + const SmallString<8> &getContents() const { return Contents; } + + /// @} + + static bool classof(const MCFragment *F) { + return F->getKind() == MCFragment::FT_LEB; + } + static bool classof(const MCLEBFragment *) { return true; } +}; + +class MCDwarfLineAddrFragment : public MCFragment { + /// LineDelta - the value of the difference between the two line numbers + /// between two .loc dwarf directives. + int64_t LineDelta; + + /// AddrDelta - The expression for the difference of the two symbols that + /// make up the address delta between two .loc dwarf directives. + const MCExpr *AddrDelta; + + SmallString<8> Contents; + +public: + MCDwarfLineAddrFragment(int64_t _LineDelta, const MCExpr &_AddrDelta, + MCSectionData *SD) + : MCFragment(FT_Dwarf, SD), + LineDelta(_LineDelta), AddrDelta(&_AddrDelta) { Contents.push_back(0); } + + /// @name Accessors + /// @{ + + int64_t getLineDelta() const { return LineDelta; } + + const MCExpr &getAddrDelta() const { return *AddrDelta; } + + SmallString<8> &getContents() { return Contents; } + const SmallString<8> &getContents() const { return Contents; } + + /// @} + + static bool classof(const MCFragment *F) { + return F->getKind() == MCFragment::FT_Dwarf; + } + static bool classof(const MCDwarfLineAddrFragment *) { return true; } +}; + +class MCDwarfCallFrameFragment : public MCFragment { + /// AddrDelta - The expression for the difference of the two symbols that + /// make up the address delta between two .cfi_* dwarf directives. + const MCExpr *AddrDelta; + + SmallString<8> Contents; + +public: + MCDwarfCallFrameFragment(const MCExpr &_AddrDelta, MCSectionData *SD) + : MCFragment(FT_DwarfFrame, SD), + AddrDelta(&_AddrDelta) { Contents.push_back(0); } + + /// @name Accessors + /// @{ + + const MCExpr &getAddrDelta() const { return *AddrDelta; } + + SmallString<8> &getContents() { return Contents; } + const SmallString<8> &getContents() const { return Contents; } + + /// @} + + static bool classof(const MCFragment *F) { + return F->getKind() == MCFragment::FT_DwarfFrame; + } + static bool classof(const MCDwarfCallFrameFragment *) { return true; } +}; + // FIXME: Should this be a separate class, or just merged into MCSection? Since // we anticipate the fast path being through an MCAssembler, the only reason to // keep it out is for API abstraction. @@ -373,10 +456,6 @@ private: // // FIXME: This could all be kept private to the assembler implementation. - /// Address - The computed address of this section. This is ~0 until - /// initialized. - uint64_t Address; - /// HasInstructions - Whether this section has had instructions emitted into /// it. unsigned HasInstructions : 1; @@ -585,6 +664,8 @@ private: MCCodeEmitter &Emitter; + MCObjectWriter &Writer; + raw_ostream &OS; iplist Sections; @@ -603,7 +684,17 @@ private: std::vector IndirectSymbols; + /// The set of function symbols for which a .thumb_func directive has + /// been seen. + // + // FIXME: We really would like this in target specific code rather than + // here. Maybe when the relocation stuff moves to target specific, + // this can go with it? The streamer would need some target specific + // refactoring too. + SmallPtrSet ThumbFuncs; + unsigned RelaxAll : 1; + unsigned NoExecStack : 1; unsigned SubsectionsViaSymbols : 1; private: @@ -633,24 +724,34 @@ private: bool FragmentNeedsRelaxation(const MCInstFragment *IF, const MCAsmLayout &Layout) const; - /// Compute the effective fragment size assuming it is layed out at the given - /// \arg SectionAddress and \arg FragmentOffset. - uint64_t ComputeFragmentSize(MCAsmLayout &Layout, const MCFragment &F, - uint64_t SectionAddress, - uint64_t FragmentOffset) const; - /// LayoutOnce - Perform one layout iteration and return true if any offsets /// were adjusted. bool LayoutOnce(MCAsmLayout &Layout); + bool LayoutSectionOnce(MCAsmLayout &Layout, MCSectionData &SD); + + bool RelaxInstruction(MCAsmLayout &Layout, MCInstFragment &IF); + + bool RelaxLEB(MCAsmLayout &Layout, MCLEBFragment &IF); + + bool RelaxDwarfLineAddr(MCAsmLayout &Layout, MCDwarfLineAddrFragment &DF); + bool RelaxDwarfCallFrameFragment(MCAsmLayout &Layout, + MCDwarfCallFrameFragment &DF); + /// FinishLayout - Finalize a layout, including fragment lowering. void FinishLayout(MCAsmLayout &Layout); + uint64_t HandleFixup(const MCAsmLayout &Layout, + MCFragment &F, const MCFixup &Fixup); + public: + /// Compute the effective fragment size assuming it is layed out at the given + /// \arg SectionAddress and \arg FragmentOffset. + uint64_t ComputeFragmentSize(const MCAsmLayout &Layout, const MCFragment &F) const; + /// Find the symbol which defines the atom containing the given symbol, or /// null if there is no such symbol. - const MCSymbolData *getAtom(const MCAsmLayout &Layout, - const MCSymbolData *Symbol) const; + const MCSymbolData *getAtom(const MCSymbolData *Symbol) const; /// Check whether a particular symbol is visible to the linker and is required /// in the symbol table, or whether it can be discarded by the assembler. This @@ -659,12 +760,16 @@ public: bool isSymbolLinkerVisible(const MCSymbol &SD) const; /// Emit the section contents using the given object writer. - // - // FIXME: Should MCAssembler always have a reference to the object writer? - void WriteSectionData(const MCSectionData *Section, const MCAsmLayout &Layout, - MCObjectWriter *OW) const; + void WriteSectionData(const MCSectionData *Section, + const MCAsmLayout &Layout) const; - void AddSectionToTheEnd(MCSectionData &SD, MCAsmLayout &Layout); + /// Check whether a given symbol has been flagged with .thumb_func. + bool isThumbFunc(const MCSymbol *Func) const { + return ThumbFuncs.count(Func); + } + + /// Flag a function symbol as the target of a .thumb_func directive. + void setIsThumbFunc(const MCSymbol *Func) { ThumbFuncs.insert(Func); } public: /// Construct a new assembler instance. @@ -675,8 +780,9 @@ public: // concrete and require clients to pass in a target like object. The other // option is to make this abstract, and have targets provide concrete // implementations as we do with AsmParser. - MCAssembler(MCContext &_Context, TargetAsmBackend &_Backend, - MCCodeEmitter &_Emitter, raw_ostream &OS); + MCAssembler(MCContext &Context_, TargetAsmBackend &Backend_, + MCCodeEmitter &Emitter_, MCObjectWriter &Writer_, + raw_ostream &OS); ~MCAssembler(); MCContext &getContext() const { return Context; } @@ -685,10 +791,12 @@ public: MCCodeEmitter &getEmitter() const { return Emitter; } + MCObjectWriter &getWriter() const { return Writer; } + /// Finish - Do final processing and write the object to the output stream. /// \arg Writer is used for custom object writer (as the MCJIT does), /// if not specified it is automatically created from backend. - void Finish(MCObjectWriter *Writer = 0); + void Finish(); // FIXME: This does not belong here. bool getSubsectionsViaSymbols() const { @@ -701,6 +809,9 @@ public: bool getRelaxAll() const { return RelaxAll; } void setRelaxAll(bool Value) { RelaxAll = Value; } + bool getNoExecStack() const { return NoExecStack; } + void setNoExecStack(bool Value) { NoExecStack = Value; } + /// @name Section List Access /// @{ diff --git a/include/llvm/MC/MCCodeEmitter.h b/include/llvm/MC/MCCodeEmitter.h index 010a2e556629..bc63241bece9 100644 --- a/include/llvm/MC/MCCodeEmitter.h +++ b/include/llvm/MC/MCCodeEmitter.h @@ -20,33 +20,6 @@ class MCInst; class raw_ostream; template class SmallVectorImpl; -/// MCFixupKindInfo - Target independent information on a fixup kind. -struct MCFixupKindInfo { - enum FixupKindFlags { - /// Is this fixup kind PCrelative. This is used by the assembler backend to - /// evaluate fixup values in a target independent manner when possible. - FKF_IsPCRel = (1 << 0) - }; - - /// A target specific name for the fixup kind. The names will be unique for - /// distinct kinds on any given target. - const char *Name; - - /// The bit offset to write the relocation into. - // - // FIXME: These two fields are under-specified and not general enough, but it - // is covers many things, and is enough to let the AsmStreamer pretty-print - // the encoding. - unsigned TargetOffset; - - /// The number of bits written by this fixup. The bits are assumed to be - /// contiguous. - unsigned TargetSize; - - /// Flags describing additional information on this fixup kind. - unsigned Flags; -}; - /// MCCodeEmitter - Generic instruction encoding interface. class MCCodeEmitter { private: @@ -58,17 +31,6 @@ protected: // Can only create subclasses. public: virtual ~MCCodeEmitter(); - /// @name Target Independent Fixup Information - /// @{ - - /// getNumFixupKinds - Get the number of target specific fixup kinds. - virtual unsigned getNumFixupKinds() const = 0; - - /// getFixupKindInfo - Get information on a fixup kind. - virtual const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const; - - /// @} - /// EncodeInstruction - Encode the given \arg Inst to bytes on the output /// stream \arg OS. virtual void EncodeInstruction(const MCInst &Inst, raw_ostream &OS, diff --git a/include/llvm/MC/MCContext.h b/include/llvm/MC/MCContext.h index d22868cdbd0c..7b26d5493776 100644 --- a/include/llvm/MC/MCContext.h +++ b/include/llvm/MC/MCContext.h @@ -29,7 +29,9 @@ namespace llvm { class MCLineSection; class StringRef; class Twine; + class TargetAsmInfo; class MCSectionMachO; + class MCSectionELF; /// MCContext - Context object for machine code objects. This class owns all /// of the sections that it creates. @@ -41,9 +43,15 @@ namespace llvm { /// The MCAsmInfo for this target. const MCAsmInfo &MAI; + const TargetAsmInfo *TAI; + /// Symbols - Bindings of names to symbols. StringMap Symbols; + /// UsedNames - Keeps tracks of names that were used both for used declared + /// and artificial symbols. + StringMap UsedNames; + /// NextUniqueID - The next ID to dole out to an unnamed assembler temporary /// symbol. unsigned NextUniqueID; @@ -56,8 +64,8 @@ namespace llvm { /// GetInstance() gets the current instance of the directional local label /// for the LocalLabelVal and adds it to the map if needed. unsigned GetInstance(int64_t LocalLabelVal); - - /// The file name of the log file from the enviromment variable + + /// The file name of the log file from the environment variable /// AS_SECURE_LOG_FILE. Which must be set before the .secure_log_unique /// directive is used or it is an error. char *SecureLogFile; @@ -79,29 +87,37 @@ namespace llvm { /// The dwarf line information from the .loc directives for the sections /// with assembled machine instructions have after seeing .loc directives. DenseMap MCLineSections; + /// We need a deterministic iteration order, so we remember the order + /// the elements were added. + std::vector MCLineSectionOrder; /// Allocator - Allocator object used for creating machine code objects. /// /// We use a bump pointer allocator to avoid the need to track all allocated /// objects. BumpPtrAllocator Allocator; - + void *MachOUniquingMap, *ELFUniquingMap, *COFFUniquingMap; + + MCSymbol *CreateSymbol(StringRef Name); + public: - explicit MCContext(const MCAsmInfo &MAI); + explicit MCContext(const MCAsmInfo &MAI, const TargetAsmInfo *TAI); ~MCContext(); - + const MCAsmInfo &getAsmInfo() const { return MAI; } - /// @name Symbol Managment + const TargetAsmInfo &getTargetAsmInfo() const { return *TAI; } + + /// @name Symbol Management /// @{ - + /// CreateTempSymbol - Create and return a new assembler temporary symbol /// with a unique but unspecified name. MCSymbol *CreateTempSymbol(); - /// CreateDirectionalLocalSymbol - Create the defintion of a directional - /// local symbol for numbered label (used for "1:" defintions). + /// CreateDirectionalLocalSymbol - Create the definition of a directional + /// local symbol for numbered label (used for "1:" definitions). MCSymbol *CreateDirectionalLocalSymbol(int64_t LocalLabelVal); /// GetDirectionalLocalSymbol - Create and return a directional local @@ -120,8 +136,8 @@ namespace llvm { MCSymbol *LookupSymbol(StringRef Name) const; /// @} - - /// @name Section Managment + + /// @name Section Management /// @{ /// getMachOSection - Return the MCSection for the specified mach-o section. @@ -137,11 +153,15 @@ namespace llvm { SectionKind K) { return getMachOSection(Segment, Section, TypeAndAttributes, 0, K); } - - const MCSection *getELFSection(StringRef Section, unsigned Type, - unsigned Flags, SectionKind Kind, - bool IsExplicit = false, - unsigned EntrySize = 0); + + const MCSectionELF *getELFSection(StringRef Section, unsigned Type, + unsigned Flags, SectionKind Kind); + + const MCSectionELF *getELFSection(StringRef Section, unsigned Type, + unsigned Flags, SectionKind Kind, + unsigned EntrySize, StringRef Group); + + const MCSectionELF *CreateELFGroupSection(); const MCSection *getCOFFSection(StringRef Section, unsigned Characteristics, int Selection, SectionKind Kind); @@ -151,16 +171,20 @@ namespace llvm { return getCOFFSection (Section, Characteristics, 0, Kind); } - + /// @} - /// @name Dwarf Managment + /// @name Dwarf Management /// @{ /// GetDwarfFile - creates an entry in the dwarf file and directory tables. unsigned GetDwarfFile(StringRef FileName, unsigned FileNumber); - bool ValidateDwarfFileNumber(unsigned FileNumber); + bool isValidDwarfFileNumber(unsigned FileNumber); + + bool hasDwarfFiles() const { + return !MCDwarfFiles.empty(); + } const std::vector &getMCDwarfFiles() { return MCDwarfFiles; @@ -168,23 +192,35 @@ namespace llvm { const std::vector &getMCDwarfDirs() { return MCDwarfDirs; } - DenseMap &getMCLineSections() { + + const DenseMap + &getMCLineSections() const { return MCLineSections; } + const std::vector &getMCLineSectionOrder() const { + return MCLineSectionOrder; + } + void addMCLineSection(const MCSection *Sec, MCLineSection *Line) { + MCLineSections[Sec] = Line; + MCLineSectionOrder.push_back(Sec); + } /// setCurrentDwarfLoc - saves the information from the currently parsed - /// dwarf .loc directive and sets DwarfLocSeen. When the next instruction /// is assembled an entry in the line number table with this information and + /// dwarf .loc directive and sets DwarfLocSeen. When the next instruction + /// is assembled an entry in the line number table with this information and /// the address of the instruction will be created. void setCurrentDwarfLoc(unsigned FileNum, unsigned Line, unsigned Column, - unsigned Flags, unsigned Isa) { + unsigned Flags, unsigned Isa, + unsigned Discriminator) { CurrentDwarfLoc.setFileNum(FileNum); CurrentDwarfLoc.setLine(Line); CurrentDwarfLoc.setColumn(Column); CurrentDwarfLoc.setFlags(Flags); CurrentDwarfLoc.setIsa(Isa); + CurrentDwarfLoc.setDiscriminator(Discriminator); DwarfLocSeen = true; } - void clearDwarfLocSeen() { DwarfLocSeen = false; } + void ClearDwarfLocSeen() { DwarfLocSeen = false; } bool getDwarfLocSeen() { return DwarfLocSeen; } const MCDwarfLoc &getCurrentDwarfLoc() { return CurrentDwarfLoc; } diff --git a/include/llvm/MC/MCDirectives.h b/include/llvm/MC/MCDirectives.h index 223b09ef7aee..1df55dc252e3 100644 --- a/include/llvm/MC/MCDirectives.h +++ b/include/llvm/MC/MCDirectives.h @@ -26,6 +26,7 @@ enum MCSymbolAttr { MCSA_ELF_TypeTLS, ///< .type _foo, STT_TLS # aka @tls_object MCSA_ELF_TypeCommon, ///< .type _foo, STT_COMMON # aka @common MCSA_ELF_TypeNoType, ///< .type _foo, STT_NOTYPE # aka @notype + MCSA_ELF_TypeGnuUniqueObject, /// .type _foo, @gnu_unique_object MCSA_Global, ///< .globl MCSA_Hidden, ///< .hidden (ELF) MCSA_IndirectSymbol, ///< .indirect_symbol (MachO) @@ -33,6 +34,7 @@ enum MCSymbolAttr { MCSA_LazyReference, ///< .lazy_reference (MachO) MCSA_Local, ///< .local (ELF) MCSA_NoDeadStrip, ///< .no_dead_strip (MachO) + MCSA_SymbolResolver, ///< .symbol_resolver (MachO) MCSA_PrivateExtern, ///< .private_extern (MachO) MCSA_Protected, ///< .protected (ELF) MCSA_Reference, ///< .reference (MachO) @@ -43,9 +45,12 @@ enum MCSymbolAttr { }; enum MCAssemblerFlag { - MCAF_SubsectionsViaSymbols ///< .subsections_via_symbols (MachO) + MCAF_SyntaxUnified, ///< .syntax (ARM/ELF) + MCAF_SubsectionsViaSymbols, ///< .subsections_via_symbols (MachO) + MCAF_Code16, ///< .code 16 + MCAF_Code32 ///< .code 32 }; - + } // end namespace llvm #endif diff --git a/include/llvm/MC/MCDisassembler.h b/include/llvm/MC/MCDisassembler.h index dfb8ed5e8a10..c9e42eb6c798 100644 --- a/include/llvm/MC/MCDisassembler.h +++ b/include/llvm/MC/MCDisassembler.h @@ -9,7 +9,7 @@ #ifndef MCDISASSEMBLER_H #define MCDISASSEMBLER_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { diff --git a/include/llvm/MC/MCDwarf.h b/include/llvm/MC/MCDwarf.h index dac875cf1b67..07a7bad15b1e 100644 --- a/include/llvm/MC/MCDwarf.h +++ b/include/llvm/MC/MCDwarf.h @@ -8,8 +8,7 @@ //===----------------------------------------------------------------------===// // // This file contains the declaration of the MCDwarfFile to support the dwarf -// .file directive. -// TODO: add the support needed for the .loc directive. +// .file directive and the .loc directive. // //===----------------------------------------------------------------------===// @@ -17,12 +16,21 @@ #define LLVM_MC_MCDWARF_H #include "llvm/ADT/StringRef.h" +#include "llvm/CodeGen/MachineLocation.h" // FIXME +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Dwarf.h" #include namespace llvm { + class MachineMove; class MCContext; + class MCExpr; class MCSection; + class MCSectionData; + class MCStreamer; class MCSymbol; + class MCObjectStreamer; class raw_ostream; /// MCDwarfFile - Instances of this class represent the name of the dwarf @@ -78,6 +86,11 @@ namespace llvm { unsigned Flags; // Isa unsigned Isa; + // Discriminator + unsigned Discriminator; + +// Flag that indicates the initial value of the is_stmt_start flag. +#define DWARF2_LINE_DEFAULT_IS_STMT 1 #define DWARF2_FLAG_IS_STMT (1 << 0) #define DWARF2_FLAG_BASIC_BLOCK (1 << 1) @@ -88,13 +101,32 @@ namespace llvm { friend class MCContext; friend class MCLineEntry; MCDwarfLoc(unsigned fileNum, unsigned line, unsigned column, unsigned flags, - unsigned isa) - : FileNum(fileNum), Line(line), Column(column), Flags(flags), Isa(isa) {} + unsigned isa, unsigned discriminator) + : FileNum(fileNum), Line(line), Column(column), Flags(flags), Isa(isa), + Discriminator(discriminator) {} // Allow the default copy constructor and assignment operator to be used // for an MCDwarfLoc object. public: + /// getFileNum - Get the FileNum of this MCDwarfLoc. + unsigned getFileNum() const { return FileNum; } + + /// getLine - Get the Line of this MCDwarfLoc. + unsigned getLine() const { return Line; } + + /// getColumn - Get the Column of this MCDwarfLoc. + unsigned getColumn() const { return Column; } + + /// getFlags - Get the Flags of this MCDwarfLoc. + unsigned getFlags() const { return Flags; } + + /// getIsa - Get the Isa of this MCDwarfLoc. + unsigned getIsa() const { return Isa; } + + /// getDiscriminator - Get the Discriminator of this MCDwarfLoc. + unsigned getDiscriminator() const { return Discriminator; } + /// setFileNum - Set the FileNum of this MCDwarfLoc. void setFileNum(unsigned fileNum) { FileNum = fileNum; } @@ -109,6 +141,11 @@ namespace llvm { /// setIsa - Set the Isa of this MCDwarfLoc. void setIsa(unsigned isa) { Isa = isa; } + + /// setDiscriminator - Set the Discriminator of this MCDwarfLoc. + void setDiscriminator(unsigned discriminator) { + Discriminator = discriminator; + } }; /// MCLineEntry - Instances of this class represent the line information for @@ -127,6 +164,13 @@ namespace llvm { // Constructor to create an MCLineEntry given a symbol and the dwarf loc. MCLineEntry(MCSymbol *label, const MCDwarfLoc loc) : MCDwarfLoc(loc), Label(label) {} + + MCSymbol *getLabel() const { return Label; } + + // This is called when an instruction is assembled into the specified + // section and if there is information from the last .loc directive that + // has yet to have a line entry made for it is made. + static void Make(MCStreamer *MCOS, const MCSection *Section); }; /// MCLineSection - Instances of this class represent the line information @@ -134,7 +178,6 @@ namespace llvm { /// .loc directives. This is the information used to build the dwarf line /// table for a section. class MCLineSection { - std::vector MCLineEntries; private: MCLineSection(const MCLineSection&); // DO NOT IMPLEMENT @@ -149,8 +192,88 @@ namespace llvm { void addLineEntry(const MCLineEntry &LineEntry) { MCLineEntries.push_back(LineEntry); } + + typedef std::vector MCLineEntryCollection; + typedef MCLineEntryCollection::iterator iterator; + typedef MCLineEntryCollection::const_iterator const_iterator; + + private: + MCLineEntryCollection MCLineEntries; + + public: + const MCLineEntryCollection *getMCLineEntries() const { + return &MCLineEntries; + } }; + class MCDwarfFileTable { + public: + // + // This emits the Dwarf file and the line tables. + // + static void Emit(MCStreamer *MCOS); + }; + + class MCDwarfLineAddr { + public: + /// Utility function to encode a Dwarf pair of LineDelta and AddrDeltas. + static void Encode(int64_t LineDelta, uint64_t AddrDelta, raw_ostream &OS); + + /// Utility function to emit the encoding to a streamer. + static void Emit(MCStreamer *MCOS, + int64_t LineDelta,uint64_t AddrDelta); + + /// Utility function to write the encoding to an object writer. + static void Write(MCObjectWriter *OW, + int64_t LineDelta, uint64_t AddrDelta); + }; + + class MCCFIInstruction { + public: + enum OpType { Remember, Restore, Move }; + private: + OpType Operation; + MCSymbol *Label; + // Move to & from location. + MachineLocation Destination; + MachineLocation Source; + public: + MCCFIInstruction(OpType Op, MCSymbol *L) + : Operation(Op), Label(L) { + assert(Op == Remember || Op == Restore); + } + MCCFIInstruction(MCSymbol *L, const MachineLocation &D, + const MachineLocation &S) + : Operation(Move), Label(L), Destination(D), Source(S) { + } + OpType getOperation() const { return Operation; } + MCSymbol *getLabel() const { return Label; } + const MachineLocation &getDestination() const { return Destination; } + const MachineLocation &getSource() const { return Source; } + }; + + struct MCDwarfFrameInfo { + MCDwarfFrameInfo() : Begin(0), End(0), Personality(0), Lsda(0), + Instructions(), PersonalityEncoding(0), + LsdaEncoding(0) {} + MCSymbol *Begin; + MCSymbol *End; + const MCSymbol *Personality; + const MCSymbol *Lsda; + std::vector Instructions; + unsigned PersonalityEncoding; + unsigned LsdaEncoding; + }; + + class MCDwarfFrameEmitter { + public: + // + // This emits the frame info section. + // + static void Emit(MCStreamer &streamer); + static void EmitAdvanceLoc(MCStreamer &Streamer, uint64_t AddrDelta); + static void EncodeAdvanceLoc(uint64_t AddrDelta, raw_ostream &OS); + }; } // end namespace llvm #endif diff --git a/include/llvm/MC/MCELFObjectWriter.h b/include/llvm/MC/MCELFObjectWriter.h new file mode 100644 index 000000000000..3c150dca9e62 --- /dev/null +++ b/include/llvm/MC/MCELFObjectWriter.h @@ -0,0 +1,47 @@ +//===-- llvm/MC/MCELFObjectWriter.h - ELF Object Writer ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCELFOBJECTWRITER_H +#define LLVM_MC_MCELFOBJECTWRITER_H + +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/Support/DataTypes.h" + +namespace llvm { +class MCELFObjectTargetWriter { + const Triple::OSType OSType; + const uint16_t EMachine; + const unsigned HasRelocationAddend : 1; + const unsigned Is64Bit : 1; +protected: + MCELFObjectTargetWriter(bool Is64Bit_, Triple::OSType OSType_, + uint16_t EMachine_, bool HasRelocationAddend_); + +public: + virtual ~MCELFObjectTargetWriter(); + + /// @name Accessors + /// @{ + Triple::OSType getOSType() { return OSType; } + uint16_t getEMachine() { return EMachine; } + bool hasRelocationAddend() { return HasRelocationAddend; } + bool is64Bit() { return Is64Bit; } + /// @} +}; + +/// \brief Construct a new ELF writer instance. +/// +/// \param MOTW - The target specific ELF writer subclass. +/// \param OS - The stream to write to. +/// \returns The constructed object writer. +MCObjectWriter *createELFObjectWriter(MCELFObjectTargetWriter *MOTW, + raw_ostream &OS, bool IsLittleEndian); +} // End llvm namespace + +#endif diff --git a/include/llvm/MC/MCELFSymbolFlags.h b/include/llvm/MC/MCELFSymbolFlags.h index eb7978b18c5c..d798fb077272 100644 --- a/include/llvm/MC/MCELFSymbolFlags.h +++ b/include/llvm/MC/MCELFSymbolFlags.h @@ -21,9 +21,10 @@ namespace llvm { enum { - ELF_STT_Shift = 0, // Shift value for STT_* flags. - ELF_STB_Shift = 4, // Shift value for STB_* flags. - ELF_STV_Shift = 8 // Shift value ofr STV_* flags. + ELF_STT_Shift = 0, // Shift value for STT_* flags. + ELF_STB_Shift = 4, // Shift value for STB_* flags. + ELF_STV_Shift = 8, // Shift value for STV_* flags. + ELF_Other_Shift = 10 // Shift value for other flags. }; enum SymbolFlags { @@ -46,7 +47,9 @@ namespace llvm { ELF_STV_Default = (ELF::STV_DEFAULT << ELF_STV_Shift), ELF_STV_Internal = (ELF::STV_INTERNAL << ELF_STV_Shift), ELF_STV_Hidden = (ELF::STV_HIDDEN << ELF_STV_Shift), - ELF_STV_Protected = (ELF::STV_PROTECTED << ELF_STV_Shift) + ELF_STV_Protected = (ELF::STV_PROTECTED << ELF_STV_Shift), + + ELF_Other_Weakref = (1 << ELF_Other_Shift) }; } // end namespace llvm diff --git a/include/llvm/MC/MCExpr.h b/include/llvm/MC/MCExpr.h index 1f9b8f256743..fea5249eaba0 100644 --- a/include/llvm/MC/MCExpr.h +++ b/include/llvm/MC/MCExpr.h @@ -10,17 +10,21 @@ #ifndef LLVM_MC_MCEXPR_H #define LLVM_MC_MCEXPR_H +#include "llvm/ADT/DenseMap.h" #include "llvm/Support/Casting.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { class MCAsmInfo; class MCAsmLayout; +class MCAssembler; class MCContext; +class MCSectionData; class MCSymbol; class MCValue; class raw_ostream; class StringRef; +typedef DenseMap SectionAddrMap; /// MCExpr - Base class for the full range of assembler expressions which are /// needed for parsing. @@ -40,9 +44,16 @@ private: MCExpr(const MCExpr&); // DO NOT IMPLEMENT void operator=(const MCExpr&); // DO NOT IMPLEMENT + bool EvaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm, + const MCAsmLayout *Layout, + const SectionAddrMap *Addrs) const; protected: explicit MCExpr(ExprKind _Kind) : Kind(_Kind) {} + bool EvaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm, + const MCAsmLayout *Layout, + const SectionAddrMap *Addrs, + bool InSet) const; public: /// @name Accessors /// @{ @@ -67,7 +78,11 @@ public: /// values. If not given, then only non-symbolic expressions will be /// evaluated. /// @result - True on success. - bool EvaluateAsAbsolute(int64_t &Res, const MCAsmLayout *Layout = 0) const; + bool EvaluateAsAbsolute(int64_t &Res) const; + bool EvaluateAsAbsolute(int64_t &Res, const MCAssembler &Asm) const; + bool EvaluateAsAbsolute(int64_t &Res, const MCAsmLayout &Layout) const; + bool EvaluateAsAbsolute(int64_t &Res, const MCAsmLayout &Layout, + const SectionAddrMap &Addrs) const; /// EvaluateAsRelocatable - Try to evaluate the expression to a relocatable /// value, i.e. an expression of the fixed form (a - b + constant). @@ -75,7 +90,7 @@ public: /// @param Res - The relocatable value, if evaluation succeeds. /// @param Layout - The assembler layout object to use for evaluating values. /// @result - True on success. - bool EvaluateAsRelocatable(MCValue &Res, const MCAsmLayout *Layout = 0) const; + bool EvaluateAsRelocatable(MCValue &Res, const MCAsmLayout &Layout) const; /// @} @@ -132,12 +147,25 @@ public: VK_GOTTPOFF, VK_INDNTPOFF, VK_NTPOFF, + VK_GOTNTPOFF, VK_PLT, VK_TLSGD, + VK_TLSLD, + VK_TLSLDM, VK_TPOFF, - VK_ARM_HI16, // The R_ARM_MOVT_ABS relocation (:upper16: in the asm file) - VK_ARM_LO16, // The R_ARM_MOVW_ABS_NC relocation (:lower16: in the asm file) - VK_TLVP // Mach-O thread local variable relocation + VK_DTPOFF, + VK_TLVP, // Mach-O thread local variable relocation + // FIXME: We'd really like to use the generic Kinds listed above for these. + VK_ARM_PLT, // ARM-style PLT references. i.e., (PLT) instead of @PLT + VK_ARM_TLSGD, // ditto for TLSGD, GOT, GOTOFF, TPOFF and GOTTPOFF + VK_ARM_GOT, + VK_ARM_GOTOFF, + VK_ARM_TPOFF, + VK_ARM_GOTTPOFF, + + VK_PPC_TOC, + VK_PPC_HA16, // ha16(symbol) + VK_PPC_LO16 // lo16(symbol) }; private: @@ -162,7 +190,7 @@ public: MCContext &Ctx); static const MCSymbolRefExpr *Create(StringRef Name, VariantKind Kind, MCContext &Ctx); - + /// @} /// @name Accessors /// @{ @@ -391,7 +419,7 @@ public: virtual void PrintImpl(raw_ostream &OS) const = 0; virtual bool EvaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout) const = 0; - + virtual void AddValueSymbols(MCAssembler *) const = 0; static bool classof(const MCExpr *E) { return E->getKind() == MCExpr::Target; diff --git a/include/llvm/MC/MCFixup.h b/include/llvm/MC/MCFixup.h index eed4c349e848..6fde797e40fd 100644 --- a/include/llvm/MC/MCFixup.h +++ b/include/llvm/MC/MCFixup.h @@ -10,7 +10,7 @@ #ifndef LLVM_MC_MCFIXUP_H #define LLVM_MC_MCFIXUP_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include namespace llvm { @@ -22,6 +22,10 @@ enum MCFixupKind { FK_Data_2, ///< A two-byte fixup. FK_Data_4, ///< A four-byte fixup. FK_Data_8, ///< A eight-byte fixup. + FK_PCRel_1, ///< A one-byte pc relative fixup. + FK_PCRel_2, ///< A two-byte pc relative fixup. + FK_PCRel_4, ///< A four-byte pc relative fixup. + FK_PCRel_8, ///< A eight-byte pc relative fixup. FirstTargetFixupKind = 128, @@ -77,13 +81,13 @@ public: /// getKindForSize - Return the generic fixup kind for a value with the given /// size. It is an error to pass an unsupported size. - static MCFixupKind getKindForSize(unsigned Size) { + static MCFixupKind getKindForSize(unsigned Size, bool isPCRel) { switch (Size) { default: assert(0 && "Invalid generic fixup size!"); - case 1: return FK_Data_1; - case 2: return FK_Data_2; - case 4: return FK_Data_4; - case 8: return FK_Data_8; + case 1: return isPCRel ? FK_PCRel_1 : FK_Data_1; + case 2: return isPCRel ? FK_PCRel_2 : FK_Data_2; + case 4: return isPCRel ? FK_PCRel_4 : FK_Data_4; + case 8: return isPCRel ? FK_PCRel_8 : FK_Data_8; } } }; diff --git a/include/llvm/MC/MCFixupKindInfo.h b/include/llvm/MC/MCFixupKindInfo.h new file mode 100644 index 000000000000..1961687146a8 --- /dev/null +++ b/include/llvm/MC/MCFixupKindInfo.h @@ -0,0 +1,43 @@ +//===-- llvm/MC/MCFixupKindInfo.h - Fixup Descriptors -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCFIXUPKINDINFO_H +#define LLVM_MC_MCFIXUPKINDINFO_H + +namespace llvm { + +/// MCFixupKindInfo - Target independent information on a fixup kind. +struct MCFixupKindInfo { + enum FixupKindFlags { + /// Is this fixup kind PCrelative? This is used by the assembler backend to + /// evaluate fixup values in a target independent manner when possible. + FKF_IsPCRel = (1 << 0), + + /// Should this fixup kind force a 4-byte aligned effective PC value? + FKF_IsAlignedDownTo32Bits = (1 << 1) + }; + + /// A target specific name for the fixup kind. The names will be unique for + /// distinct kinds on any given target. + const char *Name; + + /// The bit offset to write the relocation into. + unsigned TargetOffset; + + /// The number of bits written by this fixup. The bits are assumed to be + /// contiguous. + unsigned TargetSize; + + /// Flags describing additional information on this fixup kind. + unsigned Flags; +}; + +} // End llvm namespace + +#endif diff --git a/include/llvm/MC/MCInst.h b/include/llvm/MC/MCInst.h index dc630fe2807f..d6ef7b4c33c1 100644 --- a/include/llvm/MC/MCInst.h +++ b/include/llvm/MC/MCInst.h @@ -18,7 +18,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { class raw_ostream; @@ -33,24 +33,27 @@ class MCOperand { kInvalid, ///< Uninitialized. kRegister, ///< Register operand. kImmediate, ///< Immediate operand. + kFPImmediate, ///< Floating-point immediate operand. kExpr ///< Relocatable immediate operand. }; unsigned char Kind; - + union { unsigned RegVal; int64_t ImmVal; + double FPImmVal; const MCExpr *ExprVal; }; public: - - MCOperand() : Kind(kInvalid) {} + + MCOperand() : Kind(kInvalid), FPImmVal(0.0) {} bool isValid() const { return Kind != kInvalid; } bool isReg() const { return Kind == kRegister; } bool isImm() const { return Kind == kImmediate; } + bool isFPImm() const { return Kind == kFPImmediate; } bool isExpr() const { return Kind == kExpr; } - + /// getReg - Returns the register number. unsigned getReg() const { assert(isReg() && "This is not a register operand!"); @@ -62,7 +65,7 @@ public: assert(isReg() && "This is not a register operand!"); RegVal = Reg; } - + int64_t getImm() const { assert(isImm() && "This is not an immediate"); return ImmVal; @@ -71,7 +74,17 @@ public: assert(isImm() && "This is not an immediate"); ImmVal = Val; } - + + double getFPImm() const { + assert(isFPImm() && "This is not an FP immediate"); + return FPImmVal; + } + + void setFPImm(double Val) { + assert(isFPImm() && "This is not an FP immediate"); + FPImmVal = Val; + } + const MCExpr *getExpr() const { assert(isExpr() && "This is not an expression"); return ExprVal; @@ -80,7 +93,7 @@ public: assert(isExpr() && "This is not an expression"); ExprVal = Val; } - + static MCOperand CreateReg(unsigned Reg) { MCOperand Op; Op.Kind = kRegister; @@ -93,6 +106,12 @@ public: Op.ImmVal = Val; return Op; } + static MCOperand CreateFPImm(double Val) { + MCOperand Op; + Op.Kind = kFPImmediate; + Op.FPImmVal = Val; + return Op; + } static MCOperand CreateExpr(const MCExpr *Val) { MCOperand Op; Op.Kind = kExpr; @@ -104,23 +123,23 @@ public: void dump() const; }; - + /// MCInst - Instances of this class represent a single low-level machine -/// instruction. +/// instruction. class MCInst { unsigned Opcode; SmallVector Operands; public: MCInst() : Opcode(0) {} - + void setOpcode(unsigned Op) { Opcode = Op; } - + unsigned getOpcode() const { return Opcode; } const MCOperand &getOperand(unsigned i) const { return Operands[i]; } MCOperand &getOperand(unsigned i) { return Operands[i]; } unsigned getNumOperands() const { return Operands.size(); } - + void addOperand(const MCOperand &Op) { Operands.push_back(Op); } @@ -136,6 +155,15 @@ public: StringRef Separator = " ") const; }; +inline raw_ostream& operator<<(raw_ostream &OS, const MCOperand &MO) { + MO.print(OS, 0); + return OS; +} + +inline raw_ostream& operator<<(raw_ostream &OS, const MCInst &MI) { + MI.print(OS, 0); + return OS; +} } // end namespace llvm diff --git a/include/llvm/MC/MCInstPrinter.h b/include/llvm/MC/MCInstPrinter.h index 4839a83dba5c..96716c775fdf 100644 --- a/include/llvm/MC/MCInstPrinter.h +++ b/include/llvm/MC/MCInstPrinter.h @@ -28,21 +28,21 @@ protected: public: MCInstPrinter(const MCAsmInfo &mai) : CommentStream(0), MAI(mai) {} - + virtual ~MCInstPrinter(); /// setCommentStream - Specify a stream to emit comments to. void setCommentStream(raw_ostream &OS) { CommentStream = &OS; } - + /// printInst - Print the specified MCInst to the specified raw_ostream. /// virtual void printInst(const MCInst *MI, raw_ostream &OS) = 0; - + /// getOpcodeName - Return the name of the specified opcode enum (e.g. /// "MOV32ri") or empty if we can't resolve it. virtual StringRef getOpcodeName(unsigned Opcode) const; }; - + } // namespace llvm #endif diff --git a/include/llvm/MC/MCMachOSymbolFlags.h b/include/llvm/MC/MCMachOSymbolFlags.h index c938c81f698c..696436dffa6e 100644 --- a/include/llvm/MC/MCMachOSymbolFlags.h +++ b/include/llvm/MC/MCMachOSymbolFlags.h @@ -34,9 +34,11 @@ namespace llvm { SF_ReferenceTypePrivateUndefinedLazy = 0x0005, // Other 'desc' flags. + SF_ThumbFunc = 0x0008, SF_NoDeadStrip = 0x0020, SF_WeakReference = 0x0040, - SF_WeakDefinition = 0x0080 + SF_WeakDefinition = 0x0080, + SF_SymbolResolver = 0x0100 }; } // end namespace llvm diff --git a/include/llvm/MC/MCMachObjectWriter.h b/include/llvm/MC/MCMachObjectWriter.h new file mode 100644 index 000000000000..ec51031d0bb3 --- /dev/null +++ b/include/llvm/MC/MCMachObjectWriter.h @@ -0,0 +1,65 @@ +//===-- llvm/MC/MCMachObjectWriter.h - Mach Object Writer -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCMACHOBJECTWRITER_H +#define LLVM_MC_MCMACHOBJECTWRITER_H + +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/Support/DataTypes.h" + +namespace llvm { + +class MCMachObjectTargetWriter { + const unsigned Is64Bit : 1; + const uint32_t CPUType; + const uint32_t CPUSubtype; + // FIXME: Remove this, we should just always use it once we no longer care + // about Darwin 'as' compatibility. + const unsigned UseAggressiveSymbolFolding : 1; + unsigned LocalDifference_RIT; + +protected: + MCMachObjectTargetWriter(bool Is64Bit_, uint32_t CPUType_, + uint32_t CPUSubtype_, + bool UseAggressiveSymbolFolding_ = false); + + void setLocalDifferenceRelocationType(unsigned Type) { + LocalDifference_RIT = Type; + } + +public: + virtual ~MCMachObjectTargetWriter(); + + /// @name Accessors + /// @{ + + bool is64Bit() const { return Is64Bit; } + bool useAggressiveSymbolFolding() const { return UseAggressiveSymbolFolding; } + uint32_t getCPUType() const { return CPUType; } + uint32_t getCPUSubtype() const { return CPUSubtype; } + unsigned getLocalDifferenceRelocationType() const { + return LocalDifference_RIT; + } + + /// @} +}; + +/// \brief Construct a new Mach-O writer instance. +/// +/// This routine takes ownership of the target writer subclass. +/// +/// \param MOTW - The target specific Mach-O writer subclass. +/// \param OS - The stream to write to. +/// \returns The constructed object writer. +MCObjectWriter *createMachObjectWriter(MCMachObjectTargetWriter *MOTW, + raw_ostream &OS, bool IsLittleEndian); + +} // End llvm namespace + +#endif diff --git a/include/llvm/MC/MCObjectStreamer.h b/include/llvm/MC/MCObjectStreamer.h index ea6d9c12338d..833341eb97f5 100644 --- a/include/llvm/MC/MCObjectStreamer.h +++ b/include/llvm/MC/MCObjectStreamer.h @@ -33,6 +33,8 @@ class MCObjectStreamer : public MCStreamer { MCAssembler *Assembler; MCSectionData *CurSectionData; + virtual void EmitInstToData(const MCInst &Inst) = 0; + protected: MCObjectStreamer(MCContext &Context, TargetAsmBackend &TAB, raw_ostream &_OS, MCCodeEmitter *_Emitter); @@ -56,7 +58,21 @@ public: /// @name MCStreamer Interface /// @{ - virtual void SwitchSection(const MCSection *Section); + virtual void EmitLabel(MCSymbol *Symbol); + virtual void EmitValueImpl(const MCExpr *Value, unsigned Size, + bool isPCRel, unsigned AddrSpace); + virtual void EmitULEB128Value(const MCExpr *Value, unsigned AddrSpace = 0); + virtual void EmitSLEB128Value(const MCExpr *Value, unsigned AddrSpace = 0); + virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol); + virtual void ChangeSection(const MCSection *Section); + virtual void EmitInstruction(const MCInst &Inst); + virtual void EmitInstToFragment(const MCInst &Inst); + virtual void EmitValueToOffset(const MCExpr *Offset, unsigned char Value); + virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label); + virtual void EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel, + const MCSymbol *Label); virtual void Finish(); /// @} diff --git a/include/llvm/MC/MCObjectWriter.h b/include/llvm/MC/MCObjectWriter.h index f1c1cb8a5991..782d844598b4 100644 --- a/include/llvm/MC/MCObjectWriter.h +++ b/include/llvm/MC/MCObjectWriter.h @@ -10,8 +10,9 @@ #ifndef LLVM_MC_MCOBJECTWRITER_H #define LLVM_MC_MCOBJECTWRITER_H +#include "llvm/ADT/Triple.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include namespace llvm { @@ -19,6 +20,9 @@ class MCAsmLayout; class MCAssembler; class MCFixup; class MCFragment; +class MCSymbol; +class MCSymbolData; +class MCSymbolRefExpr; class MCValue; class raw_ostream; @@ -61,7 +65,8 @@ public: /// /// This routine is called by the assembler after layout and relaxation is /// complete. - virtual void ExecutePostLayoutBinding(MCAssembler &Asm) = 0; + virtual void ExecutePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout) = 0; /// Record a relocation entry. /// @@ -75,12 +80,31 @@ public: const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) = 0; + /// \brief Check whether the difference (A - B) between two symbol + /// references is fully resolved. + /// + /// Clients are not required to answer precisely and may conservatively return + /// false, even when a difference is fully resolved. + bool + IsSymbolRefDifferenceFullyResolved(const MCAssembler &Asm, + const MCSymbolRefExpr *A, + const MCSymbolRefExpr *B, + bool InSet) const; + + virtual bool + IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, + const MCSymbolData &DataA, + const MCFragment &FB, + bool InSet, + bool IsPCRel) const; + + /// Write the object file. /// /// This routine is called by the assembler after layout and relaxation is /// complete, fixups have been evaluated and applied, and relocations /// generated. - virtual void WriteObject(const MCAssembler &Asm, + virtual void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout) = 0; /// @} @@ -160,6 +184,11 @@ public: } /// @} + + /// Utility function to encode a SLEB128 value. + static void EncodeSLEB128(int64_t Value, raw_ostream &OS); + /// Utility function to encode a ULEB128 value. + static void EncodeULEB128(uint64_t Value, raw_ostream &OS); }; MCObjectWriter *createWinCOFFObjectWriter(raw_ostream &OS, bool is64Bit); diff --git a/include/llvm/MC/MCParser/AsmLexer.h b/include/llvm/MC/MCParser/AsmLexer.h index 21878899cac1..252696bec317 100644 --- a/include/llvm/MC/MCParser/AsmLexer.h +++ b/include/llvm/MC/MCParser/AsmLexer.h @@ -17,7 +17,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCAsmInfo.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include #include @@ -29,10 +29,10 @@ class MCAsmInfo; /// AsmLexer - Lexer class for assembly files. class AsmLexer : public MCAsmLexer { const MCAsmInfo &MAI; - + const char *CurPtr; const MemoryBuffer *CurBuf; - + void operator=(const AsmLexer&); // DO NOT IMPLEMENT AsmLexer(const AsmLexer&); // DO NOT IMPLEMENT @@ -43,13 +43,13 @@ protected: public: AsmLexer(const MCAsmInfo &MAI); ~AsmLexer(); - + void setBuffer(const MemoryBuffer *buf, const char *ptr = NULL); - + virtual StringRef LexUntilEndOfStatement(); bool isAtStartOfComment(char Char); - + const MCAsmInfo &getMAI() const { return MAI; } private: @@ -60,9 +60,11 @@ private: AsmToken LexSlash(); AsmToken LexLineComment(); AsmToken LexDigit(); + AsmToken LexSingleQuote(); AsmToken LexQuote(); + AsmToken LexFloatLiteral(); }; - + } // end namespace llvm #endif diff --git a/include/llvm/MC/MCParser/MCAsmLexer.h b/include/llvm/MC/MCParser/MCAsmLexer.h index d690e810bd39..606725a98515 100644 --- a/include/llvm/MC/MCParser/MCAsmLexer.h +++ b/include/llvm/MC/MCParser/MCAsmLexer.h @@ -11,7 +11,7 @@ #define LLVM_MC_MCASMLEXER_H #include "llvm/ADT/StringRef.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/Support/SMLoc.h" namespace llvm { @@ -29,13 +29,16 @@ public: // String values. Identifier, String, - + // Integer values. Integer, - + + // Real values. + Real, + // Register values (stored in IntVal). Only used by TargetAsmLexer. Register, - + // No-value. EndOfStatement, Colon, @@ -43,8 +46,8 @@ public: Slash, // '/' LParen, RParen, LBrac, RBrac, LCurly, RCurly, Star, Dot, Comma, Dollar, Equal, EqualEqual, - - Pipe, PipePipe, Caret, + + Pipe, PipePipe, Caret, Amp, AmpAmp, Exclaim, ExclaimEqual, Percent, Hash, Less, LessEqual, LessLess, LessGreater, Greater, GreaterEqual, GreaterGreater, At @@ -70,7 +73,7 @@ public: SMLoc getLoc() const; /// getStringContents - Get the contents of a string token (without quotes). - StringRef getStringContents() const { + StringRef getStringContents() const { assert(Kind == String && "This token isn't a string!"); return Str.slice(1, Str.size() - 1); } @@ -95,11 +98,11 @@ public: // FIXME: Don't compute this in advance, it makes every token larger, and is // also not generally what we want (it is nicer for recovery etc. to lex 123br // as a single token, then diagnose as an invalid number). - int64_t getIntVal() const { + int64_t getIntVal() const { assert(Kind == Integer && "This token isn't an integer!"); - return IntVal; + return IntVal; } - + /// getRegVal - Get the register number for the current token, which should /// be a register. unsigned getRegVal() const { @@ -113,7 +116,7 @@ public: class MCAsmLexer { /// The current token, stored in the base class for faster access. AsmToken CurTok; - + /// The location and description of the current error SMLoc ErrLoc; std::string Err; @@ -126,12 +129,12 @@ protected: // Can only create subclasses. MCAsmLexer(); virtual AsmToken LexToken() = 0; - + void SetError(const SMLoc &errLoc, const std::string &err) { ErrLoc = errLoc; Err = err; } - + public: virtual ~MCAsmLexer(); @@ -152,12 +155,12 @@ public: const AsmToken &getTok() { return CurTok; } - + /// getErrLoc - Get the current error location const SMLoc &getErrLoc() { return ErrLoc; } - + /// getErr - Get the current error string const std::string &getErr() { return Err; diff --git a/include/llvm/MC/MCParser/MCAsmParser.h b/include/llvm/MC/MCParser/MCAsmParser.h index b37d46cc5a25..54979d977db7 100644 --- a/include/llvm/MC/MCParser/MCAsmParser.h +++ b/include/llvm/MC/MCParser/MCAsmParser.h @@ -10,7 +10,7 @@ #ifndef LLVM_MC_MCASMPARSER_H #define LLVM_MC_MCASMPARSER_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { class AsmToken; @@ -99,6 +99,10 @@ public: /// will be either the EndOfStatement or EOF. virtual StringRef ParseStringToEndOfStatement() = 0; + /// EatToEndOfStatement - Skip to the end of the current statement, for error + /// recovery. + virtual void EatToEndOfStatement() = 0; + /// ParseExpression - Parse an arbitrary expression. /// /// @param Res - The value of the expression. The result is undefined diff --git a/include/llvm/MC/MCParser/MCParsedAsmOperand.h b/include/llvm/MC/MCParser/MCParsedAsmOperand.h index 99fa5adae977..91f5773b8df8 100644 --- a/include/llvm/MC/MCParser/MCParsedAsmOperand.h +++ b/include/llvm/MC/MCParser/MCParsedAsmOperand.h @@ -19,10 +19,10 @@ class raw_ostream; /// base class is used by target-independent clients and is the interface /// between parsing an asm instruction and recognizing it. class MCParsedAsmOperand { -public: +public: MCParsedAsmOperand() {} virtual ~MCParsedAsmOperand() {} - + /// getStartLoc - Get the location of the first token of this operand. virtual SMLoc getStartLoc() const = 0; /// getEndLoc - Get the location of the last token of this operand. diff --git a/include/llvm/MC/MCSection.h b/include/llvm/MC/MCSection.h index 5c997357c9d3..1c01b2f8f3cc 100644 --- a/include/llvm/MC/MCSection.h +++ b/include/llvm/MC/MCSection.h @@ -32,8 +32,7 @@ namespace llvm { enum SectionVariant { SV_COFF = 0, SV_ELF, - SV_MachO, - SV_PIC16 + SV_MachO }; private: @@ -61,6 +60,14 @@ namespace llvm { return false; } + // UseCodeAlign - Return true if a .align directive should use + // "optimized nops" to fill instead of 0s. + virtual bool UseCodeAlign() const = 0; + + /// isVirtualSection - Check whether this section is "virtual", that is + /// has no actual object file contents. + virtual bool isVirtualSection() const = 0; + static bool classof(const MCSection *) { return true; } }; diff --git a/include/llvm/MC/MCSectionCOFF.h b/include/llvm/MC/MCSectionCOFF.h index f828e1060fe6..b154cf59d106 100644 --- a/include/llvm/MC/MCSectionCOFF.h +++ b/include/llvm/MC/MCSectionCOFF.h @@ -19,12 +19,12 @@ #include "llvm/Support/COFF.h" namespace llvm { - + /// MCSectionCOFF - This represents a section on Windows class MCSectionCOFF : public MCSection { // The memory for this string is stored in the same MCContext as *this. StringRef SectionName; - + /// Characteristics - This is the Characteristics field of a section, // drawn from the enums below. unsigned Characteristics; @@ -52,9 +52,11 @@ namespace llvm { StringRef getSectionName() const { return SectionName; } unsigned getCharacteristics() const { return Characteristics; } int getSelection () const { return Selection; } - + virtual void PrintSwitchToSection(const MCAsmInfo &MAI, raw_ostream &OS) const; + virtual bool UseCodeAlign() const; + virtual bool isVirtualSection() const; static bool classof(const MCSection *S) { return S->getVariant() == SV_COFF; diff --git a/include/llvm/MC/MCSectionELF.h b/include/llvm/MC/MCSectionELF.h index 5de0bf58fe0c..c82de7128202 100644 --- a/include/llvm/MC/MCSectionELF.h +++ b/include/llvm/MC/MCSectionELF.h @@ -15,38 +15,39 @@ #define LLVM_MC_MCSECTIONELF_H #include "llvm/MC/MCSection.h" +#include "llvm/Support/ELF.h" namespace llvm { - + +class MCSymbol; + /// MCSectionELF - This represents a section on linux, lots of unix variants /// and some bare metal systems. class MCSectionELF : public MCSection { /// SectionName - This is the name of the section. The referenced memory is /// owned by TargetLoweringObjectFileELF's ELFUniqueMap. StringRef SectionName; - + /// Type - This is the sh_type field of a section, drawn from the enums below. unsigned Type; - + /// Flags - This is the sh_flags field of a section, drawn from the enums. /// below. unsigned Flags; - /// IsExplicit - Indicates that this section comes from globals with an - /// explicit section specified. - bool IsExplicit; - /// EntrySize - The size of each entry in this section. This size only /// makes sense for sections that contain fixed-sized entries. If a /// section does not contain fixed-sized entries 'EntrySize' will be 0. unsigned EntrySize; - + + const MCSymbol *Group; + private: friend class MCContext; MCSectionELF(StringRef Section, unsigned type, unsigned flags, - SectionKind K, bool isExplicit, unsigned entrySize) + SectionKind K, unsigned entrySize, const MCSymbol *group) : MCSection(SV_ELF, K), SectionName(Section), Type(type), Flags(flags), - IsExplicit(isExplicit), EntrySize(entrySize) {} + EntrySize(entrySize), Group(group) {} ~MCSectionELF(); public: @@ -54,141 +55,31 @@ public: /// should be printed before the section name bool ShouldOmitSectionDirective(StringRef Name, const MCAsmInfo &MAI) const; - /// ShouldPrintSectionType - Only prints the section type if supported - bool ShouldPrintSectionType(unsigned Ty) const; - - /// HasCommonSymbols - True if this section holds common symbols, this is - /// indicated on the ELF object file by a symbol with SHN_COMMON section - /// header index. - bool HasCommonSymbols() const; - - /// These are the section type and flags fields. An ELF section can have - /// only one Type, but can have more than one of the flags specified. - /// - /// Valid section types. - enum { - // This value marks the section header as inactive. - SHT_NULL = 0x00U, - - // Holds information defined by the program, with custom format and meaning. - SHT_PROGBITS = 0x01U, - - // This section holds a symbol table. - SHT_SYMTAB = 0x02U, - - // The section holds a string table. - SHT_STRTAB = 0x03U, - - // The section holds relocation entries with explicit addends. - SHT_RELA = 0x04U, - - // The section holds a symbol hash table. - SHT_HASH = 0x05U, - - // Information for dynamic linking. - SHT_DYNAMIC = 0x06U, - - // The section holds information that marks the file in some way. - SHT_NOTE = 0x07U, - - // A section of this type occupies no space in the file. - SHT_NOBITS = 0x08U, - - // The section holds relocation entries without explicit addends. - SHT_REL = 0x09U, - - // This section type is reserved but has unspecified semantics. - SHT_SHLIB = 0x0AU, - - // This section holds a symbol table. - SHT_DYNSYM = 0x0BU, - - // This section contains an array of pointers to initialization functions. - SHT_INIT_ARRAY = 0x0EU, - - // This section contains an array of pointers to termination functions. - SHT_FINI_ARRAY = 0x0FU, - - // This section contains an array of pointers to functions that are invoked - // before all other initialization functions. - SHT_PREINIT_ARRAY = 0x10U, - - // A section group is a set of sections that are related and that must be - // treated specially by the linker. - SHT_GROUP = 0x11U, - - // This section is associated with a section of type SHT_SYMTAB, when the - // referenced symbol table contain the escape value SHN_XINDEX - SHT_SYMTAB_SHNDX = 0x12U, - - LAST_KNOWN_SECTION_TYPE = SHT_SYMTAB_SHNDX - }; - - /// Valid section flags. - enum { - // The section contains data that should be writable. - SHF_WRITE = 0x1U, - - // The section occupies memory during execution. - SHF_ALLOC = 0x2U, - - // The section contains executable machine instructions. - SHF_EXECINSTR = 0x4U, - - // The data in the section may be merged to eliminate duplication. - SHF_MERGE = 0x10U, - - // Elements in the section consist of null-terminated character strings. - SHF_STRINGS = 0x20U, - - // A field in this section holds a section header table index. - SHF_INFO_LINK = 0x40U, - - // Adds special ordering requirements for link editors. - SHF_LINK_ORDER = 0x80U, - - // This section requires special OS-specific processing to avoid incorrect - // behavior. - SHF_OS_NONCONFORMING = 0x100U, - - // This section is a member of a section group. - SHF_GROUP = 0x200U, - - // This section holds Thread-Local Storage. - SHF_TLS = 0x400U, - - - // Start of target-specific flags. - - /// XCORE_SHF_CP_SECTION - All sections with the "c" flag are grouped - /// together by the linker to form the constant pool and the cp register is - /// set to the start of the constant pool by the boot code. - XCORE_SHF_CP_SECTION = 0x800U, - - /// XCORE_SHF_DP_SECTION - All sections with the "d" flag are grouped - /// together by the linker to form the data section and the dp register is - /// set to the start of the section by the boot code. - XCORE_SHF_DP_SECTION = 0x1000U - }; - StringRef getSectionName() const { return SectionName; } unsigned getType() const { return Type; } unsigned getFlags() const { return Flags; } unsigned getEntrySize() const { return EntrySize; } - + const MCSymbol *getGroup() const { return Group; } + void PrintSwitchToSection(const MCAsmInfo &MAI, raw_ostream &OS) const; - + virtual bool UseCodeAlign() const; + virtual bool isVirtualSection() const; + /// isBaseAddressKnownZero - We know that non-allocatable sections (like /// debug info) have a base of zero. virtual bool isBaseAddressKnownZero() const { - return (getFlags() & SHF_ALLOC) == 0; + return (getFlags() & ELF::SHF_ALLOC) == 0; } static bool classof(const MCSection *S) { return S->getVariant() == SV_ELF; } static bool classof(const MCSectionELF *) { return true; } + + // Return the entry size for sections with fixed-width data. + static unsigned DetermineEntrySize(SectionKind Kind); + }; } // end namespace llvm diff --git a/include/llvm/MC/MCSectionMachO.h b/include/llvm/MC/MCSectionMachO.h index 2d9d1333dbe2..7633515f2744 100644 --- a/include/llvm/MC/MCSectionMachO.h +++ b/include/llvm/MC/MCSectionMachO.h @@ -17,36 +17,36 @@ #include "llvm/MC/MCSection.h" namespace llvm { - + /// MCSectionMachO - This represents a section on a Mach-O system (used by /// Mac OS X). On a Mac system, these are also described in /// /usr/include/mach-o/loader.h. class MCSectionMachO : public MCSection { char SegmentName[16]; // Not necessarily null terminated! char SectionName[16]; // Not necessarily null terminated! - + /// TypeAndAttributes - This is the SECTION_TYPE and SECTION_ATTRIBUTES /// field of a section, drawn from the enums below. unsigned TypeAndAttributes; - + /// Reserved2 - The 'reserved2' field of a section, used to represent the /// size of stubs, for example. unsigned Reserved2; - + MCSectionMachO(StringRef Segment, StringRef Section, - unsigned TAA, unsigned reserved2, SectionKind K); + unsigned TAA, unsigned reserved2, SectionKind K); friend class MCContext; public: - + /// These are the section type and attributes fields. A MachO section can /// have only one Type, but can have any of the attributes specified. enum { // TypeAndAttributes bitmasks. SECTION_TYPE = 0x000000FFU, SECTION_ATTRIBUTES = 0xFFFFFF00U, - + // Valid section types. - + /// S_REGULAR - Regular section. S_REGULAR = 0x00U, /// S_ZEROFILL - Zero fill on demand section. @@ -101,10 +101,10 @@ public: S_THREAD_LOCAL_INIT_FUNCTION_POINTERS = 0x15U, LAST_KNOWN_SECTION_TYPE = S_THREAD_LOCAL_INIT_FUNCTION_POINTERS, - + // Valid section attributes. - + /// S_ATTR_PURE_INSTRUCTIONS - Section contains only true machine /// instructions. S_ATTR_PURE_INSTRUCTIONS = 1U << 31, @@ -165,6 +165,8 @@ public: virtual void PrintSwitchToSection(const MCAsmInfo &MAI, raw_ostream &OS) const; + virtual bool UseCodeAlign() const; + virtual bool isVirtualSection() const; static bool classof(const MCSection *S) { return S->getVariant() == SV_MachO; diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index 1ce1b0e09d4a..fc2451f9c19c 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -14,8 +14,10 @@ #ifndef LLVM_MC_MCSTREAMER_H #define LLVM_MC_MCSTREAMER_H -#include "llvm/System/DataTypes.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/DataTypes.h" #include "llvm/MC/MCDirectives.h" +#include "llvm/MC/MCDwarf.h" namespace llvm { class MCAsmInfo; @@ -28,6 +30,7 @@ namespace llvm { class MCSymbol; class StringRef; class TargetAsmBackend; + class TargetLoweringObjectFile; class Twine; class raw_ostream; class formatted_raw_ostream; @@ -47,29 +50,44 @@ namespace llvm { MCStreamer(const MCStreamer&); // DO NOT IMPLEMENT MCStreamer &operator=(const MCStreamer&); // DO NOT IMPLEMENT - protected: - MCStreamer(MCContext &Ctx); + void EmitSymbolValue(const MCSymbol *Sym, unsigned Size, + bool isPCRel, unsigned AddrSpace); + + std::vector FrameInfos; + MCDwarfFrameInfo *getCurrentFrameInfo(); + void EnsureValidFrame(); + + /// CurSectionStack - This is stack of CurSection values saved by + /// PushSection. + SmallVector CurSectionStack; - /// CurSection - This is the current section code is being emitted to, it is - /// kept up to date by SwitchSection. - const MCSection *CurSection; + /// PrevSectionStack - This is stack of PrevSection values saved by + /// PushSection. + SmallVector PrevSectionStack; - /// PrevSection - This is the previous section code is being emitted to, it is - /// kept up to date by SwitchSection. - const MCSection *PrevSection; + protected: + MCStreamer(MCContext &Ctx); public: virtual ~MCStreamer(); MCContext &getContext() const { return Context; } + unsigned getNumFrameInfos() { + return FrameInfos.size(); + } + + const MCDwarfFrameInfo &getFrameInfo(unsigned i) { + return FrameInfos[i]; + } + /// @name Assembly File Formatting. /// @{ - + /// isVerboseAsm - Return true if this streamer supports verbose assembly /// and if it is enabled. virtual bool isVerboseAsm() const { return false; } - + /// hasRawTextSupport - Return true if this asm streamer supports emitting /// unformatted text to the .s file with EmitRawText. virtual bool hasRawTextSupport() const { return false; } @@ -82,34 +100,83 @@ namespace llvm { /// If the comment includes embedded \n's, they will each get the comment /// prefix as appropriate. The added comment should not end with a \n. virtual void AddComment(const Twine &T) {} - + /// GetCommentOS - Return a raw_ostream that comments can be written to. /// Unlike AddComment, you are required to terminate comments with \n if you /// use this method. virtual raw_ostream &GetCommentOS(); - + /// AddBlankLine - Emit a blank line to a .s file to pretty it up. virtual void AddBlankLine() {} - + /// @} - + /// @name Symbol & Section Management /// @{ - + /// getCurrentSection - Return the current section that the streamer is /// emitting code to. - const MCSection *getCurrentSection() const { return CurSection; } + const MCSection *getCurrentSection() const { + if (!CurSectionStack.empty()) + return CurSectionStack.back(); + return NULL; + } /// getPreviousSection - Return the previous section that the streamer is /// emitting code to. - const MCSection *getPreviousSection() const { return PrevSection; } + const MCSection *getPreviousSection() const { + if (!PrevSectionStack.empty()) + return PrevSectionStack.back(); + return NULL; + } + + /// ChangeSection - Update streamer for a new active section. + /// + /// This is called by PopSection and SwitchSection, if the current + /// section changes. + virtual void ChangeSection(const MCSection *) = 0; + + /// pushSection - Save the current and previous section on the + /// section stack. + void PushSection() { + PrevSectionStack.push_back(getPreviousSection()); + CurSectionStack.push_back(getCurrentSection()); + } + + /// popSection - Restore the current and previous section from + /// the section stack. Calls ChangeSection as needed. + /// + /// Returns false if the stack was empty. + bool PopSection() { + if (PrevSectionStack.size() <= 1) + return false; + assert(CurSectionStack.size() > 1); + PrevSectionStack.pop_back(); + const MCSection *oldSection = CurSectionStack.pop_back_val(); + const MCSection *curSection = CurSectionStack.back(); + + if (oldSection != curSection) + ChangeSection(curSection); + return true; + } /// SwitchSection - Set the current section where code is being emitted to /// @p Section. This is required to update CurSection. /// /// This corresponds to assembler directives like .section, .text, etc. - virtual void SwitchSection(const MCSection *Section) = 0; - + void SwitchSection(const MCSection *Section) { + assert(Section && "Cannot switch to a null section!"); + const MCSection *curSection = CurSectionStack.back(); + PrevSectionStack.back() = curSection; + if (Section != curSection) { + CurSectionStack.back() = Section; + ChangeSection(Section); + } + } + + /// InitSections - Create the default sections and set the initial one. + virtual void InitSections() = 0; + /// EmitLabel - Emit a label for @p Symbol into the current section. /// /// This corresponds to an assembler statement such as: @@ -123,6 +190,10 @@ namespace llvm { /// EmitAssemblerFlag - Note in the output the specified @p Flag virtual void EmitAssemblerFlag(MCAssemblerFlag Flag) = 0; + /// EmitThumbFunc - Note in the output that the specified @p Func is + /// a Thumb mode function (ARM target only). + virtual void EmitThumbFunc(MCSymbol *Func) = 0; + /// EmitAssignment - Emit an assignment of @p Value to @p Symbol. /// /// This corresponds to an assembler statement such as: @@ -136,6 +207,15 @@ namespace llvm { /// @param Value - The value for the symbol. virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) = 0; + /// EmitWeakReference - Emit an weak reference from @p Alias to @p Symbol. + /// + /// This corresponds to an assembler statement such as: + /// .weakref alias, symbol + /// + /// @param Alias - The alias that is being created. + /// @param Symbol - The symbol being aliased. + virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) = 0; + /// EmitSymbolAttribute - Add the given @p Attribute to @p Symbol. virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) = 0; @@ -170,7 +250,7 @@ namespace llvm { /// .size symbol, expression /// virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) = 0; - + /// EmitCommonSymbol - Emit a common symbol. /// /// @param Symbol - The common symbol to emit. @@ -185,7 +265,7 @@ namespace llvm { /// @param Symbol - The common symbol to emit. /// @param Size - The size of the common symbol. virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) = 0; - + /// EmitZerofill - Emit the zerofill section and an optional symbol. /// /// @param Section - The zerofill section to create and or to put the symbol @@ -204,7 +284,7 @@ namespace llvm { /// @param ByteAlignment - The alignment of the thread local common symbol /// if non-zero. This must be a power of 2 on some targets. virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, - uint64_t Size, unsigned ByteAlignment = 0) = 0; + uint64_t Size, unsigned ByteAlignment = 0) = 0; /// @} /// @name Generating Data /// @{ @@ -224,38 +304,67 @@ namespace llvm { /// @param Value - The value to emit. /// @param Size - The size of the integer (in bytes) to emit. This must /// match a native machine width. - virtual void EmitValue(const MCExpr *Value, unsigned Size, - unsigned AddrSpace = 0) = 0; + virtual void EmitValueImpl(const MCExpr *Value, unsigned Size, + bool isPCRel, unsigned AddrSpace) = 0; + + void EmitValue(const MCExpr *Value, unsigned Size, unsigned AddrSpace = 0); + + void EmitPCRelValue(const MCExpr *Value, unsigned Size, + unsigned AddrSpace = 0); /// EmitIntValue - Special case of EmitValue that avoids the client having /// to pass in a MCExpr for constant integers. virtual void EmitIntValue(uint64_t Value, unsigned Size, unsigned AddrSpace = 0); - + + /// EmitAbsValue - Emit the Value, but try to avoid relocations. On MachO + /// this is done by producing + /// foo = value + /// .long foo + void EmitAbsValue(const MCExpr *Value, unsigned Size, + unsigned AddrSpace = 0); + + virtual void EmitULEB128Value(const MCExpr *Value, + unsigned AddrSpace = 0) = 0; + + virtual void EmitSLEB128Value(const MCExpr *Value, + unsigned AddrSpace = 0) = 0; + + /// EmitULEB128Value - Special case of EmitULEB128Value that avoids the + /// client having to pass in a MCExpr for constant integers. + void EmitULEB128IntValue(uint64_t Value, unsigned AddrSpace = 0); + + /// EmitSLEB128Value - Special case of EmitSLEB128Value that avoids the + /// client having to pass in a MCExpr for constant integers. + void EmitSLEB128IntValue(int64_t Value, unsigned AddrSpace = 0); + /// EmitSymbolValue - Special case of EmitValue that avoids the client /// having to pass in a MCExpr for MCSymbols. - virtual void EmitSymbolValue(const MCSymbol *Sym, unsigned Size, - unsigned AddrSpace); - + void EmitSymbolValue(const MCSymbol *Sym, unsigned Size, + unsigned AddrSpace = 0); + + void EmitPCRelSymbolValue(const MCSymbol *Sym, unsigned Size, + unsigned AddrSpace = 0); + /// EmitGPRel32Value - Emit the expression @p Value into the output as a /// gprel32 (32-bit GP relative) value. /// /// This is used to implement assembler directives such as .gprel32 on /// targets that support them. - virtual void EmitGPRel32Value(const MCExpr *Value) = 0; - + virtual void EmitGPRel32Value(const MCExpr *Value); + /// EmitFill - Emit NumBytes bytes worth of the value specified by /// FillValue. This implements directives such as '.space'. virtual void EmitFill(uint64_t NumBytes, uint8_t FillValue, unsigned AddrSpace); - + /// EmitZeros - Emit NumBytes worth of zeros. This is a convenience /// function that just wraps EmitFill. void EmitZeros(uint64_t NumBytes, unsigned AddrSpace) { EmitFill(NumBytes, 0, AddrSpace); } - + /// EmitValueToAlignment - Emit some number of copies of @p Value until /// the byte alignment @p ByteAlignment is reached. /// @@ -301,17 +410,47 @@ namespace llvm { /// @param Value - The value to use when filling bytes. virtual void EmitValueToOffset(const MCExpr *Offset, unsigned char Value = 0) = 0; - + /// @} - + /// EmitFileDirective - Switch to a new logical file. This is used to /// implement the '.file "foo.c"' assembler directive. virtual void EmitFileDirective(StringRef Filename) = 0; - + /// EmitDwarfFileDirective - Associate a filename with a specified logical /// file number. This implements the DWARF2 '.file 4 "foo.c"' assembler /// directive. - virtual void EmitDwarfFileDirective(unsigned FileNo,StringRef Filename) = 0; + virtual bool EmitDwarfFileDirective(unsigned FileNo,StringRef Filename); + + /// EmitDwarfLocDirective - This implements the DWARF2 + // '.loc fileno lineno ...' assembler directive. + virtual void EmitDwarfLocDirective(unsigned FileNo, unsigned Line, + unsigned Column, unsigned Flags, + unsigned Isa, + unsigned Discriminator); + + virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label) = 0; + + virtual void EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel, + const MCSymbol *Label) { + } + + void EmitDwarfSetLineAddr(int64_t LineDelta, const MCSymbol *Label, + int PointerSize); + + virtual bool EmitCFIStartProc(); + virtual bool EmitCFIEndProc(); + virtual bool EmitCFIDefCfa(int64_t Register, int64_t Offset); + virtual bool EmitCFIDefCfaOffset(int64_t Offset); + virtual bool EmitCFIDefCfaRegister(int64_t Register); + virtual bool EmitCFIOffset(int64_t Register, int64_t Offset); + virtual bool EmitCFIPersonality(const MCSymbol *Sym, + unsigned Encoding); + virtual bool EmitCFILsda(const MCSymbol *Sym, unsigned Encoding); + virtual bool EmitCFIRememberState(); + virtual bool EmitCFIRestoreState(); /// EmitInstruction - Emit the given @p Instruction into the current /// section. @@ -322,7 +461,7 @@ namespace llvm { /// indicated by the hasRawTextSupport() predicate. By default this aborts. virtual void EmitRawText(StringRef String); void EmitRawText(const Twine &String); - + /// Finish - Finish emission of machine code. virtual void Finish() = 0; }; @@ -342,12 +481,18 @@ namespace llvm { /// \param CE - If given, a code emitter to use to show the instruction /// encoding inline with the assembly. This method takes ownership of \arg CE. /// + /// \param TAB - If given, a target asm backend to use to show the fixup + /// information in conjunction with encoding information. This method takes + /// ownership of \arg TAB. + /// /// \param ShowInst - Whether to show the MCInst representation inline with /// the assembly. MCStreamer *createAsmStreamer(MCContext &Ctx, formatted_raw_ostream &OS, - bool isLittleEndian, bool isVerboseAsm, + bool isVerboseAsm, + bool useLoc, MCInstPrinter *InstPrint = 0, MCCodeEmitter *CE = 0, + TargetAsmBackend *TAB = 0, bool ShowInst = false); /// createMachOStreamer - Create a machine code streamer which will generate @@ -371,7 +516,7 @@ namespace llvm { /// ELF format object files. MCStreamer *createELFStreamer(MCContext &Ctx, TargetAsmBackend &TAB, raw_ostream &OS, MCCodeEmitter *CE, - bool RelaxAll = false); + bool RelaxAll, bool NoExecStack); /// createLoggingStreamer - Create a machine code streamer which just logs the /// API calls and then dispatches to another streamer. @@ -379,6 +524,13 @@ namespace llvm { /// The new streamer takes ownership of the \arg Child. MCStreamer *createLoggingStreamer(MCStreamer *Child, raw_ostream &OS); + /// createPureStreamer - Create a machine code streamer which will generate + /// "pure" MC object files, for use with MC-JIT and testing tools. + /// + /// Takes ownership of \arg TAB and \arg CE. + MCStreamer *createPureStreamer(MCContext &Ctx, TargetAsmBackend &TAB, + raw_ostream &OS, MCCodeEmitter *CE); + } // end namespace llvm #endif diff --git a/include/llvm/MC/MCSymbol.h b/include/llvm/MC/MCSymbol.h index 1b432c2b0a84..7da4d7c15e3b 100644 --- a/include/llvm/MC/MCSymbol.h +++ b/include/llvm/MC/MCSymbol.h @@ -52,15 +52,14 @@ namespace llvm { /// "Lfoo" or ".foo". unsigned IsTemporary : 1; - /// IsUsedInExpr - True if this symbol has been used in an expression and - /// cannot be redefined. - unsigned IsUsedInExpr : 1; + /// IsUsed - True if this symbol has been used. + mutable unsigned IsUsed : 1; private: // MCContext creates and uniques these. friend class MCContext; MCSymbol(StringRef name, bool isTemporary) : Name(name), Section(0), Value(0), - IsTemporary(isTemporary), IsUsedInExpr(false) {} + IsTemporary(isTemporary), IsUsed(false) {} MCSymbol(const MCSymbol&); // DO NOT IMPLEMENT void operator=(const MCSymbol&); // DO NOT IMPLEMENT @@ -74,9 +73,9 @@ namespace llvm { /// isTemporary - Check if this is an assembler temporary symbol. bool isTemporary() const { return IsTemporary; } - /// isUsedInExpr - Check if this is an assembler temporary symbol. - bool isUsedInExpr() const { return IsUsedInExpr; } - void setUsedInExpr(bool Value) { IsUsedInExpr = Value; } + /// isUsed - Check if this is used. + bool isUsed() const { return IsUsed; } + void setUsed(bool Value) const { IsUsed = Value; } /// @} /// @name Associated Sections @@ -135,9 +134,15 @@ namespace llvm { /// getValue() - Get the value for variable symbols. const MCExpr *getVariableValue() const { assert(isVariable() && "Invalid accessor!"); + IsUsed = true; return Value; } + // AliasedSymbol() - If this is an alias (a = b), return the symbol + // we ultimately point to. For a non alias, this just returns the symbol + // itself. + const MCSymbol &AliasedSymbol() const; + void setVariableValue(const MCExpr *Value); /// @} diff --git a/include/llvm/MC/MCValue.h b/include/llvm/MC/MCValue.h index 11b6c2a17b70..df8dbd930bf7 100644 --- a/include/llvm/MC/MCValue.h +++ b/include/llvm/MC/MCValue.h @@ -14,7 +14,7 @@ #ifndef LLVM_MC_MCVALUE_H #define LLVM_MC_MCVALUE_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/MC/MCSymbol.h" #include diff --git a/include/llvm/MC/MachObjectWriter.h b/include/llvm/MC/MachObjectWriter.h deleted file mode 100644 index 9b1ff1db8471..000000000000 --- a/include/llvm/MC/MachObjectWriter.h +++ /dev/null @@ -1,44 +0,0 @@ -//===-- llvm/MC/MachObjectWriter.h - Mach-O File Writer ---------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_MC_MACHOBJECTWRITER_H -#define LLVM_MC_MACHOBJECTWRITER_H - -#include "llvm/MC/MCObjectWriter.h" -#include "llvm/Support/raw_ostream.h" -#include - -namespace llvm { -class MCAssembler; -class MCFragment; -class MCFixup; -class MCValue; -class raw_ostream; - -class MachObjectWriter : public MCObjectWriter { - void *Impl; - -public: - MachObjectWriter(raw_ostream &OS, bool Is64Bit, bool IsLittleEndian = true); - virtual ~MachObjectWriter(); - - virtual void ExecutePostLayoutBinding(MCAssembler &Asm); - - virtual void RecordRelocation(const MCAssembler &Asm, - const MCAsmLayout &Layout, - const MCFragment *Fragment, - const MCFixup &Fixup, MCValue Target, - uint64_t &FixedValue); - - virtual void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout); -}; - -} // End llvm namespace - -#endif diff --git a/include/llvm/Metadata.h b/include/llvm/Metadata.h index f5a80a3dced2..a6c3f039a11e 100644 --- a/include/llvm/Metadata.h +++ b/include/llvm/Metadata.h @@ -144,9 +144,6 @@ public: unsigned getNumOperands() const { return NumOperands; } /// isFunctionLocal - Return whether MDNode is local to a function. - /// Note: MDNodes are designated as function-local when created, and keep - /// that designation even if their operands are modified to no longer - /// refer to function-local IR. bool isFunctionLocal() const { return (getSubclassDataFromValue() & FunctionLocalBit) != 0; } diff --git a/include/llvm/Module.h b/include/llvm/Module.h index b7880ca2cb76..f95895e95773 100644 --- a/include/llvm/Module.h +++ b/include/llvm/Module.h @@ -20,7 +20,7 @@ #include "llvm/GlobalAlias.h" #include "llvm/Metadata.h" #include "llvm/ADT/OwningPtr.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include namespace llvm { diff --git a/include/llvm/Object/MachOFormat.h b/include/llvm/Object/MachOFormat.h new file mode 100644 index 000000000000..31cd523ea219 --- /dev/null +++ b/include/llvm/Object/MachOFormat.h @@ -0,0 +1,367 @@ +//===- MachOFormat.h - Mach-O Format Structures And Constants ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares various structures and constants which are platform +// independent and can be shared by any client which wishes to interact with +// Mach object files. +// +// The definitions here are purposely chosen to match the LLVM style as opposed +// to following the platform specific definition of the format. +// +// On a Mach system, see the includes for more information, in +// particular . +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_MACHOFORMAT_H +#define LLVM_OBJECT_MACHOFORMAT_H + +#include "llvm/Support/DataTypes.h" + +namespace llvm { +namespace object { + +/// General Mach platform information. +namespace mach { + /// @name CPU Type and Subtype Information + /// { + + /// \brief Capability bits used in CPU type encoding. + enum CPUTypeFlagsMask { + CTFM_ArchMask = 0xFF000000, + CTFM_ArchABI64 = 0x01000000 + }; + + /// \brief Machine type IDs used in CPU type encoding. + enum CPUTypeMachine { + CTM_i386 = 7, + CTM_x86_64 = CTM_i386 | CTFM_ArchABI64, + CTM_ARM = 12, + CTM_SPARC = 14, + CTM_PowerPC = 18, + CTM_PowerPC64 = CTM_PowerPC | CTFM_ArchABI64 + }; + + /// \brief Capability bits used in CPU subtype encoding. + enum CPUSubtypeFlagsMask { + CSFM_SubtypeMask = 0xFF000000, + CSFM_SubtypeLib64 = 0x80000000 + }; + + /// \brief ARM Machine Subtypes. + enum CPUSubtypeARM { + CSARM_ALL = 0, + CSARM_V4T = 5, + CSARM_V6 = 6, + CSARM_V5TEJ = 7, + CSARM_XSCALE = 8, + CSARM_V7 = 9 + }; + + /// \brief PowerPC Machine Subtypes. + enum CPUSubtypePowerPC { + CSPPC_ALL = 0 + }; + + /// \brief SPARC Machine Subtypes. + enum CPUSubtypeSPARC { + CSSPARC_ALL = 0 + }; + + /// \brief x86 Machine Subtypes. + enum CPUSubtypeX86 { + CSX86_ALL = 3 + }; + + /// @} + +} // end namespace mach + +/// Format information for Mach object files. +namespace macho { + /// \brief Constants for structure sizes. + enum StructureSizes { + Header32Size = 28, + Header64Size = 32, + SegmentLoadCommand32Size = 56, + SegmentLoadCommand64Size = 72, + Section32Size = 68, + Section64Size = 80, + SymtabLoadCommandSize = 24, + DysymtabLoadCommandSize = 80, + Nlist32Size = 12, + Nlist64Size = 16, + RelocationInfoSize = 8 + }; + + /// \brief Constants for header magic field. + enum HeaderMagic { + HM_Object32 = 0xFEEDFACE, ///< 32-bit mach object file + HM_Object64 = 0xFEEDFACF, ///< 64-bit mach object file + HM_Universal = 0xCAFEBABE ///< Universal object file + }; + + /// \brief Header common to all Mach object files. + struct Header { + uint32_t Magic; + uint32_t CPUType; + uint32_t CPUSubtype; + uint32_t FileType; + uint32_t NumLoadCommands; + uint32_t SizeOfLoadCommands; + uint32_t Flags; + }; + + /// \brief Extended header for 64-bit object files. + struct Header64Ext { + uint32_t Reserved; + }; + + // See . + enum HeaderFileType { + HFT_Object = 0x1 + }; + + enum HeaderFlags { + HF_SubsectionsViaSymbols = 0x2000 + }; + + enum LoadCommandType { + LCT_Segment = 0x1, + LCT_Symtab = 0x2, + LCT_Dysymtab = 0xb, + LCT_Segment64 = 0x19, + LCT_UUID = 0x1b + }; + + /// \brief Load command structure. + struct LoadCommand { + uint32_t Type; + uint32_t Size; + }; + + /// @name Load Command Structures + /// @{ + + struct SegmentLoadCommand { + uint32_t Type; + uint32_t Size; + char Name[16]; + uint32_t VMAddress; + uint32_t VMSize; + uint32_t FileOffset; + uint32_t FileSize; + uint32_t MaxVMProtection; + uint32_t InitialVMProtection; + uint32_t NumSections; + uint32_t Flags; + }; + + struct Segment64LoadCommand { + uint32_t Type; + uint32_t Size; + char Name[16]; + uint64_t VMAddress; + uint64_t VMSize; + uint64_t FileOffset; + uint64_t FileSize; + uint32_t MaxVMProtection; + uint32_t InitialVMProtection; + uint32_t NumSections; + uint32_t Flags; + }; + + struct SymtabLoadCommand { + uint32_t Type; + uint32_t Size; + uint32_t SymbolTableOffset; + uint32_t NumSymbolTableEntries; + uint32_t StringTableOffset; + uint32_t StringTableSize; + }; + + struct DysymtabLoadCommand { + uint32_t Type; + uint32_t Size; + + uint32_t LocalSymbolsIndex; + uint32_t NumLocalSymbols; + + uint32_t ExternalSymbolsIndex; + uint32_t NumExternalSymbols; + + uint32_t UndefinedSymbolsIndex; + uint32_t NumUndefinedSymbols; + + uint32_t TOCOffset; + uint32_t NumTOCEntries; + + uint32_t ModuleTableOffset; + uint32_t NumModuleTableEntries; + + uint32_t ReferenceSymbolTableOffset; + uint32_t NumReferencedSymbolTableEntries; + + uint32_t IndirectSymbolTableOffset; + uint32_t NumIndirectSymbolTableEntries; + + uint32_t ExternalRelocationTableOffset; + uint32_t NumExternalRelocationTableEntries; + + uint32_t LocalRelocationTableOffset; + uint32_t NumLocalRelocationTableEntries; + }; + + /// @} + /// @name Section Data + /// @{ + + struct Section { + char Name[16]; + char SegmentName[16]; + uint32_t Address; + uint32_t Size; + uint32_t Offset; + uint32_t Align; + uint32_t RelocationTableOffset; + uint32_t NumRelocationTableEntries; + uint32_t Flags; + uint32_t Reserved1; + uint32_t Reserved2; + }; + struct Section64 { + char Name[16]; + char SegmentName[16]; + uint64_t Address; + uint64_t Size; + uint32_t Offset; + uint32_t Align; + uint32_t RelocationTableOffset; + uint32_t NumRelocationTableEntries; + uint32_t Flags; + uint32_t Reserved1; + uint32_t Reserved2; + uint32_t Reserved3; + }; + + /// @} + /// @name Symbol Table Entries + /// @{ + + struct SymbolTableEntry { + uint32_t StringIndex; + uint8_t Type; + uint8_t SectionIndex; + uint16_t Flags; + uint32_t Value; + }; + struct Symbol64TableEntry { + uint32_t StringIndex; + uint8_t Type; + uint8_t SectionIndex; + uint16_t Flags; + uint64_t Value; + }; + + /// @} + /// @name Indirect Symbol Table + /// @{ + + struct IndirectSymbolTableEntry { + uint32_t Index; + }; + + /// @} + /// @name Relocation Data + /// @{ + + struct RelocationEntry { + uint32_t Word0; + uint32_t Word1; + }; + + /// @} + + // See . + enum SymbolTypeType { + STT_Undefined = 0x00, + STT_Absolute = 0x02, + STT_Section = 0x0e + }; + + enum SymbolTypeFlags { + // If any of these bits are set, then the entry is a stab entry number (see + // . Otherwise the other masks apply. + STF_StabsEntryMask = 0xe0, + + STF_TypeMask = 0x0e, + STF_External = 0x01, + STF_PrivateExtern = 0x10 + }; + + /// IndirectSymbolFlags - Flags for encoding special values in the indirect + /// symbol entry. + enum IndirectSymbolFlags { + ISF_Local = 0x80000000, + ISF_Absolute = 0x40000000 + }; + + /// RelocationFlags - Special flags for addresses. + enum RelocationFlags { + RF_Scattered = 0x80000000 + }; + + /// Common relocation info types. + enum RelocationInfoType { + RIT_Vanilla = 0, + RIT_Pair = 1, + RIT_Difference = 2 + }; + + /// Generic relocation info types, which are shared by some (but not all) + /// platforms. + enum RelocationInfoType_Generic { + RIT_Generic_PreboundLazyPointer = 3, + RIT_Generic_LocalDifference = 4, + RIT_Generic_TLV = 5 + }; + + /// X86_64 uses its own relocation types. + enum RelocationInfoTypeX86_64 { + // Note that x86_64 doesn't even share the common relocation types. + RIT_X86_64_Unsigned = 0, + RIT_X86_64_Signed = 1, + RIT_X86_64_Branch = 2, + RIT_X86_64_GOTLoad = 3, + RIT_X86_64_GOT = 4, + RIT_X86_64_Subtractor = 5, + RIT_X86_64_Signed1 = 6, + RIT_X86_64_Signed2 = 7, + RIT_X86_64_Signed4 = 8, + RIT_X86_64_TLV = 9 + }; + + /// ARM uses its own relocation types. + enum RelocationInfoTypeARM { + RIT_ARM_LocalDifference = 3, + RIT_ARM_PreboundLazyPointer = 4, + RIT_ARM_Branch24Bit = 5, + RIT_ARM_ThumbBranch22Bit = 6, + RIT_ARM_ThumbBranch32Bit = 7, + RIT_ARM_Half = 8, + RIT_ARM_HalfDifference = 9 + + }; + +} // end namespace macho + +} // end namespace object +} // end namespace llvm + +#endif diff --git a/include/llvm/Object/MachOObject.h b/include/llvm/Object/MachOObject.h new file mode 100644 index 000000000000..03d9c147b413 --- /dev/null +++ b/include/llvm/Object/MachOObject.h @@ -0,0 +1,180 @@ +//===- MachOObject.h - Mach-O Object File Wrapper ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_MACHOOBJECT_H +#define LLVM_OBJECT_MACHOOBJECT_H + +#include +#include "llvm/ADT/InMemoryStruct.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Object/MachOFormat.h" + +namespace llvm { + +class MemoryBuffer; + +namespace object { + +/// \brief Wrapper object for manipulating Mach-O object files. +/// +/// This class is designed to implement a full-featured, efficient, portable, +/// and robust Mach-O interface to Mach-O object files. It does not attempt to +/// smooth over rough edges in the Mach-O format or generalize access to object +/// independent features. +/// +/// The class is designed around accessing the Mach-O object which is expected +/// to be fully loaded into memory. +/// +/// This class is *not* suitable for concurrent use. For efficient operation, +/// the class uses APIs which rely on the ability to cache the results of +/// certain calls in internal objects which are not safe for concurrent +/// access. This allows the API to be zero-copy on the common paths. +// +// FIXME: It would be cool if we supported a "paged" MemoryBuffer +// implementation. This would allow us to implement a more sensible version of +// MemoryObject which can work like a MemoryBuffer, but be more efficient for +// objects which are in the current address space. +class MachOObject { +public: + struct LoadCommandInfo { + /// The load command information. + macho::LoadCommand Command; + + /// The offset to the start of the load command in memory. + uint64_t Offset; + }; + +private: + OwningPtr Buffer; + + /// Whether the object is little endian. + bool IsLittleEndian; + /// Whether the object is 64-bit. + bool Is64Bit; + /// Whether the object is swapped endianness from the host. + bool IsSwappedEndian; + /// Whether the string table has been registered. + bool HasStringTable; + + /// The cached information on the load commands. + LoadCommandInfo *LoadCommands; + mutable unsigned NumLoadedCommands; + + /// The cached copy of the header. + macho::Header Header; + macho::Header64Ext Header64Ext; + + /// Cache string table information. + StringRef StringTable; + +private: + MachOObject(MemoryBuffer *Buffer, bool IsLittleEndian, bool Is64Bit); + +public: + ~MachOObject(); + + /// \brief Load a Mach-O object from a MemoryBuffer object. + /// + /// \param Buffer - The buffer to load the object from. This routine takes + /// exclusive ownership of the buffer (which is passed to the returned object + /// on success). + /// \param ErrorStr [out] - If given, will be set to a user readable error + /// message on failure. + /// \returns The loaded object, or null on error. + static MachOObject *LoadFromBuffer(MemoryBuffer *Buffer, + std::string *ErrorStr = 0); + + /// @name File Information + /// @{ + + bool isLittleEndian() const { return IsLittleEndian; } + bool isSwappedEndian() const { return IsSwappedEndian; } + bool is64Bit() const { return Is64Bit; } + + unsigned getHeaderSize() const { + return Is64Bit ? macho::Header64Size : macho::Header32Size; + } + + StringRef getData(size_t Offset, size_t Size) const; + + /// @} + /// @name String Table Data + /// @{ + + StringRef getStringTableData() const { + assert(HasStringTable && "String table has not been registered!"); + return StringTable; + } + + StringRef getStringAtIndex(unsigned Index) const { + size_t End = getStringTableData().find('\0', Index); + return getStringTableData().slice(Index, End); + } + + void RegisterStringTable(macho::SymtabLoadCommand &SLC); + + /// @} + /// @name Object Header Access + /// @{ + + const macho::Header &getHeader() const { return Header; } + const macho::Header64Ext &getHeader64Ext() const { + assert(is64Bit() && "Invalid access!"); + return Header64Ext; + } + + /// @} + /// @name Object Structure Access + /// @{ + + /// \brief Retrieve the information for the given load command. + const LoadCommandInfo &getLoadCommandInfo(unsigned Index) const; + + void ReadSegmentLoadCommand( + const LoadCommandInfo &LCI, + InMemoryStruct &Res) const; + void ReadSegment64LoadCommand( + const LoadCommandInfo &LCI, + InMemoryStruct &Res) const; + void ReadSymtabLoadCommand( + const LoadCommandInfo &LCI, + InMemoryStruct &Res) const; + void ReadDysymtabLoadCommand( + const LoadCommandInfo &LCI, + InMemoryStruct &Res) const; + void ReadIndirectSymbolTableEntry( + const macho::DysymtabLoadCommand &DLC, + unsigned Index, + InMemoryStruct &Res) const; + void ReadSection( + const LoadCommandInfo &LCI, + unsigned Index, + InMemoryStruct &Res) const; + void ReadSection64( + const LoadCommandInfo &LCI, + unsigned Index, + InMemoryStruct &Res) const; + void ReadRelocationEntry( + uint64_t RelocationTableOffset, unsigned Index, + InMemoryStruct &Res) const; + void ReadSymbolTableEntry( + uint64_t SymbolTableOffset, unsigned Index, + InMemoryStruct &Res) const; + void ReadSymbol64TableEntry( + uint64_t SymbolTableOffset, unsigned Index, + InMemoryStruct &Res) const; + + /// @} +}; + +} // end namespace object +} // end namespace llvm + +#endif diff --git a/include/llvm/Object/ObjectFile.h b/include/llvm/Object/ObjectFile.h new file mode 100644 index 000000000000..eee9d447cddf --- /dev/null +++ b/include/llvm/Object/ObjectFile.h @@ -0,0 +1,262 @@ +//===- ObjectFile.h - File format independent object file -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares a file format independent ObjectFile class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_OBJECT_FILE_H +#define LLVM_OBJECT_OBJECT_FILE_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/DataTypes.h" +#include + +namespace llvm { + +class MemoryBuffer; +class StringRef; + +namespace object { + +class ObjectFile; + +union DataRefImpl { + struct { + uint32_t a, b; + } d; + intptr_t p; +}; + +static bool operator ==(const DataRefImpl &a, const DataRefImpl &b) { + // Check bitwise identical. This is the only legal way to compare a union w/o + // knowing which member is in use. + return std::memcmp(&a, &b, sizeof(DataRefImpl)) == 0; +} + +/// SymbolRef - This is a value type class that represents a single symbol in +/// the list of symbols in the object file. +class SymbolRef { + DataRefImpl SymbolPimpl; + const ObjectFile *OwningObject; + +public: + SymbolRef(DataRefImpl SymbolP, const ObjectFile *Owner); + + bool operator==(const SymbolRef &Other) const; + + SymbolRef getNext() const; + + StringRef getName() const; + uint64_t getAddress() const; + uint64_t getSize() const; + + /// Returns the ascii char that should be displayed in a symbol table dump via + /// nm for this symbol. + char getNMTypeChar() const; + + /// Returns true for symbols that are internal to the object file format such + /// as section symbols. + bool isInternal() const; +}; + +/// SectionRef - This is a value type class that represents a single section in +/// the list of sections in the object file. +class SectionRef { + DataRefImpl SectionPimpl; + const ObjectFile *OwningObject; + +public: + SectionRef(DataRefImpl SectionP, const ObjectFile *Owner); + + bool operator==(const SectionRef &Other) const; + + SectionRef getNext() const; + + StringRef getName() const; + uint64_t getAddress() const; + uint64_t getSize() const; + StringRef getContents() const; + + // FIXME: Move to the normalization layer when it's created. + bool isText() const; +}; + +const uint64_t UnknownAddressOrSize = ~0ULL; + +/// ObjectFile - This class is the base class for all object file types. +/// Concrete instances of this object are created by createObjectFile, which +/// figure out which type to create. +class ObjectFile { +private: + ObjectFile(); // = delete + ObjectFile(const ObjectFile &other); // = delete + +protected: + MemoryBuffer *MapFile; + const uint8_t *base; + + ObjectFile(MemoryBuffer *Object); + + // These functions are for SymbolRef to call internally. The main goal of + // this is to allow SymbolRef::SymbolPimpl to point directly to the symbol + // entry in the memory mapped object file. SymbolPimpl cannot contain any + // virtual functions because then it could not point into the memory mapped + // file. + friend class SymbolRef; + virtual SymbolRef getSymbolNext(DataRefImpl Symb) const = 0; + virtual StringRef getSymbolName(DataRefImpl Symb) const = 0; + virtual uint64_t getSymbolAddress(DataRefImpl Symb) const = 0; + virtual uint64_t getSymbolSize(DataRefImpl Symb) const = 0; + virtual char getSymbolNMTypeChar(DataRefImpl Symb) const = 0; + virtual bool isSymbolInternal(DataRefImpl Symb) const = 0; + + // Same as above for SectionRef. + friend class SectionRef; + virtual SectionRef getSectionNext(DataRefImpl Sec) const = 0; + virtual StringRef getSectionName(DataRefImpl Sec) const = 0; + virtual uint64_t getSectionAddress(DataRefImpl Sec) const = 0; + virtual uint64_t getSectionSize(DataRefImpl Sec) const = 0; + virtual StringRef getSectionContents(DataRefImpl Sec) const = 0; + virtual bool isSectionText(DataRefImpl Sec) const = 0; + + +public: + template + class content_iterator { + content_type Current; + public: + content_iterator(content_type symb) + : Current(symb) {} + + const content_type* operator->() const { + return &Current; + } + + bool operator==(const content_iterator &other) const { + return Current == other.Current; + } + + bool operator!=(const content_iterator &other) const { + return !(*this == other); + } + + content_iterator& operator++() { // Preincrement + Current = Current.getNext(); + return *this; + } + }; + + typedef content_iterator symbol_iterator; + typedef content_iterator section_iterator; + + virtual ~ObjectFile(); + + virtual symbol_iterator begin_symbols() const = 0; + virtual symbol_iterator end_symbols() const = 0; + + virtual section_iterator begin_sections() const = 0; + virtual section_iterator end_sections() const = 0; + + /// @brief The number of bytes used to represent an address in this object + /// file format. + virtual uint8_t getBytesInAddress() const = 0; + + virtual StringRef getFileFormatName() const = 0; + virtual /* Triple::ArchType */ unsigned getArch() const = 0; + + StringRef getFilename() const; + + /// @returns Pointer to ObjectFile subclass to handle this type of object. + /// @param ObjectPath The path to the object file. ObjectPath.isObject must + /// return true. + /// @brief Create ObjectFile from path. + static ObjectFile *createObjectFile(StringRef ObjectPath); + static ObjectFile *createObjectFile(MemoryBuffer *Object); + +private: + static ObjectFile *createCOFFObjectFile(MemoryBuffer *Object); + static ObjectFile *createELFObjectFile(MemoryBuffer *Object); + static ObjectFile *createMachOObjectFile(MemoryBuffer *Object); + static ObjectFile *createArchiveObjectFile(MemoryBuffer *Object); + static ObjectFile *createLibObjectFile(MemoryBuffer *Object); +}; + +// Inline function definitions. +inline SymbolRef::SymbolRef(DataRefImpl SymbolP, const ObjectFile *Owner) + : SymbolPimpl(SymbolP) + , OwningObject(Owner) {} + +inline bool SymbolRef::operator==(const SymbolRef &Other) const { + return SymbolPimpl == Other.SymbolPimpl; +} + +inline SymbolRef SymbolRef::getNext() const { + return OwningObject->getSymbolNext(SymbolPimpl); +} + +inline StringRef SymbolRef::getName() const { + return OwningObject->getSymbolName(SymbolPimpl); +} + +inline uint64_t SymbolRef::getAddress() const { + return OwningObject->getSymbolAddress(SymbolPimpl); +} + +inline uint64_t SymbolRef::getSize() const { + return OwningObject->getSymbolSize(SymbolPimpl); +} + +inline char SymbolRef::getNMTypeChar() const { + return OwningObject->getSymbolNMTypeChar(SymbolPimpl); +} + +inline bool SymbolRef::isInternal() const { + return OwningObject->isSymbolInternal(SymbolPimpl); +} + + +/// SectionRef +inline SectionRef::SectionRef(DataRefImpl SectionP, + const ObjectFile *Owner) + : SectionPimpl(SectionP) + , OwningObject(Owner) {} + +inline bool SectionRef::operator==(const SectionRef &Other) const { + return SectionPimpl == Other.SectionPimpl; +} + +inline SectionRef SectionRef::getNext() const { + return OwningObject->getSectionNext(SectionPimpl); +} + +inline StringRef SectionRef::getName() const { + return OwningObject->getSectionName(SectionPimpl); +} + +inline uint64_t SectionRef::getAddress() const { + return OwningObject->getSectionAddress(SectionPimpl); +} + +inline uint64_t SectionRef::getSize() const { + return OwningObject->getSectionSize(SectionPimpl); +} + +inline StringRef SectionRef::getContents() const { + return OwningObject->getSectionContents(SectionPimpl); +} + +inline bool SectionRef::isText() const { + return OwningObject->isSectionText(SectionPimpl); +} + +} // end namespace object +} // end namespace llvm + +#endif diff --git a/include/llvm/OperandTraits.h b/include/llvm/OperandTraits.h index b614ccbc3777..f0df5fa9bde8 100644 --- a/include/llvm/OperandTraits.h +++ b/include/llvm/OperandTraits.h @@ -27,27 +27,17 @@ namespace llvm { /// when it is a prefix to the User object, and the number of Use objects is /// known at compile time. -template +template struct FixedNumOperandTraits { - static Use *op_begin(User* U) { + static Use *op_begin(SubClass* U) { return reinterpret_cast(U) - ARITY; } - static Use *op_end(User* U) { + static Use *op_end(SubClass* U) { return reinterpret_cast(U); } static unsigned operands(const User*) { return ARITY; } - struct prefix { - Use Ops[ARITY]; - prefix(); // DO NOT IMPLEMENT - }; - template - struct Layout { - struct overlay : public prefix, public U { - overlay(); // DO NOT IMPLEMENT - }; - }; }; //===----------------------------------------------------------------------===// @@ -57,8 +47,8 @@ struct FixedNumOperandTraits { /// OptionalOperandTraits - when the number of operands may change at runtime. /// Naturally it may only decrease, because the allocations may not change. -template -struct OptionalOperandTraits : public FixedNumOperandTraits { +template +struct OptionalOperandTraits : public FixedNumOperandTraits { static unsigned operands(const User *U) { return U->getNumOperands(); } @@ -72,12 +62,12 @@ struct OptionalOperandTraits : public FixedNumOperandTraits { /// when it is a prefix to the User object, and the number of Use objects is /// only known at allocation time. -template +template struct VariadicOperandTraits { - static Use *op_begin(User* U) { - return reinterpret_cast(U) - U->getNumOperands(); + static Use *op_begin(SubClass* U) { + return reinterpret_cast(U) - static_cast(U)->getNumOperands(); } - static Use *op_end(User* U) { + static Use *op_end(SubClass* U) { return reinterpret_cast(U); } static unsigned operands(const User *U) { diff --git a/include/llvm/Operator.h b/include/llvm/Operator.h index 60865aa8ad45..ff2a0ad5e4e9 100644 --- a/include/llvm/Operator.h +++ b/include/llvm/Operator.h @@ -99,19 +99,21 @@ public: /// hasNoSignedWrap - Test whether this operation is known to never /// undergo signed overflow, aka the nsw property. bool hasNoSignedWrap() const { - return SubclassOptionalData & NoSignedWrap; + return (SubclassOptionalData & NoSignedWrap) != 0; } static inline bool classof(const OverflowingBinaryOperator *) { return true; } static inline bool classof(const Instruction *I) { return I->getOpcode() == Instruction::Add || I->getOpcode() == Instruction::Sub || - I->getOpcode() == Instruction::Mul; + I->getOpcode() == Instruction::Mul || + I->getOpcode() == Instruction::Shl; } static inline bool classof(const ConstantExpr *CE) { return CE->getOpcode() == Instruction::Add || CE->getOpcode() == Instruction::Sub || - CE->getOpcode() == Instruction::Mul; + CE->getOpcode() == Instruction::Mul || + CE->getOpcode() == Instruction::Shl; } static inline bool classof(const Value *V) { return (isa(V) && classof(cast(V))) || @@ -119,105 +121,97 @@ public: } }; -/// AddOperator - Utility class for integer addition operators. -/// -class AddOperator : public OverflowingBinaryOperator { - ~AddOperator(); // do not implement -public: - static inline bool classof(const AddOperator *) { return true; } - static inline bool classof(const Instruction *I) { - return I->getOpcode() == Instruction::Add; - } - static inline bool classof(const ConstantExpr *CE) { - return CE->getOpcode() == Instruction::Add; - } - static inline bool classof(const Value *V) { - return (isa(V) && classof(cast(V))) || - (isa(V) && classof(cast(V))); - } -}; - -/// SubOperator - Utility class for integer subtraction operators. -/// -class SubOperator : public OverflowingBinaryOperator { - ~SubOperator(); // do not implement -public: - static inline bool classof(const SubOperator *) { return true; } - static inline bool classof(const Instruction *I) { - return I->getOpcode() == Instruction::Sub; - } - static inline bool classof(const ConstantExpr *CE) { - return CE->getOpcode() == Instruction::Sub; - } - static inline bool classof(const Value *V) { - return (isa(V) && classof(cast(V))) || - (isa(V) && classof(cast(V))); - } -}; - -/// MulOperator - Utility class for integer multiplication operators. -/// -class MulOperator : public OverflowingBinaryOperator { - ~MulOperator(); // do not implement -public: - static inline bool classof(const MulOperator *) { return true; } - static inline bool classof(const Instruction *I) { - return I->getOpcode() == Instruction::Mul; - } - static inline bool classof(const ConstantExpr *CE) { - return CE->getOpcode() == Instruction::Mul; - } - static inline bool classof(const Value *V) { - return (isa(V) && classof(cast(V))) || - (isa(V) && classof(cast(V))); - } -}; - -/// SDivOperator - An Operator with opcode Instruction::SDiv. -/// -class SDivOperator : public Operator { +/// PossiblyExactOperator - A udiv or sdiv instruction, which can be marked as +/// "exact", indicating that no bits are destroyed. +class PossiblyExactOperator : public Operator { public: enum { IsExact = (1 << 0) }; - -private: - ~SDivOperator(); // do not implement - + friend class BinaryOperator; friend class ConstantExpr; void setIsExact(bool B) { SubclassOptionalData = (SubclassOptionalData & ~IsExact) | (B * IsExact); } - + +private: + ~PossiblyExactOperator(); // do not implement public: /// isExact - Test whether this division is known to be exact, with /// zero remainder. bool isExact() const { return SubclassOptionalData & IsExact; } - - // Methods for support type inquiry through isa, cast, and dyn_cast: - static inline bool classof(const SDivOperator *) { return true; } + + static bool isPossiblyExactOpcode(unsigned OpC) { + return OpC == Instruction::SDiv || + OpC == Instruction::UDiv || + OpC == Instruction::AShr || + OpC == Instruction::LShr; + } static inline bool classof(const ConstantExpr *CE) { - return CE->getOpcode() == Instruction::SDiv; + return isPossiblyExactOpcode(CE->getOpcode()); } static inline bool classof(const Instruction *I) { - return I->getOpcode() == Instruction::SDiv; + return isPossiblyExactOpcode(I->getOpcode()); } static inline bool classof(const Value *V) { return (isa(V) && classof(cast(V))) || (isa(V) && classof(cast(V))); } }; + -class GEPOperator : public Operator { + +/// ConcreteOperator - A helper template for defining operators for individual +/// opcodes. +template +class ConcreteOperator : public SuperClass { + ~ConcreteOperator(); // DO NOT IMPLEMENT +public: + static inline bool classof(const ConcreteOperator *) { + return true; + } + static inline bool classof(const Instruction *I) { + return I->getOpcode() == Opc; + } + static inline bool classof(const ConstantExpr *CE) { + return CE->getOpcode() == Opc; + } + static inline bool classof(const Value *V) { + return (isa(V) && classof(cast(V))) || + (isa(V) && classof(cast(V))); + } +}; + +class AddOperator + : public ConcreteOperator {}; +class SubOperator + : public ConcreteOperator {}; +class MulOperator + : public ConcreteOperator {}; +class ShlOperator + : public ConcreteOperator {}; + + +class SDivOperator + : public ConcreteOperator {}; +class UDivOperator + : public ConcreteOperator {}; +class AShrOperator + : public ConcreteOperator {}; +class LShrOperator + : public ConcreteOperator {}; + + + +class GEPOperator + : public ConcreteOperator { enum { IsInBounds = (1 << 0) }; - ~GEPOperator(); // do not implement - friend class GetElementPtrInst; friend class ConstantExpr; void setIsInBounds(bool B) { @@ -266,8 +260,8 @@ public: /// value, just potentially different types. bool hasAllZeroIndices() const { for (const_op_iterator I = idx_begin(), E = idx_end(); I != E; ++I) { - if (Constant *C = dyn_cast(I)) - if (C->isNullValue()) + if (ConstantInt *C = dyn_cast(I)) + if (C->isZero()) continue; return false; } @@ -284,21 +278,6 @@ public: } return true; } - - - // Methods for support type inquiry through isa, cast, and dyn_cast: - static inline bool classof(const GEPOperator *) { return true; } - static inline bool classof(const GetElementPtrInst *) { return true; } - static inline bool classof(const ConstantExpr *CE) { - return CE->getOpcode() == Instruction::GetElementPtr; - } - static inline bool classof(const Instruction *I) { - return I->getOpcode() == Instruction::GetElementPtr; - } - static inline bool classof(const Value *V) { - return (isa(V) && classof(cast(V))) || - (isa(V) && classof(cast(V))); - } }; } // End llvm namespace diff --git a/include/llvm/Pass.h b/include/llvm/Pass.h index f4c6eed2cf9a..ed0fb39f5d6c 100644 --- a/include/llvm/Pass.h +++ b/include/llvm/Pass.h @@ -57,6 +57,7 @@ enum PassManagerType { PMT_CallGraphPassManager, ///< CGPassManager PMT_FunctionPassManager, ///< FPPassManager PMT_LoopPassManager, ///< LPPassManager + PMT_RegionPassManager, ///< RGPassManager PMT_BasicBlockPassManager, ///< BBPassManager PMT_Last }; @@ -64,13 +65,14 @@ enum PassManagerType { // Different types of passes. enum PassKind { PT_BasicBlock, + PT_Region, PT_Loop, PT_Function, PT_CallGraphSCC, PT_Module, PT_PassManager }; - + //===----------------------------------------------------------------------===// /// Pass interface - Implemented by all 'passes'. Subclass this if you are an /// interprocedural optimization or you do not fit into any of the more diff --git a/include/llvm/PassManagers.h b/include/llvm/PassManagers.h index 17f4a0592fbb..c4f409ef525c 100644 --- a/include/llvm/PassManagers.h +++ b/include/llvm/PassManagers.h @@ -106,6 +106,7 @@ enum PassDebuggingString { ON_BASICBLOCK_MSG, // "' on BasicBlock '" + PassName + "'...\n" ON_FUNCTION_MSG, // "' on Function '" + FunctionName + "'...\n" ON_MODULE_MSG, // "' on Module '" + ModuleName + "'...\n" + ON_REGION_MSG, // " 'on Region ...\n'" ON_LOOP_MSG, // " 'on Loop ...\n'" ON_CG_MSG // "' on Call Graph ...\n'" }; @@ -184,10 +185,10 @@ public: void schedulePass(Pass *P); /// Set pass P as the last user of the given analysis passes. - void setLastUser(SmallVector &AnalysisPasses, Pass *P); + void setLastUser(const SmallVectorImpl &AnalysisPasses, Pass *P); /// Collect passes whose last user is P - void collectLastUses(SmallVector &LastUses, Pass *P); + void collectLastUses(SmallVectorImpl &LastUses, Pass *P); /// Find the pass that implements Analysis AID. Search immutable /// passes and all pass managers. If desired pass is not found @@ -205,7 +206,7 @@ public: ImmutablePasses.push_back(P); } - inline SmallVector& getImmutablePasses() { + inline SmallVectorImpl& getImmutablePasses() { return ImmutablePasses; } @@ -313,8 +314,8 @@ public: /// Populate RequiredPasses with analysis pass that are required by /// pass P and are available. Populate ReqPassNotAvailable with analysis /// pass that are required by pass P but are not available. - void collectRequiredAnalysis(SmallVector &RequiredPasses, - SmallVector &ReqPassNotAvailable, + void collectRequiredAnalysis(SmallVectorImpl &RequiredPasses, + SmallVectorImpl &ReqPassNotAvailable, Pass *P); /// All Required analyses should be available to the pass as it runs! Here diff --git a/include/llvm/PassRegistry.h b/include/llvm/PassRegistry.h index 59071391520a..5d89c492218d 100644 --- a/include/llvm/PassRegistry.h +++ b/include/llvm/PassRegistry.h @@ -8,61 +8,74 @@ //===----------------------------------------------------------------------===// // // This file defines PassRegistry, a class that is used in the initialization -// and registration of passes. At initialization, passes are registered with -// the PassRegistry, which is later provided to the PassManager for dependency -// resolution and similar tasks. +// and registration of passes. At application startup, passes are registered +// with the PassRegistry, which is later provided to the PassManager for +// dependency resolution and similar tasks. // //===----------------------------------------------------------------------===// #ifndef LLVM_PASSREGISTRY_H #define LLVM_PASSREGISTRY_H -#include "llvm/ADT/StringMap.h" -#include "llvm/System/DataTypes.h" -#include "llvm/System/Mutex.h" -#include -#include -#include +#include "llvm/ADT/StringRef.h" namespace llvm { class PassInfo; struct PassRegistrationListener; +/// PassRegistry - This class manages the registration and intitialization of +/// the pass subsystem as application startup, and assists the PassManager +/// in resolving pass dependencies. +/// NOTE: PassRegistry is NOT thread-safe. If you want to use LLVM on multiple +/// threads simultaneously, you will need to use a separate PassRegistry on +/// each thread. class PassRegistry { - /// Guards the contents of this class. - mutable sys::SmartMutex Lock; - - /// PassInfoMap - Keep track of the PassInfo object for each registered pass. - typedef std::map MapType; - MapType PassInfoMap; - - typedef StringMap StringMapType; - StringMapType PassInfoStringMap; - - /// AnalysisGroupInfo - Keep track of information for each analysis group. - struct AnalysisGroupInfo { - std::set Implementations; - }; - std::map AnalysisGroupInfoMap; - - std::vector Listeners; - + mutable void *pImpl; + void *getImpl() const; + public: + PassRegistry() : pImpl(0) { } + ~PassRegistry(); + + /// getPassRegistry - Access the global registry object, which is + /// automatically initialized at application launch and destroyed by + /// llvm_shutdown. static PassRegistry *getPassRegistry(); + /// getPassInfo - Look up a pass' corresponding PassInfo, indexed by the pass' + /// type identifier (&MyPass::ID). const PassInfo *getPassInfo(const void *TI) const; + + /// getPassInfo - Look up a pass' corresponding PassInfo, indexed by the pass' + /// argument string. const PassInfo *getPassInfo(StringRef Arg) const; - void registerPass(const PassInfo &PI); + /// registerPass - Register a pass (by means of its PassInfo) with the + /// registry. Required in order to use the pass with a PassManager. + void registerPass(const PassInfo &PI, bool ShouldFree = false); + + /// registerPass - Unregister a pass (by means of its PassInfo) with the + /// registry. void unregisterPass(const PassInfo &PI); - /// Analysis Group Mechanisms. + /// registerAnalysisGroup - Register an analysis group (or a pass implementing + // an analysis group) with the registry. Like registerPass, this is required + // in order for a PassManager to be able to use this group/pass. void registerAnalysisGroup(const void *InterfaceID, const void *PassID, - PassInfo& Registeree, bool isDefault); + PassInfo& Registeree, bool isDefault, + bool ShouldFree = false); + /// enumerateWith - Enumerate the registered passes, calling the provided + /// PassRegistrationListener's passEnumerate() callback on each of them. void enumerateWith(PassRegistrationListener *L); - void addRegistrationListener(PassRegistrationListener* L); + + /// addRegistrationListener - Register the given PassRegistrationListener + /// to receive passRegistered() callbacks whenever a new pass is registered. + void addRegistrationListener(PassRegistrationListener *L); + + /// removeRegistrationListener - Unregister a PassRegistrationListener so that + /// it no longer receives passRegistered() callbacks. void removeRegistrationListener(PassRegistrationListener *L); }; diff --git a/include/llvm/PassSupport.h b/include/llvm/PassSupport.h index 0f559d6df736..082790956c46 100644 --- a/include/llvm/PassSupport.h +++ b/include/llvm/PassSupport.h @@ -23,6 +23,9 @@ #include "Pass.h" #include "llvm/PassRegistry.h" +#include "llvm/InitializePasses.h" +#include "llvm/Support/Atomic.h" +#include namespace llvm { @@ -54,17 +57,14 @@ public: NormalCtor_t normal, bool isCFGOnly, bool is_analysis) : PassName(name), PassArgument(arg), PassID(pi), IsCFGOnlyPass(isCFGOnly), - IsAnalysis(is_analysis), IsAnalysisGroup(false), NormalCtor(normal) { - PassRegistry::getPassRegistry()->registerPass(*this); - } + IsAnalysis(is_analysis), IsAnalysisGroup(false), NormalCtor(normal) { } /// PassInfo ctor - Do not call this directly, this should only be invoked /// through RegisterPass. This version is for use by analysis groups; it /// does not auto-register the pass. PassInfo(const char *name, const void *pi) : PassName(name), PassArgument(""), PassID(pi), IsCFGOnlyPass(false), - IsAnalysis(false), IsAnalysisGroup(true), NormalCtor(0) { - } + IsAnalysis(false), IsAnalysisGroup(true), NormalCtor(0) { } /// getPassName - Return the friendly name for the pass, never returns null /// @@ -129,8 +129,50 @@ private: PassInfo(const PassInfo &); // do not implement }; +#define CALL_ONCE_INITIALIZATION(function) \ + static volatile sys::cas_flag initialized = 0; \ + sys::cas_flag old_val = sys::CompareAndSwap(&initialized, 1, 0); \ + if (old_val == 0) { \ + function(Registry); \ + sys::MemoryFence(); \ + initialized = 2; \ + } else { \ + sys::cas_flag tmp = initialized; \ + sys::MemoryFence(); \ + while (tmp != 2) { \ + tmp = initialized; \ + sys::MemoryFence(); \ + } \ + } + #define INITIALIZE_PASS(passName, arg, name, cfg, analysis) \ - static RegisterPass passName ## _info(arg, name, cfg, analysis) + static void* initialize##passName##PassOnce(PassRegistry &Registry) { \ + PassInfo *PI = new PassInfo(name, arg, & passName ::ID, \ + PassInfo::NormalCtor_t(callDefaultCtor< passName >), cfg, analysis); \ + Registry.registerPass(*PI, true); \ + return PI; \ + } \ + void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ + CALL_ONCE_INITIALIZATION(initialize##passName##PassOnce) \ + } + +#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis) \ + static void* initialize##passName##PassOnce(PassRegistry &Registry) { + +#define INITIALIZE_PASS_DEPENDENCY(depName) \ + initialize##depName##Pass(Registry); +#define INITIALIZE_AG_DEPENDENCY(depName) \ + initialize##depName##AnalysisGroup(Registry); + +#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis) \ + PassInfo *PI = new PassInfo(name, arg, & passName ::ID, \ + PassInfo::NormalCtor_t(callDefaultCtor< passName >), cfg, analysis); \ + Registry.registerPass(*PI, true); \ + return PI; \ + } \ + void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ + CALL_ONCE_INITIALIZATION(initialize##passName##PassOnce) \ + } template Pass *callDefaultCtor() { return new PassName(); } @@ -161,7 +203,7 @@ struct RegisterPass : public PassInfo { : PassInfo(Name, PassArg, &passName::ID, PassInfo::NormalCtor_t(callDefaultCtor), CFGOnly, is_analysis) { - + PassRegistry::getPassRegistry()->registerPass(*this); } }; @@ -186,7 +228,7 @@ struct RegisterPass : public PassInfo { /// a nice name with the interface. /// class RegisterAGBase : public PassInfo { -protected: +public: RegisterAGBase(const char *Name, const void *InterfaceID, const void *PassID = 0, @@ -206,9 +248,52 @@ struct RegisterAnalysisGroup : public RegisterAGBase { } }; +#define INITIALIZE_ANALYSIS_GROUP(agName, name, defaultPass) \ + static void* initialize##agName##AnalysisGroupOnce(PassRegistry &Registry) { \ + initialize##defaultPass##Pass(Registry); \ + PassInfo *AI = new PassInfo(name, & agName :: ID); \ + Registry.registerAnalysisGroup(& agName ::ID, 0, *AI, false, true); \ + return AI; \ + } \ + void llvm::initialize##agName##AnalysisGroup(PassRegistry &Registry) { \ + CALL_ONCE_INITIALIZATION(initialize##agName##AnalysisGroupOnce) \ + } + + #define INITIALIZE_AG_PASS(passName, agName, arg, name, cfg, analysis, def) \ - static RegisterPass passName ## _info(arg, name, cfg, analysis); \ - static RegisterAnalysisGroup passName ## _ag(passName ## _info) + static void* initialize##passName##PassOnce(PassRegistry &Registry) { \ + if (!def) initialize##agName##AnalysisGroup(Registry); \ + PassInfo *PI = new PassInfo(name, arg, & passName ::ID, \ + PassInfo::NormalCtor_t(callDefaultCtor< passName >), cfg, analysis); \ + Registry.registerPass(*PI, true); \ + \ + PassInfo *AI = new PassInfo(name, & agName :: ID); \ + Registry.registerAnalysisGroup(& agName ::ID, & passName ::ID, \ + *AI, def, true); \ + return AI; \ + } \ + void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ + CALL_ONCE_INITIALIZATION(initialize##passName##PassOnce) \ + } + + +#define INITIALIZE_AG_PASS_BEGIN(passName, agName, arg, n, cfg, analysis, def) \ + static void* initialize##passName##PassOnce(PassRegistry &Registry) { \ + if (!def) initialize##agName##AnalysisGroup(Registry); + +#define INITIALIZE_AG_PASS_END(passName, agName, arg, n, cfg, analysis, def) \ + PassInfo *PI = new PassInfo(n, arg, & passName ::ID, \ + PassInfo::NormalCtor_t(callDefaultCtor< passName >), cfg, analysis); \ + Registry.registerPass(*PI, true); \ + \ + PassInfo *AI = new PassInfo(n, & agName :: ID); \ + Registry.registerAnalysisGroup(& agName ::ID, & passName ::ID, \ + *AI, def, true); \ + return AI; \ + } \ + void llvm::initialize##passName##Pass(PassRegistry &Registry) { \ + CALL_ONCE_INITIALIZATION(initialize##passName##PassOnce) \ + } //===--------------------------------------------------------------------------- /// PassRegistrationListener class - This class is meant to be derived from by diff --git a/include/llvm/Support/AIXDataTypesFix.h b/include/llvm/Support/AIXDataTypesFix.h new file mode 100644 index 000000000000..a9a9147de294 --- /dev/null +++ b/include/llvm/Support/AIXDataTypesFix.h @@ -0,0 +1,25 @@ +//===-- llvm/Support/AIXDataTypesFix.h - Fix datatype defs ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file overrides default system-defined types and limits which cannot be +// done in DataTypes.h.in because it is processed by autoheader first, which +// comments out any #undef statement +// +//===----------------------------------------------------------------------===// + +// No include guards desired! + +#ifndef SUPPORT_DATATYPES_H +#error "AIXDataTypesFix.h must only be included via DataTypes.h!" +#endif + +// GCC is strict about defining large constants: they must have LL modifier. +// These will be defined properly at the end of DataTypes.h +#undef INT64_MAX +#undef INT64_MIN diff --git a/include/llvm/Support/AlignOf.h b/include/llvm/Support/AlignOf.h index 6a7a1a6bd223..cebfa7982d6d 100644 --- a/include/llvm/Support/AlignOf.h +++ b/include/llvm/Support/AlignOf.h @@ -49,12 +49,12 @@ struct AlignOf { }; -/// alignof - A templated function that returns the mininum alignment of +/// alignOf - A templated function that returns the minimum alignment of /// of a type. This provides no extra functionality beyond the AlignOf /// class besides some cosmetic cleanliness. Example usage: -/// alignof() returns the alignment of an int. +/// alignOf() returns the alignment of an int. template -static inline unsigned alignof() { return AlignOf::Alignment; } +static inline unsigned alignOf() { return AlignOf::Alignment; } } // end namespace llvm #endif diff --git a/include/llvm/Support/Allocator.h b/include/llvm/Support/Allocator.h index 4a7251fa1ef3..c6807099f85e 100644 --- a/include/llvm/Support/Allocator.h +++ b/include/llvm/Support/Allocator.h @@ -16,13 +16,15 @@ #include "llvm/Support/AlignOf.h" #include "llvm/Support/MathExtras.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include #include #include #include namespace llvm { +template struct ReferenceAdder { typedef T& result; }; +template struct ReferenceAdder { typedef T result; }; class MallocAllocator { public: @@ -201,7 +203,7 @@ public: char *End = Slab == Allocator.CurSlab ? Allocator.CurPtr : (char *)Slab + Slab->Size; for (char *Ptr = (char*)(Slab+1); Ptr < End; Ptr += sizeof(T)) { - Ptr = Allocator.AlignPtr(Ptr, alignof()); + Ptr = Allocator.AlignPtr(Ptr, alignOf()); if (Ptr + sizeof(T) <= End) reinterpret_cast(Ptr)->~T(); } @@ -221,16 +223,12 @@ public: inline void *operator new(size_t Size, llvm::BumpPtrAllocator &Allocator) { struct S { char c; -#ifdef __GNUC__ - char x __attribute__((aligned)); -#else union { double D; long double LD; long long L; void *P; } x; -#endif }; return Allocator.Allocate(Size, std::min((size_t)llvm::NextPowerOf2(Size), offsetof(S, x))); diff --git a/include/llvm/Support/Atomic.h b/include/llvm/Support/Atomic.h new file mode 100644 index 000000000000..1a6c606aa5f6 --- /dev/null +++ b/include/llvm/Support/Atomic.h @@ -0,0 +1,39 @@ +//===- llvm/Support/Atomic.h - Atomic Operations -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the llvm::sys atomic operations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_ATOMIC_H +#define LLVM_SYSTEM_ATOMIC_H + +#include "llvm/Support/DataTypes.h" + +namespace llvm { + namespace sys { + void MemoryFence(); + +#ifdef _MSC_VER + typedef long cas_flag; +#else + typedef uint32_t cas_flag; +#endif + cas_flag CompareAndSwap(volatile cas_flag* ptr, + cas_flag new_value, + cas_flag old_value); + cas_flag AtomicIncrement(volatile cas_flag* ptr); + cas_flag AtomicDecrement(volatile cas_flag* ptr); + cas_flag AtomicAdd(volatile cas_flag* ptr, cas_flag val); + cas_flag AtomicMul(volatile cas_flag* ptr, cas_flag val); + cas_flag AtomicDiv(volatile cas_flag* ptr, cas_flag val); + } +} + +#endif diff --git a/include/llvm/Support/COFF.h b/include/llvm/Support/COFF.h index 78254ae9921f..673925593e6a 100644 --- a/include/llvm/Support/COFF.h +++ b/include/llvm/Support/COFF.h @@ -11,7 +11,7 @@ // // Structures and enums defined within this file where created using // information from Microsoft's publicly available PE/COFF format document: -// +// // Microsoft Portable Executable and Common Object File Format Specification // Revision 8.1 - February 15, 2008 // @@ -23,7 +23,7 @@ #ifndef LLVM_SUPPORT_WIN_COFF_H #define LLVM_SUPPORT_WIN_COFF_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include namespace llvm { @@ -69,7 +69,7 @@ namespace COFF { SF_ClassMask = 0x00FF0000, SF_ClassShift = 16, - SF_WeakReference = 0x01000000 + SF_WeakExternal = 0x01000000 }; enum SymbolSectionNumber { @@ -133,13 +133,13 @@ namespace COFF { }; enum SymbolComplexType { - IMAGE_SYM_DTYPE_NULL = 0, ///< No complex type; simple scalar variable. + IMAGE_SYM_DTYPE_NULL = 0, ///< No complex type; simple scalar variable. IMAGE_SYM_DTYPE_POINTER = 1, ///< A pointer to base type. IMAGE_SYM_DTYPE_FUNCTION = 2, ///< A function that returns a base type. IMAGE_SYM_DTYPE_ARRAY = 3, ///< An array of base type. - + /// Type is formed as (base + (derived << SCT_COMPLEX_TYPE_SHIFT)) - SCT_COMPLEX_TYPE_SHIFT = 8 + SCT_COMPLEX_TYPE_SHIFT = 4 }; struct section { diff --git a/include/llvm/Support/CallSite.h b/include/llvm/Support/CallSite.h index 9b6a4098b617..8a998a8cd0d1 100644 --- a/include/llvm/Support/CallSite.h +++ b/include/llvm/Support/CallSite.h @@ -52,12 +52,7 @@ public: CallSiteBase(CallTy *CI) : I(CI, true) { assert(CI); } CallSiteBase(InvokeTy *II) : I(II, false) { assert(II); } CallSiteBase(ValTy *II) { *this = get(II); } - CallSiteBase(InstrTy *II) { - assert(II && "Null instruction given?"); - *this = get(II); - assert(I.getPointer() && "Not a call?"); - } - +protected: /// CallSiteBase::get - This static method is sort of like a constructor. It /// will create an appropriate call site for a Call or Invoke instruction, but /// it can also create a null initialized CallSiteBase object for something @@ -72,7 +67,7 @@ public: } return CallSiteBase(); } - +public: /// isCall - true if a CallInst is enclosed. /// Note that !isCall() does not mean it is an InvokeInst enclosed, /// it also could signify a NULL Instruction pointer. @@ -282,16 +277,6 @@ public: bool operator==(const CallSite &CS) const { return I == CS.I; } bool operator!=(const CallSite &CS) const { return I != CS.I; } - - /// CallSite::get - This static method is sort of like a constructor. It will - /// create an appropriate call site for a Call or Invoke instruction, but it - /// can also create a null initialized CallSite object for something which is - /// NOT a call site. - /// - static CallSite get(Value *V) { - return Base::get(V); - } - bool operator<(const CallSite &CS) const { return getInstruction() < CS.getInstruction(); } diff --git a/include/llvm/Support/Casting.h b/include/llvm/Support/Casting.h index c589171bbafe..6bb98064382e 100644 --- a/include/llvm/Support/Casting.h +++ b/include/llvm/Support/Casting.h @@ -232,8 +232,8 @@ inline typename cast_retty::ret_type dyn_cast(const Y &Val) { // value is accepted. // template -inline typename cast_retty::ret_type dyn_cast_or_null(const Y &Val) { - return (Val && isa(Val)) ? cast(Val) : 0; +inline typename cast_retty::ret_type dyn_cast_or_null(Y *Val) { + return (Val && isa(Val)) ? cast(Val) : 0; } } // End llvm namespace diff --git a/include/llvm/Support/Compiler.h b/include/llvm/Support/Compiler.h index 14b36f80522d..67f0fd7e0dc6 100644 --- a/include/llvm/Support/Compiler.h +++ b/include/llvm/Support/Compiler.h @@ -15,48 +15,50 @@ #ifndef LLVM_SUPPORT_COMPILER_H #define LLVM_SUPPORT_COMPILER_H +#ifndef __has_feature +# define __has_feature(x) 0 +#endif + /// LLVM_LIBRARY_VISIBILITY - If a class marked with this attribute is linked /// into a shared library, then the class should be private to the library and /// not accessible from outside it. Can also be used to mark variables and /// functions, making them private to any shared library they are linked into. - -/// LLVM_GLOBAL_VISIBILITY - If a class marked with this attribute is linked -/// into a shared library, then the class will be accessible from outside the -/// the library. Can also be used to mark variables and functions, making them -/// accessible from outside any shared library they are linked into. -#if defined(__MINGW32__) || defined(__CYGWIN__) -#define LLVM_LIBRARY_VISIBILITY -#define LLVM_GLOBAL_VISIBILITY __declspec(dllexport) -#elif (__GNUC__ >= 4) +#if (__GNUC__ >= 4) && !defined(__MINGW32__) && !defined(__CYGWIN__) #define LLVM_LIBRARY_VISIBILITY __attribute__ ((visibility("hidden"))) -#define LLVM_GLOBAL_VISIBILITY __attribute__ ((visibility("default"))) #else #define LLVM_LIBRARY_VISIBILITY -#define LLVM_GLOBAL_VISIBILITY #endif #if (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) -#define ATTRIBUTE_USED __attribute__((__used__)) +#define LLVM_ATTRIBUTE_USED __attribute__((__used__)) #else -#define ATTRIBUTE_USED +#define LLVM_ATTRIBUTE_USED #endif +// Some compilers warn about unused functions. When a function is sometimes +// used or not depending on build settings (e.g. a function only called from +// within "assert"), this attribute can be used to suppress such warnings. +// +// However, it shouldn't be used for unused *variables*, as those have a much +// more portable solution: +// (void)unused_var_name; +// Prefer cast-to-void wherever it is sufficient. #if (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) -#define ATTRIBUTE_UNUSED __attribute__((__unused__)) +#define LLVM_ATTRIBUTE_UNUSED __attribute__((__unused__)) #else -#define ATTRIBUTE_UNUSED +#define LLVM_ATTRIBUTE_UNUSED #endif #ifdef __GNUC__ // aka 'ATTRIBUTE_CONST' but following LLVM Conventions. -#define ATTRIBUTE_READNONE __attribute__((__const__)) +#define LLVM_ATTRIBUTE_READNONE __attribute__((__const__)) #else -#define ATTRIBUTE_READNONE +#define LLVM_ATTRIBUTE_READNONE #endif #ifdef __GNUC__ // aka 'ATTRIBUTE_PURE' but following LLVM Conventions. -#define ATTRIBUTE_READONLY __attribute__((__pure__)) +#define LLVM_ATTRIBUTE_READONLY __attribute__((__pure__)) #else -#define ATTRIBUTE_READONLY +#define LLVM_ATTRIBUTE_READONLY #endif #if (__GNUC__ >= 4) @@ -78,34 +80,50 @@ #define TEMPLATE_INSTANTIATION(X) #endif -// DISABLE_INLINE - On compilers where we have a directive to do so, mark a -// method "not for inlining". +// LLVM_ATTRIBUTE_NOINLINE - On compilers where we have a directive to do so, +// mark a method "not for inlining". #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) -#define DISABLE_INLINE __attribute__((noinline)) +#define LLVM_ATTRIBUTE_NOINLINE __attribute__((noinline)) #elif defined(_MSC_VER) -#define DISABLE_INLINE __declspec(noinline) +#define LLVM_ATTRIBUTE_NOINLINE __declspec(noinline) #else -#define DISABLE_INLINE +#define LLVM_ATTRIBUTE_NOINLINE #endif -// ALWAYS_INLINE - On compilers where we have a directive to do so, mark a -// method "always inline" because it is performance sensitive. -// GCC 3.4 supported this but is buggy in various cases and produces -// unimplemented errors, just use it in GCC 4.0 and later. +// LLVM_ATTRIBUTE_ALWAYS_INLINE - On compilers where we have a directive to do +// so, mark a method "always inline" because it is performance sensitive. GCC +// 3.4 supported this but is buggy in various cases and produces unimplemented +// errors, just use it in GCC 4.0 and later. #if __GNUC__ > 3 -#define ALWAYS_INLINE __attribute__((always_inline)) +#define LLVM_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline)) +#elif defined(_MSC_VER) +#define LLVM_ATTRIBUTE_ALWAYS_INLINE __forceinline #else -// TODO: No idea how to do this with MSVC. -#define ALWAYS_INLINE +#define LLVM_ATTRIBUTE_ALWAYS_INLINE #endif #ifdef __GNUC__ -#define NORETURN __attribute__((noreturn)) +#define LLVM_ATTRIBUTE_NORETURN __attribute__((noreturn)) +#elif defined(_MSC_VER) +#define LLVM_ATTRIBUTE_NORETURN __declspec(noreturn) +#else +#define LLVM_ATTRIBUTE_NORETURN +#endif + +// LLVM_ATTRIBUTE_DEPRECATED(decl, "message") +#if __has_feature(attribute_deprecated_with_message) +# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \ + decl __attribute__((deprecated(message))) +#elif defined(__GNUC__) +# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \ + decl __attribute__((deprecated)) #elif defined(_MSC_VER) -#define NORETURN __declspec(noreturn) +# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \ + __declspec(deprecated(message)) decl #else -#define NORETURN +# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \ + decl #endif #endif diff --git a/include/llvm/Support/ConstantFolder.h b/include/llvm/Support/ConstantFolder.h index ea6c5fd82a08..bd3765d592db 100644 --- a/include/llvm/Support/ConstantFolder.h +++ b/include/llvm/Support/ConstantFolder.h @@ -33,50 +33,34 @@ public: // Binary Operators //===--------------------------------------------------------------------===// - Constant *CreateAdd(Constant *LHS, Constant *RHS) const { - return ConstantExpr::getAdd(LHS, RHS); - } - Constant *CreateNSWAdd(Constant *LHS, Constant *RHS) const { - return ConstantExpr::getNSWAdd(LHS, RHS); - } - Constant *CreateNUWAdd(Constant *LHS, Constant *RHS) const { - return ConstantExpr::getNUWAdd(LHS, RHS); + Constant *CreateAdd(Constant *LHS, Constant *RHS, + bool HasNUW = false, bool HasNSW = false) const { + return ConstantExpr::getAdd(LHS, RHS, HasNUW, HasNSW); } Constant *CreateFAdd(Constant *LHS, Constant *RHS) const { return ConstantExpr::getFAdd(LHS, RHS); } - Constant *CreateSub(Constant *LHS, Constant *RHS) const { - return ConstantExpr::getSub(LHS, RHS); - } - Constant *CreateNSWSub(Constant *LHS, Constant *RHS) const { - return ConstantExpr::getNSWSub(LHS, RHS); - } - Constant *CreateNUWSub(Constant *LHS, Constant *RHS) const { - return ConstantExpr::getNUWSub(LHS, RHS); + Constant *CreateSub(Constant *LHS, Constant *RHS, + bool HasNUW = false, bool HasNSW = false) const { + return ConstantExpr::getSub(LHS, RHS, HasNUW, HasNSW); } Constant *CreateFSub(Constant *LHS, Constant *RHS) const { return ConstantExpr::getFSub(LHS, RHS); } - Constant *CreateMul(Constant *LHS, Constant *RHS) const { - return ConstantExpr::getMul(LHS, RHS); - } - Constant *CreateNSWMul(Constant *LHS, Constant *RHS) const { - return ConstantExpr::getNSWMul(LHS, RHS); - } - Constant *CreateNUWMul(Constant *LHS, Constant *RHS) const { - return ConstantExpr::getNUWMul(LHS, RHS); + Constant *CreateMul(Constant *LHS, Constant *RHS, + bool HasNUW = false, bool HasNSW = false) const { + return ConstantExpr::getMul(LHS, RHS, HasNUW, HasNSW); } Constant *CreateFMul(Constant *LHS, Constant *RHS) const { return ConstantExpr::getFMul(LHS, RHS); } - Constant *CreateUDiv(Constant *LHS, Constant *RHS) const { - return ConstantExpr::getUDiv(LHS, RHS); - } - Constant *CreateSDiv(Constant *LHS, Constant *RHS) const { - return ConstantExpr::getSDiv(LHS, RHS); + Constant *CreateUDiv(Constant *LHS, Constant *RHS, + bool isExact = false) const { + return ConstantExpr::getUDiv(LHS, RHS, isExact); } - Constant *CreateExactSDiv(Constant *LHS, Constant *RHS) const { - return ConstantExpr::getExactSDiv(LHS, RHS); + Constant *CreateSDiv(Constant *LHS, Constant *RHS, + bool isExact = false) const { + return ConstantExpr::getSDiv(LHS, RHS, isExact); } Constant *CreateFDiv(Constant *LHS, Constant *RHS) const { return ConstantExpr::getFDiv(LHS, RHS); @@ -90,14 +74,17 @@ public: Constant *CreateFRem(Constant *LHS, Constant *RHS) const { return ConstantExpr::getFRem(LHS, RHS); } - Constant *CreateShl(Constant *LHS, Constant *RHS) const { - return ConstantExpr::getShl(LHS, RHS); + Constant *CreateShl(Constant *LHS, Constant *RHS, + bool HasNUW = false, bool HasNSW = false) const { + return ConstantExpr::getShl(LHS, RHS, HasNUW, HasNSW); } - Constant *CreateLShr(Constant *LHS, Constant *RHS) const { - return ConstantExpr::getLShr(LHS, RHS); + Constant *CreateLShr(Constant *LHS, Constant *RHS, + bool isExact = false) const { + return ConstantExpr::getLShr(LHS, RHS, isExact); } - Constant *CreateAShr(Constant *LHS, Constant *RHS) const { - return ConstantExpr::getAShr(LHS, RHS); + Constant *CreateAShr(Constant *LHS, Constant *RHS, + bool isExact = false) const { + return ConstantExpr::getAShr(LHS, RHS, isExact); } Constant *CreateAnd(Constant *LHS, Constant *RHS) const { return ConstantExpr::getAnd(LHS, RHS); @@ -118,14 +105,9 @@ public: // Unary Operators //===--------------------------------------------------------------------===// - Constant *CreateNeg(Constant *C) const { - return ConstantExpr::getNeg(C); - } - Constant *CreateNSWNeg(Constant *C) const { - return ConstantExpr::getNSWNeg(C); - } - Constant *CreateNUWNeg(Constant *C) const { - return ConstantExpr::getNUWNeg(C); + Constant *CreateNeg(Constant *C, + bool HasNUW = false, bool HasNSW = false) const { + return ConstantExpr::getNeg(C, HasNUW, HasNSW); } Constant *CreateFNeg(Constant *C) const { return ConstantExpr::getFNeg(C); diff --git a/include/llvm/Support/ConstantRange.h b/include/llvm/Support/ConstantRange.h index 29086b2ac4f2..ced3a2cf2dbd 100644 --- a/include/llvm/Support/ConstantRange.h +++ b/include/llvm/Support/ConstantRange.h @@ -33,7 +33,7 @@ #define LLVM_SUPPORT_CONSTANT_RANGE_H #include "llvm/ADT/APInt.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { @@ -54,7 +54,7 @@ public: /// @brief Initialize a range of values explicitly. This will assert out if /// Lower==Upper and Lower != Min or Max value for its type. It will also /// assert out if the two APInt's are not the same bit width. - ConstantRange(const APInt& Lower, const APInt& Upper); + ConstantRange(const APInt &Lower, const APInt &Upper); /// makeICmpRegion - Produce the smallest range that contains all values that /// might satisfy the comparison specified by Pred when compared to any value @@ -92,6 +92,11 @@ public: /// bool isWrappedSet() const; + /// isSignWrappedSet - Return true if this set wraps around the INT_MIN of + /// its bitwidth, for example: i8 [120, 140). + /// + bool isSignWrappedSet() const; + /// contains - Return true if the specified value is in the set. /// bool contains(const APInt &Val) const; @@ -219,6 +224,14 @@ public: /// \p Other. ConstantRange udiv(const ConstantRange &Other) const; + /// binaryAnd - return a new range representing the possible values resulting + /// from a binary-and of a value in this range by a value in \p Other. + ConstantRange binaryAnd(const ConstantRange &Other) const; + + /// binaryOr - return a new range representing the possible values resulting + /// from a binary-or of a value in this range by a value in \p Other. + ConstantRange binaryOr(const ConstantRange &Other) const; + /// shl - Return a new range representing the possible values resulting /// from a left shift of a value in this range by a value in \p Other. /// TODO: This isn't fully implemented yet. diff --git a/include/llvm/Support/CrashRecoveryContext.h b/include/llvm/Support/CrashRecoveryContext.h index d66609fddfec..2e9b5d4aa541 100644 --- a/include/llvm/Support/CrashRecoveryContext.h +++ b/include/llvm/Support/CrashRecoveryContext.h @@ -67,6 +67,14 @@ public: /// the backtrace of the crash on failures. bool RunSafely(void (*Fn)(void*), void *UserData); + /// \brief Execute the provide callback function (with the given arguments) in + /// a protected context which is run in another thread (optionally with a + /// requested stack size). + /// + /// See RunSafely() and llvm_execute_on_thread(). + bool RunSafelyOnThread(void (*Fn)(void*), void *UserData, + unsigned RequestedStackSize = 0); + /// \brief Explicitly trigger a crash recovery in the current process, and /// return failure from RunSafely(). This function does not return. void HandleCrash(); diff --git a/include/llvm/Support/DataTypes.h.cmake b/include/llvm/Support/DataTypes.h.cmake new file mode 100644 index 000000000000..72c451873c0f --- /dev/null +++ b/include/llvm/Support/DataTypes.h.cmake @@ -0,0 +1,189 @@ +/*===-- include/Support/DataTypes.h - Define fixed size types -----*- C -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file contains definitions to figure out the size of _HOST_ data types.*| +|* This file is important because different host OS's define different macros,*| +|* which makes portability tough. This file exports the following *| +|* definitions: *| +|* *| +|* [u]int(32|64)_t : typedefs for signed and unsigned 32/64 bit system types*| +|* [U]INT(8|16|32|64)_(MIN|MAX) : Constants for the min and max values. *| +|* *| +|* No library is required when using these functinons. *| +|* *| +|*===----------------------------------------------------------------------===*/ + +/* Please leave this file C-compatible. */ + +#ifndef SUPPORT_DATATYPES_H +#define SUPPORT_DATATYPES_H + +#cmakedefine HAVE_SYS_TYPES_H ${HAVE_SYS_TYPES_H} +#cmakedefine HAVE_INTTYPES_H ${HAVE_INTTYPES_H} +#cmakedefine HAVE_STDINT_H ${HAVE_STDINT_H} +#cmakedefine HAVE_UINT64_T ${HAVE_UINT64_T} +#cmakedefine HAVE_U_INT64_T ${HAVE_U_INT64_T} + +#ifdef __cplusplus +#include +#else +#include +#endif + +#ifndef _MSC_VER + +/* Note that this header's correct operation depends on __STDC_LIMIT_MACROS + being defined. We would define it here, but in order to prevent Bad Things + happening when system headers or C++ STL headers include stdint.h before we + define it here, we define it on the g++ command line (in Makefile.rules). */ +#if !defined(__STDC_LIMIT_MACROS) +# error "Must #define __STDC_LIMIT_MACROS before #including Support/DataTypes.h" +#endif + +#if !defined(__STDC_CONSTANT_MACROS) +# error "Must #define __STDC_CONSTANT_MACROS before " \ + "#including Support/DataTypes.h" +#endif + +/* Note that includes , if this is a C99 system. */ +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#ifdef HAVE_INTTYPES_H +#include +#endif + +#ifdef HAVE_STDINT_H +#include +#endif + +#ifdef _AIX +#include "llvm/Support/AIXDataTypesFix.h" +#endif + +/* Handle incorrect definition of uint64_t as u_int64_t */ +#ifndef HAVE_UINT64_T +#ifdef HAVE_U_INT64_T +typedef u_int64_t uint64_t; +#else +# error "Don't have a definition for uint64_t on this platform" +#endif +#endif + +#ifdef _OpenBSD_ +#define INT8_MAX 127 +#define INT8_MIN -128 +#define UINT8_MAX 255 +#define INT16_MAX 32767 +#define INT16_MIN -32768 +#define UINT16_MAX 65535 +#define INT32_MAX 2147483647 +#define INT32_MIN -2147483648 +#define UINT32_MAX 4294967295U +#endif + +#else /* _MSC_VER */ +/* Visual C++ doesn't provide standard integer headers, but it does provide + built-in data types. */ +#include +#include +#include +#ifdef __cplusplus +#include +#else +#include +#endif +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +typedef signed int int32_t; +typedef unsigned int uint32_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef signed int ssize_t; +#ifndef INT8_MAX +# define INT8_MAX 127 +#endif +#ifndef INT8_MIN +# define INT8_MIN -128 +#endif +#ifndef UINT8_MAX +# define UINT8_MAX 255 +#endif +#ifndef INT16_MAX +# define INT16_MAX 32767 +#endif +#ifndef INT16_MIN +# define INT16_MIN -32768 +#endif +#ifndef UINT16_MAX +# define UINT16_MAX 65535 +#endif +#ifndef INT32_MAX +# define INT32_MAX 2147483647 +#endif +#ifndef INT32_MIN +# define INT32_MIN -2147483648 +#endif +#ifndef UINT32_MAX +# define UINT32_MAX 4294967295U +#endif +/* Certain compatibility updates to VC++ introduce the `cstdint' + * header, which defines the INT*_C macros. On default installs they + * are absent. */ +#ifndef INT8_C +# define INT8_C(C) C##i8 +#endif +#ifndef UINT8_C +# define UINT8_C(C) C##ui8 +#endif +#ifndef INT16_C +# define INT16_C(C) C##i16 +#endif +#ifndef UINT16_C +# define UINT16_C(C) C##ui16 +#endif +#ifndef INT32_C +# define INT32_C(C) C##i32 +#endif +#ifndef UINT32_C +# define UINT32_C(C) C##ui32 +#endif +#ifndef INT64_C +# define INT64_C(C) C##i64 +#endif +#ifndef UINT64_C +# define UINT64_C(C) C##ui64 +#endif +#endif /* _MSC_VER */ + +/* Set defaults for constants which we cannot find. */ +#if !defined(INT64_MAX) +# define INT64_MAX 9223372036854775807LL +#endif +#if !defined(INT64_MIN) +# define INT64_MIN ((-INT64_MAX)-1) +#endif +#if !defined(UINT64_MAX) +# define UINT64_MAX 0xffffffffffffffffULL +#endif + +#if __GNUC__ > 3 +#define END_WITH_NULL __attribute__((sentinel)) +#else +#define END_WITH_NULL +#endif + +#ifndef HUGE_VALF +#define HUGE_VALF (float)HUGE_VAL +#endif + +#endif /* SUPPORT_DATATYPES_H */ diff --git a/include/llvm/Support/DataTypes.h.in b/include/llvm/Support/DataTypes.h.in new file mode 100644 index 000000000000..5965e8c0b2a9 --- /dev/null +++ b/include/llvm/Support/DataTypes.h.in @@ -0,0 +1,111 @@ +/*===-- include/System/DataTypes.h - Define fixed size types -----*- C -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file contains definitions to figure out the size of _HOST_ data types.*| +|* This file is important because different host OS's define different macros,*| +|* which makes portability tough. This file exports the following *| +|* definitions: *| +|* *| +|* [u]int(32|64)_t : typedefs for signed and unsigned 32/64 bit system types*| +|* [U]INT(8|16|32|64)_(MIN|MAX) : Constants for the min and max values. *| +|* *| +|* No library is required when using these functions. *| +|* *| +|*===----------------------------------------------------------------------===*/ + +/* Please leave this file C-compatible. */ + +#ifndef SUPPORT_DATATYPES_H +#define SUPPORT_DATATYPES_H + +#undef HAVE_SYS_TYPES_H +#undef HAVE_INTTYPES_H +#undef HAVE_STDINT_H +#undef HAVE_UINT64_T +#undef HAVE_U_INT64_T + +#ifdef __cplusplus +#include +#else +#include +#endif + +/* Note that this header's correct operation depends on __STDC_LIMIT_MACROS + being defined. We would define it here, but in order to prevent Bad Things + happening when system headers or C++ STL headers include stdint.h before we + define it here, we define it on the g++ command line (in Makefile.rules). */ +#if !defined(__STDC_LIMIT_MACROS) +# error "Must #define __STDC_LIMIT_MACROS before #including System/DataTypes.h" +#endif + +#if !defined(__STDC_CONSTANT_MACROS) +# error "Must #define __STDC_CONSTANT_MACROS before " \ + "#including System/DataTypes.h" +#endif + +/* Note that includes , if this is a C99 system. */ +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#ifdef HAVE_INTTYPES_H +#include +#endif + +#ifdef HAVE_STDINT_H +#include +#endif + +#ifdef _AIX +#include "llvm/Support/AIXDataTypesFix.h" +#endif + +/* Handle incorrect definition of uint64_t as u_int64_t */ +#ifndef HAVE_UINT64_T +#ifdef HAVE_U_INT64_T +typedef u_int64_t uint64_t; +#else +# error "Don't have a definition for uint64_t on this platform" +#endif +#endif + +#ifdef _OpenBSD_ +#define INT8_MAX 127 +#define INT8_MIN -128 +#define UINT8_MAX 255 +#define INT16_MAX 32767 +#define INT16_MIN -32768 +#define UINT16_MAX 65535 +#define INT32_MAX 2147483647 +#define INT32_MIN -2147483648 +#define UINT32_MAX 4294967295U +#endif + +/* Set defaults for constants which we cannot find. */ +#if !defined(INT64_MAX) +# define INT64_MAX 9223372036854775807LL +#endif +#if !defined(INT64_MIN) +# define INT64_MIN ((-INT64_MAX)-1) +#endif +#if !defined(UINT64_MAX) +# define UINT64_MAX 0xffffffffffffffffULL +#endif + +#if __GNUC__ > 3 +#define END_WITH_NULL __attribute__((sentinel)) +#else +#define END_WITH_NULL +#endif + +#ifndef HUGE_VALF +#define HUGE_VALF (float)HUGE_VAL +#endif + +#endif /* SUPPORT_DATATYPES_H */ diff --git a/include/llvm/Support/Disassembler.h b/include/llvm/Support/Disassembler.h new file mode 100644 index 000000000000..6d1cc0fdcb50 --- /dev/null +++ b/include/llvm/Support/Disassembler.h @@ -0,0 +1,35 @@ +//===- llvm/Support/Disassembler.h ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the necessary glue to call external disassembler +// libraries. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_DISASSEMBLER_H +#define LLVM_SYSTEM_DISASSEMBLER_H + +#include "llvm/Support/DataTypes.h" +#include + +namespace llvm { +namespace sys { + +/// This function returns true, if there is possible to use some external +/// disassembler library. False otherwise. +bool hasDisassembler(); + +/// This function provides some "glue" code to call external disassembler +/// libraries. +std::string disassembleBuffer(uint8_t* start, size_t length, uint64_t pc = 0); + +} +} + +#endif // LLVM_SYSTEM_DISASSEMBLER_H diff --git a/include/llvm/Support/Dwarf.h b/include/llvm/Support/Dwarf.h index 3ca8d96dfc37..5d0b5a943d56 100644 --- a/include/llvm/Support/Dwarf.h +++ b/include/llvm/Support/Dwarf.h @@ -22,7 +22,8 @@ namespace llvm { // Debug info constants. enum { - LLVMDebugVersion = (8 << 16), // Current version of debug information. + LLVMDebugVersion = (9 << 16), // Current version of debug information. + LLVMDebugVersion8 = (8 << 16), // Cconstant for version 8. LLVMDebugVersion7 = (7 << 16), // Constant for version 7. LLVMDebugVersion6 = (6 << 16), // Constant for version 6. LLVMDebugVersion5 = (5 << 16), // Constant for version 5. @@ -44,11 +45,9 @@ enum llvm_dwarf_constants { // llvm mock tags DW_TAG_invalid = ~0U, // Tag for invalid results. - DW_TAG_anchor = 0, // Tag for descriptor anchors. DW_TAG_auto_variable = 0x100, // Tag for local (auto) variables. DW_TAG_arg_variable = 0x101, // Tag for argument variables. DW_TAG_return_variable = 0x102, // Tag for return variables. - DW_TAG_vector_type = 0x103, // Tag for vector types. DW_TAG_user_base = 0x1000, // Recommended base for user tags. @@ -118,6 +117,7 @@ enum dwarf_constants { DW_TAG_imported_unit = 0x3d, DW_TAG_condition = 0x3f, DW_TAG_shared_type = 0x40, + DW_TAG_rvalue_reference_type = 0x41, DW_TAG_lo_user = 0x4080, DW_TAG_hi_user = 0xffff, @@ -509,6 +509,7 @@ enum dwarf_constants { DW_DSC_range = 0x01, // Line Number Standard Opcode Encodings + DW_LNS_extended_op = 0x00, DW_LNS_copy = 0x01, DW_LNS_advance_pc = 0x02, DW_LNS_advance_line = 0x03, diff --git a/include/llvm/Support/DynamicLibrary.h b/include/llvm/Support/DynamicLibrary.h new file mode 100644 index 000000000000..e6d9ff57ae83 --- /dev/null +++ b/include/llvm/Support/DynamicLibrary.h @@ -0,0 +1,86 @@ +//===-- llvm/Support/DynamicLibrary.h - Portable Dynamic Library -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the sys::DynamicLibrary class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_DYNAMIC_LIBRARY_H +#define LLVM_SYSTEM_DYNAMIC_LIBRARY_H + +#include + +namespace llvm { +namespace sys { + + /// This class provides a portable interface to dynamic libraries which also + /// might be known as shared libraries, shared objects, dynamic shared + /// objects, or dynamic link libraries. Regardless of the terminology or the + /// operating system interface, this class provides a portable interface that + /// allows dynamic libraries to be loaded and searched for externally + /// defined symbols. This is typically used to provide "plug-in" support. + /// It also allows for symbols to be defined which don't live in any library, + /// but rather the main program itself, useful on Windows where the main + /// executable cannot be searched. + class DynamicLibrary { + DynamicLibrary(); // DO NOT IMPLEMENT + public: + /// This function allows a library to be loaded without instantiating a + /// DynamicLibrary object. Consequently, it is marked as being permanent + /// and will only be unloaded when the program terminates. This returns + /// false on success or returns true and fills in *ErrMsg on failure. + /// @brief Open a dynamic library permanently. + /// + /// NOTE: This function is not thread safe. + /// + static bool LoadLibraryPermanently(const char *filename, + std::string *ErrMsg = 0); + + /// This function will search through all previously loaded dynamic + /// libraries for the symbol \p symbolName. If it is found, the addressof + /// that symbol is returned. If not, null is returned. Note that this will + /// search permanently loaded libraries (LoadLibraryPermanently) as well + /// as ephemerally loaded libraries (constructors). + /// @throws std::string on error. + /// @brief Search through libraries for address of a symbol + /// + /// NOTE: This function is not thread safe. + /// + static void *SearchForAddressOfSymbol(const char *symbolName); + + /// @brief Convenience function for C++ophiles. + /// + /// NOTE: This function is not thread safe. + /// + static void *SearchForAddressOfSymbol(const std::string &symbolName) { + return SearchForAddressOfSymbol(symbolName.c_str()); + } + + /// This functions permanently adds the symbol \p symbolName with the + /// value \p symbolValue. These symbols are searched before any + /// libraries. + /// @brief Add searchable symbol/value pair. + /// + /// NOTE: This function is not thread safe. + /// + static void AddSymbol(const char *symbolName, void *symbolValue); + + /// @brief Convenience function for C++ophiles. + /// + /// NOTE: This function is not thread safe. + /// + static void AddSymbol(const std::string &symbolName, void *symbolValue) { + AddSymbol(symbolName.c_str(), symbolValue); + } + }; + +} // End sys namespace +} // End llvm namespace + +#endif // LLVM_SYSTEM_DYNAMIC_LIBRARY_H diff --git a/include/llvm/Support/DynamicLinker.h b/include/llvm/Support/DynamicLinker.h deleted file mode 100644 index b60ffa875c63..000000000000 --- a/include/llvm/Support/DynamicLinker.h +++ /dev/null @@ -1,40 +0,0 @@ -//===-- llvm/Support/DynamicLinker.h - Portable Dynamic Linker --*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Lightweight interface to dynamic library linking and loading, and dynamic -// symbol lookup functionality, in whatever form the operating system -// provides it. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SUPPORT_DYNAMICLINKER_H -#define LLVM_SUPPORT_DYNAMICLINKER_H - -#include - -namespace llvm { - -/// LinkDynamicObject - Load the named file as a dynamic library -/// and link it with the currently running process. Returns false -/// on success, true if there is an error (and sets ErrorMessage -/// if it is not NULL). Analogous to dlopen(). -/// -bool LinkDynamicObject (const char *filename, std::string *ErrorMessage); - -/// GetAddressOfSymbol - Returns the address of the named symbol in -/// the currently running process, as reported by the dynamic linker, -/// or NULL if the symbol does not exist or some other error has -/// occurred. -/// -void *GetAddressOfSymbol (const char *symbolName); -void *GetAddressOfSymbol (const std::string &symbolName); - -} // End llvm namespace - -#endif // SUPPORT_DYNAMICLINKER_H diff --git a/include/llvm/Support/ELF.h b/include/llvm/Support/ELF.h index 83478b75cbc4..cc72bd59cb70 100644 --- a/include/llvm/Support/ELF.h +++ b/include/llvm/Support/ELF.h @@ -20,7 +20,7 @@ #ifndef LLVM_SUPPORT_ELF_H #define LLVM_SUPPORT_ELF_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include namespace llvm { @@ -126,25 +126,27 @@ enum { // Machine architectures enum { - EM_NONE = 0, // No machine - EM_M32 = 1, // AT&T WE 32100 - EM_SPARC = 2, // SPARC - EM_386 = 3, // Intel 386 - EM_68K = 4, // Motorola 68000 - EM_88K = 5, // Motorola 88000 - EM_486 = 6, // Intel 486 (deprecated) - EM_860 = 7, // Intel 80860 - EM_MIPS = 8, // MIPS R3000 - EM_PPC = 20, // PowerPC - EM_PPC64 = 21, // PowerPC64 - EM_ARM = 40, // ARM - EM_ALPHA = 41, // DEC Alpha - EM_SPARCV9 = 43, // SPARC V9 - EM_X86_64 = 62 // AMD64 + EM_NONE = 0, // No machine + EM_M32 = 1, // AT&T WE 32100 + EM_SPARC = 2, // SPARC + EM_386 = 3, // Intel 386 + EM_68K = 4, // Motorola 68000 + EM_88K = 5, // Motorola 88000 + EM_486 = 6, // Intel 486 (deprecated) + EM_860 = 7, // Intel 80860 + EM_MIPS = 8, // MIPS R3000 + EM_PPC = 20, // PowerPC + EM_PPC64 = 21, // PowerPC64 + EM_ARM = 40, // ARM + EM_ALPHA = 41, // DEC Alpha + EM_SPARCV9 = 43, // SPARC V9 + EM_X86_64 = 62, // AMD64 + EM_MBLAZE = 47787 // Xilinx MicroBlaze }; // Object file classes. enum { + ELFCLASSNONE = 0, ELFCLASS32 = 1, // 32-bit object file ELFCLASS64 = 2 // 64-bit object file }; @@ -231,12 +233,206 @@ enum { R_386_GOTOFF = 9, R_386_GOTPC = 10, R_386_32PLT = 11, + R_386_TLS_TPOFF = 14, + R_386_TLS_IE = 15, + R_386_TLS_GOTIE = 16, + R_386_TLS_LE = 17, + R_386_TLS_GD = 18, + R_386_TLS_LDM = 19, R_386_16 = 20, R_386_PC16 = 21, R_386_8 = 22, - R_386_PC8 = 23 + R_386_PC8 = 23, + R_386_TLS_GD_32 = 24, + R_386_TLS_GD_PUSH = 25, + R_386_TLS_GD_CALL = 26, + R_386_TLS_GD_POP = 27, + R_386_TLS_LDM_32 = 28, + R_386_TLS_LDM_PUSH = 29, + R_386_TLS_LDM_CALL = 30, + R_386_TLS_LDM_POP = 31, + R_386_TLS_LDO_32 = 32, + R_386_TLS_IE_32 = 33, + R_386_TLS_LE_32 = 34, + R_386_TLS_DTPMOD32 = 35, + R_386_TLS_DTPOFF32 = 36, + R_386_TLS_TPOFF32 = 37, + R_386_TLS_GOTDESC = 39, + R_386_TLS_DESC_CALL = 40, + R_386_TLS_DESC = 41, + R_386_IRELATIVE = 42, + R_386_NUM = 43 +}; + +// MBlaze relocations. +enum { + R_MICROBLAZE_NONE = 0, + R_MICROBLAZE_32 = 1, + R_MICROBLAZE_32_PCREL = 2, + R_MICROBLAZE_64_PCREL = 3, + R_MICROBLAZE_32_PCREL_LO = 4, + R_MICROBLAZE_64 = 5, + R_MICROBLAZE_32_LO = 6, + R_MICROBLAZE_SRO32 = 7, + R_MICROBLAZE_SRW32 = 8, + R_MICROBLAZE_64_NONE = 9, + R_MICROBLAZE_32_SYM_OP_SYM = 10, + R_MICROBLAZE_GNU_VTINHERIT = 11, + R_MICROBLAZE_GNU_VTENTRY = 12, + R_MICROBLAZE_GOTPC_64 = 13, + R_MICROBLAZE_GOT_64 = 14, + R_MICROBLAZE_PLT_64 = 15, + R_MICROBLAZE_REL = 16, + R_MICROBLAZE_JUMP_SLOT = 17, + R_MICROBLAZE_GLOB_DAT = 18, + R_MICROBLAZE_GOTOFF_64 = 19, + R_MICROBLAZE_GOTOFF_32 = 20, + R_MICROBLAZE_COPY = 21 +}; + + +// ARM Specific e_flags +enum { EF_ARM_EABIMASK = 0xFF000000U }; + +// ELF Relocation types for ARM +// Meets 2.08 ABI Specs. + +enum { + R_ARM_NONE = 0x00, + R_ARM_PC24 = 0x01, + R_ARM_ABS32 = 0x02, + R_ARM_REL32 = 0x03, + R_ARM_LDR_PC_G0 = 0x04, + R_ARM_ABS16 = 0x05, + R_ARM_ABS12 = 0x06, + R_ARM_THM_ABS5 = 0x07, + R_ARM_ABS8 = 0x08, + R_ARM_SBREL32 = 0x09, + R_ARM_THM_CALL = 0x0a, + R_ARM_THM_PC8 = 0x0b, + R_ARM_BREL_ADJ = 0x0c, + R_ARM_TLS_DESC = 0x0d, + R_ARM_THM_SWI8 = 0x0e, + R_ARM_XPC25 = 0x0f, + R_ARM_THM_XPC22 = 0x10, + R_ARM_TLS_DTPMOD32 = 0x11, + R_ARM_TLS_DTPOFF32 = 0x12, + R_ARM_TLS_TPOFF32 = 0x13, + R_ARM_COPY = 0x14, + R_ARM_GLOB_DAT = 0x15, + R_ARM_JUMP_SLOT = 0x16, + R_ARM_RELATIVE = 0x17, + R_ARM_GOTOFF32 = 0x18, + R_ARM_BASE_PREL = 0x19, + R_ARM_GOT_BREL = 0x1a, + R_ARM_PLT32 = 0x1b, + R_ARM_CALL = 0x1c, + R_ARM_JUMP24 = 0x1d, + R_ARM_THM_JUMP24 = 0x1e, + R_ARM_BASE_ABS = 0x1f, + R_ARM_ALU_PCREL_7_0 = 0x20, + R_ARM_ALU_PCREL_15_8 = 0x21, + R_ARM_ALU_PCREL_23_15 = 0x22, + R_ARM_LDR_SBREL_11_0_NC = 0x23, + R_ARM_ALU_SBREL_19_12_NC = 0x24, + R_ARM_ALU_SBREL_27_20_CK = 0x25, + R_ARM_TARGET1 = 0x26, + R_ARM_SBREL31 = 0x27, + R_ARM_V4BX = 0x28, + R_ARM_TARGET2 = 0x29, + R_ARM_PREL31 = 0x2a, + R_ARM_MOVW_ABS_NC = 0x2b, + R_ARM_MOVT_ABS = 0x2c, + R_ARM_MOVW_PREL_NC = 0x2d, + R_ARM_MOVT_PREL = 0x2e, + R_ARM_THM_MOVW_ABS_NC = 0x2f, + R_ARM_THM_MOVT_ABS = 0x30, + R_ARM_THM_MOVW_PREL_NC = 0x31, + R_ARM_THM_MOVT_PREL = 0x32, + R_ARM_THM_JUMP19 = 0x33, + R_ARM_THM_JUMP6 = 0x34, + R_ARM_THM_ALU_PREL_11_0 = 0x35, + R_ARM_THM_PC12 = 0x36, + R_ARM_ABS32_NOI = 0x37, + R_ARM_REL32_NOI = 0x38, + R_ARM_ALU_PC_G0_NC = 0x39, + R_ARM_ALU_PC_G0 = 0x3a, + R_ARM_ALU_PC_G1_NC = 0x3b, + R_ARM_ALU_PC_G1 = 0x3c, + R_ARM_ALU_PC_G2 = 0x3d, + R_ARM_LDR_PC_G1 = 0x3e, + R_ARM_LDR_PC_G2 = 0x3f, + R_ARM_LDRS_PC_G0 = 0x40, + R_ARM_LDRS_PC_G1 = 0x41, + R_ARM_LDRS_PC_G2 = 0x42, + R_ARM_LDC_PC_G0 = 0x43, + R_ARM_LDC_PC_G1 = 0x44, + R_ARM_LDC_PC_G2 = 0x45, + R_ARM_ALU_SB_G0_NC = 0x46, + R_ARM_ALU_SB_G0 = 0x47, + R_ARM_ALU_SB_G1_NC = 0x48, + R_ARM_ALU_SB_G1 = 0x49, + R_ARM_ALU_SB_G2 = 0x4a, + R_ARM_LDR_SB_G0 = 0x4b, + R_ARM_LDR_SB_G1 = 0x4c, + R_ARM_LDR_SB_G2 = 0x4d, + R_ARM_LDRS_SB_G0 = 0x4e, + R_ARM_LDRS_SB_G1 = 0x4f, + R_ARM_LDRS_SB_G2 = 0x50, + R_ARM_LDC_SB_G0 = 0x51, + R_ARM_LDC_SB_G1 = 0x52, + R_ARM_LDC_SB_G2 = 0x53, + R_ARM_MOVW_BREL_NC = 0x54, + R_ARM_MOVT_BREL = 0x55, + R_ARM_MOVW_BREL = 0x56, + R_ARM_THM_MOVW_BREL_NC = 0x57, + R_ARM_THM_MOVT_BREL = 0x58, + R_ARM_THM_MOVW_BREL = 0x59, + R_ARM_TLS_GOTDESC = 0x5a, + R_ARM_TLS_CALL = 0x5b, + R_ARM_TLS_DESCSEQ = 0x5c, + R_ARM_THM_TLS_CALL = 0x5d, + R_ARM_PLT32_ABS = 0x5e, + R_ARM_GOT_ABS = 0x5f, + R_ARM_GOT_PREL = 0x60, + R_ARM_GOT_BREL12 = 0x61, + R_ARM_GOTOFF12 = 0x62, + R_ARM_GOTRELAX = 0x63, + R_ARM_GNU_VTENTRY = 0x64, + R_ARM_GNU_VTINHERIT = 0x65, + R_ARM_THM_JUMP11 = 0x66, + R_ARM_THM_JUMP8 = 0x67, + R_ARM_TLS_GD32 = 0x68, + R_ARM_TLS_LDM32 = 0x69, + R_ARM_TLS_LDO32 = 0x6a, + R_ARM_TLS_IE32 = 0x6b, + R_ARM_TLS_LE32 = 0x6c, + R_ARM_TLS_LDO12 = 0x6d, + R_ARM_TLS_LE12 = 0x6e, + R_ARM_TLS_IE12GP = 0x6f, + R_ARM_PRIVATE_0 = 0x70, + R_ARM_PRIVATE_1 = 0x71, + R_ARM_PRIVATE_2 = 0x72, + R_ARM_PRIVATE_3 = 0x73, + R_ARM_PRIVATE_4 = 0x74, + R_ARM_PRIVATE_5 = 0x75, + R_ARM_PRIVATE_6 = 0x76, + R_ARM_PRIVATE_7 = 0x77, + R_ARM_PRIVATE_8 = 0x78, + R_ARM_PRIVATE_9 = 0x79, + R_ARM_PRIVATE_10 = 0x7a, + R_ARM_PRIVATE_11 = 0x7b, + R_ARM_PRIVATE_12 = 0x7c, + R_ARM_PRIVATE_13 = 0x7d, + R_ARM_PRIVATE_14 = 0x7e, + R_ARM_PRIVATE_15 = 0x7f, + R_ARM_ME_TOO = 0x80, + R_ARM_THM_TLS_DESCSEQ16 = 0x81, + R_ARM_THM_TLS_DESCSEQ32 = 0x82 }; + + // Section header. struct Elf32_Shdr { Elf32_Word sh_name; // Section name (index into string table) @@ -273,6 +469,7 @@ enum { SHN_HIPROC = 0xff1f, // Highest processor-specific index SHN_ABS = 0xfff1, // Symbol has absolute value; does not need relocation SHN_COMMON = 0xfff2, // FORTRAN COMMON or C external global variables + SHN_XINDEX = 0xffff, // Mark that the index is >= SHN_LORESERVE SHN_HIRESERVE = 0xffff // Highest reserved index }; @@ -298,6 +495,18 @@ enum { SHT_LOOS = 0x60000000, // Lowest operating system-specific type. SHT_HIOS = 0x6fffffff, // Highest operating system-specific type. SHT_LOPROC = 0x70000000, // Lowest processor architecture-specific type. + // Fixme: All this is duplicated in MCSectionELF. Why?? + // Exception Index table + SHT_ARM_EXIDX = 0x70000001U, + // BPABI DLL dynamic linking pre-emption map + SHT_ARM_PREEMPTMAP = 0x70000002U, + // Object file compatibility attributes + SHT_ARM_ATTRIBUTES = 0x70000003U, + SHT_ARM_DEBUGOVERLAY = 0x70000004U, + SHT_ARM_OVERLAYSECTION = 0x70000005U, + + SHT_X86_64_UNWIND = 0x70000001, // Unwind information + SHT_HIPROC = 0x7fffffff, // Highest processor architecture-specific type. SHT_LOUSER = 0x80000000, // Lowest type reserved for applications. SHT_HIUSER = 0xffffffff // Highest type reserved for applications. @@ -305,10 +514,58 @@ enum { // Section flags. enum { - SHF_WRITE = 0x1, // Section data should be writable during execution. - SHF_ALLOC = 0x2, // Section occupies memory during program execution. - SHF_EXECINSTR = 0x4, // Section contains executable machine instructions. - SHF_MASKPROC = 0xf0000000 // Bits indicating processor-specific flags. + // Section data should be writable during execution. + SHF_WRITE = 0x1, + + // Section occupies memory during program execution. + SHF_ALLOC = 0x2, + + // Section contains executable machine instructions. + SHF_EXECINSTR = 0x4, + + // The data in this section may be merged. + SHF_MERGE = 0x10, + + // The data in this section is null-terminated strings. + SHF_STRINGS = 0x20, + + // A field in this section holds a section header table index. + SHF_INFO_LINK = 0x40U, + + // Adds special ordering requirements for link editors. + SHF_LINK_ORDER = 0x80U, + + // This section requires special OS-specific processing to avoid incorrect + // behavior. + SHF_OS_NONCONFORMING = 0x100U, + + // This section is a member of a section group. + SHF_GROUP = 0x200U, + + // This section holds Thread-Local Storage. + SHF_TLS = 0x400U, + + // Start of target-specific flags. + + /// XCORE_SHF_CP_SECTION - All sections with the "c" flag are grouped + /// together by the linker to form the constant pool and the cp register is + /// set to the start of the constant pool by the boot code. + XCORE_SHF_CP_SECTION = 0x800U, + + /// XCORE_SHF_DP_SECTION - All sections with the "d" flag are grouped + /// together by the linker to form the data section and the dp register is + /// set to the start of the section by the boot code. + XCORE_SHF_DP_SECTION = 0x1000U, + + // Bits indicating processor-specific flags. + SHF_MASKPROC = 0xf0000000 +}; + +// Section Group Flags +enum { + GRP_COMDAT = 0x1, + GRP_MASKOS = 0x0ff00000, + GRP_MASKPROC = 0xf0000000 }; // Symbol table entries for ELF32. diff --git a/include/llvm/Support/Endian.h b/include/llvm/Support/Endian.h new file mode 100644 index 000000000000..f62eab0702b4 --- /dev/null +++ b/include/llvm/Support/Endian.h @@ -0,0 +1,213 @@ +//===- Endian.h - Utilities for IO with endian specific data ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares generic functions to read and write endian specific data. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ENDIAN_H +#define LLVM_SUPPORT_ENDIAN_H + +#include "llvm/Config/config.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/SwapByteOrder.h" +#include "llvm/Support/type_traits.h" + +namespace llvm { +namespace support { + +enum endianness {big, little}; +enum alignment {unaligned, aligned}; + +namespace detail { + +template +struct alignment_access_helper; + +template +struct alignment_access_helper +{ + value_type val; +}; + +// Provides unaligned loads and stores. +#pragma pack(push) +#pragma pack(1) +template +struct alignment_access_helper +{ + value_type val; +}; +#pragma pack(pop) + +} // end namespace detail + +namespace endian { + template + static value_type read_le(const void *memory) { + value_type t = + reinterpret_cast *>(memory)->val; + if (sys::isBigEndianHost()) + return sys::SwapByteOrder(t); + return t; + } + + template + static void write_le(void *memory, value_type value) { + if (sys::isBigEndianHost()) + value = sys::SwapByteOrder(value); + reinterpret_cast *> + (memory)->val = value; + } + + template + static value_type read_be(const void *memory) { + value_type t = + reinterpret_cast *>(memory)->val; + if (sys::isLittleEndianHost()) + return sys::SwapByteOrder(t); + return t; + } + + template + static void write_be(void *memory, value_type value) { + if (sys::isLittleEndianHost()) + value = sys::SwapByteOrder(value); + reinterpret_cast *> + (memory)->val = value; + } +} + +namespace detail { + +template +class packed_endian_specific_integral; + +template +class packed_endian_specific_integral { +public: + operator value_type() const { + return endian::read_le(Value); + } +private: + uint8_t Value[sizeof(value_type)]; +}; + +template +class packed_endian_specific_integral { +public: + operator value_type() const { + return endian::read_be(Value); + } +private: + uint8_t Value[sizeof(value_type)]; +}; + +template +class packed_endian_specific_integral { +public: + operator value_type() const { + return endian::read_le(&Value); + } +private: + value_type Value; +}; + +template +class packed_endian_specific_integral { +public: + operator value_type() const { + return endian::read_be(&Value); + } +private: + value_type Value; +}; + +} // end namespace detail + +typedef detail::packed_endian_specific_integral + ulittle8_t; +typedef detail::packed_endian_specific_integral + ulittle16_t; +typedef detail::packed_endian_specific_integral + ulittle32_t; +typedef detail::packed_endian_specific_integral + ulittle64_t; + +typedef detail::packed_endian_specific_integral + little8_t; +typedef detail::packed_endian_specific_integral + little16_t; +typedef detail::packed_endian_specific_integral + little32_t; +typedef detail::packed_endian_specific_integral + little64_t; + +typedef detail::packed_endian_specific_integral + aligned_ulittle8_t; +typedef detail::packed_endian_specific_integral + aligned_ulittle16_t; +typedef detail::packed_endian_specific_integral + aligned_ulittle32_t; +typedef detail::packed_endian_specific_integral + aligned_ulittle64_t; + +typedef detail::packed_endian_specific_integral + aligned_little8_t; +typedef detail::packed_endian_specific_integral + aligned_little16_t; +typedef detail::packed_endian_specific_integral + aligned_little32_t; +typedef detail::packed_endian_specific_integral + aligned_little64_t; + +typedef detail::packed_endian_specific_integral + ubig8_t; +typedef detail::packed_endian_specific_integral + ubig16_t; +typedef detail::packed_endian_specific_integral + ubig32_t; +typedef detail::packed_endian_specific_integral + ubig64_t; + +typedef detail::packed_endian_specific_integral + big8_t; +typedef detail::packed_endian_specific_integral + big16_t; +typedef detail::packed_endian_specific_integral + big32_t; +typedef detail::packed_endian_specific_integral + big64_t; + +typedef detail::packed_endian_specific_integral + aligned_ubig8_t; +typedef detail::packed_endian_specific_integral + aligned_ubig16_t; +typedef detail::packed_endian_specific_integral + aligned_ubig32_t; +typedef detail::packed_endian_specific_integral + aligned_ubig64_t; + +typedef detail::packed_endian_specific_integral + aligned_big8_t; +typedef detail::packed_endian_specific_integral + aligned_big16_t; +typedef detail::packed_endian_specific_integral + aligned_big32_t; +typedef detail::packed_endian_specific_integral + aligned_big64_t; + +} // end namespace llvm +} // end namespace support + +#endif diff --git a/include/llvm/Support/Errno.h b/include/llvm/Support/Errno.h new file mode 100644 index 000000000000..150bdb701626 --- /dev/null +++ b/include/llvm/Support/Errno.h @@ -0,0 +1,34 @@ +//===- llvm/Support/Errno.h - Portable+convenient errno handling -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares some portable and convenient functions to deal with errno. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_ERRNO_H +#define LLVM_SYSTEM_ERRNO_H + +#include + +namespace llvm { +namespace sys { + +/// Returns a string representation of the errno value, using whatever +/// thread-safe variant of strerror() is available. Be sure to call this +/// immediately after the function that set errno, or errno may have been +/// overwritten by an intervening call. +std::string StrError(); + +/// Like the no-argument version above, but uses \p errnum instead of errno. +std::string StrError(int errnum); + +} // namespace sys +} // namespace llvm + +#endif // LLVM_SYSTEM_ERRNO_H diff --git a/include/llvm/Support/ErrorHandling.h b/include/llvm/Support/ErrorHandling.h index 9854657c756f..5eca438d8b4a 100644 --- a/include/llvm/Support/ErrorHandling.h +++ b/include/llvm/Support/ErrorHandling.h @@ -16,6 +16,7 @@ #define LLVM_SUPPORT_ERRORHANDLING_H #include "llvm/Support/Compiler.h" +#include "llvm/ADT/StringRef.h" #include namespace llvm { @@ -72,15 +73,17 @@ namespace llvm { /// standard error, followed by a newline. /// After the error handler is called this function will call exit(1), it /// does not return. - NORETURN void report_fatal_error(const char *reason); - NORETURN void report_fatal_error(const std::string &reason); - NORETURN void report_fatal_error(const Twine &reason); + LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const char *reason); + LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const std::string &reason); + LLVM_ATTRIBUTE_NORETURN void report_fatal_error(StringRef reason); + LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const Twine &reason); /// This function calls abort(), and prints the optional message to stderr. /// Use the llvm_unreachable macro (that adds location info), instead of /// calling this function directly. - NORETURN void llvm_unreachable_internal(const char *msg=0, - const char *file=0, unsigned line=0); + LLVM_ATTRIBUTE_NORETURN void llvm_unreachable_internal(const char *msg=0, + const char *file=0, + unsigned line=0); } /// Prints the message and location info to stderr in !NDEBUG builds. diff --git a/include/llvm/Support/FEnv.h b/include/llvm/Support/FEnv.h new file mode 100644 index 000000000000..f6f43337bd29 --- /dev/null +++ b/include/llvm/Support/FEnv.h @@ -0,0 +1,56 @@ +//===- llvm/Support/FEnv.h - Host floating-point exceptions ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides an operating system independent interface to +// floating-point exception interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_FENV_H +#define LLVM_SYSTEM_FENV_H + +#include "llvm/Config/config.h" +#include +#ifdef HAVE_FENV_H +#include +#endif + +// FIXME: Clang's #include handling apparently doesn't work for libstdc++'s +// fenv.h; see PR6907 for details. +#if defined(__clang__) && defined(_GLIBCXX_FENV_H) +#undef HAVE_FENV_H +#endif + +namespace llvm { +namespace sys { + +/// llvm_fenv_clearexcept - Clear the floating-point exception state. +static inline void llvm_fenv_clearexcept() { +#ifdef HAVE_FENV_H + feclearexcept(FE_ALL_EXCEPT); +#endif + errno = 0; +} + +/// llvm_fenv_testexcept - Test if a floating-point exception was raised. +static inline bool llvm_fenv_testexcept() { + int errno_val = errno; + if (errno_val == ERANGE || errno_val == EDOM) + return true; +#ifdef HAVE_FENV_H + if (fetestexcept(FE_ALL_EXCEPT & ~FE_INEXACT)) + return true; +#endif + return false; +} + +} // End sys namespace +} // End llvm namespace + +#endif diff --git a/include/llvm/Support/FileSystem.h b/include/llvm/Support/FileSystem.h new file mode 100644 index 000000000000..4001bf0b84e3 --- /dev/null +++ b/include/llvm/Support/FileSystem.h @@ -0,0 +1,690 @@ +//===- llvm/Support/FileSystem.h - File System OS Concept -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the llvm::sys::fs namespace. It is designed after +// TR2/boost filesystem (v3), but modified to remove exception handling and the +// path class. +// +// All functions return an error_code and their actual work via the last out +// argument. The out argument is defined if and only if errc::success is +// returned. A function may return any error code in the generic or system +// category. However, they shall be equivalent to any error conditions listed +// in each functions respective documentation if the condition applies. [ note: +// this does not guarantee that error_code will be in the set of explicitly +// listed codes, but it does guarantee that if any of the explicitly listed +// errors occur, the correct error_code will be used ]. All functions may +// return errc::not_enough_memory if there is not enough memory to complete the +// operation. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_FILE_SYSTEM_H +#define LLVM_SUPPORT_FILE_SYSTEM_H + +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/PathV1.h" +#include "llvm/Support/system_error.h" +#include +#include +#include + +namespace llvm { +namespace sys { +namespace fs { + +/// file_type - An "enum class" enumeration for the file system's view of the +/// type. +struct file_type { + enum _ { + status_error, + file_not_found, + regular_file, + directory_file, + symlink_file, + block_file, + character_file, + fifo_file, + socket_file, + type_unknown + }; + + file_type(_ v) : v_(v) {} + explicit file_type(int v) : v_(_(v)) {} + operator int() const {return v_;} + +private: + int v_; +}; + +/// copy_option - An "enum class" enumeration of copy semantics for copy +/// operations. +struct copy_option { + enum _ { + fail_if_exists, + overwrite_if_exists + }; + + copy_option(_ v) : v_(v) {} + explicit copy_option(int v) : v_(_(v)) {} + operator int() const {return v_;} + +private: + int v_; +}; + +/// space_info - Self explanatory. +struct space_info { + uint64_t capacity; + uint64_t free; + uint64_t available; +}; + +/// file_status - Represents the result of a call to stat and friends. It has +/// a platform specific member to store the result. +class file_status +{ + // implementation defined status field. + file_type Type; +public: + explicit file_status(file_type v=file_type::status_error) + : Type(v) {} + + file_type type() const { return Type; } + void type(file_type v) { Type = v; } +}; + +/// @} +/// @name Physical Operators +/// @{ + +/// @brief Make \a path an absolute path. +/// +/// Makes \a path absolute using the current directory if it is not already. An +/// empty \a path will result in the current directory. +/// +/// /absolute/path => /absolute/path +/// relative/../path => /relative/../path +/// +/// @param path A path that is modified to be an absolute path. +/// @returns errc::success if \a path has been made absolute, otherwise a +/// platform specific error_code. +error_code make_absolute(SmallVectorImpl &path); + +/// @brief Copy the file at \a from to the path \a to. +/// +/// @param from The path to copy the file from. +/// @param to The path to copy the file to. +/// @param copt Behavior if \a to already exists. +/// @returns errc::success if the file has been successfully copied. +/// errc::file_exists if \a to already exists and \a copt == +/// copy_option::fail_if_exists. Otherwise a platform specific +/// error_code. +error_code copy_file(const Twine &from, const Twine &to, + copy_option copt = copy_option::fail_if_exists); + +/// @brief Create all the non-existent directories in path. +/// +/// @param path Directories to create. +/// @param existed Set to true if \a path already existed, false otherwise. +/// @returns errc::success if is_directory(path) and existed have been set, +/// otherwise a platform specific error_code. +error_code create_directories(const Twine &path, bool &existed); + +/// @brief Create the directory in path. +/// +/// @param path Directory to create. +/// @param existed Set to true if \a path already existed, false otherwise. +/// @returns errc::success if is_directory(path) and existed have been set, +/// otherwise a platform specific error_code. +error_code create_directory(const Twine &path, bool &existed); + +/// @brief Create a hard link from \a from to \a to. +/// +/// @param to The path to hard link to. +/// @param from The path to hard link from. This is created. +/// @returns errc::success if exists(to) && exists(from) && equivalent(to, from) +/// , otherwise a platform specific error_code. +error_code create_hard_link(const Twine &to, const Twine &from); + +/// @brief Create a symbolic link from \a from to \a to. +/// +/// @param to The path to symbolically link to. +/// @param from The path to symbolically link from. This is created. +/// @returns errc::success if exists(to) && exists(from) && is_symlink(from), +/// otherwise a platform specific error_code. +error_code create_symlink(const Twine &to, const Twine &from); + +/// @brief Get the current path. +/// +/// @param result Holds the current path on return. +/// @results errc::success if the current path has been stored in result, +/// otherwise a platform specific error_code. +error_code current_path(SmallVectorImpl &result); + +/// @brief Remove path. Equivalent to POSIX remove(). +/// +/// @param path Input path. +/// @param existed Set to true if \a path existed, false if it did not. +/// undefined otherwise. +/// @results errc::success if path has been removed and existed has been +/// successfully set, otherwise a platform specific error_code. +error_code remove(const Twine &path, bool &existed); + +/// @brief Recursively remove all files below \a path, then \a path. Files are +/// removed as if by POSIX remove(). +/// +/// @param path Input path. +/// @param num_removed Number of files removed. +/// @results errc::success if path has been removed and num_removed has been +/// successfully set, otherwise a platform specific error_code. +error_code remove_all(const Twine &path, uint32_t &num_removed); + +/// @brief Rename \a from to \a to. Files are renamed as if by POSIX rename(). +/// +/// @param from The path to rename from. +/// @param to The path to rename to. This is created. +error_code rename(const Twine &from, const Twine &to); + +/// @brief Resize path to size. File is resized as if by POSIX truncate(). +/// +/// @param path Input path. +/// @param size Size to resize to. +/// @returns errc::success if \a path has been resized to \a size, otherwise a +/// platform specific error_code. +error_code resize_file(const Twine &path, uint64_t size); + +/// @brief Make file readable. +/// +/// @param path Input path. +/// @param value If true, make readable, else, make unreadable. +/// @results errc::success if readability has been successfully set, otherwise a +/// platform specific error_code. +error_code set_read(const Twine &path, bool value); + +/// @brief Make file writeable. +/// +/// @param path Input path. +/// @param value If true, make writeable, else, make unwriteable. +/// @results errc::success if writeability has been successfully set, otherwise +/// a platform specific error_code. +error_code set_write(const Twine &path, bool value); + +/// @brief Make file executable. +/// +/// @param path Input path. +/// @param value If true, make executable, else, make unexecutable. +/// @results errc::success if executability has been successfully set, otherwise +/// a platform specific error_code. +error_code set_execute(const Twine &path, bool value); + +/// @} +/// @name Physical Observers +/// @{ + +/// @brief Does file exist? +/// +/// @param status A file_status previously returned from stat. +/// @results True if the file represented by status exists, false if it does +/// not. +bool exists(file_status status); + +/// @brief Does file exist? +/// +/// @param path Input path. +/// @param result Set to true if the file represented by status exists, false if +/// it does not. Undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code exists(const Twine &path, bool &result); + +/// @brief Do file_status's represent the same thing? +/// +/// @param A Input file_status. +/// @param B Input file_status. +/// +/// assert(status_known(A) || status_known(B)); +/// +/// @results True if A and B both represent the same file system entity, false +/// otherwise. +bool equivalent(file_status A, file_status B); + +/// @brief Do paths represent the same thing? +/// +/// @param A Input path A. +/// @param B Input path B. +/// @param result Set to true if stat(A) and stat(B) have the same device and +/// inode (or equivalent). +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code equivalent(const Twine &A, const Twine &B, bool &result); + +/// @brief Get file size. +/// +/// @param path Input path. +/// @param result Set to the size of the file in \a path. +/// @returns errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code file_size(const Twine &path, uint64_t &result); + +/// @brief Does status represent a directory? +/// +/// @param status A file_status previously returned from status. +/// @results status.type() == file_type::directory_file. +bool is_directory(file_status status); + +/// @brief Is path a directory? +/// +/// @param path Input path. +/// @param result Set to true if \a path is a directory, false if it is not. +/// Undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_directory(const Twine &path, bool &result); + +/// @brief Is path an empty file? +/// +/// @param path Input path. +/// @param result Set to true if \a path is a an empty file, false if it is not. +/// Undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_empty(const Twine &path, bool &result); + +/// @brief Does status represent a regular file? +/// +/// @param status A file_status previously returned from status. +/// @results status_known(status) && status.type() == file_type::regular_file. +bool is_regular_file(file_status status); + +/// @brief Is path a regular file? +/// +/// @param path Input path. +/// @param result Set to true if \a path is a regular file, false if it is not. +/// Undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_regular_file(const Twine &path, bool &result); + +/// @brief Does this status represent something that exists but is not a +/// directory, regular file, or symlink? +/// +/// @param status A file_status previously returned from status. +/// @results exists(s) && !is_regular_file(s) && !is_directory(s) && +/// !is_symlink(s) +bool is_other(file_status status); + +/// @brief Is path something that exists but is not a directory, +/// regular file, or symlink? +/// +/// @param path Input path. +/// @param result Set to true if \a path exists, but is not a directory, regular +/// file, or a symlink, false if it does not. Undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_other(const Twine &path, bool &result); + +/// @brief Does status represent a symlink? +/// +/// @param status A file_status previously returned from stat. +/// @param result status.type() == symlink_file. +bool is_symlink(file_status status); + +/// @brief Is path a symlink? +/// +/// @param path Input path. +/// @param result Set to true if \a path is a symlink, false if it is not. +/// Undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_symlink(const Twine &path, bool &result); + +/// @brief Get last write time without changing it. +/// +/// @param path Input path. +/// @param result Set to the last write time (UNIX time) of \a path if it +/// exists. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code last_write_time(const Twine &path, std::time_t &result); + +/// @brief Set last write time. +/// +/// @param path Input path. +/// @param value Time to set (UNIX time) \a path's last write time to. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code set_last_write_time(const Twine &path, std::time_t value); + +/// @brief Read a symlink's value. +/// +/// @param path Input path. +/// @param result Set to the value of the symbolic link \a path. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code read_symlink(const Twine &path, SmallVectorImpl &result); + +/// @brief Get disk space usage information. +/// +/// @param path Input path. +/// @param result Set to the capacity, free, and available space on the device +/// \a path is on. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code disk_space(const Twine &path, space_info &result); + +/// @brief Get file status as if by POSIX stat(). +/// +/// @param path Input path. +/// @param result Set to the file status. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code status(const Twine &path, file_status &result); + +/// @brief Is status available? +/// +/// @param path Input path. +/// @results True if status() != status_error. +bool status_known(file_status s); + +/// @brief Is status available? +/// +/// @param path Input path. +/// @param result Set to true if status() != status_error. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code status_known(const Twine &path, bool &result); + +/// @brief Get file status as if by POSIX lstat(). +/// +/// Does not resolve symlinks. +/// +/// @param path Input path. +/// @param result Set to the file status. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code symlink_status(const Twine &path, file_status &result); + +/// @brief Generate a unique path and open it as a file. +/// +/// Generates a unique path suitable for a temporary file and then opens it as a +/// file. The name is based on \a model with '%' replaced by a random char in +/// [0-9a-f]. If \a model is not an absolute path, a suitable temporary +/// directory will be prepended. +/// +/// This is an atomic operation. Either the file is created and opened, or the +/// file system is left untouched. +/// +/// clang-%%-%%-%%-%%-%%.s => /tmp/clang-a0-b1-c2-d3-e4.s +/// +/// @param model Name to base unique path off of. +/// @param result_fs Set to the opened file's file descriptor. +/// @param result_path Set to the opened file's absolute path. +/// @results errc::success if result_{fd,path} have been successfully set, +/// otherwise a platform specific error_code. +error_code unique_file(const Twine &model, int &result_fd, + SmallVectorImpl &result_path); + +/// @brief Canonicalize path. +/// +/// Sets result to the file system's idea of what path is. The result is always +/// absolute and has the same capitalization as the file system. +/// +/// @param path Input path. +/// @param result Set to the canonicalized version of \a path. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code canonicalize(const Twine &path, SmallVectorImpl &result); + +/// @brief Are \a path's first bytes \a magic? +/// +/// @param path Input path. +/// @param magic Byte sequence to compare \a path's first len(magic) bytes to. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code has_magic(const Twine &path, const Twine &magic, bool &result); + +/// @brief Get \a path's first \a len bytes. +/// +/// @param path Input path. +/// @param len Number of magic bytes to get. +/// @param result Set to the first \a len bytes in the file pointed to by +/// \a path. Or the entire file if file_size(path) < len, in which +/// case result.size() returns the size of the file. +/// @results errc::success if result has been successfully set, +/// errc::value_too_large if len is larger then the file pointed to by +/// \a path, otherwise a platform specific error_code. +error_code get_magic(const Twine &path, uint32_t len, + SmallVectorImpl &result); + +/// @brief Get and identify \a path's type based on its content. +/// +/// @param path Input path. +/// @param result Set to the type of file, or LLVMFileType::Unknown_FileType. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code identify_magic(const Twine &path, LLVMFileType &result); + +/// @brief Is file bitcode? +/// +/// @param path Input path. +/// @param result Set to true if \a path is a bitcode file, false if it is not, +/// undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_bitcode(const Twine &path, bool &result); + +/// @brief Is file a dynamic library? +/// +/// @param path Input path. +/// @param result Set to true if \a path is a dynamic library, false if it is +/// not, undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_dynamic_library(const Twine &path, bool &result); + +/// @brief Is an object file? +/// +/// @param path Input path. +/// @param result Set to true if \a path is an object file, false if it is not, +/// undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code is_object_file(const Twine &path, bool &result); + +/// @brief Can file be read? +/// +/// @param path Input path. +/// @param result Set to true if \a path is readable, false it it is not, +/// undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code can_read(const Twine &path, bool &result); + +/// @brief Can file be written? +/// +/// @param path Input path. +/// @param result Set to true if \a path is writeable, false it it is not, +/// undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code can_write(const Twine &path, bool &result); + +/// @brief Can file be executed? +/// +/// @param path Input path. +/// @param result Set to true if \a path is executable, false it it is not, +/// undefined otherwise. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code can_execute(const Twine &path, bool &result); + +/// @brief Get library paths the system linker uses. +/// +/// @param result Set to the list of system library paths. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code GetSystemLibraryPaths(SmallVectorImpl &result); + +/// @brief Get bitcode library paths the system linker uses +/// + LLVM_LIB_SEARCH_PATH + LLVM_LIBDIR. +/// +/// @param result Set to the list of bitcode library paths. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code GetBitcodeLibraryPaths(SmallVectorImpl &result); + +/// @brief Find a library. +/// +/// Find the path to a library using its short name. Use the system +/// dependent library paths to locate the library. +/// +/// c => /usr/lib/libc.so +/// +/// @param short_name Library name one would give to the system linker. +/// @param result Set to the absolute path \a short_name represents. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code FindLibrary(const Twine &short_name, SmallVectorImpl &result); + +/// @brief Get absolute path of main executable. +/// +/// @param argv0 The program name as it was spelled on the command line. +/// @param MainAddr Address of some symbol in the executable (not in a library). +/// @param result Set to the absolute path of the current executable. +/// @results errc::success if result has been successfully set, otherwise a +/// platform specific error_code. +error_code GetMainExecutable(const char *argv0, void *MainAddr, + SmallVectorImpl &result); + +/// @} +/// @name Iterators +/// @{ + +/// directory_entry - A single entry in a directory. Caches the status either +/// from the result of the iteration syscall, or the first time status or +/// symlink_status is called. +class directory_entry { + std::string Path; + mutable file_status Status; + mutable file_status SymlinkStatus; + +public: + explicit directory_entry(const Twine &path, file_status st = file_status(), + file_status symlink_st = file_status()) + : Path(path.str()) + , Status(st) + , SymlinkStatus(symlink_st) {} + + directory_entry() {} + + void assign(const Twine &path, file_status st = file_status(), + file_status symlink_st = file_status()) { + Path = path.str(); + Status = st; + SymlinkStatus = symlink_st; + } + + void replace_filename(const Twine &filename, file_status st = file_status(), + file_status symlink_st = file_status()); + + StringRef path() const { return Path; } + error_code status(file_status &result) const; + error_code symlink_status(file_status &result) const; + + bool operator==(const directory_entry& rhs) const { return Path == rhs.Path; } + bool operator!=(const directory_entry& rhs) const { return !(*this == rhs); } + bool operator< (const directory_entry& rhs) const; + bool operator<=(const directory_entry& rhs) const; + bool operator> (const directory_entry& rhs) const; + bool operator>=(const directory_entry& rhs) const; +}; + +/// directory_iterator - Iterates through the entries in path. There is no +/// operator++ because we need an error_code. If it's really needed we can make +/// it call report_fatal_error on error. +class directory_iterator { + intptr_t IterationHandle; + directory_entry CurrentEntry; + + // Platform implementations implement these functions to handle iteration. + friend error_code directory_iterator_construct(directory_iterator &it, + StringRef path); + friend error_code directory_iterator_increment(directory_iterator &it); + friend error_code directory_iterator_destruct(directory_iterator &it); + +public: + explicit directory_iterator(const Twine &path, error_code &ec) + : IterationHandle(0) { + SmallString<128> path_storage; + ec = directory_iterator_construct(*this, path.toStringRef(path_storage)); + } + + /// Construct end iterator. + directory_iterator() : IterationHandle(0) {} + + ~directory_iterator() { + directory_iterator_destruct(*this); + } + + // No operator++ because we need error_code. + directory_iterator &increment(error_code &ec) { + ec = directory_iterator_increment(*this); + return *this; + } + + const directory_entry &operator*() const { return CurrentEntry; } + const directory_entry *operator->() const { return &CurrentEntry; } + + bool operator!=(const directory_iterator &RHS) const { + return CurrentEntry != RHS.CurrentEntry; + } + // Other members as required by + // C++ Std, 24.1.1 Input iterators [input.iterators] +}; + +/// recursive_directory_iterator - Same as directory_iterator except for it +/// recurses down into child directories. +class recursive_directory_iterator { + uint16_t Level; + bool HasNoPushRequest; + // implementation directory iterator status + +public: + explicit recursive_directory_iterator(const Twine &path, error_code &ec); + // No operator++ because we need error_code. + directory_iterator &increment(error_code &ec); + + const directory_entry &operator*() const; + const directory_entry *operator->() const; + + // observers + /// Gets the current level. path is at level 0. + int level() const; + /// Returns true if no_push has been called for this directory_entry. + bool no_push_request() const; + + // modifiers + /// Goes up one level if Level > 0. + void pop(); + /// Does not go down into the current directory_entry. + void no_push(); + + // Other members as required by + // C++ Std, 24.1.1 Input iterators [input.iterators] +}; + +/// @} + +} // end namespace fs +} // end namespace sys +} // end namespace llvm + +#endif diff --git a/include/llvm/Support/FileUtilities.h b/include/llvm/Support/FileUtilities.h index d0dd4a759888..748ce7cea7bd 100644 --- a/include/llvm/Support/FileUtilities.h +++ b/include/llvm/Support/FileUtilities.h @@ -15,7 +15,7 @@ #ifndef LLVM_SUPPORT_FILEUTILITIES_H #define LLVM_SUPPORT_FILEUTILITIES_H -#include "llvm/System/Path.h" +#include "llvm/Support/Path.h" namespace llvm { diff --git a/include/llvm/Support/GraphWriter.h b/include/llvm/Support/GraphWriter.h index 287c5ba01eeb..7573ef0dc9e7 100644 --- a/include/llvm/Support/GraphWriter.h +++ b/include/llvm/Support/GraphWriter.h @@ -26,7 +26,7 @@ #include "llvm/Support/DOTGraphTraits.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/GraphTraits.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Path.h" #include #include @@ -89,14 +89,28 @@ class GraphWriter { public: GraphWriter(raw_ostream &o, const GraphType &g, bool SN) : O(o), G(g) { - DTraits = DOTTraits(SN); -} + DTraits = DOTTraits(SN); + } + + void writeGraph(const std::string &Title = "") { + // Output the header for the graph... + writeHeader(Title); + + // Emit all of the nodes in the graph... + writeNodes(); + + // Output any customizations on the graph + DOTGraphTraits::addCustomGraphFeatures(G, *this); - void writeHeader(const std::string &Name) { + // Output the end of the graph + writeFooter(); + } + + void writeHeader(const std::string &Title) { std::string GraphName = DTraits.getGraphName(G); - if (!Name.empty()) - O << "digraph \"" << DOT::EscapeString(Name) << "\" {\n"; + if (!Title.empty()) + O << "digraph \"" << DOT::EscapeString(Title) << "\" {\n"; else if (!GraphName.empty()) O << "digraph \"" << DOT::EscapeString(GraphName) << "\" {\n"; else @@ -105,8 +119,8 @@ public: if (DTraits.renderGraphFromBottomUp()) O << "\trankdir=\"BT\";\n"; - if (!Name.empty()) - O << "\tlabel=\"" << DOT::EscapeString(Name) << "\";\n"; + if (!Title.empty()) + O << "\tlabel=\"" << DOT::EscapeString(Title) << "\";\n"; else if (!GraphName.empty()) O << "\tlabel=\"" << DOT::EscapeString(GraphName) << "\";\n"; O << DTraits.getGraphProperties(G); @@ -282,22 +296,13 @@ public: template raw_ostream &WriteGraph(raw_ostream &O, const GraphType &G, bool ShortNames = false, - const std::string &Name = "", const std::string &Title = "") { // Start the graph emission process... GraphWriter W(O, G, ShortNames); - // Output the header for the graph... - W.writeHeader(Title); - - // Emit all of the nodes in the graph... - W.writeNodes(); - - // Output any customizations on the graph - DOTGraphTraits::addCustomGraphFeatures(G, W); + // Emit the graph. + W.writeGraph(Title); - // Output the end of the graph - W.writeFooter(); return O; } @@ -322,7 +327,7 @@ sys::Path WriteGraph(const GraphType &G, const std::string &Name, raw_fd_ostream O(Filename.c_str(), ErrorInfo); if (ErrorInfo.empty()) { - llvm::WriteGraph(O, G, ShortNames, Name, Title); + llvm::WriteGraph(O, G, ShortNames, Title); errs() << " done. \n"; } else { errs() << "error opening file '" << Filename.str() << "' for writing!\n"; diff --git a/include/llvm/Support/Host.h b/include/llvm/Support/Host.h new file mode 100644 index 000000000000..f77d4c1182bb --- /dev/null +++ b/include/llvm/Support/Host.h @@ -0,0 +1,66 @@ +//===- llvm/Support/Host.h - Host machine characteristics --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Methods for querying the nature of the host machine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_HOST_H +#define LLVM_SYSTEM_HOST_H + +#include "llvm/ADT/StringMap.h" +#include + +namespace llvm { +namespace sys { + + inline bool isLittleEndianHost() { + union { + int i; + char c; + }; + i = 1; + return c; + } + + inline bool isBigEndianHost() { + return !isLittleEndianHost(); + } + + /// getHostTriple() - Return the target triple of the running + /// system. + /// + /// The target triple is a string in the format of: + /// CPU_TYPE-VENDOR-OPERATING_SYSTEM + /// or + /// CPU_TYPE-VENDOR-KERNEL-OPERATING_SYSTEM + std::string getHostTriple(); + + /// getHostCPUName - Get the LLVM name for the host CPU. The particular format + /// of the name is target dependent, and suitable for passing as -mcpu to the + /// target which matches the host. + /// + /// \return - The host CPU name, or empty if the CPU could not be determined. + std::string getHostCPUName(); + + /// getHostCPUFeatures - Get the LLVM names for the host CPU features. + /// The particular format of the names are target dependent, and suitable for + /// passing as -mattr to the target which matches the host. + /// + /// \param Features - A string mapping feature names to either + /// true (if enabled) or false (if disabled). This routine makes no guarantees + /// about exactly which features may appear in this map, except that they are + /// all valid LLVM feature names. + /// + /// \return - True on success. + bool getHostCPUFeatures(StringMap &Features); +} +} + +#endif diff --git a/include/llvm/Support/IRBuilder.h b/include/llvm/Support/IRBuilder.h index c827ccedd6f1..2394a59c09cb 100644 --- a/include/llvm/Support/IRBuilder.h +++ b/include/llvm/Support/IRBuilder.h @@ -46,32 +46,39 @@ protected: BasicBlock::iterator InsertPt; LLVMContext &Context; public: - + IRBuilderBase(LLVMContext &context) : Context(context) { ClearInsertionPoint(); } - + //===--------------------------------------------------------------------===// // Builder configuration methods //===--------------------------------------------------------------------===// - + /// ClearInsertionPoint - Clear the insertion point: created instructions will /// not be inserted into a block. void ClearInsertionPoint() { BB = 0; } - + BasicBlock *GetInsertBlock() const { return BB; } BasicBlock::iterator GetInsertPoint() const { return InsertPt; } LLVMContext &getContext() const { return Context; } - + /// SetInsertPoint - This specifies that created instructions should be /// appended to the end of the specified block. void SetInsertPoint(BasicBlock *TheBB) { BB = TheBB; InsertPt = BB->end(); } + + /// SetInsertPoint - This specifies that created instructions should be + /// inserted before the specified instruction. + void SetInsertPoint(Instruction *I) { + BB = I->getParent(); + InsertPt = I; + } /// SetInsertPoint - This specifies that created instructions should be /// inserted at the specified point. @@ -79,17 +86,17 @@ public: BB = TheBB; InsertPt = IP; } - + /// SetCurrentDebugLocation - Set location information used by debugging /// information. void SetCurrentDebugLocation(const DebugLoc &L) { CurDbgLocation = L; } - + /// getCurrentDebugLocation - Get location information used by debugging /// information. const DebugLoc &getCurrentDebugLocation() const { return CurDbgLocation; } - + /// SetInstDebugLocation - If this builder has a current debug location, set /// it on the specified instruction. void SetInstDebugLocation(Instruction *I) const { @@ -142,7 +149,7 @@ public: //===--------------------------------------------------------------------===// // Miscellaneous creation methods. //===--------------------------------------------------------------------===// - + /// CreateGlobalString - Make a new global variable with an initializer that /// has array of i8 type filled in with the nul terminated string value /// specified. If Name is specified, it is the name of the global variable @@ -178,65 +185,100 @@ public: ConstantInt *getInt32(uint32_t C) { return ConstantInt::get(getInt32Ty(), C); } - + /// getInt64 - Get a constant 64-bit value. ConstantInt *getInt64(uint64_t C) { return ConstantInt::get(getInt64Ty(), C); } - + //===--------------------------------------------------------------------===// // Type creation methods //===--------------------------------------------------------------------===// - + /// getInt1Ty - Fetch the type representing a single bit const IntegerType *getInt1Ty() { return Type::getInt1Ty(Context); } - + /// getInt8Ty - Fetch the type representing an 8-bit integer. const IntegerType *getInt8Ty() { return Type::getInt8Ty(Context); } - + /// getInt16Ty - Fetch the type representing a 16-bit integer. const IntegerType *getInt16Ty() { return Type::getInt16Ty(Context); } - + /// getInt32Ty - Fetch the type resepresenting a 32-bit integer. const IntegerType *getInt32Ty() { return Type::getInt32Ty(Context); } - + /// getInt64Ty - Fetch the type representing a 64-bit integer. const IntegerType *getInt64Ty() { return Type::getInt64Ty(Context); } - + /// getFloatTy - Fetch the type representing a 32-bit floating point value. const Type *getFloatTy() { return Type::getFloatTy(Context); } - + /// getDoubleTy - Fetch the type representing a 64-bit floating point value. const Type *getDoubleTy() { return Type::getDoubleTy(Context); } - + /// getVoidTy - Fetch the type representing void. const Type *getVoidTy() { return Type::getVoidTy(Context); } - - const PointerType *getInt8PtrTy() { - return Type::getInt8PtrTy(Context); + + const PointerType *getInt8PtrTy(unsigned AddrSpace = 0) { + return Type::getInt8PtrTy(Context, AddrSpace); } - + /// getCurrentFunctionReturnType - Get the return type of the current function /// that we're emitting into. const Type *getCurrentFunctionReturnType() const; -}; + /// CreateMemSet - Create and insert a memset to the specified pointer and the + /// specified value. If the pointer isn't an i8*, it will be converted. If a + /// TBAA tag is specified, it will be added to the instruction. + CallInst *CreateMemSet(Value *Ptr, Value *Val, uint64_t Size, unsigned Align, + bool isVolatile = false, MDNode *TBAATag = 0) { + return CreateMemSet(Ptr, Val, getInt64(Size), Align, isVolatile, TBAATag); + } + + CallInst *CreateMemSet(Value *Ptr, Value *Val, Value *Size, unsigned Align, + bool isVolatile = false, MDNode *TBAATag = 0); + + /// CreateMemCpy - Create and insert a memcpy between the specified pointers. + /// If the pointers aren't i8*, they will be converted. If a TBAA tag is + /// specified, it will be added to the instruction. + CallInst *CreateMemCpy(Value *Dst, Value *Src, uint64_t Size, unsigned Align, + bool isVolatile = false, MDNode *TBAATag = 0) { + return CreateMemCpy(Dst, Src, getInt64(Size), Align, isVolatile, TBAATag); + } + + CallInst *CreateMemCpy(Value *Dst, Value *Src, Value *Size, unsigned Align, + bool isVolatile = false, MDNode *TBAATag = 0); + + /// CreateMemMove - Create and insert a memmove between the specified + /// pointers. If the pointers aren't i8*, they will be converted. If a TBAA + /// tag is specified, it will be added to the instruction. + CallInst *CreateMemMove(Value *Dst, Value *Src, uint64_t Size, unsigned Align, + bool isVolatile = false, MDNode *TBAATag = 0) { + return CreateMemMove(Dst, Src, getInt64(Size), Align, isVolatile, TBAATag); + } + + CallInst *CreateMemMove(Value *Dst, Value *Src, Value *Size, unsigned Align, + bool isVolatile = false, MDNode *TBAATag = 0); +private: + Value *getCastedInt8PtrValue(Value *Ptr); +}; + /// IRBuilder - This provides a uniform API for creating instructions and /// inserting them into a basic block: either at the end of a BasicBlock, or /// at a specific iterator location in a block. @@ -258,25 +300,30 @@ public: IRBuilder(LLVMContext &C, const T &F, const Inserter &I = Inserter()) : IRBuilderBase(C), Inserter(I), Folder(F) { } - + explicit IRBuilder(LLVMContext &C) : IRBuilderBase(C), Folder(C) { } - + explicit IRBuilder(BasicBlock *TheBB, const T &F) : IRBuilderBase(TheBB->getContext()), Folder(F) { SetInsertPoint(TheBB); } - + explicit IRBuilder(BasicBlock *TheBB) : IRBuilderBase(TheBB->getContext()), Folder(Context) { SetInsertPoint(TheBB); } + + explicit IRBuilder(Instruction *IP) + : IRBuilderBase(IP->getContext()), Folder(Context) { + SetInsertPoint(IP); + } IRBuilder(BasicBlock *TheBB, BasicBlock::iterator IP, const T& F) : IRBuilderBase(TheBB->getContext()), Folder(F) { SetInsertPoint(TheBB, IP); } - + IRBuilder(BasicBlock *TheBB, BasicBlock::iterator IP) : IRBuilderBase(TheBB->getContext()), Folder(Context) { SetInsertPoint(TheBB, IP); @@ -288,7 +335,7 @@ public: /// isNamePreserving - Return true if this builder is configured to actually /// add the requested names to IR created through it. bool isNamePreserving() const { return preserveNames; } - + /// Insert - Insert and return the specified instruction. template InstTy *Insert(InstTy *I, const Twine &Name = "") const { @@ -298,6 +345,11 @@ public: return I; } + /// Insert - No-op overload to handle constants. + Constant *Insert(Constant *C, const Twine& = "") const { + return C; + } + //===--------------------------------------------------------------------===// // Instruction creation methods: Terminators //===--------------------------------------------------------------------===// @@ -313,7 +365,7 @@ public: ReturnInst *CreateRet(Value *V) { return Insert(ReturnInst::Create(Context, V)); } - + /// CreateAggregateRet - Create a sequence of N insertvalue instructions, /// with one Value from the retVals array each, that build a aggregate /// return value one value at a time, and a ret instruction to return @@ -375,10 +427,12 @@ public: Args+3), Name); } /// CreateInvoke - Create an invoke instruction. - template + template InvokeInst *CreateInvoke(Value *Callee, BasicBlock *NormalDest, - BasicBlock *UnwindDest, InputIterator ArgBegin, - InputIterator ArgEnd, const Twine &Name = "") { + BasicBlock *UnwindDest, + RandomAccessIterator ArgBegin, + RandomAccessIterator ArgEnd, + const Twine &Name = "") { return Insert(InvokeInst::Create(Callee, NormalDest, UnwindDest, ArgBegin, ArgEnd), Name); } @@ -394,177 +448,179 @@ public: //===--------------------------------------------------------------------===// // Instruction creation methods: Binary Operators //===--------------------------------------------------------------------===// - - Value *CreateAdd(Value *LHS, Value *RHS, const Twine &Name = "") { +private: + BinaryOperator *CreateInsertNUWNSWBinOp(BinaryOperator::BinaryOps Opc, + Value *LHS, Value *RHS, + const Twine &Name, + bool HasNUW, bool HasNSW) { + BinaryOperator *BO = Insert(BinaryOperator::Create(Opc, LHS, RHS), Name); + if (HasNUW) BO->setHasNoUnsignedWrap(); + if (HasNSW) BO->setHasNoSignedWrap(); + return BO; + } +public: + Value *CreateAdd(Value *LHS, Value *RHS, const Twine &Name = "", + bool HasNUW = false, bool HasNSW = false) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateAdd(LC, RC); - return Insert(BinaryOperator::CreateAdd(LHS, RHS), Name); + return Insert(Folder.CreateAdd(LC, RC, HasNUW, HasNSW), Name); + return CreateInsertNUWNSWBinOp(Instruction::Add, LHS, RHS, Name, + HasNUW, HasNSW); } Value *CreateNSWAdd(Value *LHS, Value *RHS, const Twine &Name = "") { - if (Constant *LC = dyn_cast(LHS)) - if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateNSWAdd(LC, RC); - return Insert(BinaryOperator::CreateNSWAdd(LHS, RHS), Name); + return CreateAdd(LHS, RHS, Name, false, true); } Value *CreateNUWAdd(Value *LHS, Value *RHS, const Twine &Name = "") { - if (Constant *LC = dyn_cast(LHS)) - if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateNUWAdd(LC, RC); - return Insert(BinaryOperator::CreateNUWAdd(LHS, RHS), Name); + return CreateAdd(LHS, RHS, Name, true, false); } Value *CreateFAdd(Value *LHS, Value *RHS, const Twine &Name = "") { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateFAdd(LC, RC); + return Insert(Folder.CreateFAdd(LC, RC), Name); return Insert(BinaryOperator::CreateFAdd(LHS, RHS), Name); } - Value *CreateSub(Value *LHS, Value *RHS, const Twine &Name = "") { + Value *CreateSub(Value *LHS, Value *RHS, const Twine &Name = "", + bool HasNUW = false, bool HasNSW = false) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateSub(LC, RC); - return Insert(BinaryOperator::CreateSub(LHS, RHS), Name); + return Insert(Folder.CreateSub(LC, RC), Name); + return CreateInsertNUWNSWBinOp(Instruction::Sub, LHS, RHS, Name, + HasNUW, HasNSW); } Value *CreateNSWSub(Value *LHS, Value *RHS, const Twine &Name = "") { - if (Constant *LC = dyn_cast(LHS)) - if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateNSWSub(LC, RC); - return Insert(BinaryOperator::CreateNSWSub(LHS, RHS), Name); + return CreateSub(LHS, RHS, Name, false, true); } Value *CreateNUWSub(Value *LHS, Value *RHS, const Twine &Name = "") { - if (Constant *LC = dyn_cast(LHS)) - if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateNUWSub(LC, RC); - return Insert(BinaryOperator::CreateNUWSub(LHS, RHS), Name); + return CreateSub(LHS, RHS, Name, true, false); } Value *CreateFSub(Value *LHS, Value *RHS, const Twine &Name = "") { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateFSub(LC, RC); + return Insert(Folder.CreateFSub(LC, RC), Name); return Insert(BinaryOperator::CreateFSub(LHS, RHS), Name); } - Value *CreateMul(Value *LHS, Value *RHS, const Twine &Name = "") { + Value *CreateMul(Value *LHS, Value *RHS, const Twine &Name = "", + bool HasNUW = false, bool HasNSW = false) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateMul(LC, RC); - return Insert(BinaryOperator::CreateMul(LHS, RHS), Name); + return Insert(Folder.CreateMul(LC, RC), Name); + return CreateInsertNUWNSWBinOp(Instruction::Mul, LHS, RHS, Name, + HasNUW, HasNSW); } Value *CreateNSWMul(Value *LHS, Value *RHS, const Twine &Name = "") { - if (Constant *LC = dyn_cast(LHS)) - if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateNSWMul(LC, RC); - return Insert(BinaryOperator::CreateNSWMul(LHS, RHS), Name); + return CreateMul(LHS, RHS, Name, false, true); } Value *CreateNUWMul(Value *LHS, Value *RHS, const Twine &Name = "") { - if (Constant *LC = dyn_cast(LHS)) - if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateNUWMul(LC, RC); - return Insert(BinaryOperator::CreateNUWMul(LHS, RHS), Name); + return CreateMul(LHS, RHS, Name, true, false); } Value *CreateFMul(Value *LHS, Value *RHS, const Twine &Name = "") { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateFMul(LC, RC); + return Insert(Folder.CreateFMul(LC, RC), Name); return Insert(BinaryOperator::CreateFMul(LHS, RHS), Name); } - Value *CreateUDiv(Value *LHS, Value *RHS, const Twine &Name = "") { + Value *CreateUDiv(Value *LHS, Value *RHS, const Twine &Name = "", + bool isExact = false) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateUDiv(LC, RC); - return Insert(BinaryOperator::CreateUDiv(LHS, RHS), Name); + return Insert(Folder.CreateUDiv(LC, RC, isExact), Name); + if (!isExact) + return Insert(BinaryOperator::CreateUDiv(LHS, RHS), Name); + return Insert(BinaryOperator::CreateExactUDiv(LHS, RHS), Name); } - Value *CreateSDiv(Value *LHS, Value *RHS, const Twine &Name = "") { - if (Constant *LC = dyn_cast(LHS)) - if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateSDiv(LC, RC); - return Insert(BinaryOperator::CreateSDiv(LHS, RHS), Name); + Value *CreateExactUDiv(Value *LHS, Value *RHS, const Twine &Name = "") { + return CreateUDiv(LHS, RHS, Name, true); } - Value *CreateExactSDiv(Value *LHS, Value *RHS, const Twine &Name = "") { + Value *CreateSDiv(Value *LHS, Value *RHS, const Twine &Name = "", + bool isExact = false) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateExactSDiv(LC, RC); + return Insert(Folder.CreateSDiv(LC, RC, isExact), Name); + if (!isExact) + return Insert(BinaryOperator::CreateSDiv(LHS, RHS), Name); return Insert(BinaryOperator::CreateExactSDiv(LHS, RHS), Name); } + Value *CreateExactSDiv(Value *LHS, Value *RHS, const Twine &Name = "") { + return CreateSDiv(LHS, RHS, Name, true); + } Value *CreateFDiv(Value *LHS, Value *RHS, const Twine &Name = "") { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateFDiv(LC, RC); + return Insert(Folder.CreateFDiv(LC, RC), Name); return Insert(BinaryOperator::CreateFDiv(LHS, RHS), Name); } Value *CreateURem(Value *LHS, Value *RHS, const Twine &Name = "") { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateURem(LC, RC); + return Insert(Folder.CreateURem(LC, RC), Name); return Insert(BinaryOperator::CreateURem(LHS, RHS), Name); } Value *CreateSRem(Value *LHS, Value *RHS, const Twine &Name = "") { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateSRem(LC, RC); + return Insert(Folder.CreateSRem(LC, RC), Name); return Insert(BinaryOperator::CreateSRem(LHS, RHS), Name); } Value *CreateFRem(Value *LHS, Value *RHS, const Twine &Name = "") { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateFRem(LC, RC); + return Insert(Folder.CreateFRem(LC, RC), Name); return Insert(BinaryOperator::CreateFRem(LHS, RHS), Name); } - Value *CreateShl(Value *LHS, Value *RHS, const Twine &Name = "") { + Value *CreateShl(Value *LHS, Value *RHS, const Twine &Name = "", + bool HasNUW = false, bool HasNSW = false) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateShl(LC, RC); - return Insert(BinaryOperator::CreateShl(LHS, RHS), Name); + return Insert(Folder.CreateShl(LC, RC, HasNUW, HasNSW), Name); + return CreateInsertNUWNSWBinOp(Instruction::Shl, LHS, RHS, Name, + HasNUW, HasNSW); } - Value *CreateShl(Value *LHS, const APInt &RHS, const Twine &Name = "") { - Constant *RHSC = ConstantInt::get(LHS->getType(), RHS); - if (Constant *LC = dyn_cast(LHS)) - return Folder.CreateShl(LC, RHSC); - return Insert(BinaryOperator::CreateShl(LHS, RHSC), Name); + Value *CreateShl(Value *LHS, const APInt &RHS, const Twine &Name = "", + bool HasNUW = false, bool HasNSW = false) { + return CreateShl(LHS, ConstantInt::get(LHS->getType(), RHS), Name, + HasNUW, HasNSW); } - Value *CreateShl(Value *LHS, uint64_t RHS, const Twine &Name = "") { - Constant *RHSC = ConstantInt::get(LHS->getType(), RHS); - if (Constant *LC = dyn_cast(LHS)) - return Folder.CreateShl(LC, RHSC); - return Insert(BinaryOperator::CreateShl(LHS, RHSC), Name); + Value *CreateShl(Value *LHS, uint64_t RHS, const Twine &Name = "", + bool HasNUW = false, bool HasNSW = false) { + return CreateShl(LHS, ConstantInt::get(LHS->getType(), RHS), Name, + HasNUW, HasNSW); } - Value *CreateLShr(Value *LHS, Value *RHS, const Twine &Name = "") { + Value *CreateLShr(Value *LHS, Value *RHS, const Twine &Name = "", + bool isExact = false) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateLShr(LC, RC); - return Insert(BinaryOperator::CreateLShr(LHS, RHS), Name); + return Insert(Folder.CreateLShr(LC, RC, isExact), Name); + if (!isExact) + return Insert(BinaryOperator::CreateLShr(LHS, RHS), Name); + return Insert(BinaryOperator::CreateExactLShr(LHS, RHS), Name); } - Value *CreateLShr(Value *LHS, const APInt &RHS, const Twine &Name = "") { - Constant *RHSC = ConstantInt::get(LHS->getType(), RHS); - if (Constant *LC = dyn_cast(LHS)) - return Folder.CreateLShr(LC, RHSC); - return Insert(BinaryOperator::CreateLShr(LHS, RHSC), Name); + Value *CreateLShr(Value *LHS, const APInt &RHS, const Twine &Name = "", + bool isExact = false) { + return CreateLShr(LHS, ConstantInt::get(LHS->getType(), RHS), Name,isExact); } - Value *CreateLShr(Value *LHS, uint64_t RHS, const Twine &Name = "") { - Constant *RHSC = ConstantInt::get(LHS->getType(), RHS); - if (Constant *LC = dyn_cast(LHS)) - return Folder.CreateLShr(LC, RHSC); - return Insert(BinaryOperator::CreateLShr(LHS, RHSC), Name); + Value *CreateLShr(Value *LHS, uint64_t RHS, const Twine &Name = "", + bool isExact = false) { + return CreateLShr(LHS, ConstantInt::get(LHS->getType(), RHS), Name,isExact); } - Value *CreateAShr(Value *LHS, Value *RHS, const Twine &Name = "") { + Value *CreateAShr(Value *LHS, Value *RHS, const Twine &Name = "", + bool isExact = false) { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateAShr(LC, RC); - return Insert(BinaryOperator::CreateAShr(LHS, RHS), Name); + return Insert(Folder.CreateAShr(LC, RC, isExact), Name); + if (!isExact) + return Insert(BinaryOperator::CreateAShr(LHS, RHS), Name); + return Insert(BinaryOperator::CreateExactAShr(LHS, RHS), Name); } - Value *CreateAShr(Value *LHS, const APInt &RHS, const Twine &Name = "") { - Constant *RHSC = ConstantInt::get(LHS->getType(), RHS); - if (Constant *LC = dyn_cast(LHS)) - return Folder.CreateAShr(LC, RHSC); - return Insert(BinaryOperator::CreateAShr(LHS, RHSC), Name); + Value *CreateAShr(Value *LHS, const APInt &RHS, const Twine &Name = "", + bool isExact = false) { + return CreateAShr(LHS, ConstantInt::get(LHS->getType(), RHS), Name,isExact); } - Value *CreateAShr(Value *LHS, uint64_t RHS, const Twine &Name = "") { - Constant *RHSC = ConstantInt::get(LHS->getType(), RHS); - if (Constant *LC = dyn_cast(LHS)) - return Folder.CreateAShr(LC, RHSC); - return Insert(BinaryOperator::CreateAShr(LHS, RHSC), Name); + Value *CreateAShr(Value *LHS, uint64_t RHS, const Twine &Name = "", + bool isExact = false) { + return CreateAShr(LHS, ConstantInt::get(LHS->getType(), RHS), Name,isExact); } Value *CreateAnd(Value *LHS, Value *RHS, const Twine &Name = "") { @@ -572,21 +628,15 @@ public: if (isa(RC) && cast(RC)->isAllOnesValue()) return LHS; // LHS & -1 -> LHS if (Constant *LC = dyn_cast(LHS)) - return Folder.CreateAnd(LC, RC); + return Insert(Folder.CreateAnd(LC, RC), Name); } return Insert(BinaryOperator::CreateAnd(LHS, RHS), Name); } Value *CreateAnd(Value *LHS, const APInt &RHS, const Twine &Name = "") { - Constant *RHSC = ConstantInt::get(LHS->getType(), RHS); - if (Constant *LC = dyn_cast(LHS)) - return Folder.CreateAnd(LC, RHSC); - return Insert(BinaryOperator::CreateAnd(LHS, RHSC), Name); + return CreateAnd(LHS, ConstantInt::get(LHS->getType(), RHS), Name); } Value *CreateAnd(Value *LHS, uint64_t RHS, const Twine &Name = "") { - Constant *RHSC = ConstantInt::get(LHS->getType(), RHS); - if (Constant *LC = dyn_cast(LHS)) - return Folder.CreateAnd(LC, RHSC); - return Insert(BinaryOperator::CreateAnd(LHS, RHSC), Name); + return CreateAnd(LHS, ConstantInt::get(LHS->getType(), RHS), Name); } Value *CreateOr(Value *LHS, Value *RHS, const Twine &Name = "") { @@ -594,73 +644,61 @@ public: if (RC->isNullValue()) return LHS; // LHS | 0 -> LHS if (Constant *LC = dyn_cast(LHS)) - return Folder.CreateOr(LC, RC); + return Insert(Folder.CreateOr(LC, RC), Name); } return Insert(BinaryOperator::CreateOr(LHS, RHS), Name); } Value *CreateOr(Value *LHS, const APInt &RHS, const Twine &Name = "") { - Constant *RHSC = ConstantInt::get(LHS->getType(), RHS); - if (Constant *LC = dyn_cast(LHS)) - return Folder.CreateOr(LC, RHSC); - return Insert(BinaryOperator::CreateOr(LHS, RHSC), Name); + return CreateOr(LHS, ConstantInt::get(LHS->getType(), RHS), Name); } Value *CreateOr(Value *LHS, uint64_t RHS, const Twine &Name = "") { - Constant *RHSC = ConstantInt::get(LHS->getType(), RHS); - if (Constant *LC = dyn_cast(LHS)) - return Folder.CreateOr(LC, RHSC); - return Insert(BinaryOperator::CreateOr(LHS, RHSC), Name); + return CreateOr(LHS, ConstantInt::get(LHS->getType(), RHS), Name); } Value *CreateXor(Value *LHS, Value *RHS, const Twine &Name = "") { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateXor(LC, RC); + return Insert(Folder.CreateXor(LC, RC), Name); return Insert(BinaryOperator::CreateXor(LHS, RHS), Name); } Value *CreateXor(Value *LHS, const APInt &RHS, const Twine &Name = "") { - Constant *RHSC = ConstantInt::get(LHS->getType(), RHS); - if (Constant *LC = dyn_cast(LHS)) - return Folder.CreateXor(LC, RHSC); - return Insert(BinaryOperator::CreateXor(LHS, RHSC), Name); + return CreateXor(LHS, ConstantInt::get(LHS->getType(), RHS), Name); } Value *CreateXor(Value *LHS, uint64_t RHS, const Twine &Name = "") { - Constant *RHSC = ConstantInt::get(LHS->getType(), RHS); - if (Constant *LC = dyn_cast(LHS)) - return Folder.CreateXor(LC, RHSC); - return Insert(BinaryOperator::CreateXor(LHS, RHSC), Name); + return CreateXor(LHS, ConstantInt::get(LHS->getType(), RHS), Name); } Value *CreateBinOp(Instruction::BinaryOps Opc, Value *LHS, Value *RHS, const Twine &Name = "") { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateBinOp(Opc, LC, RC); + return Insert(Folder.CreateBinOp(Opc, LC, RC), Name); return Insert(BinaryOperator::Create(Opc, LHS, RHS), Name); } - Value *CreateNeg(Value *V, const Twine &Name = "") { + Value *CreateNeg(Value *V, const Twine &Name = "", + bool HasNUW = false, bool HasNSW = false) { if (Constant *VC = dyn_cast(V)) - return Folder.CreateNeg(VC); - return Insert(BinaryOperator::CreateNeg(V), Name); + return Insert(Folder.CreateNeg(VC, HasNUW, HasNSW), Name); + BinaryOperator *BO = Insert(BinaryOperator::CreateNeg(V), Name); + if (HasNUW) BO->setHasNoUnsignedWrap(); + if (HasNSW) BO->setHasNoSignedWrap(); + return BO; } Value *CreateNSWNeg(Value *V, const Twine &Name = "") { - if (Constant *VC = dyn_cast(V)) - return Folder.CreateNSWNeg(VC); - return Insert(BinaryOperator::CreateNSWNeg(V), Name); + return CreateNeg(V, Name, false, true); } Value *CreateNUWNeg(Value *V, const Twine &Name = "") { - if (Constant *VC = dyn_cast(V)) - return Folder.CreateNUWNeg(VC); - return Insert(BinaryOperator::CreateNUWNeg(V), Name); + return CreateNeg(V, Name, true, false); } Value *CreateFNeg(Value *V, const Twine &Name = "") { if (Constant *VC = dyn_cast(V)) - return Folder.CreateFNeg(VC); + return Insert(Folder.CreateFNeg(VC), Name); return Insert(BinaryOperator::CreateFNeg(V), Name); } Value *CreateNot(Value *V, const Twine &Name = "") { if (Constant *VC = dyn_cast(V)) - return Folder.CreateNot(VC); + return Insert(Folder.CreateNot(VC), Name); return Insert(BinaryOperator::CreateNot(V), Name); } @@ -686,33 +724,39 @@ public: StoreInst *CreateStore(Value *Val, Value *Ptr, bool isVolatile = false) { return Insert(new StoreInst(Val, Ptr, isVolatile)); } - template - Value *CreateGEP(Value *Ptr, InputIterator IdxBegin, InputIterator IdxEnd, + template + Value *CreateGEP(Value *Ptr, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, const Twine &Name = "") { if (Constant *PC = dyn_cast(Ptr)) { // Every index must be constant. - InputIterator i; + RandomAccessIterator i; for (i = IdxBegin; i < IdxEnd; ++i) if (!isa(*i)) break; if (i == IdxEnd) - return Folder.CreateGetElementPtr(PC, &IdxBegin[0], IdxEnd - IdxBegin); + return Insert(Folder.CreateGetElementPtr(PC, &IdxBegin[0], + IdxEnd - IdxBegin), + Name); } return Insert(GetElementPtrInst::Create(Ptr, IdxBegin, IdxEnd), Name); } - template - Value *CreateInBoundsGEP(Value *Ptr, InputIterator IdxBegin, - InputIterator IdxEnd, const Twine &Name = "") { + template + Value *CreateInBoundsGEP(Value *Ptr, RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, + const Twine &Name = "") { if (Constant *PC = dyn_cast(Ptr)) { // Every index must be constant. - InputIterator i; + RandomAccessIterator i; for (i = IdxBegin; i < IdxEnd; ++i) if (!isa(*i)) break; if (i == IdxEnd) - return Folder.CreateInBoundsGetElementPtr(PC, - &IdxBegin[0], - IdxEnd - IdxBegin); + return Insert(Folder.CreateInBoundsGetElementPtr(PC, + &IdxBegin[0], + IdxEnd - IdxBegin), + Name); } return Insert(GetElementPtrInst::CreateInBounds(Ptr, IdxBegin, IdxEnd), Name); @@ -720,33 +764,33 @@ public: Value *CreateGEP(Value *Ptr, Value *Idx, const Twine &Name = "") { if (Constant *PC = dyn_cast(Ptr)) if (Constant *IC = dyn_cast(Idx)) - return Folder.CreateGetElementPtr(PC, &IC, 1); + return Insert(Folder.CreateGetElementPtr(PC, &IC, 1), Name); return Insert(GetElementPtrInst::Create(Ptr, Idx), Name); } Value *CreateInBoundsGEP(Value *Ptr, Value *Idx, const Twine &Name = "") { if (Constant *PC = dyn_cast(Ptr)) if (Constant *IC = dyn_cast(Idx)) - return Folder.CreateInBoundsGetElementPtr(PC, &IC, 1); + return Insert(Folder.CreateInBoundsGetElementPtr(PC, &IC, 1), Name); return Insert(GetElementPtrInst::CreateInBounds(Ptr, Idx), Name); } Value *CreateConstGEP1_32(Value *Ptr, unsigned Idx0, const Twine &Name = "") { Value *Idx = ConstantInt::get(Type::getInt32Ty(Context), Idx0); if (Constant *PC = dyn_cast(Ptr)) - return Folder.CreateGetElementPtr(PC, &Idx, 1); + return Insert(Folder.CreateGetElementPtr(PC, &Idx, 1), Name); - return Insert(GetElementPtrInst::Create(Ptr, &Idx, &Idx+1), Name); + return Insert(GetElementPtrInst::Create(Ptr, &Idx, &Idx+1), Name); } Value *CreateConstInBoundsGEP1_32(Value *Ptr, unsigned Idx0, const Twine &Name = "") { Value *Idx = ConstantInt::get(Type::getInt32Ty(Context), Idx0); if (Constant *PC = dyn_cast(Ptr)) - return Folder.CreateInBoundsGetElementPtr(PC, &Idx, 1); + return Insert(Folder.CreateInBoundsGetElementPtr(PC, &Idx, 1), Name); return Insert(GetElementPtrInst::CreateInBounds(Ptr, &Idx, &Idx+1), Name); } - Value *CreateConstGEP2_32(Value *Ptr, unsigned Idx0, unsigned Idx1, + Value *CreateConstGEP2_32(Value *Ptr, unsigned Idx0, unsigned Idx1, const Twine &Name = "") { Value *Idxs[] = { ConstantInt::get(Type::getInt32Ty(Context), Idx0), @@ -754,9 +798,9 @@ public: }; if (Constant *PC = dyn_cast(Ptr)) - return Folder.CreateGetElementPtr(PC, Idxs, 2); + return Insert(Folder.CreateGetElementPtr(PC, Idxs, 2), Name); - return Insert(GetElementPtrInst::Create(Ptr, Idxs, Idxs+2), Name); + return Insert(GetElementPtrInst::Create(Ptr, Idxs, Idxs+2), Name); } Value *CreateConstInBoundsGEP2_32(Value *Ptr, unsigned Idx0, unsigned Idx1, const Twine &Name = "") { @@ -766,7 +810,7 @@ public: }; if (Constant *PC = dyn_cast(Ptr)) - return Folder.CreateInBoundsGetElementPtr(PC, Idxs, 2); + return Insert(Folder.CreateInBoundsGetElementPtr(PC, Idxs, 2), Name); return Insert(GetElementPtrInst::CreateInBounds(Ptr, Idxs, Idxs+2), Name); } @@ -774,16 +818,16 @@ public: Value *Idx = ConstantInt::get(Type::getInt64Ty(Context), Idx0); if (Constant *PC = dyn_cast(Ptr)) - return Folder.CreateGetElementPtr(PC, &Idx, 1); + return Insert(Folder.CreateGetElementPtr(PC, &Idx, 1), Name); - return Insert(GetElementPtrInst::Create(Ptr, &Idx, &Idx+1), Name); + return Insert(GetElementPtrInst::Create(Ptr, &Idx, &Idx+1), Name); } Value *CreateConstInBoundsGEP1_64(Value *Ptr, uint64_t Idx0, const Twine &Name = "") { Value *Idx = ConstantInt::get(Type::getInt64Ty(Context), Idx0); if (Constant *PC = dyn_cast(Ptr)) - return Folder.CreateInBoundsGetElementPtr(PC, &Idx, 1); + return Insert(Folder.CreateInBoundsGetElementPtr(PC, &Idx, 1), Name); return Insert(GetElementPtrInst::CreateInBounds(Ptr, &Idx, &Idx+1), Name); } @@ -795,9 +839,9 @@ public: }; if (Constant *PC = dyn_cast(Ptr)) - return Folder.CreateGetElementPtr(PC, Idxs, 2); + return Insert(Folder.CreateGetElementPtr(PC, Idxs, 2), Name); - return Insert(GetElementPtrInst::Create(Ptr, Idxs, Idxs+2), Name); + return Insert(GetElementPtrInst::Create(Ptr, Idxs, Idxs+2), Name); } Value *CreateConstInBoundsGEP2_64(Value *Ptr, uint64_t Idx0, uint64_t Idx1, const Twine &Name = "") { @@ -807,14 +851,14 @@ public: }; if (Constant *PC = dyn_cast(Ptr)) - return Folder.CreateInBoundsGetElementPtr(PC, Idxs, 2); + return Insert(Folder.CreateInBoundsGetElementPtr(PC, Idxs, 2), Name); return Insert(GetElementPtrInst::CreateInBounds(Ptr, Idxs, Idxs+2), Name); } Value *CreateStructGEP(Value *Ptr, unsigned Idx, const Twine &Name = "") { return CreateConstInBoundsGEP2_32(Ptr, 0, Idx, Name); } - + /// CreateGlobalStringPtr - Same as CreateGlobalString, but return a pointer /// with "i8*" type instead of a pointer to array of i8. Value *CreateGlobalStringPtr(const char *Str = "", const Twine &Name = "") { @@ -823,7 +867,7 @@ public: Value *Args[] = { zero, zero }; return CreateInBoundsGEP(gv, Args, Args+2, Name); } - + //===--------------------------------------------------------------------===// // Instruction creation methods: Cast/Conversion Operators //===--------------------------------------------------------------------===// @@ -873,7 +917,7 @@ public: if (V->getType() == DestTy) return V; if (Constant *VC = dyn_cast(V)) - return Folder.CreateZExtOrBitCast(VC, DestTy); + return Insert(Folder.CreateZExtOrBitCast(VC, DestTy), Name); return Insert(CastInst::CreateZExtOrBitCast(V, DestTy), Name); } Value *CreateSExtOrBitCast(Value *V, const Type *DestTy, @@ -881,7 +925,7 @@ public: if (V->getType() == DestTy) return V; if (Constant *VC = dyn_cast(V)) - return Folder.CreateSExtOrBitCast(VC, DestTy); + return Insert(Folder.CreateSExtOrBitCast(VC, DestTy), Name); return Insert(CastInst::CreateSExtOrBitCast(V, DestTy), Name); } Value *CreateTruncOrBitCast(Value *V, const Type *DestTy, @@ -889,7 +933,7 @@ public: if (V->getType() == DestTy) return V; if (Constant *VC = dyn_cast(V)) - return Folder.CreateTruncOrBitCast(VC, DestTy); + return Insert(Folder.CreateTruncOrBitCast(VC, DestTy), Name); return Insert(CastInst::CreateTruncOrBitCast(V, DestTy), Name); } Value *CreateCast(Instruction::CastOps Op, Value *V, const Type *DestTy, @@ -897,7 +941,7 @@ public: if (V->getType() == DestTy) return V; if (Constant *VC = dyn_cast(V)) - return Folder.CreateCast(Op, VC, DestTy); + return Insert(Folder.CreateCast(Op, VC, DestTy), Name); return Insert(CastInst::Create(Op, V, DestTy), Name); } Value *CreatePointerCast(Value *V, const Type *DestTy, @@ -905,7 +949,7 @@ public: if (V->getType() == DestTy) return V; if (Constant *VC = dyn_cast(V)) - return Folder.CreatePointerCast(VC, DestTy); + return Insert(Folder.CreatePointerCast(VC, DestTy), Name); return Insert(CastInst::CreatePointerCast(V, DestTy), Name); } Value *CreateIntCast(Value *V, const Type *DestTy, bool isSigned, @@ -913,7 +957,7 @@ public: if (V->getType() == DestTy) return V; if (Constant *VC = dyn_cast(V)) - return Folder.CreateIntCast(VC, DestTy, isSigned); + return Insert(Folder.CreateIntCast(VC, DestTy, isSigned), Name); return Insert(CastInst::CreateIntegerCast(V, DestTy, isSigned), Name); } private: @@ -925,7 +969,7 @@ public: if (V->getType() == DestTy) return V; if (Constant *VC = dyn_cast(V)) - return Folder.CreateFPCast(VC, DestTy); + return Insert(Folder.CreateFPCast(VC, DestTy), Name); return Insert(CastInst::CreateFPCast(V, DestTy), Name); } @@ -1011,14 +1055,14 @@ public: const Twine &Name = "") { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateICmp(P, LC, RC); + return Insert(Folder.CreateICmp(P, LC, RC), Name); return Insert(new ICmpInst(P, LHS, RHS), Name); } Value *CreateFCmp(CmpInst::Predicate P, Value *LHS, Value *RHS, const Twine &Name = "") { if (Constant *LC = dyn_cast(LHS)) if (Constant *RC = dyn_cast(RHS)) - return Folder.CreateFCmp(P, LC, RC); + return Insert(Folder.CreateFCmp(P, LC, RC), Name); return Insert(new FCmpInst(P, LHS, RHS), Name); } @@ -1057,9 +1101,9 @@ public: return Insert(CallInst::Create(Callee, Args, Args+5), Name); } - template - CallInst *CreateCall(Value *Callee, InputIterator ArgBegin, - InputIterator ArgEnd, const Twine &Name = "") { + template + CallInst *CreateCall(Value *Callee, RandomAccessIterator ArgBegin, + RandomAccessIterator ArgEnd, const Twine &Name = "") { return Insert(CallInst::Create(Callee, ArgBegin, ArgEnd), Name); } @@ -1068,7 +1112,7 @@ public: if (Constant *CC = dyn_cast(C)) if (Constant *TC = dyn_cast(True)) if (Constant *FC = dyn_cast(False)) - return Folder.CreateSelect(CC, TC, FC); + return Insert(Folder.CreateSelect(CC, TC, FC), Name); return Insert(SelectInst::Create(C, True, False), Name); } @@ -1080,7 +1124,7 @@ public: const Twine &Name = "") { if (Constant *VC = dyn_cast(Vec)) if (Constant *IC = dyn_cast(Idx)) - return Folder.CreateExtractElement(VC, IC); + return Insert(Folder.CreateExtractElement(VC, IC), Name); return Insert(ExtractElementInst::Create(Vec, Idx), Name); } @@ -1089,7 +1133,7 @@ public: if (Constant *VC = dyn_cast(Vec)) if (Constant *NC = dyn_cast(NewElt)) if (Constant *IC = dyn_cast(Idx)) - return Folder.CreateInsertElement(VC, NC, IC); + return Insert(Folder.CreateInsertElement(VC, NC, IC), Name); return Insert(InsertElementInst::Create(Vec, NewElt, Idx), Name); } @@ -1098,24 +1142,25 @@ public: if (Constant *V1C = dyn_cast(V1)) if (Constant *V2C = dyn_cast(V2)) if (Constant *MC = dyn_cast(Mask)) - return Folder.CreateShuffleVector(V1C, V2C, MC); + return Insert(Folder.CreateShuffleVector(V1C, V2C, MC), Name); return Insert(new ShuffleVectorInst(V1, V2, Mask), Name); } Value *CreateExtractValue(Value *Agg, unsigned Idx, const Twine &Name = "") { if (Constant *AggC = dyn_cast(Agg)) - return Folder.CreateExtractValue(AggC, &Idx, 1); + return Insert(Folder.CreateExtractValue(AggC, &Idx, 1), Name); return Insert(ExtractValueInst::Create(Agg, Idx), Name); } - template + template Value *CreateExtractValue(Value *Agg, - InputIterator IdxBegin, - InputIterator IdxEnd, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, const Twine &Name = "") { if (Constant *AggC = dyn_cast(Agg)) - return Folder.CreateExtractValue(AggC, IdxBegin, IdxEnd - IdxBegin); + return Insert(Folder.CreateExtractValue(AggC, IdxBegin, IdxEnd-IdxBegin), + Name); return Insert(ExtractValueInst::Create(Agg, IdxBegin, IdxEnd), Name); } @@ -1123,18 +1168,20 @@ public: const Twine &Name = "") { if (Constant *AggC = dyn_cast(Agg)) if (Constant *ValC = dyn_cast(Val)) - return Folder.CreateInsertValue(AggC, ValC, &Idx, 1); + return Insert(Folder.CreateInsertValue(AggC, ValC, &Idx, 1), Name); return Insert(InsertValueInst::Create(Agg, Val, Idx), Name); } - template + template Value *CreateInsertValue(Value *Agg, Value *Val, - InputIterator IdxBegin, - InputIterator IdxEnd, + RandomAccessIterator IdxBegin, + RandomAccessIterator IdxEnd, const Twine &Name = "") { if (Constant *AggC = dyn_cast(Agg)) if (Constant *ValC = dyn_cast(Val)) - return Folder.CreateInsertValue(AggC, ValC, IdxBegin, IdxEnd-IdxBegin); + return Insert(Folder.CreateInsertValue(AggC, ValC, IdxBegin, + IdxEnd - IdxBegin), + Name); return Insert(InsertValueInst::Create(Agg, Val, IdxBegin, IdxEnd), Name); } diff --git a/include/llvm/Support/IRReader.h b/include/llvm/Support/IRReader.h index a44da528acfc..292c001e09f4 100644 --- a/include/llvm/Support/IRReader.h +++ b/include/llvm/Support/IRReader.h @@ -19,10 +19,12 @@ #ifndef LLVM_SUPPORT_IRREADER_H #define LLVM_SUPPORT_IRREADER_H +#include "llvm/ADT/OwningPtr.h" #include "llvm/Assembly/Parser.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Support/system_error.h" namespace llvm { @@ -56,15 +58,14 @@ namespace llvm { inline Module *getLazyIRFileModule(const std::string &Filename, SMDiagnostic &Err, LLVMContext &Context) { - std::string ErrMsg; - MemoryBuffer *F = MemoryBuffer::getFileOrSTDIN(Filename.c_str(), &ErrMsg); - if (F == 0) { - Err = SMDiagnostic(Filename, - "Could not open input file: " + ErrMsg); + OwningPtr File; + if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename.c_str(), File)) { + Err = SMDiagnostic(Filename, + "Could not open input file: " + ec.message()); return 0; } - return getLazyIRModule(F, Err, Context); + return getLazyIRModule(File.take(), Err, Context); } /// If the given MemoryBuffer holds a bitcode image, return a Module @@ -94,15 +95,14 @@ namespace llvm { inline Module *ParseIRFile(const std::string &Filename, SMDiagnostic &Err, LLVMContext &Context) { - std::string ErrMsg; - MemoryBuffer *F = MemoryBuffer::getFileOrSTDIN(Filename.c_str(), &ErrMsg); - if (F == 0) { - Err = SMDiagnostic(Filename, - "Could not open input file: " + ErrMsg); + OwningPtr File; + if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename.c_str(), File)) { + Err = SMDiagnostic(Filename, + "Could not open input file: " + ec.message()); return 0; } - return ParseIR(F, Err, Context); + return ParseIR(File.take(), Err, Context); } } diff --git a/include/llvm/Support/IncludeFile.h b/include/llvm/Support/IncludeFile.h new file mode 100644 index 000000000000..a9319725d477 --- /dev/null +++ b/include/llvm/Support/IncludeFile.h @@ -0,0 +1,79 @@ +//===- llvm/Support/IncludeFile.h - Ensure Linking Of Library ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the FORCE_DEFINING_FILE_TO_BE_LINKED and DEFINE_FILE_FOR +// macros. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_INCLUDEFILE_H +#define LLVM_SYSTEM_INCLUDEFILE_H + +/// This macro is the public interface that IncludeFile.h exports. This gives +/// us the option to implement the "link the definition" capability in any +/// manner that we choose. All header files that depend on a specific .cpp +/// file being linked at run time should use this macro instead of the +/// IncludeFile class directly. +/// +/// For example, foo.h would use:
      +/// FORCE_DEFINING_FILE_TO_BE_LINKED(foo)
      +/// +/// And, foo.cp would use:
      +/// DEFINING_FILE_FOR(foo)
      +#ifdef __GNUC__ +// If the `used' attribute is available, use it to create a variable +// with an initializer that will force the linking of the defining file. +#define FORCE_DEFINING_FILE_TO_BE_LINKED(name) \ + namespace llvm { \ + extern const char name ## LinkVar; \ + __attribute__((used)) static const char *const name ## LinkObj = \ + &name ## LinkVar; \ + } +#else +// Otherwise use a constructor call. +#define FORCE_DEFINING_FILE_TO_BE_LINKED(name) \ + namespace llvm { \ + extern const char name ## LinkVar; \ + static const IncludeFile name ## LinkObj ( &name ## LinkVar ); \ + } +#endif + +/// This macro is the counterpart to FORCE_DEFINING_FILE_TO_BE_LINKED. It should +/// be used in a .cpp file to define the name referenced in a header file that +/// will cause linkage of the .cpp file. It should only be used at extern level. +#define DEFINING_FILE_FOR(name) \ + namespace llvm { const char name ## LinkVar = 0; } + +namespace llvm { + +/// This class is used in the implementation of FORCE_DEFINING_FILE_TO_BE_LINKED +/// macro to make sure that the implementation of a header file is included +/// into a tool that uses the header. This is solely +/// to overcome problems linking .a files and not getting the implementation +/// of compilation units we need. This is commonly an issue with the various +/// Passes but also occurs elsewhere in LLVM. We like to use .a files because +/// they link faster and provide the smallest executables. However, sometimes +/// those executables are too small, if the program doesn't reference something +/// that might be needed, especially by a loaded share object. This little class +/// helps to resolve that problem. The basic strategy is to use this class in +/// a header file and pass the address of a variable to the constructor. If the +/// variable is defined in the header file's corresponding .cpp file then all +/// tools/libraries that \#include the header file will require the .cpp as +/// well. +/// For example:
      +/// extern int LinkMyCodeStub;
      +/// static IncludeFile LinkMyModule(&LinkMyCodeStub);
      +/// @brief Class to ensure linking of corresponding object file. +struct IncludeFile { + explicit IncludeFile(const void *); +}; + +} + +#endif diff --git a/include/llvm/Support/LICENSE.TXT b/include/llvm/Support/LICENSE.TXT new file mode 100644 index 000000000000..3479b3fd74d5 --- /dev/null +++ b/include/llvm/Support/LICENSE.TXT @@ -0,0 +1,6 @@ +LLVM System Interface Library +------------------------------------------------------------------------------- +The LLVM System Interface Library is licensed under the Illinois Open Source +License and has the following additional copyright: + +Copyright (C) 2004 eXtensible Systems, Inc. diff --git a/include/llvm/Support/MachO.h b/include/llvm/Support/MachO.h index 4c13177926d2..6841a0f1fc15 100644 --- a/include/llvm/Support/MachO.h +++ b/include/llvm/Support/MachO.h @@ -14,7 +14,7 @@ #ifndef LLVM_SUPPORT_MACHO_H #define LLVM_SUPPORT_MACHO_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" // NOTE: The enums in this file are intentially named to be different than those // in the headers in /usr/include/mach (on darwin systems) to avoid conflicts @@ -23,7 +23,7 @@ namespace llvm { namespace MachO { // Enums from enum { - // Constants for the "magic" field in llvm::MachO::mach_header and + // Constants for the "magic" field in llvm::MachO::mach_header and // llvm::MachO::mach_header_64 HeaderMagic32 = 0xFEEDFACEu, // MH_MAGIC HeaderMagic32Swapped = 0xCEFAEDFEu, // MH_CIGAM @@ -71,7 +71,7 @@ namespace llvm { HeaderFlagBitNoReexportedDylibs = 0x00100000u, // MH_NO_REEXPORTED_DYLIBS HeaderFlagBitPIE = 0x00200000u, // MH_PIE HeaderFlagBitDeadStrippableDylib = 0x00400000u, // MH_DEAD_STRIPPABLE_DYLIB - + // Constants for the "cmd" field in llvm::MachO::load_command LoadCommandDynamicLinkerRequired = 0x80000000u, // LC_REQ_DYLD LoadCommandSegment32 = 0x00000001u, // LC_SEGMENT @@ -110,7 +110,7 @@ namespace llvm { LoadCommandDynamicLinkerInfo = 0x00000022u, // LC_DYLD_INFO LoadCommandDynamicLinkerInfoOnly = 0x80000022u, // LC_DYLD_INFO_ONLY LoadCommandDylibLoadUpward = 0x80000023u, // LC_LOAD_UPWARD_DYLIB - + // Constant bits for the "flags" field in llvm::MachO::segment_command SegmentCommandFlagBitHighVM = 0x1u, // SG_HIGHVM SegmentCommandFlagBitFixedVMLibrary = 0x2u, // SG_FVMLIB @@ -243,20 +243,20 @@ namespace llvm { StabFunction = 0x24u, // N_FUN StabStaticSymbol = 0x26u, // N_STSYM StabLocalCommon = 0x28u, // N_LCSYM - StabBeginSymbol = 0x2Eu, // N_BNSYM + StabBeginSymbol = 0x2Eu, // N_BNSYM StabSourceFileOptions = 0x3Cu, // N_OPT StabRegisterSymbol = 0x40u, // N_RSYM StabSourceLine = 0x44u, // N_SLINE - StabEndSymbol = 0x4Eu, // N_ENSYM + StabEndSymbol = 0x4Eu, // N_ENSYM StabStructureType = 0x60u, // N_SSYM StabSourceFileName = 0x64u, // N_SO StabObjectFileName = 0x66u, // N_OSO StabLocalSymbol = 0x80u, // N_LSYM StabBeginIncludeFileName = 0x82u, // N_BINCL StabIncludeFileName = 0x84u, // N_SOL - StabCompilerParameters = 0x86u, // N_PARAMS - StabCompilerVersion = 0x88u, // N_VERSION - StabCompilerOptLevel = 0x8Au, // N_OLEVEL + StabCompilerParameters = 0x86u, // N_PARAMS + StabCompilerVersion = 0x88u, // N_VERSION + StabCompilerOptLevel = 0x8Au, // N_OLEVEL StabParameter = 0xA0u, // N_PSYM StabEndIncludeFile = 0xA2u, // N_EINCL StabAlternateEntry = 0xA4u, // N_ENTRY @@ -269,9 +269,9 @@ namespace llvm { StabLength = 0xFEu // N_LENG }; - + // Structs from - + struct mach_header { uint32_t magic; uint32_t cputype; @@ -636,12 +636,12 @@ namespace llvm { }; // Get/Set functions from - + static inline uint16_t GET_LIBRARY_ORDINAL(uint16_t n_desc) { return (((n_desc) >> 8u) & 0xffu); } - + static inline void SET_LIBRARY_ORDINAL(uint16_t &n_desc, uint8_t ordinal) { n_desc = (((n_desc) & 0x00ff) | (((ordinal) & 0xff) << 8)); @@ -651,7 +651,7 @@ namespace llvm { { return (n_desc >> 8u) & 0x0fu; } - + static inline void SET_COMM_ALIGN (uint16_t &n_desc, uint8_t align) { n_desc = ((n_desc & 0xf0ffu) | ((align & 0x0fu) << 8u)); @@ -662,7 +662,7 @@ namespace llvm { // Capability bits used in the definition of cpu_type. CPUArchMask = 0xff000000, // Mask for architecture bits CPUArchABI64 = 0x01000000, // 64 bit ABI - + // Constants for the cputype field. CPUTypeI386 = 7, CPUTypeX86_64 = CPUTypeI386 | CPUArchABI64, @@ -673,19 +673,21 @@ namespace llvm { // Constants for the cpusubtype field. - + // X86 CPUSubType_I386_ALL = 3, CPUSubType_X86_64_ALL = 3, - + // ARM CPUSubType_ARM_ALL = 0, CPUSubType_ARM_V4T = 5, + CPUSubType_ARM_V5 = 7, CPUSubType_ARM_V6 = 6, + CPUSubType_ARM_V7 = 9, // PowerPC CPUSubType_POWERPC_ALL = 0, - + CPUSubType_SPARC_ALL = 0 }; } // end namespace MachO diff --git a/include/llvm/Support/ManagedStatic.h b/include/llvm/Support/ManagedStatic.h index b8e223587fbd..53e73ad35f49 100644 --- a/include/llvm/Support/ManagedStatic.h +++ b/include/llvm/Support/ManagedStatic.h @@ -14,8 +14,8 @@ #ifndef LLVM_SUPPORT_MANAGED_STATIC_H #define LLVM_SUPPORT_MANAGED_STATIC_H -#include "llvm/System/Atomic.h" -#include "llvm/System/Threading.h" +#include "llvm/Support/Atomic.h" +#include "llvm/Support/Threading.h" namespace llvm { @@ -91,12 +91,6 @@ public: } }; -template -class ManagedCleanup : public ManagedStaticBase { -public: - void Register() { RegisterManagedStatic(0, CleanupFn); } -}; - /// llvm_shutdown - Deallocate and destroy all ManagedStatic variables. void llvm_shutdown(); diff --git a/include/llvm/Support/MathExtras.h b/include/llvm/Support/MathExtras.h index 982813f7186f..4627557f7f1f 100644 --- a/include/llvm/Support/MathExtras.h +++ b/include/llvm/Support/MathExtras.h @@ -14,7 +14,7 @@ #ifndef LLVM_SUPPORT_MATHEXTRAS_H #define LLVM_SUPPORT_MATHEXTRAS_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/SwapByteOrder.h" namespace llvm { @@ -70,6 +70,18 @@ inline bool isUInt<32>(uint64_t x) { return static_cast(x) == x; } +/// isUIntN - Checks if an unsigned integer fits into the given (dynamic) +/// bit width. +inline bool isUIntN(unsigned N, uint64_t x) { + return x == (x & (~0ULL >> (64 - N))); +} + +/// isIntN - Checks if an signed integer fits into the given (dynamic) +/// bit width. +inline bool isIntN(unsigned N, int64_t x) { + return N >= 64 || (-(INT64_C(1)<<(N-1)) <= x && x < (INT64_C(1)<<(N-1))); +} + /// isMask_32 - This function returns true if the argument is a sequence of ones /// starting at the least significant bit with the remainder zero (32 bit /// version). Ex. isMask_32(0x0000FFFFU) == true. @@ -112,47 +124,19 @@ inline bool isPowerOf2_64(uint64_t Value) { /// ByteSwap_16 - This function returns a byte-swapped representation of the /// 16-bit argument, Value. inline uint16_t ByteSwap_16(uint16_t Value) { -#if defined(_MSC_VER) && !defined(_DEBUG) - // The DLL version of the runtime lacks these functions (bug!?), but in a - // release build they're replaced with BSWAP instructions anyway. - return _byteswap_ushort(Value); -#else - uint16_t Hi = Value << 8; - uint16_t Lo = Value >> 8; - return Hi | Lo; -#endif + return sys::SwapByteOrder_16(Value); } /// ByteSwap_32 - This function returns a byte-swapped representation of the /// 32-bit argument, Value. inline uint32_t ByteSwap_32(uint32_t Value) { -#if defined(__llvm__) || \ - (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && !defined(__ICC) - return __builtin_bswap32(Value); -#elif defined(_MSC_VER) && !defined(_DEBUG) - return _byteswap_ulong(Value); -#else - uint32_t Byte0 = Value & 0x000000FF; - uint32_t Byte1 = Value & 0x0000FF00; - uint32_t Byte2 = Value & 0x00FF0000; - uint32_t Byte3 = Value & 0xFF000000; - return (Byte0 << 24) | (Byte1 << 8) | (Byte2 >> 8) | (Byte3 >> 24); -#endif + return sys::SwapByteOrder_32(Value); } /// ByteSwap_64 - This function returns a byte-swapped representation of the /// 64-bit argument, Value. inline uint64_t ByteSwap_64(uint64_t Value) { -#if defined(__llvm__) || \ - (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && !defined(__ICC) - return __builtin_bswap64(Value); -#elif defined(_MSC_VER) && !defined(_DEBUG) - return _byteswap_uint64(Value); -#else - uint64_t Hi = ByteSwap_32(uint32_t(Value)); - uint32_t Lo = ByteSwap_32(uint32_t(Value >> 32)); - return (Hi << 32) | Lo; -#endif + return sys::SwapByteOrder_64(Value); } /// CountLeadingZeros_32 - this function performs the platform optimal form of diff --git a/include/llvm/Support/Memory.h b/include/llvm/Support/Memory.h new file mode 100644 index 000000000000..9c3f85b958bc --- /dev/null +++ b/include/llvm/Support/Memory.h @@ -0,0 +1,96 @@ +//===- llvm/Support/Memory.h - Memory Support --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the llvm::sys::Memory class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_MEMORY_H +#define LLVM_SYSTEM_MEMORY_H + +#include "llvm/Support/DataTypes.h" +#include + +namespace llvm { +namespace sys { + + /// This class encapsulates the notion of a memory block which has an address + /// and a size. It is used by the Memory class (a friend) as the result of + /// various memory allocation operations. + /// @see Memory + /// @brief Memory block abstraction. + class MemoryBlock { + public: + MemoryBlock() : Address(0), Size(0) { } + MemoryBlock(void *addr, size_t size) : Address(addr), Size(size) { } + void *base() const { return Address; } + size_t size() const { return Size; } + private: + void *Address; ///< Address of first byte of memory area + size_t Size; ///< Size, in bytes of the memory area + friend class Memory; + }; + + /// This class provides various memory handling functions that manipulate + /// MemoryBlock instances. + /// @since 1.4 + /// @brief An abstraction for memory operations. + class Memory { + public: + /// This method allocates a block of Read/Write/Execute memory that is + /// suitable for executing dynamically generated code (e.g. JIT). An + /// attempt to allocate \p NumBytes bytes of virtual memory is made. + /// \p NearBlock may point to an existing allocation in which case + /// an attempt is made to allocate more memory near the existing block. + /// + /// On success, this returns a non-null memory block, otherwise it returns + /// a null memory block and fills in *ErrMsg. + /// + /// @brief Allocate Read/Write/Execute memory. + static MemoryBlock AllocateRWX(size_t NumBytes, + const MemoryBlock *NearBlock, + std::string *ErrMsg = 0); + + /// This method releases a block of Read/Write/Execute memory that was + /// allocated with the AllocateRWX method. It should not be used to + /// release any memory block allocated any other way. + /// + /// On success, this returns false, otherwise it returns true and fills + /// in *ErrMsg. + /// @brief Release Read/Write/Execute memory. + static bool ReleaseRWX(MemoryBlock &block, std::string *ErrMsg = 0); + + + /// InvalidateInstructionCache - Before the JIT can run a block of code + /// that has been emitted it must invalidate the instruction cache on some + /// platforms. + static void InvalidateInstructionCache(const void *Addr, size_t Len); + + /// setExecutable - Before the JIT can run a block of code, it has to be + /// given read and executable privilege. Return true if it is already r-x + /// or the system is able to change its previlege. + static bool setExecutable (MemoryBlock &M, std::string *ErrMsg = 0); + + /// setWritable - When adding to a block of code, the JIT may need + /// to mark a block of code as RW since the protections are on page + /// boundaries, and the JIT internal allocations are not page aligned. + static bool setWritable (MemoryBlock &M, std::string *ErrMsg = 0); + + /// setRangeExecutable - Mark the page containing a range of addresses + /// as executable. + static bool setRangeExecutable(const void *Addr, size_t Size); + + /// setRangeWritable - Mark the page containing a range of addresses + /// as writable. + static bool setRangeWritable(const void *Addr, size_t Size); + }; +} +} + +#endif diff --git a/include/llvm/Support/MemoryBuffer.h b/include/llvm/Support/MemoryBuffer.h index 8a41aa5f94fa..b6243b7b10dd 100644 --- a/include/llvm/Support/MemoryBuffer.h +++ b/include/llvm/Support/MemoryBuffer.h @@ -15,12 +15,13 @@ #define LLVM_SUPPORT_MEMORYBUFFER_H #include "llvm/ADT/StringRef.h" -#include "llvm/System/DataTypes.h" -#include -#include +#include "llvm/Support/DataTypes.h" namespace llvm { +class error_code; +template class OwningPtr; + /// MemoryBuffer - This interface provides simple read-only access to a block /// of memory, and provides simple methods for reading files and standard input /// into a memory buffer. In addition to basic access to the characters in the @@ -47,8 +48,8 @@ public: const char *getBufferEnd() const { return BufferEnd; } size_t getBufferSize() const { return BufferEnd-BufferStart; } - StringRef getBuffer() const { - return StringRef(BufferStart, getBufferSize()); + StringRef getBuffer() const { + return StringRef(BufferStart, getBufferSize()); } /// getBufferIdentifier - Return an identifier for this buffer, typically the @@ -61,23 +62,26 @@ public: /// MemoryBuffer if successful, otherwise returning null. If FileSize is /// specified, this means that the client knows that the file exists and that /// it has the specified size. - static MemoryBuffer *getFile(StringRef Filename, - std::string *ErrStr = 0, - int64_t FileSize = -1, - struct stat *FileInfo = 0); - static MemoryBuffer *getFile(const char *Filename, - std::string *ErrStr = 0, - int64_t FileSize = -1, - struct stat *FileInfo = 0); + static error_code getFile(StringRef Filename, OwningPtr &result, + int64_t FileSize = -1); + static error_code getFile(const char *Filename, + OwningPtr &result, + int64_t FileSize = -1); + + /// getOpenFile - Given an already-open file descriptor, read the file and + /// return a MemoryBuffer. + static error_code getOpenFile(int FD, const char *Filename, + OwningPtr &result, + int64_t FileSize = -1); /// getMemBuffer - Open the specified memory range as a MemoryBuffer. Note - /// that EndPtr[0] must be a null byte and be accessible! + /// that InputData must be null terminated. static MemoryBuffer *getMemBuffer(StringRef InputData, StringRef BufferName = ""); /// getMemBufferCopy - Open the specified memory range as a MemoryBuffer, - /// copying the contents and taking ownership of it. This has no requirements - /// on EndPtr[0]. + /// copying the contents and taking ownership of it. InputData does not + /// have to be null terminated. static MemoryBuffer *getMemBufferCopy(StringRef InputData, StringRef BufferName = ""); @@ -95,21 +99,19 @@ public: StringRef BufferName = ""); /// getSTDIN - Read all of stdin into a file buffer, and return it. - /// If an error occurs, this returns null and fills in *ErrStr with a reason. - static MemoryBuffer *getSTDIN(std::string *ErrStr = 0); + /// If an error occurs, this returns null and sets ec. + static error_code getSTDIN(OwningPtr &result); /// getFileOrSTDIN - Open the specified file as a MemoryBuffer, or open stdin - /// if the Filename is "-". If an error occurs, this returns null and fills - /// in *ErrStr with a reason. - static MemoryBuffer *getFileOrSTDIN(StringRef Filename, - std::string *ErrStr = 0, - int64_t FileSize = -1, - struct stat *FileInfo = 0); - static MemoryBuffer *getFileOrSTDIN(const char *Filename, - std::string *ErrStr = 0, - int64_t FileSize = -1, - struct stat *FileInfo = 0); + /// if the Filename is "-". If an error occurs, this returns null and sets + /// ec. + static error_code getFileOrSTDIN(StringRef Filename, + OwningPtr &result, + int64_t FileSize = -1); + static error_code getFileOrSTDIN(const char *Filename, + OwningPtr &result, + int64_t FileSize = -1); }; } // end namespace llvm diff --git a/include/llvm/Support/MemoryObject.h b/include/llvm/Support/MemoryObject.h index e193ca2f2bc5..dec0f134b306 100644 --- a/include/llvm/Support/MemoryObject.h +++ b/include/llvm/Support/MemoryObject.h @@ -10,7 +10,7 @@ #ifndef MEMORYOBJECT_H #define MEMORYOBJECT_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { diff --git a/include/llvm/Support/Mutex.h b/include/llvm/Support/Mutex.h new file mode 100644 index 000000000000..42ea63060f66 --- /dev/null +++ b/include/llvm/Support/Mutex.h @@ -0,0 +1,154 @@ +//===- llvm/Support/Mutex.h - Mutex Operating System Concept -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the llvm::sys::Mutex class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_MUTEX_H +#define LLVM_SYSTEM_MUTEX_H + +#include "llvm/Support/Threading.h" +#include + +namespace llvm +{ + namespace sys + { + /// @brief Platform agnostic Mutex class. + class MutexImpl + { + /// @name Constructors + /// @{ + public: + + /// Initializes the lock but doesn't acquire it. if \p recursive is set + /// to false, the lock will not be recursive which makes it cheaper but + /// also more likely to deadlock (same thread can't acquire more than + /// once). + /// @brief Default Constructor. + explicit MutexImpl(bool recursive = true); + + /// Releases and removes the lock + /// @brief Destructor + ~MutexImpl(); + + /// @} + /// @name Methods + /// @{ + public: + + /// Attempts to unconditionally acquire the lock. If the lock is held by + /// another thread, this method will wait until it can acquire the lock. + /// @returns false if any kind of error occurs, true otherwise. + /// @brief Unconditionally acquire the lock. + bool acquire(); + + /// Attempts to release the lock. If the lock is held by the current + /// thread, the lock is released allowing other threads to acquire the + /// lock. + /// @returns false if any kind of error occurs, true otherwise. + /// @brief Unconditionally release the lock. + bool release(); + + /// Attempts to acquire the lock without blocking. If the lock is not + /// available, this function returns false quickly (without blocking). If + /// the lock is available, it is acquired. + /// @returns false if any kind of error occurs or the lock is not + /// available, true otherwise. + /// @brief Try to acquire the lock. + bool tryacquire(); + + //@} + /// @name Platform Dependent Data + /// @{ + private: + void* data_; ///< We don't know what the data will be + + /// @} + /// @name Do Not Implement + /// @{ + private: + MutexImpl(const MutexImpl & original); + void operator=(const MutexImpl &); + /// @} + }; + + + /// SmartMutex - A mutex with a compile time constant parameter that + /// indicates whether this mutex should become a no-op when we're not + /// running in multithreaded mode. + template + class SmartMutex : public MutexImpl { + unsigned acquired; + bool recursive; + public: + explicit SmartMutex(bool rec = true) : + MutexImpl(rec), acquired(0), recursive(rec) { } + + bool acquire() { + if (!mt_only || llvm_is_multithreaded()) { + return MutexImpl::acquire(); + } else { + // Single-threaded debugging code. This would be racy in + // multithreaded mode, but provides not sanity checks in single + // threaded mode. + assert((recursive || acquired == 0) && "Lock already acquired!!"); + ++acquired; + return true; + } + } + + bool release() { + if (!mt_only || llvm_is_multithreaded()) { + return MutexImpl::release(); + } else { + // Single-threaded debugging code. This would be racy in + // multithreaded mode, but provides not sanity checks in single + // threaded mode. + assert(((recursive && acquired) || (acquired == 1)) && + "Lock not acquired before release!"); + --acquired; + return true; + } + } + + bool tryacquire() { + if (!mt_only || llvm_is_multithreaded()) + return MutexImpl::tryacquire(); + else return true; + } + + private: + SmartMutex(const SmartMutex & original); + void operator=(const SmartMutex &); + }; + + /// Mutex - A standard, always enforced mutex. + typedef SmartMutex Mutex; + + template + class SmartScopedLock { + SmartMutex& mtx; + + public: + SmartScopedLock(SmartMutex& m) : mtx(m) { + mtx.acquire(); + } + + ~SmartScopedLock() { + mtx.release(); + } + }; + + typedef SmartScopedLock ScopedLock; + } +} + +#endif diff --git a/include/llvm/Support/MutexGuard.h b/include/llvm/Support/MutexGuard.h index 9958b97a3e64..cd13bfe6eeb0 100644 --- a/include/llvm/Support/MutexGuard.h +++ b/include/llvm/Support/MutexGuard.h @@ -15,7 +15,7 @@ #ifndef LLVM_SUPPORT_MUTEXGUARD_H #define LLVM_SUPPORT_MUTEXGUARD_H -#include "llvm/System/Mutex.h" +#include "llvm/Support/Mutex.h" namespace llvm { /// Instances of this class acquire a given Mutex Lock when constructed and diff --git a/include/llvm/Support/NoFolder.h b/include/llvm/Support/NoFolder.h index 01256e18a5ce..d7b5b42924c3 100644 --- a/include/llvm/Support/NoFolder.h +++ b/include/llvm/Support/NoFolder.h @@ -15,8 +15,7 @@ // llvm/Analysis/ConstantFolding.h. // // Note: since it is not actually possible to create unfolded constants, this -// class returns values rather than constants. The values do not have names, -// even if names were provided to IRBuilder, which may be confusing. +// class returns instructions rather than constants. // //===----------------------------------------------------------------------===// @@ -30,7 +29,7 @@ namespace llvm { class LLVMContext; -/// NoFolder - Create "constants" (actually, values) with no folding. +/// NoFolder - Create "constants" (actually, instructions) with no folding. class NoFolder { public: explicit NoFolder(LLVMContext &) {} @@ -39,84 +38,87 @@ public: // Binary Operators //===--------------------------------------------------------------------===// - Value *CreateAdd(Constant *LHS, Constant *RHS) const { + Instruction *CreateAdd(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateAdd(LHS, RHS); } - Value *CreateNSWAdd(Constant *LHS, Constant *RHS) const { + Instruction *CreateNSWAdd(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateNSWAdd(LHS, RHS); } - Value *CreateNUWAdd(Constant *LHS, Constant *RHS) const { + Instruction *CreateNUWAdd(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateNUWAdd(LHS, RHS); } - Value *CreateFAdd(Constant *LHS, Constant *RHS) const { + Instruction *CreateFAdd(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateFAdd(LHS, RHS); } - Value *CreateSub(Constant *LHS, Constant *RHS) const { + Instruction *CreateSub(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateSub(LHS, RHS); } - Value *CreateNSWSub(Constant *LHS, Constant *RHS) const { + Instruction *CreateNSWSub(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateNSWSub(LHS, RHS); } - Value *CreateNUWSub(Constant *LHS, Constant *RHS) const { + Instruction *CreateNUWSub(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateNUWSub(LHS, RHS); } - Value *CreateFSub(Constant *LHS, Constant *RHS) const { + Instruction *CreateFSub(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateFSub(LHS, RHS); } - Value *CreateMul(Constant *LHS, Constant *RHS) const { + Instruction *CreateMul(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateMul(LHS, RHS); } - Value *CreateNSWMul(Constant *LHS, Constant *RHS) const { + Instruction *CreateNSWMul(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateNSWMul(LHS, RHS); } - Value *CreateNUWMul(Constant *LHS, Constant *RHS) const { + Instruction *CreateNUWMul(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateNUWMul(LHS, RHS); } - Value *CreateFMul(Constant *LHS, Constant *RHS) const { + Instruction *CreateFMul(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateFMul(LHS, RHS); } - Value *CreateUDiv(Constant *LHS, Constant *RHS) const { + Instruction *CreateUDiv(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateUDiv(LHS, RHS); } - Value *CreateSDiv(Constant *LHS, Constant *RHS) const { + Instruction *CreateExactUDiv(Constant *LHS, Constant *RHS) const { + return BinaryOperator::CreateExactUDiv(LHS, RHS); + } + Instruction *CreateSDiv(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateSDiv(LHS, RHS); } - Value *CreateExactSDiv(Constant *LHS, Constant *RHS) const { + Instruction *CreateExactSDiv(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateExactSDiv(LHS, RHS); } - Value *CreateFDiv(Constant *LHS, Constant *RHS) const { + Instruction *CreateFDiv(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateFDiv(LHS, RHS); } - Value *CreateURem(Constant *LHS, Constant *RHS) const { + Instruction *CreateURem(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateURem(LHS, RHS); } - Value *CreateSRem(Constant *LHS, Constant *RHS) const { + Instruction *CreateSRem(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateSRem(LHS, RHS); } - Value *CreateFRem(Constant *LHS, Constant *RHS) const { + Instruction *CreateFRem(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateFRem(LHS, RHS); } - Value *CreateShl(Constant *LHS, Constant *RHS) const { + Instruction *CreateShl(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateShl(LHS, RHS); } - Value *CreateLShr(Constant *LHS, Constant *RHS) const { + Instruction *CreateLShr(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateLShr(LHS, RHS); } - Value *CreateAShr(Constant *LHS, Constant *RHS) const { + Instruction *CreateAShr(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateAShr(LHS, RHS); } - Value *CreateAnd(Constant *LHS, Constant *RHS) const { + Instruction *CreateAnd(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateAnd(LHS, RHS); } - Value *CreateOr(Constant *LHS, Constant *RHS) const { + Instruction *CreateOr(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateOr(LHS, RHS); } - Value *CreateXor(Constant *LHS, Constant *RHS) const { + Instruction *CreateXor(Constant *LHS, Constant *RHS) const { return BinaryOperator::CreateXor(LHS, RHS); } - Value *CreateBinOp(Instruction::BinaryOps Opc, - Constant *LHS, Constant *RHS) const { + Instruction *CreateBinOp(Instruction::BinaryOps Opc, + Constant *LHS, Constant *RHS) const { return BinaryOperator::Create(Opc, LHS, RHS); } @@ -124,16 +126,19 @@ public: // Unary Operators //===--------------------------------------------------------------------===// - Value *CreateNeg(Constant *C) const { + Instruction *CreateNeg(Constant *C) const { return BinaryOperator::CreateNeg(C); } - Value *CreateNSWNeg(Constant *C) const { + Instruction *CreateNSWNeg(Constant *C) const { return BinaryOperator::CreateNSWNeg(C); } - Value *CreateNUWNeg(Constant *C) const { + Instruction *CreateNUWNeg(Constant *C) const { return BinaryOperator::CreateNUWNeg(C); } - Value *CreateNot(Constant *C) const { + Instruction *CreateFNeg(Constant *C) const { + return BinaryOperator::CreateFNeg(C); + } + Instruction *CreateNot(Constant *C) const { return BinaryOperator::CreateNot(C); } @@ -145,8 +150,8 @@ public: unsigned NumIdx) const { return ConstantExpr::getGetElementPtr(C, IdxList, NumIdx); } - Value *CreateGetElementPtr(Constant *C, Value* const *IdxList, - unsigned NumIdx) const { + Instruction *CreateGetElementPtr(Constant *C, Value* const *IdxList, + unsigned NumIdx) const { return GetElementPtrInst::Create(C, IdxList, IdxList+NumIdx); } @@ -154,8 +159,8 @@ public: unsigned NumIdx) const { return ConstantExpr::getInBoundsGetElementPtr(C, IdxList, NumIdx); } - Value *CreateInBoundsGetElementPtr(Constant *C, Value* const *IdxList, - unsigned NumIdx) const { + Instruction *CreateInBoundsGetElementPtr(Constant *C, Value* const *IdxList, + unsigned NumIdx) const { return GetElementPtrInst::CreateInBounds(C, IdxList, IdxList+NumIdx); } @@ -163,23 +168,51 @@ public: // Cast/Conversion Operators //===--------------------------------------------------------------------===// - Value *CreateCast(Instruction::CastOps Op, Constant *C, + Instruction *CreateCast(Instruction::CastOps Op, Constant *C, const Type *DestTy) const { return CastInst::Create(Op, C, DestTy); } - Value *CreateIntCast(Constant *C, const Type *DestTy, + Instruction *CreatePointerCast(Constant *C, const Type *DestTy) const { + return CastInst::CreatePointerCast(C, DestTy); + } + Instruction *CreateIntCast(Constant *C, const Type *DestTy, bool isSigned) const { return CastInst::CreateIntegerCast(C, DestTy, isSigned); } + Instruction *CreateFPCast(Constant *C, const Type *DestTy) const { + return CastInst::CreateFPCast(C, DestTy); + } + + Instruction *CreateBitCast(Constant *C, const Type *DestTy) const { + return CreateCast(Instruction::BitCast, C, DestTy); + } + Instruction *CreateIntToPtr(Constant *C, const Type *DestTy) const { + return CreateCast(Instruction::IntToPtr, C, DestTy); + } + Instruction *CreatePtrToInt(Constant *C, const Type *DestTy) const { + return CreateCast(Instruction::PtrToInt, C, DestTy); + } + Instruction *CreateZExtOrBitCast(Constant *C, const Type *DestTy) const { + return CastInst::CreateZExtOrBitCast(C, DestTy); + } + Instruction *CreateSExtOrBitCast(Constant *C, const Type *DestTy) const { + return CastInst::CreateSExtOrBitCast(C, DestTy); + } + + Instruction *CreateTruncOrBitCast(Constant *C, const Type *DestTy) const { + return CastInst::CreateTruncOrBitCast(C, DestTy); + } //===--------------------------------------------------------------------===// // Compare Instructions //===--------------------------------------------------------------------===// - Value *CreateICmp(CmpInst::Predicate P, Constant *LHS, Constant *RHS) const { + Instruction *CreateICmp(CmpInst::Predicate P, + Constant *LHS, Constant *RHS) const { return new ICmpInst(P, LHS, RHS); } - Value *CreateFCmp(CmpInst::Predicate P, Constant *LHS, Constant *RHS) const { + Instruction *CreateFCmp(CmpInst::Predicate P, + Constant *LHS, Constant *RHS) const { return new FCmpInst(P, LHS, RHS); } @@ -187,30 +220,33 @@ public: // Other Instructions //===--------------------------------------------------------------------===// - Value *CreateSelect(Constant *C, Constant *True, Constant *False) const { + Instruction *CreateSelect(Constant *C, + Constant *True, Constant *False) const { return SelectInst::Create(C, True, False); } - Value *CreateExtractElement(Constant *Vec, Constant *Idx) const { + Instruction *CreateExtractElement(Constant *Vec, Constant *Idx) const { return ExtractElementInst::Create(Vec, Idx); } - Value *CreateInsertElement(Constant *Vec, Constant *NewElt, - Constant *Idx) const { + Instruction *CreateInsertElement(Constant *Vec, Constant *NewElt, + Constant *Idx) const { return InsertElementInst::Create(Vec, NewElt, Idx); } - Value *CreateShuffleVector(Constant *V1, Constant *V2, Constant *Mask) const { + Instruction *CreateShuffleVector(Constant *V1, Constant *V2, + Constant *Mask) const { return new ShuffleVectorInst(V1, V2, Mask); } - Value *CreateExtractValue(Constant *Agg, const unsigned *IdxList, - unsigned NumIdx) const { + Instruction *CreateExtractValue(Constant *Agg, const unsigned *IdxList, + unsigned NumIdx) const { return ExtractValueInst::Create(Agg, IdxList, IdxList+NumIdx); } - Value *CreateInsertValue(Constant *Agg, Constant *Val, - const unsigned *IdxList, unsigned NumIdx) const { + Instruction *CreateInsertValue(Constant *Agg, Constant *Val, + const unsigned *IdxList, + unsigned NumIdx) const { return InsertValueInst::Create(Agg, Val, IdxList, IdxList+NumIdx); } }; diff --git a/include/llvm/Support/Path.h b/include/llvm/Support/Path.h new file mode 100644 index 000000000000..196eecce8185 --- /dev/null +++ b/include/llvm/Support/Path.h @@ -0,0 +1,16 @@ +//===- llvm/Support/Path.h - Path Operating System Concept ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file currently includes both PathV1 and PathV2 to facilitate moving +// clients over to the new interface. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/PathV1.h" +#include "llvm/Support/PathV2.h" diff --git a/include/llvm/Support/PathV1.h b/include/llvm/Support/PathV1.h new file mode 100644 index 000000000000..a1c3f6a49a19 --- /dev/null +++ b/include/llvm/Support/PathV1.h @@ -0,0 +1,755 @@ +//===- llvm/Support/PathV1.h - Path Operating System Concept ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the llvm::sys::Path class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_PATH_H +#define LLVM_SYSTEM_PATH_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/TimeValue.h" +#include +#include +#include + +#define LLVM_PATH_DEPRECATED_MSG(replacement) \ + "PathV1 has been deprecated and will be removed as soon as all LLVM and" \ + " Clang clients have been moved over to PathV2. Please use `" #replacement \ + "` from PathV2 instead." + +namespace llvm { +namespace sys { + + /// This structure provides basic file system information about a file. It + /// is patterned after the stat(2) Unix operating system call but made + /// platform independent and eliminates many of the unix-specific fields. + /// However, to support llvm-ar, the mode, user, and group fields are + /// retained. These pertain to unix security and may not have a meaningful + /// value on non-Unix platforms. However, the other fields should + /// always be applicable on all platforms. The structure is filled in by + /// the PathWithStatus class. + /// @brief File status structure + class FileStatus { + public: + uint64_t fileSize; ///< Size of the file in bytes + TimeValue modTime; ///< Time of file's modification + uint32_t mode; ///< Mode of the file, if applicable + uint32_t user; ///< User ID of owner, if applicable + uint32_t group; ///< Group ID of owner, if applicable + uint64_t uniqueID; ///< A number to uniquely ID this file + bool isDir : 1; ///< True if this is a directory. + bool isFile : 1; ///< True if this is a file. + + FileStatus() : fileSize(0), modTime(0,0), mode(0777), user(999), + group(999), uniqueID(0), isDir(false), isFile(false) { } + + TimeValue getTimestamp() const { return modTime; } + uint64_t getSize() const { return fileSize; } + uint32_t getMode() const { return mode; } + uint32_t getUser() const { return user; } + uint32_t getGroup() const { return group; } + uint64_t getUniqueID() const { return uniqueID; } + }; + + /// This class provides an abstraction for the path to a file or directory + /// in the operating system's filesystem and provides various basic operations + /// on it. Note that this class only represents the name of a path to a file + /// or directory which may or may not be valid for a given machine's file + /// system. The class is patterned after the java.io.File class with various + /// extensions and several omissions (not relevant to LLVM). A Path object + /// ensures that the path it encapsulates is syntactically valid for the + /// operating system it is running on but does not ensure correctness for + /// any particular file system. That is, a syntactically valid path might + /// specify path components that do not exist in the file system and using + /// such a Path to act on the file system could produce errors. There is one + /// invalid Path value which is permitted: the empty path. The class should + /// never allow a syntactically invalid non-empty path name to be assigned. + /// Empty paths are required in order to indicate an error result in some + /// situations. If the path is empty, the isValid operation will return + /// false. All operations will fail if isValid is false. Operations that + /// change the path will either return false if it would cause a syntactically + /// invalid path name (in which case the Path object is left unchanged) or + /// throw an std::string exception indicating the error. The methods are + /// grouped into four basic categories: Path Accessors (provide information + /// about the path without accessing disk), Disk Accessors (provide + /// information about the underlying file or directory), Path Mutators + /// (change the path information, not the disk), and Disk Mutators (change + /// the disk file/directory referenced by the path). The Disk Mutator methods + /// all have the word "disk" embedded in their method name to reinforce the + /// notion that the operation modifies the file system. + /// @since 1.4 + /// @brief An abstraction for operating system paths. + class Path { + /// @name Constructors + /// @{ + public: + /// Construct a path to the root directory of the file system. The root + /// directory is a top level directory above which there are no more + /// directories. For example, on UNIX, the root directory is /. On Windows + /// it is file:///. Other operating systems may have different notions of + /// what the root directory is or none at all. In that case, a consistent + /// default root directory will be used. + LLVM_ATTRIBUTE_DEPRECATED(static Path GetRootDirectory(), + LLVM_PATH_DEPRECATED_MSG(NOTHING)); + + /// Construct a path to a unique temporary directory that is created in + /// a "standard" place for the operating system. The directory is + /// guaranteed to be created on exit from this function. If the directory + /// cannot be created, the function will throw an exception. + /// @returns an invalid path (empty) on error + /// @param ErrMsg Optional place for an error message if an error occurs + /// @brief Construct a path to an new, unique, existing temporary + /// directory. + static Path GetTemporaryDirectory(std::string* ErrMsg = 0); + + /// Construct a vector of sys::Path that contains the "standard" system + /// library paths suitable for linking into programs. + /// @brief Construct a path to the system library directory + static void GetSystemLibraryPaths(std::vector& Paths); + + /// Construct a vector of sys::Path that contains the "standard" bitcode + /// library paths suitable for linking into an llvm program. This function + /// *must* return the value of LLVM_LIB_SEARCH_PATH as well as the value + /// of LLVM_LIBDIR. It also must provide the System library paths as + /// returned by GetSystemLibraryPaths. + /// @see GetSystemLibraryPaths + /// @brief Construct a list of directories in which bitcode could be + /// found. + static void GetBitcodeLibraryPaths(std::vector& Paths); + + /// Find the path to a library using its short name. Use the system + /// dependent library paths to locate the library. + /// @brief Find a library. + static Path FindLibrary(std::string& short_name); + + /// Construct a path to the default LLVM configuration directory. The + /// implementation must ensure that this is a well-known (same on many + /// systems) directory in which llvm configuration files exist. For + /// example, on Unix, the /etc/llvm directory has been selected. + /// @brief Construct a path to the default LLVM configuration directory + static Path GetLLVMDefaultConfigDir(); + + /// Construct a path to the LLVM installed configuration directory. The + /// implementation must ensure that this refers to the "etc" directory of + /// the LLVM installation. This is the location where configuration files + /// will be located for a particular installation of LLVM on a machine. + /// @brief Construct a path to the LLVM installed configuration directory + static Path GetLLVMConfigDir(); + + /// Construct a path to the current user's home directory. The + /// implementation must use an operating system specific mechanism for + /// determining the user's home directory. For example, the environment + /// variable "HOME" could be used on Unix. If a given operating system + /// does not have the concept of a user's home directory, this static + /// constructor must provide the same result as GetRootDirectory. + /// @brief Construct a path to the current user's "home" directory + static Path GetUserHomeDirectory(); + + /// Construct a path to the current directory for the current process. + /// @returns The current working directory. + /// @brief Returns the current working directory. + static Path GetCurrentDirectory(); + + /// Return the suffix commonly used on file names that contain an + /// executable. + /// @returns The executable file suffix for the current platform. + /// @brief Return the executable file suffix. + static StringRef GetEXESuffix(); + + /// Return the suffix commonly used on file names that contain a shared + /// object, shared archive, or dynamic link library. Such files are + /// linked at runtime into a process and their code images are shared + /// between processes. + /// @returns The dynamic link library suffix for the current platform. + /// @brief Return the dynamic link library suffix. + static StringRef GetDLLSuffix(); + + /// GetMainExecutable - Return the path to the main executable, given the + /// value of argv[0] from program startup and the address of main itself. + /// In extremis, this function may fail and return an empty path. + static Path GetMainExecutable(const char *argv0, void *MainAddr); + + /// This is one of the very few ways in which a path can be constructed + /// with a syntactically invalid name. The only *legal* invalid name is an + /// empty one. Other invalid names are not permitted. Empty paths are + /// provided so that they can be used to indicate null or error results in + /// other lib/System functionality. + /// @brief Construct an empty (and invalid) path. + Path() : path() {} + Path(const Path &that) : path(that.path) {} + + /// This constructor will accept a char* or std::string as a path. No + /// checking is done on this path to determine if it is valid. To + /// determine validity of the path, use the isValid method. + /// @param p The path to assign. + /// @brief Construct a Path from a string. + explicit Path(StringRef p); + + /// This constructor will accept a character range as a path. No checking + /// is done on this path to determine if it is valid. To determine + /// validity of the path, use the isValid method. + /// @param StrStart A pointer to the first character of the path name + /// @param StrLen The length of the path name at StrStart + /// @brief Construct a Path from a string. + Path(const char *StrStart, unsigned StrLen); + + /// @} + /// @name Operators + /// @{ + public: + /// Makes a copy of \p that to \p this. + /// @returns \p this + /// @brief Assignment Operator + Path &operator=(const Path &that) { + path = that.path; + return *this; + } + + /// Makes a copy of \p that to \p this. + /// @param that A StringRef denoting the path + /// @returns \p this + /// @brief Assignment Operator + Path &operator=(StringRef that); + + /// Compares \p this Path with \p that Path for equality. + /// @returns true if \p this and \p that refer to the same thing. + /// @brief Equality Operator + bool operator==(const Path &that) const; + + /// Compares \p this Path with \p that Path for inequality. + /// @returns true if \p this and \p that refer to different things. + /// @brief Inequality Operator + bool operator!=(const Path &that) const { return !(*this == that); } + + /// Determines if \p this Path is less than \p that Path. This is required + /// so that Path objects can be placed into ordered collections (e.g. + /// std::map). The comparison is done lexicographically as defined by + /// the std::string::compare method. + /// @returns true if \p this path is lexicographically less than \p that. + /// @brief Less Than Operator + bool operator<(const Path& that) const; + + /// @} + /// @name Path Accessors + /// @{ + public: + /// This function will use an operating system specific algorithm to + /// determine if the current value of \p this is a syntactically valid + /// path name for the operating system. The path name does not need to + /// exist, validity is simply syntactical. Empty paths are always invalid. + /// @returns true iff the path name is syntactically legal for the + /// host operating system. + /// @brief Determine if a path is syntactically valid or not. + bool isValid() const; + + /// This function determines if the contents of the path name are empty. + /// That is, the path name has a zero length. This does NOT determine if + /// if the file is empty. To get the length of the file itself, Use the + /// PathWithStatus::getFileStatus() method and then the getSize() method + /// on the returned FileStatus object. + /// @returns true iff the path is empty. + /// @brief Determines if the path name is empty (invalid). + bool isEmpty() const { return path.empty(); } + + /// This function returns the last component of the path name. The last + /// component is the file or directory name occurring after the last + /// directory separator. If no directory separator is present, the entire + /// path name is returned (i.e. same as toString). + /// @returns StringRef containing the last component of the path name. + /// @brief Returns the last component of the path name. + LLVM_ATTRIBUTE_DEPRECATED( + StringRef getLast() const, + LLVM_PATH_DEPRECATED_MSG(path::filename)); + + /// This function strips off the path and suffix of the file or directory + /// name and returns just the basename. For example /a/foo.bar would cause + /// this function to return "foo". + /// @returns StringRef containing the basename of the path + /// @brief Get the base name of the path + LLVM_ATTRIBUTE_DEPRECATED(StringRef getBasename() const, + LLVM_PATH_DEPRECATED_MSG(path::stem)); + + /// This function strips off the suffix of the path beginning with the + /// path separator ('/' on Unix, '\' on Windows) and returns the result. + LLVM_ATTRIBUTE_DEPRECATED(StringRef getDirname() const, + LLVM_PATH_DEPRECATED_MSG(path::parent_path)); + + /// This function strips off the path and basename(up to and + /// including the last dot) of the file or directory name and + /// returns just the suffix. For example /a/foo.bar would cause + /// this function to return "bar". + /// @returns StringRef containing the suffix of the path + /// @brief Get the suffix of the path + LLVM_ATTRIBUTE_DEPRECATED(StringRef getSuffix() const, + LLVM_PATH_DEPRECATED_MSG(path::extension)); + + /// Obtain a 'C' string for the path name. + /// @returns a 'C' string containing the path name. + /// @brief Returns the path as a C string. + const char *c_str() const { return path.c_str(); } + const std::string &str() const { return path; } + + + /// size - Return the length in bytes of this path name. + size_t size() const { return path.size(); } + + /// empty - Returns true if the path is empty. + unsigned empty() const { return path.empty(); } + + /// @} + /// @name Disk Accessors + /// @{ + public: + /// This function determines if the path name is absolute, as opposed to + /// relative. + /// @brief Determine if the path is absolute. +//FIXME: LLVM_ATTRIBUTE_DEPRECATED( + bool isAbsolute() const; +//FIXME: LLVMV_PATH_DEPRECATED_MSG(path::is_absolute)); + + /// This function determines if the path name is absolute, as opposed to + /// relative. + /// @brief Determine if the path is absolute. + LLVM_ATTRIBUTE_DEPRECATED( + static bool isAbsolute(const char *NameStart, unsigned NameLen), + LLVM_PATH_DEPRECATED_MSG(path::is_absolute)); + + /// This function opens the file associated with the path name provided by + /// the Path object and reads its magic number. If the magic number at the + /// start of the file matches \p magic, true is returned. In all other + /// cases (file not found, file not accessible, etc.) it returns false. + /// @returns true if the magic number of the file matches \p magic. + /// @brief Determine if file has a specific magic number + LLVM_ATTRIBUTE_DEPRECATED(bool hasMagicNumber(StringRef magic) const, + LLVM_PATH_DEPRECATED_MSG(fs::has_magic)); + + /// This function retrieves the first \p len bytes of the file associated + /// with \p this. These bytes are returned as the "magic number" in the + /// \p Magic parameter. + /// @returns true if the Path is a file and the magic number is retrieved, + /// false otherwise. + /// @brief Get the file's magic number. + bool getMagicNumber(std::string& Magic, unsigned len) const; + + /// This function determines if the path name in the object references an + /// archive file by looking at its magic number. + /// @returns true if the file starts with the magic number for an archive + /// file. + /// @brief Determine if the path references an archive file. + bool isArchive() const; + + /// This function determines if the path name in the object references an + /// LLVM Bitcode file by looking at its magic number. + /// @returns true if the file starts with the magic number for LLVM + /// bitcode files. + /// @brief Determine if the path references a bitcode file. + bool isBitcodeFile() const; + + /// This function determines if the path name in the object references a + /// native Dynamic Library (shared library, shared object) by looking at + /// the file's magic number. The Path object must reference a file, not a + /// directory. + /// @returns true if the file starts with the magic number for a native + /// shared library. + /// @brief Determine if the path references a dynamic library. + bool isDynamicLibrary() const; + + /// This function determines if the path name in the object references a + /// native object file by looking at it's magic number. The term object + /// file is defined as "an organized collection of separate, named + /// sequences of binary data." This covers the obvious file formats such + /// as COFF and ELF, but it also includes llvm ir bitcode, archives, + /// libraries, etc... + /// @returns true if the file starts with the magic number for an object + /// file. + /// @brief Determine if the path references an object file. + bool isObjectFile() const; + + /// This function determines if the path name references an existing file + /// or directory in the file system. + /// @returns true if the pathname references an existing file or + /// directory. + /// @brief Determines if the path is a file or directory in + /// the file system. + LLVM_ATTRIBUTE_DEPRECATED(bool exists() const, + LLVM_PATH_DEPRECATED_MSG(fs::exists)); + + /// This function determines if the path name references an + /// existing directory. + /// @returns true if the pathname references an existing directory. + /// @brief Determines if the path is a directory in the file system. + LLVM_ATTRIBUTE_DEPRECATED(bool isDirectory() const, + LLVM_PATH_DEPRECATED_MSG(fs::is_directory)); + + /// This function determines if the path name references an + /// existing symbolic link. + /// @returns true if the pathname references an existing symlink. + /// @brief Determines if the path is a symlink in the file system. + LLVM_ATTRIBUTE_DEPRECATED(bool isSymLink() const, + LLVM_PATH_DEPRECATED_MSG(fs::is_symlink)); + + /// This function determines if the path name references a readable file + /// or directory in the file system. This function checks for + /// the existence and readability (by the current program) of the file + /// or directory. + /// @returns true if the pathname references a readable file. + /// @brief Determines if the path is a readable file or directory + /// in the file system. + bool canRead() const; + + /// This function determines if the path name references a writable file + /// or directory in the file system. This function checks for the + /// existence and writability (by the current program) of the file or + /// directory. + /// @returns true if the pathname references a writable file. + /// @brief Determines if the path is a writable file or directory + /// in the file system. + bool canWrite() const; + + /// This function checks that what we're trying to work only on a regular + /// file. Check for things like /dev/null, any block special file, or + /// other things that aren't "regular" regular files. + /// @returns true if the file is S_ISREG. + /// @brief Determines if the file is a regular file + bool isRegularFile() const; + + /// This function determines if the path name references an executable + /// file in the file system. This function checks for the existence and + /// executability (by the current program) of the file. + /// @returns true if the pathname references an executable file. + /// @brief Determines if the path is an executable file in the file + /// system. + bool canExecute() const; + + /// This function builds a list of paths that are the names of the + /// files and directories in a directory. + /// @returns true if an error occurs, true otherwise + /// @brief Build a list of directory's contents. + bool getDirectoryContents( + std::set &paths, ///< The resulting list of file & directory names + std::string* ErrMsg ///< Optional place to return an error message. + ) const; + + /// @} + /// @name Path Mutators + /// @{ + public: + /// The path name is cleared and becomes empty. This is an invalid + /// path name but is the *only* invalid path name. This is provided + /// so that path objects can be used to indicate the lack of a + /// valid path being found. + /// @brief Make the path empty. + void clear() { path.clear(); } + + /// This method sets the Path object to \p unverified_path. This can fail + /// if the \p unverified_path does not pass the syntactic checks of the + /// isValid() method. If verification fails, the Path object remains + /// unchanged and false is returned. Otherwise true is returned and the + /// Path object takes on the path value of \p unverified_path + /// @returns true if the path was set, false otherwise. + /// @param unverified_path The path to be set in Path object. + /// @brief Set a full path from a StringRef + bool set(StringRef unverified_path); + + /// One path component is removed from the Path. If only one component is + /// present in the path, the Path object becomes empty. If the Path object + /// is empty, no change is made. + /// @returns false if the path component could not be removed. + /// @brief Removes the last directory component of the Path. + bool eraseComponent(); + + /// The \p component is added to the end of the Path if it is a legal + /// name for the operating system. A directory separator will be added if + /// needed. + /// @returns false if the path component could not be added. + /// @brief Appends one path component to the Path. + bool appendComponent(StringRef component); + + /// A period and the \p suffix are appended to the end of the pathname. + /// When the \p suffix is empty, no action is performed. + /// @brief Adds a period and the \p suffix to the end of the pathname. + void appendSuffix(StringRef suffix); + + /// The suffix of the filename is erased. The suffix begins with and + /// includes the last . character in the filename after the last directory + /// separator and extends until the end of the name. If no . character is + /// after the last directory separator, then the file name is left + /// unchanged (i.e. it was already without a suffix) but the function + /// returns false. + /// @returns false if there was no suffix to remove, true otherwise. + /// @brief Remove the suffix from a path name. + bool eraseSuffix(); + + /// The current Path name is made unique in the file system. Upon return, + /// the Path will have been changed to make a unique file in the file + /// system or it will not have been changed if the current path name is + /// already unique. + /// @throws std::string if an unrecoverable error occurs. + /// @brief Make the current path name unique in the file system. + bool makeUnique( bool reuse_current /*= true*/, std::string* ErrMsg ); + + /// The current Path name is made absolute by prepending the + /// current working directory if necessary. + LLVM_ATTRIBUTE_DEPRECATED( + void makeAbsolute(), + LLVM_PATH_DEPRECATED_MSG(fs::make_absolute)); + + /// @} + /// @name Disk Mutators + /// @{ + public: + /// This method attempts to make the file referenced by the Path object + /// available for reading so that the canRead() method will return true. + /// @brief Make the file readable; + bool makeReadableOnDisk(std::string* ErrMsg = 0); + + /// This method attempts to make the file referenced by the Path object + /// available for writing so that the canWrite() method will return true. + /// @brief Make the file writable; + bool makeWriteableOnDisk(std::string* ErrMsg = 0); + + /// This method attempts to make the file referenced by the Path object + /// available for execution so that the canExecute() method will return + /// true. + /// @brief Make the file readable; + bool makeExecutableOnDisk(std::string* ErrMsg = 0); + + /// This method allows the last modified time stamp and permission bits + /// to be set on the disk object referenced by the Path. + /// @throws std::string if an error occurs. + /// @returns true on error. + /// @brief Set the status information. + bool setStatusInfoOnDisk(const FileStatus &SI, + std::string *ErrStr = 0) const; + + /// This method attempts to create a directory in the file system with the + /// same name as the Path object. The \p create_parents parameter controls + /// whether intermediate directories are created or not. if \p + /// create_parents is true, then an attempt will be made to create all + /// intermediate directories, as needed. If \p create_parents is false, + /// then only the final directory component of the Path name will be + /// created. The created directory will have no entries. + /// @returns true if the directory could not be created, false otherwise + /// @brief Create the directory this Path refers to. + bool createDirectoryOnDisk( + bool create_parents = false, ///< Determines whether non-existent + ///< directory components other than the last one (the "parents") + ///< are created or not. + std::string* ErrMsg = 0 ///< Optional place to put error messages. + ); + + /// This method attempts to create a file in the file system with the same + /// name as the Path object. The intermediate directories must all exist + /// at the time this method is called. Use createDirectoriesOnDisk to + /// accomplish that. The created file will be empty upon return from this + /// function. + /// @returns true if the file could not be created, false otherwise. + /// @brief Create the file this Path refers to. + bool createFileOnDisk( + std::string* ErrMsg = 0 ///< Optional place to put error messages. + ); + + /// This is like createFile except that it creates a temporary file. A + /// unique temporary file name is generated based on the contents of + /// \p this before the call. The new name is assigned to \p this and the + /// file is created. Note that this will both change the Path object + /// *and* create the corresponding file. This function will ensure that + /// the newly generated temporary file name is unique in the file system. + /// @returns true if the file couldn't be created, false otherwise. + /// @brief Create a unique temporary file + bool createTemporaryFileOnDisk( + bool reuse_current = false, ///< When set to true, this parameter + ///< indicates that if the current file name does not exist then + ///< it will be used without modification. + std::string* ErrMsg = 0 ///< Optional place to put error messages + ); + + /// This method renames the file referenced by \p this as \p newName. The + /// file referenced by \p this must exist. The file referenced by + /// \p newName does not need to exist. + /// @returns true on error, false otherwise + /// @brief Rename one file as another. + bool renamePathOnDisk(const Path& newName, std::string* ErrMsg); + + /// This method attempts to destroy the file or directory named by the + /// last component of the Path. If the Path refers to a directory and the + /// \p destroy_contents is false, an attempt will be made to remove just + /// the directory (the final Path component). If \p destroy_contents is + /// true, an attempt will be made to remove the entire contents of the + /// directory, recursively. If the Path refers to a file, the + /// \p destroy_contents parameter is ignored. + /// @param destroy_contents Indicates whether the contents of a destroyed + /// @param Err An optional string to receive an error message. + /// directory should also be destroyed (recursively). + /// @returns false if the file/directory was destroyed, true on error. + /// @brief Removes the file or directory from the filesystem. + bool eraseFromDisk(bool destroy_contents = false, + std::string *Err = 0) const; + + + /// MapInFilePages - This is a low level system API to map in the file + /// that is currently opened as FD into the current processes' address + /// space for read only access. This function may return null on failure + /// or if the system cannot provide the following constraints: + /// 1) The pages must be valid after the FD is closed, until + /// UnMapFilePages is called. + /// 2) Any padding after the end of the file must be zero filled, if + /// present. + /// 3) The pages must be contiguous. + /// + /// This API is not intended for general use, clients should use + /// MemoryBuffer::getFile instead. + static const char *MapInFilePages(int FD, uint64_t FileSize); + + /// UnMapFilePages - Free pages mapped into the current process by + /// MapInFilePages. + /// + /// This API is not intended for general use, clients should use + /// MemoryBuffer::getFile instead. + static void UnMapFilePages(const char *Base, uint64_t FileSize); + + /// @} + /// @name Data + /// @{ + protected: + // Our win32 implementation relies on this string being mutable. + mutable std::string path; ///< Storage for the path name. + + + /// @} + }; + + /// This class is identical to Path class except it allows you to obtain the + /// file status of the Path as well. The reason for the distinction is one of + /// efficiency. First, the file status requires additional space and the space + /// is incorporated directly into PathWithStatus without an additional malloc. + /// Second, obtaining status information is an expensive operation on most + /// operating systems so we want to be careful and explicit about where we + /// allow this operation in LLVM. + /// @brief Path with file status class. + class PathWithStatus : public Path { + /// @name Constructors + /// @{ + public: + /// @brief Default constructor + PathWithStatus() : Path(), status(), fsIsValid(false) {} + + /// @brief Copy constructor + PathWithStatus(const PathWithStatus &that) + : Path(static_cast(that)), status(that.status), + fsIsValid(that.fsIsValid) {} + + /// This constructor allows construction from a Path object + /// @brief Path constructor + PathWithStatus(const Path &other) + : Path(other), status(), fsIsValid(false) {} + + /// This constructor will accept a char* or std::string as a path. No + /// checking is done on this path to determine if it is valid. To + /// determine validity of the path, use the isValid method. + /// @brief Construct a Path from a string. + explicit PathWithStatus( + StringRef p ///< The path to assign. + ) : Path(p), status(), fsIsValid(false) {} + + /// This constructor will accept a character range as a path. No checking + /// is done on this path to determine if it is valid. To determine + /// validity of the path, use the isValid method. + /// @brief Construct a Path from a string. + explicit PathWithStatus( + const char *StrStart, ///< Pointer to the first character of the path + unsigned StrLen ///< Length of the path. + ) : Path(StrStart, StrLen), status(), fsIsValid(false) {} + + /// Makes a copy of \p that to \p this. + /// @returns \p this + /// @brief Assignment Operator + PathWithStatus &operator=(const PathWithStatus &that) { + static_cast(*this) = static_cast(that); + status = that.status; + fsIsValid = that.fsIsValid; + return *this; + } + + /// Makes a copy of \p that to \p this. + /// @returns \p this + /// @brief Assignment Operator + PathWithStatus &operator=(const Path &that) { + static_cast(*this) = static_cast(that); + fsIsValid = false; + return *this; + } + + /// @} + /// @name Methods + /// @{ + public: + /// This function returns status information about the file. The type of + /// path (file or directory) is updated to reflect the actual contents + /// of the file system. + /// @returns 0 on failure, with Error explaining why (if non-zero) + /// @returns a pointer to a FileStatus structure on success. + /// @brief Get file status. + const FileStatus *getFileStatus( + bool forceUpdate = false, ///< Force an update from the file system + std::string *Error = 0 ///< Optional place to return an error msg. + ) const; + + /// @} + /// @name Data + /// @{ + private: + mutable FileStatus status; ///< Status information. + mutable bool fsIsValid; ///< Whether we've obtained it or not + + /// @} + }; + + /// This enumeration delineates the kinds of files that LLVM knows about. + enum LLVMFileType { + Unknown_FileType = 0, ///< Unrecognized file + Bitcode_FileType, ///< Bitcode file + Archive_FileType, ///< ar style archive file + ELF_Relocatable_FileType, ///< ELF Relocatable object file + ELF_Executable_FileType, ///< ELF Executable image + ELF_SharedObject_FileType, ///< ELF dynamically linked shared lib + ELF_Core_FileType, ///< ELF core image + Mach_O_Object_FileType, ///< Mach-O Object file + Mach_O_Executable_FileType, ///< Mach-O Executable + Mach_O_FixedVirtualMemorySharedLib_FileType, ///< Mach-O Shared Lib, FVM + Mach_O_Core_FileType, ///< Mach-O Core File + Mach_O_PreloadExecutable_FileType, ///< Mach-O Preloaded Executable + Mach_O_DynamicallyLinkedSharedLib_FileType, ///< Mach-O dynlinked shared lib + Mach_O_DynamicLinker_FileType, ///< The Mach-O dynamic linker + Mach_O_Bundle_FileType, ///< Mach-O Bundle file + Mach_O_DynamicallyLinkedSharedLibStub_FileType, ///< Mach-O Shared lib stub + COFF_FileType ///< COFF object file or lib + }; + + /// This utility function allows any memory block to be examined in order + /// to determine its file type. + LLVMFileType IdentifyFileType(const char*magic, unsigned length); + + /// This function can be used to copy the file specified by Src to the + /// file specified by Dest. If an error occurs, Dest is removed. + /// @returns true if an error occurs, false otherwise + /// @brief Copy one file to another. + bool CopyFile(const Path& Dest, const Path& Src, std::string* ErrMsg); + + /// This is the OS-specific path separator: a colon on Unix or a semicolon + /// on Windows. + extern const char PathSeparator; +} + +} + +#endif diff --git a/include/llvm/Support/PathV2.h b/include/llvm/Support/PathV2.h new file mode 100644 index 000000000000..251563398fb4 --- /dev/null +++ b/include/llvm/Support/PathV2.h @@ -0,0 +1,347 @@ +//===- llvm/Support/PathV2.h - Path Operating System Concept ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the llvm::sys::path namespace. It is designed after +// TR2/boost filesystem (v3), but modified to remove exception handling and the +// path class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_PATHV2_H +#define LLVM_SUPPORT_PATHV2_H + +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/DataTypes.h" +#include + +namespace llvm { +namespace sys { +namespace path { + +/// @name Lexical Component Iterator +/// @{ + +/// @brief Path iterator. +/// +/// This is a bidirectional iterator that iterates over the individual +/// components in \a path. The forward traversal order is as follows: +/// * The root-name element, if present. +/// * The root-directory element, if present. +/// * Each successive filename element, if present. +/// * Dot, if one or more trailing non-root slash characters are present. +/// The backwards traversal order is the reverse of forward traversal. +/// +/// Iteration examples. Each component is separated by ',': +/// / => / +/// /foo => /,foo +/// foo/ => foo,. +/// /foo/bar => /,foo,bar +/// ../ => ..,. +/// C:\foo\bar => C:,/,foo,bar +/// +class const_iterator { + StringRef Path; //< The entire path. + StringRef Component; //< The current component. Not necessarily in Path. + size_t Position; //< The iterators current position within Path. + + // An end iterator has Position = Path.size() + 1. + friend const_iterator begin(StringRef path); + friend const_iterator end(StringRef path); + +public: + typedef const StringRef value_type; + typedef ptrdiff_t difference_type; + typedef value_type &reference; + typedef value_type *pointer; + typedef std::bidirectional_iterator_tag iterator_category; + + reference operator*() const { return Component; } + pointer operator->() const { return &Component; } + const_iterator &operator++(); // preincrement + const_iterator &operator++(int); // postincrement + const_iterator &operator--(); // predecrement + const_iterator &operator--(int); // postdecrement + bool operator==(const const_iterator &RHS) const; + bool operator!=(const const_iterator &RHS) const; + + /// @brief Difference in bytes between this and RHS. + ptrdiff_t operator-(const const_iterator &RHS) const; +}; + +typedef std::reverse_iterator reverse_iterator; + +/// @brief Get begin iterator over \a path. +/// @param path Input path. +/// @returns Iterator initialized with the first component of \a path. +const_iterator begin(StringRef path); + +/// @brief Get end iterator over \a path. +/// @param path Input path. +/// @returns Iterator initialized to the end of \a path. +const_iterator end(StringRef path); + +/// @brief Get reverse begin iterator over \a path. +/// @param path Input path. +/// @returns Iterator initialized with the first reverse component of \a path. +inline reverse_iterator rbegin(StringRef path) { + return reverse_iterator(end(path)); +} + +/// @brief Get reverse end iterator over \a path. +/// @param path Input path. +/// @returns Iterator initialized to the reverse end of \a path. +inline reverse_iterator rend(StringRef path) { + return reverse_iterator(begin(path)); +} + +/// @} +/// @name Lexical Modifiers +/// @{ + +/// @brief Remove the last component from \a path unless it is the root dir. +/// +/// directory/filename.cpp => directory/ +/// directory/ => directory +/// / => / +/// +/// @param path A path that is modified to not have a file component. +void remove_filename(SmallVectorImpl &path); + +/// @brief Replace the file extension of \a path with \a extension. +/// +/// ./filename.cpp => ./filename.extension +/// ./filename => ./filename.extension +/// ./ => ./.extension +/// +/// @param path A path that has its extension replaced with \a extension. +/// @param extension The extension to be added. It may be empty. It may also +/// optionally start with a '.', if it does not, one will be +/// prepended. +void replace_extension(SmallVectorImpl &path, const Twine &extension); + +/// @brief Append to path. +/// +/// /foo + bar/f => /foo/bar/f +/// /foo/ + bar/f => /foo/bar/f +/// foo + bar/f => foo/bar/f +/// +/// @param path Set to \a path + \a component. +/// @param component The component to be appended to \a path. +void append(SmallVectorImpl &path, const Twine &a, + const Twine &b = "", + const Twine &c = "", + const Twine &d = ""); + +/// @brief Append to path. +/// +/// /foo + [bar,f] => /foo/bar/f +/// /foo/ + [bar,f] => /foo/bar/f +/// foo + [bar,f] => foo/bar/f +/// +/// @param path Set to \a path + [\a begin, \a end). +/// @param begin Start of components to append. +/// @param end One past the end of components to append. +void append(SmallVectorImpl &path, + const_iterator begin, const_iterator end); + +/// @} +/// @name Transforms (or some other better name) +/// @{ + +/// Convert path to the native form. This is used to give paths to users and +/// operating system calls in the platform's normal way. For example, on Windows +/// all '/' are converted to '\'. +/// +/// @param path A path that is transformed to native format. +/// @param result Holds the result of the transformation. +void native(const Twine &path, SmallVectorImpl &result); + +/// @} +/// @name Lexical Observers +/// @{ + +/// @brief Get root name. +/// +/// //net/hello => //net +/// c:/hello => c: (on Windows, on other platforms nothing) +/// /hello => +/// +/// @param path Input path. +/// @result The root name of \a path if it has one, otherwise "". +const StringRef root_name(StringRef path); + +/// @brief Get root directory. +/// +/// /goo/hello => / +/// c:/hello => / +/// d/file.txt => +/// +/// @param path Input path. +/// @result The root directory of \a path if it has one, otherwise +/// "". +const StringRef root_directory(StringRef path); + +/// @brief Get root path. +/// +/// Equivalent to root_name + root_directory. +/// +/// @param path Input path. +/// @result The root path of \a path if it has one, otherwise "". +const StringRef root_path(StringRef path); + +/// @brief Get relative path. +/// +/// C:\hello\world => hello\world +/// foo/bar => foo/bar +/// /foo/bar => foo/bar +/// +/// @param path Input path. +/// @result The path starting after root_path if one exists, otherwise "". +const StringRef relative_path(StringRef path); + +/// @brief Get parent path. +/// +/// / => +/// /foo => / +/// foo/../bar => foo/.. +/// +/// @param path Input path. +/// @result The parent path of \a path if one exists, otherwise "". +const StringRef parent_path(StringRef path); + +/// @brief Get filename. +/// +/// /foo.txt => foo.txt +/// . => . +/// .. => .. +/// / => / +/// +/// @param path Input path. +/// @result The filename part of \a path. This is defined as the last component +/// of \a path. +const StringRef filename(StringRef path); + +/// @brief Get stem. +/// +/// If filename contains a dot but not solely one or two dots, result is the +/// substring of filename ending at (but not including) the last dot. Otherwise +/// it is filename. +/// +/// /foo/bar.txt => bar +/// /foo/bar => bar +/// /foo/.txt => +/// /foo/. => . +/// /foo/.. => .. +/// +/// @param path Input path. +/// @result The stem of \a path. +const StringRef stem(StringRef path); + +/// @brief Get extension. +/// +/// If filename contains a dot but not solely one or two dots, result is the +/// substring of filename starting at (and including) the last dot, and ending +/// at the end of \a path. Otherwise "". +/// +/// /foo/bar.txt => .txt +/// /foo/bar => +/// /foo/.txt => .txt +/// +/// @param path Input path. +/// @result The extension of \a path. +const StringRef extension(StringRef path); + +/// @brief Check whether the given char is a path separator on the host OS. +/// +/// @param value a character +/// @result true if \a value is a path separator character on the host OS +bool is_separator(char value); + +/// @brief Has root name? +/// +/// root_name != "" +/// +/// @param path Input path. +/// @result True if the path has a root name, false otherwise. +bool has_root_name(const Twine &path); + +/// @brief Has root directory? +/// +/// root_directory != "" +/// +/// @param path Input path. +/// @result True if the path has a root directory, false otherwise. +bool has_root_directory(const Twine &path); + +/// @brief Has root path? +/// +/// root_path != "" +/// +/// @param path Input path. +/// @result True if the path has a root path, false otherwise. +bool has_root_path(const Twine &path); + +/// @brief Has relative path? +/// +/// relative_path != "" +/// +/// @param path Input path. +/// @result True if the path has a relative path, false otherwise. +bool has_relative_path(const Twine &path); + +/// @brief Has parent path? +/// +/// parent_path != "" +/// +/// @param path Input path. +/// @result True if the path has a parent path, false otherwise. +bool has_parent_path(const Twine &path); + +/// @brief Has filename? +/// +/// filename != "" +/// +/// @param path Input path. +/// @result True if the path has a filename, false otherwise. +bool has_filename(const Twine &path); + +/// @brief Has stem? +/// +/// stem != "" +/// +/// @param path Input path. +/// @result True if the path has a stem, false otherwise. +bool has_stem(const Twine &path); + +/// @brief Has extension? +/// +/// extension != "" +/// +/// @param path Input path. +/// @result True if the path has a extension, false otherwise. +bool has_extension(const Twine &path); + +/// @brief Is path absolute? +/// +/// @param path Input path. +/// @result True if the path is absolute, false if it is not. +bool is_absolute(const Twine &path); + +/// @brief Is path relative? +/// +/// @param path Input path. +/// @result True if the path is relative, false if it is not. +bool is_relative(const Twine &path); + +} // end namespace path +} // end namespace sys +} // end namespace llvm + +#endif diff --git a/include/llvm/Support/PatternMatch.h b/include/llvm/Support/PatternMatch.h index bee676863780..948ae5176eeb 100644 --- a/include/llvm/Support/PatternMatch.h +++ b/include/llvm/Support/PatternMatch.h @@ -41,18 +41,62 @@ bool match(Val *V, const Pattern &P) { } template -struct leaf_ty { +struct class_match { template bool match(ITy *V) { return isa(V); } }; /// m_Value() - Match an arbitrary value and ignore it. -inline leaf_ty m_Value() { return leaf_ty(); } +inline class_match m_Value() { return class_match(); } /// m_ConstantInt() - Match an arbitrary ConstantInt and ignore it. -inline leaf_ty m_ConstantInt() { return leaf_ty(); } +inline class_match m_ConstantInt() { + return class_match(); +} +/// m_Undef() - Match an arbitrary undef constant. +inline class_match m_Undef() { return class_match(); } +inline class_match m_Constant() { return class_match(); } + +struct match_zero { + template + bool match(ITy *V) { + if (const Constant *C = dyn_cast(V)) + return C->isNullValue(); + return false; + } +}; + +/// m_Zero() - Match an arbitrary zero/null constant. This includes +/// zero_initializer for vectors and ConstantPointerNull for pointers. +inline match_zero m_Zero() { return match_zero(); } + + +struct apint_match { + const APInt *&Res; + apint_match(const APInt *&R) : Res(R) {} + template + bool match(ITy *V) { + if (ConstantInt *CI = dyn_cast(V)) { + Res = &CI->getValue(); + return true; + } + if (ConstantVector *CV = dyn_cast(V)) + if (ConstantInt *CI = + dyn_cast_or_null(CV->getSplatValue())) { + Res = &CI->getValue(); + return true; + } + return false; + } +}; + +/// m_APInt - Match a ConstantInt or splatted ConstantVector, binding the +/// specified pointer to the contained APInt. +inline apint_match m_APInt(const APInt *&Res) { return Res; } + + template -struct constantint_ty { +struct constantint_match { template bool match(ITy *V) { if (const ConstantInt *CI = dyn_cast(V)) { @@ -68,37 +112,82 @@ struct constantint_ty { } }; -/// m_ConstantInt(int64_t) - Match a ConstantInt with a specific value -/// and ignore it. +/// m_ConstantInt - Match a ConstantInt with a specific value. template -inline constantint_ty m_ConstantInt() { - return constantint_ty(); +inline constantint_match m_ConstantInt() { + return constantint_match(); } -struct zero_ty { +/// cst_pred_ty - This helper class is used to match scalar and vector constants +/// that satisfy a specified predicate. +template +struct cst_pred_ty : public Predicate { template bool match(ITy *V) { - if (const Constant *C = dyn_cast(V)) - return C->isNullValue(); + if (const ConstantInt *CI = dyn_cast(V)) + return this->isValue(CI->getValue()); + if (const ConstantVector *CV = dyn_cast(V)) + if (ConstantInt *CI = dyn_cast_or_null(CV->getSplatValue())) + return this->isValue(CI->getValue()); return false; } }; - -/// m_Zero() - Match an arbitrary zero/null constant. -inline zero_ty m_Zero() { return zero_ty(); } - -struct one_ty { + +/// api_pred_ty - This helper class is used to match scalar and vector constants +/// that satisfy a specified predicate, and bind them to an APInt. +template +struct api_pred_ty : public Predicate { + const APInt *&Res; + api_pred_ty(const APInt *&R) : Res(R) {} template bool match(ITy *V) { - if (const ConstantInt *C = dyn_cast(V)) - return C->isOne(); + if (const ConstantInt *CI = dyn_cast(V)) + if (this->isValue(CI->getValue())) { + Res = &CI->getValue(); + return true; + } + if (const ConstantVector *CV = dyn_cast(V)) + if (ConstantInt *CI = dyn_cast_or_null(CV->getSplatValue())) + if (this->isValue(CI->getValue())) { + Res = &CI->getValue(); + return true; + } return false; } }; + + +struct is_one { + bool isValue(const APInt &C) { return C == 1; } +}; -/// m_One() - Match a an integer 1. -inline one_ty m_One() { return one_ty(); } +/// m_One() - Match an integer 1 or a vector with all elements equal to 1. +inline cst_pred_ty m_One() { return cst_pred_ty(); } +inline api_pred_ty m_One(const APInt *&V) { return V; } + +struct is_all_ones { + bool isValue(const APInt &C) { return C.isAllOnesValue(); } +}; +/// m_AllOnes() - Match an integer or vector with all bits set to true. +inline cst_pred_ty m_AllOnes() {return cst_pred_ty();} +inline api_pred_ty m_AllOnes(const APInt *&V) { return V; } + +struct is_sign_bit { + bool isValue(const APInt &C) { return C.isSignBit(); } +}; + +/// m_SignBit() - Match an integer or vector with only the sign bit(s) set. +inline cst_pred_ty m_SignBit() {return cst_pred_ty();} +inline api_pred_ty m_SignBit(const APInt *&V) { return V; } + +struct is_power2 { + bool isValue(const APInt &C) { return C.isPowerOf2(); } +}; + +/// m_Power2() - Match an integer or vector power of 2. +inline cst_pred_ty m_Power2() { return cst_pred_ty(); } +inline api_pred_ty m_Power2(const APInt *&V) { return V; } template struct bind_ty { @@ -121,6 +210,9 @@ inline bind_ty m_Value(Value *&V) { return V; } /// m_ConstantInt - Match a ConstantInt, capturing the value if we match. inline bind_ty m_ConstantInt(ConstantInt *&CI) { return CI; } +/// m_Constant - Match a Constant, capturing the value if we match. +inline bind_ty m_Constant(Constant *&C) { return C; } + /// specificval_ty - Match a specified Value*. struct specificval_ty { const Value *Val; @@ -140,8 +232,7 @@ inline specificval_ty m_Specific(const Value *V) { return V; } // Matchers for specific binary operators. // -template +template struct BinaryOp_match { LHS_t L; RHS_t R; @@ -151,9 +242,8 @@ struct BinaryOp_match { template bool match(OpTy *V) { if (V->getValueID() == Value::InstructionVal + Opcode) { - ConcreteTy *I = cast(V); - return I->getOpcode() == Opcode && L.match(I->getOperand(0)) && - R.match(I->getOperand(1)); + BinaryOperator *I = cast(V); + return L.match(I->getOperand(0)) && R.match(I->getOperand(1)); } if (ConstantExpr *CE = dyn_cast(V)) return CE->getOpcode() == Opcode && L.match(CE->getOperand(0)) && @@ -163,193 +253,156 @@ struct BinaryOp_match { }; template -inline BinaryOp_match m_Add(const LHS &L, - const RHS &R) { +inline BinaryOp_match +m_Add(const LHS &L, const RHS &R) { return BinaryOp_match(L, R); } template -inline BinaryOp_match m_FAdd(const LHS &L, - const RHS &R) { +inline BinaryOp_match +m_FAdd(const LHS &L, const RHS &R) { return BinaryOp_match(L, R); } template -inline BinaryOp_match m_Sub(const LHS &L, - const RHS &R) { +inline BinaryOp_match +m_Sub(const LHS &L, const RHS &R) { return BinaryOp_match(L, R); } template -inline BinaryOp_match m_FSub(const LHS &L, - const RHS &R) { +inline BinaryOp_match +m_FSub(const LHS &L, const RHS &R) { return BinaryOp_match(L, R); } template -inline BinaryOp_match m_Mul(const LHS &L, - const RHS &R) { +inline BinaryOp_match +m_Mul(const LHS &L, const RHS &R) { return BinaryOp_match(L, R); } template -inline BinaryOp_match m_FMul(const LHS &L, - const RHS &R) { +inline BinaryOp_match +m_FMul(const LHS &L, const RHS &R) { return BinaryOp_match(L, R); } template -inline BinaryOp_match m_UDiv(const LHS &L, - const RHS &R) { +inline BinaryOp_match +m_UDiv(const LHS &L, const RHS &R) { return BinaryOp_match(L, R); } template -inline BinaryOp_match m_SDiv(const LHS &L, - const RHS &R) { +inline BinaryOp_match +m_SDiv(const LHS &L, const RHS &R) { return BinaryOp_match(L, R); } template -inline BinaryOp_match m_FDiv(const LHS &L, - const RHS &R) { +inline BinaryOp_match +m_FDiv(const LHS &L, const RHS &R) { return BinaryOp_match(L, R); } template -inline BinaryOp_match m_URem(const LHS &L, - const RHS &R) { +inline BinaryOp_match +m_URem(const LHS &L, const RHS &R) { return BinaryOp_match(L, R); } template -inline BinaryOp_match m_SRem(const LHS &L, - const RHS &R) { +inline BinaryOp_match +m_SRem(const LHS &L, const RHS &R) { return BinaryOp_match(L, R); } template -inline BinaryOp_match m_FRem(const LHS &L, - const RHS &R) { +inline BinaryOp_match +m_FRem(const LHS &L, const RHS &R) { return BinaryOp_match(L, R); } template -inline BinaryOp_match m_And(const LHS &L, - const RHS &R) { +inline BinaryOp_match +m_And(const LHS &L, const RHS &R) { return BinaryOp_match(L, R); } template -inline BinaryOp_match m_Or(const LHS &L, - const RHS &R) { +inline BinaryOp_match +m_Or(const LHS &L, const RHS &R) { return BinaryOp_match(L, R); } template -inline BinaryOp_match m_Xor(const LHS &L, - const RHS &R) { +inline BinaryOp_match +m_Xor(const LHS &L, const RHS &R) { return BinaryOp_match(L, R); } template -inline BinaryOp_match m_Shl(const LHS &L, - const RHS &R) { +inline BinaryOp_match +m_Shl(const LHS &L, const RHS &R) { return BinaryOp_match(L, R); } template -inline BinaryOp_match m_LShr(const LHS &L, - const RHS &R) { +inline BinaryOp_match +m_LShr(const LHS &L, const RHS &R) { return BinaryOp_match(L, R); } template -inline BinaryOp_match m_AShr(const LHS &L, - const RHS &R) { +inline BinaryOp_match +m_AShr(const LHS &L, const RHS &R) { return BinaryOp_match(L, R); } //===----------------------------------------------------------------------===// -// Matchers for either AShr or LShr .. for convenience +// Class that matches two different binary ops. // -template -struct Shr_match { +template +struct BinOp2_match { LHS_t L; RHS_t R; - Shr_match(const LHS_t &LHS, const RHS_t &RHS) : L(LHS), R(RHS) {} + BinOp2_match(const LHS_t &LHS, const RHS_t &RHS) : L(LHS), R(RHS) {} template bool match(OpTy *V) { - if (V->getValueID() == Value::InstructionVal + Instruction::LShr || - V->getValueID() == Value::InstructionVal + Instruction::AShr) { - ConcreteTy *I = cast(V); - return (I->getOpcode() == Instruction::AShr || - I->getOpcode() == Instruction::LShr) && - L.match(I->getOperand(0)) && - R.match(I->getOperand(1)); + if (V->getValueID() == Value::InstructionVal + Opc1 || + V->getValueID() == Value::InstructionVal + Opc2) { + BinaryOperator *I = cast(V); + return L.match(I->getOperand(0)) && R.match(I->getOperand(1)); } if (ConstantExpr *CE = dyn_cast(V)) - return (CE->getOpcode() == Instruction::LShr || - CE->getOpcode() == Instruction::AShr) && - L.match(CE->getOperand(0)) && - R.match(CE->getOperand(1)); + return (CE->getOpcode() == Opc1 || CE->getOpcode() == Opc2) && + L.match(CE->getOperand(0)) && R.match(CE->getOperand(1)); return false; } }; +/// m_Shr - Matches LShr or AShr. template -inline Shr_match m_Shr(const LHS &L, const RHS &R) { - return Shr_match(L, R); +inline BinOp2_match +m_Shr(const LHS &L, const RHS &R) { + return BinOp2_match(L, R); } -//===----------------------------------------------------------------------===// -// Matchers for binary classes -// - -template -struct BinaryOpClass_match { - OpcType *Opcode; - LHS_t L; - RHS_t R; - - BinaryOpClass_match(OpcType &Op, const LHS_t &LHS, - const RHS_t &RHS) - : Opcode(&Op), L(LHS), R(RHS) {} - BinaryOpClass_match(const LHS_t &LHS, const RHS_t &RHS) - : Opcode(0), L(LHS), R(RHS) {} - - template - bool match(OpTy *V) { - if (Class *I = dyn_cast(V)) - if (L.match(I->getOperand(0)) && - R.match(I->getOperand(1))) { - if (Opcode) - *Opcode = I->getOpcode(); - return true; - } -#if 0 // Doesn't handle constantexprs yet! - if (ConstantExpr *CE = dyn_cast(V)) - return CE->getOpcode() == Opcode && L.match(CE->getOperand(0)) && - R.match(CE->getOperand(1)); -#endif - return false; - } -}; - +/// m_LogicalShift - Matches LShr or Shl. template -inline BinaryOpClass_match -m_Shift(Instruction::BinaryOps &Op, const LHS &L, const RHS &R) { - return BinaryOpClass_match(Op, L, R); +inline BinOp2_match +m_LogicalShift(const LHS &L, const RHS &R) { + return BinOp2_match(L, R); } +/// m_IDiv - Matches UDiv and SDiv. template -inline BinaryOpClass_match -m_Shift(const LHS &L, const RHS &R) { - return BinaryOpClass_match(L, R); +inline BinOp2_match +m_IDiv(const LHS &L, const RHS &R) { + return BinOp2_match(L, R); } //===----------------------------------------------------------------------===// @@ -362,15 +415,13 @@ struct CmpClass_match { LHS_t L; RHS_t R; - CmpClass_match(PredicateTy &Pred, const LHS_t &LHS, - const RHS_t &RHS) + CmpClass_match(PredicateTy &Pred, const LHS_t &LHS, const RHS_t &RHS) : Predicate(Pred), L(LHS), R(RHS) {} template bool match(OpTy *V) { if (Class *I = dyn_cast(V)) - if (L.match(I->getOperand(0)) && - R.match(I->getOperand(1))) { + if (L.match(I->getOperand(0)) && R.match(I->getOperand(1))) { Predicate = I->getPredicate(); return true; } @@ -425,11 +476,9 @@ m_Select(const Cond &C, const LHS &L, const RHS &R) { /// m_SelectCst - This matches a select of two constants, e.g.: /// m_SelectCst<-1, 0>(m_Value(V)) template -inline SelectClass_match, constantint_ty > +inline SelectClass_match, constantint_match > m_SelectCst(const Cond &C) { - return SelectClass_match, - constantint_ty >(C, m_ConstantInt(), - m_ConstantInt()); + return m_Select(C, m_ConstantInt(), m_ConstantInt()); } @@ -507,20 +556,14 @@ struct not_match { if (ConstantExpr *CE = dyn_cast(V)) if (CE->getOpcode() == Instruction::Xor) return matchIfNot(CE->getOperand(0), CE->getOperand(1)); - if (ConstantInt *CI = dyn_cast(V)) - return L.match(ConstantExpr::getNot(CI)); return false; } private: bool matchIfNot(Value *LHS, Value *RHS) { if (ConstantInt *CI = dyn_cast(RHS)) return CI->isAllOnesValue() && L.match(LHS); - if (ConstantInt *CI = dyn_cast(LHS)) - return CI->isAllOnesValue() && L.match(RHS); if (ConstantVector *CV = dyn_cast(RHS)) return CV->isAllOnesValue() && L.match(LHS); - if (ConstantVector *CV = dyn_cast(LHS)) - return CV->isAllOnesValue() && L.match(RHS); return false; } }; @@ -543,17 +586,17 @@ struct neg_match { if (ConstantExpr *CE = dyn_cast(V)) if (CE->getOpcode() == Instruction::Sub) return matchIfNeg(CE->getOperand(0), CE->getOperand(1)); - if (ConstantInt *CI = dyn_cast(V)) - return L.match(ConstantExpr::getNeg(CI)); return false; } private: bool matchIfNeg(Value *LHS, Value *RHS) { - return LHS == ConstantFP::getZeroValueForNegation(LHS->getType()) && - L.match(RHS); + if (ConstantInt *C = dyn_cast(LHS)) + return C->isZero() && L.match(RHS); + return false; } }; +/// m_Neg - Match an integer negate. template inline neg_match m_Neg(const LHS &L) { return L; } @@ -572,23 +615,23 @@ struct fneg_match { if (ConstantExpr *CE = dyn_cast(V)) if (CE->getOpcode() == Instruction::FSub) return matchIfFNeg(CE->getOperand(0), CE->getOperand(1)); - if (ConstantFP *CF = dyn_cast(V)) - return L.match(ConstantExpr::getFNeg(CF)); return false; } private: bool matchIfFNeg(Value *LHS, Value *RHS) { - return LHS == ConstantFP::getZeroValueForNegation(LHS->getType()) && - L.match(RHS); + if (ConstantFP *C = dyn_cast(LHS)) + return C->isNegativeZeroValue() && L.match(RHS); + return false; } }; +/// m_FNeg - Match a floating point negate. template inline fneg_match m_FNeg(const LHS &L) { return L; } //===----------------------------------------------------------------------===// -// Matchers for control flow +// Matchers for control flow. // template @@ -602,12 +645,10 @@ struct brc_match { template bool match(OpTy *V) { if (BranchInst *BI = dyn_cast(V)) - if (BI->isConditional()) { - if (Cond.match(BI->getCondition())) { - T = BI->getSuccessor(0); - F = BI->getSuccessor(1); - return true; - } + if (BI->isConditional() && Cond.match(BI->getCondition())) { + T = BI->getSuccessor(0); + F = BI->getSuccessor(1); + return true; } return false; } diff --git a/include/llvm/Support/PointerLikeTypeTraits.h b/include/llvm/Support/PointerLikeTypeTraits.h index b85140480064..837082139214 100644 --- a/include/llvm/Support/PointerLikeTypeTraits.h +++ b/include/llvm/Support/PointerLikeTypeTraits.h @@ -15,7 +15,7 @@ #ifndef LLVM_SUPPORT_POINTERLIKETYPETRAITS_H #define LLVM_SUPPORT_POINTERLIKETYPETRAITS_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { diff --git a/include/llvm/Support/Process.h b/include/llvm/Support/Process.h new file mode 100644 index 000000000000..33799229ff35 --- /dev/null +++ b/include/llvm/Support/Process.h @@ -0,0 +1,146 @@ +//===- llvm/Support/Process.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the llvm::sys::Process class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_PROCESS_H +#define LLVM_SYSTEM_PROCESS_H + +#include "llvm/Support/TimeValue.h" + +namespace llvm { +namespace sys { + + /// This class provides an abstraction for getting information about the + /// currently executing process. + /// @since 1.4 + /// @brief An abstraction for operating system processes. + class Process { + /// @name Accessors + /// @{ + public: + /// This static function will return the operating system's virtual memory + /// page size. + /// @returns The number of bytes in a virtual memory page. + /// @brief Get the virtual memory page size + static unsigned GetPageSize(); + + /// This static function will return the total amount of memory allocated + /// by the process. This only counts the memory allocated via the malloc, + /// calloc and realloc functions and includes any "free" holes in the + /// allocated space. + /// @brief Return process memory usage. + static size_t GetMallocUsage(); + + /// This static function will return the total memory usage of the + /// process. This includes code, data, stack and mapped pages usage. Notei + /// that the value returned here is not necessarily the Running Set Size, + /// it is the total virtual memory usage, regardless of mapped state of + /// that memory. + static size_t GetTotalMemoryUsage(); + + /// This static function will set \p user_time to the amount of CPU time + /// spent in user (non-kernel) mode and \p sys_time to the amount of CPU + /// time spent in system (kernel) mode. If the operating system does not + /// support collection of these metrics, a zero TimeValue will be for both + /// values. + static void GetTimeUsage( + TimeValue& elapsed, + ///< Returns the TimeValue::now() giving current time + TimeValue& user_time, + ///< Returns the current amount of user time for the process + TimeValue& sys_time + ///< Returns the current amount of system time for the process + ); + + /// This static function will return the process' current user id number. + /// Not all operating systems support this feature. Where it is not + /// supported, the function should return 65536 as the value. + static int GetCurrentUserId(); + + /// This static function will return the process' current group id number. + /// Not all operating systems support this feature. Where it is not + /// supported, the function should return 65536 as the value. + static int GetCurrentGroupId(); + + /// This function makes the necessary calls to the operating system to + /// prevent core files or any other kind of large memory dumps that can + /// occur when a program fails. + /// @brief Prevent core file generation. + static void PreventCoreFiles(); + + /// This function determines if the standard input is connected directly + /// to a user's input (keyboard probably), rather than coming from a file + /// or pipe. + static bool StandardInIsUserInput(); + + /// This function determines if the standard output is connected to a + /// "tty" or "console" window. That is, the output would be displayed to + /// the user rather than being put on a pipe or stored in a file. + static bool StandardOutIsDisplayed(); + + /// This function determines if the standard error is connected to a + /// "tty" or "console" window. That is, the output would be displayed to + /// the user rather than being put on a pipe or stored in a file. + static bool StandardErrIsDisplayed(); + + /// This function determines if the given file descriptor is connected to + /// a "tty" or "console" window. That is, the output would be displayed to + /// the user rather than being put on a pipe or stored in a file. + static bool FileDescriptorIsDisplayed(int fd); + + /// This function determines the number of columns in the window + /// if standard output is connected to a "tty" or "console" + /// window. If standard output is not connected to a tty or + /// console, or if the number of columns cannot be determined, + /// this routine returns zero. + static unsigned StandardOutColumns(); + + /// This function determines the number of columns in the window + /// if standard error is connected to a "tty" or "console" + /// window. If standard error is not connected to a tty or + /// console, or if the number of columns cannot be determined, + /// this routine returns zero. + static unsigned StandardErrColumns(); + + /// This function determines whether the terminal connected to standard + /// output supports colors. If standard output is not connected to a + /// terminal, this function returns false. + static bool StandardOutHasColors(); + + /// This function determines whether the terminal connected to standard + /// error supports colors. If standard error is not connected to a + /// terminal, this function returns false. + static bool StandardErrHasColors(); + + /// Whether changing colors requires the output to be flushed. + /// This is needed on systems that don't support escape sequences for + /// changing colors. + static bool ColorNeedsFlush(); + + /// This function returns the colorcode escape sequences. + /// If ColorNeedsFlush() is true then this function will change the colors + /// and return an empty escape sequence. In that case it is the + /// responsibility of the client to flush the output stream prior to + /// calling this function. + static const char *OutputColor(char c, bool bold, bool bg); + + /// Same as OutputColor, but only enables the bold attribute. + static const char *OutputBold(bool bg); + + /// Resets the terminals colors, or returns an escape sequence to do so. + static const char *ResetColor(); + /// @} + }; +} +} + +#endif diff --git a/include/llvm/Support/Program.h b/include/llvm/Support/Program.h new file mode 100644 index 000000000000..78a495ef2105 --- /dev/null +++ b/include/llvm/Support/Program.h @@ -0,0 +1,157 @@ +//===- llvm/Support/Program.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the llvm::sys::Program class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_PROGRAM_H +#define LLVM_SYSTEM_PROGRAM_H + +#include "llvm/Support/Path.h" + +namespace llvm { +namespace sys { + + // TODO: Add operations to communicate with the process, redirect its I/O, + // etc. + + /// This class provides an abstraction for programs that are executable by the + /// operating system. It provides a platform generic way to find executable + /// programs from the path and to execute them in various ways. The sys::Path + /// class is used to specify the location of the Program. + /// @since 1.4 + /// @brief An abstraction for finding and executing programs. + class Program { + /// Opaque handle for target specific data. + void *Data_; + + // Noncopyable. + Program(const Program& other); + Program& operator=(const Program& other); + + /// @name Methods + /// @{ + public: + + Program(); + ~Program(); + + /// Return process ID of this program. + unsigned GetPid() const; + + /// This function executes the program using the \p arguments provided. The + /// invoked program will inherit the stdin, stdout, and stderr file + /// descriptors, the environment and other configuration settings of the + /// invoking program. If Path::executable() does not return true when this + /// function is called then a std::string is thrown. + /// @returns false in case of error, true otherwise. + /// @see FindProgramByName + /// @brief Executes the program with the given set of \p args. + bool Execute + ( const Path& path, ///< sys::Path object providing the path of the + ///< program to be executed. It is presumed this is the result of + ///< the FindProgramByName method. + const char** args, ///< A vector of strings that are passed to the + ///< program. The first element should be the name of the program. + ///< The list *must* be terminated by a null char* entry. + const char ** env = 0, ///< An optional vector of strings to use for + ///< the program's environment. If not provided, the current program's + ///< environment will be used. + const sys::Path** redirects = 0, ///< An optional array of pointers to + ///< Paths. If the array is null, no redirection is done. The array + ///< should have a size of at least three. If the pointer in the array + ///< are not null, then the inferior process's stdin(0), stdout(1), + ///< and stderr(2) will be redirected to the corresponding Paths. + ///< When an empty Path is passed in, the corresponding file + ///< descriptor will be disconnected (ie, /dev/null'd) in a portable + ///< way. + unsigned memoryLimit = 0, ///< If non-zero, this specifies max. amount + ///< of memory can be allocated by process. If memory usage will be + ///< higher limit, the child is killed and this call returns. If zero + ///< - no memory limit. + std::string* ErrMsg = 0 ///< If non-zero, provides a pointer to a string + ///< instance in which error messages will be returned. If the string + ///< is non-empty upon return an error occurred while invoking the + ///< program. + ); + + /// This function waits for the program to exit. This function will block + /// the current program until the invoked program exits. + /// @returns an integer result code indicating the status of the program. + /// A zero or positive value indicates the result code of the program. A + /// negative value is the signal number on which it terminated. + /// @see Execute + /// @brief Waits for the program to exit. + int Wait + ( const Path& path, ///< The path to the child process executable. + unsigned secondsToWait, ///< If non-zero, this specifies the amount + ///< of time to wait for the child process to exit. If the time + ///< expires, the child is killed and this call returns. If zero, + ///< this function will wait until the child finishes or forever if + ///< it doesn't. + std::string* ErrMsg ///< If non-zero, provides a pointer to a string + ///< instance in which error messages will be returned. If the string + ///< is non-empty upon return an error occurred while waiting. + ); + + /// This function terminates the program. + /// @returns true if an error occured. + /// @see Execute + /// @brief Terminates the program. + bool Kill + ( std::string* ErrMsg = 0 ///< If non-zero, provides a pointer to a string + ///< instance in which error messages will be returned. If the string + ///< is non-empty upon return an error occurred while killing the + ///< program. + ); + + /// This static constructor (factory) will attempt to locate a program in + /// the operating system's file system using some pre-determined set of + /// locations to search (e.g. the PATH on Unix). Paths with slashes are + /// returned unmodified. + /// @returns A Path object initialized to the path of the program or a + /// Path object that is empty (invalid) if the program could not be found. + /// @brief Construct a Program by finding it by name. + static Path FindProgramByName(const std::string& name); + + // These methods change the specified standard stream (stdin, + // stdout, or stderr) to binary mode. They return true if an error + // occurred + static bool ChangeStdinToBinary(); + static bool ChangeStdoutToBinary(); + static bool ChangeStderrToBinary(); + + /// A convenience function equivalent to Program prg; prg.Execute(..); + /// prg.Wait(..); + /// @see Execute, Wait + static int ExecuteAndWait(const Path& path, + const char** args, + const char ** env = 0, + const sys::Path** redirects = 0, + unsigned secondsToWait = 0, + unsigned memoryLimit = 0, + std::string* ErrMsg = 0); + + /// A convenience function equivalent to Program prg; prg.Execute(..); + /// @see Execute + static void ExecuteNoWait(const Path& path, + const char** args, + const char ** env = 0, + const sys::Path** redirects = 0, + unsigned memoryLimit = 0, + std::string* ErrMsg = 0); + + /// @} + + }; +} +} + +#endif diff --git a/include/llvm/Support/RWMutex.h b/include/llvm/Support/RWMutex.h new file mode 100644 index 000000000000..0d4cb81de397 --- /dev/null +++ b/include/llvm/Support/RWMutex.h @@ -0,0 +1,173 @@ +//===- RWMutex.h - Reader/Writer Mutual Exclusion Lock ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the llvm::sys::RWMutex class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_RWMUTEX_H +#define LLVM_SYSTEM_RWMUTEX_H + +#include "llvm/Support/Threading.h" +#include + +namespace llvm +{ + namespace sys + { + /// @brief Platform agnostic RWMutex class. + class RWMutexImpl + { + /// @name Constructors + /// @{ + public: + + /// Initializes the lock but doesn't acquire it. + /// @brief Default Constructor. + explicit RWMutexImpl(); + + /// Releases and removes the lock + /// @brief Destructor + ~RWMutexImpl(); + + /// @} + /// @name Methods + /// @{ + public: + + /// Attempts to unconditionally acquire the lock in reader mode. If the + /// lock is held by a writer, this method will wait until it can acquire + /// the lock. + /// @returns false if any kind of error occurs, true otherwise. + /// @brief Unconditionally acquire the lock in reader mode. + bool reader_acquire(); + + /// Attempts to release the lock in reader mode. + /// @returns false if any kind of error occurs, true otherwise. + /// @brief Unconditionally release the lock in reader mode. + bool reader_release(); + + /// Attempts to unconditionally acquire the lock in reader mode. If the + /// lock is held by any readers, this method will wait until it can + /// acquire the lock. + /// @returns false if any kind of error occurs, true otherwise. + /// @brief Unconditionally acquire the lock in writer mode. + bool writer_acquire(); + + /// Attempts to release the lock in writer mode. + /// @returns false if any kind of error occurs, true otherwise. + /// @brief Unconditionally release the lock in write mode. + bool writer_release(); + + //@} + /// @name Platform Dependent Data + /// @{ + private: + void* data_; ///< We don't know what the data will be + + /// @} + /// @name Do Not Implement + /// @{ + private: + RWMutexImpl(const RWMutexImpl & original); + void operator=(const RWMutexImpl &); + /// @} + }; + + /// SmartMutex - An R/W mutex with a compile time constant parameter that + /// indicates whether this mutex should become a no-op when we're not + /// running in multithreaded mode. + template + class SmartRWMutex : public RWMutexImpl { + unsigned readers, writers; + public: + explicit SmartRWMutex() : RWMutexImpl(), readers(0), writers(0) { } + + bool reader_acquire() { + if (!mt_only || llvm_is_multithreaded()) + return RWMutexImpl::reader_acquire(); + + // Single-threaded debugging code. This would be racy in multithreaded + // mode, but provides not sanity checks in single threaded mode. + ++readers; + return true; + } + + bool reader_release() { + if (!mt_only || llvm_is_multithreaded()) + return RWMutexImpl::reader_release(); + + // Single-threaded debugging code. This would be racy in multithreaded + // mode, but provides not sanity checks in single threaded mode. + assert(readers > 0 && "Reader lock not acquired before release!"); + --readers; + return true; + } + + bool writer_acquire() { + if (!mt_only || llvm_is_multithreaded()) + return RWMutexImpl::writer_acquire(); + + // Single-threaded debugging code. This would be racy in multithreaded + // mode, but provides not sanity checks in single threaded mode. + assert(writers == 0 && "Writer lock already acquired!"); + ++writers; + return true; + } + + bool writer_release() { + if (!mt_only || llvm_is_multithreaded()) + return RWMutexImpl::writer_release(); + + // Single-threaded debugging code. This would be racy in multithreaded + // mode, but provides not sanity checks in single threaded mode. + assert(writers == 1 && "Writer lock not acquired before release!"); + --writers; + return true; + } + + private: + SmartRWMutex(const SmartRWMutex & original); + void operator=(const SmartRWMutex &); + }; + typedef SmartRWMutex RWMutex; + + /// ScopedReader - RAII acquisition of a reader lock + template + struct SmartScopedReader { + SmartRWMutex& mutex; + + explicit SmartScopedReader(SmartRWMutex& m) : mutex(m) { + mutex.reader_acquire(); + } + + ~SmartScopedReader() { + mutex.reader_release(); + } + }; + typedef SmartScopedReader ScopedReader; + + /// ScopedWriter - RAII acquisition of a writer lock + template + struct SmartScopedWriter { + SmartRWMutex& mutex; + + explicit SmartScopedWriter(SmartRWMutex& m) : mutex(m) { + mutex.writer_acquire(); + } + + ~SmartScopedWriter() { + mutex.writer_release(); + } + }; + typedef SmartScopedWriter ScopedWriter; + } +} + +#endif diff --git a/include/llvm/Support/Signals.h b/include/llvm/Support/Signals.h new file mode 100644 index 000000000000..9a84df68ddba --- /dev/null +++ b/include/llvm/Support/Signals.h @@ -0,0 +1,59 @@ +//===- llvm/Support/Signals.h - Signal Handling support ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines some helpful functions for dealing with the possibility of +// unix signals occuring while your program is running. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_SIGNALS_H +#define LLVM_SYSTEM_SIGNALS_H + +#include "llvm/Support/Path.h" + +namespace llvm { +namespace sys { + + /// This function runs all the registered interrupt handlers, including the + /// removal of files registered by RemoveFileOnSignal. + void RunInterruptHandlers(); + + /// This function registers signal handlers to ensure that if a signal gets + /// delivered that the named file is removed. + /// @brief Remove a file if a fatal signal occurs. + bool RemoveFileOnSignal(const Path &Filename, std::string* ErrMsg = 0); + + /// This function removes a file from the list of files to be removed on + /// signal delivery. + void DontRemoveFileOnSignal(const Path &Filename); + + /// When an error signal (such as SIBABRT or SIGSEGV) is delivered to the + /// process, print a stack trace and then exit. + /// @brief Print a stack trace if a fatal signal occurs. + void PrintStackTraceOnErrorSignal(); + + /// AddSignalHandler - Add a function to be called when an abort/kill signal + /// is delivered to the process. The handler can have a cookie passed to it + /// to identify what instance of the handler it is. + void AddSignalHandler(void (*FnPtr)(void *), void *Cookie); + + /// This function registers a function to be called when the user "interrupts" + /// the program (typically by pressing ctrl-c). When the user interrupts the + /// program, the specified interrupt function is called instead of the program + /// being killed, and the interrupt function automatically disabled. Note + /// that interrupt functions are not allowed to call any non-reentrant + /// functions. An null interrupt function pointer disables the current + /// installed function. Note also that the handler may be executed on a + /// different thread on some platforms. + /// @brief Register a function to be called when ctrl-c is pressed. + void SetInterruptFunction(void (*IF)()); +} // End sys namespace +} // End llvm namespace + +#endif diff --git a/include/llvm/Support/Solaris.h b/include/llvm/Support/Solaris.h new file mode 100644 index 000000000000..57eee2cb4973 --- /dev/null +++ b/include/llvm/Support/Solaris.h @@ -0,0 +1,40 @@ +/*===- llvm/Support/Solaris.h ------------------------------------*- C++ -*-===* + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + *===----------------------------------------------------------------------===* + * + * This file contains portability fixes for Solaris hosts. + * + *===----------------------------------------------------------------------===*/ + +#ifndef LLVM_SYSTEM_SOLARIS_H +#define LLVM_SYSTEM_SOLARIS_H + +#include +#include + +#undef CS +#undef DS +#undef ES +#undef FS +#undef GS +#undef SS +#undef EAX +#undef ECX +#undef EDX +#undef EBX +#undef ESP +#undef EBP +#undef ESI +#undef EDI +#undef EIP +#undef UESP +#undef EFL +#undef ERR +#undef TRAPNO + +#endif diff --git a/include/llvm/Support/SourceMgr.h b/include/llvm/Support/SourceMgr.h index 270ab2b2f85c..a41a633ba6b6 100644 --- a/include/llvm/Support/SourceMgr.h +++ b/include/llvm/Support/SourceMgr.h @@ -26,6 +26,7 @@ namespace llvm { class MemoryBuffer; class SourceMgr; class SMDiagnostic; + class Twine; class raw_ostream; /// SourceMgr - This owns the files read by a parser, handles include stacks, @@ -35,8 +36,7 @@ public: /// DiagHandlerTy - Clients that want to handle their own diagnostics in a /// custom way can register a function pointer+context as a diagnostic /// handler. It gets called each time PrintMessage is invoked. - typedef void (*DiagHandlerTy)(const SMDiagnostic&, void *Context, - unsigned LocCookie); + typedef void (*DiagHandlerTy)(const SMDiagnostic&, void *Context); private: struct SrcBuffer { /// Buffer - The memory buffer for the file. @@ -60,7 +60,6 @@ private: DiagHandlerTy DiagHandler; void *DiagContext; - unsigned DiagLocCookie; SourceMgr(const SourceMgr&); // DO NOT IMPLEMENT void operator=(const SourceMgr&); // DO NOT IMPLEMENT @@ -73,12 +72,10 @@ public: } /// setDiagHandler - Specify a diagnostic handler to be invoked every time - /// PrintMessage is called. Ctx and Cookie are passed into the handler when - /// it is invoked. - void setDiagHandler(DiagHandlerTy DH, void *Ctx = 0, unsigned Cookie = 0) { + /// PrintMessage is called. Ctx is passed into the handler when it is invoked. + void setDiagHandler(DiagHandlerTy DH, void *Ctx = 0) { DiagHandler = DH; DiagContext = Ctx; - DiagLocCookie = Cookie; } const SrcBuffer &getBufferInfo(unsigned i) const { @@ -125,7 +122,7 @@ public: /// @param Type - If non-null, the kind of message (e.g., "error") which is /// prefixed to the message. /// @param ShowLine - Should the diagnostic show the source line. - void PrintMessage(SMLoc Loc, const std::string &Msg, const char *Type, + void PrintMessage(SMLoc Loc, const Twine &Msg, const char *Type, bool ShowLine = true) const; @@ -136,7 +133,7 @@ public: /// prefixed to the message. /// @param ShowLine - Should the diagnostic show the source line. SMDiagnostic GetMessage(SMLoc Loc, - const std::string &Msg, const char *Type, + const Twine &Msg, const char *Type, bool ShowLine = true) const; diff --git a/include/llvm/Support/StableBasicBlockNumbering.h b/include/llvm/Support/StableBasicBlockNumbering.h deleted file mode 100644 index 5e0f87e48950..000000000000 --- a/include/llvm/Support/StableBasicBlockNumbering.h +++ /dev/null @@ -1,59 +0,0 @@ -//===- StableBasicBlockNumbering.h - Provide BB identifiers -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This class provides a *stable* numbering of basic blocks that does not depend -// on their address in memory (which is nondeterministic). When requested, this -// class simply provides a unique ID for each basic block in the function -// specified and the inverse mapping. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SUPPORT_STABLEBASICBLOCKNUMBERING_H -#define LLVM_SUPPORT_STABLEBASICBLOCKNUMBERING_H - -#include "llvm/Function.h" -#include "llvm/ADT/UniqueVector.h" - -namespace llvm { - class StableBasicBlockNumbering { - // BBNumbering - Holds the numbering. - UniqueVector BBNumbering; - public: - StableBasicBlockNumbering(Function *F = 0) { - if (F) compute(*F); - } - - /// compute - If we have not computed a numbering for the function yet, do - /// so. - void compute(Function &F) { - if (BBNumbering.empty()) { - for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I) - BBNumbering.insert(I); - } - } - - /// getNumber - Return the ID number for the specified BasicBlock. - /// - unsigned getNumber(BasicBlock *BB) const { - unsigned Idx = BBNumbering.idFor(BB); - assert(Idx && "Invalid basic block or numbering not computed!"); - return Idx-1; - } - - /// getBlock - Return the BasicBlock corresponding to a particular ID. - /// - BasicBlock *getBlock(unsigned N) const { - assert(N < BBNumbering.size() && - "Block ID out of range or numbering not computed!"); - return BBNumbering[N+1]; - } - }; -} - -#endif diff --git a/include/llvm/Support/StandardPasses.h b/include/llvm/Support/StandardPasses.h index bb3bddd3c799..d774faf38642 100644 --- a/include/llvm/Support/StandardPasses.h +++ b/include/llvm/Support/StandardPasses.h @@ -20,20 +20,35 @@ #define LLVM_SUPPORT_STANDARDPASSES_H #include "llvm/PassManager.h" -#include "llvm/Analysis/Dominators.h" #include "llvm/Analysis/Passes.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/IPO.h" namespace llvm { + + static inline void createStandardAliasAnalysisPasses(PassManagerBase *PM) { + // Add TypeBasedAliasAnalysis before BasicAliasAnalysis so that + // BasicAliasAnalysis wins if they disagree. This is intended to help + // support "obvious" type-punning idioms. + PM->add(createTypeBasedAliasAnalysisPass()); + PM->add(createBasicAliasAnalysisPass()); + } + /// createStandardFunctionPasses - Add the standard list of function passes to /// the provided pass manager. /// /// \arg OptimizationLevel - The optimization level, corresponding to -O0, /// -O1, etc. static inline void createStandardFunctionPasses(PassManagerBase *PM, - unsigned OptimizationLevel); + unsigned OptimizationLevel) { + if (OptimizationLevel > 0) { + createStandardAliasAnalysisPasses(PM); + PM->add(createCFGSimplificationPass()); + PM->add(createScalarReplAggregatesPass()); + PM->add(createEarlyCSEPass()); + } + } /// createStandardModulePasses - Add the standard list of module passes to the /// provided pass manager. @@ -47,42 +62,6 @@ namespace llvm { /// \arg HaveExceptions - Whether the module may have code using exceptions. /// \arg InliningPass - The inlining pass to use, if any, or null. This will /// always be added, even at -O0.a - static inline void createStandardModulePasses(PassManagerBase *PM, - unsigned OptimizationLevel, - bool OptimizeSize, - bool UnitAtATime, - bool UnrollLoops, - bool SimplifyLibCalls, - bool HaveExceptions, - Pass *InliningPass); - - /// createStandardLTOPasses - Add the standard list of module passes suitable - /// for link time optimization. - /// - /// Internalize - Run the internalize pass. - /// RunInliner - Use a function inlining pass. - /// VerifyEach - Run the verifier after each pass. - static inline void createStandardLTOPasses(PassManagerBase *PM, - bool Internalize, - bool RunInliner, - bool VerifyEach); - - // Implementations - - static inline void createStandardFunctionPasses(PassManagerBase *PM, - unsigned OptimizationLevel) { - if (OptimizationLevel > 0) { - PM->add(createCFGSimplificationPass()); - if (OptimizationLevel == 1) - PM->add(createPromoteMemoryToRegisterPass()); - else - PM->add(createScalarReplAggregatesPass()); - PM->add(createInstructionCombiningPass()); - } - } - - /// createStandardModulePasses - Add the standard module passes. This is - /// expected to be run after the standard function passes. static inline void createStandardModulePasses(PassManagerBase *PM, unsigned OptimizationLevel, bool OptimizeSize, @@ -91,6 +70,8 @@ namespace llvm { bool SimplifyLibCalls, bool HaveExceptions, Pass *InliningPass) { + createStandardAliasAnalysisPasses(PM); + if (OptimizationLevel == 0) { if (InliningPass) PM->add(InliningPass); @@ -108,7 +89,7 @@ namespace llvm { // Start of CallGraph SCC passes. if (UnitAtATime && HaveExceptions) - PM->add(createPruneEHPass()); // Remove dead EH info + PM->add(createPruneEHPass()); // Remove dead EH info if (InliningPass) PM->add(InliningPass); if (UnitAtATime) @@ -117,11 +98,13 @@ namespace llvm { PM->add(createArgumentPromotionPass()); // Scalarize uninlined fn args // Start of function pass. - PM->add(createScalarReplAggregatesPass()); // Break up aggregate allocas + // Break up aggregate allocas, using SSAUpdater. + PM->add(createScalarReplAggregatesPass(-1, false)); + PM->add(createEarlyCSEPass()); // Catch trivial redundancies if (SimplifyLibCalls) PM->add(createSimplifyLibCallsPass()); // Library Call Optimizations - PM->add(createInstructionCombiningPass()); // Cleanup for scalarrepl. PM->add(createJumpThreadingPass()); // Thread jumps. + PM->add(createCorrelatedValuePropagationPass()); // Propagate conditionals PM->add(createCFGSimplificationPass()); // Merge & remove BBs PM->add(createInstructionCombiningPass()); // Combine silly seq's @@ -133,6 +116,7 @@ namespace llvm { PM->add(createLoopUnswitchPass(OptimizeSize || OptimizationLevel < 3)); PM->add(createInstructionCombiningPass()); PM->add(createIndVarSimplifyPass()); // Canonicalize indvars + PM->add(createLoopIdiomPass()); // Recognize idioms like memset. PM->add(createLoopDeletionPass()); // Delete dead loops if (UnrollLoops) PM->add(createLoopUnrollPass()); // Unroll small loops @@ -172,10 +156,19 @@ namespace llvm { PM->add(createVerifierPass()); } + /// createStandardLTOPasses - Add the standard list of module passes suitable + /// for link time optimization. + /// + /// Internalize - Run the internalize pass. + /// RunInliner - Use a function inlining pass. + /// VerifyEach - Run the verifier after each pass. static inline void createStandardLTOPasses(PassManagerBase *PM, bool Internalize, bool RunInliner, bool VerifyEach) { + // Provide AliasAnalysis services for optimizations. + createStandardAliasAnalysisPasses(PM); + // Now that composite has been compiled, scan through the module, looking // for a main function. If main is defined, mark all other functions // internal. diff --git a/include/llvm/Support/SwapByteOrder.h b/include/llvm/Support/SwapByteOrder.h new file mode 100644 index 000000000000..6c0592c05ad7 --- /dev/null +++ b/include/llvm/Support/SwapByteOrder.h @@ -0,0 +1,101 @@ +//===- SwapByteOrder.h - Generic and optimized byte swaps -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares generic and optimized functions to swap the byte order of +// an integral type. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_SWAP_BYTE_ORDER_H +#define LLVM_SYSTEM_SWAP_BYTE_ORDER_H + +#include "llvm/Support/DataTypes.h" +#include +#include + +namespace llvm { +namespace sys { + +/// SwapByteOrder_16 - This function returns a byte-swapped representation of +/// the 16-bit argument. +inline uint16_t SwapByteOrder_16(uint16_t value) { +#if defined(_MSC_VER) && !defined(_DEBUG) + // The DLL version of the runtime lacks these functions (bug!?), but in a + // release build they're replaced with BSWAP instructions anyway. + return _byteswap_ushort(value); +#else + uint16_t Hi = value << 8; + uint16_t Lo = value >> 8; + return Hi | Lo; +#endif +} + +/// SwapByteOrder_32 - This function returns a byte-swapped representation of +/// the 32-bit argument. +inline uint32_t SwapByteOrder_32(uint32_t value) { +#if defined(__llvm__) || \ +(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && !defined(__ICC) + return __builtin_bswap32(value); +#elif defined(_MSC_VER) && !defined(_DEBUG) + return _byteswap_ulong(value); +#else + uint32_t Byte0 = value & 0x000000FF; + uint32_t Byte1 = value & 0x0000FF00; + uint32_t Byte2 = value & 0x00FF0000; + uint32_t Byte3 = value & 0xFF000000; + return (Byte0 << 24) | (Byte1 << 8) | (Byte2 >> 8) | (Byte3 >> 24); +#endif +} + +/// SwapByteOrder_64 - This function returns a byte-swapped representation of +/// the 64-bit argument. +inline uint64_t SwapByteOrder_64(uint64_t value) { +#if defined(__llvm__) || \ +(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && !defined(__ICC) + return __builtin_bswap64(value); +#elif defined(_MSC_VER) && !defined(_DEBUG) + return _byteswap_uint64(value); +#else + uint64_t Hi = SwapByteOrder_32(uint32_t(value)); + uint32_t Lo = SwapByteOrder_32(uint32_t(value >> 32)); + return (Hi << 32) | Lo; +#endif +} + +inline unsigned char SwapByteOrder(unsigned char C) { return C; } +inline signed char SwapByteOrder(signed char C) { return C; } +inline char SwapByteOrder(char C) { return C; } + +inline unsigned short SwapByteOrder(unsigned short C) { return SwapByteOrder_16(C); } +inline signed short SwapByteOrder( signed short C) { return SwapByteOrder_16(C); } + +inline unsigned int SwapByteOrder(unsigned int C) { return SwapByteOrder_32(C); } +inline signed int SwapByteOrder( signed int C) { return SwapByteOrder_32(C); } + +#if __LONG_MAX__ == __INT_MAX__ +inline unsigned long SwapByteOrder(unsigned long C) { return SwapByteOrder_32(C); } +inline signed long SwapByteOrder( signed long C) { return SwapByteOrder_32(C); } +#elif __LONG_MAX__ == __LONG_LONG_MAX__ +inline unsigned long SwapByteOrder(unsigned long C) { return SwapByteOrder_64(C); } +inline signed long SwapByteOrder( signed long C) { return SwapByteOrder_64(C); } +#else +#error "Unknown long size!" +#endif + +inline unsigned long long SwapByteOrder(unsigned long long C) { + return SwapByteOrder_64(C); +} +inline signed long long SwapByteOrder(signed long long C) { + return SwapByteOrder_64(C); +} + +} // end namespace sys +} // end namespace llvm + +#endif diff --git a/include/llvm/Support/SystemUtils.h b/include/llvm/Support/SystemUtils.h index 3c182c1ca8b0..399aee51eb7b 100644 --- a/include/llvm/Support/SystemUtils.h +++ b/include/llvm/Support/SystemUtils.h @@ -30,13 +30,14 @@ bool CheckBitcodeOutputToConsole( bool print_warning = true ///< Control whether warnings are printed ); -/// FindExecutable - Find a named executable, giving the argv[0] of program -/// being executed. This allows us to find another LLVM tool if it is built in -/// the same directory. If the executable cannot be found, return an -/// empty string. +/// PrependMainExecutablePath - Prepend the path to the program being executed +/// to \p ExeName, given the value of argv[0] and the address of main() +/// itself. This allows us to find another LLVM tool if it is built in the same +/// directory. An empty string is returned on error; note that this function +/// just mainpulates the path and doesn't check for executability. /// @brief Find a named executable. -sys::Path FindExecutable(const std::string &ExeName, - const char *Argv0, void *MainAddr); +sys::Path PrependMainExecutablePath(const std::string &ExeName, + const char *Argv0, void *MainAddr); } // End llvm namespace diff --git a/include/llvm/Support/TargetFolder.h b/include/llvm/Support/TargetFolder.h index d34f35fe0d2b..20ca5571ffa3 100644 --- a/include/llvm/Support/TargetFolder.h +++ b/include/llvm/Support/TargetFolder.h @@ -46,50 +46,32 @@ public: // Binary Operators //===--------------------------------------------------------------------===// - Constant *CreateAdd(Constant *LHS, Constant *RHS) const { - return Fold(ConstantExpr::getAdd(LHS, RHS)); - } - Constant *CreateNSWAdd(Constant *LHS, Constant *RHS) const { - return Fold(ConstantExpr::getNSWAdd(LHS, RHS)); - } - Constant *CreateNUWAdd(Constant *LHS, Constant *RHS) const { - return Fold(ConstantExpr::getNUWAdd(LHS, RHS)); + Constant *CreateAdd(Constant *LHS, Constant *RHS, + bool HasNUW = false, bool HasNSW = false) const { + return Fold(ConstantExpr::getAdd(LHS, RHS, HasNUW, HasNSW)); } Constant *CreateFAdd(Constant *LHS, Constant *RHS) const { return Fold(ConstantExpr::getFAdd(LHS, RHS)); } - Constant *CreateSub(Constant *LHS, Constant *RHS) const { - return Fold(ConstantExpr::getSub(LHS, RHS)); - } - Constant *CreateNSWSub(Constant *LHS, Constant *RHS) const { - return Fold(ConstantExpr::getNSWSub(LHS, RHS)); - } - Constant *CreateNUWSub(Constant *LHS, Constant *RHS) const { - return Fold(ConstantExpr::getNUWSub(LHS, RHS)); + Constant *CreateSub(Constant *LHS, Constant *RHS, + bool HasNUW = false, bool HasNSW = false) const { + return Fold(ConstantExpr::getSub(LHS, RHS, HasNUW, HasNSW)); } Constant *CreateFSub(Constant *LHS, Constant *RHS) const { return Fold(ConstantExpr::getFSub(LHS, RHS)); } - Constant *CreateMul(Constant *LHS, Constant *RHS) const { - return Fold(ConstantExpr::getMul(LHS, RHS)); - } - Constant *CreateNSWMul(Constant *LHS, Constant *RHS) const { - return Fold(ConstantExpr::getNSWMul(LHS, RHS)); - } - Constant *CreateNUWMul(Constant *LHS, Constant *RHS) const { - return Fold(ConstantExpr::getNUWMul(LHS, RHS)); + Constant *CreateMul(Constant *LHS, Constant *RHS, + bool HasNUW = false, bool HasNSW = false) const { + return Fold(ConstantExpr::getMul(LHS, RHS, HasNUW, HasNSW)); } Constant *CreateFMul(Constant *LHS, Constant *RHS) const { return Fold(ConstantExpr::getFMul(LHS, RHS)); } - Constant *CreateUDiv(Constant *LHS, Constant *RHS) const { - return Fold(ConstantExpr::getUDiv(LHS, RHS)); - } - Constant *CreateSDiv(Constant *LHS, Constant *RHS) const { - return Fold(ConstantExpr::getSDiv(LHS, RHS)); + Constant *CreateUDiv(Constant *LHS, Constant *RHS, bool isExact = false)const{ + return Fold(ConstantExpr::getUDiv(LHS, RHS, isExact)); } - Constant *CreateExactSDiv(Constant *LHS, Constant *RHS) const { - return Fold(ConstantExpr::getExactSDiv(LHS, RHS)); + Constant *CreateSDiv(Constant *LHS, Constant *RHS, bool isExact = false)const{ + return Fold(ConstantExpr::getSDiv(LHS, RHS, isExact)); } Constant *CreateFDiv(Constant *LHS, Constant *RHS) const { return Fold(ConstantExpr::getFDiv(LHS, RHS)); @@ -103,14 +85,15 @@ public: Constant *CreateFRem(Constant *LHS, Constant *RHS) const { return Fold(ConstantExpr::getFRem(LHS, RHS)); } - Constant *CreateShl(Constant *LHS, Constant *RHS) const { - return Fold(ConstantExpr::getShl(LHS, RHS)); + Constant *CreateShl(Constant *LHS, Constant *RHS, + bool HasNUW = false, bool HasNSW = false) const { + return Fold(ConstantExpr::getShl(LHS, RHS, HasNUW, HasNSW)); } - Constant *CreateLShr(Constant *LHS, Constant *RHS) const { - return Fold(ConstantExpr::getLShr(LHS, RHS)); + Constant *CreateLShr(Constant *LHS, Constant *RHS, bool isExact = false)const{ + return Fold(ConstantExpr::getLShr(LHS, RHS, isExact)); } - Constant *CreateAShr(Constant *LHS, Constant *RHS) const { - return Fold(ConstantExpr::getAShr(LHS, RHS)); + Constant *CreateAShr(Constant *LHS, Constant *RHS, bool isExact = false)const{ + return Fold(ConstantExpr::getAShr(LHS, RHS, isExact)); } Constant *CreateAnd(Constant *LHS, Constant *RHS) const { return Fold(ConstantExpr::getAnd(LHS, RHS)); @@ -131,14 +114,9 @@ public: // Unary Operators //===--------------------------------------------------------------------===// - Constant *CreateNeg(Constant *C) const { - return Fold(ConstantExpr::getNeg(C)); - } - Constant *CreateNSWNeg(Constant *C) const { - return Fold(ConstantExpr::getNSWNeg(C)); - } - Constant *CreateNUWNeg(Constant *C) const { - return Fold(ConstantExpr::getNUWNeg(C)); + Constant *CreateNeg(Constant *C, + bool HasNUW = false, bool HasNSW = false) const { + return Fold(ConstantExpr::getNeg(C, HasNUW, HasNSW)); } Constant *CreateFNeg(Constant *C) const { return Fold(ConstantExpr::getFNeg(C)); diff --git a/include/llvm/Support/ThreadLocal.h b/include/llvm/Support/ThreadLocal.h new file mode 100644 index 000000000000..15350a7afff7 --- /dev/null +++ b/include/llvm/Support/ThreadLocal.h @@ -0,0 +1,54 @@ +//===- llvm/Support/ThreadLocal.h - Thread Local Data ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the llvm::sys::ThreadLocal class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_THREAD_LOCAL_H +#define LLVM_SYSTEM_THREAD_LOCAL_H + +#include "llvm/Support/Threading.h" +#include + +namespace llvm { + namespace sys { + // ThreadLocalImpl - Common base class of all ThreadLocal instantiations. + // YOU SHOULD NEVER USE THIS DIRECTLY. + class ThreadLocalImpl { + void* data; + public: + ThreadLocalImpl(); + virtual ~ThreadLocalImpl(); + void setInstance(const void* d); + const void* getInstance(); + void removeInstance(); + }; + + /// ThreadLocal - A class used to abstract thread-local storage. It holds, + /// for each thread, a pointer a single object of type T. + template + class ThreadLocal : public ThreadLocalImpl { + public: + ThreadLocal() : ThreadLocalImpl() { } + + /// get - Fetches a pointer to the object associated with the current + /// thread. If no object has yet been associated, it returns NULL; + T* get() { return static_cast(getInstance()); } + + // set - Associates a pointer to an object with the current thread. + void set(T* d) { setInstance(d); } + + // erase - Removes the pointer associated with the current thread. + void erase() { removeInstance(); } + }; + } +} + +#endif diff --git a/include/llvm/Support/Threading.h b/include/llvm/Support/Threading.h new file mode 100644 index 000000000000..c0e842c2fe73 --- /dev/null +++ b/include/llvm/Support/Threading.h @@ -0,0 +1,59 @@ +//===-- llvm/Support/Threading.h - Control multithreading mode --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// TThis file defines llvm_start_multithreaded() and friends. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_THREADING_H +#define LLVM_SYSTEM_THREADING_H + +namespace llvm { + /// llvm_start_multithreaded - Allocate and initialize structures needed to + /// make LLVM safe for multithreading. The return value indicates whether + /// multithreaded initialization succeeded. LLVM will still be operational + /// on "failed" return, and will still be safe for hosting threading + /// applications in the JIT, but will not be safe for concurrent calls to the + /// LLVM APIs. + /// THIS MUST EXECUTE IN ISOLATION FROM ALL OTHER LLVM API CALLS. + bool llvm_start_multithreaded(); + + /// llvm_stop_multithreaded - Deallocate structures necessary to make LLVM + /// safe for multithreading. + /// THIS MUST EXECUTE IN ISOLATION FROM ALL OTHER LLVM API CALLS. + void llvm_stop_multithreaded(); + + /// llvm_is_multithreaded - Check whether LLVM is executing in thread-safe + /// mode or not. + bool llvm_is_multithreaded(); + + /// acquire_global_lock - Acquire the global lock. This is a no-op if called + /// before llvm_start_multithreaded(). + void llvm_acquire_global_lock(); + + /// release_global_lock - Release the global lock. This is a no-op if called + /// before llvm_start_multithreaded(). + void llvm_release_global_lock(); + + /// llvm_execute_on_thread - Execute the given \arg UserFn on a separate + /// thread, passing it the provided \arg UserData. + /// + /// This function does not guarantee that the code will actually be executed + /// on a separate thread or honoring the requested stack size, but tries to do + /// so where system support is available. + /// + /// \param UserFn - The callback to execute. + /// \param UserData - An argument to pass to the callback function. + /// \param RequestedStackSize - If non-zero, a requested size (in bytes) for + /// the thread stack. + void llvm_execute_on_thread(void (*UserFn)(void*), void *UserData, + unsigned RequestedStackSize = 0); +} + +#endif diff --git a/include/llvm/Support/TimeValue.h b/include/llvm/Support/TimeValue.h new file mode 100644 index 000000000000..e1227118c22c --- /dev/null +++ b/include/llvm/Support/TimeValue.h @@ -0,0 +1,382 @@ +//===-- TimeValue.h - Declare OS TimeValue Concept --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header file declares the operating system TimeValue concept. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/DataTypes.h" +#include + +#ifndef LLVM_SYSTEM_TIMEVALUE_H +#define LLVM_SYSTEM_TIMEVALUE_H + +namespace llvm { +namespace sys { + /// This class is used where a precise fixed point in time is required. The + /// range of TimeValue spans many hundreds of billions of years both past and + /// present. The precision of TimeValue is to the nanosecond. However, the + /// actual precision of its values will be determined by the resolution of + /// the system clock. The TimeValue class is used in conjunction with several + /// other lib/System interfaces to specify the time at which a call should + /// timeout, etc. + /// @since 1.4 + /// @brief Provides an abstraction for a fixed point in time. + class TimeValue { + + /// @name Constants + /// @{ + public: + + /// A constant TimeValue representing the smallest time + /// value permissable by the class. MinTime is some point + /// in the distant past, about 300 billion years BCE. + /// @brief The smallest possible time value. + static const TimeValue MinTime; + + /// A constant TimeValue representing the largest time + /// value permissable by the class. MaxTime is some point + /// in the distant future, about 300 billion years AD. + /// @brief The largest possible time value. + static const TimeValue MaxTime; + + /// A constant TimeValue representing the base time, + /// or zero time of 00:00:00 (midnight) January 1st, 2000. + /// @brief 00:00:00 Jan 1, 2000 UTC. + static const TimeValue ZeroTime; + + /// A constant TimeValue for the Posix base time which is + /// 00:00:00 (midnight) January 1st, 1970. + /// @brief 00:00:00 Jan 1, 1970 UTC. + static const TimeValue PosixZeroTime; + + /// A constant TimeValue for the Win32 base time which is + /// 00:00:00 (midnight) January 1st, 1601. + /// @brief 00:00:00 Jan 1, 1601 UTC. + static const TimeValue Win32ZeroTime; + + /// @} + /// @name Types + /// @{ + public: + typedef int64_t SecondsType; ///< Type used for representing seconds. + typedef int32_t NanoSecondsType;///< Type used for representing nanoseconds. + + enum TimeConversions { + NANOSECONDS_PER_SECOND = 1000000000, ///< One Billion + MICROSECONDS_PER_SECOND = 1000000, ///< One Million + MILLISECONDS_PER_SECOND = 1000, ///< One Thousand + NANOSECONDS_PER_MICROSECOND = 1000, ///< One Thousand + NANOSECONDS_PER_MILLISECOND = 1000000,///< One Million + NANOSECONDS_PER_POSIX_TICK = 100, ///< Posix tick is 100 Hz (10ms) + NANOSECONDS_PER_WIN32_TICK = 100 ///< Win32 tick is 100 Hz (10ms) + }; + + /// @} + /// @name Constructors + /// @{ + public: + /// Caller provides the exact value in seconds and nanoseconds. The + /// \p nanos argument defaults to zero for convenience. + /// @brief Explicit constructor + explicit TimeValue (SecondsType seconds, NanoSecondsType nanos = 0) + : seconds_( seconds ), nanos_( nanos ) { this->normalize(); } + + /// Caller provides the exact value as a double in seconds with the + /// fractional part representing nanoseconds. + /// @brief Double Constructor. + explicit TimeValue( double new_time ) + : seconds_( 0 ) , nanos_ ( 0 ) { + SecondsType integer_part = static_cast( new_time ); + seconds_ = integer_part; + nanos_ = static_cast( (new_time - + static_cast(integer_part)) * NANOSECONDS_PER_SECOND ); + this->normalize(); + } + + /// This is a static constructor that returns a TimeValue that represents + /// the current time. + /// @brief Creates a TimeValue with the current time (UTC). + static TimeValue now(); + + /// @} + /// @name Operators + /// @{ + public: + /// Add \p that to \p this. + /// @returns this + /// @brief Incrementing assignment operator. + TimeValue& operator += (const TimeValue& that ) { + this->seconds_ += that.seconds_ ; + this->nanos_ += that.nanos_ ; + this->normalize(); + return *this; + } + + /// Subtract \p that from \p this. + /// @returns this + /// @brief Decrementing assignment operator. + TimeValue& operator -= (const TimeValue &that ) { + this->seconds_ -= that.seconds_ ; + this->nanos_ -= that.nanos_ ; + this->normalize(); + return *this; + } + + /// Determine if \p this is less than \p that. + /// @returns True iff *this < that. + /// @brief True if this < that. + int operator < (const TimeValue &that) const { return that > *this; } + + /// Determine if \p this is greather than \p that. + /// @returns True iff *this > that. + /// @brief True if this > that. + int operator > (const TimeValue &that) const { + if ( this->seconds_ > that.seconds_ ) { + return 1; + } else if ( this->seconds_ == that.seconds_ ) { + if ( this->nanos_ > that.nanos_ ) return 1; + } + return 0; + } + + /// Determine if \p this is less than or equal to \p that. + /// @returns True iff *this <= that. + /// @brief True if this <= that. + int operator <= (const TimeValue &that) const { return that >= *this; } + + /// Determine if \p this is greater than or equal to \p that. + /// @returns True iff *this >= that. + /// @brief True if this >= that. + int operator >= (const TimeValue &that) const { + if ( this->seconds_ > that.seconds_ ) { + return 1; + } else if ( this->seconds_ == that.seconds_ ) { + if ( this->nanos_ >= that.nanos_ ) return 1; + } + return 0; + } + + /// Determines if two TimeValue objects represent the same moment in time. + /// @brief True iff *this == that. + /// @brief True if this == that. + int operator == (const TimeValue &that) const { + return (this->seconds_ == that.seconds_) && + (this->nanos_ == that.nanos_); + } + + /// Determines if two TimeValue objects represent times that are not the + /// same. + /// @return True iff *this != that. + /// @brief True if this != that. + int operator != (const TimeValue &that) const { return !(*this == that); } + + /// Adds two TimeValue objects together. + /// @returns The sum of the two operands as a new TimeValue + /// @brief Addition operator. + friend TimeValue operator + (const TimeValue &tv1, const TimeValue &tv2); + + /// Subtracts two TimeValue objects. + /// @returns The difference of the two operands as a new TimeValue + /// @brief Subtraction operator. + friend TimeValue operator - (const TimeValue &tv1, const TimeValue &tv2); + + /// @} + /// @name Accessors + /// @{ + public: + + /// Returns only the seconds component of the TimeValue. The nanoseconds + /// portion is ignored. No rounding is performed. + /// @brief Retrieve the seconds component + SecondsType seconds() const { return seconds_; } + + /// Returns only the nanoseconds component of the TimeValue. The seconds + /// portion is ignored. + /// @brief Retrieve the nanoseconds component. + NanoSecondsType nanoseconds() const { return nanos_; } + + /// Returns only the fractional portion of the TimeValue rounded down to the + /// nearest microsecond (divide by one thousand). + /// @brief Retrieve the fractional part as microseconds; + uint32_t microseconds() const { + return nanos_ / NANOSECONDS_PER_MICROSECOND; + } + + /// Returns only the fractional portion of the TimeValue rounded down to the + /// nearest millisecond (divide by one million). + /// @brief Retrieve the fractional part as milliseconds; + uint32_t milliseconds() const { + return nanos_ / NANOSECONDS_PER_MILLISECOND; + } + + /// Returns the TimeValue as a number of microseconds. Note that the value + /// returned can overflow because the range of a uint64_t is smaller than + /// the range of a TimeValue. Nevertheless, this is useful on some operating + /// systems and is therefore provided. + /// @brief Convert to a number of microseconds (can overflow) + uint64_t usec() const { + return seconds_ * MICROSECONDS_PER_SECOND + + ( nanos_ / NANOSECONDS_PER_MICROSECOND ); + } + + /// Returns the TimeValue as a number of milliseconds. Note that the value + /// returned can overflow because the range of a uint64_t is smaller than + /// the range of a TimeValue. Nevertheless, this is useful on some operating + /// systems and is therefore provided. + /// @brief Convert to a number of milliseconds (can overflow) + uint64_t msec() const { + return seconds_ * MILLISECONDS_PER_SECOND + + ( nanos_ / NANOSECONDS_PER_MILLISECOND ); + } + + /// Converts the TimeValue into the corresponding number of "ticks" for + /// Posix, correcting for the difference in Posix zero time. + /// @brief Convert to unix time (100 nanoseconds since 12:00:00a Jan 1,1970) + uint64_t toPosixTime() const { + uint64_t result = seconds_ - PosixZeroTime.seconds_; + result += nanos_ / NANOSECONDS_PER_POSIX_TICK; + return result; + } + + /// Converts the TimeValue into the corresponding number of seconds + /// since the epoch (00:00:00 Jan 1,1970). + uint64_t toEpochTime() const { + return seconds_ - PosixZeroTime.seconds_; + } + + /// Converts the TimeValue into the corresponding number of "ticks" for + /// Win32 platforms, correcting for the difference in Win32 zero time. + /// @brief Convert to windows time (seconds since 12:00:00a Jan 1, 1601) + uint64_t toWin32Time() const { + uint64_t result = seconds_ - Win32ZeroTime.seconds_; + result += nanos_ / NANOSECONDS_PER_WIN32_TICK; + return result; + } + + /// Provides the seconds and nanoseconds as results in its arguments after + /// correction for the Posix zero time. + /// @brief Convert to timespec time (ala POSIX.1b) + void getTimespecTime( uint64_t& seconds, uint32_t& nanos ) const { + seconds = seconds_ - PosixZeroTime.seconds_; + nanos = nanos_; + } + + /// Provides conversion of the TimeValue into a readable time & date. + /// @returns std::string containing the readable time value + /// @brief Convert time to a string. + std::string str() const; + + /// @} + /// @name Mutators + /// @{ + public: + /// The seconds component of the TimeValue is set to \p sec without + /// modifying the nanoseconds part. This is useful for whole second + /// arithmetic. + /// @brief Set the seconds component. + void seconds (SecondsType sec ) { + this->seconds_ = sec; + this->normalize(); + } + + /// The nanoseconds component of the TimeValue is set to \p nanos without + /// modifying the seconds part. This is useful for basic computations + /// involving just the nanoseconds portion. Note that the TimeValue will be + /// normalized after this call so that the fractional (nanoseconds) portion + /// will have the smallest equivalent value. + /// @brief Set the nanoseconds component using a number of nanoseconds. + void nanoseconds ( NanoSecondsType nanos ) { + this->nanos_ = nanos; + this->normalize(); + } + + /// The seconds component remains unchanged. + /// @brief Set the nanoseconds component using a number of microseconds. + void microseconds ( int32_t micros ) { + this->nanos_ = micros * NANOSECONDS_PER_MICROSECOND; + this->normalize(); + } + + /// The seconds component remains unchanged. + /// @brief Set the nanoseconds component using a number of milliseconds. + void milliseconds ( int32_t millis ) { + this->nanos_ = millis * NANOSECONDS_PER_MILLISECOND; + this->normalize(); + } + + /// @brief Converts from microsecond format to TimeValue format + void usec( int64_t microseconds ) { + this->seconds_ = microseconds / MICROSECONDS_PER_SECOND; + this->nanos_ = NanoSecondsType(microseconds % MICROSECONDS_PER_SECOND) * + NANOSECONDS_PER_MICROSECOND; + this->normalize(); + } + + /// @brief Converts from millisecond format to TimeValue format + void msec( int64_t milliseconds ) { + this->seconds_ = milliseconds / MILLISECONDS_PER_SECOND; + this->nanos_ = NanoSecondsType(milliseconds % MILLISECONDS_PER_SECOND) * + NANOSECONDS_PER_MILLISECOND; + this->normalize(); + } + + /// Converts the \p seconds argument from PosixTime to the corresponding + /// TimeValue and assigns that value to \p this. + /// @brief Convert seconds form PosixTime to TimeValue + void fromEpochTime( SecondsType seconds ) { + seconds_ = seconds + PosixZeroTime.seconds_; + nanos_ = 0; + this->normalize(); + } + + /// Converts the \p win32Time argument from Windows FILETIME to the + /// corresponding TimeValue and assigns that value to \p this. + /// @brief Convert seconds form Windows FILETIME to TimeValue + void fromWin32Time( uint64_t win32Time ) { + this->seconds_ = win32Time / 10000000 + Win32ZeroTime.seconds_; + this->nanos_ = NanoSecondsType(win32Time % 10000000) * 100; + } + + /// @} + /// @name Implementation + /// @{ + private: + /// This causes the values to be represented so that the fractional + /// part is minimized, possibly incrementing the seconds part. + /// @brief Normalize to canonical form. + void normalize(); + + /// @} + /// @name Data + /// @{ + private: + /// Store the values as a . + SecondsType seconds_;///< Stores the seconds part of the TimeVal + NanoSecondsType nanos_; ///< Stores the nanoseconds part of the TimeVal + /// @} + + }; + +inline TimeValue operator + (const TimeValue &tv1, const TimeValue &tv2) { + TimeValue sum (tv1.seconds_ + tv2.seconds_, tv1.nanos_ + tv2.nanos_); + sum.normalize (); + return sum; +} + +inline TimeValue operator - (const TimeValue &tv1, const TimeValue &tv2) { + TimeValue difference (tv1.seconds_ - tv2.seconds_, tv1.nanos_ - tv2.nanos_ ); + difference.normalize (); + return difference; +} + +} +} + +#endif diff --git a/include/llvm/Support/Timer.h b/include/llvm/Support/Timer.h index f959136f86a0..404cb6d6c8b6 100644 --- a/include/llvm/Support/Timer.h +++ b/include/llvm/Support/Timer.h @@ -15,7 +15,7 @@ #ifndef LLVM_SUPPORT_TIMER_H #define LLVM_SUPPORT_TIMER_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/ADT/StringRef.h" #include #include diff --git a/include/llvm/Support/ToolOutputFile.h b/include/llvm/Support/ToolOutputFile.h new file mode 100644 index 000000000000..65b182a24535 --- /dev/null +++ b/include/llvm/Support/ToolOutputFile.h @@ -0,0 +1,62 @@ +//===- ToolOutputFile.h - Output files for compiler-like tools -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the tool_output_file class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_TOOL_OUTPUT_FILE_H +#define LLVM_SUPPORT_TOOL_OUTPUT_FILE_H + +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +/// tool_output_file - This class contains a raw_fd_ostream and adds a +/// few extra features commonly needed for compiler-like tool output files: +/// - The file is automatically deleted if the process is killed. +/// - The file is automatically deleted when the tool_output_file +/// object is destroyed unless the client calls keep(). +class tool_output_file { + /// Installer - This class is declared before the raw_fd_ostream so that + /// it is constructed before the raw_fd_ostream is constructed and + /// destructed after the raw_fd_ostream is destructed. It installs + /// cleanups in its constructor and uninstalls them in its destructor. + class CleanupInstaller { + /// Filename - The name of the file. + std::string Filename; + public: + /// Keep - The flag which indicates whether we should not delete the file. + bool Keep; + + explicit CleanupInstaller(const char *filename); + ~CleanupInstaller(); + } Installer; + + /// OS - The contained stream. This is intentionally declared after + /// Installer. + raw_fd_ostream OS; + +public: + /// tool_output_file - This constructor's arguments are passed to + /// to raw_fd_ostream's constructor. + tool_output_file(const char *filename, std::string &ErrorInfo, + unsigned Flags = 0); + + /// os - Return the contained raw_fd_ostream. + raw_fd_ostream &os() { return OS; } + + /// keep - Indicate that the tool's job wrt this output file has been + /// successful and the file should not be deleted. + void keep() { Installer.Keep = true; } +}; + +} // end llvm namespace + +#endif diff --git a/include/llvm/Support/TypeBuilder.h b/include/llvm/Support/TypeBuilder.h index 81c2747b6c05..ea63da00edcd 100644 --- a/include/llvm/Support/TypeBuilder.h +++ b/include/llvm/Support/TypeBuilder.h @@ -88,6 +88,8 @@ class ieee_double {}; class x86_fp80 {}; class fp128 {}; class ppc_fp128 {}; +// X86 MMX. +class x86_mmx {}; } // namespace types // LLVM doesn't have const or volatile types. @@ -219,6 +221,10 @@ template class TypeBuilder { public: static const Type *get(LLVMContext& C) { return Type::getPPC_FP128Ty(C); } }; +template class TypeBuilder { +public: + static const Type *get(LLVMContext& C) { return Type::getX86_MMXTy(C); } +}; template class TypeBuilder { public: diff --git a/include/llvm/Support/Valgrind.h b/include/llvm/Support/Valgrind.h new file mode 100644 index 000000000000..7662eaaff5a9 --- /dev/null +++ b/include/llvm/Support/Valgrind.h @@ -0,0 +1,32 @@ +//===- llvm/Support/Valgrind.h - Communication with Valgrind -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Methods for communicating with a valgrind instance this program is running +// under. These are all no-ops unless LLVM was configured on a system with the +// valgrind headers installed and valgrind is controlling this process. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_VALGRIND_H +#define LLVM_SYSTEM_VALGRIND_H + +#include + +namespace llvm { +namespace sys { + // True if Valgrind is controlling this process. + bool RunningOnValgrind(); + + // Discard valgrind's translation of code in the range [Addr .. Addr + Len). + // Otherwise valgrind may continue to execute the old version of the code. + void ValgrindDiscardTranslations(const void *Addr, size_t Len); +} +} + +#endif diff --git a/include/llvm/Support/raw_ostream.h b/include/llvm/Support/raw_ostream.h index 39bdbd804c27..6bfae5e29822 100644 --- a/include/llvm/Support/raw_ostream.h +++ b/include/llvm/Support/raw_ostream.h @@ -15,7 +15,7 @@ #define LLVM_SUPPORT_RAW_OSTREAM_H #include "llvm/ADT/StringRef.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { class format_object_base; @@ -165,7 +165,7 @@ public: } raw_ostream &operator<<(const char *Str) { - // Inline fast path, particulary for constant strings where a sufficiently + // Inline fast path, particularly for constant strings where a sufficiently // smart compiler will simplify strlen. return this->operator<<(StringRef(Str)); @@ -196,7 +196,7 @@ public: /// write_escaped - Output \arg Str, turning '\\', '\t', '\n', '"', and /// anything that doesn't satisfy std::isprint into an escape sequence. - raw_ostream &write_escaped(StringRef Str); + raw_ostream &write_escaped(StringRef Str, bool UseHexEscapes = false); raw_ostream &write(unsigned char C); raw_ostream &write(const char *Ptr, size_t Size); @@ -301,6 +301,10 @@ class raw_fd_ostream : public raw_ostream { /// bool Error; + /// Controls whether the stream should attempt to use atomic writes, when + /// possible. + bool UseAtomicWrites; + uint64_t pos; /// write_impl - See raw_ostream::write_impl. @@ -349,10 +353,7 @@ public: /// raw_fd_ostream ctor - FD is the file descriptor that this writes to. If /// ShouldClose is true, this closes the file when the stream is destroyed. - raw_fd_ostream(int fd, bool shouldClose, - bool unbuffered=false) : raw_ostream(unbuffered), FD(fd), - ShouldClose(shouldClose), - Error(false) {} + raw_fd_ostream(int fd, bool shouldClose, bool unbuffered=false); ~raw_fd_ostream(); @@ -361,9 +362,19 @@ public: void close(); /// seek - Flushes the stream and repositions the underlying file descriptor - /// positition to the offset specified from the beginning of the file. + /// position to the offset specified from the beginning of the file. uint64_t seek(uint64_t off); + /// SetUseAtomicWrite - Set the stream to attempt to use atomic writes for + /// individual output routines where possible. + /// + /// Note that because raw_ostream's are typically buffered, this flag is only + /// sensible when used on unbuffered streams which will flush their output + /// immediately. + void SetUseAtomicWrites(bool Value) { + UseAtomicWrites = Value; + } + virtual raw_ostream &changeColor(enum Colors colors, bool bold=false, bool bg=false); virtual raw_ostream &resetColor(); @@ -475,45 +486,6 @@ public: ~raw_null_ostream(); }; -/// tool_output_file - This class contains a raw_fd_ostream and adds a -/// few extra features commonly needed for compiler-like tool output files: -/// - The file is automatically deleted if the process is killed. -/// - The file is automatically deleted when the tool_output_file -/// object is destroyed unless the client calls keep(). -class tool_output_file { - /// Installer - This class is declared before the raw_fd_ostream so that - /// it is constructed before the raw_fd_ostream is constructed and - /// destructed after the raw_fd_ostream is destructed. It installs - /// cleanups in its constructor and uninstalls them in its destructor. - class CleanupInstaller { - /// Filename - The name of the file. - std::string Filename; - public: - /// Keep - The flag which indicates whether we should not delete the file. - bool Keep; - - explicit CleanupInstaller(const char *filename); - ~CleanupInstaller(); - } Installer; - - /// OS - The contained stream. This is intentionally declared after - /// Installer. - raw_fd_ostream OS; - -public: - /// tool_output_file - This constructor's arguments are passed to - /// to raw_fd_ostream's constructor. - tool_output_file(const char *filename, std::string &ErrorInfo, - unsigned Flags = 0); - - /// os - Return the contained raw_fd_ostream. - raw_fd_ostream &os() { return OS; } - - /// keep - Indicate that the tool's job wrt this output file has been - /// successful and the file should not be deleted. - void keep() { Installer.Keep = true; } -}; - } // end llvm namespace #endif diff --git a/include/llvm/Support/system_error.h b/include/llvm/Support/system_error.h new file mode 100644 index 000000000000..e5306ecfb35c --- /dev/null +++ b/include/llvm/Support/system_error.h @@ -0,0 +1,910 @@ +//===---------------------------- system_error ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This was lifted from libc++ and modified for C++03. This is called +// system_error even though it does not define that class because that's what +// it's called in C++0x. We don't define system_error because it is only used +// for exception handling, which we don't use in LLVM. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_SYSTEM_ERROR_H +#define LLVM_SYSTEM_SYSTEM_ERROR_H + +/* + system_error synopsis + +namespace std +{ + +class error_category +{ +public: + virtual ~error_category(); + + error_category(const error_category&) = delete; + error_category& operator=(const error_category&) = delete; + + virtual const char* name() const = 0; + virtual error_condition default_error_condition(int ev) const; + virtual bool equivalent(int code, const error_condition& condition) const; + virtual bool equivalent(const error_code& code, int condition) const; + virtual std::string message(int ev) const = 0; + + bool operator==(const error_category& rhs) const; + bool operator!=(const error_category& rhs) const; + bool operator<(const error_category& rhs) const; +}; + +const error_category& generic_category(); +const error_category& system_category(); + +template struct is_error_code_enum + : public false_type {}; + +template struct is_error_condition_enum + : public false_type {}; + +class error_code +{ +public: + // constructors: + error_code(); + error_code(int val, const error_category& cat); + template + error_code(ErrorCodeEnum e); + + // modifiers: + void assign(int val, const error_category& cat); + template + error_code& operator=(ErrorCodeEnum e); + void clear(); + + // observers: + int value() const; + const error_category& category() const; + error_condition default_error_condition() const; + std::string message() const; + explicit operator bool() const; +}; + +// non-member functions: +bool operator<(const error_code& lhs, const error_code& rhs); +template + basic_ostream& + operator<<(basic_ostream& os, const error_code& ec); + +class error_condition +{ +public: + // constructors: + error_condition(); + error_condition(int val, const error_category& cat); + template + error_condition(ErrorConditionEnum e); + + // modifiers: + void assign(int val, const error_category& cat); + template + error_condition& operator=(ErrorConditionEnum e); + void clear(); + + // observers: + int value() const; + const error_category& category() const; + std::string message() const; + explicit operator bool() const; +}; + +bool operator<(const error_condition& lhs, const error_condition& rhs); + +class system_error + : public runtime_error +{ +public: + system_error(error_code ec, const std::string& what_arg); + system_error(error_code ec, const char* what_arg); + system_error(error_code ec); + system_error(int ev, const error_category& ecat, const std::string& what_arg); + system_error(int ev, const error_category& ecat, const char* what_arg); + system_error(int ev, const error_category& ecat); + + const error_code& code() const throw(); + const char* what() const throw(); +}; + +enum class errc +{ + address_family_not_supported, // EAFNOSUPPORT + address_in_use, // EADDRINUSE + address_not_available, // EADDRNOTAVAIL + already_connected, // EISCONN + argument_list_too_long, // E2BIG + argument_out_of_domain, // EDOM + bad_address, // EFAULT + bad_file_descriptor, // EBADF + bad_message, // EBADMSG + broken_pipe, // EPIPE + connection_aborted, // ECONNABORTED + connection_already_in_progress, // EALREADY + connection_refused, // ECONNREFUSED + connection_reset, // ECONNRESET + cross_device_link, // EXDEV + destination_address_required, // EDESTADDRREQ + device_or_resource_busy, // EBUSY + directory_not_empty, // ENOTEMPTY + executable_format_error, // ENOEXEC + file_exists, // EEXIST + file_too_large, // EFBIG + filename_too_long, // ENAMETOOLONG + function_not_supported, // ENOSYS + host_unreachable, // EHOSTUNREACH + identifier_removed, // EIDRM + illegal_byte_sequence, // EILSEQ + inappropriate_io_control_operation, // ENOTTY + interrupted, // EINTR + invalid_argument, // EINVAL + invalid_seek, // ESPIPE + io_error, // EIO + is_a_directory, // EISDIR + message_size, // EMSGSIZE + network_down, // ENETDOWN + network_reset, // ENETRESET + network_unreachable, // ENETUNREACH + no_buffer_space, // ENOBUFS + no_child_process, // ECHILD + no_link, // ENOLINK + no_lock_available, // ENOLCK + no_message_available, // ENODATA + no_message, // ENOMSG + no_protocol_option, // ENOPROTOOPT + no_space_on_device, // ENOSPC + no_stream_resources, // ENOSR + no_such_device_or_address, // ENXIO + no_such_device, // ENODEV + no_such_file_or_directory, // ENOENT + no_such_process, // ESRCH + not_a_directory, // ENOTDIR + not_a_socket, // ENOTSOCK + not_a_stream, // ENOSTR + not_connected, // ENOTCONN + not_enough_memory, // ENOMEM + not_supported, // ENOTSUP + operation_canceled, // ECANCELED + operation_in_progress, // EINPROGRESS + operation_not_permitted, // EPERM + operation_not_supported, // EOPNOTSUPP + operation_would_block, // EWOULDBLOCK + owner_dead, // EOWNERDEAD + permission_denied, // EACCES + protocol_error, // EPROTO + protocol_not_supported, // EPROTONOSUPPORT + read_only_file_system, // EROFS + resource_deadlock_would_occur, // EDEADLK + resource_unavailable_try_again, // EAGAIN + result_out_of_range, // ERANGE + state_not_recoverable, // ENOTRECOVERABLE + stream_timeout, // ETIME + text_file_busy, // ETXTBSY + timed_out, // ETIMEDOUT + too_many_files_open_in_system, // ENFILE + too_many_files_open, // EMFILE + too_many_links, // EMLINK + too_many_symbolic_link_levels, // ELOOP + value_too_large, // EOVERFLOW + wrong_protocol_type // EPROTOTYPE +}; + +template <> struct is_error_condition_enum : true_type { } + +error_code make_error_code(errc e); +error_condition make_error_condition(errc e); + +// Comparison operators: +bool operator==(const error_code& lhs, const error_code& rhs); +bool operator==(const error_code& lhs, const error_condition& rhs); +bool operator==(const error_condition& lhs, const error_code& rhs); +bool operator==(const error_condition& lhs, const error_condition& rhs); +bool operator!=(const error_code& lhs, const error_code& rhs); +bool operator!=(const error_code& lhs, const error_condition& rhs); +bool operator!=(const error_condition& lhs, const error_code& rhs); +bool operator!=(const error_condition& lhs, const error_condition& rhs); + +template <> struct hash; + +} // std + +*/ + +#include "llvm/Config/config.h" +#include "llvm/Support/type_traits.h" +#include +#include + +// This must be here instead of a .inc file because it is used in the definition +// of the enum values below. +#ifdef LLVM_ON_WIN32 + + // The following numbers were taken from VS2010. +# ifndef EAFNOSUPPORT +# define EAFNOSUPPORT 102 +# endif +# ifndef EADDRINUSE +# define EADDRINUSE 100 +# endif +# ifndef EADDRNOTAVAIL +# define EADDRNOTAVAIL 101 +# endif +# ifndef EISCONN +# define EISCONN 113 +# endif +# ifndef E2BIG +# define E2BIG 7 +# endif +# ifndef EDOM +# define EDOM 33 +# endif +# ifndef EFAULT +# define EFAULT 14 +# endif +# ifndef EBADF +# define EBADF 9 +# endif +# ifndef EBADMSG +# define EBADMSG 104 +# endif +# ifndef EPIPE +# define EPIPE 32 +# endif +# ifndef ECONNABORTED +# define ECONNABORTED 106 +# endif +# ifndef EALREADY +# define EALREADY 103 +# endif +# ifndef ECONNREFUSED +# define ECONNREFUSED 107 +# endif +# ifndef ECONNRESET +# define ECONNRESET 108 +# endif +# ifndef EXDEV +# define EXDEV 18 +# endif +# ifndef EDESTADDRREQ +# define EDESTADDRREQ 109 +# endif +# ifndef EBUSY +# define EBUSY 16 +# endif +# ifndef ENOTEMPTY +# define ENOTEMPTY 41 +# endif +# ifndef ENOEXEC +# define ENOEXEC 8 +# endif +# ifndef EEXIST +# define EEXIST 17 +# endif +# ifndef EFBIG +# define EFBIG 27 +# endif +# ifndef ENAMETOOLONG +# define ENAMETOOLONG 38 +# endif +# ifndef ENOSYS +# define ENOSYS 40 +# endif +# ifndef EHOSTUNREACH +# define EHOSTUNREACH 110 +# endif +# ifndef EIDRM +# define EIDRM 111 +# endif +# ifndef EILSEQ +# define EILSEQ 42 +# endif +# ifndef ENOTTY +# define ENOTTY 25 +# endif +# ifndef EINTR +# define EINTR 4 +# endif +# ifndef EINVAL +# define EINVAL 22 +# endif +# ifndef ESPIPE +# define ESPIPE 29 +# endif +# ifndef EIO +# define EIO 5 +# endif +# ifndef EISDIR +# define EISDIR 21 +# endif +# ifndef EMSGSIZE +# define EMSGSIZE 115 +# endif +# ifndef ENETDOWN +# define ENETDOWN 116 +# endif +# ifndef ENETRESET +# define ENETRESET 117 +# endif +# ifndef ENETUNREACH +# define ENETUNREACH 118 +# endif +# ifndef ENOBUFS +# define ENOBUFS 119 +# endif +# ifndef ECHILD +# define ECHILD 10 +# endif +# ifndef ENOLINK +# define ENOLINK 121 +# endif +# ifndef ENOLCK +# define ENOLCK 39 +# endif +# ifndef ENODATA +# define ENODATA 120 +# endif +# ifndef ENOMSG +# define ENOMSG 122 +# endif +# ifndef ENOPROTOOPT +# define ENOPROTOOPT 123 +# endif +# ifndef ENOSPC +# define ENOSPC 28 +# endif +# ifndef ENOSR +# define ENOSR 124 +# endif +# ifndef ENXIO +# define ENXIO 6 +# endif +# ifndef ENODEV +# define ENODEV 19 +# endif +# ifndef ENOENT +# define ENOENT 2 +# endif +# ifndef ESRCH +# define ESRCH 3 +# endif +# ifndef ENOTDIR +# define ENOTDIR 20 +# endif +# ifndef ENOTSOCK +# define ENOTSOCK 128 +# endif +# ifndef ENOSTR +# define ENOSTR 125 +# endif +# ifndef ENOTCONN +# define ENOTCONN 126 +# endif +# ifndef ENOMEM +# define ENOMEM 12 +# endif +# ifndef ENOTSUP +# define ENOTSUP 129 +# endif +# ifndef ECANCELED +# define ECANCELED 105 +# endif +# ifndef EINPROGRESS +# define EINPROGRESS 112 +# endif +# ifndef EPERM +# define EPERM 1 +# endif +# ifndef EOPNOTSUPP +# define EOPNOTSUPP 130 +# endif +# ifndef EWOULDBLOCK +# define EWOULDBLOCK 140 +# endif +# ifndef EOWNERDEAD +# define EOWNERDEAD 133 +# endif +# ifndef EACCES +# define EACCES 13 +# endif +# ifndef EPROTO +# define EPROTO 134 +# endif +# ifndef EPROTONOSUPPORT +# define EPROTONOSUPPORT 135 +# endif +# ifndef EROFS +# define EROFS 30 +# endif +# ifndef EDEADLK +# define EDEADLK 36 +# endif +# ifndef EAGAIN +# define EAGAIN 11 +# endif +# ifndef ERANGE +# define ERANGE 34 +# endif +# ifndef ENOTRECOVERABLE +# define ENOTRECOVERABLE 127 +# endif +# ifndef ETIME +# define ETIME 137 +# endif +# ifndef ETXTBSY +# define ETXTBSY 139 +# endif +# ifndef ETIMEDOUT +# define ETIMEDOUT 138 +# endif +# ifndef ENFILE +# define ENFILE 23 +# endif +# ifndef EMFILE +# define EMFILE 24 +# endif +# ifndef EMLINK +# define EMLINK 31 +# endif +# ifndef ELOOP +# define ELOOP 114 +# endif +# ifndef EOVERFLOW +# define EOVERFLOW 132 +# endif +# ifndef EPROTOTYPE +# define EPROTOTYPE 136 +# endif +#endif + +namespace llvm { + +template +struct integral_constant { + typedef T value_type; + static const value_type value = v; + typedef integral_constant type; + operator value_type() { return value; } +}; + +typedef integral_constant true_type; +typedef integral_constant false_type; + +// is_error_code_enum + +template struct is_error_code_enum : public false_type {}; + +// is_error_condition_enum + +template struct is_error_condition_enum : public false_type {}; + +// Some error codes are not present on all platforms, so we provide equivalents +// for them: + +//enum class errc +struct errc { +enum _ { + success = 0, + address_family_not_supported = EAFNOSUPPORT, + address_in_use = EADDRINUSE, + address_not_available = EADDRNOTAVAIL, + already_connected = EISCONN, + argument_list_too_long = E2BIG, + argument_out_of_domain = EDOM, + bad_address = EFAULT, + bad_file_descriptor = EBADF, +#ifdef EBADMSG + bad_message = EBADMSG, +#else + bad_message = EINVAL, +#endif + broken_pipe = EPIPE, + connection_aborted = ECONNABORTED, + connection_already_in_progress = EALREADY, + connection_refused = ECONNREFUSED, + connection_reset = ECONNRESET, + cross_device_link = EXDEV, + destination_address_required = EDESTADDRREQ, + device_or_resource_busy = EBUSY, + directory_not_empty = ENOTEMPTY, + executable_format_error = ENOEXEC, + file_exists = EEXIST, + file_too_large = EFBIG, + filename_too_long = ENAMETOOLONG, + function_not_supported = ENOSYS, + host_unreachable = EHOSTUNREACH, + identifier_removed = EIDRM, + illegal_byte_sequence = EILSEQ, + inappropriate_io_control_operation = ENOTTY, + interrupted = EINTR, + invalid_argument = EINVAL, + invalid_seek = ESPIPE, + io_error = EIO, + is_a_directory = EISDIR, + message_size = EMSGSIZE, + network_down = ENETDOWN, + network_reset = ENETRESET, + network_unreachable = ENETUNREACH, + no_buffer_space = ENOBUFS, + no_child_process = ECHILD, +#ifdef ENOLINK + no_link = ENOLINK, +#else + no_link = EINVAL, +#endif + no_lock_available = ENOLCK, +#ifdef ENODATA + no_message_available = ENODATA, +#else + no_message_available = ENOMSG, +#endif + no_message = ENOMSG, + no_protocol_option = ENOPROTOOPT, + no_space_on_device = ENOSPC, +#ifdef ENOSR + no_stream_resources = ENOSR, +#else + no_stream_resources = ENOMEM, +#endif + no_such_device_or_address = ENXIO, + no_such_device = ENODEV, + no_such_file_or_directory = ENOENT, + no_such_process = ESRCH, + not_a_directory = ENOTDIR, + not_a_socket = ENOTSOCK, +#ifdef ENOSTR + not_a_stream = ENOSTR, +#else + not_a_stream = EINVAL, +#endif + not_connected = ENOTCONN, + not_enough_memory = ENOMEM, + not_supported = ENOTSUP, +#ifdef ECANCELED + operation_canceled = ECANCELED, +#else + operation_canceled = EINVAL, +#endif + operation_in_progress = EINPROGRESS, + operation_not_permitted = EPERM, + operation_not_supported = EOPNOTSUPP, + operation_would_block = EWOULDBLOCK, +#ifdef EOWNERDEAD + owner_dead = EOWNERDEAD, +#else + owner_dead = EINVAL, +#endif + permission_denied = EACCES, +#ifdef EPROTO + protocol_error = EPROTO, +#else + protocol_error = EINVAL, +#endif + protocol_not_supported = EPROTONOSUPPORT, + read_only_file_system = EROFS, + resource_deadlock_would_occur = EDEADLK, + resource_unavailable_try_again = EAGAIN, + result_out_of_range = ERANGE, +#ifdef ENOTRECOVERABLE + state_not_recoverable = ENOTRECOVERABLE, +#else + state_not_recoverable = EINVAL, +#endif +#ifdef ETIME + stream_timeout = ETIME, +#else + stream_timeout = ETIMEDOUT, +#endif + text_file_busy = ETXTBSY, + timed_out = ETIMEDOUT, + too_many_files_open_in_system = ENFILE, + too_many_files_open = EMFILE, + too_many_links = EMLINK, + too_many_symbolic_link_levels = ELOOP, + value_too_large = EOVERFLOW, + wrong_protocol_type = EPROTOTYPE +}; + + _ v_; + + errc(_ v) : v_(v) {} + operator int() const {return v_;} +}; + +template <> struct is_error_condition_enum : true_type { }; + +template <> struct is_error_condition_enum : true_type { }; + +class error_condition; +class error_code; + +// class error_category + +class _do_message; + +class error_category +{ +public: + virtual ~error_category(); + +private: + error_category(); + error_category(const error_category&);// = delete; + error_category& operator=(const error_category&);// = delete; + +public: + virtual const char* name() const = 0; + virtual error_condition default_error_condition(int _ev) const; + virtual bool equivalent(int _code, const error_condition& _condition) const; + virtual bool equivalent(const error_code& _code, int _condition) const; + virtual std::string message(int _ev) const = 0; + + bool operator==(const error_category& _rhs) const {return this == &_rhs;} + + bool operator!=(const error_category& _rhs) const {return !(*this == _rhs);} + + bool operator< (const error_category& _rhs) const {return this < &_rhs;} + + friend class _do_message; +}; + +class _do_message : public error_category +{ +public: + virtual std::string message(int ev) const; +}; + +const error_category& generic_category(); +const error_category& system_category(); + +/// Get the error_category used for errno values from POSIX functions. This is +/// the same as the system_category on POISIX systems, but is the same as the +/// generic_category on Windows. +const error_category& posix_category(); + +class error_condition +{ + int _val_; + const error_category* _cat_; +public: + error_condition() : _val_(0), _cat_(&generic_category()) {} + + error_condition(int _val, const error_category& _cat) + : _val_(_val), _cat_(&_cat) {} + + template + error_condition(E _e, typename enable_if_c< + is_error_condition_enum::value + >::type* = 0) + {*this = make_error_condition(_e);} + + void assign(int _val, const error_category& _cat) { + _val_ = _val; + _cat_ = &_cat; + } + + template + typename enable_if_c + < + is_error_condition_enum::value, + error_condition& + >::type + operator=(E _e) + {*this = make_error_condition(_e); return *this;} + + void clear() { + _val_ = 0; + _cat_ = &generic_category(); + } + + int value() const {return _val_;} + + const error_category& category() const {return *_cat_;} + std::string message() const; + + typedef void (*unspecified_bool_type)(); + static void unspecified_bool_true() {} + + operator unspecified_bool_type() const { // true if error + return _val_ == 0 ? 0 : unspecified_bool_true; + } +}; + +inline error_condition make_error_condition(errc _e) { + return error_condition(static_cast(_e), generic_category()); +} + +inline bool operator<(const error_condition& _x, const error_condition& _y) { + return _x.category() < _y.category() + || (_x.category() == _y.category() && _x.value() < _y.value()); +} + +// error_code + +class error_code { + int _val_; + const error_category* _cat_; +public: + error_code() : _val_(0), _cat_(&system_category()) {} + + error_code(int _val, const error_category& _cat) + : _val_(_val), _cat_(&_cat) {} + + template + error_code(E _e, typename enable_if_c< + is_error_code_enum::value + >::type* = 0) { + *this = make_error_code(_e); + } + + void assign(int _val, const error_category& _cat) { + _val_ = _val; + _cat_ = &_cat; + } + + template + typename enable_if_c + < + is_error_code_enum::value, + error_code& + >::type + operator=(E _e) + {*this = make_error_code(_e); return *this;} + + void clear() { + _val_ = 0; + _cat_ = &system_category(); + } + + int value() const {return _val_;} + + const error_category& category() const {return *_cat_;} + + error_condition default_error_condition() const + {return _cat_->default_error_condition(_val_);} + + std::string message() const; + + typedef void (*unspecified_bool_type)(); + static void unspecified_bool_true() {} + + operator unspecified_bool_type() const { // true if error + return _val_ == 0 ? 0 : unspecified_bool_true; + } +}; + +inline error_code make_error_code(errc _e) { + return error_code(static_cast(_e), generic_category()); +} + +inline bool operator<(const error_code& _x, const error_code& _y) { + return _x.category() < _y.category() + || (_x.category() == _y.category() && _x.value() < _y.value()); +} + +inline bool operator==(const error_code& _x, const error_code& _y) { + return _x.category() == _y.category() && _x.value() == _y.value(); +} + +inline bool operator==(const error_code& _x, const error_condition& _y) { + return _x.category().equivalent(_x.value(), _y) + || _y.category().equivalent(_x, _y.value()); +} + +inline bool operator==(const error_condition& _x, const error_code& _y) { + return _y == _x; +} + +inline bool operator==(const error_condition& _x, const error_condition& _y) { + return _x.category() == _y.category() && _x.value() == _y.value(); +} + +inline bool operator!=(const error_code& _x, const error_code& _y) { + return !(_x == _y); +} + +inline bool operator!=(const error_code& _x, const error_condition& _y) { + return !(_x == _y); +} + +inline bool operator!=(const error_condition& _x, const error_code& _y) { + return !(_x == _y); +} + +inline bool operator!=(const error_condition& _x, const error_condition& _y) { + return !(_x == _y); +} + +// Windows errors. + +// To construct an error_code after an API error: +// +// error_code( ::GetLastError(), system_category() ) +struct windows_error { +enum _ { + success = 0, + // These names and values are based on Windows WinError.h + // This is not a complete list. Add to this list if you need to explicitly + // check for it. + invalid_function = 1, // ERROR_INVALID_FUNCTION, + file_not_found = 2, // ERROR_FILE_NOT_FOUND, + path_not_found = 3, // ERROR_PATH_NOT_FOUND, + too_many_open_files = 4, // ERROR_TOO_MANY_OPEN_FILES, + access_denied = 5, // ERROR_ACCESS_DENIED, + invalid_handle = 6, // ERROR_INVALID_HANDLE, + arena_trashed = 7, // ERROR_ARENA_TRASHED, + not_enough_memory = 8, // ERROR_NOT_ENOUGH_MEMORY, + invalid_block = 9, // ERROR_INVALID_BLOCK, + bad_environment = 10, // ERROR_BAD_ENVIRONMENT, + bad_format = 11, // ERROR_BAD_FORMAT, + invalid_access = 12, // ERROR_INVALID_ACCESS, + outofmemory = 14, // ERROR_OUTOFMEMORY, + invalid_drive = 15, // ERROR_INVALID_DRIVE, + current_directory = 16, // ERROR_CURRENT_DIRECTORY, + not_same_device = 17, // ERROR_NOT_SAME_DEVICE, + no_more_files = 18, // ERROR_NO_MORE_FILES, + write_protect = 19, // ERROR_WRITE_PROTECT, + bad_unit = 20, // ERROR_BAD_UNIT, + not_ready = 21, // ERROR_NOT_READY, + bad_command = 22, // ERROR_BAD_COMMAND, + crc = 23, // ERROR_CRC, + bad_length = 24, // ERROR_BAD_LENGTH, + seek = 25, // ERROR_SEEK, + not_dos_disk = 26, // ERROR_NOT_DOS_DISK, + sector_not_found = 27, // ERROR_SECTOR_NOT_FOUND, + out_of_paper = 28, // ERROR_OUT_OF_PAPER, + write_fault = 29, // ERROR_WRITE_FAULT, + read_fault = 30, // ERROR_READ_FAULT, + gen_failure = 31, // ERROR_GEN_FAILURE, + sharing_violation = 32, // ERROR_SHARING_VIOLATION, + lock_violation = 33, // ERROR_LOCK_VIOLATION, + wrong_disk = 34, // ERROR_WRONG_DISK, + sharing_buffer_exceeded = 36, // ERROR_SHARING_BUFFER_EXCEEDED, + handle_eof = 38, // ERROR_HANDLE_EOF, + handle_disk_full = 39, // ERROR_HANDLE_DISK_FULL, + rem_not_list = 51, // ERROR_REM_NOT_LIST, + dup_name = 52, // ERROR_DUP_NAME, + bad_net_path = 53, // ERROR_BAD_NETPATH, + network_busy = 54, // ERROR_NETWORK_BUSY, + file_exists = 80, // ERROR_FILE_EXISTS, + cannot_make = 82, // ERROR_CANNOT_MAKE, + broken_pipe = 109, // ERROR_BROKEN_PIPE, + open_failed = 110, // ERROR_OPEN_FAILED, + buffer_overflow = 111, // ERROR_BUFFER_OVERFLOW, + disk_full = 112, // ERROR_DISK_FULL, + insufficient_buffer = 122, // ERROR_INSUFFICIENT_BUFFER, + lock_failed = 167, // ERROR_LOCK_FAILED, + busy = 170, // ERROR_BUSY, + cancel_violation = 173, // ERROR_CANCEL_VIOLATION, + already_exists = 183 // ERROR_ALREADY_EXISTS +}; + _ v_; + + windows_error(_ v) : v_(v) {} + explicit windows_error(int v) : v_(_(v)) {} + operator int() const {return v_;} +}; + + +template <> struct is_error_code_enum : true_type { }; + +template <> struct is_error_code_enum : true_type { }; + +inline error_code make_error_code(windows_error e) { + return error_code(static_cast(e), system_category()); +} + +} // end namespace llvm + +#endif diff --git a/include/llvm/System/AIXDataTypesFix.h b/include/llvm/System/AIXDataTypesFix.h deleted file mode 100644 index 8dbf02f28269..000000000000 --- a/include/llvm/System/AIXDataTypesFix.h +++ /dev/null @@ -1,25 +0,0 @@ -//===-- llvm/System/AIXDataTypesFix.h - Fix datatype defs ------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file overrides default system-defined types and limits which cannot be -// done in DataTypes.h.in because it is processed by autoheader first, which -// comments out any #undef statement -// -//===----------------------------------------------------------------------===// - -// No include guards desired! - -#ifndef SUPPORT_DATATYPES_H -#error "AIXDataTypesFix.h must only be included via DataTypes.h!" -#endif - -// GCC is strict about defining large constants: they must have LL modifier. -// These will be defined properly at the end of DataTypes.h -#undef INT64_MAX -#undef INT64_MIN diff --git a/include/llvm/System/Alarm.h b/include/llvm/System/Alarm.h deleted file mode 100644 index 7c284167c2ce..000000000000 --- a/include/llvm/System/Alarm.h +++ /dev/null @@ -1,51 +0,0 @@ -//===- llvm/System/Alarm.h - Alarm Generation support ----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file provides an operating system independent interface to alarm(2) -// type functionality. The Alarm class allows a one-shot alarm to be set up -// at some number of seconds in the future. When the alarm triggers, a method -// is called to process the event -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SYSTEM_ALARM_H -#define LLVM_SYSTEM_ALARM_H - -namespace llvm { -namespace sys { - - /// This function registers an alarm to trigger some number of \p seconds in - /// the future. When that time arrives, the AlarmStatus function will begin - /// to return 1 instead of 0. The user must poll the status of the alarm by - /// making occasional calls to AlarmStatus. If the user sends an interrupt - /// signal, AlarmStatus will begin returning -1, even if the alarm event - /// occurred. - /// @returns nothing - void SetupAlarm( - unsigned seconds ///< Number of seconds in future when alarm arrives - ); - - /// This function terminates the alarm previously set up - /// @returns nothing - void TerminateAlarm(); - - /// This function acquires the status of the alarm. - /// @returns -1=cancelled, 0=untriggered, 1=triggered - int AlarmStatus(); - - /// Sleep for n seconds. Warning: mixing calls to Sleep() and other *Alarm - /// calls may be a bad idea on some platforms (source: Linux man page). - /// @returns nothing. - void Sleep(unsigned n); - - -} // End sys namespace -} // End llvm namespace - -#endif diff --git a/include/llvm/System/Atomic.h b/include/llvm/System/Atomic.h deleted file mode 100644 index fc19369d11bd..000000000000 --- a/include/llvm/System/Atomic.h +++ /dev/null @@ -1,39 +0,0 @@ -//===- llvm/System/Atomic.h - Atomic Operations -----------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares the llvm::sys atomic operations. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SYSTEM_ATOMIC_H -#define LLVM_SYSTEM_ATOMIC_H - -#include "llvm/System/DataTypes.h" - -namespace llvm { - namespace sys { - void MemoryFence(); - -#ifdef _MSC_VER - typedef long cas_flag; -#else - typedef uint32_t cas_flag; -#endif - cas_flag CompareAndSwap(volatile cas_flag* ptr, - cas_flag new_value, - cas_flag old_value); - cas_flag AtomicIncrement(volatile cas_flag* ptr); - cas_flag AtomicDecrement(volatile cas_flag* ptr); - cas_flag AtomicAdd(volatile cas_flag* ptr, cas_flag val); - cas_flag AtomicMul(volatile cas_flag* ptr, cas_flag val); - cas_flag AtomicDiv(volatile cas_flag* ptr, cas_flag val); - } -} - -#endif diff --git a/include/llvm/System/DataTypes.h.cmake b/include/llvm/System/DataTypes.h.cmake deleted file mode 100644 index 9efe75a56ebc..000000000000 --- a/include/llvm/System/DataTypes.h.cmake +++ /dev/null @@ -1,189 +0,0 @@ -/*===-- include/System/DataTypes.h - Define fixed size types -----*- C -*-===*\ -|* *| -|* The LLVM Compiler Infrastructure *| -|* *| -|* This file is distributed under the University of Illinois Open Source *| -|* License. See LICENSE.TXT for details. *| -|* *| -|*===----------------------------------------------------------------------===*| -|* *| -|* This file contains definitions to figure out the size of _HOST_ data types.*| -|* This file is important because different host OS's define different macros,*| -|* which makes portability tough. This file exports the following *| -|* definitions: *| -|* *| -|* [u]int(32|64)_t : typedefs for signed and unsigned 32/64 bit system types*| -|* [U]INT(8|16|32|64)_(MIN|MAX) : Constants for the min and max values. *| -|* *| -|* No library is required when using these functinons. *| -|* *| -|*===----------------------------------------------------------------------===*/ - -/* Please leave this file C-compatible. */ - -#ifndef SUPPORT_DATATYPES_H -#define SUPPORT_DATATYPES_H - -#cmakedefine HAVE_SYS_TYPES_H ${HAVE_SYS_TYPES_H} -#cmakedefine HAVE_INTTYPES_H ${HAVE_INTTYPES_H} -#cmakedefine HAVE_STDINT_H ${HAVE_STDINT_H} -#cmakedefine HAVE_UINT64_T ${HAVE_UINT64_T} -#cmakedefine HAVE_U_INT64_T ${HAVE_U_INT64_T} - -#ifdef __cplusplus -#include -#else -#include -#endif - -#ifndef _MSC_VER - -/* Note that this header's correct operation depends on __STDC_LIMIT_MACROS - being defined. We would define it here, but in order to prevent Bad Things - happening when system headers or C++ STL headers include stdint.h before we - define it here, we define it on the g++ command line (in Makefile.rules). */ -#if !defined(__STDC_LIMIT_MACROS) -# error "Must #define __STDC_LIMIT_MACROS before #including System/DataTypes.h" -#endif - -#if !defined(__STDC_CONSTANT_MACROS) -# error "Must #define __STDC_CONSTANT_MACROS before " \ - "#including System/DataTypes.h" -#endif - -/* Note that includes , if this is a C99 system. */ -#ifdef HAVE_SYS_TYPES_H -#include -#endif - -#ifdef HAVE_INTTYPES_H -#include -#endif - -#ifdef HAVE_STDINT_H -#include -#endif - -#ifdef _AIX -#include "llvm/System/AIXDataTypesFix.h" -#endif - -/* Handle incorrect definition of uint64_t as u_int64_t */ -#ifndef HAVE_UINT64_T -#ifdef HAVE_U_INT64_T -typedef u_int64_t uint64_t; -#else -# error "Don't have a definition for uint64_t on this platform" -#endif -#endif - -#ifdef _OpenBSD_ -#define INT8_MAX 127 -#define INT8_MIN -128 -#define UINT8_MAX 255 -#define INT16_MAX 32767 -#define INT16_MIN -32768 -#define UINT16_MAX 65535 -#define INT32_MAX 2147483647 -#define INT32_MIN -2147483648 -#define UINT32_MAX 4294967295U -#endif - -#else /* _MSC_VER */ -/* Visual C++ doesn't provide standard integer headers, but it does provide - built-in data types. */ -#include -#include -#include -#ifdef __cplusplus -#include -#else -#include -#endif -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -typedef signed int int32_t; -typedef unsigned int uint32_t; -typedef short int16_t; -typedef unsigned short uint16_t; -typedef signed char int8_t; -typedef unsigned char uint8_t; -typedef signed int ssize_t; -#ifndef INT8_MAX -# define INT8_MAX 127 -#endif -#ifndef INT8_MIN -# define INT8_MIN -128 -#endif -#ifndef UINT8_MAX -# define UINT8_MAX 255 -#endif -#ifndef INT16_MAX -# define INT16_MAX 32767 -#endif -#ifndef INT16_MIN -# define INT16_MIN -32768 -#endif -#ifndef UINT16_MAX -# define UINT16_MAX 65535 -#endif -#ifndef INT32_MAX -# define INT32_MAX 2147483647 -#endif -#ifndef INT32_MIN -# define INT32_MIN -2147483648 -#endif -#ifndef UINT32_MAX -# define UINT32_MAX 4294967295U -#endif -/* Certain compatibility updates to VC++ introduce the `cstdint' - * header, which defines the INT*_C macros. On default installs they - * are absent. */ -#ifndef INT8_C -# define INT8_C(C) C##i8 -#endif -#ifndef UINT8_C -# define UINT8_C(C) C##ui8 -#endif -#ifndef INT16_C -# define INT16_C(C) C##i16 -#endif -#ifndef UINT16_C -# define UINT16_C(C) C##ui16 -#endif -#ifndef INT32_C -# define INT32_C(C) C##i32 -#endif -#ifndef UINT32_C -# define UINT32_C(C) C##ui32 -#endif -#ifndef INT64_C -# define INT64_C(C) C##i64 -#endif -#ifndef UINT64_C -# define UINT64_C(C) C##ui64 -#endif -#endif /* _MSC_VER */ - -/* Set defaults for constants which we cannot find. */ -#if !defined(INT64_MAX) -# define INT64_MAX 9223372036854775807LL -#endif -#if !defined(INT64_MIN) -# define INT64_MIN ((-INT64_MAX)-1) -#endif -#if !defined(UINT64_MAX) -# define UINT64_MAX 0xffffffffffffffffULL -#endif - -#if __GNUC__ > 3 -#define END_WITH_NULL __attribute__((sentinel)) -#else -#define END_WITH_NULL -#endif - -#ifndef HUGE_VALF -#define HUGE_VALF (float)HUGE_VAL -#endif - -#endif /* SUPPORT_DATATYPES_H */ diff --git a/include/llvm/System/DataTypes.h.in b/include/llvm/System/DataTypes.h.in deleted file mode 100644 index 6537f3010fae..000000000000 --- a/include/llvm/System/DataTypes.h.in +++ /dev/null @@ -1,111 +0,0 @@ -/*===-- include/System/DataTypes.h - Define fixed size types -----*- C -*-===*\ -|* *| -|* The LLVM Compiler Infrastructure *| -|* *| -|* This file is distributed under the University of Illinois Open Source *| -|* License. See LICENSE.TXT for details. *| -|* *| -|*===----------------------------------------------------------------------===*| -|* *| -|* This file contains definitions to figure out the size of _HOST_ data types.*| -|* This file is important because different host OS's define different macros,*| -|* which makes portability tough. This file exports the following *| -|* definitions: *| -|* *| -|* [u]int(32|64)_t : typedefs for signed and unsigned 32/64 bit system types*| -|* [U]INT(8|16|32|64)_(MIN|MAX) : Constants for the min and max values. *| -|* *| -|* No library is required when using these functions. *| -|* *| -|*===----------------------------------------------------------------------===*/ - -/* Please leave this file C-compatible. */ - -#ifndef SUPPORT_DATATYPES_H -#define SUPPORT_DATATYPES_H - -#undef HAVE_SYS_TYPES_H -#undef HAVE_INTTYPES_H -#undef HAVE_STDINT_H -#undef HAVE_UINT64_T -#undef HAVE_U_INT64_T - -#ifdef __cplusplus -#include -#else -#include -#endif - -/* Note that this header's correct operation depends on __STDC_LIMIT_MACROS - being defined. We would define it here, but in order to prevent Bad Things - happening when system headers or C++ STL headers include stdint.h before we - define it here, we define it on the g++ command line (in Makefile.rules). */ -#if !defined(__STDC_LIMIT_MACROS) -# error "Must #define __STDC_LIMIT_MACROS before #including System/DataTypes.h" -#endif - -#if !defined(__STDC_CONSTANT_MACROS) -# error "Must #define __STDC_CONSTANT_MACROS before " \ - "#including System/DataTypes.h" -#endif - -/* Note that includes , if this is a C99 system. */ -#ifdef HAVE_SYS_TYPES_H -#include -#endif - -#ifdef HAVE_INTTYPES_H -#include -#endif - -#ifdef HAVE_STDINT_H -#include -#endif - -#ifdef _AIX -#include "llvm/System/AIXDataTypesFix.h" -#endif - -/* Handle incorrect definition of uint64_t as u_int64_t */ -#ifndef HAVE_UINT64_T -#ifdef HAVE_U_INT64_T -typedef u_int64_t uint64_t; -#else -# error "Don't have a definition for uint64_t on this platform" -#endif -#endif - -#ifdef _OpenBSD_ -#define INT8_MAX 127 -#define INT8_MIN -128 -#define UINT8_MAX 255 -#define INT16_MAX 32767 -#define INT16_MIN -32768 -#define UINT16_MAX 65535 -#define INT32_MAX 2147483647 -#define INT32_MIN -2147483648 -#define UINT32_MAX 4294967295U -#endif - -/* Set defaults for constants which we cannot find. */ -#if !defined(INT64_MAX) -# define INT64_MAX 9223372036854775807LL -#endif -#if !defined(INT64_MIN) -# define INT64_MIN ((-INT64_MAX)-1) -#endif -#if !defined(UINT64_MAX) -# define UINT64_MAX 0xffffffffffffffffULL -#endif - -#if __GNUC__ > 3 -#define END_WITH_NULL __attribute__((sentinel)) -#else -#define END_WITH_NULL -#endif - -#ifndef HUGE_VALF -#define HUGE_VALF (float)HUGE_VAL -#endif - -#endif /* SUPPORT_DATATYPES_H */ diff --git a/include/llvm/System/Disassembler.h b/include/llvm/System/Disassembler.h deleted file mode 100644 index e11e792de85a..000000000000 --- a/include/llvm/System/Disassembler.h +++ /dev/null @@ -1,35 +0,0 @@ -//===- llvm/Support/Disassembler.h ------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the necessary glue to call external disassembler -// libraries. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SYSTEM_DISASSEMBLER_H -#define LLVM_SYSTEM_DISASSEMBLER_H - -#include "llvm/System/DataTypes.h" -#include - -namespace llvm { -namespace sys { - -/// This function returns true, if there is possible to use some external -/// disassembler library. False otherwise. -bool hasDisassembler(); - -/// This function provides some "glue" code to call external disassembler -/// libraries. -std::string disassembleBuffer(uint8_t* start, size_t length, uint64_t pc = 0); - -} -} - -#endif // LLVM_SYSTEM_DISASSEMBLER_H diff --git a/include/llvm/System/DynamicLibrary.h b/include/llvm/System/DynamicLibrary.h deleted file mode 100644 index 745b8f8b5b4b..000000000000 --- a/include/llvm/System/DynamicLibrary.h +++ /dev/null @@ -1,86 +0,0 @@ -//===-- llvm/System/DynamicLibrary.h - Portable Dynamic Library -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares the sys::DynamicLibrary class. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SYSTEM_DYNAMIC_LIBRARY_H -#define LLVM_SYSTEM_DYNAMIC_LIBRARY_H - -#include - -namespace llvm { -namespace sys { - - /// This class provides a portable interface to dynamic libraries which also - /// might be known as shared libraries, shared objects, dynamic shared - /// objects, or dynamic link libraries. Regardless of the terminology or the - /// operating system interface, this class provides a portable interface that - /// allows dynamic libraries to be loaded and searched for externally - /// defined symbols. This is typically used to provide "plug-in" support. - /// It also allows for symbols to be defined which don't live in any library, - /// but rather the main program itself, useful on Windows where the main - /// executable cannot be searched. - class DynamicLibrary { - DynamicLibrary(); // DO NOT IMPLEMENT - public: - /// This function allows a library to be loaded without instantiating a - /// DynamicLibrary object. Consequently, it is marked as being permanent - /// and will only be unloaded when the program terminates. This returns - /// false on success or returns true and fills in *ErrMsg on failure. - /// @brief Open a dynamic library permanently. - /// - /// NOTE: This function is not thread safe. - /// - static bool LoadLibraryPermanently(const char *filename, - std::string *ErrMsg = 0); - - /// This function will search through all previously loaded dynamic - /// libraries for the symbol \p symbolName. If it is found, the addressof - /// that symbol is returned. If not, null is returned. Note that this will - /// search permanently loaded libraries (LoadLibraryPermanently) as well - /// as ephemerally loaded libraries (constructors). - /// @throws std::string on error. - /// @brief Search through libraries for address of a symbol - /// - /// NOTE: This function is not thread safe. - /// - static void *SearchForAddressOfSymbol(const char *symbolName); - - /// @brief Convenience function for C++ophiles. - /// - /// NOTE: This function is not thread safe. - /// - static void *SearchForAddressOfSymbol(const std::string &symbolName) { - return SearchForAddressOfSymbol(symbolName.c_str()); - } - - /// This functions permanently adds the symbol \p symbolName with the - /// value \p symbolValue. These symbols are searched before any - /// libraries. - /// @brief Add searchable symbol/value pair. - /// - /// NOTE: This function is not thread safe. - /// - static void AddSymbol(const char *symbolName, void *symbolValue); - - /// @brief Convenience function for C++ophiles. - /// - /// NOTE: This function is not thread safe. - /// - static void AddSymbol(const std::string &symbolName, void *symbolValue) { - AddSymbol(symbolName.c_str(), symbolValue); - } - }; - -} // End sys namespace -} // End llvm namespace - -#endif // LLVM_SYSTEM_DYNAMIC_LIBRARY_H diff --git a/include/llvm/System/Errno.h b/include/llvm/System/Errno.h deleted file mode 100644 index 6e292ba62651..000000000000 --- a/include/llvm/System/Errno.h +++ /dev/null @@ -1,34 +0,0 @@ -//===- llvm/System/Errno.h - Portable+convenient errno handling -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares some portable and convenient functions to deal with errno. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SYSTEM_ERRNO_H -#define LLVM_SYSTEM_ERRNO_H - -#include - -namespace llvm { -namespace sys { - -/// Returns a string representation of the errno value, using whatever -/// thread-safe variant of strerror() is available. Be sure to call this -/// immediately after the function that set errno, or errno may have been -/// overwritten by an intervening call. -std::string StrError(); - -/// Like the no-argument version above, but uses \p errnum instead of errno. -std::string StrError(int errnum); - -} // namespace sys -} // namespace llvm - -#endif // LLVM_SYSTEM_ERRNO_H diff --git a/include/llvm/System/Host.h b/include/llvm/System/Host.h deleted file mode 100644 index 4fbf5c177c6e..000000000000 --- a/include/llvm/System/Host.h +++ /dev/null @@ -1,66 +0,0 @@ -//===- llvm/System/Host.h - Host machine characteristics --------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Methods for querying the nature of the host machine. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SYSTEM_HOST_H -#define LLVM_SYSTEM_HOST_H - -#include "llvm/ADT/StringMap.h" -#include - -namespace llvm { -namespace sys { - - inline bool isLittleEndianHost() { - union { - int i; - char c; - }; - i = 1; - return c; - } - - inline bool isBigEndianHost() { - return !isLittleEndianHost(); - } - - /// getHostTriple() - Return the target triple of the running - /// system. - /// - /// The target triple is a string in the format of: - /// CPU_TYPE-VENDOR-OPERATING_SYSTEM - /// or - /// CPU_TYPE-VENDOR-KERNEL-OPERATING_SYSTEM - std::string getHostTriple(); - - /// getHostCPUName - Get the LLVM name for the host CPU. The particular format - /// of the name is target dependent, and suitable for passing as -mcpu to the - /// target which matches the host. - /// - /// \return - The host CPU name, or empty if the CPU could not be determined. - std::string getHostCPUName(); - - /// getHostCPUFeatures - Get the LLVM names for the host CPU features. - /// The particular format of the names are target dependent, and suitable for - /// passing as -mattr to the target which matches the host. - /// - /// \param Features - A string mapping feature names to either - /// true (if enabled) or false (if disabled). This routine makes no guarantees - /// about exactly which features may appear in this map, except that they are - /// all valid LLVM feature names. - /// - /// \return - True on success. - bool getHostCPUFeatures(StringMap &Features); -} -} - -#endif diff --git a/include/llvm/System/IncludeFile.h b/include/llvm/System/IncludeFile.h deleted file mode 100644 index 3268ea225f51..000000000000 --- a/include/llvm/System/IncludeFile.h +++ /dev/null @@ -1,79 +0,0 @@ -//===- llvm/System/IncludeFile.h - Ensure Linking Of Library ---*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the FORCE_DEFINING_FILE_TO_BE_LINKED and DEFINE_FILE_FOR -// macros. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SYSTEM_INCLUDEFILE_H -#define LLVM_SYSTEM_INCLUDEFILE_H - -/// This macro is the public interface that IncludeFile.h exports. This gives -/// us the option to implement the "link the definition" capability in any -/// manner that we choose. All header files that depend on a specific .cpp -/// file being linked at run time should use this macro instead of the -/// IncludeFile class directly. -/// -/// For example, foo.h would use:
      -/// FORCE_DEFINING_FILE_TO_BE_LINKED(foo)
      -/// -/// And, foo.cp would use:
      -/// DEFINING_FILE_FOR(foo)
      -#ifdef __GNUC__ -// If the `used' attribute is available, use it to create a variable -// with an initializer that will force the linking of the defining file. -#define FORCE_DEFINING_FILE_TO_BE_LINKED(name) \ - namespace llvm { \ - extern const char name ## LinkVar; \ - __attribute__((used)) static const char *const name ## LinkObj = \ - &name ## LinkVar; \ - } -#else -// Otherwise use a constructor call. -#define FORCE_DEFINING_FILE_TO_BE_LINKED(name) \ - namespace llvm { \ - extern const char name ## LinkVar; \ - static const IncludeFile name ## LinkObj ( &name ## LinkVar ); \ - } -#endif - -/// This macro is the counterpart to FORCE_DEFINING_FILE_TO_BE_LINKED. It should -/// be used in a .cpp file to define the name referenced in a header file that -/// will cause linkage of the .cpp file. It should only be used at extern level. -#define DEFINING_FILE_FOR(name) \ - namespace llvm { const char name ## LinkVar = 0; } - -namespace llvm { - -/// This class is used in the implementation of FORCE_DEFINING_FILE_TO_BE_LINKED -/// macro to make sure that the implementation of a header file is included -/// into a tool that uses the header. This is solely -/// to overcome problems linking .a files and not getting the implementation -/// of compilation units we need. This is commonly an issue with the various -/// Passes but also occurs elsewhere in LLVM. We like to use .a files because -/// they link faster and provide the smallest executables. However, sometimes -/// those executables are too small, if the program doesn't reference something -/// that might be needed, especially by a loaded share object. This little class -/// helps to resolve that problem. The basic strategy is to use this class in -/// a header file and pass the address of a variable to the constructor. If the -/// variable is defined in the header file's corresponding .cpp file then all -/// tools/libraries that \#include the header file will require the .cpp as -/// well. -/// For example:
      -/// extern int LinkMyCodeStub;
      -/// static IncludeFile LinkMyModule(&LinkMyCodeStub);
      -/// @brief Class to ensure linking of corresponding object file. -struct IncludeFile { - explicit IncludeFile(const void *); -}; - -} - -#endif diff --git a/include/llvm/System/LICENSE.TXT b/include/llvm/System/LICENSE.TXT deleted file mode 100644 index f569da205289..000000000000 --- a/include/llvm/System/LICENSE.TXT +++ /dev/null @@ -1,6 +0,0 @@ -LLVM System Interface Library -------------------------------------------------------------------------------- -The LLVM System Interface Library is licensed under the Illinois Open Source -License and has the following additional copyright: - -Copyright (C) 2004 eXtensible Systems, Inc. diff --git a/include/llvm/System/Memory.h b/include/llvm/System/Memory.h deleted file mode 100644 index 2dd36e8ab147..000000000000 --- a/include/llvm/System/Memory.h +++ /dev/null @@ -1,96 +0,0 @@ -//===- llvm/System/Memory.h - Memory Support --------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares the llvm::sys::Memory class. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SYSTEM_MEMORY_H -#define LLVM_SYSTEM_MEMORY_H - -#include "llvm/System/DataTypes.h" -#include - -namespace llvm { -namespace sys { - - /// This class encapsulates the notion of a memory block which has an address - /// and a size. It is used by the Memory class (a friend) as the result of - /// various memory allocation operations. - /// @see Memory - /// @brief Memory block abstraction. - class MemoryBlock { - public: - MemoryBlock() : Address(0), Size(0) { } - MemoryBlock(void *addr, size_t size) : Address(addr), Size(size) { } - void *base() const { return Address; } - size_t size() const { return Size; } - private: - void *Address; ///< Address of first byte of memory area - size_t Size; ///< Size, in bytes of the memory area - friend class Memory; - }; - - /// This class provides various memory handling functions that manipulate - /// MemoryBlock instances. - /// @since 1.4 - /// @brief An abstraction for memory operations. - class Memory { - public: - /// This method allocates a block of Read/Write/Execute memory that is - /// suitable for executing dynamically generated code (e.g. JIT). An - /// attempt to allocate \p NumBytes bytes of virtual memory is made. - /// \p NearBlock may point to an existing allocation in which case - /// an attempt is made to allocate more memory near the existing block. - /// - /// On success, this returns a non-null memory block, otherwise it returns - /// a null memory block and fills in *ErrMsg. - /// - /// @brief Allocate Read/Write/Execute memory. - static MemoryBlock AllocateRWX(size_t NumBytes, - const MemoryBlock *NearBlock, - std::string *ErrMsg = 0); - - /// This method releases a block of Read/Write/Execute memory that was - /// allocated with the AllocateRWX method. It should not be used to - /// release any memory block allocated any other way. - /// - /// On success, this returns false, otherwise it returns true and fills - /// in *ErrMsg. - /// @brief Release Read/Write/Execute memory. - static bool ReleaseRWX(MemoryBlock &block, std::string *ErrMsg = 0); - - - /// InvalidateInstructionCache - Before the JIT can run a block of code - /// that has been emitted it must invalidate the instruction cache on some - /// platforms. - static void InvalidateInstructionCache(const void *Addr, size_t Len); - - /// setExecutable - Before the JIT can run a block of code, it has to be - /// given read and executable privilege. Return true if it is already r-x - /// or the system is able to change its previlege. - static bool setExecutable (MemoryBlock &M, std::string *ErrMsg = 0); - - /// setWritable - When adding to a block of code, the JIT may need - /// to mark a block of code as RW since the protections are on page - /// boundaries, and the JIT internal allocations are not page aligned. - static bool setWritable (MemoryBlock &M, std::string *ErrMsg = 0); - - /// setRangeExecutable - Mark the page containing a range of addresses - /// as executable. - static bool setRangeExecutable(const void *Addr, size_t Size); - - /// setRangeWritable - Mark the page containing a range of addresses - /// as writable. - static bool setRangeWritable(const void *Addr, size_t Size); - }; -} -} - -#endif diff --git a/include/llvm/System/Mutex.h b/include/llvm/System/Mutex.h deleted file mode 100644 index 71d10067c303..000000000000 --- a/include/llvm/System/Mutex.h +++ /dev/null @@ -1,154 +0,0 @@ -//===- llvm/System/Mutex.h - Mutex Operating System Concept -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares the llvm::sys::Mutex class. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SYSTEM_MUTEX_H -#define LLVM_SYSTEM_MUTEX_H - -#include "llvm/System/Threading.h" -#include - -namespace llvm -{ - namespace sys - { - /// @brief Platform agnostic Mutex class. - class MutexImpl - { - /// @name Constructors - /// @{ - public: - - /// Initializes the lock but doesn't acquire it. if \p recursive is set - /// to false, the lock will not be recursive which makes it cheaper but - /// also more likely to deadlock (same thread can't acquire more than - /// once). - /// @brief Default Constructor. - explicit MutexImpl(bool recursive = true); - - /// Releases and removes the lock - /// @brief Destructor - ~MutexImpl(); - - /// @} - /// @name Methods - /// @{ - public: - - /// Attempts to unconditionally acquire the lock. If the lock is held by - /// another thread, this method will wait until it can acquire the lock. - /// @returns false if any kind of error occurs, true otherwise. - /// @brief Unconditionally acquire the lock. - bool acquire(); - - /// Attempts to release the lock. If the lock is held by the current - /// thread, the lock is released allowing other threads to acquire the - /// lock. - /// @returns false if any kind of error occurs, true otherwise. - /// @brief Unconditionally release the lock. - bool release(); - - /// Attempts to acquire the lock without blocking. If the lock is not - /// available, this function returns false quickly (without blocking). If - /// the lock is available, it is acquired. - /// @returns false if any kind of error occurs or the lock is not - /// available, true otherwise. - /// @brief Try to acquire the lock. - bool tryacquire(); - - //@} - /// @name Platform Dependent Data - /// @{ - private: - void* data_; ///< We don't know what the data will be - - /// @} - /// @name Do Not Implement - /// @{ - private: - MutexImpl(const MutexImpl & original); - void operator=(const MutexImpl &); - /// @} - }; - - - /// SmartMutex - A mutex with a compile time constant parameter that - /// indicates whether this mutex should become a no-op when we're not - /// running in multithreaded mode. - template - class SmartMutex : public MutexImpl { - unsigned acquired; - bool recursive; - public: - explicit SmartMutex(bool rec = true) : - MutexImpl(rec), acquired(0), recursive(rec) { } - - bool acquire() { - if (!mt_only || llvm_is_multithreaded()) { - return MutexImpl::acquire(); - } else { - // Single-threaded debugging code. This would be racy in - // multithreaded mode, but provides not sanity checks in single - // threaded mode. - assert((recursive || acquired == 0) && "Lock already acquired!!"); - ++acquired; - return true; - } - } - - bool release() { - if (!mt_only || llvm_is_multithreaded()) { - return MutexImpl::release(); - } else { - // Single-threaded debugging code. This would be racy in - // multithreaded mode, but provides not sanity checks in single - // threaded mode. - assert(((recursive && acquired) || (acquired == 1)) && - "Lock not acquired before release!"); - --acquired; - return true; - } - } - - bool tryacquire() { - if (!mt_only || llvm_is_multithreaded()) - return MutexImpl::tryacquire(); - else return true; - } - - private: - SmartMutex(const SmartMutex & original); - void operator=(const SmartMutex &); - }; - - /// Mutex - A standard, always enforced mutex. - typedef SmartMutex Mutex; - - template - class SmartScopedLock { - SmartMutex& mtx; - - public: - SmartScopedLock(SmartMutex& m) : mtx(m) { - mtx.acquire(); - } - - ~SmartScopedLock() { - mtx.release(); - } - }; - - typedef SmartScopedLock ScopedLock; - } -} - -#endif diff --git a/include/llvm/System/Path.h b/include/llvm/System/Path.h deleted file mode 100644 index 23b18d47145a..000000000000 --- a/include/llvm/System/Path.h +++ /dev/null @@ -1,716 +0,0 @@ -//===- llvm/System/Path.h - Path Operating System Concept -------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares the llvm::sys::Path class. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SYSTEM_PATH_H -#define LLVM_SYSTEM_PATH_H - -#include "llvm/ADT/StringRef.h" -#include "llvm/System/TimeValue.h" -#include -#include -#include - -namespace llvm { -namespace sys { - - /// This structure provides basic file system information about a file. It - /// is patterned after the stat(2) Unix operating system call but made - /// platform independent and eliminates many of the unix-specific fields. - /// However, to support llvm-ar, the mode, user, and group fields are - /// retained. These pertain to unix security and may not have a meaningful - /// value on non-Unix platforms. However, the other fields should - /// always be applicable on all platforms. The structure is filled in by - /// the PathWithStatus class. - /// @brief File status structure - class FileStatus { - public: - uint64_t fileSize; ///< Size of the file in bytes - TimeValue modTime; ///< Time of file's modification - uint32_t mode; ///< Mode of the file, if applicable - uint32_t user; ///< User ID of owner, if applicable - uint32_t group; ///< Group ID of owner, if applicable - uint64_t uniqueID; ///< A number to uniquely ID this file - bool isDir : 1; ///< True if this is a directory. - bool isFile : 1; ///< True if this is a file. - - FileStatus() : fileSize(0), modTime(0,0), mode(0777), user(999), - group(999), uniqueID(0), isDir(false), isFile(false) { } - - TimeValue getTimestamp() const { return modTime; } - uint64_t getSize() const { return fileSize; } - uint32_t getMode() const { return mode; } - uint32_t getUser() const { return user; } - uint32_t getGroup() const { return group; } - uint64_t getUniqueID() const { return uniqueID; } - }; - - /// This class provides an abstraction for the path to a file or directory - /// in the operating system's filesystem and provides various basic operations - /// on it. Note that this class only represents the name of a path to a file - /// or directory which may or may not be valid for a given machine's file - /// system. The class is patterned after the java.io.File class with various - /// extensions and several omissions (not relevant to LLVM). A Path object - /// ensures that the path it encapsulates is syntactically valid for the - /// operating system it is running on but does not ensure correctness for - /// any particular file system. That is, a syntactically valid path might - /// specify path components that do not exist in the file system and using - /// such a Path to act on the file system could produce errors. There is one - /// invalid Path value which is permitted: the empty path. The class should - /// never allow a syntactically invalid non-empty path name to be assigned. - /// Empty paths are required in order to indicate an error result in some - /// situations. If the path is empty, the isValid operation will return - /// false. All operations will fail if isValid is false. Operations that - /// change the path will either return false if it would cause a syntactically - /// invalid path name (in which case the Path object is left unchanged) or - /// throw an std::string exception indicating the error. The methods are - /// grouped into four basic categories: Path Accessors (provide information - /// about the path without accessing disk), Disk Accessors (provide - /// information about the underlying file or directory), Path Mutators - /// (change the path information, not the disk), and Disk Mutators (change - /// the disk file/directory referenced by the path). The Disk Mutator methods - /// all have the word "disk" embedded in their method name to reinforce the - /// notion that the operation modifies the file system. - /// @since 1.4 - /// @brief An abstraction for operating system paths. - class Path { - /// @name Constructors - /// @{ - public: - /// Construct a path to the root directory of the file system. The root - /// directory is a top level directory above which there are no more - /// directories. For example, on UNIX, the root directory is /. On Windows - /// it is C:\. Other operating systems may have different notions of - /// what the root directory is or none at all. In that case, a consistent - /// default root directory will be used. - static Path GetRootDirectory(); - - /// Construct a path to a unique temporary directory that is created in - /// a "standard" place for the operating system. The directory is - /// guaranteed to be created on exit from this function. If the directory - /// cannot be created, the function will throw an exception. - /// @returns an invalid path (empty) on error - /// @param ErrMsg Optional place for an error message if an error occurs - /// @brief Constrct a path to an new, unique, existing temporary - /// directory. - static Path GetTemporaryDirectory(std::string* ErrMsg = 0); - - /// Construct a vector of sys::Path that contains the "standard" system - /// library paths suitable for linking into programs. This function *must* - /// return the value of LLVM_LIB_SEARCH_PATH as the first item in \p Paths - /// if that environment variable is set and it references a directory. - /// @brief Construct a path to the system library directory - static void GetSystemLibraryPaths(std::vector& Paths); - - /// Construct a vector of sys::Path that contains the "standard" bitcode - /// library paths suitable for linking into an llvm program. This function - /// *must* return the value of LLVM_LIB_SEARCH_PATH as well as the value - /// of LLVM_LIBDIR. It also must provide the System library paths as - /// returned by GetSystemLibraryPaths. - /// @see GetSystemLibraryPaths - /// @brief Construct a list of directories in which bitcode could be - /// found. - static void GetBitcodeLibraryPaths(std::vector& Paths); - - /// Find the path to a library using its short name. Use the system - /// dependent library paths to locate the library. - /// @brief Find a library. - static Path FindLibrary(std::string& short_name); - - /// Construct a path to the default LLVM configuration directory. The - /// implementation must ensure that this is a well-known (same on many - /// systems) directory in which llvm configuration files exist. For - /// example, on Unix, the /etc/llvm directory has been selected. - /// @brief Construct a path to the default LLVM configuration directory - static Path GetLLVMDefaultConfigDir(); - - /// Construct a path to the LLVM installed configuration directory. The - /// implementation must ensure that this refers to the "etc" directory of - /// the LLVM installation. This is the location where configuration files - /// will be located for a particular installation of LLVM on a machine. - /// @brief Construct a path to the LLVM installed configuration directory - static Path GetLLVMConfigDir(); - - /// Construct a path to the current user's home directory. The - /// implementation must use an operating system specific mechanism for - /// determining the user's home directory. For example, the environment - /// variable "HOME" could be used on Unix. If a given operating system - /// does not have the concept of a user's home directory, this static - /// constructor must provide the same result as GetRootDirectory. - /// @brief Construct a path to the current user's "home" directory - static Path GetUserHomeDirectory(); - - /// Construct a path to the current directory for the current process. - /// @returns The current working directory. - /// @brief Returns the current working directory. - static Path GetCurrentDirectory(); - - /// Return the suffix commonly used on file names that contain a shared - /// object, shared archive, or dynamic link library. Such files are - /// linked at runtime into a process and their code images are shared - /// between processes. - /// @returns The dynamic link library suffix for the current platform. - /// @brief Return the dynamic link library suffix. - static StringRef GetDLLSuffix(); - - /// GetMainExecutable - Return the path to the main executable, given the - /// value of argv[0] from program startup and the address of main itself. - /// In extremis, this function may fail and return an empty path. - static Path GetMainExecutable(const char *argv0, void *MainAddr); - - /// This is one of the very few ways in which a path can be constructed - /// with a syntactically invalid name. The only *legal* invalid name is an - /// empty one. Other invalid names are not permitted. Empty paths are - /// provided so that they can be used to indicate null or error results in - /// other lib/System functionality. - /// @brief Construct an empty (and invalid) path. - Path() : path() {} - Path(const Path &that) : path(that.path) {} - - /// This constructor will accept a char* or std::string as a path. No - /// checking is done on this path to determine if it is valid. To - /// determine validity of the path, use the isValid method. - /// @param p The path to assign. - /// @brief Construct a Path from a string. - explicit Path(StringRef p); - - /// This constructor will accept a character range as a path. No checking - /// is done on this path to determine if it is valid. To determine - /// validity of the path, use the isValid method. - /// @param StrStart A pointer to the first character of the path name - /// @param StrLen The length of the path name at StrStart - /// @brief Construct a Path from a string. - Path(const char *StrStart, unsigned StrLen); - - /// @} - /// @name Operators - /// @{ - public: - /// Makes a copy of \p that to \p this. - /// @returns \p this - /// @brief Assignment Operator - Path &operator=(const Path &that) { - path = that.path; - return *this; - } - - /// Makes a copy of \p that to \p this. - /// @param that A StringRef denoting the path - /// @returns \p this - /// @brief Assignment Operator - Path &operator=(StringRef that); - - /// Compares \p this Path with \p that Path for equality. - /// @returns true if \p this and \p that refer to the same thing. - /// @brief Equality Operator - bool operator==(const Path &that) const; - - /// Compares \p this Path with \p that Path for inequality. - /// @returns true if \p this and \p that refer to different things. - /// @brief Inequality Operator - bool operator!=(const Path &that) const { return !(*this == that); } - - /// Determines if \p this Path is less than \p that Path. This is required - /// so that Path objects can be placed into ordered collections (e.g. - /// std::map). The comparison is done lexicographically as defined by - /// the std::string::compare method. - /// @returns true if \p this path is lexicographically less than \p that. - /// @brief Less Than Operator - bool operator<(const Path& that) const; - - /// @} - /// @name Path Accessors - /// @{ - public: - /// This function will use an operating system specific algorithm to - /// determine if the current value of \p this is a syntactically valid - /// path name for the operating system. The path name does not need to - /// exist, validity is simply syntactical. Empty paths are always invalid. - /// @returns true iff the path name is syntactically legal for the - /// host operating system. - /// @brief Determine if a path is syntactically valid or not. - bool isValid() const; - - /// This function determines if the contents of the path name are empty. - /// That is, the path name has a zero length. This does NOT determine if - /// if the file is empty. To get the length of the file itself, Use the - /// PathWithStatus::getFileStatus() method and then the getSize() method - /// on the returned FileStatus object. - /// @returns true iff the path is empty. - /// @brief Determines if the path name is empty (invalid). - bool isEmpty() const { return path.empty(); } - - /// This function returns the last component of the path name. The last - /// component is the file or directory name occuring after the last - /// directory separator. If no directory separator is present, the entire - /// path name is returned (i.e. same as toString). - /// @returns StringRef containing the last component of the path name. - /// @brief Returns the last component of the path name. - StringRef getLast() const; - - /// This function strips off the path and suffix of the file or directory - /// name and returns just the basename. For example /a/foo.bar would cause - /// this function to return "foo". - /// @returns StringRef containing the basename of the path - /// @brief Get the base name of the path - StringRef getBasename() const; - - /// This function strips off the suffix of the path beginning with the - /// path separator ('/' on Unix, '\' on Windows) and returns the result. - StringRef getDirname() const; - - /// This function strips off the path and basename(up to and - /// including the last dot) of the file or directory name and - /// returns just the suffix. For example /a/foo.bar would cause - /// this function to return "bar". - /// @returns StringRef containing the suffix of the path - /// @brief Get the suffix of the path - StringRef getSuffix() const; - - /// Obtain a 'C' string for the path name. - /// @returns a 'C' string containing the path name. - /// @brief Returns the path as a C string. - const char *c_str() const { return path.c_str(); } - const std::string &str() const { return path; } - - - /// size - Return the length in bytes of this path name. - size_t size() const { return path.size(); } - - /// empty - Returns true if the path is empty. - unsigned empty() const { return path.empty(); } - - /// @} - /// @name Disk Accessors - /// @{ - public: - /// This function determines if the path name is absolute, as opposed to - /// relative. - /// @brief Determine if the path is absolute. - bool isAbsolute() const; - - /// This function determines if the path name is absolute, as opposed to - /// relative. - /// @brief Determine if the path is absolute. - static bool isAbsolute(const char *NameStart, unsigned NameLen); - - /// This function opens the file associated with the path name provided by - /// the Path object and reads its magic number. If the magic number at the - /// start of the file matches \p magic, true is returned. In all other - /// cases (file not found, file not accessible, etc.) it returns false. - /// @returns true if the magic number of the file matches \p magic. - /// @brief Determine if file has a specific magic number - bool hasMagicNumber(StringRef magic) const; - - /// This function retrieves the first \p len bytes of the file associated - /// with \p this. These bytes are returned as the "magic number" in the - /// \p Magic parameter. - /// @returns true if the Path is a file and the magic number is retrieved, - /// false otherwise. - /// @brief Get the file's magic number. - bool getMagicNumber(std::string& Magic, unsigned len) const; - - /// This function determines if the path name in the object references an - /// archive file by looking at its magic number. - /// @returns true if the file starts with the magic number for an archive - /// file. - /// @brief Determine if the path references an archive file. - bool isArchive() const; - - /// This function determines if the path name in the object references an - /// LLVM Bitcode file by looking at its magic number. - /// @returns true if the file starts with the magic number for LLVM - /// bitcode files. - /// @brief Determine if the path references a bitcode file. - bool isBitcodeFile() const; - - /// This function determines if the path name in the object references a - /// native Dynamic Library (shared library, shared object) by looking at - /// the file's magic number. The Path object must reference a file, not a - /// directory. - /// @returns true if the file starts with the magic number for a native - /// shared library. - /// @brief Determine if the path references a dynamic library. - bool isDynamicLibrary() const; - - /// This function determines if the path name references an existing file - /// or directory in the file system. - /// @returns true if the pathname references an existing file or - /// directory. - /// @brief Determines if the path is a file or directory in - /// the file system. - bool exists() const; - - /// This function determines if the path name refences an - /// existing directory. - /// @returns true if the pathname references an existing directory. - /// @brief Determins if the path is a directory in the file system. - bool isDirectory() const; - - /// This function determines if the path name references a readable file - /// or directory in the file system. This function checks for - /// the existence and readability (by the current program) of the file - /// or directory. - /// @returns true if the pathname references a readable file. - /// @brief Determines if the path is a readable file or directory - /// in the file system. - bool canRead() const; - - /// This function determines if the path name references a writable file - /// or directory in the file system. This function checks for the - /// existence and writability (by the current program) of the file or - /// directory. - /// @returns true if the pathname references a writable file. - /// @brief Determines if the path is a writable file or directory - /// in the file system. - bool canWrite() const; - - /// This function checks that what we're trying to work only on a regular file. - /// Check for things like /dev/null, any block special file, - /// or other things that aren't "regular" regular files. - /// @returns true if the file is S_ISREG. - /// @brief Determines if the file is a regular file - bool isRegularFile() const; - - /// This function determines if the path name references an executable - /// file in the file system. This function checks for the existence and - /// executability (by the current program) of the file. - /// @returns true if the pathname references an executable file. - /// @brief Determines if the path is an executable file in the file - /// system. - bool canExecute() const; - - /// This function builds a list of paths that are the names of the - /// files and directories in a directory. - /// @returns true if an error occurs, true otherwise - /// @brief Build a list of directory's contents. - bool getDirectoryContents( - std::set &paths, ///< The resulting list of file & directory names - std::string* ErrMsg ///< Optional place to return an error message. - ) const; - - /// @} - /// @name Path Mutators - /// @{ - public: - /// The path name is cleared and becomes empty. This is an invalid - /// path name but is the *only* invalid path name. This is provided - /// so that path objects can be used to indicate the lack of a - /// valid path being found. - /// @brief Make the path empty. - void clear() { path.clear(); } - - /// This method sets the Path object to \p unverified_path. This can fail - /// if the \p unverified_path does not pass the syntactic checks of the - /// isValid() method. If verification fails, the Path object remains - /// unchanged and false is returned. Otherwise true is returned and the - /// Path object takes on the path value of \p unverified_path - /// @returns true if the path was set, false otherwise. - /// @param unverified_path The path to be set in Path object. - /// @brief Set a full path from a StringRef - bool set(StringRef unverified_path); - - /// One path component is removed from the Path. If only one component is - /// present in the path, the Path object becomes empty. If the Path object - /// is empty, no change is made. - /// @returns false if the path component could not be removed. - /// @brief Removes the last directory component of the Path. - bool eraseComponent(); - - /// The \p component is added to the end of the Path if it is a legal - /// name for the operating system. A directory separator will be added if - /// needed. - /// @returns false if the path component could not be added. - /// @brief Appends one path component to the Path. - bool appendComponent(StringRef component); - - /// A period and the \p suffix are appended to the end of the pathname. - /// The precondition for this function is that the Path reference a file - /// name (i.e. isFile() returns true). If the Path is not a file, no - /// action is taken and the function returns false. If the path would - /// become invalid for the host operating system, false is returned. - /// @returns false if the suffix could not be added, true if it was. - /// @brief Adds a period and the \p suffix to the end of the pathname. - bool appendSuffix(StringRef suffix); - - /// The suffix of the filename is erased. The suffix begins with and - /// includes the last . character in the filename after the last directory - /// separator and extends until the end of the name. If no . character is - /// after the last directory separator, then the file name is left - /// unchanged (i.e. it was already without a suffix) but the function - /// returns false. - /// @returns false if there was no suffix to remove, true otherwise. - /// @brief Remove the suffix from a path name. - bool eraseSuffix(); - - /// The current Path name is made unique in the file system. Upon return, - /// the Path will have been changed to make a unique file in the file - /// system or it will not have been changed if the current path name is - /// already unique. - /// @throws std::string if an unrecoverable error occurs. - /// @brief Make the current path name unique in the file system. - bool makeUnique( bool reuse_current /*= true*/, std::string* ErrMsg ); - - /// The current Path name is made absolute by prepending the - /// current working directory if necessary. - void makeAbsolute(); - - /// @} - /// @name Disk Mutators - /// @{ - public: - /// This method attempts to make the file referenced by the Path object - /// available for reading so that the canRead() method will return true. - /// @brief Make the file readable; - bool makeReadableOnDisk(std::string* ErrMsg = 0); - - /// This method attempts to make the file referenced by the Path object - /// available for writing so that the canWrite() method will return true. - /// @brief Make the file writable; - bool makeWriteableOnDisk(std::string* ErrMsg = 0); - - /// This method attempts to make the file referenced by the Path object - /// available for execution so that the canExecute() method will return - /// true. - /// @brief Make the file readable; - bool makeExecutableOnDisk(std::string* ErrMsg = 0); - - /// This method allows the last modified time stamp and permission bits - /// to be set on the disk object referenced by the Path. - /// @throws std::string if an error occurs. - /// @returns true on error. - /// @brief Set the status information. - bool setStatusInfoOnDisk(const FileStatus &SI, - std::string *ErrStr = 0) const; - - /// This method attempts to create a directory in the file system with the - /// same name as the Path object. The \p create_parents parameter controls - /// whether intermediate directories are created or not. if \p - /// create_parents is true, then an attempt will be made to create all - /// intermediate directories, as needed. If \p create_parents is false, - /// then only the final directory component of the Path name will be - /// created. The created directory will have no entries. - /// @returns true if the directory could not be created, false otherwise - /// @brief Create the directory this Path refers to. - bool createDirectoryOnDisk( - bool create_parents = false, ///< Determines whether non-existent - ///< directory components other than the last one (the "parents") - ///< are created or not. - std::string* ErrMsg = 0 ///< Optional place to put error messages. - ); - - /// This method attempts to create a file in the file system with the same - /// name as the Path object. The intermediate directories must all exist - /// at the time this method is called. Use createDirectoriesOnDisk to - /// accomplish that. The created file will be empty upon return from this - /// function. - /// @returns true if the file could not be created, false otherwise. - /// @brief Create the file this Path refers to. - bool createFileOnDisk( - std::string* ErrMsg = 0 ///< Optional place to put error messages. - ); - - /// This is like createFile except that it creates a temporary file. A - /// unique temporary file name is generated based on the contents of - /// \p this before the call. The new name is assigned to \p this and the - /// file is created. Note that this will both change the Path object - /// *and* create the corresponding file. This function will ensure that - /// the newly generated temporary file name is unique in the file system. - /// @returns true if the file couldn't be created, false otherwise. - /// @brief Create a unique temporary file - bool createTemporaryFileOnDisk( - bool reuse_current = false, ///< When set to true, this parameter - ///< indicates that if the current file name does not exist then - ///< it will be used without modification. - std::string* ErrMsg = 0 ///< Optional place to put error messages - ); - - /// This method renames the file referenced by \p this as \p newName. The - /// file referenced by \p this must exist. The file referenced by - /// \p newName does not need to exist. - /// @returns true on error, false otherwise - /// @brief Rename one file as another. - bool renamePathOnDisk(const Path& newName, std::string* ErrMsg); - - /// This method attempts to destroy the file or directory named by the - /// last component of the Path. If the Path refers to a directory and the - /// \p destroy_contents is false, an attempt will be made to remove just - /// the directory (the final Path component). If \p destroy_contents is - /// true, an attempt will be made to remove the entire contents of the - /// directory, recursively. If the Path refers to a file, the - /// \p destroy_contents parameter is ignored. - /// @param destroy_contents Indicates whether the contents of a destroyed - /// @param Err An optional string to receive an error message. - /// directory should also be destroyed (recursively). - /// @returns false if the file/directory was destroyed, true on error. - /// @brief Removes the file or directory from the filesystem. - bool eraseFromDisk(bool destroy_contents = false, - std::string *Err = 0) const; - - - /// MapInFilePages - This is a low level system API to map in the file - /// that is currently opened as FD into the current processes' address - /// space for read only access. This function may return null on failure - /// or if the system cannot provide the following constraints: - /// 1) The pages must be valid after the FD is closed, until - /// UnMapFilePages is called. - /// 2) Any padding after the end of the file must be zero filled, if - /// present. - /// 3) The pages must be contiguous. - /// - /// This API is not intended for general use, clients should use - /// MemoryBuffer::getFile instead. - static const char *MapInFilePages(int FD, uint64_t FileSize); - - /// UnMapFilePages - Free pages mapped into the current process by - /// MapInFilePages. - /// - /// This API is not intended for general use, clients should use - /// MemoryBuffer::getFile instead. - static void UnMapFilePages(const char *Base, uint64_t FileSize); - - /// @} - /// @name Data - /// @{ - protected: - // Our win32 implementation relies on this string being mutable. - mutable std::string path; ///< Storage for the path name. - - - /// @} - }; - - /// This class is identical to Path class except it allows you to obtain the - /// file status of the Path as well. The reason for the distinction is one of - /// efficiency. First, the file status requires additional space and the space - /// is incorporated directly into PathWithStatus without an additional malloc. - /// Second, obtaining status information is an expensive operation on most - /// operating systems so we want to be careful and explicity about where we - /// allow this operation in LLVM. - /// @brief Path with file status class. - class PathWithStatus : public Path { - /// @name Constructors - /// @{ - public: - /// @brief Default constructor - PathWithStatus() : Path(), status(), fsIsValid(false) {} - - /// @brief Copy constructor - PathWithStatus(const PathWithStatus &that) - : Path(static_cast(that)), status(that.status), - fsIsValid(that.fsIsValid) {} - - /// This constructor allows construction from a Path object - /// @brief Path constructor - PathWithStatus(const Path &other) - : Path(other), status(), fsIsValid(false) {} - - /// This constructor will accept a char* or std::string as a path. No - /// checking is done on this path to determine if it is valid. To - /// determine validity of the path, use the isValid method. - /// @brief Construct a Path from a string. - explicit PathWithStatus( - StringRef p ///< The path to assign. - ) : Path(p), status(), fsIsValid(false) {} - - /// This constructor will accept a character range as a path. No checking - /// is done on this path to determine if it is valid. To determine - /// validity of the path, use the isValid method. - /// @brief Construct a Path from a string. - explicit PathWithStatus( - const char *StrStart, ///< Pointer to the first character of the path - unsigned StrLen ///< Length of the path. - ) : Path(StrStart, StrLen), status(), fsIsValid(false) {} - - /// Makes a copy of \p that to \p this. - /// @returns \p this - /// @brief Assignment Operator - PathWithStatus &operator=(const PathWithStatus &that) { - static_cast(*this) = static_cast(that); - status = that.status; - fsIsValid = that.fsIsValid; - return *this; - } - - /// Makes a copy of \p that to \p this. - /// @returns \p this - /// @brief Assignment Operator - PathWithStatus &operator=(const Path &that) { - static_cast(*this) = static_cast(that); - fsIsValid = false; - return *this; - } - - /// @} - /// @name Methods - /// @{ - public: - /// This function returns status information about the file. The type of - /// path (file or directory) is updated to reflect the actual contents - /// of the file system. - /// @returns 0 on failure, with Error explaining why (if non-zero) - /// @returns a pointer to a FileStatus structure on success. - /// @brief Get file status. - const FileStatus *getFileStatus( - bool forceUpdate = false, ///< Force an update from the file system - std::string *Error = 0 ///< Optional place to return an error msg. - ) const; - - /// @} - /// @name Data - /// @{ - private: - mutable FileStatus status; ///< Status information. - mutable bool fsIsValid; ///< Whether we've obtained it or not - - /// @} - }; - - /// This enumeration delineates the kinds of files that LLVM knows about. - enum LLVMFileType { - Unknown_FileType = 0, ///< Unrecognized file - Bitcode_FileType, ///< Bitcode file - Archive_FileType, ///< ar style archive file - ELF_Relocatable_FileType, ///< ELF Relocatable object file - ELF_Executable_FileType, ///< ELF Executable image - ELF_SharedObject_FileType, ///< ELF dynamically linked shared lib - ELF_Core_FileType, ///< ELF core image - Mach_O_Object_FileType, ///< Mach-O Object file - Mach_O_Executable_FileType, ///< Mach-O Executable - Mach_O_FixedVirtualMemorySharedLib_FileType, ///< Mach-O Shared Lib, FVM - Mach_O_Core_FileType, ///< Mach-O Core File - Mach_O_PreloadExectuable_FileType, ///< Mach-O Preloaded Executable - Mach_O_DynamicallyLinkedSharedLib_FileType, ///< Mach-O dynlinked shared lib - Mach_O_DynamicLinker_FileType, ///< The Mach-O dynamic linker - Mach_O_Bundle_FileType, ///< Mach-O Bundle file - Mach_O_DynamicallyLinkedSharedLibStub_FileType, ///< Mach-O Shared lib stub - COFF_FileType ///< COFF object file or lib - }; - - /// This utility function allows any memory block to be examined in order - /// to determine its file type. - LLVMFileType IdentifyFileType(const char*magic, unsigned length); - - /// This function can be used to copy the file specified by Src to the - /// file specified by Dest. If an error occurs, Dest is removed. - /// @returns true if an error occurs, false otherwise - /// @brief Copy one file to another. - bool CopyFile(const Path& Dest, const Path& Src, std::string* ErrMsg); - - /// This is the OS-specific path separator: a colon on Unix or a semicolon - /// on Windows. - extern const char PathSeparator; -} - -} - -#endif diff --git a/include/llvm/System/Process.h b/include/llvm/System/Process.h deleted file mode 100644 index 41bcd69b6a44..000000000000 --- a/include/llvm/System/Process.h +++ /dev/null @@ -1,146 +0,0 @@ -//===- llvm/System/Process.h ------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares the llvm::sys::Process class. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SYSTEM_PROCESS_H -#define LLVM_SYSTEM_PROCESS_H - -#include "llvm/System/TimeValue.h" - -namespace llvm { -namespace sys { - - /// This class provides an abstraction for getting information about the - /// currently executing process. - /// @since 1.4 - /// @brief An abstraction for operating system processes. - class Process { - /// @name Accessors - /// @{ - public: - /// This static function will return the operating system's virtual memory - /// page size. - /// @returns The number of bytes in a virtual memory page. - /// @brief Get the virtual memory page size - static unsigned GetPageSize(); - - /// This static function will return the total amount of memory allocated - /// by the process. This only counts the memory allocated via the malloc, - /// calloc and realloc functions and includes any "free" holes in the - /// allocated space. - /// @brief Return process memory usage. - static size_t GetMallocUsage(); - - /// This static function will return the total memory usage of the - /// process. This includes code, data, stack and mapped pages usage. Notei - /// that the value returned here is not necessarily the Running Set Size, - /// it is the total virtual memory usage, regardless of mapped state of - /// that memory. - static size_t GetTotalMemoryUsage(); - - /// This static function will set \p user_time to the amount of CPU time - /// spent in user (non-kernel) mode and \p sys_time to the amount of CPU - /// time spent in system (kernel) mode. If the operating system does not - /// support collection of these metrics, a zero TimeValue will be for both - /// values. - static void GetTimeUsage( - TimeValue& elapsed, - ///< Returns the TimeValue::now() giving current time - TimeValue& user_time, - ///< Returns the current amount of user time for the process - TimeValue& sys_time - ///< Returns the current amount of system time for the process - ); - - /// This static function will return the process' current user id number. - /// Not all operating systems support this feature. Where it is not - /// supported, the function should return 65536 as the value. - static int GetCurrentUserId(); - - /// This static function will return the process' current group id number. - /// Not all operating systems support this feature. Where it is not - /// supported, the function should return 65536 as the value. - static int GetCurrentGroupId(); - - /// This function makes the necessary calls to the operating system to - /// prevent core files or any other kind of large memory dumps that can - /// occur when a program fails. - /// @brief Prevent core file generation. - static void PreventCoreFiles(); - - /// This function determines if the standard input is connected directly - /// to a user's input (keyboard probably), rather than coming from a file - /// or pipe. - static bool StandardInIsUserInput(); - - /// This function determines if the standard output is connected to a - /// "tty" or "console" window. That is, the output would be displayed to - /// the user rather than being put on a pipe or stored in a file. - static bool StandardOutIsDisplayed(); - - /// This function determines if the standard error is connected to a - /// "tty" or "console" window. That is, the output would be displayed to - /// the user rather than being put on a pipe or stored in a file. - static bool StandardErrIsDisplayed(); - - /// This function determines if the given file descriptor is connected to - /// a "tty" or "console" window. That is, the output would be displayed to - /// the user rather than being put on a pipe or stored in a file. - static bool FileDescriptorIsDisplayed(int fd); - - /// This function determines the number of columns in the window - /// if standard output is connected to a "tty" or "console" - /// window. If standard output is not connected to a tty or - /// console, or if the number of columns cannot be determined, - /// this routine returns zero. - static unsigned StandardOutColumns(); - - /// This function determines the number of columns in the window - /// if standard error is connected to a "tty" or "console" - /// window. If standard error is not connected to a tty or - /// console, or if the number of columns cannot be determined, - /// this routine returns zero. - static unsigned StandardErrColumns(); - - /// This function determines whether the terminal connected to standard - /// output supports colors. If standard output is not connected to a - /// terminal, this function returns false. - static bool StandardOutHasColors(); - - /// This function determines whether the terminal connected to standard - /// error supports colors. If standard error is not connected to a - /// terminal, this function returns false. - static bool StandardErrHasColors(); - - /// Whether changing colors requires the output to be flushed. - /// This is needed on systems that don't support escape sequences for - /// changing colors. - static bool ColorNeedsFlush(); - - /// This function returns the colorcode escape sequences. - /// If ColorNeedsFlush() is true then this function will change the colors - /// and return an empty escape sequence. In that case it is the - /// responsibility of the client to flush the output stream prior to - /// calling this function. - static const char *OutputColor(char c, bool bold, bool bg); - - /// Same as OutputColor, but only enables the bold attribute. - static const char *OutputBold(bool bg); - - /// Resets the terminals colors, or returns an escape sequence to do so. - static const char *ResetColor(); - /// @} - }; -} -} - -#endif diff --git a/include/llvm/System/Program.h b/include/llvm/System/Program.h deleted file mode 100644 index 7017305a2eb6..000000000000 --- a/include/llvm/System/Program.h +++ /dev/null @@ -1,155 +0,0 @@ -//===- llvm/System/Program.h ------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares the llvm::sys::Program class. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SYSTEM_PROGRAM_H -#define LLVM_SYSTEM_PROGRAM_H - -#include "llvm/System/Path.h" - -namespace llvm { -namespace sys { - - // TODO: Add operations to communicate with the process, redirect its I/O, - // etc. - - /// This class provides an abstraction for programs that are executable by the - /// operating system. It provides a platform generic way to find executable - /// programs from the path and to execute them in various ways. The sys::Path - /// class is used to specify the location of the Program. - /// @since 1.4 - /// @brief An abstraction for finding and executing programs. - class Program { - /// Opaque handle for target specific data. - void *Data_; - - // Noncopyable. - Program(const Program& other); - Program& operator=(const Program& other); - - /// @name Methods - /// @{ - public: - - Program(); - ~Program(); - - /// Return process ID of this program. - unsigned GetPid() const; - - /// This function executes the program using the \p arguments provided. The - /// invoked program will inherit the stdin, stdout, and stderr file - /// descriptors, the environment and other configuration settings of the - /// invoking program. If Path::executable() does not return true when this - /// function is called then a std::string is thrown. - /// @returns false in case of error, true otherwise. - /// @see FindProgramByName - /// @brief Executes the program with the given set of \p args. - bool Execute - ( const Path& path, ///< sys::Path object providing the path of the - ///< program to be executed. It is presumed this is the result of - ///< the FindProgramByName method. - const char** args, ///< A vector of strings that are passed to the - ///< program. The first element should be the name of the program. - ///< The list *must* be terminated by a null char* entry. - const char ** env = 0, ///< An optional vector of strings to use for - ///< the program's environment. If not provided, the current program's - ///< environment will be used. - const sys::Path** redirects = 0, ///< An optional array of pointers to - ///< Paths. If the array is null, no redirection is done. The array - ///< should have a size of at least three. If the pointer in the array - ///< are not null, then the inferior process's stdin(0), stdout(1), - ///< and stderr(2) will be redirected to the corresponding Paths. - ///< When an empty Path is passed in, the corresponding file - ///< descriptor will be disconnected (ie, /dev/null'd) in a portable - ///< way. - unsigned memoryLimit = 0, ///< If non-zero, this specifies max. amount - ///< of memory can be allocated by process. If memory usage will be - ///< higher limit, the child is killed and this call returns. If zero - ///< - no memory limit. - std::string* ErrMsg = 0 ///< If non-zero, provides a pointer to a string - ///< instance in which error messages will be returned. If the string - ///< is non-empty upon return an error occurred while invoking the - ///< program. - ); - - /// This function waits for the program to exit. This function will block - /// the current program until the invoked program exits. - /// @returns an integer result code indicating the status of the program. - /// A zero or positive value indicates the result code of the program. A - /// negative value is the signal number on which it terminated. - /// @see Execute - /// @brief Waits for the program to exit. - int Wait - ( unsigned secondsToWait = 0, ///< If non-zero, this specifies the amount - ///< of time to wait for the child process to exit. If the time - ///< expires, the child is killed and this call returns. If zero, - ///< this function will wait until the child finishes or forever if - ///< it doesn't. - std::string* ErrMsg = 0 ///< If non-zero, provides a pointer to a string - ///< instance in which error messages will be returned. If the string - ///< is non-empty upon return an error occurred while waiting. - ); - - /// This function terminates the program. - /// @returns true if an error occured. - /// @see Execute - /// @brief Terminates the program. - bool Kill - ( std::string* ErrMsg = 0 ///< If non-zero, provides a pointer to a string - ///< instance in which error messages will be returned. If the string - ///< is non-empty upon return an error occurred while killing the - ///< program. - ); - - /// This static constructor (factory) will attempt to locate a program in - /// the operating system's file system using some pre-determined set of - /// locations to search (e.g. the PATH on Unix). - /// @returns A Path object initialized to the path of the program or a - /// Path object that is empty (invalid) if the program could not be found. - /// @brief Construct a Program by finding it by name. - static Path FindProgramByName(const std::string& name); - - // These methods change the specified standard stream (stdin, - // stdout, or stderr) to binary mode. They return true if an error - // occurred - static bool ChangeStdinToBinary(); - static bool ChangeStdoutToBinary(); - static bool ChangeStderrToBinary(); - - /// A convenience function equivalent to Program prg; prg.Execute(..); - /// prg.Wait(..); - /// @see Execute, Wait - static int ExecuteAndWait(const Path& path, - const char** args, - const char ** env = 0, - const sys::Path** redirects = 0, - unsigned secondsToWait = 0, - unsigned memoryLimit = 0, - std::string* ErrMsg = 0); - - /// A convenience function equivalent to Program prg; prg.Execute(..); - /// @see Execute - static void ExecuteNoWait(const Path& path, - const char** args, - const char ** env = 0, - const sys::Path** redirects = 0, - unsigned memoryLimit = 0, - std::string* ErrMsg = 0); - - /// @} - - }; -} -} - -#endif diff --git a/include/llvm/System/RWMutex.h b/include/llvm/System/RWMutex.h deleted file mode 100644 index 3a288180bf07..000000000000 --- a/include/llvm/System/RWMutex.h +++ /dev/null @@ -1,173 +0,0 @@ -//===- RWMutex.h - Reader/Writer Mutual Exclusion Lock ----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares the llvm::sys::RWMutex class. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SYSTEM_RWMUTEX_H -#define LLVM_SYSTEM_RWMUTEX_H - -#include "llvm/System/Threading.h" -#include - -namespace llvm -{ - namespace sys - { - /// @brief Platform agnostic RWMutex class. - class RWMutexImpl - { - /// @name Constructors - /// @{ - public: - - /// Initializes the lock but doesn't acquire it. - /// @brief Default Constructor. - explicit RWMutexImpl(); - - /// Releases and removes the lock - /// @brief Destructor - ~RWMutexImpl(); - - /// @} - /// @name Methods - /// @{ - public: - - /// Attempts to unconditionally acquire the lock in reader mode. If the - /// lock is held by a writer, this method will wait until it can acquire - /// the lock. - /// @returns false if any kind of error occurs, true otherwise. - /// @brief Unconditionally acquire the lock in reader mode. - bool reader_acquire(); - - /// Attempts to release the lock in reader mode. - /// @returns false if any kind of error occurs, true otherwise. - /// @brief Unconditionally release the lock in reader mode. - bool reader_release(); - - /// Attempts to unconditionally acquire the lock in reader mode. If the - /// lock is held by any readers, this method will wait until it can - /// acquire the lock. - /// @returns false if any kind of error occurs, true otherwise. - /// @brief Unconditionally acquire the lock in writer mode. - bool writer_acquire(); - - /// Attempts to release the lock in writer mode. - /// @returns false if any kind of error occurs, true otherwise. - /// @brief Unconditionally release the lock in write mode. - bool writer_release(); - - //@} - /// @name Platform Dependent Data - /// @{ - private: - void* data_; ///< We don't know what the data will be - - /// @} - /// @name Do Not Implement - /// @{ - private: - RWMutexImpl(const RWMutexImpl & original); - void operator=(const RWMutexImpl &); - /// @} - }; - - /// SmartMutex - An R/W mutex with a compile time constant parameter that - /// indicates whether this mutex should become a no-op when we're not - /// running in multithreaded mode. - template - class SmartRWMutex : public RWMutexImpl { - unsigned readers, writers; - public: - explicit SmartRWMutex() : RWMutexImpl(), readers(0), writers(0) { } - - bool reader_acquire() { - if (!mt_only || llvm_is_multithreaded()) - return RWMutexImpl::reader_acquire(); - - // Single-threaded debugging code. This would be racy in multithreaded - // mode, but provides not sanity checks in single threaded mode. - ++readers; - return true; - } - - bool reader_release() { - if (!mt_only || llvm_is_multithreaded()) - return RWMutexImpl::reader_release(); - - // Single-threaded debugging code. This would be racy in multithreaded - // mode, but provides not sanity checks in single threaded mode. - assert(readers > 0 && "Reader lock not acquired before release!"); - --readers; - return true; - } - - bool writer_acquire() { - if (!mt_only || llvm_is_multithreaded()) - return RWMutexImpl::writer_acquire(); - - // Single-threaded debugging code. This would be racy in multithreaded - // mode, but provides not sanity checks in single threaded mode. - assert(writers == 0 && "Writer lock already acquired!"); - ++writers; - return true; - } - - bool writer_release() { - if (!mt_only || llvm_is_multithreaded()) - return RWMutexImpl::writer_release(); - - // Single-threaded debugging code. This would be racy in multithreaded - // mode, but provides not sanity checks in single threaded mode. - assert(writers == 1 && "Writer lock not acquired before release!"); - --writers; - return true; - } - - private: - SmartRWMutex(const SmartRWMutex & original); - void operator=(const SmartRWMutex &); - }; - typedef SmartRWMutex RWMutex; - - /// ScopedReader - RAII acquisition of a reader lock - template - struct SmartScopedReader { - SmartRWMutex& mutex; - - explicit SmartScopedReader(SmartRWMutex& m) : mutex(m) { - mutex.reader_acquire(); - } - - ~SmartScopedReader() { - mutex.reader_release(); - } - }; - typedef SmartScopedReader ScopedReader; - - /// ScopedWriter - RAII acquisition of a writer lock - template - struct SmartScopedWriter { - SmartRWMutex& mutex; - - explicit SmartScopedWriter(SmartRWMutex& m) : mutex(m) { - mutex.writer_acquire(); - } - - ~SmartScopedWriter() { - mutex.writer_release(); - } - }; - typedef SmartScopedWriter ScopedWriter; - } -} - -#endif diff --git a/include/llvm/System/Signals.h b/include/llvm/System/Signals.h deleted file mode 100644 index 7f1c87c3d55a..000000000000 --- a/include/llvm/System/Signals.h +++ /dev/null @@ -1,59 +0,0 @@ -//===- llvm/System/Signals.h - Signal Handling support ----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines some helpful functions for dealing with the possibility of -// unix signals occuring while your program is running. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SYSTEM_SIGNALS_H -#define LLVM_SYSTEM_SIGNALS_H - -#include "llvm/System/Path.h" - -namespace llvm { -namespace sys { - - /// This function runs all the registered interrupt handlers, including the - /// removal of files registered by RemoveFileOnSignal. - void RunInterruptHandlers(); - - /// This function registers signal handlers to ensure that if a signal gets - /// delivered that the named file is removed. - /// @brief Remove a file if a fatal signal occurs. - bool RemoveFileOnSignal(const Path &Filename, std::string* ErrMsg = 0); - - /// This function removes a file from the list of files to be removed on - /// signal delivery. - void DontRemoveFileOnSignal(const Path &Filename); - - /// When an error signal (such as SIBABRT or SIGSEGV) is delivered to the - /// process, print a stack trace and then exit. - /// @brief Print a stack trace if a fatal signal occurs. - void PrintStackTraceOnErrorSignal(); - - /// AddSignalHandler - Add a function to be called when an abort/kill signal - /// is delivered to the process. The handler can have a cookie passed to it - /// to identify what instance of the handler it is. - void AddSignalHandler(void (*FnPtr)(void *), void *Cookie); - - /// This function registers a function to be called when the user "interrupts" - /// the program (typically by pressing ctrl-c). When the user interrupts the - /// program, the specified interrupt function is called instead of the program - /// being killed, and the interrupt function automatically disabled. Note - /// that interrupt functions are not allowed to call any non-reentrant - /// functions. An null interrupt function pointer disables the current - /// installed function. Note also that the handler may be executed on a - /// different thread on some platforms. - /// @brief Register a function to be called when ctrl-c is pressed. - void SetInterruptFunction(void (*IF)()); -} // End sys namespace -} // End llvm namespace - -#endif diff --git a/include/llvm/System/Solaris.h b/include/llvm/System/Solaris.h deleted file mode 100644 index 15adb7472c10..000000000000 --- a/include/llvm/System/Solaris.h +++ /dev/null @@ -1,40 +0,0 @@ -/*===- llvm/System/Solaris.h ------------------------------------*- C++ -*-===* - * - * The LLVM Compiler Infrastructure - * - * This file is distributed under the University of Illinois Open Source - * License. See LICENSE.TXT for details. - * - *===----------------------------------------------------------------------===* - * - * This file contains portability fixes for Solaris hosts. - * - *===----------------------------------------------------------------------===*/ - -#ifndef LLVM_SYSTEM_SOLARIS_H -#define LLVM_SYSTEM_SOLARIS_H - -#include -#include - -#undef CS -#undef DS -#undef ES -#undef FS -#undef GS -#undef SS -#undef EAX -#undef ECX -#undef EDX -#undef EBX -#undef ESP -#undef EBP -#undef ESI -#undef EDI -#undef EIP -#undef UESP -#undef EFL -#undef ERR -#undef TRAPNO - -#endif diff --git a/include/llvm/System/ThreadLocal.h b/include/llvm/System/ThreadLocal.h deleted file mode 100644 index e6edd79d6ff1..000000000000 --- a/include/llvm/System/ThreadLocal.h +++ /dev/null @@ -1,54 +0,0 @@ -//===- llvm/System/ThreadLocal.h - Thread Local Data ------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares the llvm::sys::ThreadLocal class. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SYSTEM_THREAD_LOCAL_H -#define LLVM_SYSTEM_THREAD_LOCAL_H - -#include "llvm/System/Threading.h" -#include - -namespace llvm { - namespace sys { - // ThreadLocalImpl - Common base class of all ThreadLocal instantiations. - // YOU SHOULD NEVER USE THIS DIRECTLY. - class ThreadLocalImpl { - void* data; - public: - ThreadLocalImpl(); - virtual ~ThreadLocalImpl(); - void setInstance(const void* d); - const void* getInstance(); - void removeInstance(); - }; - - /// ThreadLocal - A class used to abstract thread-local storage. It holds, - /// for each thread, a pointer a single object of type T. - template - class ThreadLocal : public ThreadLocalImpl { - public: - ThreadLocal() : ThreadLocalImpl() { } - - /// get - Fetches a pointer to the object associated with the current - /// thread. If no object has yet been associated, it returns NULL; - T* get() { return static_cast(getInstance()); } - - // set - Associates a pointer to an object with the current thread. - void set(T* d) { setInstance(d); } - - // erase - Removes the pointer associated with the current thread. - void erase() { removeInstance(); } - }; - } -} - -#endif diff --git a/include/llvm/System/Threading.h b/include/llvm/System/Threading.h deleted file mode 100644 index 42d2f89bcb82..000000000000 --- a/include/llvm/System/Threading.h +++ /dev/null @@ -1,45 +0,0 @@ -//===-- llvm/System/Threading.h - Control multithreading mode --*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// TThis file defines llvm_start_multithreaded() and friends. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SYSTEM_THREADING_H -#define LLVM_SYSTEM_THREADING_H - -namespace llvm { - /// llvm_start_multithreaded - Allocate and initialize structures needed to - /// make LLVM safe for multithreading. The return value indicates whether - /// multithreaded initialization succeeded. LLVM will still be operational - /// on "failed" return, and will still be safe for hosting threading - /// applications in the JIT, but will not be safe for concurrent calls to the - /// LLVM APIs. - /// THIS MUST EXECUTE IN ISOLATION FROM ALL OTHER LLVM API CALLS. - bool llvm_start_multithreaded(); - - /// llvm_stop_multithreaded - Deallocate structures necessary to make LLVM - /// safe for multithreading. - /// THIS MUST EXECUTE IN ISOLATION FROM ALL OTHER LLVM API CALLS. - void llvm_stop_multithreaded(); - - /// llvm_is_multithreaded - Check whether LLVM is executing in thread-safe - /// mode or not. - bool llvm_is_multithreaded(); - - /// acquire_global_lock - Acquire the global lock. This is a no-op if called - /// before llvm_start_multithreaded(). - void llvm_acquire_global_lock(); - - /// release_global_lock - Release the global lock. This is a no-op if called - /// before llvm_start_multithreaded(). - void llvm_release_global_lock(); -} - -#endif diff --git a/include/llvm/System/TimeValue.h b/include/llvm/System/TimeValue.h deleted file mode 100644 index b82647f74ed5..000000000000 --- a/include/llvm/System/TimeValue.h +++ /dev/null @@ -1,382 +0,0 @@ -//===-- TimeValue.h - Declare OS TimeValue Concept --------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This header file declares the operating system TimeValue concept. -// -//===----------------------------------------------------------------------===// - -#include "llvm/System/DataTypes.h" -#include - -#ifndef LLVM_SYSTEM_TIMEVALUE_H -#define LLVM_SYSTEM_TIMEVALUE_H - -namespace llvm { -namespace sys { - /// This class is used where a precise fixed point in time is required. The - /// range of TimeValue spans many hundreds of billions of years both past and - /// present. The precision of TimeValue is to the nanosecond. However, the - /// actual precision of its values will be determined by the resolution of - /// the system clock. The TimeValue class is used in conjunction with several - /// other lib/System interfaces to specify the time at which a call should - /// timeout, etc. - /// @since 1.4 - /// @brief Provides an abstraction for a fixed point in time. - class TimeValue { - - /// @name Constants - /// @{ - public: - - /// A constant TimeValue representing the smallest time - /// value permissable by the class. MinTime is some point - /// in the distant past, about 300 billion years BCE. - /// @brief The smallest possible time value. - static const TimeValue MinTime; - - /// A constant TimeValue representing the largest time - /// value permissable by the class. MaxTime is some point - /// in the distant future, about 300 billion years AD. - /// @brief The largest possible time value. - static const TimeValue MaxTime; - - /// A constant TimeValue representing the base time, - /// or zero time of 00:00:00 (midnight) January 1st, 2000. - /// @brief 00:00:00 Jan 1, 2000 UTC. - static const TimeValue ZeroTime; - - /// A constant TimeValue for the Posix base time which is - /// 00:00:00 (midnight) January 1st, 1970. - /// @brief 00:00:00 Jan 1, 1970 UTC. - static const TimeValue PosixZeroTime; - - /// A constant TimeValue for the Win32 base time which is - /// 00:00:00 (midnight) January 1st, 1601. - /// @brief 00:00:00 Jan 1, 1601 UTC. - static const TimeValue Win32ZeroTime; - - /// @} - /// @name Types - /// @{ - public: - typedef int64_t SecondsType; ///< Type used for representing seconds. - typedef int32_t NanoSecondsType;///< Type used for representing nanoseconds. - - enum TimeConversions { - NANOSECONDS_PER_SECOND = 1000000000, ///< One Billion - MICROSECONDS_PER_SECOND = 1000000, ///< One Million - MILLISECONDS_PER_SECOND = 1000, ///< One Thousand - NANOSECONDS_PER_MICROSECOND = 1000, ///< One Thousand - NANOSECONDS_PER_MILLISECOND = 1000000,///< One Million - NANOSECONDS_PER_POSIX_TICK = 100, ///< Posix tick is 100 Hz (10ms) - NANOSECONDS_PER_WIN32_TICK = 100 ///< Win32 tick is 100 Hz (10ms) - }; - - /// @} - /// @name Constructors - /// @{ - public: - /// Caller provides the exact value in seconds and nanoseconds. The - /// \p nanos argument defaults to zero for convenience. - /// @brief Explicit constructor - explicit TimeValue (SecondsType seconds, NanoSecondsType nanos = 0) - : seconds_( seconds ), nanos_( nanos ) { this->normalize(); } - - /// Caller provides the exact value as a double in seconds with the - /// fractional part representing nanoseconds. - /// @brief Double Constructor. - explicit TimeValue( double new_time ) - : seconds_( 0 ) , nanos_ ( 0 ) { - SecondsType integer_part = static_cast( new_time ); - seconds_ = integer_part; - nanos_ = static_cast( (new_time - - static_cast(integer_part)) * NANOSECONDS_PER_SECOND ); - this->normalize(); - } - - /// This is a static constructor that returns a TimeValue that represents - /// the current time. - /// @brief Creates a TimeValue with the current time (UTC). - static TimeValue now(); - - /// @} - /// @name Operators - /// @{ - public: - /// Add \p that to \p this. - /// @returns this - /// @brief Incrementing assignment operator. - TimeValue& operator += (const TimeValue& that ) { - this->seconds_ += that.seconds_ ; - this->nanos_ += that.nanos_ ; - this->normalize(); - return *this; - } - - /// Subtract \p that from \p this. - /// @returns this - /// @brief Decrementing assignment operator. - TimeValue& operator -= (const TimeValue &that ) { - this->seconds_ -= that.seconds_ ; - this->nanos_ -= that.nanos_ ; - this->normalize(); - return *this; - } - - /// Determine if \p this is less than \p that. - /// @returns True iff *this < that. - /// @brief True if this < that. - int operator < (const TimeValue &that) const { return that > *this; } - - /// Determine if \p this is greather than \p that. - /// @returns True iff *this > that. - /// @brief True if this > that. - int operator > (const TimeValue &that) const { - if ( this->seconds_ > that.seconds_ ) { - return 1; - } else if ( this->seconds_ == that.seconds_ ) { - if ( this->nanos_ > that.nanos_ ) return 1; - } - return 0; - } - - /// Determine if \p this is less than or equal to \p that. - /// @returns True iff *this <= that. - /// @brief True if this <= that. - int operator <= (const TimeValue &that) const { return that >= *this; } - - /// Determine if \p this is greater than or equal to \p that. - /// @returns True iff *this >= that. - /// @brief True if this >= that. - int operator >= (const TimeValue &that) const { - if ( this->seconds_ > that.seconds_ ) { - return 1; - } else if ( this->seconds_ == that.seconds_ ) { - if ( this->nanos_ >= that.nanos_ ) return 1; - } - return 0; - } - - /// Determines if two TimeValue objects represent the same moment in time. - /// @brief True iff *this == that. - /// @brief True if this == that. - int operator == (const TimeValue &that) const { - return (this->seconds_ == that.seconds_) && - (this->nanos_ == that.nanos_); - } - - /// Determines if two TimeValue objects represent times that are not the - /// same. - /// @return True iff *this != that. - /// @brief True if this != that. - int operator != (const TimeValue &that) const { return !(*this == that); } - - /// Adds two TimeValue objects together. - /// @returns The sum of the two operands as a new TimeValue - /// @brief Addition operator. - friend TimeValue operator + (const TimeValue &tv1, const TimeValue &tv2); - - /// Subtracts two TimeValue objects. - /// @returns The difference of the two operands as a new TimeValue - /// @brief Subtraction operator. - friend TimeValue operator - (const TimeValue &tv1, const TimeValue &tv2); - - /// @} - /// @name Accessors - /// @{ - public: - - /// Returns only the seconds component of the TimeValue. The nanoseconds - /// portion is ignored. No rounding is performed. - /// @brief Retrieve the seconds component - SecondsType seconds() const { return seconds_; } - - /// Returns only the nanoseconds component of the TimeValue. The seconds - /// portion is ignored. - /// @brief Retrieve the nanoseconds component. - NanoSecondsType nanoseconds() const { return nanos_; } - - /// Returns only the fractional portion of the TimeValue rounded down to the - /// nearest microsecond (divide by one thousand). - /// @brief Retrieve the fractional part as microseconds; - uint32_t microseconds() const { - return nanos_ / NANOSECONDS_PER_MICROSECOND; - } - - /// Returns only the fractional portion of the TimeValue rounded down to the - /// nearest millisecond (divide by one million). - /// @brief Retrieve the fractional part as milliseconds; - uint32_t milliseconds() const { - return nanos_ / NANOSECONDS_PER_MILLISECOND; - } - - /// Returns the TimeValue as a number of microseconds. Note that the value - /// returned can overflow because the range of a uint64_t is smaller than - /// the range of a TimeValue. Nevertheless, this is useful on some operating - /// systems and is therefore provided. - /// @brief Convert to a number of microseconds (can overflow) - uint64_t usec() const { - return seconds_ * MICROSECONDS_PER_SECOND + - ( nanos_ / NANOSECONDS_PER_MICROSECOND ); - } - - /// Returns the TimeValue as a number of milliseconds. Note that the value - /// returned can overflow because the range of a uint64_t is smaller than - /// the range of a TimeValue. Nevertheless, this is useful on some operating - /// systems and is therefore provided. - /// @brief Convert to a number of milliseconds (can overflow) - uint64_t msec() const { - return seconds_ * MILLISECONDS_PER_SECOND + - ( nanos_ / NANOSECONDS_PER_MILLISECOND ); - } - - /// Converts the TimeValue into the corresponding number of "ticks" for - /// Posix, correcting for the difference in Posix zero time. - /// @brief Convert to unix time (100 nanoseconds since 12:00:00a Jan 1,1970) - uint64_t toPosixTime() const { - uint64_t result = seconds_ - PosixZeroTime.seconds_; - result += nanos_ / NANOSECONDS_PER_POSIX_TICK; - return result; - } - - /// Converts the TimeValue into the corresponding number of seconds - /// since the epoch (00:00:00 Jan 1,1970). - uint64_t toEpochTime() const { - return seconds_ - PosixZeroTime.seconds_; - } - - /// Converts the TimeValue into the corresponding number of "ticks" for - /// Win32 platforms, correcting for the difference in Win32 zero time. - /// @brief Convert to windows time (seconds since 12:00:00a Jan 1, 1601) - uint64_t toWin32Time() const { - uint64_t result = seconds_ - Win32ZeroTime.seconds_; - result += nanos_ / NANOSECONDS_PER_WIN32_TICK; - return result; - } - - /// Provides the seconds and nanoseconds as results in its arguments after - /// correction for the Posix zero time. - /// @brief Convert to timespec time (ala POSIX.1b) - void getTimespecTime( uint64_t& seconds, uint32_t& nanos ) const { - seconds = seconds_ - PosixZeroTime.seconds_; - nanos = nanos_; - } - - /// Provides conversion of the TimeValue into a readable time & date. - /// @returns std::string containing the readable time value - /// @brief Convert time to a string. - std::string str() const; - - /// @} - /// @name Mutators - /// @{ - public: - /// The seconds component of the TimeValue is set to \p sec without - /// modifying the nanoseconds part. This is useful for whole second - /// arithmetic. - /// @brief Set the seconds component. - void seconds (SecondsType sec ) { - this->seconds_ = sec; - this->normalize(); - } - - /// The nanoseconds component of the TimeValue is set to \p nanos without - /// modifying the seconds part. This is useful for basic computations - /// involving just the nanoseconds portion. Note that the TimeValue will be - /// normalized after this call so that the fractional (nanoseconds) portion - /// will have the smallest equivalent value. - /// @brief Set the nanoseconds component using a number of nanoseconds. - void nanoseconds ( NanoSecondsType nanos ) { - this->nanos_ = nanos; - this->normalize(); - } - - /// The seconds component remains unchanged. - /// @brief Set the nanoseconds component using a number of microseconds. - void microseconds ( int32_t micros ) { - this->nanos_ = micros * NANOSECONDS_PER_MICROSECOND; - this->normalize(); - } - - /// The seconds component remains unchanged. - /// @brief Set the nanoseconds component using a number of milliseconds. - void milliseconds ( int32_t millis ) { - this->nanos_ = millis * NANOSECONDS_PER_MILLISECOND; - this->normalize(); - } - - /// @brief Converts from microsecond format to TimeValue format - void usec( int64_t microseconds ) { - this->seconds_ = microseconds / MICROSECONDS_PER_SECOND; - this->nanos_ = NanoSecondsType(microseconds % MICROSECONDS_PER_SECOND) * - NANOSECONDS_PER_MICROSECOND; - this->normalize(); - } - - /// @brief Converts from millisecond format to TimeValue format - void msec( int64_t milliseconds ) { - this->seconds_ = milliseconds / MILLISECONDS_PER_SECOND; - this->nanos_ = NanoSecondsType(milliseconds % MILLISECONDS_PER_SECOND) * - NANOSECONDS_PER_MILLISECOND; - this->normalize(); - } - - /// Converts the \p seconds argument from PosixTime to the corresponding - /// TimeValue and assigns that value to \p this. - /// @brief Convert seconds form PosixTime to TimeValue - void fromEpochTime( SecondsType seconds ) { - seconds_ = seconds + PosixZeroTime.seconds_; - nanos_ = 0; - this->normalize(); - } - - /// Converts the \p win32Time argument from Windows FILETIME to the - /// corresponding TimeValue and assigns that value to \p this. - /// @brief Convert seconds form Windows FILETIME to TimeValue - void fromWin32Time( uint64_t win32Time ) { - this->seconds_ = win32Time / 10000000 + Win32ZeroTime.seconds_; - this->nanos_ = NanoSecondsType(win32Time % 10000000) * 100; - } - - /// @} - /// @name Implementation - /// @{ - private: - /// This causes the values to be represented so that the fractional - /// part is minimized, possibly incrementing the seconds part. - /// @brief Normalize to canonical form. - void normalize(); - - /// @} - /// @name Data - /// @{ - private: - /// Store the values as a . - SecondsType seconds_;///< Stores the seconds part of the TimeVal - NanoSecondsType nanos_; ///< Stores the nanoseconds part of the TimeVal - /// @} - - }; - -inline TimeValue operator + (const TimeValue &tv1, const TimeValue &tv2) { - TimeValue sum (tv1.seconds_ + tv2.seconds_, tv1.nanos_ + tv2.nanos_); - sum.normalize (); - return sum; -} - -inline TimeValue operator - (const TimeValue &tv1, const TimeValue &tv2) { - TimeValue difference (tv1.seconds_ - tv2.seconds_, tv1.nanos_ - tv2.nanos_ ); - difference.normalize (); - return difference; -} - -} -} - -#endif diff --git a/include/llvm/System/Valgrind.h b/include/llvm/System/Valgrind.h deleted file mode 100644 index 5ec79c3c5573..000000000000 --- a/include/llvm/System/Valgrind.h +++ /dev/null @@ -1,32 +0,0 @@ -//===- llvm/System/Valgrind.h - Communication with Valgrind -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Methods for communicating with a valgrind instance this program is running -// under. These are all no-ops unless LLVM was configured on a system with the -// valgrind headers installed and valgrind is controlling this process. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SYSTEM_VALGRIND_H -#define LLVM_SYSTEM_VALGRIND_H - -#include - -namespace llvm { -namespace sys { - // True if Valgrind is controlling this process. - bool RunningOnValgrind(); - - // Discard valgrind's translation of code in the range [Addr .. Addr + Len). - // Otherwise valgrind may continue to execute the old version of the code. - void ValgrindDiscardTranslations(const void *Addr, size_t Len); -} -} - -#endif diff --git a/include/llvm/Target/Mangler.h b/include/llvm/Target/Mangler.h index a9f3576559d4..c1c118b08cab 100644 --- a/include/llvm/Target/Mangler.h +++ b/include/llvm/Target/Mangler.h @@ -15,7 +15,6 @@ #define LLVM_SUPPORT_MANGLER_H #include "llvm/ADT/DenseMap.h" -#include namespace llvm { class StringRef; @@ -69,12 +68,6 @@ public: /// empty. void getNameWithPrefix(SmallVectorImpl &OutName, const Twine &GVName, ManglerPrefixTy PrefixTy = Mangler::Default); - - /// getNameWithPrefix - Return the name of the appropriate prefix - /// and the specified global variable's name. If the global variable doesn't - /// have a name, this fills in a unique name for the global. - std::string getNameWithPrefix(const GlobalValue *GV, - bool isImplicitlyPrivate = false); }; } // End llvm namespace diff --git a/include/llvm/Target/SubtargetFeature.h b/include/llvm/Target/SubtargetFeature.h index 45468714a3bc..6c21ae9583e0 100644 --- a/include/llvm/Target/SubtargetFeature.h +++ b/include/llvm/Target/SubtargetFeature.h @@ -22,7 +22,7 @@ #include #include #include "llvm/ADT/Triple.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { class raw_ostream; diff --git a/include/llvm/Target/Target.td b/include/llvm/Target/Target.td index b141a77df4f2..0f7e6aaaf2fa 100644 --- a/include/llvm/Target/Target.td +++ b/include/llvm/Target/Target.td @@ -1,10 +1,10 @@ //===- Target.td - Target Independent TableGen interface ---*- tablegen -*-===// -// +// // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. -// +// //===----------------------------------------------------------------------===// // // This file defines the target-independent interfaces which should be @@ -47,7 +47,7 @@ class Register { // modification of this register can potentially read or modify the aliased // registers. list Aliases = []; - + // SubRegs - A list of registers that are parts of this register. Note these // are "immediate" sub-registers and the registers within the list do not // themselves overlap. e.g. For X86, EAX's SubRegs list contains only [AX], @@ -84,7 +84,7 @@ class Register { // need to specify sub-registers. // List "subregs" specifies which registers are sub-registers to this one. This // is used to populate the SubRegs and AliasSet fields of TargetRegisterDesc. -// This allows the code generator to be careful not to put two values with +// This allows the code generator to be careful not to put two values with // overlapping live ranges into registers which alias. class RegisterWithSubRegs subregs> : Register { let SubRegs = subregs; @@ -101,7 +101,7 @@ class RegisterClass regTypes, int alignment, // RegType - Specify the list ValueType of the registers in this register // class. Note that all registers in a register class must have the same - // ValueTypes. This is a list because some targets permit storing different + // ValueTypes. This is a list because some targets permit storing different // types in same register, for example vector values with 128-bit total size, // but different count/size of items, like SSE on x86. // @@ -127,13 +127,13 @@ class RegisterClass regTypes, int alignment, // allocation used by the register allocator. // list MemberList = regList; - + // SubRegClasses - Specify the register class of subregisters as a list of // dags: (RegClass SubRegIndex, SubRegindex, ...) list SubRegClasses = []; // MethodProtos/MethodBodies - These members can be used to insert arbitrary - // code into a generated register class. The normal usage of this is to + // code into a generated register class. The normal usage of this is to // overload virtual methods. code MethodProtos = [{}]; code MethodBodies = [{}]; @@ -150,8 +150,8 @@ class DwarfRegNum Numbers> { // These values can be determined by locating the .h file in the // directory llvmgcc/gcc/config// and looking for REGISTER_NAMES. The // order of these names correspond to the enumeration used by gcc. A value of - // -1 indicates that the gcc number is undefined and -2 that register number is - // invalid for this mode/flavour. + // -1 indicates that the gcc number is undefined and -2 that register number + // is invalid for this mode/flavour. list DwarfNumbers = Numbers; } @@ -199,6 +199,7 @@ class Instruction { bit isBranch = 0; // Is this instruction a branch instruction? bit isIndirectBranch = 0; // Is this instruction an indirect branch? bit isCompare = 0; // Is this instruction a comparison instruction? + bit isMoveImm = 0; // Is this instruction a move immediate instruction? bit isBarrier = 0; // Can control flow fall through this instruction? bit isCall = 0; // Is this instruction a call instruction? bit canFoldAsLoad = 0; // Can this be folded as a simple memory operand? @@ -243,14 +244,29 @@ class Instruction { /// be encoded into the output machineinstr. string DisableEncoding = ""; + string PostEncoderMethod = ""; + string DecoderMethod = ""; + /// Target-specific flags. This becomes the TSFlags field in TargetInstrDesc. bits<64> TSFlags = 0; + + ///@name Assembler Parser Support + ///@{ + + string AsmMatchConverter = ""; + + ///@} } /// Predicates - These are extra conditionals which are turned into instruction /// selector matching code. Currently each predicate is just a string. class Predicate { string CondString = cond; + + /// AssemblerMatcherPredicate - If this feature can be used by the assembler + /// matcher, this is true. Targets should set this by inheriting their + /// feature from the AssemblerPredicate class in addition to Predicate. + bit AssemblerMatcherPredicate = 0; } /// NoHonorSignDependentRounding - This predicate is true if support for @@ -262,9 +278,9 @@ class Requires preds> { list Predicates = preds; } -/// ops definition - This is just a simple marker used to identify the operands -/// list for an instruction. outs and ins are identical both syntatically and -/// semantically, they are used to define def operands and use operands to +/// ops definition - This is just a simple marker used to identify the operand +/// list for an instruction. outs and ins are identical both syntactically and +/// semanticallyr; they are used to define def operands and use operands to /// improve readibility. This should be used like this: /// (outs R32:$dst), (ins R32:$src1, R32:$src2) or something similar. def ops; @@ -326,18 +342,26 @@ class AsmOperandClass { /// signature should be: /// void addFooOperands(MCInst &Inst, unsigned N) const; string RenderMethod = ?; + + /// The name of the method on the target specific operand to call to custom + /// handle the operand parsing. This is useful when the operands do not relate + /// to immediates or registers and are very instruction specific (as flags to + /// set in a processor register, coprocessor number, ...). + string ParserMethod = ?; } def ImmAsmOperand : AsmOperandClass { let Name = "Imm"; } - + /// Operand Types - These provide the built-in operand types that may be used /// by a target. Targets can optionally provide their own operand types as /// needed, though this should not be needed for RISC targets. class Operand { ValueType Type = ty; string PrintMethod = "printOperand"; + string EncoderMethod = ""; + string DecoderMethod = ""; string AsmOperandLowerMethod = ?; dag MIOperandInfo = (ops); @@ -409,6 +433,7 @@ def INLINEASM : Instruction { let OutOperandList = (outs); let InOperandList = (ins variable_ops); let AsmString = ""; + let neverHasSideEffects = 1; // Note side effect is encoded in an operand. } def PROLOG_LABEL : Instruction { let OutOperandList = (outs); @@ -475,7 +500,7 @@ def DBG_VALUE : Instruction { let OutOperandList = (outs); let InOperandList = (ins variable_ops); let AsmString = "DBG_VALUE"; - let isAsCheapAsAMove = 1; + let neverHasSideEffects = 1; } def REG_SEQUENCE : Instruction { let OutOperandList = (outs unknown:$dst); @@ -506,9 +531,9 @@ class AsmParser { // name. string AsmParserClassName = "AsmParser"; - // AsmParserInstCleanup - If non-empty, this is the name of a custom function on the - // AsmParser class to call on every matched instruction. This can be used to - // perform target specific instruction post-processing. + // AsmParserInstCleanup - If non-empty, this is the name of a custom member + // function of the AsmParser class to call on every matched instruction. + // This can be used to perform target specific instruction post-processing. string AsmParserInstCleanup = ""; // Variant - AsmParsers can be of multiple different variants. Variants are @@ -529,6 +554,49 @@ class AsmParser { } def DefaultAsmParser : AsmParser; +/// AssemblerPredicate - This is a Predicate that can be used when the assembler +/// matches instructions and aliases. +class AssemblerPredicate { + bit AssemblerMatcherPredicate = 1; +} + + + +/// MnemonicAlias - This class allows targets to define assembler mnemonic +/// aliases. This should be used when all forms of one mnemonic are accepted +/// with a different mnemonic. For example, X86 allows: +/// sal %al, 1 -> shl %al, 1 +/// sal %ax, %cl -> shl %ax, %cl +/// sal %eax, %cl -> shl %eax, %cl +/// etc. Though "sal" is accepted with many forms, all of them are directly +/// translated to a shl, so it can be handled with (in the case of X86, it +/// actually has one for each suffix as well): +/// def : MnemonicAlias<"sal", "shl">; +/// +/// Mnemonic aliases are mapped before any other translation in the match phase, +/// and do allow Requires predicates, e.g.: +/// +/// def : MnemonicAlias<"pushf", "pushfq">, Requires<[In64BitMode]>; +/// def : MnemonicAlias<"pushf", "pushfl">, Requires<[In32BitMode]>; +/// +class MnemonicAlias { + string FromMnemonic = From; + string ToMnemonic = To; + + // Predicates - Predicates that must be true for this remapping to happen. + list Predicates = []; +} + +/// InstAlias - This defines an alternate assembly syntax that is allowed to +/// match an instruction that has a different (more canonical) assembly +/// representation. +class InstAlias { + string AsmString = Asm; // The .s format to match the instruction with. + dag ResultInst = Result; // The MCInst to generate. + + // Predicates - Predicates that must be true for this to match. + list Predicates = []; +} //===----------------------------------------------------------------------===// // AsmWriter - This class can be implemented by targets that need to customize @@ -543,10 +611,6 @@ class AsmWriter { // name. string AsmWriterClassName = "AsmPrinter"; - // InstFormatName - AsmWriters can specify the name of the format string to - // print instructions with. - string InstFormatName = "AsmString"; - // Variant - AsmWriters can be of multiple different variants. Variants are // used to support targets that need to emit assembly code in ways that are // mostly the same for different targets, but have minor differences in @@ -554,17 +618,22 @@ class AsmWriter { // will specify which alternative to use. For example "{x|y|z}" with Variant // == 1, will expand to "y". int Variant = 0; - - + + // FirstOperandColumn/OperandSpacing - If the assembler syntax uses a columnar // layout, the asmwriter can actually generate output in this columns (in // verbose-asm mode). These two values indicate the width of the first column // (the "opcode" area) and the width to reserve for subsequent operands. When // verbose asm mode is enabled, operands will be indented to respect this. int FirstOperandColumn = -1; - + // OperandSpacing - Space between operand columns. int OperandSpacing = -1; + + // isMCAsmWriter - Is this assembly writer for an MC emitter? This controls + // generation of the printInstruction() method. For MC printers, it takes + // an MCInstr* operand, otherwise it takes a MachineInstr*. + bit isMCAsmWriter = 0; } def DefaultAsmWriter : AsmWriter; @@ -592,15 +661,15 @@ class SubtargetFeature f> { // appropriate target chip. // string Name = n; - + // ProcItin - The scheduling information for the target processor. // ProcessorItineraries ProcItin = pi; - - // Features - list of + + // Features - list of list Features = f; } diff --git a/include/llvm/Target/TargetAsmBackend.h b/include/llvm/Target/TargetAsmBackend.h index 979595ad4f42..7527298efa9e 100644 --- a/include/llvm/Target/TargetAsmBackend.h +++ b/include/llvm/Target/TargetAsmBackend.h @@ -10,17 +10,18 @@ #ifndef LLVM_TARGET_TARGETASMBACKEND_H #define LLVM_TARGET_TARGETASMBACKEND_H -#include "llvm/System/DataTypes.h" +#include "llvm/MC/MCDirectives.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/Support/DataTypes.h" namespace llvm { -class MCDataFragment; class MCFixup; class MCInst; class MCObjectWriter; class MCSection; template class SmallVectorImpl; -class Target; class raw_ostream; /// TargetAsmBackend - Generic interface to target specific assembler backends. @@ -28,37 +29,17 @@ class TargetAsmBackend { TargetAsmBackend(const TargetAsmBackend &); // DO NOT IMPLEMENT void operator=(const TargetAsmBackend &); // DO NOT IMPLEMENT protected: // Can only create subclasses. - TargetAsmBackend(const Target &); + TargetAsmBackend(); - /// TheTarget - The Target that this machine was created for. - const Target &TheTarget; - - unsigned HasAbsolutizedSet : 1; unsigned HasReliableSymbolDifference : 1; - unsigned HasScatteredSymbols : 1; public: virtual ~TargetAsmBackend(); - const Target &getTarget() const { return TheTarget; } - /// createObjectWriter - Create a new MCObjectWriter instance for use by the /// assembler backend to emit the final object file. virtual MCObjectWriter *createObjectWriter(raw_ostream &OS) const = 0; - /// hasAbsolutizedSet - Check whether this target "absolutizes" - /// assignments. That is, given code like: - /// a: - /// ... - /// b: - /// tmp = a - b - /// .long tmp - /// will the value of 'tmp' be a relocatable expression, or the assembly time - /// value of L0 - L1. This distinction is only relevant for platforms that - /// support scattered symbols, since in the absence of scattered symbols (a - - /// b) cannot change after assembly. - bool hasAbsolutizedSet() const { return HasAbsolutizedSet; } - /// hasReliableSymbolDifference - Check whether this target implements /// accurate relocations for differences between symbols. If not, differences /// between symbols will always be relocatable expressions and any references @@ -68,21 +49,11 @@ public: /// This should always be true (since it results in fewer relocations with no /// loss of functionality), but is currently supported as a way to maintain /// exact object compatibility with Darwin 'as' (on non-x86_64). It should - /// eventually should be eliminated. See also \see hasAbsolutizedSet. + /// eventually should be eliminated. bool hasReliableSymbolDifference() const { return HasReliableSymbolDifference; } - /// hasScatteredSymbols - Check whether this target supports scattered - /// symbols. If so, the assembler should assume that atoms can be scattered by - /// the linker. In particular, this means that the offsets between symbols - /// which are in distinct atoms is not known at link time, and the assembler - /// must generate fixups and relocations appropriately. - /// - /// Note that the assembler currently does not reason about atoms, instead it - /// assumes all temporary symbols reside in the "current atom". - bool hasScatteredSymbols() const { return HasScatteredSymbols; } - /// doesSectionRequireSymbols - Check whether the given section requires that /// all symbols (even temporaries) have symbol table entries. virtual bool doesSectionRequireSymbols(const MCSection &Section) const { @@ -97,16 +68,28 @@ public: return true; } - /// isVirtualSection - Check whether the given section is "virtual", that is - /// has no actual object file contents. - virtual bool isVirtualSection(const MCSection &Section) const = 0; + /// @name Target Fixup Interfaces + /// @{ + + /// getNumFixupKinds - Get the number of target specific fixup kinds. + virtual unsigned getNumFixupKinds() const = 0; + + /// getFixupKindInfo - Get information on a fixup kind. + virtual const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const; + + /// @} /// ApplyFixup - Apply the \arg Value for given \arg Fixup into the provided /// data fragment, at the offset specified by the fixup and following the /// fixup kind as appropriate. - virtual void ApplyFixup(const MCFixup &Fixup, MCDataFragment &Fragment, + virtual void ApplyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, uint64_t Value) const = 0; + /// @} + + /// @name Target Relaxation Interfaces + /// @{ + /// MayNeedRelaxation - Check whether the given instruction may need /// relaxation. /// @@ -121,12 +104,18 @@ public: /// \parm Res [output] - On return, the relaxed instruction. virtual void RelaxInstruction(const MCInst &Inst, MCInst &Res) const = 0; + /// @} + /// WriteNopData - Write an (optimal) nop sequence of Count bytes to the given /// output. If the target cannot generate such a sequence, it should return an /// error. /// /// \return - True on success. virtual bool WriteNopData(uint64_t Count, MCObjectWriter *OW) const = 0; + + /// HandleAssemblerFlag - Handle any target-specific assembler flags. + /// By default, do nothing. + virtual void HandleAssemblerFlag(MCAssemblerFlag Flag) {} }; } // End llvm namespace diff --git a/include/llvm/Target/TargetAsmInfo.h b/include/llvm/Target/TargetAsmInfo.h new file mode 100644 index 000000000000..98aab142b8e4 --- /dev/null +++ b/include/llvm/Target/TargetAsmInfo.h @@ -0,0 +1,75 @@ +//===-- llvm/Target/TargetAsmInfo.h -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Interface to provide the information necessary for producing assembly files. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_TARGETASMINFO_H +#define LLVM_TARGET_TARGETASMINFO_H + +#include "llvm/CodeGen/MachineLocation.h" +#include "llvm/Target/TargetLoweringObjectFile.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetRegisterInfo.h" + +namespace llvm { + class MCSection; + class MCContext; + class TargetMachine; + class TargetLoweringObjectFile; + +class TargetAsmInfo { + unsigned PointerSize; + bool IsLittleEndian; + TargetFrameLowering::StackDirection StackDir; + const TargetRegisterInfo *TRI; + std::vector InitialFrameState; + const TargetLoweringObjectFile *TLOF; + +public: + explicit TargetAsmInfo(const TargetMachine &TM); + + /// getPointerSize - Get the pointer size in bytes. + unsigned getPointerSize() const { + return PointerSize; + } + + /// islittleendian - True if the target is little endian. + bool isLittleEndian() const { + return IsLittleEndian; + } + + TargetFrameLowering::StackDirection getStackGrowthDirection() const { + return StackDir; + } + + const MCSection *getDwarfLineSection() const { + return TLOF->getDwarfLineSection(); + } + + const MCSection *getEHFrameSection() const { + return TLOF->getEHFrameSection(); + } + + unsigned getDwarfRARegNum(bool isEH) const { + return TRI->getDwarfRegNum(TRI->getRARegister(), isEH); + } + + const std::vector &getInitialFrameState() const { + return InitialFrameState; + } + + int getDwarfRegNum(unsigned RegNum, bool isEH) const { + return TRI->getDwarfRegNum(RegNum, isEH); + } +}; + +} +#endif diff --git a/include/llvm/Target/TargetAsmParser.h b/include/llvm/Target/TargetAsmParser.h index 5830d1f99f5c..9ff50cb275be 100644 --- a/include/llvm/Target/TargetAsmParser.h +++ b/include/llvm/Target/TargetAsmParser.h @@ -13,7 +13,7 @@ #include "llvm/MC/MCParser/MCAsmParserExtension.h" namespace llvm { -class MCInst; +class MCStreamer; class StringRef; class Target; class SMLoc; @@ -42,6 +42,8 @@ public: unsigned getAvailableFeatures() const { return AvailableFeatures; } void setAvailableFeatures(unsigned Value) { AvailableFeatures = Value; } + virtual bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) = 0; + /// ParseInstruction - Parse one assembly instruction. /// /// The parser is positioned following the instruction name. The target @@ -70,16 +72,16 @@ public: /// \param DirectiveID - the identifier token of the directive. virtual bool ParseDirective(AsmToken DirectiveID) = 0; - /// MatchInstruction - Recognize a series of operands of a parsed instruction - /// as an actual MCInst. This returns false and fills in Inst on success and - /// returns true on failure to match. + /// MatchAndEmitInstruction - Recognize a series of operands of a parsed + /// instruction as an actual MCInst and emit it to the specified MCStreamer. + /// This returns false on success and returns true on failure to match. /// /// On failure, the target parser is responsible for emitting a diagnostic /// explaining the match failure. virtual bool - MatchInstruction(SMLoc IDLoc, - const SmallVectorImpl &Operands, - MCInst &Inst) = 0; + MatchAndEmitInstruction(SMLoc IDLoc, + SmallVectorImpl &Operands, + MCStreamer &Out) = 0; }; diff --git a/include/llvm/Target/TargetCallingConv.h b/include/llvm/Target/TargetCallingConv.h index f368a2e38c42..275957e01532 100644 --- a/include/llvm/Target/TargetCallingConv.h +++ b/include/llvm/Target/TargetCallingConv.h @@ -106,14 +106,13 @@ namespace ISD { /// struct InputArg { ArgFlagsTy Flags; - EVT VT; + MVT VT; bool Used; InputArg() : VT(MVT::Other), Used(false) {} InputArg(ArgFlagsTy flags, EVT vt, bool used) - : Flags(flags), VT(vt), Used(used) { - assert(VT.isSimple() && - "InputArg value type must be Simple!"); + : Flags(flags), Used(used) { + VT = vt.getSimpleVT(); } }; @@ -123,16 +122,15 @@ namespace ISD { /// struct OutputArg { ArgFlagsTy Flags; - EVT VT; + MVT VT; /// IsFixed - Is this a "fixed" value, ie not passed through a vararg "...". bool IsFixed; OutputArg() : IsFixed(false) {} OutputArg(ArgFlagsTy flags, EVT vt, bool isfixed) - : Flags(flags), VT(vt), IsFixed(isfixed) { - assert(VT.isSimple() && - "OutputArg value type must be Simple!"); + : Flags(flags), IsFixed(isfixed) { + VT = vt.getSimpleVT(); } }; } diff --git a/include/llvm/Target/TargetData.h b/include/llvm/Target/TargetData.h index b89cbe0133f8..25065d30bb6e 100644 --- a/include/llvm/Target/TargetData.h +++ b/include/llvm/Target/TargetData.h @@ -22,6 +22,7 @@ #include "llvm/Pass.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/DataTypes.h" namespace llvm { @@ -143,7 +144,7 @@ public: std::string getStringRepresentation() const; /// isLegalInteger - This function returns true if the specified type is - /// known tobe a native integer type supported by the CPU. For example, + /// known to be a native integer type supported by the CPU. For example, /// i64 is not native on most 32-bit CPUs and i37 is not native on any known /// one. This returns false if the integer width is not legal. /// diff --git a/include/llvm/Target/TargetELFWriterInfo.h b/include/llvm/Target/TargetELFWriterInfo.h index 7cb693155c29..b97f3e2f4d0f 100644 --- a/include/llvm/Target/TargetELFWriterInfo.h +++ b/include/llvm/Target/TargetELFWriterInfo.h @@ -28,7 +28,6 @@ namespace llvm { // EMachine - This field is the target specific value to emit as the // e_machine member of the ELF header. unsigned short EMachine; - TargetMachine &TM; bool is64Bit, isLittleEndian; public: @@ -62,7 +61,7 @@ namespace llvm { ELFDATA2MSB = 2 // Big-endian object file }; - explicit TargetELFWriterInfo(TargetMachine &tm); + explicit TargetELFWriterInfo(bool is64Bit_, bool isLittleEndian_); virtual ~TargetELFWriterInfo(); unsigned short getEMachine() const { return EMachine; } diff --git a/include/llvm/Target/TargetFrameInfo.h b/include/llvm/Target/TargetFrameInfo.h deleted file mode 100644 index 975d15659c15..000000000000 --- a/include/llvm/Target/TargetFrameInfo.h +++ /dev/null @@ -1,97 +0,0 @@ -//===-- llvm/Target/TargetFrameInfo.h ---------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Interface to describe the layout of a stack frame on the target machine. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TARGET_TARGETFRAMEINFO_H -#define LLVM_TARGET_TARGETFRAMEINFO_H - -#include - -namespace llvm { - -/// Information about stack frame layout on the target. It holds the direction -/// of stack growth, the known stack alignment on entry to each function, and -/// the offset to the locals area. -/// -/// The offset to the local area is the offset from the stack pointer on -/// function entry to the first location where function data (local variables, -/// spill locations) can be stored. -class TargetFrameInfo { -public: - enum StackDirection { - StackGrowsUp, // Adding to the stack increases the stack address - StackGrowsDown // Adding to the stack decreases the stack address - }; - - // Maps a callee saved register to a stack slot with a fixed offset. - struct SpillSlot { - unsigned Reg; - int Offset; // Offset relative to stack pointer on function entry. - }; -private: - StackDirection StackDir; - unsigned StackAlignment; - unsigned TransientStackAlignment; - int LocalAreaOffset; -public: - TargetFrameInfo(StackDirection D, unsigned StackAl, int LAO, - unsigned TransAl = 1) - : StackDir(D), StackAlignment(StackAl), TransientStackAlignment(TransAl), - LocalAreaOffset(LAO) {} - - virtual ~TargetFrameInfo(); - - // These methods return information that describes the abstract stack layout - // of the target machine. - - /// getStackGrowthDirection - Return the direction the stack grows - /// - StackDirection getStackGrowthDirection() const { return StackDir; } - - /// getStackAlignment - This method returns the number of bytes to which the - /// stack pointer must be aligned on entry to a function. Typically, this - /// is the largest alignment for any data object in the target. - /// - unsigned getStackAlignment() const { return StackAlignment; } - - /// getTransientStackAlignment - This method returns the number of bytes to - /// which the stack pointer must be aligned at all times, even between - /// calls. - /// - unsigned getTransientStackAlignment() const { - return TransientStackAlignment; - } - - /// getOffsetOfLocalArea - This method returns the offset of the local area - /// from the stack pointer on entrance to a function. - /// - int getOffsetOfLocalArea() const { return LocalAreaOffset; } - - /// getCalleeSavedSpillSlots - This method returns a pointer to an array of - /// pairs, that contains an entry for each callee saved register that must be - /// spilled to a particular stack location if it is spilled. - /// - /// Each entry in this array contains a pair, indicating the - /// fixed offset from the incoming stack pointer that each register should be - /// spilled at. If a register is not listed here, the code generator is - /// allowed to spill it anywhere it chooses. - /// - virtual const SpillSlot * - getCalleeSavedSpillSlots(unsigned &NumEntries) const { - NumEntries = 0; - return 0; - } -}; - -} // End llvm namespace - -#endif diff --git a/include/llvm/Target/TargetFrameLowering.h b/include/llvm/Target/TargetFrameLowering.h new file mode 100644 index 000000000000..e104b1663fdd --- /dev/null +++ b/include/llvm/Target/TargetFrameLowering.h @@ -0,0 +1,196 @@ +//===-- llvm/Target/TargetFrameLowering.h ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Interface to describe the layout of a stack frame on the target machine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_TARGETFRAMELOWERING_H +#define LLVM_TARGET_TARGETFRAMELOWERING_H + +#include "llvm/CodeGen/MachineBasicBlock.h" + +#include +#include + +namespace llvm { + class CalleeSavedInfo; + class MachineFunction; + class MachineBasicBlock; + class MachineMove; + class RegScavenger; + +/// Information about stack frame layout on the target. It holds the direction +/// of stack growth, the known stack alignment on entry to each function, and +/// the offset to the locals area. +/// +/// The offset to the local area is the offset from the stack pointer on +/// function entry to the first location where function data (local variables, +/// spill locations) can be stored. +class TargetFrameLowering { +public: + enum StackDirection { + StackGrowsUp, // Adding to the stack increases the stack address + StackGrowsDown // Adding to the stack decreases the stack address + }; + + // Maps a callee saved register to a stack slot with a fixed offset. + struct SpillSlot { + unsigned Reg; + int Offset; // Offset relative to stack pointer on function entry. + }; +private: + StackDirection StackDir; + unsigned StackAlignment; + unsigned TransientStackAlignment; + int LocalAreaOffset; +public: + TargetFrameLowering(StackDirection D, unsigned StackAl, int LAO, + unsigned TransAl = 1) + : StackDir(D), StackAlignment(StackAl), TransientStackAlignment(TransAl), + LocalAreaOffset(LAO) {} + + virtual ~TargetFrameLowering(); + + // These methods return information that describes the abstract stack layout + // of the target machine. + + /// getStackGrowthDirection - Return the direction the stack grows + /// + StackDirection getStackGrowthDirection() const { return StackDir; } + + /// getStackAlignment - This method returns the number of bytes to which the + /// stack pointer must be aligned on entry to a function. Typically, this + /// is the largest alignment for any data object in the target. + /// + unsigned getStackAlignment() const { return StackAlignment; } + + /// getTransientStackAlignment - This method returns the number of bytes to + /// which the stack pointer must be aligned at all times, even between + /// calls. + /// + unsigned getTransientStackAlignment() const { + return TransientStackAlignment; + } + + /// getOffsetOfLocalArea - This method returns the offset of the local area + /// from the stack pointer on entrance to a function. + /// + int getOffsetOfLocalArea() const { return LocalAreaOffset; } + + /// getCalleeSavedSpillSlots - This method returns a pointer to an array of + /// pairs, that contains an entry for each callee saved register that must be + /// spilled to a particular stack location if it is spilled. + /// + /// Each entry in this array contains a pair, indicating the + /// fixed offset from the incoming stack pointer that each register should be + /// spilled at. If a register is not listed here, the code generator is + /// allowed to spill it anywhere it chooses. + /// + virtual const SpillSlot * + getCalleeSavedSpillSlots(unsigned &NumEntries) const { + NumEntries = 0; + return 0; + } + + /// targetHandlesStackFrameRounding - Returns true if the target is + /// responsible for rounding up the stack frame (probably at emitPrologue + /// time). + virtual bool targetHandlesStackFrameRounding() const { + return false; + } + + /// emitProlog/emitEpilog - These methods insert prolog and epilog code into + /// the function. + virtual void emitPrologue(MachineFunction &MF) const = 0; + virtual void emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const = 0; + + /// spillCalleeSavedRegisters - Issues instruction(s) to spill all callee + /// saved registers and returns true if it isn't possible / profitable to do + /// so by issuing a series of store instructions via + /// storeRegToStackSlot(). Returns false otherwise. + virtual bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector &CSI, + const TargetRegisterInfo *TRI) const { + return false; + } + + /// restoreCalleeSavedRegisters - Issues instruction(s) to restore all callee + /// saved registers and returns true if it isn't possible / profitable to do + /// so by issuing a series of load instructions via loadRegToStackSlot(). + /// Returns false otherwise. + virtual bool restoreCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector &CSI, + const TargetRegisterInfo *TRI) const { + return false; + } + + /// hasFP - Return true if the specified function should have a dedicated + /// frame pointer register. For most targets this is true only if the function + /// has variable sized allocas or if frame pointer elimination is disabled. + virtual bool hasFP(const MachineFunction &MF) const = 0; + + /// hasReservedCallFrame - Under normal circumstances, when a frame pointer is + /// not required, we reserve argument space for call sites in the function + /// immediately on entry to the current function. This eliminates the need for + /// add/sub sp brackets around call sites. Returns true if the call frame is + /// included as part of the stack frame. + virtual bool hasReservedCallFrame(const MachineFunction &MF) const { + return !hasFP(MF); + } + + /// canSimplifyCallFramePseudos - When possible, it's best to simplify the + /// call frame pseudo ops before doing frame index elimination. This is + /// possible only when frame index references between the pseudos won't + /// need adjusting for the call frame adjustments. Normally, that's true + /// if the function has a reserved call frame or a frame pointer. Some + /// targets (Thumb2, for example) may have more complicated criteria, + /// however, and can override this behavior. + virtual bool canSimplifyCallFramePseudos(const MachineFunction &MF) const { + return hasReservedCallFrame(MF) || hasFP(MF); + } + + /// getInitialFrameState - Returns a list of machine moves that are assumed + /// on entry to all functions. Note that LabelID is ignored (assumed to be + /// the beginning of the function.) + virtual void getInitialFrameState(std::vector &Moves) const; + + /// getFrameIndexOffset - Returns the displacement from the frame register to + /// the stack frame of the specified index. + virtual int getFrameIndexOffset(const MachineFunction &MF, int FI) const; + + /// getFrameIndexReference - This method should return the base register + /// and offset used to reference a frame index location. The offset is + /// returned directly, and the base register is returned via FrameReg. + virtual int getFrameIndexReference(const MachineFunction &MF, int FI, + unsigned &FrameReg) const; + + /// processFunctionBeforeCalleeSavedScan - This method is called immediately + /// before PrologEpilogInserter scans the physical registers used to determine + /// what callee saved registers should be spilled. This method is optional. + virtual void processFunctionBeforeCalleeSavedScan(MachineFunction &MF, + RegScavenger *RS = NULL) const { + + } + + /// processFunctionBeforeFrameFinalized - This method is called immediately + /// before the specified function's frame layout (MF.getFrameInfo()) is + /// finalized. Once the frame is finalized, MO_FrameIndex operands are + /// replaced with direct constants. This method is optional. + /// + virtual void processFunctionBeforeFrameFinalized(MachineFunction &MF) const { + } +}; + +} // End llvm namespace + +#endif diff --git a/include/llvm/Target/TargetInstrDesc.h b/include/llvm/Target/TargetInstrDesc.h index a127aed8f6df..8823d5a4d17e 100644 --- a/include/llvm/Target/TargetInstrDesc.h +++ b/include/llvm/Target/TargetInstrDesc.h @@ -15,7 +15,7 @@ #ifndef LLVM_TARGET_TARGETINSTRDESC_H #define LLVM_TARGET_TARGETINSTRDESC_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { @@ -103,13 +103,14 @@ namespace TID { Terminator, Branch, IndirectBranch, - Predicable, - NotDuplicable, Compare, + MoveImm, DelaySlot, FoldableAsLoad, MayLoad, MayStore, + Predicable, + NotDuplicable, UnmodeledSideEffects, Commutable, ConvertibleTo3Addr, @@ -352,6 +353,12 @@ public: return Flags & (1 << TID::Compare); } + /// isMoveImmediate - Return true if this instruction is a move immediate + /// (including conditional moves) instruction. + bool isMoveImmediate() const { + return Flags & (1 << TID::MoveImm); + } + /// isNotDuplicable - Return true if this instruction cannot be safely /// duplicated. For example, if the instruction has a unique labels attached /// to it, duplicating it would cause multiple definition errors. diff --git a/include/llvm/Target/TargetInstrInfo.h b/include/llvm/Target/TargetInstrInfo.h index 520c41be7428..fc7b51ec6c2c 100644 --- a/include/llvm/Target/TargetInstrInfo.h +++ b/include/llvm/Target/TargetInstrInfo.h @@ -19,16 +19,17 @@ namespace llvm { -class CalleeSavedInfo; class InstrItineraryData; class LiveVariables; class MCAsmInfo; class MachineMemOperand; +class MachineRegisterInfo; class MDNode; class MCInst; class SDNode; class ScheduleHazardRecognizer; class SelectionDAG; +class ScheduleDAG; class TargetRegisterClass; class TargetRegisterInfo; @@ -134,7 +135,7 @@ public: int &FrameIndex) const { return 0; } - + /// isStoreToStackSlot - If the specified machine instruction is a direct /// store to a stack slot, return the virtual or physical register number of /// the source reg along with the FrameIndex of the loaded stack slot. If @@ -227,9 +228,12 @@ public: /// produceSameValue - Return true if two machine instructions would produce /// identical values. By default, this is only true when the two instructions - /// are deemed identical except for defs. + /// are deemed identical except for defs. If this function is called when the + /// IR is still in SSA form, the caller can pass the MachineRegisterInfo for + /// aggressive checks. virtual bool produceSameValue(const MachineInstr *MI0, - const MachineInstr *MI1) const = 0; + const MachineInstr *MI1, + const MachineRegisterInfo *MRI = 0) const = 0; /// AnalyzeBranch - Analyze the branching code at the end of MBB, returning /// true if it cannot be understood (e.g. it's a switch dispatch or isn't @@ -267,7 +271,7 @@ public: /// This is only invoked in cases where AnalyzeBranch returns success. It /// returns the number of instructions that were removed. virtual unsigned RemoveBranch(MachineBasicBlock &MBB) const { - assert(0 && "Target didn't implement TargetInstrInfo::RemoveBranch!"); + assert(0 && "Target didn't implement TargetInstrInfo::RemoveBranch!"); return 0; } @@ -285,7 +289,7 @@ public: MachineBasicBlock *FBB, const SmallVectorImpl &Cond, DebugLoc DL) const { - assert(0 && "Target didn't implement TargetInstrInfo::InsertBranch!"); + assert(0 && "Target didn't implement TargetInstrInfo::InsertBranch!"); return 0; } @@ -303,31 +307,45 @@ public: return true; } - /// isProfitableToIfCvt - Return true if it's profitable to first "NumInstrs" - /// of the specified basic block. + /// isProfitableToIfCvt - Return true if it's profitable to predicate + /// instructions with accumulated instruction latency of "NumCycles" + /// of the specified basic block, where the probability of the instructions + /// being executed is given by Probability, and Confidence is a measure + /// of our confidence that it will be properly predicted. virtual - bool isProfitableToIfCvt(MachineBasicBlock &MBB, unsigned NumInstrs) const { + bool isProfitableToIfCvt(MachineBasicBlock &MBB, unsigned NumCyles, + unsigned ExtraPredCycles, + float Probability, float Confidence) const { return false; } - + /// isProfitableToIfCvt - Second variant of isProfitableToIfCvt, this one /// checks for the case where two basic blocks from true and false path /// of a if-then-else (diamond) are predicated on mutally exclusive - /// predicates. + /// predicates, where the probability of the true path being taken is given + /// by Probability, and Confidence is a measure of our confidence that it + /// will be properly predicted. virtual bool - isProfitableToIfCvt(MachineBasicBlock &TMBB, unsigned NumTInstrs, - MachineBasicBlock &FMBB, unsigned NumFInstrs) const { + isProfitableToIfCvt(MachineBasicBlock &TMBB, + unsigned NumTCycles, unsigned ExtraTCycles, + MachineBasicBlock &FMBB, + unsigned NumFCycles, unsigned ExtraFCycles, + float Probability, float Confidence) const { return false; } /// isProfitableToDupForIfCvt - Return true if it's profitable for - /// if-converter to duplicate a specific number of instructions in the - /// specified MBB to enable if-conversion. + /// if-converter to duplicate instructions of specified accumulated + /// instruction latencies in the specified MBB to enable if-conversion. + /// The probability of the instructions being executed is given by + /// Probability, and Confidence is a measure of our confidence that it + /// will be properly predicted. virtual bool - isProfitableToDupForIfCvt(MachineBasicBlock &MBB,unsigned NumInstrs) const { + isProfitableToDupForIfCvt(MachineBasicBlock &MBB, unsigned NumCyles, + float Probability, float Confidence) const { return false; } - + /// copyPhysReg - Emit instructions to copy a pair of physical registers. virtual void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, DebugLoc DL, @@ -360,29 +378,7 @@ public: const TargetRegisterInfo *TRI) const { assert(0 && "Target didn't implement TargetInstrInfo::loadRegFromStackSlot!"); } - - /// spillCalleeSavedRegisters - Issues instruction(s) to spill all callee - /// saved registers and returns true if it isn't possible / profitable to do - /// so by issuing a series of store instructions via - /// storeRegToStackSlot(). Returns false otherwise. - virtual bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, - const std::vector &CSI, - const TargetRegisterInfo *TRI) const { - return false; - } - /// restoreCalleeSavedRegisters - Issues instruction(s) to restore all callee - /// saved registers and returns true if it isn't possible / profitable to do - /// so by issuing a series of load instructions via loadRegToStackSlot(). - /// Returns false otherwise. - virtual bool restoreCalleeSavedRegisters(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, - const std::vector &CSI, - const TargetRegisterInfo *TRI) const { - return false; - } - /// emitFrameIndexDebugValue - Emit a target-dependent form of /// DBG_VALUE encoding the address of a frame index. Addresses would /// normally be lowered the same way as other addresses on the target, @@ -493,7 +489,7 @@ public: unsigned NumLoads) const { return false; } - + /// ReverseBranchCondition - Reverses the branch condition of the specified /// condition list, returning false on success and true if it cannot be /// reversed. @@ -501,19 +497,19 @@ public: bool ReverseBranchCondition(SmallVectorImpl &Cond) const { return true; } - + /// insertNoop - Insert a noop into the instruction stream at the specified /// point. - virtual void insertNoop(MachineBasicBlock &MBB, + virtual void insertNoop(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const; - - + + /// getNoopForMachoTarget - Return the noop instruction to use for a noop. virtual void getNoopForMachoTarget(MCInst &NopInst) const { // Default to just using 'nop' string. } - - + + /// isPredicated - Returns true if the instruction is already predicated. /// virtual bool isPredicated(const MachineInstr *MI) const { @@ -571,26 +567,98 @@ public: virtual unsigned getInlineAsmLength(const char *Str, const MCAsmInfo &MAI) const; - /// CreateTargetHazardRecognizer - Allocate and return a hazard recognizer - /// to use for this target when scheduling the machine instructions after + /// CreateTargetHazardRecognizer - Allocate and return a hazard recognizer to + /// use for this target when scheduling the machine instructions before /// register allocation. virtual ScheduleHazardRecognizer* - CreateTargetPostRAHazardRecognizer(const InstrItineraryData&) const = 0; + CreateTargetHazardRecognizer(const TargetMachine *TM, + const ScheduleDAG *DAG) const = 0; + + /// CreateTargetPostRAHazardRecognizer - Allocate and return a hazard + /// recognizer to use for this target when scheduling the machine instructions + /// after register allocation. + virtual ScheduleHazardRecognizer* + CreateTargetPostRAHazardRecognizer(const InstrItineraryData*, + const ScheduleDAG *DAG) const = 0; /// AnalyzeCompare - For a comparison instruction, return the source register /// in SrcReg and the value it compares against in CmpValue. Return true if /// the comparison instruction can be analyzed. virtual bool AnalyzeCompare(const MachineInstr *MI, - unsigned &SrcReg, int &CmpValue) const { + unsigned &SrcReg, int &Mask, int &Value) const { + return false; + } + + /// OptimizeCompareInstr - See if the comparison instruction can be converted + /// into something more efficient. E.g., on ARM most instructions can set the + /// flags register, obviating the need for a separate CMP. + virtual bool OptimizeCompareInstr(MachineInstr *CmpInstr, + unsigned SrcReg, int Mask, int Value, + const MachineRegisterInfo *MRI) const { return false; } - /// ConvertToSetZeroFlag - Convert the instruction to set the zero flag so - /// that we can remove a "comparison with zero". - virtual bool ConvertToSetZeroFlag(MachineInstr *Instr, - MachineInstr *CmpInstr) const { + /// FoldImmediate - 'Reg' is known to be defined by a move immediate + /// instruction, try to fold the immediate into the use instruction. + virtual bool FoldImmediate(MachineInstr *UseMI, MachineInstr *DefMI, + unsigned Reg, MachineRegisterInfo *MRI) const { return false; } + + /// getNumMicroOps - Return the number of u-operations the given machine + /// instruction will be decoded to on the target cpu. + virtual unsigned getNumMicroOps(const InstrItineraryData *ItinData, + const MachineInstr *MI) const; + + /// isZeroCost - Return true for pseudo instructions that don't consume any + /// machine resources in their current form. These are common cases that the + /// scheduler should consider free, rather than conservatively handling them + /// as instructions with no itinerary. + bool isZeroCost(unsigned Opcode) const { + return Opcode <= TargetOpcode::COPY; + } + + /// getOperandLatency - Compute and return the use operand latency of a given + /// pair of def and use. + /// In most cases, the static scheduling itinerary was enough to determine the + /// operand latency. But it may not be possible for instructions with variable + /// number of defs / uses. + virtual int getOperandLatency(const InstrItineraryData *ItinData, + const MachineInstr *DefMI, unsigned DefIdx, + const MachineInstr *UseMI, unsigned UseIdx) const; + + virtual int getOperandLatency(const InstrItineraryData *ItinData, + SDNode *DefNode, unsigned DefIdx, + SDNode *UseNode, unsigned UseIdx) const; + + /// getInstrLatency - Compute the instruction latency of a given instruction. + /// If the instruction has higher cost when predicated, it's returned via + /// PredCost. + virtual int getInstrLatency(const InstrItineraryData *ItinData, + const MachineInstr *MI, + unsigned *PredCost = 0) const; + + virtual int getInstrLatency(const InstrItineraryData *ItinData, + SDNode *Node) const; + + /// hasHighOperandLatency - Compute operand latency between a def of 'Reg' + /// and an use in the current loop, return true if the target considered + /// it 'high'. This is used by optimization passes such as machine LICM to + /// determine whether it makes sense to hoist an instruction out even in + /// high register pressure situation. + virtual + bool hasHighOperandLatency(const InstrItineraryData *ItinData, + const MachineRegisterInfo *MRI, + const MachineInstr *DefMI, unsigned DefIdx, + const MachineInstr *UseMI, unsigned UseIdx) const { + return false; + } + + /// hasLowDefLatency - Compute operand latency of a def of 'Reg', return true + /// if the target considered it 'low'. + virtual + bool hasLowDefLatency(const InstrItineraryData *ItinData, + const MachineInstr *DefMI, unsigned DefIdx) const; }; /// TargetInstrInfoImpl - This is the default implementation of @@ -620,13 +688,20 @@ public: virtual MachineInstr *duplicate(MachineInstr *Orig, MachineFunction &MF) const; virtual bool produceSameValue(const MachineInstr *MI0, - const MachineInstr *MI1) const; + const MachineInstr *MI1, + const MachineRegisterInfo *MRI) const; virtual bool isSchedulingBoundary(const MachineInstr *MI, const MachineBasicBlock *MBB, const MachineFunction &MF) const; + bool usePreRAHazardRecognizer() const; + + virtual ScheduleHazardRecognizer * + CreateTargetHazardRecognizer(const TargetMachine*, const ScheduleDAG*) const; + virtual ScheduleHazardRecognizer * - CreateTargetPostRAHazardRecognizer(const InstrItineraryData&) const; + CreateTargetPostRAHazardRecognizer(const InstrItineraryData*, + const ScheduleDAG*) const; }; } // End llvm namespace diff --git a/include/llvm/Target/TargetInstrItineraries.h b/include/llvm/Target/TargetInstrItineraries.h index 39648c233fa8..a95b70f6b997 100644 --- a/include/llvm/Target/TargetInstrItineraries.h +++ b/include/llvm/Target/TargetInstrItineraries.h @@ -95,6 +95,7 @@ struct InstrStage { /// operands are read and written. /// struct InstrItinerary { + unsigned NumMicroOps; ///< # of micro-ops, 0 means it's variable unsigned FirstStage; ///< Index of first stage in itinerary unsigned LastStage; ///< Index of last + 1 stage in itinerary unsigned FirstOperandCycle; ///< Index of first operand rd/wr @@ -110,38 +111,42 @@ class InstrItineraryData { public: const InstrStage *Stages; ///< Array of stages selected const unsigned *OperandCycles; ///< Array of operand cycles selected - const InstrItinerary *Itineratries; ///< Array of itineraries selected + const unsigned *Forwardings; ///< Array of pipeline forwarding pathes + const InstrItinerary *Itineraries; ///< Array of itineraries selected + unsigned IssueWidth; ///< Max issue per cycle. 0=Unknown. /// Ctors. /// - InstrItineraryData() : Stages(0), OperandCycles(0), Itineratries(0) {} + InstrItineraryData() : Stages(0), OperandCycles(0), Forwardings(0), + Itineraries(0), IssueWidth(0) {} + InstrItineraryData(const InstrStage *S, const unsigned *OS, - const InstrItinerary *I) - : Stages(S), OperandCycles(OS), Itineratries(I) {} - + const unsigned *F, const InstrItinerary *I) + : Stages(S), OperandCycles(OS), Forwardings(F), Itineraries(I) {} + /// isEmpty - Returns true if there are no itineraries. /// - bool isEmpty() const { return Itineratries == 0; } + bool isEmpty() const { return Itineraries == 0; } /// isEndMarker - Returns true if the index is for the end marker /// itinerary. /// bool isEndMarker(unsigned ItinClassIndx) const { - return ((Itineratries[ItinClassIndx].FirstStage == ~0U) && - (Itineratries[ItinClassIndx].LastStage == ~0U)); + return ((Itineraries[ItinClassIndx].FirstStage == ~0U) && + (Itineraries[ItinClassIndx].LastStage == ~0U)); } /// beginStage - Return the first stage of the itinerary. - /// + /// const InstrStage *beginStage(unsigned ItinClassIndx) const { - unsigned StageIdx = Itineratries[ItinClassIndx].FirstStage; + unsigned StageIdx = Itineraries[ItinClassIndx].FirstStage; return Stages + StageIdx; } /// endStage - Return the last+1 stage of the itinerary. - /// + /// const InstrStage *endStage(unsigned ItinClassIndx) const { - unsigned StageIdx = Itineratries[ItinClassIndx].LastStage; + unsigned StageIdx = Itineraries[ItinClassIndx].LastStage; return Stages + StageIdx; } @@ -173,13 +178,68 @@ public: if (isEmpty()) return -1; - unsigned FirstIdx = Itineratries[ItinClassIndx].FirstOperandCycle; - unsigned LastIdx = Itineratries[ItinClassIndx].LastOperandCycle; + unsigned FirstIdx = Itineraries[ItinClassIndx].FirstOperandCycle; + unsigned LastIdx = Itineraries[ItinClassIndx].LastOperandCycle; if ((FirstIdx + OperandIdx) >= LastIdx) return -1; return (int)OperandCycles[FirstIdx + OperandIdx]; } + + /// hasPipelineForwarding - Return true if there is a pipeline forwarding + /// between instructions of itinerary classes DefClass and UseClasses so that + /// value produced by an instruction of itinerary class DefClass, operand + /// index DefIdx can be bypassed when it's read by an instruction of + /// itinerary class UseClass, operand index UseIdx. + bool hasPipelineForwarding(unsigned DefClass, unsigned DefIdx, + unsigned UseClass, unsigned UseIdx) const { + unsigned FirstDefIdx = Itineraries[DefClass].FirstOperandCycle; + unsigned LastDefIdx = Itineraries[DefClass].LastOperandCycle; + if ((FirstDefIdx + DefIdx) >= LastDefIdx) + return false; + if (Forwardings[FirstDefIdx + DefIdx] == 0) + return false; + + unsigned FirstUseIdx = Itineraries[UseClass].FirstOperandCycle; + unsigned LastUseIdx = Itineraries[UseClass].LastOperandCycle; + if ((FirstUseIdx + UseIdx) >= LastUseIdx) + return false; + + return Forwardings[FirstDefIdx + DefIdx] == + Forwardings[FirstUseIdx + UseIdx]; + } + + /// getOperandLatency - Compute and return the use operand latency of a given + /// itinerary class and operand index if the value is produced by an + /// instruction of the specified itinerary class and def operand index. + int getOperandLatency(unsigned DefClass, unsigned DefIdx, + unsigned UseClass, unsigned UseIdx) const { + if (isEmpty()) + return -1; + + int DefCycle = getOperandCycle(DefClass, DefIdx); + if (DefCycle == -1) + return -1; + + int UseCycle = getOperandCycle(UseClass, UseIdx); + if (UseCycle == -1) + return -1; + + UseCycle = DefCycle - UseCycle + 1; + if (UseCycle > 0 && + hasPipelineForwarding(DefClass, DefIdx, UseClass, UseIdx)) + // FIXME: This assumes one cycle benefit for every pipeline forwarding. + --UseCycle; + return UseCycle; + } + + /// isMicroCoded - Return true if the instructions in the given class decode + /// to more than one micro-ops. + bool isMicroCoded(unsigned ItinClassIndx) const { + if (isEmpty()) + return false; + return Itineraries[ItinClassIndx].NumMicroOps != 1; + } }; diff --git a/include/llvm/Target/TargetJITInfo.h b/include/llvm/Target/TargetJITInfo.h index 7208a8dc4464..b198eb62f0c6 100644 --- a/include/llvm/Target/TargetJITInfo.h +++ b/include/llvm/Target/TargetJITInfo.h @@ -19,7 +19,7 @@ #include #include "llvm/Support/ErrorHandling.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { class Function; diff --git a/include/llvm/Target/TargetLibraryInfo.h b/include/llvm/Target/TargetLibraryInfo.h new file mode 100644 index 000000000000..bdd214b6b743 --- /dev/null +++ b/include/llvm/Target/TargetLibraryInfo.h @@ -0,0 +1,66 @@ +//===-- llvm/Target/TargetLibraryInfo.h - Library information ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TARGET_TARGETLIBRARYINFO_H +#define LLVM_TARGET_TARGETLIBRARYINFO_H + +#include "llvm/Pass.h" + +namespace llvm { + class Triple; + + namespace LibFunc { + enum Func { + /// void *memset(void *b, int c, size_t len); + memset, + + // void *memcpy(void *s1, const void *s2, size_t n); + memcpy, + + /// void memset_pattern16(void *b, const void *pattern16, size_t len); + memset_pattern16, + + NumLibFuncs + }; + } + +/// TargetLibraryInfo - This immutable pass captures information about what +/// library functions are available for the current target, and allows a +/// frontend to disable optimizations through -fno-builtin etc. +class TargetLibraryInfo : public ImmutablePass { + unsigned char AvailableArray[(LibFunc::NumLibFuncs+7)/8]; +public: + static char ID; + TargetLibraryInfo(); + TargetLibraryInfo(const Triple &T); + + /// has - This function is used by optimizations that want to match on or form + /// a given library function. + bool has(LibFunc::Func F) const { + return (AvailableArray[F/8] & (1 << (F&7))) != 0; + } + + /// setUnavailable - this can be used by whatever sets up TargetLibraryInfo to + /// ban use of specific library functions. + void setUnavailable(LibFunc::Func F) { + AvailableArray[F/8] &= ~(1 << (F&7)); + } + + void setAvailable(LibFunc::Func F) { + AvailableArray[F/8] |= 1 << (F&7); + } + + /// disableAllFunctions - This disables all builtins, which is used for + /// options like -fno-builtin. + void disableAllFunctions(); +}; + +} // end namespace llvm + +#endif diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h index 29de994a21c9..5141b7b56229 100644 --- a/include/llvm/Target/TargetLowering.h +++ b/include/llvm/Target/TargetLowering.h @@ -25,13 +25,9 @@ #include "llvm/CallingConv.h" #include "llvm/InlineAsm.h" #include "llvm/Attributes.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/CodeGen/SelectionDAGNodes.h" #include "llvm/CodeGen/RuntimeLibcalls.h" -#include "llvm/ADT/APFloat.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallSet.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/Support/DebugLoc.h" #include "llvm/Target/TargetCallingConv.h" #include "llvm/Target/TargetMachine.h" @@ -41,10 +37,12 @@ namespace llvm { class AllocaInst; + class APFloat; class CallInst; class Function; class FastISel; class FunctionLoweringInfo; + class ImmutableCallSite; class MachineBasicBlock; class MachineFunction; class MachineFrameInfo; @@ -55,6 +53,7 @@ namespace llvm { class SDNode; class SDValue; class SelectionDAG; + template class SmallVectorImpl; class TargetData; class TargetMachine; class TargetRegisterClass; @@ -126,6 +125,10 @@ public: /// srl/add/sra. bool isPow2DivCheap() const { return Pow2DivIsCheap; } + /// isJumpExpensive() - Return true if Flow Control is an expensive operation + /// that should be avoided. + bool isJumpExpensive() const { return JumpIsExpensive; } + /// getSetCCResultType - Return the ValueType of the result of SETCC /// operations. Also used to obtain the target's preferred type for /// the condition operand of SELECT and BRCOND nodes. In the case of @@ -203,13 +206,6 @@ public: return VT.isSimple() && RegClassForVT[VT.getSimpleVT().SimpleTy] != 0; } - /// isTypeSynthesizable - Return true if it's OK for the compiler to create - /// new operations of this type. All Legal types are synthesizable except - /// MMX vector types on X86. Non-Legal types are not synthesizable. - bool isTypeSynthesizable(EVT VT) const { - return isTypeLegal(VT) && Synthesizable[VT.getSimpleVT().SimpleTy]; - } - class ValueTypeActionImpl { /// ValueTypeActions - For each value type, keep a LegalizeAction enum /// that indicates how instruction selection should deal with the type. @@ -441,7 +437,7 @@ public: /// for it. LegalizeAction getLoadExtAction(unsigned ExtType, EVT VT) const { assert(ExtType < ISD::LAST_LOADEXT_TYPE && - (unsigned)VT.getSimpleVT().SimpleTy < MVT::LAST_VALUETYPE && + VT.getSimpleVT() < MVT::LAST_VALUETYPE && "Table isn't big enough!"); return (LegalizeAction)LoadExtActions[VT.getSimpleVT().SimpleTy][ExtType]; } @@ -459,8 +455,8 @@ public: /// to be expanded to some other code sequence, or the target has a custom /// expander for it. LegalizeAction getTruncStoreAction(EVT ValVT, EVT MemVT) const { - assert((unsigned)ValVT.getSimpleVT().SimpleTy < MVT::LAST_VALUETYPE && - (unsigned)MemVT.getSimpleVT().SimpleTy < MVT::LAST_VALUETYPE && + assert(ValVT.getSimpleVT() < MVT::LAST_VALUETYPE && + MemVT.getSimpleVT() < MVT::LAST_VALUETYPE && "Table isn't big enough!"); return (LegalizeAction)TruncStoreActions[ValVT.getSimpleVT().SimpleTy] [MemVT.getSimpleVT().SimpleTy]; @@ -480,8 +476,8 @@ public: /// for it. LegalizeAction getIndexedLoadAction(unsigned IdxMode, EVT VT) const { - assert( IdxMode < ISD::LAST_INDEXED_MODE && - ((unsigned)VT.getSimpleVT().SimpleTy) < MVT::LAST_VALUETYPE && + assert(IdxMode < ISD::LAST_INDEXED_MODE && + VT.getSimpleVT() < MVT::LAST_VALUETYPE && "Table isn't big enough!"); unsigned Ty = (unsigned)VT.getSimpleVT().SimpleTy; return (LegalizeAction)((IndexedModeActions[Ty][IdxMode] & 0xf0) >> 4); @@ -501,8 +497,8 @@ public: /// for it. LegalizeAction getIndexedStoreAction(unsigned IdxMode, EVT VT) const { - assert( IdxMode < ISD::LAST_INDEXED_MODE && - ((unsigned)VT.getSimpleVT().SimpleTy) < MVT::LAST_VALUETYPE && + assert(IdxMode < ISD::LAST_INDEXED_MODE && + VT.getSimpleVT() < MVT::LAST_VALUETYPE && "Table isn't big enough!"); unsigned Ty = (unsigned)VT.getSimpleVT().SimpleTy; return (LegalizeAction)(IndexedModeActions[Ty][IdxMode] & 0x0f); @@ -646,21 +642,30 @@ public: /// This function returns the maximum number of store operations permitted /// to replace a call to llvm.memset. The value is set by the target at the - /// performance threshold for such a replacement. + /// performance threshold for such a replacement. If OptSize is true, + /// return the limit for functions that have OptSize attribute. /// @brief Get maximum # of store operations permitted for llvm.memset - unsigned getMaxStoresPerMemset() const { return maxStoresPerMemset; } + unsigned getMaxStoresPerMemset(bool OptSize) const { + return OptSize ? maxStoresPerMemsetOptSize : maxStoresPerMemset; + } /// This function returns the maximum number of store operations permitted /// to replace a call to llvm.memcpy. The value is set by the target at the - /// performance threshold for such a replacement. + /// performance threshold for such a replacement. If OptSize is true, + /// return the limit for functions that have OptSize attribute. /// @brief Get maximum # of store operations permitted for llvm.memcpy - unsigned getMaxStoresPerMemcpy() const { return maxStoresPerMemcpy; } + unsigned getMaxStoresPerMemcpy(bool OptSize) const { + return OptSize ? maxStoresPerMemcpyOptSize : maxStoresPerMemcpy; + } /// This function returns the maximum number of store operations permitted /// to replace a call to llvm.memmove. The value is set by the target at the - /// performance threshold for such a replacement. + /// performance threshold for such a replacement. If OptSize is true, + /// return the limit for functions that have OptSize attribute. /// @brief Get maximum # of store operations permitted for llvm.memmove - unsigned getMaxStoresPerMemmove() const { return maxStoresPerMemmove; } + unsigned getMaxStoresPerMemmove(bool OptSize) const { + return OptSize ? maxStoresPerMemmoveOptSize : maxStoresPerMemmove; + } /// This function returns true if the target allows unaligned memory accesses. /// of the specified type. This is used, for example, in situations where an @@ -958,6 +963,13 @@ public: return isTypeLegal(VT); } + /// isDesirableToPromoteOp - Return true if it is profitable for dag combiner + /// to transform a floating point op of specified opcode to a equivalent op of + /// an integer type. e.g. f32 load -> i32 load can be profitable on ARM. + virtual bool isDesirableToTransformToIntegerOp(unsigned Opc, EVT VT) const { + return false; + } + /// IsDesirableToPromoteOp - This method query the target whether it is /// beneficial for dag combiner to promote the specified node. If true, it /// should return the desired promotion type by reference. @@ -1021,7 +1033,16 @@ protected: /// SelectIsExpensive - Tells the code generator not to expand operations /// into sequences that use the select operations if possible. - void setSelectIsExpensive() { SelectIsExpensive = true; } + void setSelectIsExpensive(bool isExpensive = true) { + SelectIsExpensive = isExpensive; + } + + /// JumpIsExpensive - Tells the code generator not to expand sequence of + /// operations into a seperate sequences that increases the amount of + /// flow control. + void setJumpIsExpensive(bool isExpensive = true) { + JumpIsExpensive = isExpensive; + } /// setIntDivIsCheap - Tells the code generator that integer divide is /// expensive, and if possible, should be replaced by an alternate sequence @@ -1036,12 +1057,10 @@ protected: /// addRegisterClass - Add the specified register class as an available /// regclass for the specified value type. This indicates the selector can /// handle values of that class natively. - void addRegisterClass(EVT VT, TargetRegisterClass *RC, - bool isSynthesizable = true) { + void addRegisterClass(EVT VT, TargetRegisterClass *RC) { assert((unsigned)VT.getSimpleVT().SimpleTy < array_lengthof(RegClassForVT)); AvailableRegClasses.push_back(std::make_pair(VT, RC)); RegClassForVT[VT.getSimpleVT().SimpleTy] = RC; - Synthesizable[VT.getSimpleVT().SimpleTy] = isSynthesizable; } /// findRepresentativeClass - Return the largest legal super-reg register class @@ -1065,8 +1084,7 @@ protected: /// not work with the specified type and indicate what to do about it. void setLoadExtAction(unsigned ExtType, MVT VT, LegalizeAction Action) { - assert(ExtType < ISD::LAST_LOADEXT_TYPE && - (unsigned)VT.SimpleTy < MVT::LAST_VALUETYPE && + assert(ExtType < ISD::LAST_LOADEXT_TYPE && VT < MVT::LAST_VALUETYPE && "Table isn't big enough!"); LoadExtActions[VT.SimpleTy][ExtType] = (uint8_t)Action; } @@ -1075,8 +1093,7 @@ protected: /// not work with the specified type and indicate what to do about it. void setTruncStoreAction(MVT ValVT, MVT MemVT, LegalizeAction Action) { - assert((unsigned)ValVT.SimpleTy < MVT::LAST_VALUETYPE && - (unsigned)MemVT.SimpleTy < MVT::LAST_VALUETYPE && + assert(ValVT < MVT::LAST_VALUETYPE && MemVT < MVT::LAST_VALUETYPE && "Table isn't big enough!"); TruncStoreActions[ValVT.SimpleTy][MemVT.SimpleTy] = (uint8_t)Action; } @@ -1087,10 +1104,8 @@ protected: /// TargetLowering.cpp void setIndexedLoadAction(unsigned IdxMode, MVT VT, LegalizeAction Action) { - assert((unsigned)VT.SimpleTy < MVT::LAST_VALUETYPE && - IdxMode < ISD::LAST_INDEXED_MODE && - (unsigned)Action < 0xf && - "Table isn't big enough!"); + assert(VT < MVT::LAST_VALUETYPE && IdxMode < ISD::LAST_INDEXED_MODE && + (unsigned)Action < 0xf && "Table isn't big enough!"); // Load action are kept in the upper half. IndexedModeActions[(unsigned)VT.SimpleTy][IdxMode] &= ~0xf0; IndexedModeActions[(unsigned)VT.SimpleTy][IdxMode] |= ((uint8_t)Action) <<4; @@ -1102,10 +1117,8 @@ protected: /// TargetLowering.cpp void setIndexedStoreAction(unsigned IdxMode, MVT VT, LegalizeAction Action) { - assert((unsigned)VT.SimpleTy < MVT::LAST_VALUETYPE && - IdxMode < ISD::LAST_INDEXED_MODE && - (unsigned)Action < 0xf && - "Table isn't big enough!"); + assert(VT < MVT::LAST_VALUETYPE && IdxMode < ISD::LAST_INDEXED_MODE && + (unsigned)Action < 0xf && "Table isn't big enough!"); // Store action are kept in the lower half. IndexedModeActions[(unsigned)VT.SimpleTy][IdxMode] &= ~0x0f; IndexedModeActions[(unsigned)VT.SimpleTy][IdxMode] |= ((uint8_t)Action); @@ -1115,7 +1128,7 @@ protected: /// supported on the target and indicate what to do about it. void setCondCodeAction(ISD::CondCode CC, MVT VT, LegalizeAction Action) { - assert((unsigned)VT.SimpleTy < MVT::LAST_VALUETYPE && + assert(VT < MVT::LAST_VALUETYPE && (unsigned)CC < array_lengthof(CondCodeActions) && "Table isn't big enough!"); CondCodeActions[(unsigned)CC] &= ~(uint64_t(3UL) << VT.SimpleTy*2); @@ -1261,6 +1274,13 @@ public: return SDValue(); // this is here to silence compiler errors } + /// isUsedByReturnOnly - Return true if result of the specified node is used + /// by a return node only. This is used to determine whether it is possible + /// to codegen a libcall as tail call at legalization time. + virtual bool isUsedByReturnOnly(SDNode *N) const { + return false; + } + /// LowerOperationWrapper - This callback is invoked by the type legalizer /// to legalize nodes with an illegal operand type but legal result types. /// It replaces the LowerOperation callback in the type Legalizer. @@ -1328,6 +1348,22 @@ public: C_Unknown // Unsupported constraint. }; + enum ConstraintWeight { + // Generic weights. + CW_Invalid = -1, // No match. + CW_Okay = 0, // Acceptable. + CW_Good = 1, // Good weight. + CW_Better = 2, // Better weight. + CW_Best = 3, // Best weight. + + // Well-known weights. + CW_SpecificReg = CW_Okay, // Specific register operands. + CW_Register = CW_Good, // Register operands. + CW_Memory = CW_Better, // Memory operands. + CW_Constant = CW_Best, // Constant operand. + CW_Default = CW_Okay // Default or don't know type. + }; + /// AsmOperandInfo - This contains information for each constraint that we are /// lowering. struct AsmOperandInfo : public InlineAsm::ConstraintInfo { @@ -1356,12 +1392,41 @@ public: /// returns the output operand it matches. unsigned getMatchedOperand() const; + /// Copy constructor for copying from an AsmOperandInfo. + AsmOperandInfo(const AsmOperandInfo &info) + : InlineAsm::ConstraintInfo(info), + ConstraintCode(info.ConstraintCode), + ConstraintType(info.ConstraintType), + CallOperandVal(info.CallOperandVal), + ConstraintVT(info.ConstraintVT) { + } + + /// Copy constructor for copying from a ConstraintInfo. AsmOperandInfo(const InlineAsm::ConstraintInfo &info) : InlineAsm::ConstraintInfo(info), ConstraintType(TargetLowering::C_Unknown), CallOperandVal(0), ConstraintVT(MVT::Other) { } }; + + typedef std::vector AsmOperandInfoVector; + + /// ParseConstraints - Split up the constraint string from the inline + /// assembly value into the specific constraints and their prefixes, + /// and also tie in the associated operand values. + /// If this returns an empty vector, and if the constraint string itself + /// isn't empty, there was an error parsing. + virtual AsmOperandInfoVector ParseConstraints(ImmutableCallSite CS) const; + + /// Examine constraint type and operand type and determine a weight value. + /// The operand object must already have been set up with the operand type. + virtual ConstraintWeight getMultipleConstraintMatchWeight( + AsmOperandInfo &info, int maIndex) const; + + /// Examine constraint string and operand type and determine a weight value. + /// The operand object must already have been set up with the operand type. + virtual ConstraintWeight getSingleConstraintMatchWeight( + AsmOperandInfo &info, const char *constraint) const; /// ComputeConstraintToUse - Determines the constraint code and constraint /// type to use for the specific AsmOperandInfo, setting @@ -1568,6 +1633,11 @@ private: /// it. bool Pow2DivIsCheap; + /// JumpIsExpensive - Tells the code generator that it shouldn't generate + /// extra flow control instructions and should attempt to combine flow + /// control instructions via predication. + bool JumpIsExpensive; + /// UseUnderscoreSetJmp - This target prefers to use _setjmp to implement /// llvm.setjmp. Defaults to false. bool UseUnderscoreSetJmp; @@ -1643,11 +1713,6 @@ private: /// approximate register pressure. uint8_t RepRegClassCostForVT[MVT::LAST_VALUETYPE]; - /// Synthesizable indicates whether it is OK for the compiler to create new - /// operations using this type. All Legal types are Synthesizable except - /// MMX types on X86. Non-Legal types are not Synthesizable. - bool Synthesizable[MVT::LAST_VALUETYPE]; - /// TransformToType - For any value types we are promoting or expanding, this /// contains the value type that we are changing to. For Expanded types, this /// contains one step of the expand (e.g. i64 -> i32), even if there are @@ -1727,6 +1792,10 @@ protected: /// @brief Specify maximum number of store instructions per memset call. unsigned maxStoresPerMemset; + /// Maximum number of stores operations that may be substituted for the call + /// to memset, used for functions with OptSize attribute. + unsigned maxStoresPerMemsetOptSize; + /// When lowering \@llvm.memcpy this field specifies the maximum number of /// store operations that may be substituted for a call to memcpy. Targets /// must set this value based on the cost threshold for that target. Targets @@ -1739,6 +1808,10 @@ protected: /// @brief Specify maximum bytes of store instructions per memcpy call. unsigned maxStoresPerMemcpy; + /// Maximum number of store operations that may be substituted for a call + /// to memcpy, used for functions with OptSize attribute. + unsigned maxStoresPerMemcpyOptSize; + /// When lowering \@llvm.memmove this field specifies the maximum number of /// store instructions that may be substituted for a call to memmove. Targets /// must set this value based on the cost threshold for that target. Targets @@ -1750,6 +1823,10 @@ protected: /// @brief Specify maximum bytes of store instructions per memmove call. unsigned maxStoresPerMemmove; + /// Maximum number of store instructions that may be substituted for a call + /// to memmove, used for functions with OpSize attribute. + unsigned maxStoresPerMemmoveOptSize; + /// This field specifies whether the target can benefit from code placement /// optimization. bool benefitFromCodePlacementOpt; diff --git a/include/llvm/Target/TargetLoweringObjectFile.h b/include/llvm/Target/TargetLoweringObjectFile.h index 819709fa20c2..34bf27132de5 100644 --- a/include/llvm/Target/TargetLoweringObjectFile.h +++ b/include/llvm/Target/TargetLoweringObjectFile.h @@ -69,10 +69,6 @@ protected: /// the section the Language Specific Data Area information is emitted to. const MCSection *LSDASection; - /// EHFrameSection - If exception handling is supported by the target, this is - /// the section the EH Frame is emitted to. - const MCSection *EHFrameSection; - // Dwarf sections for debug info. If a target supports debug info, these must // be set. const MCSection *DwarfAbbrevSection; @@ -92,6 +88,11 @@ protected: // information for a TLS variable, it'll go here. const MCSection *TLSExtraDataSection; + /// CommDirectiveSupportsAlignment - True if .comm supports alignment. This + /// is a hack for as long as we support 10.4 Tiger, whose assembler doesn't + /// support alignment on comm. + bool CommDirectiveSupportsAlignment; + /// SupportsWeakEmptyEHFrame - True if target object file supports a /// weak_definition of constant 0 for an omitted EH frame. bool SupportsWeakOmittedEHFrame; @@ -128,13 +129,17 @@ public: return SupportsWeakOmittedEHFrame; } + bool getCommDirectiveSupportsAlignment() const { + return CommDirectiveSupportsAlignment; + } + const MCSection *getTextSection() const { return TextSection; } const MCSection *getDataSection() const { return DataSection; } const MCSection *getBSSSection() const { return BSSSection; } const MCSection *getStaticCtorSection() const { return StaticCtorSection; } const MCSection *getStaticDtorSection() const { return StaticDtorSection; } const MCSection *getLSDASection() const { return LSDASection; } - const MCSection *getEHFrameSection() const { return EHFrameSection; } + virtual const MCSection *getEHFrameSection() const = 0; const MCSection *getDwarfAbbrevSection() const { return DwarfAbbrevSection; } const MCSection *getDwarfInfoSection() const { return DwarfInfoSection; } const MCSection *getDwarfLineSection() const { return DwarfLineSection; } diff --git a/include/llvm/Target/TargetMachine.h b/include/llvm/Target/TargetMachine.h index 42e99e015644..030bf5b89f77 100644 --- a/include/llvm/Target/TargetMachine.h +++ b/include/llvm/Target/TargetMachine.h @@ -29,7 +29,7 @@ class TargetIntrinsicInfo; class TargetJITInfo; class TargetLowering; class TargetSelectionDAGInfo; -class TargetFrameInfo; +class TargetFrameLowering; class JITCodeEmitter; class MCContext; class TargetRegisterInfo; @@ -98,12 +98,14 @@ protected: // Can only create subclasses. /// TheTarget - The Target that this machine was created for. const Target &TheTarget; - + /// AsmInfo - Contains target specific asm information. /// const MCAsmInfo *AsmInfo; unsigned MCRelaxAll : 1; + unsigned MCNoExecStack : 1; + unsigned MCUseLoc : 1; public: virtual ~TargetMachine(); @@ -116,16 +118,16 @@ public: // -- Stack frame information // -- Selection DAG lowering information // - virtual const TargetInstrInfo *getInstrInfo() const { return 0; } - virtual const TargetFrameInfo *getFrameInfo() const { return 0; } + virtual const TargetInstrInfo *getInstrInfo() const { return 0; } + virtual const TargetFrameLowering *getFrameLowering() const { return 0; } virtual const TargetLowering *getTargetLowering() const { return 0; } virtual const TargetSelectionDAGInfo *getSelectionDAGInfo() const{ return 0; } - virtual const TargetData *getTargetData() const { return 0; } - + virtual const TargetData *getTargetData() const { return 0; } + /// getMCAsmInfo - Return target specific asm information. /// const MCAsmInfo *getMCAsmInfo() const { return AsmInfo; } - + /// getSubtarget - This method returns a pointer to the specified type of /// TargetSubtarget. In debug builds, it verifies that the object being /// returned is of the correct type. @@ -138,7 +140,7 @@ public: /// details of graph coloring register allocation removed from it. /// virtual const TargetRegisterInfo *getRegisterInfo() const { return 0; } - + /// getIntrinsicInfo - If intrinsic information is available, return it. If /// not, return null. /// @@ -148,17 +150,17 @@ public: /// otherwise return null. /// virtual TargetJITInfo *getJITInfo() { return 0; } - + /// getInstrItineraryData - Returns instruction itinerary data for the target /// or specific subtarget. /// - virtual const InstrItineraryData getInstrItineraryData() const { - return InstrItineraryData(); + virtual const InstrItineraryData *getInstrItineraryData() const { + return 0; } /// getELFWriterInfo - If this target supports an ELF writer, return /// information for it, otherwise return null. - /// + /// virtual const TargetELFWriterInfo *getELFWriterInfo() const { return 0; } /// hasMCRelaxAll - Check whether all machine code instructions should be @@ -169,6 +171,18 @@ public: /// relaxed. void setMCRelaxAll(bool Value) { MCRelaxAll = Value; } + /// hasMCNoExecStack - Check whether an executable stack is not needed. + bool hasMCNoExecStack() const { return MCNoExecStack; } + + /// setMCNoExecStack - Set whether an executabel stack is not needed. + void setMCNoExecStack(bool Value) { MCNoExecStack = Value; } + + /// hasMCUseLoc - Check whether we should use dwarf's .loc directive. + bool hasMCUseLoc() const { return MCUseLoc; } + + /// setMCUseLoc - Set whether all we should use dwarf's .loc directive. + void setMCUseLoc(bool Value) { MCUseLoc = Value; } + /// getRelocationModel - Returns the code generation relocation model. The /// choices are static, PIC, and dynamic-no-pic, and target default. static Reloc::Model getRelocationModel(); @@ -267,7 +281,7 @@ class LLVMTargetMachine : public TargetMachine { protected: // Can only create subclasses. LLVMTargetMachine(const Target &T, const std::string &TargetTriple); - + private: /// addCommonCodeGenPasses - Add standard LLVM codegen passes used for /// both emitting to assembly files or machine code output. @@ -277,9 +291,11 @@ private: virtual void setCodeModelForJIT(); virtual void setCodeModelForStatic(); - + public: - + + const std::string &getTargetTriple() const { return TargetTriple; } + /// addPassesToEmitFile - Add passes to the specified pass manager to get the /// specified file emitted. Typically this will involve several steps of code /// generation. If OptLevel is None, the code generator should emit code as @@ -289,7 +305,7 @@ public: CodeGenFileType FileType, CodeGenOpt::Level, bool DisableVerify = true); - + /// addPassesToEmitMachineCode - Add passes to the specified pass manager to /// get machine code emitted. This uses a JITCodeEmitter object to handle /// actually outputting the machine code and resolving things like the address @@ -310,7 +326,7 @@ public: MCContext *&Ctx, CodeGenOpt::Level OptLevel, bool DisableVerify = true); - + /// Target-Independent Code Generator Pass Configuration Options. /// addPreISelPasses - This method should add any "last minute" LLVM->LLVM @@ -347,15 +363,15 @@ public: virtual bool addPreSched2(PassManagerBase &, CodeGenOpt::Level) { return false; } - + /// addPreEmitPass - This pass may be implemented by targets that want to run /// passes immediately before machine code is emitted. This should return /// true if -print-machineinstrs should print out the code after the passes. virtual bool addPreEmitPass(PassManagerBase &, CodeGenOpt::Level) { return false; } - - + + /// addCodeEmitter - This pass should be overridden by the target to add a /// code emitter, if supported. If this is not supported, 'true' should be /// returned. diff --git a/include/llvm/Target/TargetRegisterInfo.h b/include/llvm/Target/TargetRegisterInfo.h index 81dec3e5b78d..121091c9b49b 100644 --- a/include/llvm/Target/TargetRegisterInfo.h +++ b/include/llvm/Target/TargetRegisterInfo.h @@ -29,21 +29,21 @@ class MachineFunction; class MachineMove; class RegScavenger; template class SmallVectorImpl; +class raw_ostream; /// TargetRegisterDesc - This record contains all of the information known about -/// a particular register. The AliasSet field (if not null) contains a pointer -/// to a Zero terminated array of registers that this register aliases. This is -/// needed for architectures like X86 which have AL alias AX alias EAX. -/// Registers that this does not apply to simply should set this to null. -/// The SubRegs field is a zero terminated array of registers that are -/// sub-registers of the specific register, e.g. AL, AH are sub-registers of AX. -/// The SuperRegs field is a zero terminated array of registers that are +/// a particular register. The Overlaps field contains a pointer to a zero +/// terminated array of registers that this register aliases, starting with +/// itself. This is needed for architectures like X86 which have AL alias AX +/// alias EAX. The SubRegs field is a zero terminated array of registers that +/// are sub-registers of the specific register, e.g. AL, AH are sub-registers of +/// AX. The SuperRegs field is a zero terminated array of registers that are /// super-registers of the specific register, e.g. RAX, EAX, are super-registers /// of AX. /// struct TargetRegisterDesc { const char *Name; // Printable name for the reg (for debugging) - const unsigned *AliasSet; // Register Alias Set, described above + const unsigned *Overlaps; // Overlapping registers, described above const unsigned *SubRegs; // Sub-register set, described above const unsigned *SuperRegs; // Super-register set, described above }; @@ -123,7 +123,7 @@ public: /// hasType - return true if this TargetRegisterClass has the ValueType vt. /// bool hasType(EVT vt) const { - for(int i = 0; VTs[i].getSimpleVT().SimpleTy != MVT::Other; ++i) + for(int i = 0; VTs[i] != MVT::Other; ++i) if (VTs[i] == vt) return true; return false; @@ -137,7 +137,7 @@ public: vt_iterator vt_end() const { vt_iterator I = VTs; - while (I->getSimpleVT().SimpleTy != MVT::Other) ++I; + while (*I != MVT::Other) ++I; return I; } @@ -227,9 +227,12 @@ public: /// cheaper to allocate caller saved registers. /// /// These methods take a MachineFunction argument, which can be used to tune - /// the allocatable registers based on the characteristics of the function. - /// One simple example is that the frame pointer register can be used if - /// frame-pointer-elimination is performed. + /// the allocatable registers based on the characteristics of the function, + /// subtarget, or other criteria. + /// + /// Register allocators should account for the fact that an allocation + /// order iterator may return a reserved register and always check + /// if the register is allocatable (getAllocatableSet()) before using it. /// /// By default, these methods return all registers in the class. /// @@ -292,30 +295,68 @@ protected: virtual ~TargetRegisterInfo(); public: - enum { // Define some target independent constants - /// NoRegister - This physical register is not a real target register. It - /// is useful as a sentinal. - NoRegister = 0, + // Register numbers can represent physical registers, virtual registers, and + // sometimes stack slots. The unsigned values are divided into these ranges: + // + // 0 Not a register, can be used as a sentinel. + // [1;2^30) Physical registers assigned by TableGen. + // [2^30;2^31) Stack slots. (Rarely used.) + // [2^31;2^32) Virtual registers assigned by MachineRegisterInfo. + // + // Further sentinels can be allocated from the small negative integers. + // DenseMapInfo uses -1u and -2u. - /// FirstVirtualRegister - This is the first register number that is - /// considered to be a 'virtual' register, which is part of the SSA - /// namespace. This must be the same for all targets, which means that each - /// target is limited to this fixed number of registers. - FirstVirtualRegister = 16384 - }; + /// isStackSlot - Sometimes it is useful the be able to store a non-negative + /// frame index in a variable that normally holds a register. isStackSlot() + /// returns true if Reg is in the range used for stack slots. + /// + /// Note that isVirtualRegister() and isPhysicalRegister() cannot handle stack + /// slots, so if a variable may contains a stack slot, always check + /// isStackSlot() first. + /// + static bool isStackSlot(unsigned Reg) { + return int(Reg) >= (1 << 30); + } + + /// stackSlot2Index - Compute the frame index from a register value + /// representing a stack slot. + static int stackSlot2Index(unsigned Reg) { + assert(isStackSlot(Reg) && "Not a stack slot"); + return int(Reg - (1u << 30)); + } + + /// index2StackSlot - Convert a non-negative frame index to a stack slot + /// register value. + static unsigned index2StackSlot(int FI) { + assert(FI >= 0 && "Cannot hold a negative frame index."); + return FI + (1u << 30); + } /// isPhysicalRegister - Return true if the specified register number is in /// the physical register namespace. static bool isPhysicalRegister(unsigned Reg) { - assert(Reg && "this is not a register!"); - return Reg < FirstVirtualRegister; + assert(!isStackSlot(Reg) && "Not a register! Check isStackSlot() first."); + return int(Reg) > 0; } /// isVirtualRegister - Return true if the specified register number is in /// the virtual register namespace. static bool isVirtualRegister(unsigned Reg) { - assert(Reg && "this is not a register!"); - return Reg >= FirstVirtualRegister; + assert(!isStackSlot(Reg) && "Not a register! Check isStackSlot() first."); + return int(Reg) < 0; + } + + /// virtReg2Index - Convert a virtual register number to a 0-based index. + /// The first virtual register in a function will get the index 0. + static unsigned virtReg2Index(unsigned Reg) { + assert(isVirtualRegister(Reg) && "Not a virtual register"); + return Reg - (1u << 31); + } + + /// index2VirtReg - Convert a 0-based index to a virtual register number. + /// This is the inverse operation of VirtReg2IndexFunctor below. + static unsigned index2VirtReg(unsigned Index) { + return Index + (1u << 31); } /// getMinimalPhysRegClass - Returns the Register Class of a physical @@ -348,7 +389,17 @@ public: /// terminated. /// const unsigned *getAliasSet(unsigned RegNo) const { - return get(RegNo).AliasSet; + // The Overlaps set always begins with Reg itself. + return get(RegNo).Overlaps + 1; + } + + /// getOverlaps - Return a list of registers that overlap Reg, including + /// itself. This is the same as the alias set except Reg is included in the + /// list. + /// These are exactly the registers in { x | regsOverlap(x, Reg) }. + /// + const unsigned *getOverlaps(unsigned RegNo) const { + return get(RegNo).Overlaps; } /// getSubRegisters - Return the list of registers that are sub-registers of @@ -574,13 +625,6 @@ public: // Do nothing. } - /// targetHandlesStackFrameRounding - Returns true if the target is - /// responsible for rounding up the stack frame (probably at emitPrologue - /// time). - virtual bool targetHandlesStackFrameRounding() const { - return false; - } - /// requiresRegisterScavenging - returns true if the target requires (and can /// make use of) the register scavenger. virtual bool requiresRegisterScavenging(const MachineFunction &MF) const { @@ -600,31 +644,6 @@ public: return false; } - /// hasFP - Return true if the specified function should have a dedicated - /// frame pointer register. For most targets this is true only if the function - /// has variable sized allocas or if frame pointer elimination is disabled. - virtual bool hasFP(const MachineFunction &MF) const = 0; - - /// hasReservedCallFrame - Under normal circumstances, when a frame pointer is - /// not required, we reserve argument space for call sites in the function - /// immediately on entry to the current function. This eliminates the need for - /// add/sub sp brackets around call sites. Returns true if the call frame is - /// included as part of the stack frame. - virtual bool hasReservedCallFrame(const MachineFunction &MF) const { - return !hasFP(MF); - } - - /// canSimplifyCallFramePseudos - When possible, it's best to simplify the - /// call frame pseudo ops before doing frame index elimination. This is - /// possible only when frame index references between the pseudos won't - /// need adjusting for the call frame adjustments. Normally, that's true - /// if the function has a reserved call frame or a frame pointer. Some - /// targets (Thumb2, for example) may have more complicated criteria, - /// however, and can override this behavior. - virtual bool canSimplifyCallFramePseudos(const MachineFunction &MF) const { - return hasReservedCallFrame(MF) || hasFP(MF); - } - /// hasReservedSpillSlot - Return true if target has reserved a spill slot in /// the stack frame of the given function for the specified register. e.g. On /// x86, if the frame register is required, the first fixed stack object is @@ -644,7 +663,7 @@ public: } /// getFrameIndexInstrOffset - Get the offset from the referenced frame - /// index in the instruction, if the is one. + /// index in the instruction, if there is one. virtual int64_t getFrameIndexInstrOffset(const MachineInstr *MI, int Idx) const { return 0; @@ -660,7 +679,7 @@ public: /// materializeFrameBaseRegister - Insert defining instruction(s) for /// BaseReg to be a pointer to FrameIdx before insertion point I. - virtual void materializeFrameBaseRegister(MachineBasicBlock::iterator I, + virtual void materializeFrameBaseRegister(MachineBasicBlock *MBB, unsigned BaseReg, int FrameIdx, int64_t Offset) const { assert(0 && "materializeFrameBaseRegister does not exist on this target"); @@ -707,21 +726,6 @@ public: assert(0 && "Call Frame Pseudo Instructions do not exist on this target!"); } - /// processFunctionBeforeCalleeSavedScan - This method is called immediately - /// before PrologEpilogInserter scans the physical registers used to determine - /// what callee saved registers should be spilled. This method is optional. - virtual void processFunctionBeforeCalleeSavedScan(MachineFunction &MF, - RegScavenger *RS = NULL) const { - - } - - /// processFunctionBeforeFrameFinalized - This method is called immediately - /// before the specified function's frame layout (MF.getFrameInfo()) is - /// finalized. Once the frame is finalized, MO_FrameIndex operands are - /// replaced with direct constants. This method is optional. - /// - virtual void processFunctionBeforeFrameFinalized(MachineFunction &MF) const { - } /// saveScavengerRegister - Spill the register so it can be used by the /// register scavenger. Return true if the register was spilled, false @@ -746,12 +750,6 @@ public: virtual void eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj, RegScavenger *RS=NULL) const = 0; - /// emitProlog/emitEpilog - These methods insert prolog and epilog code into - /// the function. - virtual void emitPrologue(MachineFunction &MF) const = 0; - virtual void emitEpilogue(MachineFunction &MF, - MachineBasicBlock &MBB) const = 0; - //===--------------------------------------------------------------------===// /// Debug information queries. @@ -765,37 +763,16 @@ public: /// for values allocated in the current stack frame. virtual unsigned getFrameRegister(const MachineFunction &MF) const = 0; - /// getFrameIndexOffset - Returns the displacement from the frame register to - /// the stack frame of the specified index. - virtual int getFrameIndexOffset(const MachineFunction &MF, int FI) const; - - /// getFrameIndexReference - This method should return the base register - /// and offset used to reference a frame index location. The offset is - /// returned directly, and the base register is returned via FrameReg. - virtual int getFrameIndexReference(const MachineFunction &MF, int FI, - unsigned &FrameReg) const { - // By default, assume all frame indices are referenced via whatever - // getFrameRegister() says. The target can override this if it's doing - // something different. - FrameReg = getFrameRegister(MF); - return getFrameIndexOffset(MF, FI); - } - /// getRARegister - This method should return the register where the return /// address can be found. virtual unsigned getRARegister() const = 0; - - /// getInitialFrameState - Returns a list of machine moves that are assumed - /// on entry to all functions. Note that LabelID is ignored (assumed to be - /// the beginning of the function.) - virtual void getInitialFrameState(std::vector &Moves) const; }; // This is useful when building IndexedMaps keyed on virtual registers struct VirtReg2IndexFunctor : public std::unary_function { unsigned operator()(unsigned Reg) const { - return Reg - TargetRegisterInfo::FirstVirtualRegister; + return TargetRegisterInfo::virtReg2Index(Reg); } }; @@ -804,6 +781,33 @@ struct VirtReg2IndexFunctor : public std::unary_function { const TargetRegisterClass *getCommonSubClass(const TargetRegisterClass *A, const TargetRegisterClass *B); +/// PrintReg - Helper class for printing registers on a raw_ostream. +/// Prints virtual and physical registers with or without a TRI instance. +/// +/// The format is: +/// %noreg - NoRegister +/// %vreg5 - a virtual register. +/// %vreg5:sub_8bit - a virtual register with sub-register index (with TRI). +/// %EAX - a physical register +/// %physreg17 - a physical register when no TRI instance given. +/// +/// Usage: OS << PrintReg(Reg, TRI) << '\n'; +/// +class PrintReg { + const TargetRegisterInfo *TRI; + unsigned Reg; + unsigned SubIdx; +public: + PrintReg(unsigned reg, const TargetRegisterInfo *tri = 0, unsigned subidx = 0) + : TRI(tri), Reg(reg), SubIdx(subidx) {} + void print(raw_ostream&) const; +}; + +static inline raw_ostream &operator<<(raw_ostream &OS, const PrintReg &PR) { + PR.print(OS); + return OS; +} + } // End llvm namespace #endif diff --git a/include/llvm/Target/TargetRegistry.h b/include/llvm/Target/TargetRegistry.h index 2817b0c421ed..f851ad0a9bfb 100644 --- a/include/llvm/Target/TargetRegistry.h +++ b/include/llvm/Target/TargetRegistry.h @@ -39,6 +39,15 @@ namespace llvm { class TargetAsmParser; class TargetMachine; class raw_ostream; + class formatted_raw_ostream; + + MCStreamer *createAsmStreamer(MCContext &Ctx, formatted_raw_ostream &OS, + bool isVerboseAsm, + bool useLoc, + MCInstPrinter *InstPrint, + MCCodeEmitter *CE, + TargetAsmBackend *TAB, + bool ShowInst); /// Target - Wrapper for Target specific information. /// @@ -80,7 +89,16 @@ namespace llvm { TargetAsmBackend &TAB, raw_ostream &_OS, MCCodeEmitter *_Emitter, - bool RelaxAll); + bool RelaxAll, + bool NoExecStack); + typedef MCStreamer *(*AsmStreamerCtorTy)(MCContext &Ctx, + formatted_raw_ostream &OS, + bool isVerboseAsm, + bool useLoc, + MCInstPrinter *InstPrint, + MCCodeEmitter *CE, + TargetAsmBackend *TAB, + bool ShowInst); private: /// Next - The next registered target in the linked list, maintained by the @@ -138,7 +156,13 @@ namespace llvm { /// ObjectStreamer, if registered. ObjectStreamerCtorTy ObjectStreamerCtorFn; + /// AsmStreamerCtorFn - Construction function for this target's + /// AsmStreamer, if registered (default = llvm::createAsmStreamer). + AsmStreamerCtorTy AsmStreamerCtorFn; + public: + Target() : AsmStreamerCtorFn(llvm::createAsmStreamer) {} + /// @name Target Information /// @{ @@ -185,6 +209,9 @@ namespace llvm { /// hasObjectStreamer - Check if this target supports streaming to files. bool hasObjectStreamer() const { return ObjectStreamerCtorFn != 0; } + /// hasAsmStreamer - Check if this target supports streaming to files. + bool hasAsmStreamer() const { return AsmStreamerCtorFn != 0; } + /// @} /// @name Feature Constructors /// @{ @@ -282,14 +309,31 @@ namespace llvm { /// \arg _OS - The stream object. /// \arg _Emitter - The target independent assembler object.Takes ownership. /// \arg RelaxAll - Relax all fixups? + /// \arg NoExecStack - Mark file as not needing a executable stack. MCStreamer *createObjectStreamer(const std::string &TT, MCContext &Ctx, TargetAsmBackend &TAB, raw_ostream &_OS, MCCodeEmitter *_Emitter, - bool RelaxAll) const { + bool RelaxAll, + bool NoExecStack) const { if (!ObjectStreamerCtorFn) return 0; - return ObjectStreamerCtorFn(*this, TT, Ctx, TAB, _OS, _Emitter, RelaxAll); + return ObjectStreamerCtorFn(*this, TT, Ctx, TAB, _OS, _Emitter, RelaxAll, + NoExecStack); + } + + /// createAsmStreamer - Create a target specific MCStreamer. + MCStreamer *createAsmStreamer(MCContext &Ctx, + formatted_raw_ostream &OS, + bool isVerboseAsm, + bool useLoc, + MCInstPrinter *InstPrint, + MCCodeEmitter *CE, + TargetAsmBackend *TAB, + bool ShowInst) const { + // AsmStreamerCtorFn is default to llvm::createAsmStreamer + return AsmStreamerCtorFn(Ctx, OS, isVerboseAsm, useLoc, + InstPrint, CE, TAB, ShowInst); } /// @} @@ -513,7 +557,7 @@ namespace llvm { T.CodeEmitterCtorFn = Fn; } - /// RegisterObjectStreamer - Register an MCStreamer implementation + /// RegisterObjectStreamer - Register a object code MCStreamer implementation /// for the given target. /// /// Clients are responsible for ensuring that registration doesn't occur @@ -527,6 +571,20 @@ namespace llvm { T.ObjectStreamerCtorFn = Fn; } + /// RegisterAsmStreamer - Register an assembly MCStreamer implementation + /// for the given target. + /// + /// Clients are responsible for ensuring that registration doesn't occur + /// while another thread is attempting to access the registry. Typically + /// this is done by initializing all targets at program startup. + /// + /// @param T - The target being registered. + /// @param Fn - A function to construct an MCStreamer for the target. + static void RegisterAsmStreamer(Target &T, Target::AsmStreamerCtorTy Fn) { + if (T.AsmStreamerCtorFn == createAsmStreamer) + T.AsmStreamerCtorFn = Fn; + } + /// @} }; diff --git a/include/llvm/Target/TargetSchedule.td b/include/llvm/Target/TargetSchedule.td index 96c83674cb03..97ea82ab9e3d 100644 --- a/include/llvm/Target/TargetSchedule.td +++ b/include/llvm/Target/TargetSchedule.td @@ -22,6 +22,13 @@ // class FuncUnit; +//===----------------------------------------------------------------------===// +// Pipeline bypass / forwarding - These values specifies the symbolic names of +// pipeline bypasses which can be used to forward results of instructions +// that are forwarded to uses. +class Bypass; +def NoBypass : Bypass; + class ReservationKind val> { int Value = val; } @@ -66,30 +73,58 @@ class InstrStage units, // across all chip sets. Thus a new chip set can be added without modifying // instruction information. // -class InstrItinClass; +// NumMicroOps represents the number of micro-operations that each instruction +// in the class are decoded to. If the number is zero, then it means the +// instruction can decode into variable number of micro-ops and it must be +// determined dynamically. +// +class InstrItinClass { + int NumMicroOps = ops; +} def NoItinerary : InstrItinClass; //===----------------------------------------------------------------------===// // Instruction itinerary data - These values provide a runtime map of an // instruction itinerary class (name) to its itinerary data. // +// OperandCycles are optional "cycle counts". They specify the cycle after +// instruction issue the values which correspond to specific operand indices +// are defined or read. Bypasses are optional "pipeline forwarding pathes", if +// a def by an instruction is available on a specific bypass and the use can +// read from the same bypass, then the operand use latency is reduced by one. +// +// InstrItinData, +// InstrStage<1, [A9_AGU]>], +// [3, 1], [A9_LdBypass]>, +// InstrItinData], +// [1, 1], [NoBypass, A9_LdBypass]>, +// +// In this example, the instruction of IIC_iLoadi reads its input on cycle 1 +// (after issue) and the result of the load is available on cycle 3. The result +// is available via forwarding path A9_LdBypass. If it's used by the first +// source operand of instructions of IIC_iMVNr class, then the operand latency +// is reduced by 1. class InstrItinData stages, - list operandcycles = []> { + list operandcycles = [], + list bypasses = []> { InstrItinClass TheClass = Class; list Stages = stages; list OperandCycles = operandcycles; + list Bypasses = bypasses; } //===----------------------------------------------------------------------===// // Processor itineraries - These values represent the set of all itinerary // classes for a given chip set. // -class ProcessorItineraries fu, list iid> { +class ProcessorItineraries fu, list bp, + list iid> { list FU = fu; + list BP = bp; list IID = iid; } // NoItineraries - A marker that can be used by processors without schedule // info. -def NoItineraries : ProcessorItineraries<[], []>; +def NoItineraries : ProcessorItineraries<[], [], []>; diff --git a/include/llvm/Target/TargetSelectionDAG.td b/include/llvm/Target/TargetSelectionDAG.td index 58ccfbacc6f7..c9be40d23f00 100644 --- a/include/llvm/Target/TargetSelectionDAG.td +++ b/include/llvm/Target/TargetSelectionDAG.td @@ -1,10 +1,10 @@ //===- TargetSelectionDAG.td - Common code for DAG isels ---*- tablegen -*-===// -// +// // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. -// +// //===----------------------------------------------------------------------===// // // This file defines the target-independent interfaces used by SelectionDAG @@ -61,6 +61,13 @@ class SDTCisEltOfVec int OtherOpNum = OtherOp; } +/// SDTCisSubVecOfVec - This indicates that ThisOp is a vector type +/// with length less that of OtherOp, which is a vector type. +class SDTCisSubVecOfVec + : SDTypeConstraint { + int OtherOpNum = OtherOp; +} + //===----------------------------------------------------------------------===// // Selection DAG Type Profile definitions. // @@ -123,10 +130,10 @@ def SDTFPRoundOp : SDTypeProfile<1, 1, [ // fround def SDTFPExtendOp : SDTypeProfile<1, 1, [ // fextend SDTCisFP<0>, SDTCisFP<1>, SDTCisOpSmallerThanOp<1, 0> ]>; -def SDTIntToFPOp : SDTypeProfile<1, 1, [ // [su]int_to_fp +def SDTIntToFPOp : SDTypeProfile<1, 1, [ // [su]int_to_fp SDTCisFP<0>, SDTCisInt<1> ]>; -def SDTFPToIntOp : SDTypeProfile<1, 1, [ // fp_to_[su]int +def SDTFPToIntOp : SDTypeProfile<1, 1, [ // fp_to_[su]int SDTCisInt<0>, SDTCisFP<1> ]>; def SDTExtInreg : SDTypeProfile<1, 2, [ // sext_inreg @@ -138,7 +145,7 @@ def SDTSetCC : SDTypeProfile<1, 3, [ // setcc SDTCisInt<0>, SDTCisSameAs<1, 2>, SDTCisVT<3, OtherVT> ]>; -def SDTSelect : SDTypeProfile<1, 3, [ // select +def SDTSelect : SDTypeProfile<1, 3, [ // select SDTCisInt<1>, SDTCisSameAs<0, 2>, SDTCisSameAs<2, 3> ]>; @@ -162,11 +169,11 @@ def SDTBrind : SDTypeProfile<0, 1, [ // brind def SDTNone : SDTypeProfile<0, 0, []>; // ret, trap def SDTLoad : SDTypeProfile<1, 1, [ // load - SDTCisPtrTy<1> + SDTCisPtrTy<1> ]>; def SDTStore : SDTypeProfile<0, 2, [ // store - SDTCisPtrTy<1> + SDTCisPtrTy<1> ]>; def SDTIStore : SDTypeProfile<1, 3, [ // indexed store @@ -183,18 +190,25 @@ def SDTVecInsert : SDTypeProfile<1, 3, [ // vector insert SDTCisEltOfVec<2, 1>, SDTCisSameAs<0, 1>, SDTCisPtrTy<3> ]>; -def STDPrefetch : SDTypeProfile<0, 3, [ // prefetch +def SDTSubVecExtract : SDTypeProfile<1, 2, [// subvector extract + SDTCisSubVecOfVec<0,1>, SDTCisInt<2> +]>; +def SDTSubVecInsert : SDTypeProfile<1, 3, [ // subvector insert + SDTCisSubVecOfVec<2, 1>, SDTCisSameAs<0,1>, SDTCisInt<3> +]>; + +def SDTPrefetch : SDTypeProfile<0, 3, [ // prefetch SDTCisPtrTy<0>, SDTCisSameAs<1, 2>, SDTCisInt<1> ]>; -def STDMemBarrier : SDTypeProfile<0, 5, [ // memory barier +def SDTMemBarrier : SDTypeProfile<0, 5, [ // memory barier SDTCisSameAs<0,1>, SDTCisSameAs<0,2>, SDTCisSameAs<0,3>, SDTCisSameAs<0,4>, SDTCisInt<0> ]>; -def STDAtomic3 : SDTypeProfile<1, 3, [ +def SDTAtomic3 : SDTypeProfile<1, 3, [ SDTCisSameAs<0,2>, SDTCisSameAs<0,3>, SDTCisInt<0>, SDTCisPtrTy<1> ]>; -def STDAtomic2 : SDTypeProfile<1, 2, [ +def SDTAtomic2 : SDTypeProfile<1, 2, [ SDTCisSameAs<0,2>, SDTCisInt<0>, SDTCisPtrTy<1> ]>; @@ -216,20 +230,27 @@ class SDNodeProperty; def SDNPCommutative : SDNodeProperty; // X op Y == Y op X def SDNPAssociative : SDNodeProperty; // (X op Y) op Z == X op (Y op Z) def SDNPHasChain : SDNodeProperty; // R/W chain operand and result -def SDNPOutFlag : SDNodeProperty; // Write a flag result -def SDNPInFlag : SDNodeProperty; // Read a flag operand -def SDNPOptInFlag : SDNodeProperty; // Optionally read a flag operand +def SDNPOutGlue : SDNodeProperty; // Write a flag result +def SDNPInGlue : SDNodeProperty; // Read a flag operand +def SDNPOptInGlue : SDNodeProperty; // Optionally read a flag operand def SDNPMayStore : SDNodeProperty; // May write to memory, sets 'mayStore'. def SDNPMayLoad : SDNodeProperty; // May read memory, sets 'mayLoad'. def SDNPSideEffect : SDNodeProperty; // Sets 'HasUnmodelledSideEffects'. def SDNPMemOperand : SDNodeProperty; // Touches memory, has assoc MemOperand def SDNPVariadic : SDNodeProperty; // Node has variable arguments. +def SDNPWantRoot : SDNodeProperty; // ComplexPattern gets the root of match +def SDNPWantParent : SDNodeProperty; // ComplexPattern gets the parent + +//===----------------------------------------------------------------------===// +// Selection DAG Pattern Operations +class SDPatternOperator; //===----------------------------------------------------------------------===// // Selection DAG Node definitions. // class SDNode props = [], string sdclass = "SDNode"> { + list props = [], string sdclass = "SDNode"> + : SDPatternOperator { string Opcode = opcode; string SDClass = sdclass; list Properties = props; @@ -305,14 +326,14 @@ def or : SDNode<"ISD::OR" , SDTIntBinOp, def xor : SDNode<"ISD::XOR" , SDTIntBinOp, [SDNPCommutative, SDNPAssociative]>; def addc : SDNode<"ISD::ADDC" , SDTIntBinOp, - [SDNPCommutative, SDNPOutFlag]>; + [SDNPCommutative, SDNPOutGlue]>; def adde : SDNode<"ISD::ADDE" , SDTIntBinOp, - [SDNPCommutative, SDNPOutFlag, SDNPInFlag]>; + [SDNPCommutative, SDNPOutGlue, SDNPInGlue]>; def subc : SDNode<"ISD::SUBC" , SDTIntBinOp, - [SDNPOutFlag]>; + [SDNPOutGlue]>; def sube : SDNode<"ISD::SUBE" , SDTIntBinOp, - [SDNPOutFlag, SDNPInFlag]>; - + [SDNPOutGlue, SDNPInGlue]>; + def sext_inreg : SDNode<"ISD::SIGN_EXTEND_INREG", SDTExtInreg>; def bswap : SDNode<"ISD::BSWAP" , SDTIntUnaryOp>; def ctlz : SDNode<"ISD::CTLZ" , SDTIntUnaryOp>; @@ -322,11 +343,11 @@ def sext : SDNode<"ISD::SIGN_EXTEND", SDTIntExtendOp>; def zext : SDNode<"ISD::ZERO_EXTEND", SDTIntExtendOp>; def anyext : SDNode<"ISD::ANY_EXTEND" , SDTIntExtendOp>; def trunc : SDNode<"ISD::TRUNCATE" , SDTIntTruncOp>; -def bitconvert : SDNode<"ISD::BIT_CONVERT", SDTUnaryOp>; +def bitconvert : SDNode<"ISD::BITCAST" , SDTUnaryOp>; def extractelt : SDNode<"ISD::EXTRACT_VECTOR_ELT", SDTVecExtract>; def insertelt : SDNode<"ISD::INSERT_VECTOR_ELT", SDTVecInsert>; - + def fadd : SDNode<"ISD::FADD" , SDTFPBinOp, [SDNPCommutative]>; def fsub : SDNode<"ISD::FSUB" , SDTFPBinOp>; def fmul : SDNode<"ISD::FMUL" , SDTFPBinOp, [SDNPCommutative]>; @@ -367,35 +388,36 @@ def br : SDNode<"ISD::BR" , SDTBr, [SDNPHasChain]>; def trap : SDNode<"ISD::TRAP" , SDTNone, [SDNPHasChain, SDNPSideEffect]>; -def prefetch : SDNode<"ISD::PREFETCH" , STDPrefetch, - [SDNPHasChain, SDNPMayLoad, SDNPMayStore]>; +def prefetch : SDNode<"ISD::PREFETCH" , SDTPrefetch, + [SDNPHasChain, SDNPMayLoad, SDNPMayStore, + SDNPMemOperand]>; -def membarrier : SDNode<"ISD::MEMBARRIER" , STDMemBarrier, +def membarrier : SDNode<"ISD::MEMBARRIER" , SDTMemBarrier, [SDNPHasChain, SDNPSideEffect]>; -def atomic_cmp_swap : SDNode<"ISD::ATOMIC_CMP_SWAP" , STDAtomic3, +def atomic_cmp_swap : SDNode<"ISD::ATOMIC_CMP_SWAP" , SDTAtomic3, [SDNPHasChain, SDNPMayStore, SDNPMayLoad, SDNPMemOperand]>; -def atomic_load_add : SDNode<"ISD::ATOMIC_LOAD_ADD" , STDAtomic2, +def atomic_load_add : SDNode<"ISD::ATOMIC_LOAD_ADD" , SDTAtomic2, [SDNPHasChain, SDNPMayStore, SDNPMayLoad, SDNPMemOperand]>; -def atomic_swap : SDNode<"ISD::ATOMIC_SWAP", STDAtomic2, +def atomic_swap : SDNode<"ISD::ATOMIC_SWAP", SDTAtomic2, [SDNPHasChain, SDNPMayStore, SDNPMayLoad, SDNPMemOperand]>; -def atomic_load_sub : SDNode<"ISD::ATOMIC_LOAD_SUB" , STDAtomic2, +def atomic_load_sub : SDNode<"ISD::ATOMIC_LOAD_SUB" , SDTAtomic2, [SDNPHasChain, SDNPMayStore, SDNPMayLoad, SDNPMemOperand]>; -def atomic_load_and : SDNode<"ISD::ATOMIC_LOAD_AND" , STDAtomic2, +def atomic_load_and : SDNode<"ISD::ATOMIC_LOAD_AND" , SDTAtomic2, [SDNPHasChain, SDNPMayStore, SDNPMayLoad, SDNPMemOperand]>; -def atomic_load_or : SDNode<"ISD::ATOMIC_LOAD_OR" , STDAtomic2, +def atomic_load_or : SDNode<"ISD::ATOMIC_LOAD_OR" , SDTAtomic2, [SDNPHasChain, SDNPMayStore, SDNPMayLoad, SDNPMemOperand]>; -def atomic_load_xor : SDNode<"ISD::ATOMIC_LOAD_XOR" , STDAtomic2, +def atomic_load_xor : SDNode<"ISD::ATOMIC_LOAD_XOR" , SDTAtomic2, [SDNPHasChain, SDNPMayStore, SDNPMayLoad, SDNPMemOperand]>; -def atomic_load_nand: SDNode<"ISD::ATOMIC_LOAD_NAND", STDAtomic2, +def atomic_load_nand: SDNode<"ISD::ATOMIC_LOAD_NAND", SDTAtomic2, [SDNPHasChain, SDNPMayStore, SDNPMayLoad, SDNPMemOperand]>; -def atomic_load_min : SDNode<"ISD::ATOMIC_LOAD_MIN", STDAtomic2, +def atomic_load_min : SDNode<"ISD::ATOMIC_LOAD_MIN", SDTAtomic2, [SDNPHasChain, SDNPMayStore, SDNPMayLoad, SDNPMemOperand]>; -def atomic_load_max : SDNode<"ISD::ATOMIC_LOAD_MAX", STDAtomic2, +def atomic_load_max : SDNode<"ISD::ATOMIC_LOAD_MAX", SDTAtomic2, [SDNPHasChain, SDNPMayStore, SDNPMayLoad, SDNPMemOperand]>; -def atomic_load_umin : SDNode<"ISD::ATOMIC_LOAD_UMIN", STDAtomic2, +def atomic_load_umin : SDNode<"ISD::ATOMIC_LOAD_UMIN", SDTAtomic2, [SDNPHasChain, SDNPMayStore, SDNPMayLoad, SDNPMemOperand]>; -def atomic_load_umax : SDNode<"ISD::ATOMIC_LOAD_UMAX", STDAtomic2, +def atomic_load_umax : SDNode<"ISD::ATOMIC_LOAD_UMAX", SDTAtomic2, [SDNPHasChain, SDNPMayStore, SDNPMayLoad, SDNPMemOperand]>; // Do not use ld, st directly. Use load, extload, sextload, zextload, store, @@ -415,16 +437,26 @@ def vector_extract : SDNode<"ISD::EXTRACT_VECTOR_ELT", SDTypeProfile<1, 2, [SDTCisPtrTy<2>]>, []>; def vector_insert : SDNode<"ISD::INSERT_VECTOR_ELT", SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>, SDTCisPtrTy<3>]>, []>; - + +// This operator does not do subvector type checking. The ARM +// backend, at least, needs it. +def vector_extract_subvec : SDNode<"ISD::EXTRACT_SUBVECTOR", + SDTypeProfile<1, 2, [SDTCisInt<2>, SDTCisVec<1>, SDTCisVec<0>]>, + []>; + +// This operator does subvector type checking. +def extract_subvector : SDNode<"ISD::EXTRACT_SUBVECTOR", SDTSubVecExtract, []>; +def insert_subvector : SDNode<"ISD::INSERT_SUBVECTOR", SDTSubVecInsert, []>; + // Nodes for intrinsics, you should use the intrinsic itself and let tblgen use // these internally. Don't reference these directly. -def intrinsic_void : SDNode<"ISD::INTRINSIC_VOID", +def intrinsic_void : SDNode<"ISD::INTRINSIC_VOID", SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>, [SDNPHasChain]>; -def intrinsic_w_chain : SDNode<"ISD::INTRINSIC_W_CHAIN", +def intrinsic_w_chain : SDNode<"ISD::INTRINSIC_W_CHAIN", SDTypeProfile<1, -1, [SDTCisPtrTy<1>]>, [SDNPHasChain]>; -def intrinsic_wo_chain : SDNode<"ISD::INTRINSIC_WO_CHAIN", +def intrinsic_wo_chain : SDNode<"ISD::INTRINSIC_WO_CHAIN", SDTypeProfile<1, -1, [SDTCisPtrTy<1>]>, []>; // Do not use cvt directly. Use cvt forms below @@ -469,10 +501,10 @@ def NOOP_SDNodeXForm : SDNodeXForm; // /// PatFrag - Represents a pattern fragment. This can match something on the -/// DAG, frame a single node to multiply nested other fragments. +/// DAG, from a single node to multiple nested other fragments. /// class PatFrag { + SDNodeXForm xform = NOOP_SDNodeXForm> : SDPatternOperator { dag Operands = ops; dag Fragment = frag; code Predicate = pred; @@ -822,7 +854,7 @@ def cvtfu : PatFrag<(ops node:$val, node:$dty, node:$sty, node:$rd, node:$sat), //===----------------------------------------------------------------------===// // Selection DAG Pattern Support. // -// Patterns are what are actually matched against the target-flavored +// Patterns are what are actually matched against by the target-flavored // instruction selection DAG. Instructions defined by the target implicitly // define patterns in most cases, but patterns can also be explicitly added when // an operation is defined by a sequence of instructions (e.g. loading a large @@ -834,7 +866,7 @@ class Pattern resultInstrs> { dag PatternToMatch = patternToMatch; list ResultInstrs = resultInstrs; list Predicates = []; // See class Instruction in Target.td. - int AddedComplexity = 0; // See class Instruction in Target.td. + int AddedComplexity = 0; // See class Instruction in Target.td. } // Pat - A simple (but common) form of a pattern, which produces a simple result diff --git a/include/llvm/Target/TargetSelectionDAGInfo.h b/include/llvm/Target/TargetSelectionDAGInfo.h index 2be183440224..c9ca7223b5f5 100644 --- a/include/llvm/Target/TargetSelectionDAGInfo.h +++ b/include/llvm/Target/TargetSelectionDAGInfo.h @@ -59,8 +59,8 @@ public: SDValue Op1, SDValue Op2, SDValue Op3, unsigned Align, bool isVolatile, bool AlwaysInline, - const Value *DstSV, uint64_t DstOff, - const Value *SrcSV, uint64_t SrcOff) const { + MachinePointerInfo DstPtrInfo, + MachinePointerInfo SrcPtrInfo) const { return SDValue(); } @@ -75,8 +75,8 @@ public: SDValue Chain, SDValue Op1, SDValue Op2, SDValue Op3, unsigned Align, bool isVolatile, - const Value *DstSV, uint64_t DstOff, - const Value *SrcSV, uint64_t SrcOff) const { + MachinePointerInfo DstPtrInfo, + MachinePointerInfo SrcPtrInfo) const { return SDValue(); } @@ -91,7 +91,7 @@ public: SDValue Chain, SDValue Op1, SDValue Op2, SDValue Op3, unsigned Align, bool isVolatile, - const Value *DstSV, uint64_t DstOff) const { + MachinePointerInfo DstPtrInfo) const { return SDValue(); } }; diff --git a/include/llvm/Transforms/IPO.h b/include/llvm/Transforms/IPO.h index 0de100348d0f..12398813cc76 100644 --- a/include/llvm/Transforms/IPO.h +++ b/include/llvm/Transforms/IPO.h @@ -99,6 +99,8 @@ ModulePass *createGVExtractionPass(std::vector& GVs, bool /// createFunctionInliningPass - Return a new pass object that uses a heuristic /// to inline direct function calls to small functions. /// +/// The -inline-threshold command line option takes precedence over the +/// threshold given here. Pass *createFunctionInliningPass(); Pass *createFunctionInliningPass(int Threshold); @@ -186,12 +188,6 @@ ModulePass *createBlockExtractorPass(); /// (prototypes) that are not used. ModulePass *createStripDeadPrototypesPass(); -//===----------------------------------------------------------------------===// -/// createPartialSpecializationPass - This pass specializes functions for -/// constant arguments. -/// -ModulePass *createPartialSpecializationPass(); - //===----------------------------------------------------------------------===// /// createFunctionAttrsPass - This pass discovers functions that do not access /// memory, or only read memory, and gives them the readnone/readonly attribute. diff --git a/include/llvm/Transforms/Instrumentation.h b/include/llvm/Transforms/Instrumentation.h index 9c579ac76105..aa9873fb8afa 100644 --- a/include/llvm/Transforms/Instrumentation.h +++ b/include/llvm/Transforms/Instrumentation.h @@ -25,6 +25,9 @@ ModulePass *createEdgeProfilerPass(); // Insert optimal edge profiling instrumentation ModulePass *createOptimalEdgeProfilerPass(); +// Insert path profiling instrumentation +ModulePass *createPathProfilerPass(); + } // End llvm namespace #endif diff --git a/include/llvm/Transforms/RSProfiling.h b/include/llvm/Transforms/RSProfiling.h deleted file mode 100644 index 02439e8e2388..000000000000 --- a/include/llvm/Transforms/RSProfiling.h +++ /dev/null @@ -1,42 +0,0 @@ -//===- RSProfiling.cpp - Various profiling using random sampling ----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the abstract interface that a profiler must implement to -// support the random profiling transform. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TRANSFORMS_RSPROFILING_H -#define LLVM_TRANSFORMS_RSPROFILING_H - -#include "llvm/Pass.h" - -namespace llvm { - class Value; - - //===--------------------------------------------------------------------===// - /// RSProfilers - The basic Random Sampling Profiler Interface Any profiler - /// that implements this interface can be transformed by the random sampling - /// pass to be sample based rather than always on. - /// - /// The only exposed function can be queried to find out if an instruction - /// was original or if it was inserted by the profiler. Implementations of - /// this interface are expected to chain to other implementations, such that - /// multiple profilers can be support simultaniously. - struct RSProfilers : public ModulePass { - static char ID; // Pass identification, replacement for typeinfo - RSProfilers() : ModulePass(&ID) {} - - /// isProfiling - This method returns true if the value passed it was - /// inserted by the profiler. - virtual bool isProfiling(Value* v) = 0; - }; -} - -#endif diff --git a/include/llvm/Transforms/Scalar.h b/include/llvm/Transforms/Scalar.h index 0c35d7e01fa4..6f2a38e5840c 100644 --- a/include/llvm/Transforms/Scalar.h +++ b/include/llvm/Transforms/Scalar.h @@ -73,7 +73,8 @@ FunctionPass *createAggressiveDCEPass(); // ScalarReplAggregates - Break up alloca's of aggregates into multiple allocas // if possible. // -FunctionPass *createScalarReplAggregatesPass(signed Threshold = -1); +FunctionPass *createScalarReplAggregatesPass(signed Threshold = -1, + bool UseDomTree = true); //===----------------------------------------------------------------------===// // @@ -117,6 +118,12 @@ Pass *createLoopStrengthReducePass(const TargetLowering *TLI = 0); // Pass *createLoopUnswitchPass(bool OptimizeForSize = false); +//===----------------------------------------------------------------------===// +// +// LoopInstSimplify - This pass simplifies instructions in a loop's body. +// +Pass *createLoopInstSimplifyPass(); + //===----------------------------------------------------------------------===// // // LoopUnroll - This pass is a simple loop unrolling pass. @@ -131,11 +138,10 @@ Pass *createLoopRotatePass(); //===----------------------------------------------------------------------===// // -// LoopIndexSplit - This pass divides loop's iteration range by spliting loop -// such that each individual loop is executed efficiently. +// LoopIdiom - This pass recognizes and replaces idioms in loops. // -Pass *createLoopIndexSplitPass(); - +Pass *createLoopIdiomPass(); + //===----------------------------------------------------------------------===// // // PromoteMemoryToRegister - This pass is used to promote memory references to @@ -259,6 +265,13 @@ FunctionPass *createBlockPlacementPass(); Pass *createLCSSAPass(); extern char &LCSSAID; +//===----------------------------------------------------------------------===// +// +// EarlyCSE - This pass performs a simple and fast CSE pass over the dominator +// tree. +// +FunctionPass *createEarlyCSEPass(); + //===----------------------------------------------------------------------===// // // GVN - This pass performs global value numbering and redundant load @@ -329,6 +342,13 @@ Pass *createLowerAtomicPass(); // Pass *createCorrelatedValuePropagationPass(); +//===----------------------------------------------------------------------===// +// +// InstructionSimplifier - Remove redundant instructions. +// +FunctionPass *createInstructionSimplifierPass(); +extern char &InstructionSimplifierID; + } // End llvm namespace #endif diff --git a/include/llvm/Transforms/Utils/AddrModeMatcher.h b/include/llvm/Transforms/Utils/AddrModeMatcher.h index be601e257b8c..0678eccb5d69 100644 --- a/include/llvm/Transforms/Utils/AddrModeMatcher.h +++ b/include/llvm/Transforms/Utils/AddrModeMatcher.h @@ -39,6 +39,12 @@ struct ExtAddrMode : public TargetLowering::AddrMode { ExtAddrMode() : BaseReg(0), ScaledReg(0) {} void print(raw_ostream &OS) const; void dump() const; + + bool operator==(const ExtAddrMode& O) const { + return (BaseReg == O.BaseReg) && (ScaledReg == O.ScaledReg) && + (BaseGV == O.BaseGV) && (BaseOffs == O.BaseOffs) && + (HasBaseReg == O.HasBaseReg) && (Scale == O.Scale); + } }; static inline raw_ostream &operator<<(raw_ostream &OS, const ExtAddrMode &AM) { @@ -84,7 +90,7 @@ public: bool Success = AddressingModeMatcher(AddrModeInsts, TLI, AccessTy, MemoryInst, Result).MatchAddr(V, 0); - Success = Success; assert(Success && "Couldn't select *anything*?"); + (void)Success; assert(Success && "Couldn't select *anything*?"); return Result; } private: diff --git a/include/llvm/Transforms/Utils/BasicBlockUtils.h b/include/llvm/Transforms/Utils/BasicBlockUtils.h index 0f5445077bef..533586028700 100644 --- a/include/llvm/Transforms/Utils/BasicBlockUtils.h +++ b/include/llvm/Transforms/Utils/BasicBlockUtils.h @@ -22,9 +22,10 @@ namespace llvm { +class AliasAnalysis; class Instruction; class Pass; -class AliasAnalysis; +class ReturnInst; /// DeleteDeadBlock - Delete the specified block, which must have no /// predecessors. @@ -35,7 +36,7 @@ void DeleteDeadBlock(BasicBlock *BB); /// any single-entry PHI nodes in it, fold them away. This handles the case /// when all entries to the PHI nodes in a block are guaranteed equal, such as /// when the block has exactly one predecessor. -void FoldSingleEntryPHINodes(BasicBlock *BB); +void FoldSingleEntryPHINodes(BasicBlock *BB, Pass *P = 0); /// DeleteDeadPHIs - Examine each PHI in the given block and delete it if it /// is dead. Also recursively delete any operands that become dead as @@ -46,7 +47,7 @@ bool DeleteDeadPHIs(BasicBlock *BB); /// MergeBlockIntoPredecessor - Attempts to merge a block into its predecessor, /// if possible. The return value indicates success or failure. -bool MergeBlockIntoPredecessor(BasicBlock* BB, Pass* P = 0); +bool MergeBlockIntoPredecessor(BasicBlock *BB, Pass *P = 0); // ReplaceInstWithValue - Replace all uses of an instruction (specified by BI) // with a value, then remove and delete the original instruction. @@ -75,15 +76,6 @@ void FindFunctionBackedges(const Function &F, SmallVectorImpl > &Result); -// RemoveSuccessor - Change the specified terminator instruction such that its -// successor #SuccNum no longer exists. Because this reduces the outgoing -// degree of the current basic block, the actual terminator instruction itself -// may have to be changed. In the case where the last successor of the block is -// deleted, a return instruction is inserted in its place which can cause a -// suprising change in program behavior if it is not expected. -// -void RemoveSuccessor(TerminatorInst *TI, unsigned SuccNum); - /// GetSuccessorNumber - Search for the specified successor of basic block BB /// and return its position in the terminator instruction's list of /// successors. It is an error to call this with a block that is not a @@ -180,7 +172,15 @@ BasicBlock *SplitBlock(BasicBlock *Old, Instruction *SplitPt, Pass *P); BasicBlock *SplitBlockPredecessors(BasicBlock *BB, BasicBlock *const *Preds, unsigned NumPreds, const char *Suffix, Pass *P = 0); - + +/// FoldReturnIntoUncondBranch - This method duplicates the specified return +/// instruction into a predecessor which ends in an unconditional branch. If +/// the return instruction returns a value defined by a PHI, propagate the +/// right value into the return. It returns the new return instruction in the +/// predecessor. +ReturnInst *FoldReturnIntoUncondBranch(ReturnInst *RI, BasicBlock *BB, + BasicBlock *Pred); + } // End llvm namespace #endif diff --git a/include/llvm/Transforms/Utils/BuildLibCalls.h b/include/llvm/Transforms/Utils/BuildLibCalls.h index c75c14277ff6..e82593838467 100644 --- a/include/llvm/Transforms/Utils/BuildLibCalls.h +++ b/include/llvm/Transforms/Utils/BuildLibCalls.h @@ -47,11 +47,6 @@ namespace llvm { /// specified pointer arguments and length. Value *EmitStrNCpy(Value *Dst, Value *Src, Value *Len, IRBuilder<> &B, const TargetData *TD, StringRef Name = "strncpy"); - - /// EmitMemCpy - Emit a call to the memcpy function to the builder. This - /// always expects that the size has type 'intptr_t' and Dst/Src are pointers. - Value *EmitMemCpy(Value *Dst, Value *Src, Value *Len, unsigned Align, - bool isVolatile, IRBuilder<> &B, const TargetData *TD); /// EmitMemCpyChk - Emit a call to the __memcpy_chk function to the builder. /// This expects that the Len and ObjSize have type 'intptr_t' and Dst/Src @@ -59,11 +54,6 @@ namespace llvm { Value *EmitMemCpyChk(Value *Dst, Value *Src, Value *Len, Value *ObjSize, IRBuilder<> &B, const TargetData *TD); - /// EmitMemMove - Emit a call to the memmove function to the builder. This - /// always expects that the size has type 'intptr_t' and Dst/Src are pointers. - Value *EmitMemMove(Value *Dst, Value *Src, Value *Len, unsigned Align, - bool isVolatile, IRBuilder<> &B, const TargetData *TD); - /// EmitMemChr - Emit a call to the memchr function. This assumes that Ptr is /// a pointer, Val is an i32 value, and Len is an 'intptr_t' value. Value *EmitMemChr(Value *Ptr, Value *Val, Value *Len, IRBuilder<> &B, @@ -73,10 +63,6 @@ namespace llvm { Value *EmitMemCmp(Value *Ptr1, Value *Ptr2, Value *Len, IRBuilder<> &B, const TargetData *TD); - /// EmitMemSet - Emit a call to the memset function - Value *EmitMemSet(Value *Dst, Value *Val, Value *Len, bool isVolatile, - IRBuilder<> &B, const TargetData *TD); - /// EmitUnaryFloatFnCall - Emit a call to the unary function named 'Name' /// (e.g. 'floor'). This function is known to take a single of type matching /// 'Op' and returns one value with the same type. If 'Op' is a long double, diff --git a/include/llvm/Transforms/Utils/Cloning.h b/include/llvm/Transforms/Utils/Cloning.h index 62bf92aced49..24ebb109a0ad 100644 --- a/include/llvm/Transforms/Utils/Cloning.h +++ b/include/llvm/Transforms/Utils/Cloning.h @@ -22,6 +22,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/ValueHandle.h" +#include "llvm/Transforms/Utils/ValueMapper.h" namespace llvm { @@ -46,7 +47,7 @@ class AllocaInst; /// CloneModule - Return an exact copy of the specified module /// Module *CloneModule(const Module *M); -Module *CloneModule(const Module *M, ValueMap &VMap); +Module *CloneModule(const Module *M, ValueToValueMapTy &VMap); /// ClonedCodeInfo - This struct can be used to capture information about code /// being cloned, while it is being cloned. @@ -102,7 +103,7 @@ struct ClonedCodeInfo { /// parameter. /// BasicBlock *CloneBasicBlock(const BasicBlock *BB, - ValueMap &VMap, + ValueToValueMapTy &VMap, const Twine &NameSuffix = "", Function *F = 0, ClonedCodeInfo *CodeInfo = 0); @@ -110,7 +111,7 @@ BasicBlock *CloneBasicBlock(const BasicBlock *BB, /// CloneLoop - Clone Loop. Clone dominator info for loop insiders. Populate /// VMap using old blocks to new blocks mapping. Loop *CloneLoop(Loop *L, LPPassManager *LPM, LoopInfo *LI, - ValueMap &VMap, Pass *P); + ValueToValueMapTy &VMap, Pass *P); /// CloneFunction - Return a copy of the specified function, but without /// embedding the function into another module. Also, any references specified @@ -125,14 +126,14 @@ Loop *CloneLoop(Loop *L, LPPassManager *LPM, LoopInfo *LI, /// mappings. /// Function *CloneFunction(const Function *F, - ValueMap &VMap, + ValueToValueMapTy &VMap, bool ModuleLevelChanges, ClonedCodeInfo *CodeInfo = 0); /// CloneFunction - Version of the function that doesn't need the VMap. /// inline Function *CloneFunction(const Function *F, ClonedCodeInfo *CodeInfo = 0){ - ValueMap VMap; + ValueToValueMapTy VMap; return CloneFunction(F, VMap, CodeInfo); } @@ -146,7 +147,7 @@ inline Function *CloneFunction(const Function *F, ClonedCodeInfo *CodeInfo = 0){ /// mappings. /// void CloneFunctionInto(Function *NewFunc, const Function *OldFunc, - ValueMap &VMap, + ValueToValueMapTy &VMap, bool ModuleLevelChanges, SmallVectorImpl &Returns, const char *NameSuffix = "", @@ -164,7 +165,7 @@ void CloneFunctionInto(Function *NewFunc, const Function *OldFunc, /// mappings. /// void CloneAndPruneFunctionInto(Function *NewFunc, const Function *OldFunc, - ValueMap &VMap, + ValueToValueMapTy &VMap, bool ModuleLevelChanges, SmallVectorImpl &Returns, const char *NameSuffix = "", diff --git a/include/llvm/Transforms/Utils/Local.h b/include/llvm/Transforms/Utils/Local.h index caae27f47a44..26b5dd8365f1 100644 --- a/include/llvm/Transforms/Utils/Local.h +++ b/include/llvm/Transforms/Utils/Local.h @@ -69,6 +69,10 @@ bool RecursivelyDeleteDeadPHINode(PHINode *PN); /// /// This returns true if it changed the code, note that it can delete /// instructions in other blocks as well in this block. +/// +/// WARNING: Do not use this function on unreachable blocks, as recursive +/// simplification is not able to handle corner-case scenarios that can +/// arise in them. bool SimplifyInstructionsInBlock(BasicBlock *BB, const TargetData *TD = 0); //===----------------------------------------------------------------------===// @@ -141,6 +145,18 @@ AllocaInst *DemoteRegToStack(Instruction &X, /// The phi node is deleted and it returns the pointer to the alloca inserted. AllocaInst *DemotePHIToStack(PHINode *P, Instruction *AllocaPoint = 0); +/// getOrEnforceKnownAlignment - If the specified pointer has an alignment that +/// we can determine, return it, otherwise return 0. If PrefAlign is specified, +/// and it is more than the alignment of the ultimate object, see if we can +/// increase the alignment of the ultimate object, making this check succeed. +unsigned getOrEnforceKnownAlignment(Value *V, unsigned PrefAlign, + const TargetData *TD = 0); + +/// getKnownAlignment - Try to infer an alignment for the specified pointer. +static inline unsigned getKnownAlignment(Value *V, const TargetData *TD = 0) { + return getOrEnforceKnownAlignment(V, 0, TD); +} + } // End llvm namespace #endif diff --git a/include/llvm/Transforms/Utils/PromoteMemToReg.h b/include/llvm/Transforms/Utils/PromoteMemToReg.h index 35cfaddb7379..98d51a29ad71 100644 --- a/include/llvm/Transforms/Utils/PromoteMemToReg.h +++ b/include/llvm/Transforms/Utils/PromoteMemToReg.h @@ -38,8 +38,7 @@ bool isAllocaPromotable(const AllocaInst *AI); /// made to the IR. /// void PromoteMemToReg(const std::vector &Allocas, - DominatorTree &DT, DominanceFrontier &DF, - AliasSetTracker *AST = 0); + DominatorTree &DT, AliasSetTracker *AST = 0); } // End llvm namespace diff --git a/include/llvm/Transforms/Utils/SSAUpdater.h b/include/llvm/Transforms/Utils/SSAUpdater.h index e50a6b15df81..b4048b9b4409 100644 --- a/include/llvm/Transforms/Utils/SSAUpdater.h +++ b/include/llvm/Transforms/Utils/SSAUpdater.h @@ -108,6 +108,55 @@ private: void operator=(const SSAUpdater&); // DO NOT IMPLEMENT SSAUpdater(const SSAUpdater&); // DO NOT IMPLEMENT }; + +/// LoadAndStorePromoter - This little helper class provides a convenient way to +/// promote a collection of loads and stores into SSA Form using the SSAUpdater. +/// This handles complexities that SSAUpdater doesn't, such as multiple loads +/// and stores in one block. +/// +/// Clients of this class are expected to subclass this and implement the +/// virtual methods. +/// +class LoadAndStorePromoter { +protected: + SSAUpdater &SSA; +public: + LoadAndStorePromoter(const SmallVectorImpl &Insts, + SSAUpdater &S, StringRef Name = StringRef()); + virtual ~LoadAndStorePromoter() {} + + /// run - This does the promotion. Insts is a list of loads and stores to + /// promote, and Name is the basename for the PHIs to insert. After this is + /// complete, the loads and stores are removed from the code. + void run(const SmallVectorImpl &Insts) const; + + + /// Return true if the specified instruction is in the Inst list (which was + /// passed into the run method). Clients should implement this with a more + /// efficient version if possible. + virtual bool isInstInList(Instruction *I, + const SmallVectorImpl &Insts) const { + for (unsigned i = 0, e = Insts.size(); i != e; ++i) + if (Insts[i] == I) + return true; + return false; + } + + /// doExtraRewritesBeforeFinalDeletion - This hook is invoked after all the + /// stores are found and inserted as available values, but + virtual void doExtraRewritesBeforeFinalDeletion() const { + } + + /// replaceLoadWithValue - Clients can choose to implement this to get + /// notified right before a load is RAUW'd another value. + virtual void replaceLoadWithValue(LoadInst *LI, Value *V) const { + } + + /// This is called before each instruction is deleted. + virtual void instructionDeleted(Instruction *I) const { + } + +}; } // End llvm namespace diff --git a/include/llvm/Transforms/Utils/UnifyFunctionExitNodes.h b/include/llvm/Transforms/Utils/UnifyFunctionExitNodes.h index a5060e6f5860..54506cfff4c3 100644 --- a/include/llvm/Transforms/Utils/UnifyFunctionExitNodes.h +++ b/include/llvm/Transforms/Utils/UnifyFunctionExitNodes.h @@ -27,7 +27,9 @@ struct UnifyFunctionExitNodes : public FunctionPass { public: static char ID; // Pass identification, replacement for typeid UnifyFunctionExitNodes() : FunctionPass(ID), - ReturnBlock(0), UnwindBlock(0) {} + ReturnBlock(0), UnwindBlock(0) { + initializeUnifyFunctionExitNodesPass(*PassRegistry::getPassRegistry()); + } // We can preserve non-critical-edgeness when we unify function exit nodes virtual void getAnalysisUsage(AnalysisUsage &AU) const; diff --git a/include/llvm/Transforms/Utils/ValueMapper.h b/include/llvm/Transforms/Utils/ValueMapper.h index 5274112897b7..d612213a8717 100644 --- a/include/llvm/Transforms/Utils/ValueMapper.h +++ b/include/llvm/Transforms/Utils/ValueMapper.h @@ -20,12 +20,31 @@ namespace llvm { class Value; class Instruction; - typedef ValueMap ValueToValueMapTy; + typedef ValueMap > ValueToValueMapTy; + /// RemapFlags - These are flags that the value mapping APIs allow. + enum RemapFlags { + RF_None = 0, + + /// RF_NoModuleLevelChanges - If this flag is set, the remapper knows that + /// only local values within a function (such as an instruction or argument) + /// are mapped, not global values like functions and global metadata. + RF_NoModuleLevelChanges = 1, + + /// RF_IgnoreMissingEntries - If this flag is set, the remapper ignores + /// entries that are not in the value map. If it is unset, it aborts if an + /// operand is asked to be remapped which doesn't exist in the mapping. + RF_IgnoreMissingEntries = 2 + }; + + static inline RemapFlags operator|(RemapFlags LHS, RemapFlags RHS) { + return RemapFlags(unsigned(LHS)|unsigned(RHS)); + } + Value *MapValue(const Value *V, ValueToValueMapTy &VM, - bool ModuleLevelChanges); + RemapFlags Flags = RF_None); void RemapInstruction(Instruction *I, ValueToValueMapTy &VM, - bool ModuleLevelChanges); + RemapFlags Flags = RF_None); } // End llvm namespace #endif diff --git a/include/llvm/Type.h b/include/llvm/Type.h index f7d6fd57a23c..0939d67265b0 100644 --- a/include/llvm/Type.h +++ b/include/llvm/Type.h @@ -12,7 +12,6 @@ #include "llvm/AbstractTypeUser.h" #include "llvm/Support/Casting.h" -#include "llvm/System/DataTypes.h" #include "llvm/ADT/GraphTraits.h" #include #include @@ -76,19 +75,20 @@ public: PPC_FP128TyID, ///< 5: 128 bit floating point type (two 64-bits) LabelTyID, ///< 6: Labels MetadataTyID, ///< 7: Metadata + X86_MMXTyID, ///< 8: MMX vectors (64 bits) // Derived types... see DerivedTypes.h file... // Make sure FirstDerivedTyID stays up to date!!! - IntegerTyID, ///< 8: Arbitrary bit width integers - FunctionTyID, ///< 9: Functions - StructTyID, ///< 10: Structures - ArrayTyID, ///< 11: Arrays - PointerTyID, ///< 12: Pointers - OpaqueTyID, ///< 13: Opaque: type with unknown structure - VectorTyID, ///< 14: SIMD 'packed' format, or other vector type + IntegerTyID, ///< 9: Arbitrary bit width integers + FunctionTyID, ///< 10: Functions + StructTyID, ///< 11: Structures + ArrayTyID, ///< 12: Arrays + PointerTyID, ///< 13: Pointers + OpaqueTyID, ///< 14: Opaque: type with unknown structure + VectorTyID, ///< 15: SIMD 'packed' format, or other vector type NumTypeIDs, // Must remain as last defined ID - LastPrimitiveTyID = MetadataTyID, + LastPrimitiveTyID = X86_MMXTyID, FirstDerivedTyID = IntegerTyID }; @@ -212,6 +212,9 @@ public: bool isFloatingPointTy() const { return ID == FloatTyID || ID == DoubleTyID || ID == X86_FP80TyID || ID == FP128TyID || ID == PPC_FP128TyID; } + /// isX86_MMXTy - Return true if this is X86 MMX. + bool isX86_MMXTy() const { return ID == X86_MMXTyID; } + /// isFPOrFPVectorTy - Return true if this is a FP type or a vector of FP. /// bool isFPOrFPVectorTy() const; @@ -310,7 +313,8 @@ public: /// bool isSized() const { // If it's a primitive, it is always sized. - if (ID == IntegerTyID || isFloatingPointTy() || ID == PointerTyID) + if (ID == IntegerTyID || isFloatingPointTy() || ID == PointerTyID || + ID == X86_MMXTyID) return true; // If it is not something that can have a size (e.g. a function or label), // it doesn't have a size. @@ -400,6 +404,7 @@ public: static const Type *getX86_FP80Ty(LLVMContext &C); static const Type *getFP128Ty(LLVMContext &C); static const Type *getPPC_FP128Ty(LLVMContext &C); + static const Type *getX86_MMXTy(LLVMContext &C); static const IntegerType *getIntNTy(LLVMContext &C, unsigned N); static const IntegerType *getInt1Ty(LLVMContext &C); static const IntegerType *getInt8Ty(LLVMContext &C); @@ -416,6 +421,7 @@ public: static const PointerType *getX86_FP80PtrTy(LLVMContext &C, unsigned AS = 0); static const PointerType *getFP128PtrTy(LLVMContext &C, unsigned AS = 0); static const PointerType *getPPC_FP128PtrTy(LLVMContext &C, unsigned AS = 0); + static const PointerType *getX86_MMXPtrTy(LLVMContext &C, unsigned AS = 0); static const PointerType *getIntNPtrTy(LLVMContext &C, unsigned N, unsigned AS = 0); static const PointerType *getInt1PtrTy(LLVMContext &C, unsigned AS = 0); diff --git a/include/llvm/TypeSymbolTable.h b/include/llvm/TypeSymbolTable.h index 26b1dbf2df41..9fdcb983232c 100644 --- a/include/llvm/TypeSymbolTable.h +++ b/include/llvm/TypeSymbolTable.h @@ -16,12 +16,11 @@ #include "llvm/Type.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/DataTypes.h" #include namespace llvm { -class StringRef; - /// This class provides a symbol table of name/type pairs with operations to /// support constructing, searching and iterating over the symbol table. The /// class derives from AbstractTypeUser so that the contents of the symbol diff --git a/include/llvm/Use.h b/include/llvm/Use.h index e1ebc6a51be5..ccbdd7fcae13 100644 --- a/include/llvm/Use.h +++ b/include/llvm/Use.h @@ -25,7 +25,6 @@ #ifndef LLVM_USE_H #define LLVM_USE_H -#include "llvm/Support/Casting.h" #include "llvm/ADT/PointerIntPair.h" #include #include @@ -35,9 +34,8 @@ namespace llvm { class Value; class User; class Use; - -/// Tag - generic tag type for (at least 32 bit) pointers -enum Tag { noTag, tagOne, tagTwo, tagThree }; +template +struct simplify_type; // Use** is only 4-byte aligned. template<> @@ -67,17 +65,19 @@ private: Use(const Use &U); /// Destructor - Only for zap() - inline ~Use() { + ~Use() { if (Val) removeFromList(); } - /// Default ctor - This leaves the Use completely uninitialized. The only - /// thing that is valid to do with this use is to call the "init" method. - inline Use() {} - enum PrevPtrTag { zeroDigitTag = noTag - , oneDigitTag = tagOne - , stopTag = tagTwo - , fullStopTag = tagThree }; + enum PrevPtrTag { zeroDigitTag + , oneDigitTag + , stopTag + , fullStopTag }; + + /// Constructor + Use(PrevPtrTag tag) : Val(0) { + Prev.setInt(tag); + } public: /// Normally Use will just implicitly convert to a Value* that it holds. @@ -112,11 +112,9 @@ public: /// a User changes. static void zap(Use *Start, const Use *Stop, bool del = false); - /// getPrefix - Return deletable pointer if appropriate - Use *getPrefix(); private: const Use* getImpliedUser() const; - static Use *initTags(Use *Start, Use *Stop, ptrdiff_t Done = 0); + static Use *initTags(Use *Start, Use *Stop); Value *Val; Use *Next; @@ -210,6 +208,15 @@ public: unsigned getOperandNo() const; }; +//===----------------------------------------------------------------------===// +// AugmentedUse layout struct +//===----------------------------------------------------------------------===// + +struct AugmentedUse : public Use { + PointerIntPair ref; + AugmentedUse(); // not implemented +}; + } // End llvm namespace #endif diff --git a/include/llvm/User.h b/include/llvm/User.h index f8277952ee4b..1363495f7c07 100644 --- a/include/llvm/User.h +++ b/include/llvm/User.h @@ -29,20 +29,6 @@ namespace llvm { template struct OperandTraits; -class User; - -/// OperandTraits - specialization to User -template <> -struct OperandTraits { - static inline Use *op_begin(User*); - static inline Use *op_end(User*); - static inline unsigned operands(const User*); - template - struct Layout { - typedef U overlay; - }; -}; - class User : public Value { User(const User &); // Do not implement void *operator new(size_t); // Do not implement @@ -61,21 +47,18 @@ protected: unsigned NumOperands; void *operator new(size_t s, unsigned Us); - void *operator new(size_t s, unsigned Us, bool Prefix); User(const Type *ty, unsigned vty, Use *OpList, unsigned NumOps) : Value(ty, vty), OperandList(OpList), NumOperands(NumOps) {} Use *allocHungoffUses(unsigned) const; - void dropHungoffUses(Use *U) { - if (OperandList == U) { - OperandList = 0; - NumOperands = 0; - } - Use::zap(U, U->getImpliedUser(), true); + void dropHungoffUses() { + Use::zap(OperandList, OperandList + NumOperands, true); + OperandList = 0; + // Reset NumOperands so User::operator delete() does the right thing. + NumOperands = 0; } public: ~User() { - if ((intptr_t(OperandList) & 1) == 0) - Use::zap(OperandList, OperandList + NumOperands); + Use::zap(OperandList, OperandList + NumOperands); } /// operator delete - free memory allocated for User and Use objects void operator delete(void *Usr); @@ -158,18 +141,6 @@ public: } }; -inline Use *OperandTraits::op_begin(User *U) { - return U->op_begin(); -} - -inline Use *OperandTraits::op_end(User *U) { - return U->op_end(); -} - -inline unsigned OperandTraits::operands(const User *U) { - return U->getNumOperands(); -} - template<> struct simplify_type { typedef Value* SimpleType; diff --git a/include/llvm/Value.h b/include/llvm/Value.h index 8740f353ab51..130e2735f525 100644 --- a/include/llvm/Value.h +++ b/include/llvm/Value.h @@ -252,6 +252,12 @@ public: return SubclassOptionalData; } + /// clearSubclassOptionalData - Clear the optional flags contained in + /// this value. + void clearSubclassOptionalData() { + SubclassOptionalData = 0; + } + /// hasSameSubclassOptionalData - Test whether the optional flags contained /// in this value are equal to the optional flags in the given value. bool hasSameSubclassOptionalData(const Value *V) const { @@ -285,15 +291,9 @@ public: return const_cast(this)->stripPointerCasts(); } - /// getUnderlyingObject - This method strips off any GEP address adjustments - /// and pointer casts from the specified value, returning the original object - /// being addressed. Note that the returned value has pointer type if the - /// specified value does. If the MaxLookup value is non-zero, it limits the - /// number of instructions to be stripped off. - Value *getUnderlyingObject(unsigned MaxLookup = 6); - const Value *getUnderlyingObject(unsigned MaxLookup = 6) const { - return const_cast(this)->getUnderlyingObject(MaxLookup); - } + /// isDereferenceablePointer - Test if this value is always a pointer to + /// allocated and suitably aligned memory for a simple load or store. + bool isDereferenceablePointer() const; /// DoPHITranslation - If this value is a PHI node with CurBB as its parent, /// return the value in the PHI node corresponding to PredBB. If not, return diff --git a/include/llvm/ValueSymbolTable.h b/include/llvm/ValueSymbolTable.h index 35fc97b2d3ce..1738cc4a7a79 100644 --- a/include/llvm/ValueSymbolTable.h +++ b/include/llvm/ValueSymbolTable.h @@ -16,7 +16,7 @@ #include "llvm/Value.h" #include "llvm/ADT/StringMap.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { template diff --git a/lib/Analysis/AliasAnalysis.cpp b/lib/Analysis/AliasAnalysis.cpp index 1f2528fa560f..be02ddbaa534 100644 --- a/lib/Analysis/AliasAnalysis.cpp +++ b/lib/Analysis/AliasAnalysis.cpp @@ -30,12 +30,13 @@ #include "llvm/Function.h" #include "llvm/IntrinsicInst.h" #include "llvm/Instructions.h" +#include "llvm/LLVMContext.h" #include "llvm/Type.h" #include "llvm/Target/TargetData.h" using namespace llvm; // Register the AliasAnalysis interface, providing a nice name to refer to. -static RegisterAnalysisGroup Z("Alias Analysis"); +INITIALIZE_ANALYSIS_GROUP(AliasAnalysis, "Alias Analysis", NoAA) char AliasAnalysis::ID = 0; //===----------------------------------------------------------------------===// @@ -43,15 +44,15 @@ char AliasAnalysis::ID = 0; //===----------------------------------------------------------------------===// AliasAnalysis::AliasResult -AliasAnalysis::alias(const Value *V1, unsigned V1Size, - const Value *V2, unsigned V2Size) { +AliasAnalysis::alias(const Location &LocA, const Location &LocB) { assert(AA && "AA didn't call InitializeAliasAnalysis in its run method!"); - return AA->alias(V1, V1Size, V2, V2Size); + return AA->alias(LocA, LocB); } -bool AliasAnalysis::pointsToConstantMemory(const Value *P) { +bool AliasAnalysis::pointsToConstantMemory(const Location &Loc, + bool OrLocal) { assert(AA && "AA didn't call InitializeAliasAnalysis in its run method!"); - return AA->pointsToConstantMemory(P); + return AA->pointsToConstantMemory(Loc, OrLocal); } void AliasAnalysis::deleteValue(Value *V) { @@ -64,49 +65,55 @@ void AliasAnalysis::copyValue(Value *From, Value *To) { AA->copyValue(From, To); } +void AliasAnalysis::addEscapingUse(Use &U) { + assert(AA && "AA didn't call InitializeAliasAnalysis in its run method!"); + AA->addEscapingUse(U); +} + + AliasAnalysis::ModRefResult AliasAnalysis::getModRefInfo(ImmutableCallSite CS, - const Value *P, unsigned Size) { - // Don't assert AA because BasicAA calls us in order to make use of the - // logic here. + const Location &Loc) { + assert(AA && "AA didn't call InitializeAliasAnalysis in its run method!"); ModRefBehavior MRB = getModRefBehavior(CS); if (MRB == DoesNotAccessMemory) return NoModRef; ModRefResult Mask = ModRef; - if (MRB == OnlyReadsMemory) + if (onlyReadsMemory(MRB)) Mask = Ref; - else if (MRB == AliasAnalysis::AccessesArguments) { + + if (onlyAccessesArgPointees(MRB)) { bool doesAlias = false; - for (ImmutableCallSite::arg_iterator AI = CS.arg_begin(), AE = CS.arg_end(); - AI != AE; ++AI) - if (!isNoAlias(*AI, ~0U, P, Size)) { - doesAlias = true; - break; - } + if (doesAccessArgPointees(MRB)) + for (ImmutableCallSite::arg_iterator AI = CS.arg_begin(), AE = CS.arg_end(); + AI != AE; ++AI) + if (!isNoAlias(Location(*AI), Loc)) { + doesAlias = true; + break; + } if (!doesAlias) return NoModRef; } - // If P points to a constant memory location, the call definitely could not + // If Loc is a constant memory location, the call definitely could not // modify the memory location. - if ((Mask & Mod) && pointsToConstantMemory(P)) + if ((Mask & Mod) && pointsToConstantMemory(Loc)) Mask = ModRefResult(Mask & ~Mod); - // If this is BasicAA, don't forward. + // If this is the end of the chain, don't forward. if (!AA) return Mask; // Otherwise, fall back to the next AA in the chain. But we can merge // in any mask we've managed to compute. - return ModRefResult(AA->getModRefInfo(CS, P, Size) & Mask); + return ModRefResult(AA->getModRefInfo(CS, Loc) & Mask); } AliasAnalysis::ModRefResult AliasAnalysis::getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2) { - // Don't assert AA because BasicAA calls us in order to make use of the - // logic here. + assert(AA && "AA didn't call InitializeAliasAnalysis in its run method!"); // If CS1 or CS2 are readnone, they don't interact. ModRefBehavior CS1B = getModRefBehavior(CS1); @@ -116,45 +123,47 @@ AliasAnalysis::getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2) { if (CS2B == DoesNotAccessMemory) return NoModRef; // If they both only read from memory, there is no dependence. - if (CS1B == OnlyReadsMemory && CS2B == OnlyReadsMemory) + if (onlyReadsMemory(CS1B) && onlyReadsMemory(CS2B)) return NoModRef; AliasAnalysis::ModRefResult Mask = ModRef; // If CS1 only reads memory, the only dependence on CS2 can be // from CS1 reading memory written by CS2. - if (CS1B == OnlyReadsMemory) + if (onlyReadsMemory(CS1B)) Mask = ModRefResult(Mask & Ref); // If CS2 only access memory through arguments, accumulate the mod/ref // information from CS1's references to the memory referenced by // CS2's arguments. - if (CS2B == AccessesArguments) { + if (onlyAccessesArgPointees(CS2B)) { AliasAnalysis::ModRefResult R = NoModRef; - for (ImmutableCallSite::arg_iterator - I = CS2.arg_begin(), E = CS2.arg_end(); I != E; ++I) { - R = ModRefResult((R | getModRefInfo(CS1, *I, UnknownSize)) & Mask); - if (R == Mask) - break; - } + if (doesAccessArgPointees(CS2B)) + for (ImmutableCallSite::arg_iterator + I = CS2.arg_begin(), E = CS2.arg_end(); I != E; ++I) { + R = ModRefResult((R | getModRefInfo(CS1, *I, UnknownSize)) & Mask); + if (R == Mask) + break; + } return R; } // If CS1 only accesses memory through arguments, check if CS2 references // any of the memory referenced by CS1's arguments. If not, return NoModRef. - if (CS1B == AccessesArguments) { + if (onlyAccessesArgPointees(CS1B)) { AliasAnalysis::ModRefResult R = NoModRef; - for (ImmutableCallSite::arg_iterator - I = CS1.arg_begin(), E = CS1.arg_end(); I != E; ++I) - if (getModRefInfo(CS2, *I, UnknownSize) != NoModRef) { - R = Mask; - break; - } + if (doesAccessArgPointees(CS1B)) + for (ImmutableCallSite::arg_iterator + I = CS1.arg_begin(), E = CS1.arg_end(); I != E; ++I) + if (getModRefInfo(CS2, *I, UnknownSize) != NoModRef) { + R = Mask; + break; + } if (R == NoModRef) return R; } - // If this is BasicAA, don't forward. + // If this is the end of the chain, don't forward. if (!AA) return Mask; // Otherwise, fall back to the next AA in the chain. But we can merge @@ -164,8 +173,7 @@ AliasAnalysis::getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2) { AliasAnalysis::ModRefBehavior AliasAnalysis::getModRefBehavior(ImmutableCallSite CS) { - // Don't assert AA because BasicAA calls us in order to make use of the - // logic here. + assert(AA && "AA didn't call InitializeAliasAnalysis in its run method!"); ModRefBehavior Min = UnknownModRefBehavior; @@ -174,12 +182,12 @@ AliasAnalysis::getModRefBehavior(ImmutableCallSite CS) { if (const Function *F = CS.getCalledFunction()) Min = getModRefBehavior(F); - // If this is BasicAA, don't forward. + // If this is the end of the chain, don't forward. if (!AA) return Min; // Otherwise, fall back to the next AA in the chain. But we can merge // in any result we've managed to compute. - return std::min(AA->getModRefBehavior(CS), Min); + return ModRefBehavior(AA->getModRefBehavior(CS) & Min); } AliasAnalysis::ModRefBehavior @@ -188,20 +196,66 @@ AliasAnalysis::getModRefBehavior(const Function *F) { return AA->getModRefBehavior(F); } - //===----------------------------------------------------------------------===// // AliasAnalysis non-virtual helper method implementation //===----------------------------------------------------------------------===// +AliasAnalysis::Location AliasAnalysis::getLocation(const LoadInst *LI) { + return Location(LI->getPointerOperand(), + getTypeStoreSize(LI->getType()), + LI->getMetadata(LLVMContext::MD_tbaa)); +} + +AliasAnalysis::Location AliasAnalysis::getLocation(const StoreInst *SI) { + return Location(SI->getPointerOperand(), + getTypeStoreSize(SI->getValueOperand()->getType()), + SI->getMetadata(LLVMContext::MD_tbaa)); +} + +AliasAnalysis::Location AliasAnalysis::getLocation(const VAArgInst *VI) { + return Location(VI->getPointerOperand(), + UnknownSize, + VI->getMetadata(LLVMContext::MD_tbaa)); +} + + +AliasAnalysis::Location +AliasAnalysis::getLocationForSource(const MemTransferInst *MTI) { + uint64_t Size = UnknownSize; + if (ConstantInt *C = dyn_cast(MTI->getLength())) + Size = C->getValue().getZExtValue(); + + // memcpy/memmove can have TBAA tags. For memcpy, they apply + // to both the source and the destination. + MDNode *TBAATag = MTI->getMetadata(LLVMContext::MD_tbaa); + + return Location(MTI->getRawSource(), Size, TBAATag); +} + +AliasAnalysis::Location +AliasAnalysis::getLocationForDest(const MemIntrinsic *MTI) { + uint64_t Size = UnknownSize; + if (ConstantInt *C = dyn_cast(MTI->getLength())) + Size = C->getValue().getZExtValue(); + + // memcpy/memmove can have TBAA tags. For memcpy, they apply + // to both the source and the destination. + MDNode *TBAATag = MTI->getMetadata(LLVMContext::MD_tbaa); + + return Location(MTI->getRawDest(), Size, TBAATag); +} + + + AliasAnalysis::ModRefResult -AliasAnalysis::getModRefInfo(const LoadInst *L, const Value *P, unsigned Size) { +AliasAnalysis::getModRefInfo(const LoadInst *L, const Location &Loc) { // Be conservative in the face of volatile. if (L->isVolatile()) return ModRef; // If the load address doesn't alias the given address, it doesn't read // or write the specified memory. - if (!alias(L->getOperand(0), getTypeStoreSize(L->getType()), P, Size)) + if (!alias(getLocation(L), Loc)) return NoModRef; // Otherwise, a load just reads. @@ -209,20 +263,19 @@ AliasAnalysis::getModRefInfo(const LoadInst *L, const Value *P, unsigned Size) { } AliasAnalysis::ModRefResult -AliasAnalysis::getModRefInfo(const StoreInst *S, const Value *P, unsigned Size) { +AliasAnalysis::getModRefInfo(const StoreInst *S, const Location &Loc) { // Be conservative in the face of volatile. if (S->isVolatile()) return ModRef; // If the store address cannot alias the pointer in question, then the // specified memory cannot be modified by the store. - if (!alias(S->getOperand(1), - getTypeStoreSize(S->getOperand(0)->getType()), P, Size)) + if (!alias(getLocation(S), Loc)) return NoModRef; // If the pointer is a pointer to constant memory, then it could not have been // modified by this store. - if (pointsToConstantMemory(P)) + if (pointsToConstantMemory(Loc)) return NoModRef; // Otherwise, a store just writes. @@ -230,29 +283,21 @@ AliasAnalysis::getModRefInfo(const StoreInst *S, const Value *P, unsigned Size) } AliasAnalysis::ModRefResult -AliasAnalysis::getModRefInfo(const VAArgInst *V, const Value *P, unsigned Size) { +AliasAnalysis::getModRefInfo(const VAArgInst *V, const Location &Loc) { // If the va_arg address cannot alias the pointer in question, then the // specified memory cannot be accessed by the va_arg. - if (!alias(V->getOperand(0), UnknownSize, P, Size)) + if (!alias(getLocation(V), Loc)) return NoModRef; // If the pointer is a pointer to constant memory, then it could not have been // modified by this va_arg. - if (pointsToConstantMemory(P)) + if (pointsToConstantMemory(Loc)) return NoModRef; // Otherwise, a va_arg reads and writes. return ModRef; } - -AliasAnalysis::ModRefBehavior -AliasAnalysis::getIntrinsicModRefBehavior(unsigned iid) { -#define GET_INTRINSIC_MODREF_BEHAVIOR -#include "llvm/Intrinsics.gen" -#undef GET_INTRINSIC_MODREF_BEHAVIOR -} - // AliasAnalysis destructor: DO NOT move this to the header file for // AliasAnalysis or else clients of the AliasAnalysis class may not depend on // the AliasAnalysis.o file in the current .a file, causing alias analysis @@ -277,16 +322,16 @@ void AliasAnalysis::getAnalysisUsage(AnalysisUsage &AU) const { /// getTypeStoreSize - Return the TargetData store size for the given type, /// if known, or a conservative value otherwise. /// -unsigned AliasAnalysis::getTypeStoreSize(const Type *Ty) { - return TD ? TD->getTypeStoreSize(Ty) : ~0u; +uint64_t AliasAnalysis::getTypeStoreSize(const Type *Ty) { + return TD ? TD->getTypeStoreSize(Ty) : UnknownSize; } /// canBasicBlockModify - Return true if it is possible for execution of the /// specified basic block to modify the value pointed to by Ptr. /// bool AliasAnalysis::canBasicBlockModify(const BasicBlock &BB, - const Value *Ptr, unsigned Size) { - return canInstructionRangeModify(BB.front(), BB.back(), Ptr, Size); + const Location &Loc) { + return canInstructionRangeModify(BB.front(), BB.back(), Loc); } /// canInstructionRangeModify - Return true if it is possible for the execution @@ -296,7 +341,7 @@ bool AliasAnalysis::canBasicBlockModify(const BasicBlock &BB, /// bool AliasAnalysis::canInstructionRangeModify(const Instruction &I1, const Instruction &I2, - const Value *Ptr, unsigned Size) { + const Location &Loc) { assert(I1.getParent() == I2.getParent() && "Instructions not in same basic block!"); BasicBlock::const_iterator I = &I1; @@ -304,7 +349,7 @@ bool AliasAnalysis::canInstructionRangeModify(const Instruction &I1, ++E; // Convert from inclusive to exclusive range. for (; I != E; ++I) // Check every instruction in range - if (getModRefInfo(I, Ptr, Size) & Mod) + if (getModRefInfo(I, Loc) & Mod) return true; return false; } @@ -336,9 +381,3 @@ bool llvm::isIdentifiedObject(const Value *V) { return A->hasNoAliasAttr() || A->hasByValAttr(); return false; } - -// Because of the way .a files work, we must force the BasicAA implementation to -// be pulled in if the AliasAnalysis classes are pulled in. Otherwise we run -// the risk of AliasAnalysis being used, but the default implementation not -// being linked into the tool that uses it. -DEFINING_FILE_FOR(AliasAnalysis) diff --git a/lib/Analysis/AliasAnalysisCounter.cpp b/lib/Analysis/AliasAnalysisCounter.cpp index b17804186a63..d947220e078d 100644 --- a/lib/Analysis/AliasAnalysisCounter.cpp +++ b/lib/Analysis/AliasAnalysisCounter.cpp @@ -29,13 +29,14 @@ PrintAllFailures("count-aa-print-all-failed-queries", cl::ReallyHidden); namespace { class AliasAnalysisCounter : public ModulePass, public AliasAnalysis { - unsigned No, May, Must; + unsigned No, May, Partial, Must; unsigned NoMR, JustRef, JustMod, MR; Module *M; public: static char ID; // Class identification, replacement for typeinfo AliasAnalysisCounter() : ModulePass(ID) { - No = May = Must = 0; + initializeAliasAnalysisCounterPass(*PassRegistry::getPassRegistry()); + No = May = Partial = Must = 0; NoMR = JustRef = JustMod = MR = 0; } @@ -44,7 +45,7 @@ namespace { << Val*100/Sum << "%)\n"; } ~AliasAnalysisCounter() { - unsigned AASum = No+May+Must; + unsigned AASum = No+May+Partial+Must; unsigned MRSum = NoMR+JustRef+JustMod+MR; if (AASum + MRSum) { // Print a report if any counted queries occurred... errs() << "\n===== Alias Analysis Counter Report =====\n" @@ -53,9 +54,12 @@ namespace { if (AASum) { printLine("no alias", No, AASum); printLine("may alias", May, AASum); + printLine("partial alias", Partial, AASum); printLine("must alias", Must, AASum); errs() << " Alias Analysis Counter Summary: " << No*100/AASum << "%/" - << May*100/AASum << "%/" << Must*100/AASum<<"%\n\n"; + << May*100/AASum << "%/" + << Partial*100/AASum << "%/" + << Must*100/AASum<<"%\n\n"; } errs() << " " << MRSum << " Total Mod/Ref Queries Performed\n"; @@ -94,17 +98,16 @@ namespace { } // FIXME: We could count these too... - bool pointsToConstantMemory(const Value *P) { - return getAnalysis().pointsToConstantMemory(P); + bool pointsToConstantMemory(const Location &Loc, bool OrLocal) { + return getAnalysis().pointsToConstantMemory(Loc, OrLocal); } // Forwarding functions: just delegate to a real AA implementation, counting // the number of responses... - AliasResult alias(const Value *V1, unsigned V1Size, - const Value *V2, unsigned V2Size); + AliasResult alias(const Location &LocA, const Location &LocB); ModRefResult getModRefInfo(ImmutableCallSite CS, - const Value *P, unsigned Size); + const Location &Loc); ModRefResult getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2) { return AliasAnalysis::getModRefInfo(CS1,CS2); @@ -114,32 +117,32 @@ namespace { char AliasAnalysisCounter::ID = 0; INITIALIZE_AG_PASS(AliasAnalysisCounter, AliasAnalysis, "count-aa", - "Count Alias Analysis Query Responses", false, true, false); + "Count Alias Analysis Query Responses", false, true, false) ModulePass *llvm::createAliasAnalysisCounterPass() { return new AliasAnalysisCounter(); } AliasAnalysis::AliasResult -AliasAnalysisCounter::alias(const Value *V1, unsigned V1Size, - const Value *V2, unsigned V2Size) { - AliasResult R = getAnalysis().alias(V1, V1Size, V2, V2Size); +AliasAnalysisCounter::alias(const Location &LocA, const Location &LocB) { + AliasResult R = getAnalysis().alias(LocA, LocB); const char *AliasString; switch (R) { default: llvm_unreachable("Unknown alias type!"); case NoAlias: No++; AliasString = "No alias"; break; case MayAlias: May++; AliasString = "May alias"; break; + case PartialAlias: Partial++; AliasString = "Partial alias"; break; case MustAlias: Must++; AliasString = "Must alias"; break; } if (PrintAll || (PrintAllFailures && R == MayAlias)) { errs() << AliasString << ":\t"; - errs() << "[" << V1Size << "B] "; - WriteAsOperand(errs(), V1, true, M); + errs() << "[" << LocA.Size << "B] "; + WriteAsOperand(errs(), LocA.Ptr, true, M); errs() << ", "; - errs() << "[" << V2Size << "B] "; - WriteAsOperand(errs(), V2, true, M); + errs() << "[" << LocB.Size << "B] "; + WriteAsOperand(errs(), LocB.Ptr, true, M); errs() << "\n"; } @@ -148,8 +151,8 @@ AliasAnalysisCounter::alias(const Value *V1, unsigned V1Size, AliasAnalysis::ModRefResult AliasAnalysisCounter::getModRefInfo(ImmutableCallSite CS, - const Value *P, unsigned Size) { - ModRefResult R = getAnalysis().getModRefInfo(CS, P, Size); + const Location &Loc) { + ModRefResult R = getAnalysis().getModRefInfo(CS, Loc); const char *MRString; switch (R) { @@ -162,8 +165,8 @@ AliasAnalysisCounter::getModRefInfo(ImmutableCallSite CS, if (PrintAll || (PrintAllFailures && R == ModRef)) { errs() << MRString << ": Ptr: "; - errs() << "[" << Size << "B] "; - WriteAsOperand(errs(), P, true, M); + errs() << "[" << Loc.Size << "B] "; + WriteAsOperand(errs(), Loc.Ptr, true, M); errs() << "\t<->" << *CS.getInstruction() << '\n'; } return R; diff --git a/lib/Analysis/AliasAnalysisEvaluator.cpp b/lib/Analysis/AliasAnalysisEvaluator.cpp index ce363cbc7bbd..1afc1b71d93e 100644 --- a/lib/Analysis/AliasAnalysisEvaluator.cpp +++ b/lib/Analysis/AliasAnalysisEvaluator.cpp @@ -36,6 +36,7 @@ static cl::opt PrintAll("print-all-alias-modref-info", cl::ReallyHidden); static cl::opt PrintNoAlias("print-no-aliases", cl::ReallyHidden); static cl::opt PrintMayAlias("print-may-aliases", cl::ReallyHidden); +static cl::opt PrintPartialAlias("print-partial-aliases", cl::ReallyHidden); static cl::opt PrintMustAlias("print-must-aliases", cl::ReallyHidden); static cl::opt PrintNoModRef("print-no-modref", cl::ReallyHidden); @@ -45,12 +46,14 @@ static cl::opt PrintModRef("print-modref", cl::ReallyHidden); namespace { class AAEval : public FunctionPass { - unsigned NoAlias, MayAlias, MustAlias; + unsigned NoAlias, MayAlias, PartialAlias, MustAlias; unsigned NoModRef, Mod, Ref, ModRef; public: static char ID; // Pass identification, replacement for typeid - AAEval() : FunctionPass(ID) {} + AAEval() : FunctionPass(ID) { + initializeAAEvalPass(*PassRegistry::getPassRegistry()); + } virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); @@ -58,11 +61,12 @@ namespace { } bool doInitialization(Module &M) { - NoAlias = MayAlias = MustAlias = 0; + NoAlias = MayAlias = PartialAlias = MustAlias = 0; NoModRef = Mod = Ref = ModRef = 0; if (PrintAll) { - PrintNoAlias = PrintMayAlias = PrintMustAlias = true; + PrintNoAlias = PrintMayAlias = true; + PrintPartialAlias = PrintMustAlias = true; PrintNoModRef = PrintMod = PrintRef = PrintModRef = true; } return false; @@ -74,8 +78,11 @@ namespace { } char AAEval::ID = 0; -INITIALIZE_PASS(AAEval, "aa-eval", - "Exhaustive Alias Analysis Precision Evaluator", false, true); +INITIALIZE_PASS_BEGIN(AAEval, "aa-eval", + "Exhaustive Alias Analysis Precision Evaluator", false, true) +INITIALIZE_AG_DEPENDENCY(AliasAnalysis) +INITIALIZE_PASS_END(AAEval, "aa-eval", + "Exhaustive Alias Analysis Precision Evaluator", false, true) FunctionPass *llvm::createAAEvalPass() { return new AAEval(); } @@ -155,7 +162,7 @@ bool AAEval::runOnFunction(Function &F) { } } - if (PrintNoAlias || PrintMayAlias || PrintMustAlias || + if (PrintNoAlias || PrintMayAlias || PrintPartialAlias || PrintMustAlias || PrintNoModRef || PrintMod || PrintRef || PrintModRef) errs() << "Function: " << F.getName() << ": " << Pointers.size() << " pointers, " << CallSites.size() << " call sites\n"; @@ -163,12 +170,12 @@ bool AAEval::runOnFunction(Function &F) { // iterate over the worklist, and run the full (n^2)/2 disambiguations for (SetVector::iterator I1 = Pointers.begin(), E = Pointers.end(); I1 != E; ++I1) { - unsigned I1Size = ~0u; + uint64_t I1Size = AliasAnalysis::UnknownSize; const Type *I1ElTy = cast((*I1)->getType())->getElementType(); if (I1ElTy->isSized()) I1Size = AA.getTypeStoreSize(I1ElTy); for (SetVector::iterator I2 = Pointers.begin(); I2 != I1; ++I2) { - unsigned I2Size = ~0u; + uint64_t I2Size = AliasAnalysis::UnknownSize; const Type *I2ElTy =cast((*I2)->getType())->getElementType(); if (I2ElTy->isSized()) I2Size = AA.getTypeStoreSize(I2ElTy); @@ -179,6 +186,10 @@ bool AAEval::runOnFunction(Function &F) { case AliasAnalysis::MayAlias: PrintResults("MayAlias", PrintMayAlias, *I1, *I2, F.getParent()); ++MayAlias; break; + case AliasAnalysis::PartialAlias: + PrintResults("PartialAlias", PrintPartialAlias, *I1, *I2, + F.getParent()); + ++PartialAlias; break; case AliasAnalysis::MustAlias: PrintResults("MustAlias", PrintMustAlias, *I1, *I2, F.getParent()); ++MustAlias; break; @@ -195,7 +206,7 @@ bool AAEval::runOnFunction(Function &F) { for (SetVector::iterator V = Pointers.begin(), Ve = Pointers.end(); V != Ve; ++V) { - unsigned Size = ~0u; + uint64_t Size = AliasAnalysis::UnknownSize; const Type *ElTy = cast((*V)->getType())->getElementType(); if (ElTy->isSized()) Size = AA.getTypeStoreSize(ElTy); @@ -250,7 +261,7 @@ static void PrintPercent(unsigned Num, unsigned Sum) { } bool AAEval::doFinalization(Module &M) { - unsigned AliasSum = NoAlias + MayAlias + MustAlias; + unsigned AliasSum = NoAlias + MayAlias + PartialAlias + MustAlias; errs() << "===== Alias Analysis Evaluator Report =====\n"; if (AliasSum == 0) { errs() << " Alias Analysis Evaluator Summary: No pointers!\n"; @@ -260,10 +271,13 @@ bool AAEval::doFinalization(Module &M) { PrintPercent(NoAlias, AliasSum); errs() << " " << MayAlias << " may alias responses "; PrintPercent(MayAlias, AliasSum); + errs() << " " << PartialAlias << " partial alias responses "; + PrintPercent(PartialAlias, AliasSum); errs() << " " << MustAlias << " must alias responses "; PrintPercent(MustAlias, AliasSum); errs() << " Alias Analysis Evaluator Pointer Alias Summary: " << NoAlias*100/AliasSum << "%/" << MayAlias*100/AliasSum << "%/" + << PartialAlias*100/AliasSum << "%/" << MustAlias*100/AliasSum << "%\n"; } diff --git a/lib/Analysis/AliasDebugger.cpp b/lib/Analysis/AliasDebugger.cpp index b9fe64608c01..f15c05153e10 100644 --- a/lib/Analysis/AliasDebugger.cpp +++ b/lib/Analysis/AliasDebugger.cpp @@ -39,7 +39,9 @@ namespace { public: static char ID; // Class identification, replacement for typeinfo - AliasDebugger() : ModulePass(ID) {} + AliasDebugger() : ModulePass(ID) { + initializeAliasDebuggerPass(*PassRegistry::getPassRegistry()); + } bool runOnModule(Module &M) { InitializeAliasAnalysis(this); // set up super class @@ -92,17 +94,18 @@ namespace { //------------------------------------------------ // Implement the AliasAnalysis API // - AliasResult alias(const Value *V1, unsigned V1Size, - const Value *V2, unsigned V2Size) { - assert(Vals.find(V1) != Vals.end() && "Never seen value in AA before"); - assert(Vals.find(V2) != Vals.end() && "Never seen value in AA before"); - return AliasAnalysis::alias(V1, V1Size, V2, V2Size); + AliasResult alias(const Location &LocA, const Location &LocB) { + assert(Vals.find(LocA.Ptr) != Vals.end() && + "Never seen value in AA before"); + assert(Vals.find(LocB.Ptr) != Vals.end() && + "Never seen value in AA before"); + return AliasAnalysis::alias(LocA, LocB); } ModRefResult getModRefInfo(ImmutableCallSite CS, - const Value *P, unsigned Size) { - assert(Vals.find(P) != Vals.end() && "Never seen value in AA before"); - return AliasAnalysis::getModRefInfo(CS, P, Size); + const Location &Loc) { + assert(Vals.find(Loc.Ptr) != Vals.end() && "Never seen value in AA before"); + return AliasAnalysis::getModRefInfo(CS, Loc); } ModRefResult getModRefInfo(ImmutableCallSite CS1, @@ -110,9 +113,9 @@ namespace { return AliasAnalysis::getModRefInfo(CS1,CS2); } - bool pointsToConstantMemory(const Value *P) { - assert(Vals.find(P) != Vals.end() && "Never seen value in AA before"); - return AliasAnalysis::pointsToConstantMemory(P); + bool pointsToConstantMemory(const Location &Loc, bool OrLocal) { + assert(Vals.find(Loc.Ptr) != Vals.end() && "Never seen value in AA before"); + return AliasAnalysis::pointsToConstantMemory(Loc, OrLocal); } virtual void deleteValue(Value *V) { @@ -129,7 +132,7 @@ namespace { char AliasDebugger::ID = 0; INITIALIZE_AG_PASS(AliasDebugger, AliasAnalysis, "debug-aa", - "AA use debugger", false, true, false); + "AA use debugger", false, true, false) Pass *llvm::createAliasDebugger() { return new AliasDebugger(); } diff --git a/lib/Analysis/AliasSetTracker.cpp b/lib/Analysis/AliasSetTracker.cpp index e74543bb508a..3a46976d66f7 100644 --- a/lib/Analysis/AliasSetTracker.cpp +++ b/lib/Analysis/AliasSetTracker.cpp @@ -15,6 +15,7 @@ #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Instructions.h" #include "llvm/IntrinsicInst.h" +#include "llvm/LLVMContext.h" #include "llvm/Pass.h" #include "llvm/Type.h" #include "llvm/Target/TargetData.h" @@ -45,7 +46,12 @@ void AliasSet::mergeSetIn(AliasSet &AS, AliasSetTracker &AST) { PointerRec *R = AS.getSomePointer(); // If the pointers are not a must-alias pair, this set becomes a may alias. - if (AA.alias(L->getValue(), L->getSize(), R->getValue(), R->getSize()) + if (AA.alias(AliasAnalysis::Location(L->getValue(), + L->getSize(), + L->getTBAAInfo()), + AliasAnalysis::Location(R->getValue(), + R->getSize(), + R->getTBAAInfo())) != AliasAnalysis::MustAlias) AliasTy = MayAlias; } @@ -87,7 +93,8 @@ void AliasSet::removeFromTracker(AliasSetTracker &AST) { } void AliasSet::addPointer(AliasSetTracker &AST, PointerRec &Entry, - unsigned Size, bool KnownMustAlias) { + uint64_t Size, const MDNode *TBAAInfo, + bool KnownMustAlias) { assert(!Entry.hasAliasSet() && "Entry already in set!"); // Check to see if we have to downgrade to _may_ alias. @@ -95,16 +102,18 @@ void AliasSet::addPointer(AliasSetTracker &AST, PointerRec &Entry, if (PointerRec *P = getSomePointer()) { AliasAnalysis &AA = AST.getAliasAnalysis(); AliasAnalysis::AliasResult Result = - AA.alias(P->getValue(), P->getSize(), Entry.getValue(), Size); - if (Result == AliasAnalysis::MayAlias) + AA.alias(AliasAnalysis::Location(P->getValue(), P->getSize(), + P->getTBAAInfo()), + AliasAnalysis::Location(Entry.getValue(), Size, TBAAInfo)); + if (Result != AliasAnalysis::MustAlias) AliasTy = MayAlias; else // First entry of must alias must have maximum size! - P->updateSize(Size); + P->updateSizeAndTBAAInfo(Size, TBAAInfo); assert(Result != AliasAnalysis::NoAlias && "Cannot be part of must set!"); } Entry.setAliasSet(this); - Entry.updateSize(Size); + Entry.updateSizeAndTBAAInfo(Size, TBAAInfo); // Add it to the end of the list... assert(*PtrListEnd == 0 && "End of list is not null?"); @@ -120,7 +129,7 @@ void AliasSet::addCallSite(CallSite CS, AliasAnalysis &AA) { AliasAnalysis::ModRefBehavior Behavior = AA.getModRefBehavior(CS); if (Behavior == AliasAnalysis::DoesNotAccessMemory) return; - else if (Behavior == AliasAnalysis::OnlyReadsMemory) { + if (AliasAnalysis::onlyReadsMemory(Behavior)) { AliasTy = MayAlias; AccessTy |= Refs; return; @@ -134,7 +143,8 @@ void AliasSet::addCallSite(CallSite CS, AliasAnalysis &AA) { /// aliasesPointer - Return true if the specified pointer "may" (or must) /// alias one of the members in the set. /// -bool AliasSet::aliasesPointer(const Value *Ptr, unsigned Size, +bool AliasSet::aliasesPointer(const Value *Ptr, uint64_t Size, + const MDNode *TBAAInfo, AliasAnalysis &AA) const { if (AliasTy == MustAlias) { assert(CallSites.empty() && "Illegal must alias set!"); @@ -143,19 +153,26 @@ bool AliasSet::aliasesPointer(const Value *Ptr, unsigned Size, // SOME value in the set. PointerRec *SomePtr = getSomePointer(); assert(SomePtr && "Empty must-alias set??"); - return AA.alias(SomePtr->getValue(), SomePtr->getSize(), Ptr, Size); + return AA.alias(AliasAnalysis::Location(SomePtr->getValue(), + SomePtr->getSize(), + SomePtr->getTBAAInfo()), + AliasAnalysis::Location(Ptr, Size, TBAAInfo)); } // If this is a may-alias set, we have to check all of the pointers in the set // to be sure it doesn't alias the set... for (iterator I = begin(), E = end(); I != E; ++I) - if (AA.alias(Ptr, Size, I.getPointer(), I.getSize())) + if (AA.alias(AliasAnalysis::Location(Ptr, Size, TBAAInfo), + AliasAnalysis::Location(I.getPointer(), I.getSize(), + I.getTBAAInfo()))) return true; // Check the call sites list and invoke list... if (!CallSites.empty()) { for (unsigned i = 0, e = CallSites.size(); i != e; ++i) - if (AA.getModRefInfo(CallSites[i], Ptr, Size) != AliasAnalysis::NoModRef) + if (AA.getModRefInfo(CallSites[i], + AliasAnalysis::Location(Ptr, Size, TBAAInfo)) != + AliasAnalysis::NoModRef) return true; } @@ -198,10 +215,11 @@ void AliasSetTracker::clear() { /// that may alias the pointer, merge them together and return the unified set. /// AliasSet *AliasSetTracker::findAliasSetForPointer(const Value *Ptr, - unsigned Size) { + uint64_t Size, + const MDNode *TBAAInfo) { AliasSet *FoundSet = 0; for (iterator I = begin(), E = end(); I != E; ++I) { - if (I->Forward || !I->aliasesPointer(Ptr, Size, AA)) continue; + if (I->Forward || !I->aliasesPointer(Ptr, Size, TBAAInfo, AA)) continue; if (FoundSet == 0) { // If this is the first alias set ptr can go into. FoundSet = I; // Remember it. @@ -216,9 +234,10 @@ AliasSet *AliasSetTracker::findAliasSetForPointer(const Value *Ptr, /// containsPointer - Return true if the specified location is represented by /// this alias set, false otherwise. This does not modify the AST object or /// alias sets. -bool AliasSetTracker::containsPointer(Value *Ptr, unsigned Size) const { +bool AliasSetTracker::containsPointer(Value *Ptr, uint64_t Size, + const MDNode *TBAAInfo) const { for (const_iterator I = begin(), E = end(); I != E; ++I) - if (!I->Forward && I->aliasesPointer(Ptr, Size, AA)) + if (!I->Forward && I->aliasesPointer(Ptr, Size, TBAAInfo, AA)) return true; return false; } @@ -244,33 +263,34 @@ AliasSet *AliasSetTracker::findAliasSetForCallSite(CallSite CS) { /// getAliasSetForPointer - Return the alias set that the specified pointer /// lives in. -AliasSet &AliasSetTracker::getAliasSetForPointer(Value *Pointer, unsigned Size, +AliasSet &AliasSetTracker::getAliasSetForPointer(Value *Pointer, uint64_t Size, + const MDNode *TBAAInfo, bool *New) { AliasSet::PointerRec &Entry = getEntryFor(Pointer); // Check to see if the pointer is already known. if (Entry.hasAliasSet()) { - Entry.updateSize(Size); + Entry.updateSizeAndTBAAInfo(Size, TBAAInfo); // Return the set! return *Entry.getAliasSet(*this)->getForwardedTarget(*this); } - if (AliasSet *AS = findAliasSetForPointer(Pointer, Size)) { + if (AliasSet *AS = findAliasSetForPointer(Pointer, Size, TBAAInfo)) { // Add it to the alias set it aliases. - AS->addPointer(*this, Entry, Size); + AS->addPointer(*this, Entry, Size, TBAAInfo); return *AS; } if (New) *New = true; // Otherwise create a new alias set to hold the loaded pointer. AliasSets.push_back(new AliasSet()); - AliasSets.back().addPointer(*this, Entry, Size); + AliasSets.back().addPointer(*this, Entry, Size, TBAAInfo); return AliasSets.back(); } -bool AliasSetTracker::add(Value *Ptr, unsigned Size) { +bool AliasSetTracker::add(Value *Ptr, uint64_t Size, const MDNode *TBAAInfo) { bool NewPtr; - addPointer(Ptr, Size, AliasSet::NoModRef, NewPtr); + addPointer(Ptr, Size, TBAAInfo, AliasSet::NoModRef, NewPtr); return NewPtr; } @@ -279,6 +299,7 @@ bool AliasSetTracker::add(LoadInst *LI) { bool NewPtr; AliasSet &AS = addPointer(LI->getOperand(0), AA.getTypeStoreSize(LI->getType()), + LI->getMetadata(LLVMContext::MD_tbaa), AliasSet::Refs, NewPtr); if (LI->isVolatile()) AS.setVolatile(); return NewPtr; @@ -289,6 +310,7 @@ bool AliasSetTracker::add(StoreInst *SI) { Value *Val = SI->getOperand(0); AliasSet &AS = addPointer(SI->getOperand(1), AA.getTypeStoreSize(Val->getType()), + SI->getMetadata(LLVMContext::MD_tbaa), AliasSet::Mods, NewPtr); if (SI->isVolatile()) AS.setVolatile(); return NewPtr; @@ -296,7 +318,9 @@ bool AliasSetTracker::add(StoreInst *SI) { bool AliasSetTracker::add(VAArgInst *VAAI) { bool NewPtr; - addPointer(VAAI->getOperand(0), ~0, AliasSet::ModRef, NewPtr); + addPointer(VAAI->getOperand(0), AliasAnalysis::UnknownSize, + VAAI->getMetadata(LLVMContext::MD_tbaa), + AliasSet::ModRef, NewPtr); return NewPtr; } @@ -358,6 +382,7 @@ void AliasSetTracker::add(const AliasSetTracker &AST) { bool X; for (AliasSet::iterator ASI = AS.begin(), E = AS.end(); ASI != E; ++ASI) { AliasSet &NewAS = addPointer(ASI.getPointer(), ASI.getSize(), + ASI.getTBAAInfo(), (AliasSet::AccessType)AS.AccessTy, X); if (AS.isVolatile()) NewAS.setVolatile(); } @@ -393,31 +418,36 @@ void AliasSetTracker::remove(AliasSet &AS) { AS.removeFromTracker(*this); } -bool AliasSetTracker::remove(Value *Ptr, unsigned Size) { - AliasSet *AS = findAliasSetForPointer(Ptr, Size); +bool +AliasSetTracker::remove(Value *Ptr, uint64_t Size, const MDNode *TBAAInfo) { + AliasSet *AS = findAliasSetForPointer(Ptr, Size, TBAAInfo); if (!AS) return false; remove(*AS); return true; } bool AliasSetTracker::remove(LoadInst *LI) { - unsigned Size = AA.getTypeStoreSize(LI->getType()); - AliasSet *AS = findAliasSetForPointer(LI->getOperand(0), Size); + uint64_t Size = AA.getTypeStoreSize(LI->getType()); + const MDNode *TBAAInfo = LI->getMetadata(LLVMContext::MD_tbaa); + AliasSet *AS = findAliasSetForPointer(LI->getOperand(0), Size, TBAAInfo); if (!AS) return false; remove(*AS); return true; } bool AliasSetTracker::remove(StoreInst *SI) { - unsigned Size = AA.getTypeStoreSize(SI->getOperand(0)->getType()); - AliasSet *AS = findAliasSetForPointer(SI->getOperand(1), Size); + uint64_t Size = AA.getTypeStoreSize(SI->getOperand(0)->getType()); + const MDNode *TBAAInfo = SI->getMetadata(LLVMContext::MD_tbaa); + AliasSet *AS = findAliasSetForPointer(SI->getOperand(1), Size, TBAAInfo); if (!AS) return false; remove(*AS); return true; } bool AliasSetTracker::remove(VAArgInst *VAAI) { - AliasSet *AS = findAliasSetForPointer(VAAI->getOperand(0), ~0); + AliasSet *AS = findAliasSetForPointer(VAAI->getOperand(0), + AliasAnalysis::UnknownSize, + VAAI->getMetadata(LLVMContext::MD_tbaa)); if (!AS) return false; remove(*AS); return true; @@ -507,7 +537,9 @@ void AliasSetTracker::copyValue(Value *From, Value *To) { // Add it to the alias set it aliases... I = PointerMap.find(From); AliasSet *AS = I->second->getAliasSet(*this); - AS->addPointer(*this, Entry, I->second->getSize(), true); + AS->addPointer(*this, Entry, I->second->getSize(), + I->second->getTBAAInfo(), + true); } @@ -587,7 +619,9 @@ namespace { AliasSetTracker *Tracker; public: static char ID; // Pass identification, replacement for typeid - AliasSetPrinter() : FunctionPass(ID) {} + AliasSetPrinter() : FunctionPass(ID) { + initializeAliasSetPrinterPass(*PassRegistry::getPassRegistry()); + } virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); @@ -607,5 +641,8 @@ namespace { } char AliasSetPrinter::ID = 0; -INITIALIZE_PASS(AliasSetPrinter, "print-alias-sets", - "Alias Set Printer", false, true); +INITIALIZE_PASS_BEGIN(AliasSetPrinter, "print-alias-sets", + "Alias Set Printer", false, true) +INITIALIZE_AG_DEPENDENCY(AliasAnalysis) +INITIALIZE_PASS_END(AliasSetPrinter, "print-alias-sets", + "Alias Set Printer", false, true) diff --git a/lib/Analysis/Analysis.cpp b/lib/Analysis/Analysis.cpp index 398dec7dd0a1..1af1c35f5392 100644 --- a/lib/Analysis/Analysis.cpp +++ b/lib/Analysis/Analysis.cpp @@ -8,22 +8,83 @@ //===----------------------------------------------------------------------===// #include "llvm-c/Analysis.h" +#include "llvm/InitializePasses.h" #include "llvm/Analysis/Verifier.h" #include using namespace llvm; +/// initializeAnalysis - Initialize all passes linked into the Analysis library. +void llvm::initializeAnalysis(PassRegistry &Registry) { + initializeAliasAnalysisAnalysisGroup(Registry); + initializeAliasAnalysisCounterPass(Registry); + initializeAAEvalPass(Registry); + initializeAliasDebuggerPass(Registry); + initializeAliasSetPrinterPass(Registry); + initializeNoAAPass(Registry); + initializeBasicAliasAnalysisPass(Registry); + initializeCFGViewerPass(Registry); + initializeCFGPrinterPass(Registry); + initializeCFGOnlyViewerPass(Registry); + initializeCFGOnlyPrinterPass(Registry); + initializePrintDbgInfoPass(Registry); + initializeDominanceFrontierPass(Registry); + initializeDomViewerPass(Registry); + initializeDomPrinterPass(Registry); + initializeDomOnlyViewerPass(Registry); + initializePostDomViewerPass(Registry); + initializeDomOnlyPrinterPass(Registry); + initializePostDomPrinterPass(Registry); + initializePostDomOnlyViewerPass(Registry); + initializePostDomOnlyPrinterPass(Registry); + initializeIVUsersPass(Registry); + initializeInstCountPass(Registry); + initializeIntervalPartitionPass(Registry); + initializeLazyValueInfoPass(Registry); + initializeLibCallAliasAnalysisPass(Registry); + initializeLintPass(Registry); + initializeLiveValuesPass(Registry); + initializeLoopDependenceAnalysisPass(Registry); + initializeLoopInfoPass(Registry); + initializeMemDepPrinterPass(Registry); + initializeMemoryDependenceAnalysisPass(Registry); + initializeModuleDebugInfoPrinterPass(Registry); + initializePostDominatorTreePass(Registry); + initializePostDominanceFrontierPass(Registry); + initializeProfileEstimatorPassPass(Registry); + initializeNoProfileInfoPass(Registry); + initializeNoPathProfileInfoPass(Registry); + initializeProfileInfoAnalysisGroup(Registry); + initializePathProfileInfoAnalysisGroup(Registry); + initializeLoaderPassPass(Registry); + initializePathProfileLoaderPassPass(Registry); + initializeProfileVerifierPassPass(Registry); + initializePathProfileVerifierPass(Registry); + initializeRegionInfoPass(Registry); + initializeRegionViewerPass(Registry); + initializeRegionPrinterPass(Registry); + initializeRegionOnlyViewerPass(Registry); + initializeRegionOnlyPrinterPass(Registry); + initializeScalarEvolutionPass(Registry); + initializeScalarEvolutionAliasAnalysisPass(Registry); + initializeTypeBasedAliasAnalysisPass(Registry); +} + +void LLVMInitializeAnalysis(LLVMPassRegistryRef R) { + initializeAnalysis(*unwrap(R)); +} + LLVMBool LLVMVerifyModule(LLVMModuleRef M, LLVMVerifierFailureAction Action, char **OutMessages) { std::string Messages; - + LLVMBool Result = verifyModule(*unwrap(M), static_cast(Action), OutMessages? &Messages : 0); - + if (OutMessages) *OutMessages = strdup(Messages.c_str()); - + return Result; } diff --git a/lib/Analysis/BasicAliasAnalysis.cpp b/lib/Analysis/BasicAliasAnalysis.cpp index 113c72b94dac..f7bcd9ec44d8 100644 --- a/lib/Analysis/BasicAliasAnalysis.cpp +++ b/lib/Analysis/BasicAliasAnalysis.cpp @@ -1,4 +1,4 @@ -//===- BasicAliasAnalysis.cpp - Local Alias Analysis Impl -----------------===// +//===- BasicAliasAnalysis.cpp - Stateless Alias Analysis Impl -------------===// // // The LLVM Compiler Infrastructure // @@ -7,9 +7,9 @@ // //===----------------------------------------------------------------------===// // -// This file defines the default implementation of the Alias Analysis interface -// that simply implements a few identities (two different globals cannot alias, -// etc), but otherwise does no analysis. +// This file defines the primary stateless implementation of the +// Alias Analysis interface that implements identities (two different +// globals cannot alias, etc), but does no stateful analysis. // //===----------------------------------------------------------------------===// @@ -22,10 +22,12 @@ #include "llvm/GlobalVariable.h" #include "llvm/Instructions.h" #include "llvm/IntrinsicInst.h" +#include "llvm/LLVMContext.h" #include "llvm/Operator.h" #include "llvm/Pass.h" #include "llvm/Analysis/CaptureTracking.h" #include "llvm/Analysis/MemoryBuiltins.h" +#include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/Target/TargetData.h" #include "llvm/ADT/SmallPtrSet.h" @@ -95,104 +97,54 @@ static bool isEscapeSource(const Value *V) { return false; } -/// isObjectSmallerThan - Return true if we can prove that the object specified -/// by V is smaller than Size. -static bool isObjectSmallerThan(const Value *V, unsigned Size, - const TargetData &TD) { +/// getObjectSize - Return the size of the object specified by V, or +/// UnknownSize if unknown. +static uint64_t getObjectSize(const Value *V, const TargetData &TD) { const Type *AccessTy; if (const GlobalVariable *GV = dyn_cast(V)) { + if (!GV->hasDefinitiveInitializer()) + return AliasAnalysis::UnknownSize; AccessTy = GV->getType()->getElementType(); } else if (const AllocaInst *AI = dyn_cast(V)) { if (!AI->isArrayAllocation()) AccessTy = AI->getType()->getElementType(); else - return false; + return AliasAnalysis::UnknownSize; } else if (const CallInst* CI = extractMallocCall(V)) { if (!isArrayMalloc(V, &TD)) // The size is the argument to the malloc call. if (const ConstantInt* C = dyn_cast(CI->getArgOperand(0))) - return (C->getZExtValue() < Size); - return false; + return C->getZExtValue(); + return AliasAnalysis::UnknownSize; } else if (const Argument *A = dyn_cast(V)) { if (A->hasByValAttr()) AccessTy = cast(A->getType())->getElementType(); else - return false; + return AliasAnalysis::UnknownSize; } else { - return false; + return AliasAnalysis::UnknownSize; } if (AccessTy->isSized()) - return TD.getTypeAllocSize(AccessTy) < Size; - return false; + return TD.getTypeAllocSize(AccessTy); + return AliasAnalysis::UnknownSize; } -//===----------------------------------------------------------------------===// -// NoAA Pass -//===----------------------------------------------------------------------===// - -namespace { - /// NoAA - This class implements the -no-aa pass, which always returns "I - /// don't know" for alias queries. NoAA is unlike other alias analysis - /// implementations, in that it does not chain to a previous analysis. As - /// such it doesn't follow many of the rules that other alias analyses must. - /// - struct NoAA : public ImmutablePass, public AliasAnalysis { - static char ID; // Class identification, replacement for typeinfo - NoAA() : ImmutablePass(ID) {} - explicit NoAA(char &PID) : ImmutablePass(PID) { } - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - } - - virtual void initializePass() { - TD = getAnalysisIfAvailable(); - } - - virtual AliasResult alias(const Value *V1, unsigned V1Size, - const Value *V2, unsigned V2Size) { - return MayAlias; - } - - virtual ModRefBehavior getModRefBehavior(ImmutableCallSite CS) { - return UnknownModRefBehavior; - } - virtual ModRefBehavior getModRefBehavior(const Function *F) { - return UnknownModRefBehavior; - } - - virtual bool pointsToConstantMemory(const Value *P) { return false; } - virtual ModRefResult getModRefInfo(ImmutableCallSite CS, - const Value *P, unsigned Size) { - return ModRef; - } - virtual ModRefResult getModRefInfo(ImmutableCallSite CS1, - ImmutableCallSite CS2) { - return ModRef; - } - - virtual void deleteValue(Value *V) {} - virtual void copyValue(Value *From, Value *To) {} - - /// getAdjustedAnalysisPointer - This method is used when a pass implements - /// an analysis interface through multiple inheritance. If needed, it - /// should override this to adjust the this pointer as needed for the - /// specified pass info. - virtual void *getAdjustedAnalysisPointer(const void *ID) { - if (ID == &AliasAnalysis::ID) - return (AliasAnalysis*)this; - return this; - } - }; -} // End of anonymous namespace - -// Register this pass... -char NoAA::ID = 0; -INITIALIZE_AG_PASS(NoAA, AliasAnalysis, "no-aa", - "No Alias Analysis (always returns 'may' alias)", - true, true, false); +/// isObjectSmallerThan - Return true if we can prove that the object specified +/// by V is smaller than Size. +static bool isObjectSmallerThan(const Value *V, uint64_t Size, + const TargetData &TD) { + uint64_t ObjectSize = getObjectSize(V, TD); + return ObjectSize != AliasAnalysis::UnknownSize && ObjectSize < Size; +} -ImmutablePass *llvm::createNoAAPass() { return new NoAA(); } +/// isObjectSize - Return true if we can prove that the object specified +/// by V has size Size. +static bool isObjectSize(const Value *V, uint64_t Size, + const TargetData &TD) { + uint64_t ObjectSize = getObjectSize(V, TD); + return ObjectSize != AliasAnalysis::UnknownSize && ObjectSize == Size; +} //===----------------------------------------------------------------------===// // GetElementPtr Instruction Decomposition and Analysis @@ -272,14 +224,14 @@ static Value *GetLinearExpression(Value *V, APInt &Scale, APInt &Offset, Value *CastOp = cast(V)->getOperand(0); unsigned OldWidth = Scale.getBitWidth(); unsigned SmallWidth = CastOp->getType()->getPrimitiveSizeInBits(); - Scale.trunc(SmallWidth); - Offset.trunc(SmallWidth); + Scale = Scale.trunc(SmallWidth); + Offset = Offset.trunc(SmallWidth); Extension = isa(V) ? EK_SignExt : EK_ZeroExt; Value *Result = GetLinearExpression(CastOp, Scale, Offset, Extension, TD, Depth+1); - Scale.zext(OldWidth); - Offset.zext(OldWidth); + Scale = Scale.zext(OldWidth); + Offset = Offset.zext(OldWidth); return Result; } @@ -299,7 +251,7 @@ static Value *GetLinearExpression(Value *V, APInt &Scale, APInt &Offset, /// the gep cannot necessarily be reconstructed from its decomposed form. /// /// When TargetData is around, this function is capable of analyzing everything -/// that Value::getUnderlyingObject() can look through. When not, it just looks +/// that GetUnderlyingObject can look through. When not, it just looks /// through pointer casts. /// static const Value * @@ -328,6 +280,14 @@ DecomposeGEPExpression(const Value *V, int64_t &BaseOffs, V = Op->getOperand(0); continue; } + + if (const Instruction *I = dyn_cast(V)) + // TODO: Get a DominatorTree and use it here. + if (const Value *Simplified = + SimplifyInstruction(const_cast(I), TD)) { + V = Simplified; + continue; + } const GEPOperator *GEPOp = dyn_cast(Op); if (GEPOp == 0) @@ -386,8 +346,8 @@ DecomposeGEPExpression(const Value *V, int64_t &BaseOffs, // The GEP index scale ("Scale") scales C1*V+C2, yielding (C1*V+C2)*Scale. // This gives us an aggregate computation of (C1*Scale)*V + C2*Scale. - BaseOffs += IndexOffset.getZExtValue()*Scale; - Scale *= IndexScale.getZExtValue(); + BaseOffs += IndexOffset.getSExtValue()*Scale; + Scale *= IndexScale.getSExtValue(); // If we already had an occurrance of this index variable, merge this @@ -407,7 +367,7 @@ DecomposeGEPExpression(const Value *V, int64_t &BaseOffs, // pointer size. if (unsigned ShiftBits = 64-TD->getPointerSizeInBits()) { Scale <<= ShiftBits; - Scale >>= ShiftBits; + Scale = (int64_t)Scale >> ShiftBits; } if (Scale) { @@ -485,25 +445,34 @@ static bool notDifferentParent(const Value *O1, const Value *O2) { #endif namespace { - /// BasicAliasAnalysis - This is the default alias analysis implementation. - /// Because it doesn't chain to a previous alias analysis (like -no-aa), it - /// derives from the NoAA class. - struct BasicAliasAnalysis : public NoAA { + /// BasicAliasAnalysis - This is the primary alias analysis implementation. + struct BasicAliasAnalysis : public ImmutablePass, public AliasAnalysis { static char ID; // Class identification, replacement for typeinfo - BasicAliasAnalysis() : NoAA(ID) {} + BasicAliasAnalysis() : ImmutablePass(ID) { + initializeBasicAliasAnalysisPass(*PassRegistry::getPassRegistry()); + } + + virtual void initializePass() { + InitializeAliasAnalysis(this); + } + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired(); + } - virtual AliasResult alias(const Value *V1, unsigned V1Size, - const Value *V2, unsigned V2Size) { + virtual AliasResult alias(const Location &LocA, + const Location &LocB) { assert(Visited.empty() && "Visited must be cleared after use!"); - assert(notDifferentParent(V1, V2) && + assert(notDifferentParent(LocA.Ptr, LocB.Ptr) && "BasicAliasAnalysis doesn't support interprocedural queries."); - AliasResult Alias = aliasCheck(V1, V1Size, V2, V2Size); + AliasResult Alias = aliasCheck(LocA.Ptr, LocA.Size, LocA.TBAATag, + LocB.Ptr, LocB.Size, LocB.TBAATag); Visited.clear(); return Alias; } virtual ModRefResult getModRefInfo(ImmutableCallSite CS, - const Value *P, unsigned Size); + const Location &Loc); virtual ModRefResult getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2) { @@ -513,7 +482,7 @@ namespace { /// pointsToConstantMemory - Chase pointers until we find a (constant /// global) or not. - virtual bool pointsToConstantMemory(const Value *P); + virtual bool pointsToConstantMemory(const Location &Loc, bool OrLocal); /// getModRefBehavior - Return the behavior when calling the given /// call site. @@ -539,46 +508,102 @@ namespace { // aliasGEP - Provide a bunch of ad-hoc rules to disambiguate a GEP // instruction against another. - AliasResult aliasGEP(const GEPOperator *V1, unsigned V1Size, - const Value *V2, unsigned V2Size, + AliasResult aliasGEP(const GEPOperator *V1, uint64_t V1Size, + const Value *V2, uint64_t V2Size, + const MDNode *V2TBAAInfo, const Value *UnderlyingV1, const Value *UnderlyingV2); // aliasPHI - Provide a bunch of ad-hoc rules to disambiguate a PHI // instruction against another. - AliasResult aliasPHI(const PHINode *PN, unsigned PNSize, - const Value *V2, unsigned V2Size); + AliasResult aliasPHI(const PHINode *PN, uint64_t PNSize, + const MDNode *PNTBAAInfo, + const Value *V2, uint64_t V2Size, + const MDNode *V2TBAAInfo); /// aliasSelect - Disambiguate a Select instruction against another value. - AliasResult aliasSelect(const SelectInst *SI, unsigned SISize, - const Value *V2, unsigned V2Size); - - AliasResult aliasCheck(const Value *V1, unsigned V1Size, - const Value *V2, unsigned V2Size); + AliasResult aliasSelect(const SelectInst *SI, uint64_t SISize, + const MDNode *SITBAAInfo, + const Value *V2, uint64_t V2Size, + const MDNode *V2TBAAInfo); + + AliasResult aliasCheck(const Value *V1, uint64_t V1Size, + const MDNode *V1TBAATag, + const Value *V2, uint64_t V2Size, + const MDNode *V2TBAATag); }; } // End of anonymous namespace // Register this pass... char BasicAliasAnalysis::ID = 0; INITIALIZE_AG_PASS(BasicAliasAnalysis, AliasAnalysis, "basicaa", - "Basic Alias Analysis (default AA impl)", - false, true, true); + "Basic Alias Analysis (stateless AA impl)", + false, true, false) ImmutablePass *llvm::createBasicAliasAnalysisPass() { return new BasicAliasAnalysis(); } +/// pointsToConstantMemory - Returns whether the given pointer value +/// points to memory that is local to the function, with global constants being +/// considered local to all functions. +bool +BasicAliasAnalysis::pointsToConstantMemory(const Location &Loc, bool OrLocal) { + assert(Visited.empty() && "Visited must be cleared after use!"); + + unsigned MaxLookup = 8; + SmallVector Worklist; + Worklist.push_back(Loc.Ptr); + do { + const Value *V = GetUnderlyingObject(Worklist.pop_back_val(), TD); + if (!Visited.insert(V)) { + Visited.clear(); + return AliasAnalysis::pointsToConstantMemory(Loc, OrLocal); + } + + // An alloca instruction defines local memory. + if (OrLocal && isa(V)) + continue; + + // A global constant counts as local memory for our purposes. + if (const GlobalVariable *GV = dyn_cast(V)) { + // Note: this doesn't require GV to be "ODR" because it isn't legal for a + // global to be marked constant in some modules and non-constant in + // others. GV may even be a declaration, not a definition. + if (!GV->isConstant()) { + Visited.clear(); + return AliasAnalysis::pointsToConstantMemory(Loc, OrLocal); + } + continue; + } + + // If both select values point to local memory, then so does the select. + if (const SelectInst *SI = dyn_cast(V)) { + Worklist.push_back(SI->getTrueValue()); + Worklist.push_back(SI->getFalseValue()); + continue; + } + + // If all values incoming to a phi node point to local memory, then so does + // the phi. + if (const PHINode *PN = dyn_cast(V)) { + // Don't bother inspecting phi nodes with many operands. + if (PN->getNumIncomingValues() > MaxLookup) { + Visited.clear(); + return AliasAnalysis::pointsToConstantMemory(Loc, OrLocal); + } + for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) + Worklist.push_back(PN->getIncomingValue(i)); + continue; + } -/// pointsToConstantMemory - Chase pointers until we find a (constant -/// global) or not. -bool BasicAliasAnalysis::pointsToConstantMemory(const Value *P) { - if (const GlobalVariable *GV = - dyn_cast(P->getUnderlyingObject())) - // Note: this doesn't require GV to be "ODR" because it isn't legal for a - // global to be marked constant in some modules and non-constant in others. - // GV may even be a declaration, not a definition. - return GV->isConstant(); + // Otherwise be conservative. + Visited.clear(); + return AliasAnalysis::pointsToConstantMemory(Loc, OrLocal); - return NoAA::pointsToConstantMemory(P); + } while (!Worklist.empty() && --MaxLookup); + + Visited.clear(); + return Worklist.empty(); } /// getModRefBehavior - Return the behavior when calling the given call site. @@ -596,22 +621,32 @@ BasicAliasAnalysis::getModRefBehavior(ImmutableCallSite CS) { Min = OnlyReadsMemory; // The AliasAnalysis base class has some smarts, lets use them. - return std::min(AliasAnalysis::getModRefBehavior(CS), Min); + return ModRefBehavior(AliasAnalysis::getModRefBehavior(CS) & Min); } /// getModRefBehavior - Return the behavior when calling the given function. /// For use when the call site is not known. AliasAnalysis::ModRefBehavior BasicAliasAnalysis::getModRefBehavior(const Function *F) { + // If the function declares it doesn't access memory, we can't do better. if (F->doesNotAccessMemory()) - // Can't do better than this. return DoesNotAccessMemory; + + // For intrinsics, we can check the table. + if (unsigned iid = F->getIntrinsicID()) { +#define GET_INTRINSIC_MODREF_BEHAVIOR +#include "llvm/Intrinsics.gen" +#undef GET_INTRINSIC_MODREF_BEHAVIOR + } + + ModRefBehavior Min = UnknownModRefBehavior; + + // If the function declares it only reads memory, go with that. if (F->onlyReadsMemory()) - return OnlyReadsMemory; - if (unsigned id = F->getIntrinsicID()) - return getIntrinsicModRefBehavior(id); + Min = OnlyReadsMemory; - return NoAA::getModRefBehavior(F); + // Otherwise be conservative. + return ModRefBehavior(AliasAnalysis::getModRefBehavior(F) & Min); } /// getModRefInfo - Check to see if the specified callsite can clobber the @@ -620,13 +655,13 @@ BasicAliasAnalysis::getModRefBehavior(const Function *F) { /// simple "address taken" analysis on local objects. AliasAnalysis::ModRefResult BasicAliasAnalysis::getModRefInfo(ImmutableCallSite CS, - const Value *P, unsigned Size) { - assert(notDifferentParent(CS.getInstruction(), P) && + const Location &Loc) { + assert(notDifferentParent(CS.getInstruction(), Loc.Ptr) && "AliasAnalysis query involving multiple functions!"); - const Value *Object = P->getUnderlyingObject(); + const Value *Object = GetUnderlyingObject(Loc.Ptr, TD); - // If this is a tail call and P points to a stack location, we know that + // If this is a tail call and Loc.Ptr points to a stack location, we know that // the tail call cannot access or modify the local stack. // We cannot exclude byval arguments here; these belong to the caller of // the current function not to the current function, and a tail callee @@ -650,11 +685,11 @@ BasicAliasAnalysis::getModRefInfo(ImmutableCallSite CS, !CS.paramHasAttr(ArgNo+1, Attribute::NoCapture)) continue; - // If this is a no-capture pointer argument, see if we can tell that it + // If this is a no-capture pointer argument, see if we can tell that it // is impossible to alias the pointer we're checking. If not, we have to // assume that the call could touch the pointer, even though it doesn't // escape. - if (!isNoAlias(cast(CI), UnknownSize, P, UnknownSize)) { + if (!isNoAlias(Location(cast(CI)), Loc)) { PassedAsArg = true; break; } @@ -664,6 +699,8 @@ BasicAliasAnalysis::getModRefInfo(ImmutableCallSite CS, return NoModRef; } + ModRefResult Min = ModRef; + // Finally, handle specific knowledge of intrinsics. const IntrinsicInst *II = dyn_cast(CS.getInstruction()); if (II != 0) @@ -671,15 +708,20 @@ BasicAliasAnalysis::getModRefInfo(ImmutableCallSite CS, default: break; case Intrinsic::memcpy: case Intrinsic::memmove: { - unsigned Len = UnknownSize; + uint64_t Len = UnknownSize; if (ConstantInt *LenCI = dyn_cast(II->getArgOperand(2))) Len = LenCI->getZExtValue(); Value *Dest = II->getArgOperand(0); Value *Src = II->getArgOperand(1); - if (isNoAlias(Dest, Len, P, Size)) { - if (isNoAlias(Src, Len, P, Size)) + // If it can't overlap the source dest, then it doesn't modref the loc. + if (isNoAlias(Location(Dest, Len), Loc)) { + if (isNoAlias(Location(Src, Len), Loc)) return NoModRef; - return Ref; + // If it can't overlap the dest, then worst case it reads the loc. + Min = Ref; + } else if (isNoAlias(Location(Src, Len), Loc)) { + // If it can't overlap the source, then worst case it mutates the loc. + Min = Mod; } break; } @@ -687,11 +729,13 @@ BasicAliasAnalysis::getModRefInfo(ImmutableCallSite CS, // Since memset is 'accesses arguments' only, the AliasAnalysis base class // will handle it for the variable length case. if (ConstantInt *LenCI = dyn_cast(II->getArgOperand(2))) { - unsigned Len = LenCI->getZExtValue(); + uint64_t Len = LenCI->getZExtValue(); Value *Dest = II->getArgOperand(0); - if (isNoAlias(Dest, Len, P, Size)) + if (isNoAlias(Location(Dest, Len), Loc)) return NoModRef; } + // We know that memset doesn't load anything. + Min = Mod; break; case Intrinsic::atomic_cmp_swap: case Intrinsic::atomic_swap: @@ -707,42 +751,49 @@ BasicAliasAnalysis::getModRefInfo(ImmutableCallSite CS, case Intrinsic::atomic_load_umin: if (TD) { Value *Op1 = II->getArgOperand(0); - unsigned Op1Size = TD->getTypeStoreSize(Op1->getType()); - if (isNoAlias(Op1, Op1Size, P, Size)) + uint64_t Op1Size = TD->getTypeStoreSize(Op1->getType()); + MDNode *Tag = II->getMetadata(LLVMContext::MD_tbaa); + if (isNoAlias(Location(Op1, Op1Size, Tag), Loc)) return NoModRef; } break; case Intrinsic::lifetime_start: case Intrinsic::lifetime_end: case Intrinsic::invariant_start: { - unsigned PtrSize = + uint64_t PtrSize = cast(II->getArgOperand(0))->getZExtValue(); - if (isNoAlias(II->getArgOperand(1), PtrSize, P, Size)) + if (isNoAlias(Location(II->getArgOperand(1), + PtrSize, + II->getMetadata(LLVMContext::MD_tbaa)), + Loc)) return NoModRef; break; } case Intrinsic::invariant_end: { - unsigned PtrSize = + uint64_t PtrSize = cast(II->getArgOperand(1))->getZExtValue(); - if (isNoAlias(II->getArgOperand(2), PtrSize, P, Size)) + if (isNoAlias(Location(II->getArgOperand(2), + PtrSize, + II->getMetadata(LLVMContext::MD_tbaa)), + Loc)) return NoModRef; break; } } // The AliasAnalysis base class has some smarts, lets use them. - return AliasAnalysis::getModRefInfo(CS, P, Size); + return ModRefResult(AliasAnalysis::getModRefInfo(CS, Loc) & Min); } - /// aliasGEP - Provide a bunch of ad-hoc rules to disambiguate a GEP instruction /// against another pointer. We know that V1 is a GEP, but we don't know -/// anything about V2. UnderlyingV1 is GEP1->getUnderlyingObject(), +/// anything about V2. UnderlyingV1 is GetUnderlyingObject(GEP1, TD), /// UnderlyingV2 is the same for V2. /// AliasAnalysis::AliasResult -BasicAliasAnalysis::aliasGEP(const GEPOperator *GEP1, unsigned V1Size, - const Value *V2, unsigned V2Size, +BasicAliasAnalysis::aliasGEP(const GEPOperator *GEP1, uint64_t V1Size, + const Value *V2, uint64_t V2Size, + const MDNode *V2TBAAInfo, const Value *UnderlyingV1, const Value *UnderlyingV2) { // If this GEP has been visited before, we're on a use-def cycle. @@ -759,8 +810,8 @@ BasicAliasAnalysis::aliasGEP(const GEPOperator *GEP1, unsigned V1Size, // out if the indexes to the GEP tell us anything about the derived pointer. if (const GEPOperator *GEP2 = dyn_cast(V2)) { // Do the base pointers alias? - AliasResult BaseAlias = aliasCheck(UnderlyingV1, UnknownSize, - UnderlyingV2, UnknownSize); + AliasResult BaseAlias = aliasCheck(UnderlyingV1, UnknownSize, 0, + UnderlyingV2, UnknownSize, 0); // If we get a No or May, then return it immediately, no amount of analysis // will improve this situation. @@ -782,7 +833,7 @@ BasicAliasAnalysis::aliasGEP(const GEPOperator *GEP1, unsigned V1Size, // to handle without it. if (GEP1BasePtr != UnderlyingV1 || GEP2BasePtr != UnderlyingV2) { assert(TD == 0 && - "DecomposeGEPExpression and getUnderlyingObject disagree!"); + "DecomposeGEPExpression and GetUnderlyingObject disagree!"); return MayAlias; } @@ -800,7 +851,8 @@ BasicAliasAnalysis::aliasGEP(const GEPOperator *GEP1, unsigned V1Size, if (V1Size == UnknownSize && V2Size == UnknownSize) return MayAlias; - AliasResult R = aliasCheck(UnderlyingV1, UnknownSize, V2, V2Size); + AliasResult R = aliasCheck(UnderlyingV1, UnknownSize, 0, + V2, V2Size, V2TBAAInfo); if (R != MustAlias) // If V2 may alias GEP base pointer, conservatively returns MayAlias. // If V2 is known not to alias GEP base pointer, then the two values @@ -817,7 +869,7 @@ BasicAliasAnalysis::aliasGEP(const GEPOperator *GEP1, unsigned V1Size, // to handle without it. if (GEP1BasePtr != UnderlyingV1) { assert(TD == 0 && - "DecomposeGEPExpression and getUnderlyingObject disagree!"); + "DecomposeGEPExpression and GetUnderlyingObject disagree!"); return MayAlias; } } @@ -831,6 +883,17 @@ BasicAliasAnalysis::aliasGEP(const GEPOperator *GEP1, unsigned V1Size, if (GEP1BaseOffset == 0 && GEP1VariableIndices.empty()) return MustAlias; + // If there is a difference betwen the pointers, but the difference is + // less than the size of the associated memory object, then we know + // that the objects are partially overlapping. + if (GEP1BaseOffset != 0 && GEP1VariableIndices.empty()) { + if (GEP1BaseOffset >= 0 ? + (V2Size != UnknownSize && (uint64_t)GEP1BaseOffset < V2Size) : + (V1Size != UnknownSize && -(uint64_t)GEP1BaseOffset < V1Size && + GEP1BaseOffset != INT64_MIN)) + return PartialAlias; + } + // If we have a known constant offset, see if this offset is larger than the // access size being queried. If so, and if no variable indices can remove // pieces of this constant, then we know we have a no-alias. For example, @@ -850,8 +913,10 @@ BasicAliasAnalysis::aliasGEP(const GEPOperator *GEP1, unsigned V1Size, // If our known offset is bigger than the access size, we know we don't have // an alias. if (GEP1BaseOffset) { - if (GEP1BaseOffset >= (int64_t)V2Size || - GEP1BaseOffset <= -(int64_t)V1Size) + if (GEP1BaseOffset >= 0 ? + (V2Size != UnknownSize && (uint64_t)GEP1BaseOffset >= V2Size) : + (V1Size != UnknownSize && -(uint64_t)GEP1BaseOffset >= V1Size && + GEP1BaseOffset != INT64_MIN)) return NoAlias; } @@ -861,8 +926,10 @@ BasicAliasAnalysis::aliasGEP(const GEPOperator *GEP1, unsigned V1Size, /// aliasSelect - Provide a bunch of ad-hoc rules to disambiguate a Select /// instruction against another. AliasAnalysis::AliasResult -BasicAliasAnalysis::aliasSelect(const SelectInst *SI, unsigned SISize, - const Value *V2, unsigned V2Size) { +BasicAliasAnalysis::aliasSelect(const SelectInst *SI, uint64_t SISize, + const MDNode *SITBAAInfo, + const Value *V2, uint64_t V2Size, + const MDNode *V2TBAAInfo) { // If this select has been visited before, we're on a use-def cycle. // Such cycles are only valid when PHI nodes are involved or in unreachable // code. The visitPHI function catches cycles containing PHIs, but there @@ -875,13 +942,13 @@ BasicAliasAnalysis::aliasSelect(const SelectInst *SI, unsigned SISize, if (const SelectInst *SI2 = dyn_cast(V2)) if (SI->getCondition() == SI2->getCondition()) { AliasResult Alias = - aliasCheck(SI->getTrueValue(), SISize, - SI2->getTrueValue(), V2Size); + aliasCheck(SI->getTrueValue(), SISize, SITBAAInfo, + SI2->getTrueValue(), V2Size, V2TBAAInfo); if (Alias == MayAlias) return MayAlias; AliasResult ThisAlias = - aliasCheck(SI->getFalseValue(), SISize, - SI2->getFalseValue(), V2Size); + aliasCheck(SI->getFalseValue(), SISize, SITBAAInfo, + SI2->getFalseValue(), V2Size, V2TBAAInfo); if (ThisAlias != Alias) return MayAlias; return Alias; @@ -890,7 +957,7 @@ BasicAliasAnalysis::aliasSelect(const SelectInst *SI, unsigned SISize, // If both arms of the Select node NoAlias or MustAlias V2, then returns // NoAlias / MustAlias. Otherwise, returns MayAlias. AliasResult Alias = - aliasCheck(V2, V2Size, SI->getTrueValue(), SISize); + aliasCheck(V2, V2Size, V2TBAAInfo, SI->getTrueValue(), SISize, SITBAAInfo); if (Alias == MayAlias) return MayAlias; @@ -900,7 +967,7 @@ BasicAliasAnalysis::aliasSelect(const SelectInst *SI, unsigned SISize, Visited.erase(V2); AliasResult ThisAlias = - aliasCheck(V2, V2Size, SI->getFalseValue(), SISize); + aliasCheck(V2, V2Size, V2TBAAInfo, SI->getFalseValue(), SISize, SITBAAInfo); if (ThisAlias != Alias) return MayAlias; return Alias; @@ -909,8 +976,10 @@ BasicAliasAnalysis::aliasSelect(const SelectInst *SI, unsigned SISize, // aliasPHI - Provide a bunch of ad-hoc rules to disambiguate a PHI instruction // against another. AliasAnalysis::AliasResult -BasicAliasAnalysis::aliasPHI(const PHINode *PN, unsigned PNSize, - const Value *V2, unsigned V2Size) { +BasicAliasAnalysis::aliasPHI(const PHINode *PN, uint64_t PNSize, + const MDNode *PNTBAAInfo, + const Value *V2, uint64_t V2Size, + const MDNode *V2TBAAInfo) { // The PHI node has already been visited, avoid recursion any further. if (!Visited.insert(PN)) return MayAlias; @@ -921,16 +990,16 @@ BasicAliasAnalysis::aliasPHI(const PHINode *PN, unsigned PNSize, if (const PHINode *PN2 = dyn_cast(V2)) if (PN2->getParent() == PN->getParent()) { AliasResult Alias = - aliasCheck(PN->getIncomingValue(0), PNSize, + aliasCheck(PN->getIncomingValue(0), PNSize, PNTBAAInfo, PN2->getIncomingValueForBlock(PN->getIncomingBlock(0)), - V2Size); + V2Size, V2TBAAInfo); if (Alias == MayAlias) return MayAlias; for (unsigned i = 1, e = PN->getNumIncomingValues(); i != e; ++i) { AliasResult ThisAlias = - aliasCheck(PN->getIncomingValue(i), PNSize, + aliasCheck(PN->getIncomingValue(i), PNSize, PNTBAAInfo, PN2->getIncomingValueForBlock(PN->getIncomingBlock(i)), - V2Size); + V2Size, V2TBAAInfo); if (ThisAlias != Alias) return MayAlias; } @@ -951,7 +1020,8 @@ BasicAliasAnalysis::aliasPHI(const PHINode *PN, unsigned PNSize, V1Srcs.push_back(PV1); } - AliasResult Alias = aliasCheck(V2, V2Size, V1Srcs[0], PNSize); + AliasResult Alias = aliasCheck(V2, V2Size, V2TBAAInfo, + V1Srcs[0], PNSize, PNTBAAInfo); // Early exit if the check of the first PHI source against V2 is MayAlias. // Other results are not possible. if (Alias == MayAlias) @@ -967,7 +1037,8 @@ BasicAliasAnalysis::aliasPHI(const PHINode *PN, unsigned PNSize, // don't need to assume that V2 is being visited recursively. Visited.erase(V2); - AliasResult ThisAlias = aliasCheck(V2, V2Size, V, PNSize); + AliasResult ThisAlias = aliasCheck(V2, V2Size, V2TBAAInfo, + V, PNSize, PNTBAAInfo); if (ThisAlias != Alias || ThisAlias == MayAlias) return MayAlias; } @@ -979,8 +1050,10 @@ BasicAliasAnalysis::aliasPHI(const PHINode *PN, unsigned PNSize, // such as array references. // AliasAnalysis::AliasResult -BasicAliasAnalysis::aliasCheck(const Value *V1, unsigned V1Size, - const Value *V2, unsigned V2Size) { +BasicAliasAnalysis::aliasCheck(const Value *V1, uint64_t V1Size, + const MDNode *V1TBAAInfo, + const Value *V2, uint64_t V2Size, + const MDNode *V2TBAAInfo) { // If either of the memory references is empty, it doesn't matter what the // pointer values are. if (V1Size == 0 || V2Size == 0) @@ -997,8 +1070,8 @@ BasicAliasAnalysis::aliasCheck(const Value *V1, unsigned V1Size, return NoAlias; // Scalars cannot alias each other // Figure out what objects these things are pointing to if we can. - const Value *O1 = V1->getUnderlyingObject(); - const Value *O2 = V2->getUnderlyingObject(); + const Value *O1 = GetUnderlyingObject(V1, TD); + const Value *O2 = GetUnderlyingObject(V2, TD); // Null values in the default address space don't point to any object, so they // don't alias any other pointer. @@ -1059,25 +1132,39 @@ BasicAliasAnalysis::aliasCheck(const Value *V1, unsigned V1Size, std::swap(V1Size, V2Size); std::swap(O1, O2); } - if (const GEPOperator *GV1 = dyn_cast(V1)) - return aliasGEP(GV1, V1Size, V2, V2Size, O1, O2); + if (const GEPOperator *GV1 = dyn_cast(V1)) { + AliasResult Result = aliasGEP(GV1, V1Size, V2, V2Size, V2TBAAInfo, O1, O2); + if (Result != MayAlias) return Result; + } if (isa(V2) && !isa(V1)) { std::swap(V1, V2); std::swap(V1Size, V2Size); } - if (const PHINode *PN = dyn_cast(V1)) - return aliasPHI(PN, V1Size, V2, V2Size); + if (const PHINode *PN = dyn_cast(V1)) { + AliasResult Result = aliasPHI(PN, V1Size, V1TBAAInfo, + V2, V2Size, V2TBAAInfo); + if (Result != MayAlias) return Result; + } if (isa(V2) && !isa(V1)) { std::swap(V1, V2); std::swap(V1Size, V2Size); } - if (const SelectInst *S1 = dyn_cast(V1)) - return aliasSelect(S1, V1Size, V2, V2Size); + if (const SelectInst *S1 = dyn_cast(V1)) { + AliasResult Result = aliasSelect(S1, V1Size, V1TBAAInfo, + V2, V2Size, V2TBAAInfo); + if (Result != MayAlias) return Result; + } - return NoAA::alias(V1, V1Size, V2, V2Size); -} + // If both pointers are pointing into the same object and one of them + // accesses is accessing the entire object, then the accesses must + // overlap in some way. + if (TD && O1 == O2) + if ((V1Size != UnknownSize && isObjectSize(O1, V1Size, *TD)) || + (V2Size != UnknownSize && isObjectSize(O2, V2Size, *TD))) + return PartialAlias; -// Make sure that anything that uses AliasAnalysis pulls in this file. -DEFINING_FILE_FOR(BasicAliasAnalysis) + return AliasAnalysis::alias(Location(V1, V1Size, V1TBAAInfo), + Location(V2, V2Size, V2TBAAInfo)); +} diff --git a/lib/Analysis/CFGPrinter.cpp b/lib/Analysis/CFGPrinter.cpp index 617a362062fc..7bb063fbbbcf 100644 --- a/lib/Analysis/CFGPrinter.cpp +++ b/lib/Analysis/CFGPrinter.cpp @@ -25,7 +25,9 @@ using namespace llvm; namespace { struct CFGViewer : public FunctionPass { static char ID; // Pass identifcation, replacement for typeid - CFGViewer() : FunctionPass(ID) {} + CFGViewer() : FunctionPass(ID) { + initializeCFGOnlyViewerPass(*PassRegistry::getPassRegistry()); + } virtual bool runOnFunction(Function &F) { F.viewCFG(); @@ -41,12 +43,14 @@ namespace { } char CFGViewer::ID = 0; -INITIALIZE_PASS(CFGViewer, "view-cfg", "View CFG of function", false, true); +INITIALIZE_PASS(CFGViewer, "view-cfg", "View CFG of function", false, true) namespace { struct CFGOnlyViewer : public FunctionPass { static char ID; // Pass identifcation, replacement for typeid - CFGOnlyViewer() : FunctionPass(ID) {} + CFGOnlyViewer() : FunctionPass(ID) { + initializeCFGOnlyViewerPass(*PassRegistry::getPassRegistry()); + } virtual bool runOnFunction(Function &F) { F.viewCFGOnly(); @@ -63,13 +67,14 @@ namespace { char CFGOnlyViewer::ID = 0; INITIALIZE_PASS(CFGOnlyViewer, "view-cfg-only", - "View CFG of function (with no function bodies)", false, true); + "View CFG of function (with no function bodies)", false, true) namespace { struct CFGPrinter : public FunctionPass { static char ID; // Pass identification, replacement for typeid - CFGPrinter() : FunctionPass(ID) {} - explicit CFGPrinter(char &pid) : FunctionPass(pid) {} + CFGPrinter() : FunctionPass(ID) { + initializeCFGPrinterPass(*PassRegistry::getPassRegistry()); + } virtual bool runOnFunction(Function &F) { std::string Filename = "cfg." + F.getNameStr() + ".dot"; @@ -96,13 +101,15 @@ namespace { char CFGPrinter::ID = 0; INITIALIZE_PASS(CFGPrinter, "dot-cfg", "Print CFG of function to 'dot' file", - false, true); + false, true) namespace { struct CFGOnlyPrinter : public FunctionPass { static char ID; // Pass identification, replacement for typeid - CFGOnlyPrinter() : FunctionPass(ID) {} - explicit CFGOnlyPrinter(char &pid) : FunctionPass(pid) {} + CFGOnlyPrinter() : FunctionPass(ID) { + initializeCFGOnlyPrinterPass(*PassRegistry::getPassRegistry()); + } + virtual bool runOnFunction(Function &F) { std::string Filename = "cfg." + F.getNameStr() + ".dot"; errs() << "Writing '" << Filename << "'..."; @@ -128,7 +135,7 @@ namespace { char CFGOnlyPrinter::ID = 0; INITIALIZE_PASS(CFGOnlyPrinter, "dot-cfg-only", "Print CFG of function to 'dot' file (with no function bodies)", - false, true); + false, true) /// viewCFG - This function is meant for use from the debugger. You can just /// say 'call F->viewCFG()' and a ghostview window should pop up from the diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index 6a2ab681d1ac..1a738fae837d 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -11,6 +11,8 @@ add_llvm_library(LLVMAnalysis ConstantFolding.cpp DbgInfoPrinter.cpp DebugInfo.cpp + DIBuilder.cpp + DominanceFrontier.cpp DomPrinter.cpp IVUsers.cpp InlineCost.cpp @@ -27,11 +29,15 @@ add_llvm_library(LLVMAnalysis LoopDependenceAnalysis.cpp LoopInfo.cpp LoopPass.cpp + MemDepPrinter.cpp MemoryBuiltins.cpp MemoryDependenceAnalysis.cpp ModuleDebugInfoPrinter.cpp + PathNumbering.cpp + PathProfileInfo.cpp + PathProfileVerifier.cpp + NoAliasAnalysis.cpp PHITransAddr.cpp - PointerTracking.cpp PostDominators.cpp ProfileEstimatorPass.cpp ProfileInfo.cpp @@ -39,6 +45,7 @@ add_llvm_library(LLVMAnalysis ProfileInfoLoaderPass.cpp ProfileVerifierPass.cpp RegionInfo.cpp + RegionPass.cpp RegionPrinter.cpp ScalarEvolution.cpp ScalarEvolutionAliasAnalysis.cpp @@ -50,4 +57,4 @@ add_llvm_library(LLVMAnalysis ValueTracking.cpp ) -target_link_libraries (LLVMAnalysis LLVMSupport) +add_subdirectory(IPA) diff --git a/lib/Analysis/CaptureTracking.cpp b/lib/Analysis/CaptureTracking.cpp index 90eae20858fb..42a54d9d1eb3 100644 --- a/lib/Analysis/CaptureTracking.cpp +++ b/lib/Analysis/CaptureTracking.cpp @@ -95,6 +95,9 @@ bool llvm::PointerMayBeCaptured(const Value *V, case Instruction::Load: // Loading from a pointer does not cause it to be captured. break; + case Instruction::VAArg: + // "va-arg" from a pointer does not cause it to be captured. + break; case Instruction::Ret: if (ReturnCaptures) return true; diff --git a/lib/Analysis/ConstantFolding.cpp b/lib/Analysis/ConstantFolding.cpp index 0bf7967e83b1..cd8d52c1c465 100644 --- a/lib/Analysis/ConstantFolding.cpp +++ b/lib/Analysis/ConstantFolding.cpp @@ -30,6 +30,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/GetElementPtrTypeIterator.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/FEnv.h" #include #include using namespace llvm; @@ -53,7 +54,7 @@ static Constant *FoldBitCast(Constant *C, const Type *DestTy, // vector so the code below can handle it uniformly. if (isa(C) || isa(C)) { Constant *Ops = C; // don't take the address of C! - return FoldBitCast(ConstantVector::get(&Ops, 1), DestTy, TD); + return FoldBitCast(ConstantVector::get(Ops), DestTy, TD); } // If this is a bitcast from constant vector -> vector, fold it. @@ -166,7 +167,7 @@ static Constant *FoldBitCast(Constant *C, const Type *DestTy, } } - return ConstantVector::get(Result.data(), Result.size()); + return ConstantVector::get(Result); } @@ -339,6 +340,13 @@ static bool ReadDataFromGlobal(Constant *C, uint64_t ByteOffset, return true; } + if (ConstantExpr *CE = dyn_cast(C)) { + if (CE->getOpcode() == Instruction::IntToPtr && + CE->getOperand(0)->getType() == TD.getIntPtrType(CE->getContext())) + return ReadDataFromGlobal(CE->getOperand(0), ByteOffset, CurPtr, + BytesLeft, TD); + } + // Otherwise, unknown initializer type. return false; } @@ -466,7 +474,8 @@ Constant *llvm::ConstantFoldLoadFromConstPtr(Constant *C, // If this load comes from anywhere in a constant global, and if the global // is all undef or zero, we know what it loads. - if (GlobalVariable *GV = dyn_cast(CE->getUnderlyingObject())){ + if (GlobalVariable *GV = + dyn_cast(GetUnderlyingObject(CE, TD))) { if (GV->isConstant() && GV->hasDefinitiveInitializer()) { const Type *ResTy = cast(C->getType())->getElementType(); if (GV->getInitializer()->isNullValue()) @@ -537,7 +546,7 @@ static Constant *CastGEPIndices(Constant *const *Ops, unsigned NumOps, for (unsigned i = 1; i != NumOps; ++i) { if ((i == 1 || !isa(GetElementPtrInst::getIndexedType(Ops[0]->getType(), - reinterpret_cast(Ops+1), + reinterpret_cast(Ops+1), i-1))) && Ops[i]->getType() != IntPtrTy) { Any = true; @@ -567,16 +576,35 @@ static Constant *SymbolicallyEvaluateGEP(Constant *const *Ops, unsigned NumOps, Constant *Ptr = Ops[0]; if (!TD || !cast(Ptr->getType())->getElementType()->isSized()) return 0; - - unsigned BitWidth = - TD->getTypeSizeInBits(TD->getIntPtrType(Ptr->getContext())); + + const Type *IntPtrTy = TD->getIntPtrType(Ptr->getContext()); // If this is a constant expr gep that is effectively computing an // "offsetof", fold it into 'cast int Size to T*' instead of 'gep 0, 0, 12' for (unsigned i = 1; i != NumOps; ++i) - if (!isa(Ops[i])) + if (!isa(Ops[i])) { + + // If this is "gep i8* Ptr, (sub 0, V)", fold this as: + // "inttoptr (sub (ptrtoint Ptr), V)" + if (NumOps == 2 && + cast(ResultTy)->getElementType()->isIntegerTy(8)) { + ConstantExpr *CE = dyn_cast(Ops[1]); + assert((CE == 0 || CE->getType() == IntPtrTy) && + "CastGEPIndices didn't canonicalize index types!"); + if (CE && CE->getOpcode() == Instruction::Sub && + CE->getOperand(0)->isNullValue()) { + Constant *Res = ConstantExpr::getPtrToInt(Ptr, CE->getType()); + Res = ConstantExpr::getSub(Res, CE->getOperand(1)); + Res = ConstantExpr::getIntToPtr(Res, ResultTy); + if (ConstantExpr *ResCE = dyn_cast(Res)) + Res = ConstantFoldConstantExpression(ResCE, TD); + return Res; + } + } return 0; + } + unsigned BitWidth = TD->getTypeSizeInBits(IntPtrTy); APInt Offset = APInt(BitWidth, TD->getIndexedOffset(Ptr->getType(), (Value**)Ops+1, NumOps-1)); @@ -609,10 +637,8 @@ static Constant *SymbolicallyEvaluateGEP(Constant *const *Ops, unsigned NumOps, APInt BasePtr(BitWidth, 0); if (ConstantExpr *CE = dyn_cast(Ptr)) if (CE->getOpcode() == Instruction::IntToPtr) - if (ConstantInt *Base = dyn_cast(CE->getOperand(0))) { - BasePtr = Base->getValue(); - BasePtr.zextOrTrunc(BitWidth); - } + if (ConstantInt *Base = dyn_cast(CE->getOperand(0))) + BasePtr = Base->getValue().zextOrTrunc(BitWidth); if (Ptr->isNullValue() || BasePtr != 0) { Constant *C = ConstantInt::get(Ptr->getContext(), Offset+BasePtr); return ConstantExpr::getIntToPtr(C, ResultTy); @@ -638,12 +664,19 @@ static Constant *SymbolicallyEvaluateGEP(Constant *const *Ops, unsigned NumOps, // Determine which element of the array the offset points into. APInt ElemSize(BitWidth, TD->getTypeAllocSize(ATy->getElementType())); + const IntegerType *IntPtrTy = TD->getIntPtrType(Ty->getContext()); if (ElemSize == 0) - return 0; - APInt NewIdx = Offset.udiv(ElemSize); - Offset -= NewIdx * ElemSize; - NewIdxs.push_back(ConstantInt::get(TD->getIntPtrType(Ty->getContext()), - NewIdx)); + // The element size is 0. This may be [0 x Ty]*, so just use a zero + // index for this level and proceed to the next level to see if it can + // accommodate the offset. + NewIdxs.push_back(ConstantInt::get(IntPtrTy, 0)); + else { + // The element size is non-zero divide the offset by the element + // size (rounding down), to compute the index at this level. + APInt NewIdx = Offset.udiv(ElemSize); + Offset -= NewIdx * ElemSize; + NewIdxs.push_back(ConstantInt::get(IntPtrTy, NewIdx)); + } Ty = ATy->getElementType(); } else if (const StructType *STy = dyn_cast(Ty)) { // Determine which field of the struct the offset points into. The @@ -687,27 +720,34 @@ static Constant *SymbolicallyEvaluateGEP(Constant *const *Ops, unsigned NumOps, // Constant Folding public APIs //===----------------------------------------------------------------------===// - -/// ConstantFoldInstruction - Attempt to constant fold the specified -/// instruction. If successful, the constant result is returned, if not, null -/// is returned. Note that this function can only fail when attempting to fold -/// instructions like loads and stores, which have no constant expression form. -/// +/// ConstantFoldInstruction - Try to constant fold the specified instruction. +/// If successful, the constant result is returned, if not, null is returned. +/// Note that this fails if not all of the operands are constant. Otherwise, +/// this function can only fail when attempting to fold instructions like loads +/// and stores, which have no constant expression form. Constant *llvm::ConstantFoldInstruction(Instruction *I, const TargetData *TD) { + // Handle PHI nodes quickly here... if (PHINode *PN = dyn_cast(I)) { - if (PN->getNumIncomingValues() == 0) - return UndefValue::get(PN->getType()); - - Constant *Result = dyn_cast(PN->getIncomingValue(0)); - if (Result == 0) return 0; - - // Handle PHI nodes specially here... - for (unsigned i = 1, e = PN->getNumIncomingValues(); i != e; ++i) - if (PN->getIncomingValue(i) != Result && PN->getIncomingValue(i) != PN) - return 0; // Not all the same incoming constants... + Constant *CommonValue = 0; + + for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { + Value *Incoming = PN->getIncomingValue(i); + // If the incoming value is undef then skip it. Note that while we could + // skip the value if it is equal to the phi node itself we choose not to + // because that would break the rule that constant folding only applies if + // all operands are constants. + if (isa(Incoming)) + continue; + // If the incoming value is not a constant, or is a different constant to + // the one we saw previously, then give up. + Constant *C = dyn_cast(Incoming); + if (!C || (CommonValue && C != CommonValue)) + return 0; + CommonValue = C; + } - // If we reach here, all incoming values are the same constant. - return Result; + // If we reach here, all incoming values are the same constant or undef. + return CommonValue ? CommonValue : UndefValue::get(PN->getType()); } // Scan the operand list, checking to see if they are all constants, if so, @@ -725,7 +765,18 @@ Constant *llvm::ConstantFoldInstruction(Instruction *I, const TargetData *TD) { if (const LoadInst *LI = dyn_cast(I)) return ConstantFoldLoadInst(LI, TD); - + + if (InsertValueInst *IVI = dyn_cast(I)) + return ConstantExpr::getInsertValue( + cast(IVI->getAggregateOperand()), + cast(IVI->getInsertedValueOperand()), + IVI->idx_begin(), IVI->getNumIndices()); + + if (ExtractValueInst *EVI = dyn_cast(I)) + return ConstantExpr::getExtractValue( + cast(EVI->getAggregateOperand()), + EVI->idx_begin(), EVI->getNumIndices()); + return ConstantFoldInstOperands(I->getOpcode(), I->getType(), Ops.data(), Ops.size(), TD); } @@ -736,7 +787,8 @@ Constant *llvm::ConstantFoldInstruction(Instruction *I, const TargetData *TD) { Constant *llvm::ConstantFoldConstantExpression(const ConstantExpr *CE, const TargetData *TD) { SmallVector Ops; - for (User::const_op_iterator i = CE->op_begin(), e = CE->op_end(); i != e; ++i) { + for (User::const_op_iterator i = CE->op_begin(), e = CE->op_end(); + i != e; ++i) { Constant *NewC = cast(*i); // Recursively fold the ConstantExpr's operands. if (ConstantExpr *NewCE = dyn_cast(NewC)) @@ -1000,8 +1052,17 @@ llvm::canConstantFoldCallTo(const Function *F) { case Intrinsic::usub_with_overflow: case Intrinsic::sadd_with_overflow: case Intrinsic::ssub_with_overflow: + case Intrinsic::smul_with_overflow: case Intrinsic::convert_from_fp16: case Intrinsic::convert_to_fp16: + case Intrinsic::x86_sse_cvtss2si: + case Intrinsic::x86_sse_cvtss2si64: + case Intrinsic::x86_sse_cvttss2si: + case Intrinsic::x86_sse_cvttss2si64: + case Intrinsic::x86_sse2_cvtsd2si: + case Intrinsic::x86_sse2_cvtsd2si64: + case Intrinsic::x86_sse2_cvttsd2si: + case Intrinsic::x86_sse2_cvttsd2si64: return true; default: return false; @@ -1039,10 +1100,10 @@ llvm::canConstantFoldCallTo(const Function *F) { static Constant *ConstantFoldFP(double (*NativeFP)(double), double V, const Type *Ty) { - errno = 0; + sys::llvm_fenv_clearexcept(); V = NativeFP(V); - if (errno != 0) { - errno = 0; + if (sys::llvm_fenv_testexcept()) { + sys::llvm_fenv_clearexcept(); return 0; } @@ -1056,10 +1117,10 @@ static Constant *ConstantFoldFP(double (*NativeFP)(double), double V, static Constant *ConstantFoldBinaryFP(double (*NativeFP)(double, double), double V, double W, const Type *Ty) { - errno = 0; + sys::llvm_fenv_clearexcept(); V = NativeFP(V, W); - if (errno != 0) { - errno = 0; + if (sys::llvm_fenv_testexcept()) { + sys::llvm_fenv_clearexcept(); return 0; } @@ -1071,6 +1132,36 @@ static Constant *ConstantFoldBinaryFP(double (*NativeFP)(double, double), return 0; // dummy return to suppress warning } +/// ConstantFoldConvertToInt - Attempt to an SSE floating point to integer +/// conversion of a constant floating point. If roundTowardZero is false, the +/// default IEEE rounding is used (toward nearest, ties to even). This matches +/// the behavior of the non-truncating SSE instructions in the default rounding +/// mode. The desired integer type Ty is used to select how many bits are +/// available for the result. Returns null if the conversion cannot be +/// performed, otherwise returns the Constant value resulting from the +/// conversion. +static Constant *ConstantFoldConvertToInt(ConstantFP *Op, bool roundTowardZero, + const Type *Ty) { + assert(Op && "Called with NULL operand"); + APFloat Val(Op->getValueAPF()); + + // All of these conversion intrinsics form an integer of at most 64bits. + unsigned ResultWidth = cast(Ty)->getBitWidth(); + assert(ResultWidth <= 64 && + "Can only constant fold conversions to 64 and 32 bit ints"); + + uint64_t UIntVal; + bool isExact = false; + APFloat::roundingMode mode = roundTowardZero? APFloat::rmTowardZero + : APFloat::rmNearestTiesToEven; + APFloat::opStatus status = Val.convertToInteger(&UIntVal, ResultWidth, + /*isSigned=*/true, mode, + &isExact); + if (status != APFloat::opOK && status != APFloat::opInexact) + return 0; + return ConstantInt::get(Ty, UIntVal, /*isSigned=*/true); +} + /// ConstantFoldCall - Attempt to constant fold a call to the specified function /// with the specified arguments, returning null if unsuccessful. Constant * @@ -1082,7 +1173,7 @@ llvm::ConstantFoldCall(Function *F, const Type *Ty = F->getReturnType(); if (NumOperands == 1) { if (ConstantFP *Op = dyn_cast(Operands[0])) { - if (Name == "llvm.convert.to.fp16") { + if (F->getIntrinsicID() == Intrinsic::convert_to_fp16) { APFloat Val(Op->getValueAPF()); bool lost = false; @@ -1093,6 +1184,13 @@ llvm::ConstantFoldCall(Function *F, if (!Ty->isFloatTy() && !Ty->isDoubleTy()) return 0; + + /// We only fold functions with finite arguments. Folding NaN and inf is + /// likely to be aborted with an exception anyway, and some host libms + /// have known errors raising exceptions. + if (Op->getValueAPF().isNaN() || Op->getValueAPF().isInfinity()) + return 0; + /// Currently APFloat versions of these functions do not exist, so we use /// the host native double versions. Float versions are not called /// directly but for all these it is true (float)(f((double)arg)) == @@ -1133,8 +1231,8 @@ llvm::ConstantFoldCall(Function *F, return ConstantFoldFP(log, V, Ty); else if (Name == "log10" && V > 0) return ConstantFoldFP(log10, V, Ty); - else if (Name == "llvm.sqrt.f32" || - Name == "llvm.sqrt.f64") { + else if (F->getIntrinsicID() == Intrinsic::sqrt && + (Ty->isFloatTy() || Ty->isDoubleTy())) { if (V >= -0.0) return ConstantFoldFP(sqrt, V, Ty); else // Undefined @@ -1164,18 +1262,18 @@ llvm::ConstantFoldCall(Function *F, } return 0; } - - + if (ConstantInt *Op = dyn_cast(Operands[0])) { - if (Name.startswith("llvm.bswap")) + switch (F->getIntrinsicID()) { + case Intrinsic::bswap: return ConstantInt::get(F->getContext(), Op->getValue().byteSwap()); - else if (Name.startswith("llvm.ctpop")) + case Intrinsic::ctpop: return ConstantInt::get(Ty, Op->getValue().countPopulation()); - else if (Name.startswith("llvm.cttz")) + case Intrinsic::cttz: return ConstantInt::get(Ty, Op->getValue().countTrailingZeros()); - else if (Name.startswith("llvm.ctlz")) + case Intrinsic::ctlz: return ConstantInt::get(Ty, Op->getValue().countLeadingZeros()); - else if (Name == "llvm.convert.from.fp16") { + case Intrinsic::convert_from_fp16: { APFloat Val(Op->getValue()); bool lost = false; @@ -1183,24 +1281,44 @@ llvm::ConstantFoldCall(Function *F, Val.convert(APFloat::IEEEsingle, APFloat::rmNearestTiesToEven, &lost); // Conversion is always precise. - status = status; + (void)status; assert(status == APFloat::opOK && !lost && "Precision lost during fp16 constfolding"); return ConstantFP::get(F->getContext(), Val); } - return 0; + default: + return 0; + } } - + + if (ConstantVector *Op = dyn_cast(Operands[0])) { + switch (F->getIntrinsicID()) { + default: break; + case Intrinsic::x86_sse_cvtss2si: + case Intrinsic::x86_sse_cvtss2si64: + case Intrinsic::x86_sse2_cvtsd2si: + case Intrinsic::x86_sse2_cvtsd2si64: + if (ConstantFP *FPOp = dyn_cast(Op->getOperand(0))) + return ConstantFoldConvertToInt(FPOp, /*roundTowardZero=*/false, Ty); + case Intrinsic::x86_sse_cvttss2si: + case Intrinsic::x86_sse_cvttss2si64: + case Intrinsic::x86_sse2_cvttsd2si: + case Intrinsic::x86_sse2_cvttsd2si64: + if (ConstantFP *FPOp = dyn_cast(Op->getOperand(0))) + return ConstantFoldConvertToInt(FPOp, /*roundTowardZero=*/true, Ty); + } + } + if (isa(Operands[0])) { - if (Name.startswith("llvm.bswap")) + if (F->getIntrinsicID() == Intrinsic::bswap) return Operands[0]; return 0; } return 0; } - + if (NumOperands == 2) { if (ConstantFP *Op1 = dyn_cast(Operands[0])) { if (!Ty->isFloatTy() && !Ty->isDoubleTy()) @@ -1223,11 +1341,11 @@ llvm::ConstantFoldCall(Function *F, if (Name == "atan2") return ConstantFoldBinaryFP(atan2, Op1V, Op2V, Ty); } else if (ConstantInt *Op2C = dyn_cast(Operands[1])) { - if (Name == "llvm.powi.f32") + if (F->getIntrinsicID() == Intrinsic::powi && Ty->isFloatTy()) return ConstantFP::get(F->getContext(), APFloat((float)std::pow((float)Op1V, (int)Op2C->getZExtValue()))); - if (Name == "llvm.powi.f64") + if (F->getIntrinsicID() == Intrinsic::powi && Ty->isDoubleTy()) return ConstantFP::get(F->getContext(), APFloat((double)std::pow((double)Op1V, (int)Op2C->getZExtValue()))); @@ -1240,42 +1358,37 @@ llvm::ConstantFoldCall(Function *F, if (ConstantInt *Op2 = dyn_cast(Operands[1])) { switch (F->getIntrinsicID()) { default: break; - case Intrinsic::uadd_with_overflow: { - Constant *Res = ConstantExpr::getAdd(Op1, Op2); // result. - Constant *Ops[] = { - Res, ConstantExpr::getICmp(CmpInst::ICMP_ULT, Res, Op1) // overflow. - }; - return ConstantStruct::get(F->getContext(), Ops, 2, false); - } - case Intrinsic::usub_with_overflow: { - Constant *Res = ConstantExpr::getSub(Op1, Op2); // result. + case Intrinsic::sadd_with_overflow: + case Intrinsic::uadd_with_overflow: + case Intrinsic::ssub_with_overflow: + case Intrinsic::usub_with_overflow: + case Intrinsic::smul_with_overflow: { + APInt Res; + bool Overflow; + switch (F->getIntrinsicID()) { + default: assert(0 && "Invalid case"); + case Intrinsic::sadd_with_overflow: + Res = Op1->getValue().sadd_ov(Op2->getValue(), Overflow); + break; + case Intrinsic::uadd_with_overflow: + Res = Op1->getValue().uadd_ov(Op2->getValue(), Overflow); + break; + case Intrinsic::ssub_with_overflow: + Res = Op1->getValue().ssub_ov(Op2->getValue(), Overflow); + break; + case Intrinsic::usub_with_overflow: + Res = Op1->getValue().usub_ov(Op2->getValue(), Overflow); + break; + case Intrinsic::smul_with_overflow: + Res = Op1->getValue().smul_ov(Op2->getValue(), Overflow); + break; + } Constant *Ops[] = { - Res, ConstantExpr::getICmp(CmpInst::ICMP_UGT, Res, Op1) // overflow. + ConstantInt::get(F->getContext(), Res), + ConstantInt::get(Type::getInt1Ty(F->getContext()), Overflow) }; return ConstantStruct::get(F->getContext(), Ops, 2, false); } - case Intrinsic::sadd_with_overflow: { - Constant *Res = ConstantExpr::getAdd(Op1, Op2); // result. - Constant *Overflow = ConstantExpr::getSelect( - ConstantExpr::getICmp(CmpInst::ICMP_SGT, - ConstantInt::get(Op1->getType(), 0), Op1), - ConstantExpr::getICmp(CmpInst::ICMP_SGT, Res, Op2), - ConstantExpr::getICmp(CmpInst::ICMP_SLT, Res, Op2)); // overflow. - - Constant *Ops[] = { Res, Overflow }; - return ConstantStruct::get(F->getContext(), Ops, 2, false); - } - case Intrinsic::ssub_with_overflow: { - Constant *Res = ConstantExpr::getSub(Op1, Op2); // result. - Constant *Overflow = ConstantExpr::getSelect( - ConstantExpr::getICmp(CmpInst::ICMP_SGT, - ConstantInt::get(Op2->getType(), 0), Op2), - ConstantExpr::getICmp(CmpInst::ICMP_SLT, Res, Op1), - ConstantExpr::getICmp(CmpInst::ICMP_SGT, Res, Op1)); // overflow. - - Constant *Ops[] = { Res, Overflow }; - return ConstantStruct::get(F->getContext(), Ops, 2, false); - } } } @@ -1285,4 +1398,3 @@ llvm::ConstantFoldCall(Function *F, } return 0; } - diff --git a/lib/Analysis/DIBuilder.cpp b/lib/Analysis/DIBuilder.cpp new file mode 100644 index 000000000000..c1072df72925 --- /dev/null +++ b/lib/Analysis/DIBuilder.cpp @@ -0,0 +1,801 @@ +//===--- DIBuilder.cpp - Debug Information Builder ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the DIBuilder. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/DIBuilder.h" +#include "llvm/Analysis/DebugInfo.h" +#include "llvm/Constants.h" +#include "llvm/IntrinsicInst.h" +#include "llvm/Module.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Dwarf.h" + +using namespace llvm; +using namespace llvm::dwarf; + +static Constant *GetTagConstant(LLVMContext &VMContext, unsigned Tag) { + assert((Tag & LLVMDebugVersionMask) == 0 && + "Tag too large for debug encoding!"); + return ConstantInt::get(Type::getInt32Ty(VMContext), Tag | LLVMDebugVersion); +} + +DIBuilder::DIBuilder(Module &m) + : M(m), VMContext(M.getContext()), TheCU(0), DeclareFn(0), ValueFn(0) {} + +/// CreateCompileUnit - A CompileUnit provides an anchor for all debugging +/// information generated during this instance of compilation. +void DIBuilder::CreateCompileUnit(unsigned Lang, StringRef Filename, + StringRef Directory, StringRef Producer, + bool isOptimized, StringRef Flags, + unsigned RunTimeVer) { + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_compile_unit), + llvm::Constant::getNullValue(Type::getInt32Ty(VMContext)), + ConstantInt::get(Type::getInt32Ty(VMContext), Lang), + MDString::get(VMContext, Filename), + MDString::get(VMContext, Directory), + MDString::get(VMContext, Producer), + // Deprecate isMain field. + ConstantInt::get(Type::getInt1Ty(VMContext), true), // isMain + ConstantInt::get(Type::getInt1Ty(VMContext), isOptimized), + MDString::get(VMContext, Flags), + ConstantInt::get(Type::getInt32Ty(VMContext), RunTimeVer) + }; + TheCU = DICompileUnit(MDNode::get(VMContext, &Elts[0], array_lengthof(Elts))); +} + +/// CreateFile - Create a file descriptor to hold debugging information +/// for a file. +DIFile DIBuilder::CreateFile(StringRef Filename, StringRef Directory) { + assert(TheCU && "Unable to create DW_TAG_file_type without CompileUnit"); + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_file_type), + MDString::get(VMContext, Filename), + MDString::get(VMContext, Directory), + TheCU + }; + return DIFile(MDNode::get(VMContext, &Elts[0], array_lengthof(Elts))); +} + +/// CreateEnumerator - Create a single enumerator value. +DIEnumerator DIBuilder::CreateEnumerator(StringRef Name, uint64_t Val) { + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_enumerator), + MDString::get(VMContext, Name), + ConstantInt::get(Type::getInt64Ty(VMContext), Val) + }; + return DIEnumerator(MDNode::get(VMContext, &Elts[0], array_lengthof(Elts))); +} + +/// CreateBasicType - Create debugging information entry for a basic +/// type, e.g 'char'. +DIType DIBuilder::CreateBasicType(StringRef Name, uint64_t SizeInBits, + uint64_t AlignInBits, + unsigned Encoding) { + // Basic types are encoded in DIBasicType format. Line number, filename, + // offset and flags are always empty here. + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_base_type), + TheCU, + MDString::get(VMContext, Name), + NULL, // Filename + ConstantInt::get(Type::getInt32Ty(VMContext), 0), // Line + ConstantInt::get(Type::getInt64Ty(VMContext), SizeInBits), + ConstantInt::get(Type::getInt64Ty(VMContext), AlignInBits), + ConstantInt::get(Type::getInt64Ty(VMContext), 0), // Offset + ConstantInt::get(Type::getInt32Ty(VMContext), 0), // Flags; + ConstantInt::get(Type::getInt32Ty(VMContext), Encoding) + }; + return DIType(MDNode::get(VMContext, &Elts[0], array_lengthof(Elts))); +} + +/// CreateQaulifiedType - Create debugging information entry for a qualified +/// type, e.g. 'const int'. +DIType DIBuilder::CreateQualifiedType(unsigned Tag, DIType FromTy) { + // Qualified types are encoded in DIDerivedType format. + Value *Elts[] = { + GetTagConstant(VMContext, Tag), + TheCU, + MDString::get(VMContext, StringRef()), // Empty name. + NULL, // Filename + ConstantInt::get(Type::getInt32Ty(VMContext), 0), // Line + ConstantInt::get(Type::getInt64Ty(VMContext), 0), // Size + ConstantInt::get(Type::getInt64Ty(VMContext), 0), // Align + ConstantInt::get(Type::getInt64Ty(VMContext), 0), // Offset + ConstantInt::get(Type::getInt32Ty(VMContext), 0), // Flags + FromTy + }; + return DIType(MDNode::get(VMContext, &Elts[0], array_lengthof(Elts))); +} + +/// CreatePointerType - Create debugging information entry for a pointer. +DIType DIBuilder::CreatePointerType(DIType PointeeTy, uint64_t SizeInBits, + uint64_t AlignInBits, StringRef Name) { + // Pointer types are encoded in DIDerivedType format. + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_pointer_type), + TheCU, + MDString::get(VMContext, Name), + NULL, // Filename + ConstantInt::get(Type::getInt32Ty(VMContext), 0), // Line + ConstantInt::get(Type::getInt64Ty(VMContext), SizeInBits), + ConstantInt::get(Type::getInt64Ty(VMContext), AlignInBits), + ConstantInt::get(Type::getInt64Ty(VMContext), 0), // Offset + ConstantInt::get(Type::getInt32Ty(VMContext), 0), // Flags + PointeeTy + }; + return DIType(MDNode::get(VMContext, &Elts[0], array_lengthof(Elts))); +} + +/// CreateReferenceType - Create debugging information entry for a reference. +DIType DIBuilder::CreateReferenceType(DIType RTy) { + // References are encoded in DIDerivedType format. + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_reference_type), + TheCU, + NULL, // Name + NULL, // Filename + ConstantInt::get(Type::getInt32Ty(VMContext), 0), // Line + ConstantInt::get(Type::getInt64Ty(VMContext), 0), // Size + ConstantInt::get(Type::getInt64Ty(VMContext), 0), // Align + ConstantInt::get(Type::getInt64Ty(VMContext), 0), // Offset + ConstantInt::get(Type::getInt32Ty(VMContext), 0), // Flags + RTy + }; + return DIType(MDNode::get(VMContext, &Elts[0], array_lengthof(Elts))); +} + +/// CreateTypedef - Create debugging information entry for a typedef. +DIType DIBuilder::CreateTypedef(DIType Ty, StringRef Name, DIFile File, + unsigned LineNo) { + // typedefs are encoded in DIDerivedType format. + assert(Ty.Verify() && "Invalid typedef type!"); + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_typedef), + Ty.getContext(), + MDString::get(VMContext, Name), + File, + ConstantInt::get(Type::getInt32Ty(VMContext), LineNo), + ConstantInt::get(Type::getInt64Ty(VMContext), 0), // Size + ConstantInt::get(Type::getInt64Ty(VMContext), 0), // Align + ConstantInt::get(Type::getInt64Ty(VMContext), 0), // Offset + ConstantInt::get(Type::getInt32Ty(VMContext), 0), // Flags + Ty + }; + return DIType(MDNode::get(VMContext, &Elts[0], array_lengthof(Elts))); +} + +/// CreateFriend - Create debugging information entry for a 'friend'. +DIType DIBuilder::CreateFriend(DIType Ty, DIType FriendTy) { + // typedefs are encoded in DIDerivedType format. + assert(Ty.Verify() && "Invalid type!"); + assert(FriendTy.Verify() && "Invalid friend type!"); + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_friend), + Ty, + NULL, // Name + Ty.getFile(), + ConstantInt::get(Type::getInt32Ty(VMContext), 0), // Line + ConstantInt::get(Type::getInt64Ty(VMContext), 0), // Size + ConstantInt::get(Type::getInt64Ty(VMContext), 0), // Align + ConstantInt::get(Type::getInt64Ty(VMContext), 0), // Offset + ConstantInt::get(Type::getInt32Ty(VMContext), 0), // Flags + FriendTy + }; + return DIType(MDNode::get(VMContext, &Elts[0], array_lengthof(Elts))); +} + +/// CreateInheritance - Create debugging information entry to establish +/// inheritnace relationship between two types. +DIType DIBuilder::CreateInheritance(DIType Ty, DIType BaseTy, + uint64_t BaseOffset, unsigned Flags) { + // TAG_inheritance is encoded in DIDerivedType format. + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_inheritance), + Ty, + NULL, // Name + Ty.getFile(), + ConstantInt::get(Type::getInt32Ty(VMContext), 0), // Line + ConstantInt::get(Type::getInt64Ty(VMContext), 0), // Size + ConstantInt::get(Type::getInt64Ty(VMContext), 0), // Align + ConstantInt::get(Type::getInt64Ty(VMContext), BaseOffset), + ConstantInt::get(Type::getInt32Ty(VMContext), Flags), + BaseTy + }; + return DIType(MDNode::get(VMContext, &Elts[0], array_lengthof(Elts))); +} + +/// CreateMemberType - Create debugging information entry for a member. +DIType DIBuilder::CreateMemberType(StringRef Name, + DIFile File, unsigned LineNumber, + uint64_t SizeInBits, uint64_t AlignInBits, + uint64_t OffsetInBits, unsigned Flags, + DIType Ty) { + // TAG_member is encoded in DIDerivedType format. + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_member), + File, // Or TheCU ? Ty ? + MDString::get(VMContext, Name), + File, + ConstantInt::get(Type::getInt32Ty(VMContext), LineNumber), + ConstantInt::get(Type::getInt64Ty(VMContext), SizeInBits), + ConstantInt::get(Type::getInt64Ty(VMContext), AlignInBits), + ConstantInt::get(Type::getInt64Ty(VMContext), OffsetInBits), + ConstantInt::get(Type::getInt32Ty(VMContext), Flags), + Ty + }; + return DIType(MDNode::get(VMContext, &Elts[0], array_lengthof(Elts))); +} + +/// CreateClassType - Create debugging information entry for a class. +DIType DIBuilder::CreateClassType(DIDescriptor Context, StringRef Name, + DIFile File, unsigned LineNumber, + uint64_t SizeInBits, uint64_t AlignInBits, + uint64_t OffsetInBits, unsigned Flags, + DIType DerivedFrom, DIArray Elements, + MDNode *VTableHoder, MDNode *TemplateParams) { + // TAG_class_type is encoded in DICompositeType format. + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_class_type), + Context, + MDString::get(VMContext, Name), + File, + ConstantInt::get(Type::getInt32Ty(VMContext), LineNumber), + ConstantInt::get(Type::getInt64Ty(VMContext), SizeInBits), + ConstantInt::get(Type::getInt64Ty(VMContext), AlignInBits), + ConstantInt::get(Type::getInt32Ty(VMContext), OffsetInBits), + ConstantInt::get(Type::getInt32Ty(VMContext), Flags), + DerivedFrom, + Elements, + ConstantInt::get(Type::getInt32Ty(VMContext), 0), + VTableHoder, + TemplateParams + }; + return DIType(MDNode::get(VMContext, &Elts[0], array_lengthof(Elts))); +} + +/// CreateTemplateTypeParameter - Create debugging information for template +/// type parameter. +DITemplateTypeParameter +DIBuilder::CreateTemplateTypeParameter(DIDescriptor Context, StringRef Name, + DIType Ty, MDNode *File, unsigned LineNo, + unsigned ColumnNo) { + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_template_type_parameter), + Context, + MDString::get(VMContext, Name), + Ty, + File, + ConstantInt::get(Type::getInt32Ty(VMContext), LineNo), + ConstantInt::get(Type::getInt32Ty(VMContext), ColumnNo) + }; + return DITemplateTypeParameter(MDNode::get(VMContext, &Elts[0], + array_lengthof(Elts))); +} + +/// CreateTemplateValueParameter - Create debugging information for template +/// value parameter. +DITemplateValueParameter +DIBuilder::CreateTemplateValueParameter(DIDescriptor Context, StringRef Name, + DIType Ty, uint64_t Val, + MDNode *File, unsigned LineNo, + unsigned ColumnNo) { + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_template_value_parameter), + Context, + MDString::get(VMContext, Name), + Ty, + ConstantInt::get(Type::getInt64Ty(VMContext), Val), + File, + ConstantInt::get(Type::getInt32Ty(VMContext), LineNo), + ConstantInt::get(Type::getInt32Ty(VMContext), ColumnNo) + }; + return DITemplateValueParameter(MDNode::get(VMContext, &Elts[0], + array_lengthof(Elts))); +} + +/// CreateStructType - Create debugging information entry for a struct. +DIType DIBuilder::CreateStructType(DIDescriptor Context, StringRef Name, + DIFile File, unsigned LineNumber, + uint64_t SizeInBits, uint64_t AlignInBits, + unsigned Flags, DIArray Elements, + unsigned RunTimeLang) { + // TAG_structure_type is encoded in DICompositeType format. + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_structure_type), + Context, + MDString::get(VMContext, Name), + File, + ConstantInt::get(Type::getInt32Ty(VMContext), LineNumber), + ConstantInt::get(Type::getInt64Ty(VMContext), SizeInBits), + ConstantInt::get(Type::getInt64Ty(VMContext), AlignInBits), + ConstantInt::get(Type::getInt32Ty(VMContext), 0), + ConstantInt::get(Type::getInt32Ty(VMContext), Flags), + llvm::Constant::getNullValue(Type::getInt32Ty(VMContext)), + Elements, + ConstantInt::get(Type::getInt32Ty(VMContext), RunTimeLang), + llvm::Constant::getNullValue(Type::getInt32Ty(VMContext)), + }; + return DIType(MDNode::get(VMContext, &Elts[0], array_lengthof(Elts))); +} + +/// CreateUnionType - Create debugging information entry for an union. +DIType DIBuilder::CreateUnionType(DIDescriptor Scope, StringRef Name, + DIFile File, + unsigned LineNumber, uint64_t SizeInBits, + uint64_t AlignInBits, unsigned Flags, + DIArray Elements, unsigned RunTimeLang) { + // TAG_union_type is encoded in DICompositeType format. + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_union_type), + Scope, + MDString::get(VMContext, Name), + File, + ConstantInt::get(Type::getInt32Ty(VMContext), LineNumber), + ConstantInt::get(Type::getInt64Ty(VMContext), SizeInBits), + ConstantInt::get(Type::getInt64Ty(VMContext), AlignInBits), + ConstantInt::get(Type::getInt64Ty(VMContext), 0), + ConstantInt::get(Type::getInt32Ty(VMContext), Flags), + llvm::Constant::getNullValue(Type::getInt32Ty(VMContext)), + Elements, + ConstantInt::get(Type::getInt32Ty(VMContext), RunTimeLang), + llvm::Constant::getNullValue(Type::getInt32Ty(VMContext)), + }; + return DIType(MDNode::get(VMContext, &Elts[0], array_lengthof(Elts))); +} + +/// CreateSubroutineType - Create subroutine type. +DIType DIBuilder::CreateSubroutineType(DIFile File, DIArray ParameterTypes) { + // TAG_subroutine_type is encoded in DICompositeType format. + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_subroutine_type), + File, + MDString::get(VMContext, ""), + File, + ConstantInt::get(Type::getInt32Ty(VMContext), 0), + ConstantInt::get(Type::getInt64Ty(VMContext), 0), + ConstantInt::get(Type::getInt64Ty(VMContext), 0), + ConstantInt::get(Type::getInt32Ty(VMContext), 0), + ConstantInt::get(Type::getInt32Ty(VMContext), 0), + llvm::Constant::getNullValue(Type::getInt32Ty(VMContext)), + ParameterTypes, + ConstantInt::get(Type::getInt32Ty(VMContext), 0), + llvm::Constant::getNullValue(Type::getInt32Ty(VMContext)), + }; + return DIType(MDNode::get(VMContext, &Elts[0], array_lengthof(Elts))); +} + +/// CreateEnumerationType - Create debugging information entry for an +/// enumeration. +DIType DIBuilder::CreateEnumerationType(DIDescriptor Scope, StringRef Name, + DIFile File, unsigned LineNumber, + uint64_t SizeInBits, + uint64_t AlignInBits, DIArray Elements) { + // TAG_enumeration_type is encoded in DICompositeType format. + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_enumeration_type), + Scope, + MDString::get(VMContext, Name), + File, + ConstantInt::get(Type::getInt32Ty(VMContext), LineNumber), + ConstantInt::get(Type::getInt64Ty(VMContext), SizeInBits), + ConstantInt::get(Type::getInt64Ty(VMContext), AlignInBits), + ConstantInt::get(Type::getInt32Ty(VMContext), 0), + ConstantInt::get(Type::getInt32Ty(VMContext), 0), + llvm::Constant::getNullValue(Type::getInt32Ty(VMContext)), + Elements, + ConstantInt::get(Type::getInt32Ty(VMContext), 0), + llvm::Constant::getNullValue(Type::getInt32Ty(VMContext)), + }; + MDNode *Node = MDNode::get(VMContext, &Elts[0], array_lengthof(Elts)); + NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.enum"); + NMD->addOperand(Node); + return DIType(Node); +} + +/// CreateArrayType - Create debugging information entry for an array. +DIType DIBuilder::CreateArrayType(uint64_t Size, uint64_t AlignInBits, + DIType Ty, DIArray Subscripts) { + // TAG_array_type is encoded in DICompositeType format. + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_array_type), + TheCU, + MDString::get(VMContext, ""), + TheCU, + ConstantInt::get(Type::getInt32Ty(VMContext), 0), + ConstantInt::get(Type::getInt64Ty(VMContext), Size), + ConstantInt::get(Type::getInt64Ty(VMContext), AlignInBits), + ConstantInt::get(Type::getInt32Ty(VMContext), 0), + ConstantInt::get(Type::getInt32Ty(VMContext), 0), + Ty, + Subscripts, + ConstantInt::get(Type::getInt32Ty(VMContext), 0), + llvm::Constant::getNullValue(Type::getInt32Ty(VMContext)), + }; + return DIType(MDNode::get(VMContext, &Elts[0], array_lengthof(Elts))); +} + +/// CreateVectorType - Create debugging information entry for a vector. +DIType DIBuilder::CreateVectorType(uint64_t Size, uint64_t AlignInBits, + DIType Ty, DIArray Subscripts) { + // TAG_vector_type is encoded in DICompositeType format. + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_vector_type), + TheCU, + MDString::get(VMContext, ""), + TheCU, + ConstantInt::get(Type::getInt32Ty(VMContext), 0), + ConstantInt::get(Type::getInt64Ty(VMContext), Size), + ConstantInt::get(Type::getInt64Ty(VMContext), AlignInBits), + ConstantInt::get(Type::getInt32Ty(VMContext), 0), + ConstantInt::get(Type::getInt32Ty(VMContext), 0), + Ty, + Subscripts, + ConstantInt::get(Type::getInt32Ty(VMContext), 0), + llvm::Constant::getNullValue(Type::getInt32Ty(VMContext)), + }; + return DIType(MDNode::get(VMContext, &Elts[0], array_lengthof(Elts))); +} + +/// CreateArtificialType - Create a new DIType with "artificial" flag set. +DIType DIBuilder::CreateArtificialType(DIType Ty) { + if (Ty.isArtificial()) + return Ty; + + SmallVector Elts; + MDNode *N = Ty; + assert (N && "Unexpected input DIType!"); + for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) { + if (Value *V = N->getOperand(i)) + Elts.push_back(V); + else + Elts.push_back(Constant::getNullValue(Type::getInt32Ty(VMContext))); + } + + unsigned CurFlags = Ty.getFlags(); + CurFlags = CurFlags | DIType::FlagArtificial; + + // Flags are stored at this slot. + Elts[8] = ConstantInt::get(Type::getInt32Ty(VMContext), CurFlags); + + return DIType(MDNode::get(VMContext, Elts.data(), Elts.size())); +} + +/// RetainType - Retain DIType in a module even if it is not referenced +/// through debug info anchors. +void DIBuilder::RetainType(DIType T) { + NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.ty"); + NMD->addOperand(T); +} + +/// CreateUnspecifiedParameter - Create unspeicified type descriptor +/// for the subroutine type. +DIDescriptor DIBuilder::CreateUnspecifiedParameter() { + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_unspecified_parameters) + }; + return DIDescriptor(MDNode::get(VMContext, &Elts[0], 1)); +} + +/// CreateTemporaryType - Create a temporary forward-declared type. +DIType DIBuilder::CreateTemporaryType() { + // Give the temporary MDNode a tag. It doesn't matter what tag we + // use here as long as DIType accepts it. + Value *Elts[] = { GetTagConstant(VMContext, DW_TAG_base_type) }; + MDNode *Node = MDNode::getTemporary(VMContext, Elts, array_lengthof(Elts)); + return DIType(Node); +} + +/// CreateTemporaryType - Create a temporary forward-declared type. +DIType DIBuilder::CreateTemporaryType(DIFile F) { + // Give the temporary MDNode a tag. It doesn't matter what tag we + // use here as long as DIType accepts it. + Value *Elts[] = { + GetTagConstant(VMContext, DW_TAG_base_type), + F.getCompileUnit(), + NULL, + F + }; + MDNode *Node = MDNode::getTemporary(VMContext, Elts, array_lengthof(Elts)); + return DIType(Node); +} + +/// GetOrCreateArray - Get a DIArray, create one if required. +DIArray DIBuilder::GetOrCreateArray(Value *const *Elements, unsigned NumElements) { + if (NumElements == 0) { + Value *Null = llvm::Constant::getNullValue(Type::getInt32Ty(VMContext)); + return DIArray(MDNode::get(VMContext, &Null, 1)); + } + return DIArray(MDNode::get(VMContext, Elements, NumElements)); +} + +/// GetOrCreateSubrange - Create a descriptor for a value range. This +/// implicitly uniques the values returned. +DISubrange DIBuilder::GetOrCreateSubrange(int64_t Lo, int64_t Hi) { + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_subrange_type), + ConstantInt::get(Type::getInt64Ty(VMContext), Lo), + ConstantInt::get(Type::getInt64Ty(VMContext), Hi) + }; + + return DISubrange(MDNode::get(VMContext, &Elts[0], 3)); +} + +/// CreateGlobalVariable - Create a new descriptor for the specified global. +DIGlobalVariable DIBuilder:: +CreateGlobalVariable(StringRef Name, DIFile F, unsigned LineNumber, + DIType Ty, bool isLocalToUnit, llvm::Value *Val) { + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_variable), + llvm::Constant::getNullValue(Type::getInt32Ty(VMContext)), + TheCU, + MDString::get(VMContext, Name), + MDString::get(VMContext, Name), + MDString::get(VMContext, Name), + F, + ConstantInt::get(Type::getInt32Ty(VMContext), LineNumber), + Ty, + ConstantInt::get(Type::getInt32Ty(VMContext), isLocalToUnit), + ConstantInt::get(Type::getInt32Ty(VMContext), 1), /* isDefinition*/ + Val + }; + MDNode *Node = MDNode::get(VMContext, &Elts[0], array_lengthof(Elts)); + // Create a named metadata so that we do not lose this mdnode. + NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.gv"); + NMD->addOperand(Node); + return DIGlobalVariable(Node); +} + +/// CreateStaticVariable - Create a new descriptor for the specified static +/// variable. +DIGlobalVariable DIBuilder:: +CreateStaticVariable(DIDescriptor Context, StringRef Name, + StringRef LinkageName, DIFile F, unsigned LineNumber, + DIType Ty, bool isLocalToUnit, llvm::Value *Val) { + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_variable), + llvm::Constant::getNullValue(Type::getInt32Ty(VMContext)), + Context, + MDString::get(VMContext, Name), + MDString::get(VMContext, Name), + MDString::get(VMContext, LinkageName), + F, + ConstantInt::get(Type::getInt32Ty(VMContext), LineNumber), + Ty, + ConstantInt::get(Type::getInt32Ty(VMContext), isLocalToUnit), + ConstantInt::get(Type::getInt32Ty(VMContext), 1), /* isDefinition*/ + Val + }; + MDNode *Node = MDNode::get(VMContext, &Elts[0], array_lengthof(Elts)); + // Create a named metadata so that we do not lose this mdnode. + NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.gv"); + NMD->addOperand(Node); + return DIGlobalVariable(Node); +} + +/// CreateVariable - Create a new descriptor for the specified variable. +DIVariable DIBuilder::CreateLocalVariable(unsigned Tag, DIDescriptor Scope, + StringRef Name, DIFile File, + unsigned LineNo, DIType Ty, + bool AlwaysPreserve, unsigned Flags) { + Value *Elts[] = { + GetTagConstant(VMContext, Tag), + Scope, + MDString::get(VMContext, Name), + File, + ConstantInt::get(Type::getInt32Ty(VMContext), LineNo), + Ty, + ConstantInt::get(Type::getInt32Ty(VMContext), Flags) + }; + MDNode *Node = MDNode::get(VMContext, &Elts[0], array_lengthof(Elts)); + if (AlwaysPreserve) { + // The optimizer may remove local variable. If there is an interest + // to preserve variable info in such situation then stash it in a + // named mdnode. + DISubprogram Fn(getDISubprogram(Scope)); + StringRef FName = "fn"; + if (Fn.getFunction()) + FName = Fn.getFunction()->getName(); + char One = '\1'; + if (FName.startswith(StringRef(&One, 1))) + FName = FName.substr(1); + NamedMDNode *FnLocals = getOrInsertFnSpecificMDNode(M, FName); + FnLocals->addOperand(Node); + } + return DIVariable(Node); +} + +/// CreateComplexVariable - Create a new descriptor for the specified variable +/// which has a complex address expression for its address. +DIVariable DIBuilder::CreateComplexVariable(unsigned Tag, DIDescriptor Scope, + StringRef Name, DIFile F, + unsigned LineNo, + DIType Ty, Value *const *Addr, + unsigned NumAddr) { + SmallVector Elts; + Elts.push_back(GetTagConstant(VMContext, Tag)); + Elts.push_back(Scope); + Elts.push_back(MDString::get(VMContext, Name)); + Elts.push_back(F); + Elts.push_back(ConstantInt::get(Type::getInt32Ty(VMContext), LineNo)); + Elts.push_back(Ty); + Elts.append(Addr, Addr+NumAddr); + + return DIVariable(MDNode::get(VMContext, Elts.data(), Elts.size())); +} + +/// CreateFunction - Create a new descriptor for the specified function. +DISubprogram DIBuilder::CreateFunction(DIDescriptor Context, + StringRef Name, + StringRef LinkageName, + DIFile File, unsigned LineNo, + DIType Ty, + bool isLocalToUnit, bool isDefinition, + unsigned Flags, bool isOptimized, + Function *Fn) { + + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_subprogram), + llvm::Constant::getNullValue(Type::getInt32Ty(VMContext)), + Context, + MDString::get(VMContext, Name), + MDString::get(VMContext, Name), + MDString::get(VMContext, LinkageName), + File, + ConstantInt::get(Type::getInt32Ty(VMContext), LineNo), + Ty, + ConstantInt::get(Type::getInt1Ty(VMContext), isLocalToUnit), + ConstantInt::get(Type::getInt1Ty(VMContext), isDefinition), + ConstantInt::get(Type::getInt32Ty(VMContext), 0), + ConstantInt::get(Type::getInt32Ty(VMContext), 0), + llvm::Constant::getNullValue(Type::getInt32Ty(VMContext)), + ConstantInt::get(Type::getInt32Ty(VMContext), Flags), + ConstantInt::get(Type::getInt1Ty(VMContext), isOptimized), + Fn + }; + MDNode *Node = MDNode::get(VMContext, &Elts[0], array_lengthof(Elts)); + + // Create a named metadata so that we do not lose this mdnode. + NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.sp"); + NMD->addOperand(Node); + return DISubprogram(Node); +} + +/// CreateMethod - Create a new descriptor for the specified C++ method. +DISubprogram DIBuilder::CreateMethod(DIDescriptor Context, + StringRef Name, + StringRef LinkageName, + DIFile F, + unsigned LineNo, DIType Ty, + bool isLocalToUnit, + bool isDefinition, + unsigned VK, unsigned VIndex, + MDNode *VTableHolder, + unsigned Flags, + bool isOptimized, + Function *Fn) { + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_subprogram), + llvm::Constant::getNullValue(Type::getInt32Ty(VMContext)), + Context, + MDString::get(VMContext, Name), + MDString::get(VMContext, Name), + MDString::get(VMContext, LinkageName), + F, + ConstantInt::get(Type::getInt32Ty(VMContext), LineNo), + Ty, + ConstantInt::get(Type::getInt1Ty(VMContext), isLocalToUnit), + ConstantInt::get(Type::getInt1Ty(VMContext), isDefinition), + ConstantInt::get(Type::getInt32Ty(VMContext), (unsigned)VK), + ConstantInt::get(Type::getInt32Ty(VMContext), VIndex), + VTableHolder, + ConstantInt::get(Type::getInt32Ty(VMContext), Flags), + ConstantInt::get(Type::getInt1Ty(VMContext), isOptimized), + Fn + }; + MDNode *Node = MDNode::get(VMContext, &Elts[0], array_lengthof(Elts)); + + // Create a named metadata so that we do not lose this mdnode. + NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.sp"); + NMD->addOperand(Node); + return DISubprogram(Node); +} + +/// CreateNameSpace - This creates new descriptor for a namespace +/// with the specified parent scope. +DINameSpace DIBuilder::CreateNameSpace(DIDescriptor Scope, StringRef Name, + DIFile File, unsigned LineNo) { + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_namespace), + Scope, + MDString::get(VMContext, Name), + File, + ConstantInt::get(Type::getInt32Ty(VMContext), LineNo) + }; + return DINameSpace(MDNode::get(VMContext, &Elts[0], array_lengthof(Elts))); +} + +DILexicalBlock DIBuilder::CreateLexicalBlock(DIDescriptor Scope, DIFile File, + unsigned Line, unsigned Col) { + // Defeat MDNode uniqing for lexical blocks by using unique id. + static unsigned int unique_id = 0; + Value *Elts[] = { + GetTagConstant(VMContext, dwarf::DW_TAG_lexical_block), + Scope, + ConstantInt::get(Type::getInt32Ty(VMContext), Line), + ConstantInt::get(Type::getInt32Ty(VMContext), Col), + File, + ConstantInt::get(Type::getInt32Ty(VMContext), unique_id++) + }; + return DILexicalBlock(MDNode::get(VMContext, &Elts[0], array_lengthof(Elts))); +} + +/// InsertDeclare - Insert a new llvm.dbg.declare intrinsic call. +Instruction *DIBuilder::InsertDeclare(Value *Storage, DIVariable VarInfo, + Instruction *InsertBefore) { + assert(Storage && "no storage passed to dbg.declare"); + assert(VarInfo.Verify() && "empty DIVariable passed to dbg.declare"); + if (!DeclareFn) + DeclareFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_declare); + + Value *Args[] = { MDNode::get(Storage->getContext(), &Storage, 1), VarInfo }; + return CallInst::Create(DeclareFn, Args, Args+2, "", InsertBefore); +} + +/// InsertDeclare - Insert a new llvm.dbg.declare intrinsic call. +Instruction *DIBuilder::InsertDeclare(Value *Storage, DIVariable VarInfo, + BasicBlock *InsertAtEnd) { + assert(Storage && "no storage passed to dbg.declare"); + assert(VarInfo.Verify() && "invalid DIVariable passed to dbg.declare"); + if (!DeclareFn) + DeclareFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_declare); + + Value *Args[] = { MDNode::get(Storage->getContext(), &Storage, 1), VarInfo }; + + // If this block already has a terminator then insert this intrinsic + // before the terminator. + if (TerminatorInst *T = InsertAtEnd->getTerminator()) + return CallInst::Create(DeclareFn, Args, Args+2, "", T); + else + return CallInst::Create(DeclareFn, Args, Args+2, "", InsertAtEnd); +} + +/// InsertDbgValueIntrinsic - Insert a new llvm.dbg.value intrinsic call. +Instruction *DIBuilder::InsertDbgValueIntrinsic(Value *V, uint64_t Offset, + DIVariable VarInfo, + Instruction *InsertBefore) { + assert(V && "no value passed to dbg.value"); + assert(VarInfo.Verify() && "invalid DIVariable passed to dbg.value"); + if (!ValueFn) + ValueFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_value); + + Value *Args[] = { MDNode::get(V->getContext(), &V, 1), + ConstantInt::get(Type::getInt64Ty(V->getContext()), Offset), + VarInfo }; + return CallInst::Create(ValueFn, Args, Args+3, "", InsertBefore); +} + +/// InsertDbgValueIntrinsic - Insert a new llvm.dbg.value intrinsic call. +Instruction *DIBuilder::InsertDbgValueIntrinsic(Value *V, uint64_t Offset, + DIVariable VarInfo, + BasicBlock *InsertAtEnd) { + assert(V && "no value passed to dbg.value"); + assert(VarInfo.Verify() && "invalid DIVariable passed to dbg.value"); + if (!ValueFn) + ValueFn = Intrinsic::getDeclaration(&M, Intrinsic::dbg_value); + + Value *Args[] = { MDNode::get(V->getContext(), &V, 1), + ConstantInt::get(Type::getInt64Ty(V->getContext()), Offset), + VarInfo }; + return CallInst::Create(ValueFn, Args, Args+3, "", InsertAtEnd); +} + diff --git a/lib/Analysis/DbgInfoPrinter.cpp b/lib/Analysis/DbgInfoPrinter.cpp index 056775060610..b23c3514d0bd 100644 --- a/lib/Analysis/DbgInfoPrinter.cpp +++ b/lib/Analysis/DbgInfoPrinter.cpp @@ -20,6 +20,7 @@ #include "llvm/Function.h" #include "llvm/IntrinsicInst.h" #include "llvm/Metadata.h" +#include "llvm/Module.h" #include "llvm/Assembly/Writer.h" #include "llvm/Analysis/DebugInfo.h" #include "llvm/Analysis/Passes.h" @@ -40,7 +41,9 @@ namespace { void printVariableDeclaration(const Value *V); public: static char ID; // Pass identification - PrintDbgInfo() : FunctionPass(ID), Out(errs()) {} + PrintDbgInfo() : FunctionPass(ID), Out(errs()) { + initializePrintDbgInfoPass(*PassRegistry::getPassRegistry()); + } virtual bool runOnFunction(Function &F); virtual void getAnalysisUsage(AnalysisUsage &AU) const { @@ -48,12 +51,124 @@ namespace { } }; char PrintDbgInfo::ID = 0; - INITIALIZE_PASS(PrintDbgInfo, "print-dbginfo", - "Print debug info in human readable form", false, false); } +INITIALIZE_PASS(PrintDbgInfo, "print-dbginfo", + "Print debug info in human readable form", false, false) + FunctionPass *llvm::createDbgInfoPrinterPass() { return new PrintDbgInfo(); } +/// Find the debug info descriptor corresponding to this global variable. +static Value *findDbgGlobalDeclare(GlobalVariable *V) { + const Module *M = V->getParent(); + NamedMDNode *NMD = M->getNamedMetadata("llvm.dbg.gv"); + if (!NMD) + return 0; + + for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { + DIDescriptor DIG(cast(NMD->getOperand(i))); + if (!DIG.isGlobalVariable()) + continue; + if (DIGlobalVariable(DIG).getGlobal() == V) + return DIG; + } + return 0; +} + +/// Find the debug info descriptor corresponding to this function. +static Value *findDbgSubprogramDeclare(Function *V) { + const Module *M = V->getParent(); + NamedMDNode *NMD = M->getNamedMetadata("llvm.dbg.sp"); + if (!NMD) + return 0; + + for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { + DIDescriptor DIG(cast(NMD->getOperand(i))); + if (!DIG.isSubprogram()) + continue; + if (DISubprogram(DIG).getFunction() == V) + return DIG; + } + return 0; +} + +/// Finds the llvm.dbg.declare intrinsic corresponding to this value if any. +/// It looks through pointer casts too. +static const DbgDeclareInst *findDbgDeclare(const Value *V) { + V = V->stripPointerCasts(); + + if (!isa(V) && !isa(V)) + return 0; + + const Function *F = NULL; + if (const Instruction *I = dyn_cast(V)) + F = I->getParent()->getParent(); + else if (const Argument *A = dyn_cast(V)) + F = A->getParent(); + + for (Function::const_iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI) + for (BasicBlock::const_iterator BI = (*FI).begin(), BE = (*FI).end(); + BI != BE; ++BI) + if (const DbgDeclareInst *DDI = dyn_cast(BI)) + if (DDI->getAddress() == V) + return DDI; + + return 0; +} + +static bool getLocationInfo(const Value *V, std::string &DisplayName, + std::string &Type, unsigned &LineNo, + std::string &File, std::string &Dir) { + DICompileUnit Unit; + DIType TypeD; + + if (GlobalVariable *GV = dyn_cast(const_cast(V))) { + Value *DIGV = findDbgGlobalDeclare(GV); + if (!DIGV) return false; + DIGlobalVariable Var(cast(DIGV)); + + StringRef D = Var.getDisplayName(); + if (!D.empty()) + DisplayName = D; + LineNo = Var.getLineNumber(); + Unit = Var.getCompileUnit(); + TypeD = Var.getType(); + } else if (Function *F = dyn_cast(const_cast(V))){ + Value *DIF = findDbgSubprogramDeclare(F); + if (!DIF) return false; + DISubprogram Var(cast(DIF)); + + StringRef D = Var.getDisplayName(); + if (!D.empty()) + DisplayName = D; + LineNo = Var.getLineNumber(); + Unit = Var.getCompileUnit(); + TypeD = Var.getType(); + } else { + const DbgDeclareInst *DDI = findDbgDeclare(V); + if (!DDI) return false; + DIVariable Var(cast(DDI->getVariable())); + + StringRef D = Var.getName(); + if (!D.empty()) + DisplayName = D; + LineNo = Var.getLineNumber(); + Unit = Var.getCompileUnit(); + TypeD = Var.getType(); + } + + StringRef T = TypeD.getName(); + if (!T.empty()) + Type = T; + StringRef F = Unit.getFilename(); + if (!F.empty()) + File = F; + StringRef D = Unit.getDirectory(); + if (!D.empty()) + Dir = D; + return true; +} + void PrintDbgInfo::printVariableDeclaration(const Value *V) { std::string DisplayName, File, Directory, Type; unsigned LineNo; @@ -63,8 +178,12 @@ void PrintDbgInfo::printVariableDeclaration(const Value *V) { Out << "; "; WriteAsOperand(Out, V, false, 0); - Out << " is variable " << DisplayName - << " of type " << Type << " declared at "; + if (isa(V)) + Out << " is function " << DisplayName + << " of type " << Type << " declared at "; + else + Out << " is variable " << DisplayName + << " of type " << Type << " declared at "; if (PrintDirectory) Out << Directory << "/"; diff --git a/lib/Analysis/DebugInfo.cpp b/lib/Analysis/DebugInfo.cpp index 5ca89c658df6..9db1456edd05 100644 --- a/lib/Analysis/DebugInfo.cpp +++ b/lib/Analysis/DebugInfo.cpp @@ -109,7 +109,9 @@ Function *DIDescriptor::getFunctionField(unsigned Elt) const { } unsigned DIVariable::getNumAddrElements() const { - return DbgNode->getNumOperands()-6; + if (getVersion() <= llvm::LLVMDebugVersion8) + return DbgNode->getNumOperands()-6; + return DbgNode->getNumOperands()-7; } @@ -197,6 +199,12 @@ bool DIDescriptor::isGlobal() const { return isGlobalVariable(); } +/// isUnspecifiedParmeter - Return true if the specified tag is +/// DW_TAG_unspecified_parameters. +bool DIDescriptor::isUnspecifiedParameter() const { + return DbgNode && getTag() == dwarf::DW_TAG_unspecified_parameters; +} + /// isScope - Return true if the specified tag is one of the scope /// related tag. bool DIDescriptor::isScope() const { @@ -213,6 +221,18 @@ bool DIDescriptor::isScope() const { return false; } +/// isTemplateTypeParameter - Return true if the specified tag is +/// DW_TAG_template_type_parameter. +bool DIDescriptor::isTemplateTypeParameter() const { + return DbgNode && getTag() == dwarf::DW_TAG_template_type_parameter; +} + +/// isTemplateValueParameter - Return true if the specified tag is +/// DW_TAG_template_value_parameter. +bool DIDescriptor::isTemplateValueParameter() const { + return DbgNode && getTag() == dwarf::DW_TAG_template_value_parameter; +} + /// isCompileUnit - Return true if the specified tag is DW_TAG_compile_unit. bool DIDescriptor::isCompileUnit() const { return DbgNode && getTag() == dwarf::DW_TAG_compile_unit; @@ -280,6 +300,26 @@ void DIType::replaceAllUsesWith(DIDescriptor &D) { } } +/// replaceAllUsesWith - Replace all uses of debug info referenced by +/// this descriptor. +void DIType::replaceAllUsesWith(MDNode *D) { + if (!DbgNode) + return; + + // Since we use a TrackingVH for the node, its easy for clients to manufacture + // legitimate situations where they want to replaceAllUsesWith() on something + // which, due to uniquing, has merged with the source. We shield clients from + // this detail by allowing a value to be replaced with replaceAllUsesWith() + // itself. + if (DbgNode != D) { + MDNode *Node = const_cast(DbgNode); + const MDNode *DN = D; + const Value *V = cast_or_null(DN); + Node->replaceAllUsesWith(const_cast(V)); + MDNode::deleteTemporary(Node); + } +} + /// Verify - Verify that a compile unit is well formed. bool DICompileUnit::Verify() const { if (!DbgNode) @@ -297,9 +337,13 @@ bool DIType::Verify() const { return false; if (!getContext().Verify()) return false; - - DICompileUnit CU = getCompileUnit(); - if (!CU.Verify()) + unsigned Tag = getTag(); + if (!isBasicType() && Tag != dwarf::DW_TAG_const_type && + Tag != dwarf::DW_TAG_volatile_type && Tag != dwarf::DW_TAG_pointer_type && + Tag != dwarf::DW_TAG_reference_type && Tag != dwarf::DW_TAG_restrict_type + && Tag != dwarf::DW_TAG_vector_type && Tag != dwarf::DW_TAG_array_type + && Tag != dwarf::DW_TAG_enumeration_type + && getFilename().empty()) return false; return true; } @@ -701,15 +745,13 @@ Constant *DIFactory::GetTagConstant(unsigned TAG) { /// GetOrCreateArray - Create an descriptor for an array of descriptors. /// This implicitly uniques the arrays created. DIArray DIFactory::GetOrCreateArray(DIDescriptor *Tys, unsigned NumTys) { - SmallVector Elts; - - if (NumTys == 0) - Elts.push_back(llvm::Constant::getNullValue(Type::getInt32Ty(VMContext))); - else - for (unsigned i = 0; i != NumTys; ++i) - Elts.push_back(Tys[i]); + if (NumTys == 0) { + Value *Null = llvm::Constant::getNullValue(Type::getInt32Ty(VMContext)); + return DIArray(MDNode::get(VMContext, &Null, 1)); + } - return DIArray(MDNode::get(VMContext,Elts.data(), Elts.size())); + SmallVector Elts(Tys, Tys+NumTys); + return DIArray(MDNode::get(VMContext, Elts.data(), Elts.size())); } /// GetOrCreateSubrange - Create a descriptor for a value range. This @@ -724,7 +766,14 @@ DISubrange DIFactory::GetOrCreateSubrange(int64_t Lo, int64_t Hi) { return DISubrange(MDNode::get(VMContext, &Elts[0], 3)); } - +/// CreateUnspecifiedParameter - Create unspeicified type descriptor +/// for the subroutine type. +DIDescriptor DIFactory::CreateUnspecifiedParameter() { + Value *Elts[] = { + GetTagConstant(dwarf::DW_TAG_unspecified_parameters) + }; + return DIDescriptor(MDNode::get(VMContext, &Elts[0], 1)); +} /// CreateCompileUnit - Create a new descriptor for the specified compile /// unit. Note that this does not unique compile units within the module. @@ -946,7 +995,6 @@ DICompositeType DIFactory::CreateCompositeType(unsigned Tag, return DICompositeType(Node); } - /// CreateTemporaryType - Create a temporary forward-declared type. DIType DIFactory::CreateTemporaryType() { // Give the temporary MDNode a tag. It doesn't matter what tag we @@ -958,6 +1006,19 @@ DIType DIFactory::CreateTemporaryType() { return DIType(Node); } +/// CreateTemporaryType - Create a temporary forward-declared type. +DIType DIFactory::CreateTemporaryType(DIFile F) { + // Give the temporary MDNode a tag. It doesn't matter what tag we + // use here as long as DIType accepts it. + Value *Elts[] = { + GetTagConstant(DW_TAG_base_type), + F.getCompileUnit(), + NULL, + F + }; + MDNode *Node = MDNode::getTemporary(VMContext, Elts, array_lengthof(Elts)); + return DIType(Node); +} /// CreateCompositeType - Create a composite type like array, struct, etc. DICompositeType DIFactory::CreateCompositeTypeEx(unsigned Tag, @@ -1011,7 +1072,7 @@ DISubprogram DIFactory::CreateSubprogram(DIDescriptor Context, bool isDefinition, unsigned VK, unsigned VIndex, DIType ContainingType, - bool isArtificial, + unsigned Flags, bool isOptimized, Function *Fn) { @@ -1030,7 +1091,7 @@ DISubprogram DIFactory::CreateSubprogram(DIDescriptor Context, ConstantInt::get(Type::getInt32Ty(VMContext), (unsigned)VK), ConstantInt::get(Type::getInt32Ty(VMContext), VIndex), ContainingType, - ConstantInt::get(Type::getInt1Ty(VMContext), isArtificial), + ConstantInt::get(Type::getInt32Ty(VMContext), Flags), ConstantInt::get(Type::getInt1Ty(VMContext), isOptimized), Fn }; @@ -1064,7 +1125,7 @@ DISubprogram DIFactory::CreateSubprogramDefinition(DISubprogram &SPDeclaration){ DeclNode->getOperand(11), // Virtuality DeclNode->getOperand(12), // VIndex DeclNode->getOperand(13), // Containting Type - DeclNode->getOperand(14), // isArtificial + DeclNode->getOperand(14), // Flags DeclNode->getOperand(15), // isOptimized SPDeclaration.getFunction() }; @@ -1142,12 +1203,47 @@ DIFactory::CreateGlobalVariable(DIDescriptor Context, StringRef Name, return DIGlobalVariable(Node); } +/// fixupObjcLikeName - Replace contains special characters used +/// in a typical Objective-C names with '.' in a given string. +static void fixupObjcLikeName(std::string &Str) { + for (size_t i = 0, e = Str.size(); i < e; ++i) { + char C = Str[i]; + if (C == '[' || C == ']' || C == ' ' || C == ':' || C == '+' || + C == '(' || C == ')') + Str[i] = '.'; + } +} + +/// getOrInsertFnSpecificMDNode - Return a NameMDNode that is suitable +/// to hold function specific information. +NamedMDNode *llvm::getOrInsertFnSpecificMDNode(Module &M, StringRef FuncName) { + SmallString<32> Out; + if (FuncName.find('[') == StringRef::npos) + return M.getOrInsertNamedMetadata(Twine("llvm.dbg.lv.", FuncName) + .toStringRef(Out)); + std::string Name = FuncName; + fixupObjcLikeName(Name); + return M.getOrInsertNamedMetadata(Twine("llvm.dbg.lv.", Name) + .toStringRef(Out)); +} + +/// getFnSpecificMDNode - Return a NameMDNode, if available, that is +/// suitable to hold function specific information. +NamedMDNode *llvm::getFnSpecificMDNode(const Module &M, StringRef FuncName) { + if (FuncName.find('[') == StringRef::npos) + return M.getNamedMetadata(Twine("llvm.dbg.lv.", FuncName)); + std::string Name = FuncName; + fixupObjcLikeName(Name); + return M.getNamedMetadata(Twine("llvm.dbg.lv.", Name)); +} + /// CreateVariable - Create a new descriptor for the specified variable. DIVariable DIFactory::CreateVariable(unsigned Tag, DIDescriptor Context, StringRef Name, DIFile F, unsigned LineNo, - DIType Ty, bool AlwaysPreserve) { + DIType Ty, bool AlwaysPreserve, + unsigned Flags) { Value *Elts[] = { GetTagConstant(Tag), Context, @@ -1155,8 +1251,9 @@ DIVariable DIFactory::CreateVariable(unsigned Tag, DIDescriptor Context, F, ConstantInt::get(Type::getInt32Ty(VMContext), LineNo), Ty, + ConstantInt::get(Type::getInt32Ty(VMContext), Flags) }; - MDNode *Node = MDNode::get(VMContext, &Elts[0], 6); + MDNode *Node = MDNode::get(VMContext, &Elts[0], 7); if (AlwaysPreserve) { // The optimizer may remove local variable. If there is an interest // to preserve variable info in such situation then stash it in a @@ -1169,9 +1266,8 @@ DIVariable DIFactory::CreateVariable(unsigned Tag, DIDescriptor Context, if (FName.startswith(StringRef(&One, 1))) FName = FName.substr(1); - SmallString<32> Out; - NamedMDNode *FnLocals = - M.getOrInsertNamedMetadata(Twine("llvm.dbg.lv.", FName).toStringRef(Out)); + + NamedMDNode *FnLocals = getOrInsertFnSpecificMDNode(M, FName); FnLocals->addOperand(Node); } return DIVariable(Node); @@ -1181,21 +1277,20 @@ DIVariable DIFactory::CreateVariable(unsigned Tag, DIDescriptor Context, /// CreateComplexVariable - Create a new descriptor for the specified variable /// which has a complex address expression for its address. DIVariable DIFactory::CreateComplexVariable(unsigned Tag, DIDescriptor Context, - const std::string &Name, - DIFile F, + StringRef Name, DIFile F, unsigned LineNo, - DIType Ty, - SmallVector &addr) { - SmallVector Elts; + DIType Ty, Value *const *Addr, + unsigned NumAddr) { + SmallVector Elts; Elts.push_back(GetTagConstant(Tag)); Elts.push_back(Context); Elts.push_back(MDString::get(VMContext, Name)); Elts.push_back(F); Elts.push_back(ConstantInt::get(Type::getInt32Ty(VMContext), LineNo)); Elts.push_back(Ty); - Elts.insert(Elts.end(), addr.begin(), addr.end()); + Elts.append(Addr, Addr+NumAddr); - return DIVariable(MDNode::get(VMContext, &Elts[0], 6+addr.size())); + return DIVariable(MDNode::get(VMContext, Elts.data(), Elts.size())); } @@ -1309,6 +1404,14 @@ Instruction *DIFactory::InsertDbgValueIntrinsic(Value *V, uint64_t Offset, return CallInst::Create(ValueFn, Args, Args+3, "", InsertAtEnd); } +// RecordType - Record DIType in a module such that it is not lost even if +// it is not referenced through debug info anchors. +void DIFactory::RecordType(DIType T) { + NamedMDNode *NMD = M.getOrInsertNamedMetadata("llvm.dbg.ty"); + NMD->addOperand(T); +} + + //===----------------------------------------------------------------------===// // DebugInfoFinder implementations. //===----------------------------------------------------------------------===// @@ -1472,89 +1575,6 @@ bool DebugInfoFinder::addSubprogram(DISubprogram SP) { return true; } -/// Find the debug info descriptor corresponding to this global variable. -static Value *findDbgGlobalDeclare(GlobalVariable *V) { - const Module *M = V->getParent(); - NamedMDNode *NMD = M->getNamedMetadata("llvm.dbg.gv"); - if (!NMD) - return 0; - - for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { - DIDescriptor DIG(cast(NMD->getOperand(i))); - if (!DIG.isGlobalVariable()) - continue; - if (DIGlobalVariable(DIG).getGlobal() == V) - return DIG; - } - return 0; -} - -/// Finds the llvm.dbg.declare intrinsic corresponding to this value if any. -/// It looks through pointer casts too. -static const DbgDeclareInst *findDbgDeclare(const Value *V) { - V = V->stripPointerCasts(); - - if (!isa(V) && !isa(V)) - return 0; - - const Function *F = NULL; - if (const Instruction *I = dyn_cast(V)) - F = I->getParent()->getParent(); - else if (const Argument *A = dyn_cast(V)) - F = A->getParent(); - - for (Function::const_iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI) - for (BasicBlock::const_iterator BI = (*FI).begin(), BE = (*FI).end(); - BI != BE; ++BI) - if (const DbgDeclareInst *DDI = dyn_cast(BI)) - if (DDI->getAddress() == V) - return DDI; - - return 0; -} - -bool llvm::getLocationInfo(const Value *V, std::string &DisplayName, - std::string &Type, unsigned &LineNo, - std::string &File, std::string &Dir) { - DICompileUnit Unit; - DIType TypeD; - - if (GlobalVariable *GV = dyn_cast(const_cast(V))) { - Value *DIGV = findDbgGlobalDeclare(GV); - if (!DIGV) return false; - DIGlobalVariable Var(cast(DIGV)); - - StringRef D = Var.getDisplayName(); - if (!D.empty()) - DisplayName = D; - LineNo = Var.getLineNumber(); - Unit = Var.getCompileUnit(); - TypeD = Var.getType(); - } else { - const DbgDeclareInst *DDI = findDbgDeclare(V); - if (!DDI) return false; - DIVariable Var(cast(DDI->getVariable())); - - StringRef D = Var.getName(); - if (!D.empty()) - DisplayName = D; - LineNo = Var.getLineNumber(); - Unit = Var.getCompileUnit(); - TypeD = Var.getType(); - } - - StringRef T = TypeD.getName(); - if (!T.empty()) - Type = T; - StringRef F = Unit.getFilename(); - if (!F.empty()) - File = F; - StringRef D = Unit.getDirectory(); - if (!D.empty()) - Dir = D; - return true; -} - /// getDISubprogram - Find subprogram that is enclosing this scope. DISubprogram llvm::getDISubprogram(const MDNode *Scope) { DIDescriptor D(Scope); diff --git a/lib/Analysis/DomPrinter.cpp b/lib/Analysis/DomPrinter.cpp index 9f340942f2cc..cde431459d50 100644 --- a/lib/Analysis/DomPrinter.cpp +++ b/lib/Analysis/DomPrinter.cpp @@ -19,8 +19,6 @@ //===----------------------------------------------------------------------===// #include "llvm/Analysis/DomPrinter.h" - -#include "llvm/Analysis/Dominators.h" #include "llvm/Analysis/DOTGraphTraitsPass.h" #include "llvm/Analysis/PostDominators.h" @@ -86,74 +84,90 @@ namespace { struct DomViewer : public DOTGraphTraitsViewer { static char ID; - DomViewer() : DOTGraphTraitsViewer("dom", ID){} + DomViewer() : DOTGraphTraitsViewer("dom", ID){ + initializeDomViewerPass(*PassRegistry::getPassRegistry()); + } }; struct DomOnlyViewer : public DOTGraphTraitsViewer { static char ID; - DomOnlyViewer() : DOTGraphTraitsViewer("domonly", ID){} + DomOnlyViewer() : DOTGraphTraitsViewer("domonly", ID){ + initializeDomOnlyViewerPass(*PassRegistry::getPassRegistry()); + } }; struct PostDomViewer : public DOTGraphTraitsViewer { static char ID; PostDomViewer() : - DOTGraphTraitsViewer("postdom", ID){} + DOTGraphTraitsViewer("postdom", ID){ + initializePostDomViewerPass(*PassRegistry::getPassRegistry()); + } }; struct PostDomOnlyViewer : public DOTGraphTraitsViewer { static char ID; PostDomOnlyViewer() : - DOTGraphTraitsViewer("postdomonly", ID){} + DOTGraphTraitsViewer("postdomonly", ID){ + initializePostDomOnlyViewerPass(*PassRegistry::getPassRegistry()); + } }; } // end anonymous namespace char DomViewer::ID = 0; INITIALIZE_PASS(DomViewer, "view-dom", - "View dominance tree of function", false, false); + "View dominance tree of function", false, false) char DomOnlyViewer::ID = 0; INITIALIZE_PASS(DomOnlyViewer, "view-dom-only", "View dominance tree of function (with no function bodies)", - false, false); + false, false) char PostDomViewer::ID = 0; INITIALIZE_PASS(PostDomViewer, "view-postdom", - "View postdominance tree of function", false, false); + "View postdominance tree of function", false, false) char PostDomOnlyViewer::ID = 0; INITIALIZE_PASS(PostDomOnlyViewer, "view-postdom-only", "View postdominance tree of function " "(with no function bodies)", - false, false); + false, false) namespace { struct DomPrinter : public DOTGraphTraitsPrinter { static char ID; - DomPrinter() : DOTGraphTraitsPrinter("dom", ID) {} + DomPrinter() : DOTGraphTraitsPrinter("dom", ID) { + initializeDomPrinterPass(*PassRegistry::getPassRegistry()); + } }; struct DomOnlyPrinter : public DOTGraphTraitsPrinter { static char ID; - DomOnlyPrinter() : DOTGraphTraitsPrinter("domonly", ID) {} + DomOnlyPrinter() : DOTGraphTraitsPrinter("domonly", ID) { + initializeDomOnlyPrinterPass(*PassRegistry::getPassRegistry()); + } }; struct PostDomPrinter : public DOTGraphTraitsPrinter { static char ID; PostDomPrinter() : - DOTGraphTraitsPrinter("postdom", ID) {} + DOTGraphTraitsPrinter("postdom", ID) { + initializePostDomPrinterPass(*PassRegistry::getPassRegistry()); + } }; struct PostDomOnlyPrinter : public DOTGraphTraitsPrinter { static char ID; PostDomOnlyPrinter() : - DOTGraphTraitsPrinter("postdomonly", ID) {} + DOTGraphTraitsPrinter("postdomonly", ID) { + initializePostDomOnlyPrinterPass(*PassRegistry::getPassRegistry()); + } }; } // end anonymous namespace @@ -162,24 +176,24 @@ struct PostDomOnlyPrinter char DomPrinter::ID = 0; INITIALIZE_PASS(DomPrinter, "dot-dom", "Print dominance tree of function to 'dot' file", - false, false); + false, false) char DomOnlyPrinter::ID = 0; INITIALIZE_PASS(DomOnlyPrinter, "dot-dom-only", "Print dominance tree of function to 'dot' file " "(with no function bodies)", - false, false); + false, false) char PostDomPrinter::ID = 0; INITIALIZE_PASS(PostDomPrinter, "dot-postdom", "Print postdominance tree of function to 'dot' file", - false, false); + false, false) char PostDomOnlyPrinter::ID = 0; INITIALIZE_PASS(PostDomOnlyPrinter, "dot-postdom-only", "Print postdominance tree of function to 'dot' file " "(with no function bodies)", - false, false); + false, false) // Create methods available outside of this file, to use them // "include/llvm/LinkAllPasses.h". Otherwise the pass would be deleted by diff --git a/lib/Analysis/DominanceFrontier.cpp b/lib/Analysis/DominanceFrontier.cpp new file mode 100644 index 000000000000..6de4e1e1d7de --- /dev/null +++ b/lib/Analysis/DominanceFrontier.cpp @@ -0,0 +1,137 @@ +//===- DominanceFrontier.cpp - Dominance Frontier Calculation -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/DominanceFrontier.h" +#include "llvm/Support/Debug.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Assembly/Writer.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +char DominanceFrontier::ID = 0; +INITIALIZE_PASS_BEGIN(DominanceFrontier, "domfrontier", + "Dominance Frontier Construction", true, true) +INITIALIZE_PASS_DEPENDENCY(DominatorTree) +INITIALIZE_PASS_END(DominanceFrontier, "domfrontier", + "Dominance Frontier Construction", true, true) + +namespace { + class DFCalculateWorkObject { + public: + DFCalculateWorkObject(BasicBlock *B, BasicBlock *P, + const DomTreeNode *N, + const DomTreeNode *PN) + : currentBB(B), parentBB(P), Node(N), parentNode(PN) {} + BasicBlock *currentBB; + BasicBlock *parentBB; + const DomTreeNode *Node; + const DomTreeNode *parentNode; + }; +} + +const DominanceFrontier::DomSetType & +DominanceFrontier::calculate(const DominatorTree &DT, + const DomTreeNode *Node) { + BasicBlock *BB = Node->getBlock(); + DomSetType *Result = NULL; + + std::vector workList; + SmallPtrSet visited; + + workList.push_back(DFCalculateWorkObject(BB, NULL, Node, NULL)); + do { + DFCalculateWorkObject *currentW = &workList.back(); + assert (currentW && "Missing work object."); + + BasicBlock *currentBB = currentW->currentBB; + BasicBlock *parentBB = currentW->parentBB; + const DomTreeNode *currentNode = currentW->Node; + const DomTreeNode *parentNode = currentW->parentNode; + assert (currentBB && "Invalid work object. Missing current Basic Block"); + assert (currentNode && "Invalid work object. Missing current Node"); + DomSetType &S = Frontiers[currentBB]; + + // Visit each block only once. + if (visited.count(currentBB) == 0) { + visited.insert(currentBB); + + // Loop over CFG successors to calculate DFlocal[currentNode] + for (succ_iterator SI = succ_begin(currentBB), SE = succ_end(currentBB); + SI != SE; ++SI) { + // Does Node immediately dominate this successor? + if (DT[*SI]->getIDom() != currentNode) + S.insert(*SI); + } + } + + // At this point, S is DFlocal. Now we union in DFup's of our children... + // Loop through and visit the nodes that Node immediately dominates (Node's + // children in the IDomTree) + bool visitChild = false; + for (DomTreeNode::const_iterator NI = currentNode->begin(), + NE = currentNode->end(); NI != NE; ++NI) { + DomTreeNode *IDominee = *NI; + BasicBlock *childBB = IDominee->getBlock(); + if (visited.count(childBB) == 0) { + workList.push_back(DFCalculateWorkObject(childBB, currentBB, + IDominee, currentNode)); + visitChild = true; + } + } + + // If all children are visited or there is any child then pop this block + // from the workList. + if (!visitChild) { + + if (!parentBB) { + Result = &S; + break; + } + + DomSetType::const_iterator CDFI = S.begin(), CDFE = S.end(); + DomSetType &parentSet = Frontiers[parentBB]; + for (; CDFI != CDFE; ++CDFI) { + if (!DT.properlyDominates(parentNode, DT[*CDFI])) + parentSet.insert(*CDFI); + } + workList.pop_back(); + } + + } while (!workList.empty()); + + return *Result; +} + +void DominanceFrontierBase::print(raw_ostream &OS, const Module* ) const { + for (const_iterator I = begin(), E = end(); I != E; ++I) { + OS << " DomFrontier for BB "; + if (I->first) + WriteAsOperand(OS, I->first, false); + else + OS << " <>"; + OS << " is:\t"; + + const std::set &BBs = I->second; + + for (std::set::const_iterator I = BBs.begin(), E = BBs.end(); + I != E; ++I) { + OS << ' '; + if (*I) + WriteAsOperand(OS, *I, false); + else + OS << "<>"; + } + OS << "\n"; + } +} + +void DominanceFrontierBase::dump() const { + print(dbgs()); +} + diff --git a/lib/Analysis/IPA/CMakeLists.txt b/lib/Analysis/IPA/CMakeLists.txt index 007ad228ae56..8ffef29870ae 100644 --- a/lib/Analysis/IPA/CMakeLists.txt +++ b/lib/Analysis/IPA/CMakeLists.txt @@ -3,4 +3,5 @@ add_llvm_library(LLVMipa CallGraphSCCPass.cpp FindUsedTypes.cpp GlobalsModRef.cpp + IPA.cpp ) diff --git a/lib/Analysis/IPA/CallGraph.cpp b/lib/Analysis/IPA/CallGraph.cpp index b3635283fda5..690c4b4b6f1a 100644 --- a/lib/Analysis/IPA/CallGraph.cpp +++ b/lib/Analysis/IPA/CallGraph.cpp @@ -43,7 +43,9 @@ class BasicCallGraph : public ModulePass, public CallGraph { public: static char ID; // Class identification, replacement for typeinfo BasicCallGraph() : ModulePass(ID), Root(0), - ExternalCallingNode(0), CallsExternalNode(0) {} + ExternalCallingNode(0), CallsExternalNode(0) { + initializeBasicCallGraphPass(*PassRegistry::getPassRegistry()); + } // runOnModule - Compute the call graph for the specified module. virtual bool runOnModule(Module &M) { @@ -171,9 +173,9 @@ private: } //End anonymous namespace -static RegisterAnalysisGroup X("Call Graph"); +INITIALIZE_ANALYSIS_GROUP(CallGraph, "Call Graph", BasicCallGraph) INITIALIZE_AG_PASS(BasicCallGraph, CallGraph, "basiccg", - "Basic CallGraph Construction", false, true, true); + "Basic CallGraph Construction", false, true, true) char CallGraph::ID = 0; char BasicCallGraph::ID = 0; @@ -228,6 +230,21 @@ Function *CallGraph::removeFunctionFromModule(CallGraphNode *CGN) { return F; } +/// spliceFunction - Replace the function represented by this node by another. +/// This does not rescan the body of the function, so it is suitable when +/// splicing the body of the old function to the new while also updating all +/// callers from old to new. +/// +void CallGraph::spliceFunction(const Function *From, const Function *To) { + assert(FunctionMap.count(From) && "No CallGraphNode for function!"); + assert(!FunctionMap.count(To) && + "Pointing CallGraphNode at a function that already exists"); + FunctionMapTy::iterator I = FunctionMap.find(From); + I->second->F = const_cast(To); + FunctionMap[To] = I->second; + FunctionMap.erase(I); +} + // getOrInsertFunction - This method is identical to calling operator[], but // it will insert a new CallGraphNode for the specified function if one does // not already exist. @@ -274,7 +291,6 @@ void CallGraphNode::removeCallEdgeFor(CallSite CS) { } } - // removeAnyCallEdgeTo - This method removes any call edges from this node to // the specified callee function. This takes more time to execute than // removeCallEdgeTo, so it should not be used unless necessary. diff --git a/lib/Analysis/IPA/CallGraphSCCPass.cpp b/lib/Analysis/IPA/CallGraphSCCPass.cpp index b7a27cb288d9..725ab72f5595 100644 --- a/lib/Analysis/IPA/CallGraphSCCPass.cpp +++ b/lib/Analysis/IPA/CallGraphSCCPass.cpp @@ -582,7 +582,6 @@ namespace { public: static char ID; - PrintCallGraphPass() : CallGraphSCCPass(ID), Out(dbgs()) {} PrintCallGraphPass(const std::string &B, raw_ostream &o) : CallGraphSCCPass(ID), Banner(B), Out(o) {} diff --git a/lib/Analysis/IPA/FindUsedTypes.cpp b/lib/Analysis/IPA/FindUsedTypes.cpp index 8eed9d6f68bc..06ae34cfd989 100644 --- a/lib/Analysis/IPA/FindUsedTypes.cpp +++ b/lib/Analysis/IPA/FindUsedTypes.cpp @@ -24,7 +24,7 @@ using namespace llvm; char FindUsedTypes::ID = 0; INITIALIZE_PASS(FindUsedTypes, "print-used-types", - "Find Used Types", false, true); + "Find Used Types", false, true) // IncorporateType - Incorporate one type and all of its subtypes into the // collection of used types. diff --git a/lib/Analysis/IPA/GlobalsModRef.cpp b/lib/Analysis/IPA/GlobalsModRef.cpp index 6759b0afdce3..116aaf418ea0 100644 --- a/lib/Analysis/IPA/GlobalsModRef.cpp +++ b/lib/Analysis/IPA/GlobalsModRef.cpp @@ -24,6 +24,7 @@ #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/MemoryBuiltins.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/InstIterator.h" #include "llvm/ADT/Statistic.h" @@ -88,7 +89,9 @@ namespace { public: static char ID; - GlobalsModRef() : ModulePass(ID) {} + GlobalsModRef() : ModulePass(ID) { + initializeGlobalsModRefPass(*PassRegistry::getPassRegistry()); + } bool runOnModule(Module &M) { InitializeAliasAnalysis(this); // set up super class @@ -106,10 +109,9 @@ namespace { //------------------------------------------------ // Implement the AliasAnalysis API // - AliasResult alias(const Value *V1, unsigned V1Size, - const Value *V2, unsigned V2Size); + AliasResult alias(const Location &LocA, const Location &LocB); ModRefResult getModRefInfo(ImmutableCallSite CS, - const Value *P, unsigned Size); + const Location &Loc); ModRefResult getModRefInfo(ImmutableCallSite CS1, ImmutableCallSite CS2) { return AliasAnalysis::getModRefInfo(CS1, CS2); @@ -119,32 +121,38 @@ namespace { /// called from the specified call site. The call site may be null in which /// case the most generic behavior of this function should be returned. ModRefBehavior getModRefBehavior(const Function *F) { + ModRefBehavior Min = UnknownModRefBehavior; + if (FunctionRecord *FR = getFunctionInfo(F)) { if (FR->FunctionEffect == 0) - return DoesNotAccessMemory; + Min = DoesNotAccessMemory; else if ((FR->FunctionEffect & Mod) == 0) - return OnlyReadsMemory; + Min = OnlyReadsMemory; } - return AliasAnalysis::getModRefBehavior(F); + + return ModRefBehavior(AliasAnalysis::getModRefBehavior(F) & Min); } /// getModRefBehavior - Return the behavior of the specified function if /// called from the specified call site. The call site may be null in which /// case the most generic behavior of this function should be returned. ModRefBehavior getModRefBehavior(ImmutableCallSite CS) { - const Function* F = CS.getCalledFunction(); - if (!F) return AliasAnalysis::getModRefBehavior(CS); - if (FunctionRecord *FR = getFunctionInfo(F)) { - if (FR->FunctionEffect == 0) - return DoesNotAccessMemory; - else if ((FR->FunctionEffect & Mod) == 0) - return OnlyReadsMemory; - } - return AliasAnalysis::getModRefBehavior(CS); + ModRefBehavior Min = UnknownModRefBehavior; + + if (const Function* F = CS.getCalledFunction()) + if (FunctionRecord *FR = getFunctionInfo(F)) { + if (FR->FunctionEffect == 0) + Min = DoesNotAccessMemory; + else if ((FR->FunctionEffect & Mod) == 0) + Min = OnlyReadsMemory; + } + + return ModRefBehavior(AliasAnalysis::getModRefBehavior(CS) & Min); } virtual void deleteValue(Value *V); virtual void copyValue(Value *From, Value *To); + virtual void addEscapingUse(Use &U); /// getAdjustedAnalysisPointer - This method is used when a pass implements /// an analysis interface through multiple inheritance. If needed, it @@ -177,9 +185,13 @@ namespace { } char GlobalsModRef::ID = 0; -INITIALIZE_AG_PASS(GlobalsModRef, AliasAnalysis, +INITIALIZE_AG_PASS_BEGIN(GlobalsModRef, AliasAnalysis, "globalsmodref-aa", "Simple mod/ref analysis for globals", - false, true, false); + false, true, false) +INITIALIZE_AG_DEPENDENCY(CallGraph) +INITIALIZE_AG_PASS_END(GlobalsModRef, AliasAnalysis, + "globalsmodref-aa", "Simple mod/ref analysis for globals", + false, true, false) Pass *llvm::createGlobalsModRefPass() { return new GlobalsModRef(); } @@ -314,7 +326,7 @@ bool GlobalsModRef::AnalyzeIndirectGlobalMemory(GlobalValue *GV) { continue; // Check the value being stored. - Value *Ptr = SI->getOperand(0)->getUnderlyingObject(); + Value *Ptr = GetUnderlyingObject(SI->getOperand(0)); if (isMalloc(Ptr)) { // Okay, easy case. @@ -476,11 +488,11 @@ void GlobalsModRef::AnalyzeCallGraph(CallGraph &CG, Module &M) { /// other is some random pointer, we know there cannot be an alias, because the /// address of the global isn't taken. AliasAnalysis::AliasResult -GlobalsModRef::alias(const Value *V1, unsigned V1Size, - const Value *V2, unsigned V2Size) { +GlobalsModRef::alias(const Location &LocA, + const Location &LocB) { // Get the base object these pointers point to. - const Value *UV1 = V1->getUnderlyingObject(); - const Value *UV2 = V2->getUnderlyingObject(); + const Value *UV1 = GetUnderlyingObject(LocA.Ptr); + const Value *UV2 = GetUnderlyingObject(LocB.Ptr); // If either of the underlying values is a global, they may be non-addr-taken // globals, which we can answer queries about. @@ -528,17 +540,18 @@ GlobalsModRef::alias(const Value *V1, unsigned V1Size, if ((GV1 || GV2) && GV1 != GV2) return NoAlias; - return AliasAnalysis::alias(V1, V1Size, V2, V2Size); + return AliasAnalysis::alias(LocA, LocB); } AliasAnalysis::ModRefResult GlobalsModRef::getModRefInfo(ImmutableCallSite CS, - const Value *P, unsigned Size) { + const Location &Loc) { unsigned Known = ModRef; // If we are asking for mod/ref info of a direct call with a pointer to a // global we are tracking, return information if we have it. - if (const GlobalValue *GV = dyn_cast(P->getUnderlyingObject())) + if (const GlobalValue *GV = + dyn_cast(GetUnderlyingObject(Loc.Ptr))) if (GV->hasLocalLinkage()) if (const Function *F = CS.getCalledFunction()) if (NonAddressTakenGlobals.count(GV)) @@ -547,7 +560,7 @@ GlobalsModRef::getModRefInfo(ImmutableCallSite CS, if (Known == NoModRef) return NoModRef; // No need to query other mod/ref analyses - return ModRefResult(Known & AliasAnalysis::getModRefInfo(CS, P, Size)); + return ModRefResult(Known & AliasAnalysis::getModRefInfo(CS, Loc)); } @@ -584,3 +597,13 @@ void GlobalsModRef::deleteValue(Value *V) { void GlobalsModRef::copyValue(Value *From, Value *To) { AliasAnalysis::copyValue(From, To); } + +void GlobalsModRef::addEscapingUse(Use &U) { + // For the purposes of this analysis, it is conservatively correct to treat + // a newly escaping value equivalently to a deleted one. We could perhaps + // be more precise by processing the new use and attempting to update our + // saved analysis results to accomodate it. + deleteValue(U); + + AliasAnalysis::addEscapingUse(U); +} diff --git a/lib/Analysis/IPA/IPA.cpp b/lib/Analysis/IPA/IPA.cpp new file mode 100644 index 000000000000..0ba2e04c6302 --- /dev/null +++ b/lib/Analysis/IPA/IPA.cpp @@ -0,0 +1,29 @@ +//===-- IPA.cpp -----------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the common initialization routines for the IPA library. +// +//===----------------------------------------------------------------------===// + +#include "llvm/InitializePasses.h" +#include "llvm-c/Initialization.h" + +using namespace llvm; + +/// initializeIPA - Initialize all passes linked into the IPA library. +void llvm::initializeIPA(PassRegistry &Registry) { + initializeBasicCallGraphPass(Registry); + initializeCallGraphAnalysisGroup(Registry); + initializeFindUsedTypesPass(Registry); + initializeGlobalsModRefPass(Registry); +} + +void LLVMInitializeIPA(LLVMPassRegistryRef R) { + initializeIPA(*unwrap(R)); +} diff --git a/lib/Analysis/IVUsers.cpp b/lib/Analysis/IVUsers.cpp index cdf667ad6eed..c8382186df3a 100644 --- a/lib/Analysis/IVUsers.cpp +++ b/lib/Analysis/IVUsers.cpp @@ -21,6 +21,7 @@ #include "llvm/Analysis/Dominators.h" #include "llvm/Analysis/LoopPass.h" #include "llvm/Analysis/ScalarEvolutionExpressions.h" +#include "llvm/Assembly/Writer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -28,7 +29,13 @@ using namespace llvm; char IVUsers::ID = 0; -INITIALIZE_PASS(IVUsers, "iv-users", "Induction Variable Users", false, true); +INITIALIZE_PASS_BEGIN(IVUsers, "iv-users", + "Induction Variable Users", false, true) +INITIALIZE_PASS_DEPENDENCY(LoopInfo) +INITIALIZE_PASS_DEPENDENCY(DominatorTree) +INITIALIZE_PASS_DEPENDENCY(ScalarEvolution) +INITIALIZE_PASS_END(IVUsers, "iv-users", + "Induction Variable Users", false, true) Pass *llvm::createIVUsersPass() { return new IVUsers(); @@ -143,7 +150,8 @@ IVStrideUse &IVUsers::AddUser(Instruction *User, Value *Operand) { } IVUsers::IVUsers() - : LoopPass(ID) { + : LoopPass(ID) { + initializeIVUsersPass(*PassRegistry::getPassRegistry()); } void IVUsers::getAnalysisUsage(AnalysisUsage &AU) const { diff --git a/lib/Analysis/InlineCost.cpp b/lib/Analysis/InlineCost.cpp index 3e550f35c255..47f91cfc3bed 100644 --- a/lib/Analysis/InlineCost.cpp +++ b/lib/Analysis/InlineCost.cpp @@ -16,97 +16,8 @@ #include "llvm/CallingConv.h" #include "llvm/IntrinsicInst.h" #include "llvm/ADT/SmallPtrSet.h" -using namespace llvm; - -// CountCodeReductionForConstant - Figure out an approximation for how many -// instructions will be constant folded if the specified value is constant. -// -unsigned InlineCostAnalyzer::FunctionInfo:: -CountCodeReductionForConstant(Value *V) { - unsigned Reduction = 0; - for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E;++UI){ - User *U = *UI; - if (isa(U) || isa(U)) { - // We will be able to eliminate all but one of the successors. - const TerminatorInst &TI = cast(*U); - const unsigned NumSucc = TI.getNumSuccessors(); - unsigned Instrs = 0; - for (unsigned I = 0; I != NumSucc; ++I) - Instrs += Metrics.NumBBInsts[TI.getSuccessor(I)]; - // We don't know which blocks will be eliminated, so use the average size. - Reduction += InlineConstants::InstrCost*Instrs*(NumSucc-1)/NumSucc; - } else if (CallInst *CI = dyn_cast(U)) { - // Turning an indirect call into a direct call is a BIG win - if (CI->getCalledValue() == V) - Reduction += InlineConstants::IndirectCallBonus; - } else if (InvokeInst *II = dyn_cast(U)) { - // Turning an indirect call into a direct call is a BIG win - if (II->getCalledValue() == V) - Reduction += InlineConstants::IndirectCallBonus; - } else { - // Figure out if this instruction will be removed due to simple constant - // propagation. - Instruction &Inst = cast(*U); - - // We can't constant propagate instructions which have effects or - // read memory. - // - // FIXME: It would be nice to capture the fact that a load from a - // pointer-to-constant-global is actually a *really* good thing to zap. - // Unfortunately, we don't know the pointer that may get propagated here, - // so we can't make this decision. - if (Inst.mayReadFromMemory() || Inst.mayHaveSideEffects() || - isa(Inst)) - continue; - - bool AllOperandsConstant = true; - for (unsigned i = 0, e = Inst.getNumOperands(); i != e; ++i) - if (!isa(Inst.getOperand(i)) && Inst.getOperand(i) != V) { - AllOperandsConstant = false; - break; - } - if (AllOperandsConstant) { - // We will get to remove this instruction... - Reduction += InlineConstants::InstrCost; - - // And any other instructions that use it which become constants - // themselves. - Reduction += CountCodeReductionForConstant(&Inst); - } - } - } - return Reduction; -} - -// CountCodeReductionForAlloca - Figure out an approximation of how much smaller -// the function will be if it is inlined into a context where an argument -// becomes an alloca. -// -unsigned InlineCostAnalyzer::FunctionInfo:: - CountCodeReductionForAlloca(Value *V) { - if (!V->getType()->isPointerTy()) return 0; // Not a pointer - unsigned Reduction = 0; - for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E;++UI){ - Instruction *I = cast(*UI); - if (isa(I) || isa(I)) - Reduction += InlineConstants::InstrCost; - else if (GetElementPtrInst *GEP = dyn_cast(I)) { - // If the GEP has variable indices, we won't be able to do much with it. - if (GEP->hasAllConstantIndices()) - Reduction += CountCodeReductionForAlloca(GEP); - } else if (BitCastInst *BCI = dyn_cast(I)) { - // Track pointer through bitcasts. - Reduction += CountCodeReductionForAlloca(BCI); - } else { - // If there is some other strange instruction, we're not going to be able - // to do much if we inline this. - return 0; - } - } - - return Reduction; -} +using namespace llvm; /// callIsSmall - If a call is likely to lower to a single target instruction, /// or is otherwise deemed small return true. @@ -160,6 +71,12 @@ void CodeMetrics::analyzeBasicBlock(const BasicBlock *BB) { // variables as volatile if they are live across a setjmp call, and they // probably won't do this in callers. if (const Function *F = CS.getCalledFunction()) { + // If a function is both internal and has a single use, then it is + // extremely likely to get inlined in the future (it was probably + // exposed by an interleaved devirtualization pass). + if (F->hasInternalLinkage() && F->hasOneUse()) + ++NumInlineCandidates; + if (F->isDeclaration() && (F->getName() == "setjmp" || F->getName() == "_setjmp")) callsSetJmp = true; @@ -226,6 +143,86 @@ void CodeMetrics::analyzeBasicBlock(const BasicBlock *BB) { NumBBInsts[BB] = NumInsts - NumInstsBeforeThisBB; } +// CountCodeReductionForConstant - Figure out an approximation for how many +// instructions will be constant folded if the specified value is constant. +// +unsigned CodeMetrics::CountCodeReductionForConstant(Value *V) { + unsigned Reduction = 0; + for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E;++UI){ + User *U = *UI; + if (isa(U) || isa(U)) { + // We will be able to eliminate all but one of the successors. + const TerminatorInst &TI = cast(*U); + const unsigned NumSucc = TI.getNumSuccessors(); + unsigned Instrs = 0; + for (unsigned I = 0; I != NumSucc; ++I) + Instrs += NumBBInsts[TI.getSuccessor(I)]; + // We don't know which blocks will be eliminated, so use the average size. + Reduction += InlineConstants::InstrCost*Instrs*(NumSucc-1)/NumSucc; + } else { + // Figure out if this instruction will be removed due to simple constant + // propagation. + Instruction &Inst = cast(*U); + + // We can't constant propagate instructions which have effects or + // read memory. + // + // FIXME: It would be nice to capture the fact that a load from a + // pointer-to-constant-global is actually a *really* good thing to zap. + // Unfortunately, we don't know the pointer that may get propagated here, + // so we can't make this decision. + if (Inst.mayReadFromMemory() || Inst.mayHaveSideEffects() || + isa(Inst)) + continue; + + bool AllOperandsConstant = true; + for (unsigned i = 0, e = Inst.getNumOperands(); i != e; ++i) + if (!isa(Inst.getOperand(i)) && Inst.getOperand(i) != V) { + AllOperandsConstant = false; + break; + } + + if (AllOperandsConstant) { + // We will get to remove this instruction... + Reduction += InlineConstants::InstrCost; + + // And any other instructions that use it which become constants + // themselves. + Reduction += CountCodeReductionForConstant(&Inst); + } + } + } + return Reduction; +} + +// CountCodeReductionForAlloca - Figure out an approximation of how much smaller +// the function will be if it is inlined into a context where an argument +// becomes an alloca. +// +unsigned CodeMetrics::CountCodeReductionForAlloca(Value *V) { + if (!V->getType()->isPointerTy()) return 0; // Not a pointer + unsigned Reduction = 0; + for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E;++UI){ + Instruction *I = cast(*UI); + if (isa(I) || isa(I)) + Reduction += InlineConstants::InstrCost; + else if (GetElementPtrInst *GEP = dyn_cast(I)) { + // If the GEP has variable indices, we won't be able to do much with it. + if (GEP->hasAllConstantIndices()) + Reduction += CountCodeReductionForAlloca(GEP); + } else if (BitCastInst *BCI = dyn_cast(I)) { + // Track pointer through bitcasts. + Reduction += CountCodeReductionForAlloca(BCI); + } else { + // If there is some other strange instruction, we're not going to be able + // to do much if we inline this. + return 0; + } + } + + return Reduction; +} + /// analyzeFunction - Fill in the current structure with information gleaned /// from the specified function. void CodeMetrics::analyzeFunction(Function *F) { @@ -245,76 +242,246 @@ void InlineCostAnalyzer::FunctionInfo::analyzeFunction(Function *F) { if (Metrics.NumRets==1) --Metrics.NumInsts; - // Don't bother calculating argument weights if we are never going to inline - // the function anyway. - if (NeverInline()) - return; - // Check out all of the arguments to the function, figuring out how much // code can be eliminated if one of the arguments is a constant. ArgumentWeights.reserve(F->arg_size()); for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I) - ArgumentWeights.push_back(ArgInfo(CountCodeReductionForConstant(I), - CountCodeReductionForAlloca(I))); + ArgumentWeights.push_back(ArgInfo(Metrics.CountCodeReductionForConstant(I), + Metrics.CountCodeReductionForAlloca(I))); } /// NeverInline - returns true if the function should never be inlined into /// any caller -bool InlineCostAnalyzer::FunctionInfo::NeverInline() -{ +bool InlineCostAnalyzer::FunctionInfo::NeverInline() { return (Metrics.callsSetJmp || Metrics.isRecursive || Metrics.containsIndirectBr); +} +// getSpecializationBonus - The heuristic used to determine the per-call +// performance boost for using a specialization of Callee with argument +// specializedArgNo replaced by a constant. +int InlineCostAnalyzer::getSpecializationBonus(Function *Callee, + SmallVectorImpl &SpecializedArgNos) +{ + if (Callee->mayBeOverridden()) + return 0; + + int Bonus = 0; + // If this function uses the coldcc calling convention, prefer not to + // specialize it. + if (Callee->getCallingConv() == CallingConv::Cold) + Bonus -= InlineConstants::ColdccPenalty; + + // Get information about the callee. + FunctionInfo *CalleeFI = &CachedFunctionInfo[Callee]; + + // If we haven't calculated this information yet, do so now. + if (CalleeFI->Metrics.NumBlocks == 0) + CalleeFI->analyzeFunction(Callee); + unsigned ArgNo = 0; + unsigned i = 0; + for (Function::arg_iterator I = Callee->arg_begin(), E = Callee->arg_end(); + I != E; ++I, ++ArgNo) + if (ArgNo == SpecializedArgNos[i]) { + ++i; + Bonus += CountBonusForConstant(I); + } + + // Calls usually take a long time, so they make the specialization gain + // smaller. + Bonus -= CalleeFI->Metrics.NumCalls * InlineConstants::CallPenalty; + + return Bonus; } -// getInlineCost - The heuristic used to determine if we should inline the -// function call or not. -// -InlineCost InlineCostAnalyzer::getInlineCost(CallSite CS, - SmallPtrSet &NeverInline) { - return getInlineCost(CS, CS.getCalledFunction(), NeverInline); + +// ConstantFunctionBonus - Figure out how much of a bonus we can get for +// possibly devirtualizing a function. We'll subtract the size of the function +// we may wish to inline from the indirect call bonus providing a limit on +// growth. Leave an upper limit of 0 for the bonus - we don't want to penalize +// inlining because we decide we don't want to give a bonus for +// devirtualizing. +int InlineCostAnalyzer::ConstantFunctionBonus(CallSite CS, Constant *C) { + + // This could just be NULL. + if (!C) return 0; + + Function *F = dyn_cast(C); + if (!F) return 0; + + int Bonus = InlineConstants::IndirectCallBonus + getInlineSize(CS, F); + return (Bonus > 0) ? 0 : Bonus; } -InlineCost InlineCostAnalyzer::getInlineCost(CallSite CS, - Function *Callee, - SmallPtrSet &NeverInline) { - Instruction *TheCall = CS.getInstruction(); - Function *Caller = TheCall->getParent()->getParent(); - bool isDirectCall = CS.getCalledFunction() == Callee; +// CountBonusForConstant - Figure out an approximation for how much per-call +// performance boost we can expect if the specified value is constant. +int InlineCostAnalyzer::CountBonusForConstant(Value *V, Constant *C) { + unsigned Bonus = 0; + for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E;++UI){ + User *U = *UI; + if (CallInst *CI = dyn_cast(U)) { + // Turning an indirect call into a direct call is a BIG win + if (CI->getCalledValue() == V) + Bonus += ConstantFunctionBonus(CallSite(CI), C); + } else if (InvokeInst *II = dyn_cast(U)) { + // Turning an indirect call into a direct call is a BIG win + if (II->getCalledValue() == V) + Bonus += ConstantFunctionBonus(CallSite(II), C); + } + // FIXME: Eliminating conditional branches and switches should + // also yield a per-call performance boost. + else { + // Figure out the bonuses that wll accrue due to simple constant + // propagation. + Instruction &Inst = cast(*U); - // Don't inline functions which can be redefined at link-time to mean - // something else. Don't inline functions marked noinline or call sites - // marked noinline. - if (Callee->mayBeOverridden() || - Callee->hasFnAttr(Attribute::NoInline) || NeverInline.count(Callee) || - CS.isNoInline()) - return llvm::InlineCost::getNever(); + // We can't constant propagate instructions which have effects or + // read memory. + // + // FIXME: It would be nice to capture the fact that a load from a + // pointer-to-constant-global is actually a *really* good thing to zap. + // Unfortunately, we don't know the pointer that may get propagated here, + // so we can't make this decision. + if (Inst.mayReadFromMemory() || Inst.mayHaveSideEffects() || + isa(Inst)) + continue; + bool AllOperandsConstant = true; + for (unsigned i = 0, e = Inst.getNumOperands(); i != e; ++i) + if (!isa(Inst.getOperand(i)) && Inst.getOperand(i) != V) { + AllOperandsConstant = false; + break; + } + + if (AllOperandsConstant) + Bonus += CountBonusForConstant(&Inst); + } + } + + return Bonus; +} + +int InlineCostAnalyzer::getInlineSize(CallSite CS, Function *Callee) { + // Get information about the callee. + FunctionInfo *CalleeFI = &CachedFunctionInfo[Callee]; + + // If we haven't calculated this information yet, do so now. + if (CalleeFI->Metrics.NumBlocks == 0) + CalleeFI->analyzeFunction(Callee); + // InlineCost - This value measures how good of an inline candidate this call // site is to inline. A lower inline cost make is more likely for the call to // be inlined. This value may go negative. // int InlineCost = 0; + // Compute any size reductions we can expect due to arguments being passed into + // the function. + // + unsigned ArgNo = 0; + CallSite::arg_iterator I = CS.arg_begin(); + for (Function::arg_iterator FI = Callee->arg_begin(), FE = Callee->arg_end(); + FI != FE; ++I, ++FI, ++ArgNo) { + + // If an alloca is passed in, inlining this function is likely to allow + // significant future optimization possibilities (like scalar promotion, and + // scalarization), so encourage the inlining of the function. + // + if (isa(I)) + InlineCost -= CalleeFI->ArgumentWeights[ArgNo].AllocaWeight; + + // If this is a constant being passed into the function, use the argument + // weights calculated for the callee to determine how much will be folded + // away with this information. + else if (isa(I)) + InlineCost -= CalleeFI->ArgumentWeights[ArgNo].ConstantWeight; + } + + // Each argument passed in has a cost at both the caller and the callee + // sides. Measurements show that each argument costs about the same as an + // instruction. + InlineCost -= (CS.arg_size() * InlineConstants::InstrCost); + + // Now that we have considered all of the factors that make the call site more + // likely to be inlined, look at factors that make us not want to inline it. + + // Calls usually take a long time, so they make the inlining gain smaller. + InlineCost += CalleeFI->Metrics.NumCalls * InlineConstants::CallPenalty; + + // Look at the size of the callee. Each instruction counts as 5. + InlineCost += CalleeFI->Metrics.NumInsts*InlineConstants::InstrCost; + + return InlineCost; +} + +int InlineCostAnalyzer::getInlineBonuses(CallSite CS, Function *Callee) { + // Get information about the callee. + FunctionInfo *CalleeFI = &CachedFunctionInfo[Callee]; + + // If we haven't calculated this information yet, do so now. + if (CalleeFI->Metrics.NumBlocks == 0) + CalleeFI->analyzeFunction(Callee); + + bool isDirectCall = CS.getCalledFunction() == Callee; + Instruction *TheCall = CS.getInstruction(); + int Bonus = 0; + // If there is only one call of the function, and it has internal linkage, // make it almost guaranteed to be inlined. // if (Callee->hasLocalLinkage() && Callee->hasOneUse() && isDirectCall) - InlineCost += InlineConstants::LastCallToStaticBonus; - - // If this function uses the coldcc calling convention, prefer not to inline - // it. - if (Callee->getCallingConv() == CallingConv::Cold) - InlineCost += InlineConstants::ColdccPenalty; + Bonus += InlineConstants::LastCallToStaticBonus; // If the instruction after the call, or if the normal destination of the // invoke is an unreachable instruction, the function is noreturn. As such, // there is little point in inlining this. if (InvokeInst *II = dyn_cast(TheCall)) { if (isa(II->getNormalDest()->begin())) - InlineCost += InlineConstants::NoreturnPenalty; + Bonus += InlineConstants::NoreturnPenalty; } else if (isa(++BasicBlock::iterator(TheCall))) - InlineCost += InlineConstants::NoreturnPenalty; + Bonus += InlineConstants::NoreturnPenalty; + + // If this function uses the coldcc calling convention, prefer not to inline + // it. + if (Callee->getCallingConv() == CallingConv::Cold) + Bonus += InlineConstants::ColdccPenalty; + // Add to the inline quality for properties that make the call valuable to + // inline. This includes factors that indicate that the result of inlining + // the function will be optimizable. Currently this just looks at arguments + // passed into the function. + // + CallSite::arg_iterator I = CS.arg_begin(); + for (Function::arg_iterator FI = Callee->arg_begin(), FE = Callee->arg_end(); + FI != FE; ++I, ++FI) + // Compute any constant bonus due to inlining we want to give here. + if (isa(I)) + Bonus += CountBonusForConstant(FI, cast(I)); + + return Bonus; +} + +// getInlineCost - The heuristic used to determine if we should inline the +// function call or not. +// +InlineCost InlineCostAnalyzer::getInlineCost(CallSite CS, + SmallPtrSet &NeverInline) { + return getInlineCost(CS, CS.getCalledFunction(), NeverInline); +} + +InlineCost InlineCostAnalyzer::getInlineCost(CallSite CS, + Function *Callee, + SmallPtrSet &NeverInline) { + Instruction *TheCall = CS.getInstruction(); + Function *Caller = TheCall->getParent()->getParent(); + + // Don't inline functions which can be redefined at link-time to mean + // something else. Don't inline functions marked noinline or call sites + // marked noinline. + if (Callee->mayBeOverridden() || + Callee->hasFnAttr(Attribute::NoInline) || NeverInline.count(Callee) || + CS.isNoInline()) + return llvm::InlineCost::getNever(); + // Get information about the callee. FunctionInfo *CalleeFI = &CachedFunctionInfo[Callee]; @@ -353,46 +520,45 @@ InlineCost InlineCostAnalyzer::getInlineCost(CallSite CS, return InlineCost::getNever(); } - // Add to the inline quality for properties that make the call valuable to - // inline. This includes factors that indicate that the result of inlining - // the function will be optimizable. Currently this just looks at arguments - // passed into the function. + // InlineCost - This value measures how good of an inline candidate this call + // site is to inline. A lower inline cost make is more likely for the call to + // be inlined. This value may go negative due to the fact that bonuses + // are negative numbers. // - unsigned ArgNo = 0; - for (CallSite::arg_iterator I = CS.arg_begin(), E = CS.arg_end(); - I != E; ++I, ++ArgNo) { - // Each argument passed in has a cost at both the caller and the callee - // sides. Measurements show that each argument costs about the same as an - // instruction. - InlineCost -= InlineConstants::InstrCost; + int InlineCost = getInlineSize(CS, Callee) + getInlineBonuses(CS, Callee); + return llvm::InlineCost::get(InlineCost); +} - // If an alloca is passed in, inlining this function is likely to allow - // significant future optimization possibilities (like scalar promotion, and - // scalarization), so encourage the inlining of the function. - // - if (isa(I)) { - if (ArgNo < CalleeFI->ArgumentWeights.size()) - InlineCost -= CalleeFI->ArgumentWeights[ArgNo].AllocaWeight; - - // If this is a constant being passed into the function, use the argument - // weights calculated for the callee to determine how much will be folded - // away with this information. - } else if (isa(I)) { - if (ArgNo < CalleeFI->ArgumentWeights.size()) - InlineCost -= CalleeFI->ArgumentWeights[ArgNo].ConstantWeight; - } - } +// getSpecializationCost - The heuristic used to determine the code-size +// impact of creating a specialized version of Callee with argument +// SpecializedArgNo replaced by a constant. +InlineCost InlineCostAnalyzer::getSpecializationCost(Function *Callee, + SmallVectorImpl &SpecializedArgNos) +{ + // Don't specialize functions which can be redefined at link-time to mean + // something else. + if (Callee->mayBeOverridden()) + return llvm::InlineCost::getNever(); - // Now that we have considered all of the factors that make the call site more - // likely to be inlined, look at factors that make us not want to inline it. + // Get information about the callee. + FunctionInfo *CalleeFI = &CachedFunctionInfo[Callee]; + + // If we haven't calculated this information yet, do so now. + if (CalleeFI->Metrics.NumBlocks == 0) + CalleeFI->analyzeFunction(Callee); - // Calls usually take a long time, so they make the inlining gain smaller. - InlineCost += CalleeFI->Metrics.NumCalls * InlineConstants::CallPenalty; + int Cost = 0; + + // Look at the orginal size of the callee. Each instruction counts as 5. + Cost += CalleeFI->Metrics.NumInsts * InlineConstants::InstrCost; - // Look at the size of the callee. Each instruction counts as 5. - InlineCost += CalleeFI->Metrics.NumInsts*InlineConstants::InstrCost; + // Offset that with the amount of code that can be constant-folded + // away with the given arguments replaced by constants. + for (SmallVectorImpl::iterator an = SpecializedArgNos.begin(), + ae = SpecializedArgNos.end(); an != ae; ++an) + Cost -= CalleeFI->ArgumentWeights[*an].ConstantWeight; - return llvm::InlineCost::get(InlineCost); + return llvm::InlineCost::get(Cost); } // getInlineFudgeFactor - Return a > 1.0 factor if the inliner should use a diff --git a/lib/Analysis/InstCount.cpp b/lib/Analysis/InstCount.cpp index dcbcac005a2f..3b385d26ba3c 100644 --- a/lib/Analysis/InstCount.cpp +++ b/lib/Analysis/InstCount.cpp @@ -51,7 +51,9 @@ namespace { } public: static char ID; // Pass identification, replacement for typeid - InstCount() : FunctionPass(ID) {} + InstCount() : FunctionPass(ID) { + initializeInstCountPass(*PassRegistry::getPassRegistry()); + } virtual bool runOnFunction(Function &F); @@ -65,7 +67,7 @@ namespace { char InstCount::ID = 0; INITIALIZE_PASS(InstCount, "instcount", - "Counts the various types of Instructions", false, true); + "Counts the various types of Instructions", false, true) FunctionPass *llvm::createInstCountPass() { return new InstCount(); } diff --git a/lib/Analysis/InstructionSimplify.cpp b/lib/Analysis/InstructionSimplify.cpp index 24cd3433a2ca..a2f9862383fd 100644 --- a/lib/Analysis/InstructionSimplify.cpp +++ b/lib/Analysis/InstructionSimplify.cpp @@ -8,179 +8,1267 @@ //===----------------------------------------------------------------------===// // // This file implements routines for folding instructions into simpler forms -// that do not require creating new instructions. For example, this does -// constant folding, and can handle identities like (X&0)->0. +// that do not require creating new instructions. This does constant folding +// ("add i32 1, 1" -> "2") but can also handle non-constant operands, either +// returning a constant ("and i32 %x, 0" -> "0") or an already existing value +// ("and i32 %x, %x" -> "%x"). All operands are assumed to have already been +// simplified: This is usually true and assuming it simplifies the logic (if +// they have not been simplified then results are correct but maybe suboptimal). // //===----------------------------------------------------------------------===// +#define DEBUG_TYPE "instsimplify" +#include "llvm/ADT/Statistic.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/ConstantFolding.h" -#include "llvm/Support/ValueHandle.h" -#include "llvm/Instructions.h" +#include "llvm/Analysis/Dominators.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/Support/PatternMatch.h" +#include "llvm/Support/ValueHandle.h" +#include "llvm/Target/TargetData.h" using namespace llvm; using namespace llvm::PatternMatch; +enum { RecursionLimit = 3 }; + +STATISTIC(NumExpand, "Number of expansions"); +STATISTIC(NumFactor , "Number of factorizations"); +STATISTIC(NumReassoc, "Number of reassociations"); + +static Value *SimplifyAndInst(Value *, Value *, const TargetData *, + const DominatorTree *, unsigned); +static Value *SimplifyBinOp(unsigned, Value *, Value *, const TargetData *, + const DominatorTree *, unsigned); +static Value *SimplifyCmpInst(unsigned, Value *, Value *, const TargetData *, + const DominatorTree *, unsigned); +static Value *SimplifyOrInst(Value *, Value *, const TargetData *, + const DominatorTree *, unsigned); +static Value *SimplifyXorInst(Value *, Value *, const TargetData *, + const DominatorTree *, unsigned); + +/// ValueDominatesPHI - Does the given value dominate the specified phi node? +static bool ValueDominatesPHI(Value *V, PHINode *P, const DominatorTree *DT) { + Instruction *I = dyn_cast(V); + if (!I) + // Arguments and constants dominate all instructions. + return true; + + // If we have a DominatorTree then do a precise test. + if (DT) + return DT->dominates(I, P); + + // Otherwise, if the instruction is in the entry block, and is not an invoke, + // then it obviously dominates all phi nodes. + if (I->getParent() == &I->getParent()->getParent()->getEntryBlock() && + !isa(I)) + return true; + + return false; +} + +/// ExpandBinOp - Simplify "A op (B op' C)" by distributing op over op', turning +/// it into "(A op B) op' (A op C)". Here "op" is given by Opcode and "op'" is +/// given by OpcodeToExpand, while "A" corresponds to LHS and "B op' C" to RHS. +/// Also performs the transform "(A op' B) op C" -> "(A op C) op' (B op C)". +/// Returns the simplified value, or null if no simplification was performed. +static Value *ExpandBinOp(unsigned Opcode, Value *LHS, Value *RHS, + unsigned OpcToExpand, const TargetData *TD, + const DominatorTree *DT, unsigned MaxRecurse) { + Instruction::BinaryOps OpcodeToExpand = (Instruction::BinaryOps)OpcToExpand; + // Recursion is always used, so bail out at once if we already hit the limit. + if (!MaxRecurse--) + return 0; + + // Check whether the expression has the form "(A op' B) op C". + if (BinaryOperator *Op0 = dyn_cast(LHS)) + if (Op0->getOpcode() == OpcodeToExpand) { + // It does! Try turning it into "(A op C) op' (B op C)". + Value *A = Op0->getOperand(0), *B = Op0->getOperand(1), *C = RHS; + // Do "A op C" and "B op C" both simplify? + if (Value *L = SimplifyBinOp(Opcode, A, C, TD, DT, MaxRecurse)) + if (Value *R = SimplifyBinOp(Opcode, B, C, TD, DT, MaxRecurse)) { + // They do! Return "L op' R" if it simplifies or is already available. + // If "L op' R" equals "A op' B" then "L op' R" is just the LHS. + if ((L == A && R == B) || (Instruction::isCommutative(OpcodeToExpand) + && L == B && R == A)) { + ++NumExpand; + return LHS; + } + // Otherwise return "L op' R" if it simplifies. + if (Value *V = SimplifyBinOp(OpcodeToExpand, L, R, TD, DT, + MaxRecurse)) { + ++NumExpand; + return V; + } + } + } + + // Check whether the expression has the form "A op (B op' C)". + if (BinaryOperator *Op1 = dyn_cast(RHS)) + if (Op1->getOpcode() == OpcodeToExpand) { + // It does! Try turning it into "(A op B) op' (A op C)". + Value *A = LHS, *B = Op1->getOperand(0), *C = Op1->getOperand(1); + // Do "A op B" and "A op C" both simplify? + if (Value *L = SimplifyBinOp(Opcode, A, B, TD, DT, MaxRecurse)) + if (Value *R = SimplifyBinOp(Opcode, A, C, TD, DT, MaxRecurse)) { + // They do! Return "L op' R" if it simplifies or is already available. + // If "L op' R" equals "B op' C" then "L op' R" is just the RHS. + if ((L == B && R == C) || (Instruction::isCommutative(OpcodeToExpand) + && L == C && R == B)) { + ++NumExpand; + return RHS; + } + // Otherwise return "L op' R" if it simplifies. + if (Value *V = SimplifyBinOp(OpcodeToExpand, L, R, TD, DT, + MaxRecurse)) { + ++NumExpand; + return V; + } + } + } + + return 0; +} + +/// FactorizeBinOp - Simplify "LHS Opcode RHS" by factorizing out a common term +/// using the operation OpCodeToExtract. For example, when Opcode is Add and +/// OpCodeToExtract is Mul then this tries to turn "(A*B)+(A*C)" into "A*(B+C)". +/// Returns the simplified value, or null if no simplification was performed. +static Value *FactorizeBinOp(unsigned Opcode, Value *LHS, Value *RHS, + unsigned OpcToExtract, const TargetData *TD, + const DominatorTree *DT, unsigned MaxRecurse) { + Instruction::BinaryOps OpcodeToExtract = (Instruction::BinaryOps)OpcToExtract; + // Recursion is always used, so bail out at once if we already hit the limit. + if (!MaxRecurse--) + return 0; + + BinaryOperator *Op0 = dyn_cast(LHS); + BinaryOperator *Op1 = dyn_cast(RHS); + + if (!Op0 || Op0->getOpcode() != OpcodeToExtract || + !Op1 || Op1->getOpcode() != OpcodeToExtract) + return 0; + + // The expression has the form "(A op' B) op (C op' D)". + Value *A = Op0->getOperand(0), *B = Op0->getOperand(1); + Value *C = Op1->getOperand(0), *D = Op1->getOperand(1); + + // Use left distributivity, i.e. "X op' (Y op Z) = (X op' Y) op (X op' Z)". + // Does the instruction have the form "(A op' B) op (A op' D)" or, in the + // commutative case, "(A op' B) op (C op' A)"? + if (A == C || (Instruction::isCommutative(OpcodeToExtract) && A == D)) { + Value *DD = A == C ? D : C; + // Form "A op' (B op DD)" if it simplifies completely. + // Does "B op DD" simplify? + if (Value *V = SimplifyBinOp(Opcode, B, DD, TD, DT, MaxRecurse)) { + // It does! Return "A op' V" if it simplifies or is already available. + // If V equals B then "A op' V" is just the LHS. If V equals DD then + // "A op' V" is just the RHS. + if (V == B || V == DD) { + ++NumFactor; + return V == B ? LHS : RHS; + } + // Otherwise return "A op' V" if it simplifies. + if (Value *W = SimplifyBinOp(OpcodeToExtract, A, V, TD, DT, MaxRecurse)) { + ++NumFactor; + return W; + } + } + } + + // Use right distributivity, i.e. "(X op Y) op' Z = (X op' Z) op (Y op' Z)". + // Does the instruction have the form "(A op' B) op (C op' B)" or, in the + // commutative case, "(A op' B) op (B op' D)"? + if (B == D || (Instruction::isCommutative(OpcodeToExtract) && B == C)) { + Value *CC = B == D ? C : D; + // Form "(A op CC) op' B" if it simplifies completely.. + // Does "A op CC" simplify? + if (Value *V = SimplifyBinOp(Opcode, A, CC, TD, DT, MaxRecurse)) { + // It does! Return "V op' B" if it simplifies or is already available. + // If V equals A then "V op' B" is just the LHS. If V equals CC then + // "V op' B" is just the RHS. + if (V == A || V == CC) { + ++NumFactor; + return V == A ? LHS : RHS; + } + // Otherwise return "V op' B" if it simplifies. + if (Value *W = SimplifyBinOp(OpcodeToExtract, V, B, TD, DT, MaxRecurse)) { + ++NumFactor; + return W; + } + } + } + + return 0; +} + +/// SimplifyAssociativeBinOp - Generic simplifications for associative binary +/// operations. Returns the simpler value, or null if none was found. +static Value *SimplifyAssociativeBinOp(unsigned Opc, Value *LHS, Value *RHS, + const TargetData *TD, + const DominatorTree *DT, + unsigned MaxRecurse) { + Instruction::BinaryOps Opcode = (Instruction::BinaryOps)Opc; + assert(Instruction::isAssociative(Opcode) && "Not an associative operation!"); + + // Recursion is always used, so bail out at once if we already hit the limit. + if (!MaxRecurse--) + return 0; + + BinaryOperator *Op0 = dyn_cast(LHS); + BinaryOperator *Op1 = dyn_cast(RHS); + + // Transform: "(A op B) op C" ==> "A op (B op C)" if it simplifies completely. + if (Op0 && Op0->getOpcode() == Opcode) { + Value *A = Op0->getOperand(0); + Value *B = Op0->getOperand(1); + Value *C = RHS; + + // Does "B op C" simplify? + if (Value *V = SimplifyBinOp(Opcode, B, C, TD, DT, MaxRecurse)) { + // It does! Return "A op V" if it simplifies or is already available. + // If V equals B then "A op V" is just the LHS. + if (V == B) return LHS; + // Otherwise return "A op V" if it simplifies. + if (Value *W = SimplifyBinOp(Opcode, A, V, TD, DT, MaxRecurse)) { + ++NumReassoc; + return W; + } + } + } + + // Transform: "A op (B op C)" ==> "(A op B) op C" if it simplifies completely. + if (Op1 && Op1->getOpcode() == Opcode) { + Value *A = LHS; + Value *B = Op1->getOperand(0); + Value *C = Op1->getOperand(1); + + // Does "A op B" simplify? + if (Value *V = SimplifyBinOp(Opcode, A, B, TD, DT, MaxRecurse)) { + // It does! Return "V op C" if it simplifies or is already available. + // If V equals B then "V op C" is just the RHS. + if (V == B) return RHS; + // Otherwise return "V op C" if it simplifies. + if (Value *W = SimplifyBinOp(Opcode, V, C, TD, DT, MaxRecurse)) { + ++NumReassoc; + return W; + } + } + } + + // The remaining transforms require commutativity as well as associativity. + if (!Instruction::isCommutative(Opcode)) + return 0; + + // Transform: "(A op B) op C" ==> "(C op A) op B" if it simplifies completely. + if (Op0 && Op0->getOpcode() == Opcode) { + Value *A = Op0->getOperand(0); + Value *B = Op0->getOperand(1); + Value *C = RHS; + + // Does "C op A" simplify? + if (Value *V = SimplifyBinOp(Opcode, C, A, TD, DT, MaxRecurse)) { + // It does! Return "V op B" if it simplifies or is already available. + // If V equals A then "V op B" is just the LHS. + if (V == A) return LHS; + // Otherwise return "V op B" if it simplifies. + if (Value *W = SimplifyBinOp(Opcode, V, B, TD, DT, MaxRecurse)) { + ++NumReassoc; + return W; + } + } + } + + // Transform: "A op (B op C)" ==> "B op (C op A)" if it simplifies completely. + if (Op1 && Op1->getOpcode() == Opcode) { + Value *A = LHS; + Value *B = Op1->getOperand(0); + Value *C = Op1->getOperand(1); + + // Does "C op A" simplify? + if (Value *V = SimplifyBinOp(Opcode, C, A, TD, DT, MaxRecurse)) { + // It does! Return "B op V" if it simplifies or is already available. + // If V equals C then "B op V" is just the RHS. + if (V == C) return RHS; + // Otherwise return "B op V" if it simplifies. + if (Value *W = SimplifyBinOp(Opcode, B, V, TD, DT, MaxRecurse)) { + ++NumReassoc; + return W; + } + } + } + + return 0; +} + +/// ThreadBinOpOverSelect - In the case of a binary operation with a select +/// instruction as an operand, try to simplify the binop by seeing whether +/// evaluating it on both branches of the select results in the same value. +/// Returns the common value if so, otherwise returns null. +static Value *ThreadBinOpOverSelect(unsigned Opcode, Value *LHS, Value *RHS, + const TargetData *TD, + const DominatorTree *DT, + unsigned MaxRecurse) { + // Recursion is always used, so bail out at once if we already hit the limit. + if (!MaxRecurse--) + return 0; + + SelectInst *SI; + if (isa(LHS)) { + SI = cast(LHS); + } else { + assert(isa(RHS) && "No select instruction operand!"); + SI = cast(RHS); + } + + // Evaluate the BinOp on the true and false branches of the select. + Value *TV; + Value *FV; + if (SI == LHS) { + TV = SimplifyBinOp(Opcode, SI->getTrueValue(), RHS, TD, DT, MaxRecurse); + FV = SimplifyBinOp(Opcode, SI->getFalseValue(), RHS, TD, DT, MaxRecurse); + } else { + TV = SimplifyBinOp(Opcode, LHS, SI->getTrueValue(), TD, DT, MaxRecurse); + FV = SimplifyBinOp(Opcode, LHS, SI->getFalseValue(), TD, DT, MaxRecurse); + } + + // If they simplified to the same value, then return the common value. + // If they both failed to simplify then return null. + if (TV == FV) + return TV; + + // If one branch simplified to undef, return the other one. + if (TV && isa(TV)) + return FV; + if (FV && isa(FV)) + return TV; + + // If applying the operation did not change the true and false select values, + // then the result of the binop is the select itself. + if (TV == SI->getTrueValue() && FV == SI->getFalseValue()) + return SI; + + // If one branch simplified and the other did not, and the simplified + // value is equal to the unsimplified one, return the simplified value. + // For example, select (cond, X, X & Z) & Z -> X & Z. + if ((FV && !TV) || (TV && !FV)) { + // Check that the simplified value has the form "X op Y" where "op" is the + // same as the original operation. + Instruction *Simplified = dyn_cast(FV ? FV : TV); + if (Simplified && Simplified->getOpcode() == Opcode) { + // The value that didn't simplify is "UnsimplifiedLHS op UnsimplifiedRHS". + // We already know that "op" is the same as for the simplified value. See + // if the operands match too. If so, return the simplified value. + Value *UnsimplifiedBranch = FV ? SI->getTrueValue() : SI->getFalseValue(); + Value *UnsimplifiedLHS = SI == LHS ? UnsimplifiedBranch : LHS; + Value *UnsimplifiedRHS = SI == LHS ? RHS : UnsimplifiedBranch; + if (Simplified->getOperand(0) == UnsimplifiedLHS && + Simplified->getOperand(1) == UnsimplifiedRHS) + return Simplified; + if (Simplified->isCommutative() && + Simplified->getOperand(1) == UnsimplifiedLHS && + Simplified->getOperand(0) == UnsimplifiedRHS) + return Simplified; + } + } + + return 0; +} + +/// ThreadCmpOverSelect - In the case of a comparison with a select instruction, +/// try to simplify the comparison by seeing whether both branches of the select +/// result in the same value. Returns the common value if so, otherwise returns +/// null. +static Value *ThreadCmpOverSelect(CmpInst::Predicate Pred, Value *LHS, + Value *RHS, const TargetData *TD, + const DominatorTree *DT, + unsigned MaxRecurse) { + // Recursion is always used, so bail out at once if we already hit the limit. + if (!MaxRecurse--) + return 0; + + // Make sure the select is on the LHS. + if (!isa(LHS)) { + std::swap(LHS, RHS); + Pred = CmpInst::getSwappedPredicate(Pred); + } + assert(isa(LHS) && "Not comparing with a select instruction!"); + SelectInst *SI = cast(LHS); + + // Now that we have "cmp select(Cond, TV, FV), RHS", analyse it. + // Does "cmp TV, RHS" simplify? + if (Value *TCmp = SimplifyCmpInst(Pred, SI->getTrueValue(), RHS, TD, DT, + MaxRecurse)) { + // It does! Does "cmp FV, RHS" simplify? + if (Value *FCmp = SimplifyCmpInst(Pred, SI->getFalseValue(), RHS, TD, DT, + MaxRecurse)) { + // It does! If they simplified to the same value, then use it as the + // result of the original comparison. + if (TCmp == FCmp) + return TCmp; + Value *Cond = SI->getCondition(); + // If the false value simplified to false, then the result of the compare + // is equal to "Cond && TCmp". This also catches the case when the false + // value simplified to false and the true value to true, returning "Cond". + if (match(FCmp, m_Zero())) + if (Value *V = SimplifyAndInst(Cond, TCmp, TD, DT, MaxRecurse)) + return V; + // If the true value simplified to true, then the result of the compare + // is equal to "Cond || FCmp". + if (match(TCmp, m_One())) + if (Value *V = SimplifyOrInst(Cond, FCmp, TD, DT, MaxRecurse)) + return V; + // Finally, if the false value simplified to true and the true value to + // false, then the result of the compare is equal to "!Cond". + if (match(FCmp, m_One()) && match(TCmp, m_Zero())) + if (Value *V = + SimplifyXorInst(Cond, Constant::getAllOnesValue(Cond->getType()), + TD, DT, MaxRecurse)) + return V; + } + } + + return 0; +} + +/// ThreadBinOpOverPHI - In the case of a binary operation with an operand that +/// is a PHI instruction, try to simplify the binop by seeing whether evaluating +/// it on the incoming phi values yields the same result for every value. If so +/// returns the common value, otherwise returns null. +static Value *ThreadBinOpOverPHI(unsigned Opcode, Value *LHS, Value *RHS, + const TargetData *TD, const DominatorTree *DT, + unsigned MaxRecurse) { + // Recursion is always used, so bail out at once if we already hit the limit. + if (!MaxRecurse--) + return 0; + + PHINode *PI; + if (isa(LHS)) { + PI = cast(LHS); + // Bail out if RHS and the phi may be mutually interdependent due to a loop. + if (!ValueDominatesPHI(RHS, PI, DT)) + return 0; + } else { + assert(isa(RHS) && "No PHI instruction operand!"); + PI = cast(RHS); + // Bail out if LHS and the phi may be mutually interdependent due to a loop. + if (!ValueDominatesPHI(LHS, PI, DT)) + return 0; + } + + // Evaluate the BinOp on the incoming phi values. + Value *CommonValue = 0; + for (unsigned i = 0, e = PI->getNumIncomingValues(); i != e; ++i) { + Value *Incoming = PI->getIncomingValue(i); + // If the incoming value is the phi node itself, it can safely be skipped. + if (Incoming == PI) continue; + Value *V = PI == LHS ? + SimplifyBinOp(Opcode, Incoming, RHS, TD, DT, MaxRecurse) : + SimplifyBinOp(Opcode, LHS, Incoming, TD, DT, MaxRecurse); + // If the operation failed to simplify, or simplified to a different value + // to previously, then give up. + if (!V || (CommonValue && V != CommonValue)) + return 0; + CommonValue = V; + } + + return CommonValue; +} + +/// ThreadCmpOverPHI - In the case of a comparison with a PHI instruction, try +/// try to simplify the comparison by seeing whether comparing with all of the +/// incoming phi values yields the same result every time. If so returns the +/// common result, otherwise returns null. +static Value *ThreadCmpOverPHI(CmpInst::Predicate Pred, Value *LHS, Value *RHS, + const TargetData *TD, const DominatorTree *DT, + unsigned MaxRecurse) { + // Recursion is always used, so bail out at once if we already hit the limit. + if (!MaxRecurse--) + return 0; + + // Make sure the phi is on the LHS. + if (!isa(LHS)) { + std::swap(LHS, RHS); + Pred = CmpInst::getSwappedPredicate(Pred); + } + assert(isa(LHS) && "Not comparing with a phi instruction!"); + PHINode *PI = cast(LHS); + + // Bail out if RHS and the phi may be mutually interdependent due to a loop. + if (!ValueDominatesPHI(RHS, PI, DT)) + return 0; + + // Evaluate the BinOp on the incoming phi values. + Value *CommonValue = 0; + for (unsigned i = 0, e = PI->getNumIncomingValues(); i != e; ++i) { + Value *Incoming = PI->getIncomingValue(i); + // If the incoming value is the phi node itself, it can safely be skipped. + if (Incoming == PI) continue; + Value *V = SimplifyCmpInst(Pred, Incoming, RHS, TD, DT, MaxRecurse); + // If the operation failed to simplify, or simplified to a different value + // to previously, then give up. + if (!V || (CommonValue && V != CommonValue)) + return 0; + CommonValue = V; + } + + return CommonValue; +} + /// SimplifyAddInst - Given operands for an Add, see if we can /// fold the result. If not, this returns null. -Value *llvm::SimplifyAddInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW, - const TargetData *TD) { +static Value *SimplifyAddInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW, + const TargetData *TD, const DominatorTree *DT, + unsigned MaxRecurse) { if (Constant *CLHS = dyn_cast(Op0)) { if (Constant *CRHS = dyn_cast(Op1)) { Constant *Ops[] = { CLHS, CRHS }; return ConstantFoldInstOperands(Instruction::Add, CLHS->getType(), Ops, 2, TD); } - + + // Canonicalize the constant to the RHS. + std::swap(Op0, Op1); + } + + // X + undef -> undef + if (match(Op1, m_Undef())) + return Op1; + + // X + 0 -> X + if (match(Op1, m_Zero())) + return Op0; + + // X + (Y - X) -> Y + // (Y - X) + X -> Y + // Eg: X + -X -> 0 + Value *Y = 0; + if (match(Op1, m_Sub(m_Value(Y), m_Specific(Op0))) || + match(Op0, m_Sub(m_Value(Y), m_Specific(Op1)))) + return Y; + + // X + ~X -> -1 since ~X = -X-1 + if (match(Op0, m_Not(m_Specific(Op1))) || + match(Op1, m_Not(m_Specific(Op0)))) + return Constant::getAllOnesValue(Op0->getType()); + + /// i1 add -> xor. + if (MaxRecurse && Op0->getType()->isIntegerTy(1)) + if (Value *V = SimplifyXorInst(Op0, Op1, TD, DT, MaxRecurse-1)) + return V; + + // Try some generic simplifications for associative operations. + if (Value *V = SimplifyAssociativeBinOp(Instruction::Add, Op0, Op1, TD, DT, + MaxRecurse)) + return V; + + // Mul distributes over Add. Try some generic simplifications based on this. + if (Value *V = FactorizeBinOp(Instruction::Add, Op0, Op1, Instruction::Mul, + TD, DT, MaxRecurse)) + return V; + + // Threading Add over selects and phi nodes is pointless, so don't bother. + // Threading over the select in "A + select(cond, B, C)" means evaluating + // "A+B" and "A+C" and seeing if they are equal; but they are equal if and + // only if B and C are equal. If B and C are equal then (since we assume + // that operands have already been simplified) "select(cond, B, C)" should + // have been simplified to the common value of B and C already. Analysing + // "A+B" and "A+C" thus gains nothing, but costs compile time. Similarly + // for threading over phi nodes. + + return 0; +} + +Value *llvm::SimplifyAddInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW, + const TargetData *TD, const DominatorTree *DT) { + return ::SimplifyAddInst(Op0, Op1, isNSW, isNUW, TD, DT, RecursionLimit); +} + +/// SimplifySubInst - Given operands for a Sub, see if we can +/// fold the result. If not, this returns null. +static Value *SimplifySubInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW, + const TargetData *TD, const DominatorTree *DT, + unsigned MaxRecurse) { + if (Constant *CLHS = dyn_cast(Op0)) + if (Constant *CRHS = dyn_cast(Op1)) { + Constant *Ops[] = { CLHS, CRHS }; + return ConstantFoldInstOperands(Instruction::Sub, CLHS->getType(), + Ops, 2, TD); + } + + // X - undef -> undef + // undef - X -> undef + if (match(Op0, m_Undef()) || match(Op1, m_Undef())) + return UndefValue::get(Op0->getType()); + + // X - 0 -> X + if (match(Op1, m_Zero())) + return Op0; + + // X - X -> 0 + if (Op0 == Op1) + return Constant::getNullValue(Op0->getType()); + + // (X*2) - X -> X + // (X<<1) - X -> X + Value *X = 0; + if (match(Op0, m_Mul(m_Specific(Op1), m_ConstantInt<2>())) || + match(Op0, m_Shl(m_Specific(Op1), m_One()))) + return Op1; + + // (X + Y) - Z -> X + (Y - Z) or Y + (X - Z) if everything simplifies. + // For example, (X + Y) - Y -> X; (Y + X) - Y -> X + Value *Y = 0, *Z = Op1; + if (MaxRecurse && match(Op0, m_Add(m_Value(X), m_Value(Y)))) { // (X + Y) - Z + // See if "V === Y - Z" simplifies. + if (Value *V = SimplifyBinOp(Instruction::Sub, Y, Z, TD, DT, MaxRecurse-1)) + // It does! Now see if "X + V" simplifies. + if (Value *W = SimplifyBinOp(Instruction::Add, X, V, TD, DT, + MaxRecurse-1)) { + // It does, we successfully reassociated! + ++NumReassoc; + return W; + } + // See if "V === X - Z" simplifies. + if (Value *V = SimplifyBinOp(Instruction::Sub, X, Z, TD, DT, MaxRecurse-1)) + // It does! Now see if "Y + V" simplifies. + if (Value *W = SimplifyBinOp(Instruction::Add, Y, V, TD, DT, + MaxRecurse-1)) { + // It does, we successfully reassociated! + ++NumReassoc; + return W; + } + } + + // X - (Y + Z) -> (X - Y) - Z or (X - Z) - Y if everything simplifies. + // For example, X - (X + 1) -> -1 + X = Op0; + if (MaxRecurse && match(Op1, m_Add(m_Value(Y), m_Value(Z)))) { // X - (Y + Z) + // See if "V === X - Y" simplifies. + if (Value *V = SimplifyBinOp(Instruction::Sub, X, Y, TD, DT, MaxRecurse-1)) + // It does! Now see if "V - Z" simplifies. + if (Value *W = SimplifyBinOp(Instruction::Sub, V, Z, TD, DT, + MaxRecurse-1)) { + // It does, we successfully reassociated! + ++NumReassoc; + return W; + } + // See if "V === X - Z" simplifies. + if (Value *V = SimplifyBinOp(Instruction::Sub, X, Z, TD, DT, MaxRecurse-1)) + // It does! Now see if "V - Y" simplifies. + if (Value *W = SimplifyBinOp(Instruction::Sub, V, Y, TD, DT, + MaxRecurse-1)) { + // It does, we successfully reassociated! + ++NumReassoc; + return W; + } + } + + // Z - (X - Y) -> (Z - X) + Y if everything simplifies. + // For example, X - (X - Y) -> Y. + Z = Op0; + if (MaxRecurse && match(Op1, m_Sub(m_Value(X), m_Value(Y)))) // Z - (X - Y) + // See if "V === Z - X" simplifies. + if (Value *V = SimplifyBinOp(Instruction::Sub, Z, X, TD, DT, MaxRecurse-1)) + // It does! Now see if "V + Y" simplifies. + if (Value *W = SimplifyBinOp(Instruction::Add, V, Y, TD, DT, + MaxRecurse-1)) { + // It does, we successfully reassociated! + ++NumReassoc; + return W; + } + + // Mul distributes over Sub. Try some generic simplifications based on this. + if (Value *V = FactorizeBinOp(Instruction::Sub, Op0, Op1, Instruction::Mul, + TD, DT, MaxRecurse)) + return V; + + // i1 sub -> xor. + if (MaxRecurse && Op0->getType()->isIntegerTy(1)) + if (Value *V = SimplifyXorInst(Op0, Op1, TD, DT, MaxRecurse-1)) + return V; + + // Threading Sub over selects and phi nodes is pointless, so don't bother. + // Threading over the select in "A - select(cond, B, C)" means evaluating + // "A-B" and "A-C" and seeing if they are equal; but they are equal if and + // only if B and C are equal. If B and C are equal then (since we assume + // that operands have already been simplified) "select(cond, B, C)" should + // have been simplified to the common value of B and C already. Analysing + // "A-B" and "A-C" thus gains nothing, but costs compile time. Similarly + // for threading over phi nodes. + + return 0; +} + +Value *llvm::SimplifySubInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW, + const TargetData *TD, const DominatorTree *DT) { + return ::SimplifySubInst(Op0, Op1, isNSW, isNUW, TD, DT, RecursionLimit); +} + +/// SimplifyMulInst - Given operands for a Mul, see if we can +/// fold the result. If not, this returns null. +static Value *SimplifyMulInst(Value *Op0, Value *Op1, const TargetData *TD, + const DominatorTree *DT, unsigned MaxRecurse) { + if (Constant *CLHS = dyn_cast(Op0)) { + if (Constant *CRHS = dyn_cast(Op1)) { + Constant *Ops[] = { CLHS, CRHS }; + return ConstantFoldInstOperands(Instruction::Mul, CLHS->getType(), + Ops, 2, TD); + } + // Canonicalize the constant to the RHS. std::swap(Op0, Op1); } - - if (Constant *Op1C = dyn_cast(Op1)) { - // X + undef -> undef - if (isa(Op1C)) - return Op1C; - - // X + 0 --> X - if (Op1C->isNullValue()) - return Op0; - } - - // FIXME: Could pull several more out of instcombine. + + // X * undef -> 0 + if (match(Op1, m_Undef())) + return Constant::getNullValue(Op0->getType()); + + // X * 0 -> 0 + if (match(Op1, m_Zero())) + return Op1; + + // X * 1 -> X + if (match(Op1, m_One())) + return Op0; + + // (X / Y) * Y -> X if the division is exact. + Value *X = 0, *Y = 0; + if ((match(Op0, m_IDiv(m_Value(X), m_Value(Y))) && Y == Op1) || // (X / Y) * Y + (match(Op1, m_IDiv(m_Value(X), m_Value(Y))) && Y == Op0)) { // Y * (X / Y) + BinaryOperator *Div = cast(Y == Op1 ? Op0 : Op1); + if (Div->isExact()) + return X; + } + + // i1 mul -> and. + if (MaxRecurse && Op0->getType()->isIntegerTy(1)) + if (Value *V = SimplifyAndInst(Op0, Op1, TD, DT, MaxRecurse-1)) + return V; + + // Try some generic simplifications for associative operations. + if (Value *V = SimplifyAssociativeBinOp(Instruction::Mul, Op0, Op1, TD, DT, + MaxRecurse)) + return V; + + // Mul distributes over Add. Try some generic simplifications based on this. + if (Value *V = ExpandBinOp(Instruction::Mul, Op0, Op1, Instruction::Add, + TD, DT, MaxRecurse)) + return V; + + // If the operation is with the result of a select instruction, check whether + // operating on either branch of the select always yields the same value. + if (isa(Op0) || isa(Op1)) + if (Value *V = ThreadBinOpOverSelect(Instruction::Mul, Op0, Op1, TD, DT, + MaxRecurse)) + return V; + + // If the operation is with the result of a phi instruction, check whether + // operating on all incoming values of the phi always yields the same value. + if (isa(Op0) || isa(Op1)) + if (Value *V = ThreadBinOpOverPHI(Instruction::Mul, Op0, Op1, TD, DT, + MaxRecurse)) + return V; + + return 0; +} + +Value *llvm::SimplifyMulInst(Value *Op0, Value *Op1, const TargetData *TD, + const DominatorTree *DT) { + return ::SimplifyMulInst(Op0, Op1, TD, DT, RecursionLimit); +} + +/// SimplifyDiv - Given operands for an SDiv or UDiv, see if we can +/// fold the result. If not, this returns null. +static Value *SimplifyDiv(Instruction::BinaryOps Opcode, Value *Op0, Value *Op1, + const TargetData *TD, const DominatorTree *DT, + unsigned MaxRecurse) { + if (Constant *C0 = dyn_cast(Op0)) { + if (Constant *C1 = dyn_cast(Op1)) { + Constant *Ops[] = { C0, C1 }; + return ConstantFoldInstOperands(Opcode, C0->getType(), Ops, 2, TD); + } + } + + bool isSigned = Opcode == Instruction::SDiv; + + // X / undef -> undef + if (match(Op1, m_Undef())) + return Op1; + + // undef / X -> 0 + if (match(Op0, m_Undef())) + return Constant::getNullValue(Op0->getType()); + + // 0 / X -> 0, we don't need to preserve faults! + if (match(Op0, m_Zero())) + return Op0; + + // X / 1 -> X + if (match(Op1, m_One())) + return Op0; + + if (Op0->getType()->isIntegerTy(1)) + // It can't be division by zero, hence it must be division by one. + return Op0; + + // X / X -> 1 + if (Op0 == Op1) + return ConstantInt::get(Op0->getType(), 1); + + // (X * Y) / Y -> X if the multiplication does not overflow. + Value *X = 0, *Y = 0; + if (match(Op0, m_Mul(m_Value(X), m_Value(Y))) && (X == Op1 || Y == Op1)) { + if (Y != Op1) std::swap(X, Y); // Ensure expression is (X * Y) / Y, Y = Op1 + BinaryOperator *Mul = cast(Op0); + // If the Mul knows it does not overflow, then we are good to go. + if ((isSigned && Mul->hasNoSignedWrap()) || + (!isSigned && Mul->hasNoUnsignedWrap())) + return X; + // If X has the form X = A / Y then X * Y cannot overflow. + if (BinaryOperator *Div = dyn_cast(X)) + if (Div->getOpcode() == Opcode && Div->getOperand(1) == Y) + return X; + } + + // (X rem Y) / Y -> 0 + if ((isSigned && match(Op0, m_SRem(m_Value(), m_Specific(Op1)))) || + (!isSigned && match(Op0, m_URem(m_Value(), m_Specific(Op1))))) + return Constant::getNullValue(Op0->getType()); + + // If the operation is with the result of a select instruction, check whether + // operating on either branch of the select always yields the same value. + if (isa(Op0) || isa(Op1)) + if (Value *V = ThreadBinOpOverSelect(Opcode, Op0, Op1, TD, DT, MaxRecurse)) + return V; + + // If the operation is with the result of a phi instruction, check whether + // operating on all incoming values of the phi always yields the same value. + if (isa(Op0) || isa(Op1)) + if (Value *V = ThreadBinOpOverPHI(Opcode, Op0, Op1, TD, DT, MaxRecurse)) + return V; + + return 0; +} + +/// SimplifySDivInst - Given operands for an SDiv, see if we can +/// fold the result. If not, this returns null. +static Value *SimplifySDivInst(Value *Op0, Value *Op1, const TargetData *TD, + const DominatorTree *DT, unsigned MaxRecurse) { + if (Value *V = SimplifyDiv(Instruction::SDiv, Op0, Op1, TD, DT, MaxRecurse)) + return V; + + return 0; +} + +Value *llvm::SimplifySDivInst(Value *Op0, Value *Op1, const TargetData *TD, + const DominatorTree *DT) { + return ::SimplifySDivInst(Op0, Op1, TD, DT, RecursionLimit); +} + +/// SimplifyUDivInst - Given operands for a UDiv, see if we can +/// fold the result. If not, this returns null. +static Value *SimplifyUDivInst(Value *Op0, Value *Op1, const TargetData *TD, + const DominatorTree *DT, unsigned MaxRecurse) { + if (Value *V = SimplifyDiv(Instruction::UDiv, Op0, Op1, TD, DT, MaxRecurse)) + return V; + + return 0; +} + +Value *llvm::SimplifyUDivInst(Value *Op0, Value *Op1, const TargetData *TD, + const DominatorTree *DT) { + return ::SimplifyUDivInst(Op0, Op1, TD, DT, RecursionLimit); +} + +static Value *SimplifyFDivInst(Value *Op0, Value *Op1, const TargetData *, + const DominatorTree *, unsigned) { + // undef / X -> undef (the undef could be a snan). + if (match(Op0, m_Undef())) + return Op0; + + // X / undef -> undef + if (match(Op1, m_Undef())) + return Op1; + + return 0; +} + +Value *llvm::SimplifyFDivInst(Value *Op0, Value *Op1, const TargetData *TD, + const DominatorTree *DT) { + return ::SimplifyFDivInst(Op0, Op1, TD, DT, RecursionLimit); +} + +/// SimplifyShift - Given operands for an Shl, LShr or AShr, see if we can +/// fold the result. If not, this returns null. +static Value *SimplifyShift(unsigned Opcode, Value *Op0, Value *Op1, + const TargetData *TD, const DominatorTree *DT, + unsigned MaxRecurse) { + if (Constant *C0 = dyn_cast(Op0)) { + if (Constant *C1 = dyn_cast(Op1)) { + Constant *Ops[] = { C0, C1 }; + return ConstantFoldInstOperands(Opcode, C0->getType(), Ops, 2, TD); + } + } + + // 0 shift by X -> 0 + if (match(Op0, m_Zero())) + return Op0; + + // X shift by 0 -> X + if (match(Op1, m_Zero())) + return Op0; + + // X shift by undef -> undef because it may shift by the bitwidth. + if (match(Op1, m_Undef())) + return Op1; + + // Shifting by the bitwidth or more is undefined. + if (ConstantInt *CI = dyn_cast(Op1)) + if (CI->getValue().getLimitedValue() >= + Op0->getType()->getScalarSizeInBits()) + return UndefValue::get(Op0->getType()); + + // If the operation is with the result of a select instruction, check whether + // operating on either branch of the select always yields the same value. + if (isa(Op0) || isa(Op1)) + if (Value *V = ThreadBinOpOverSelect(Opcode, Op0, Op1, TD, DT, MaxRecurse)) + return V; + + // If the operation is with the result of a phi instruction, check whether + // operating on all incoming values of the phi always yields the same value. + if (isa(Op0) || isa(Op1)) + if (Value *V = ThreadBinOpOverPHI(Opcode, Op0, Op1, TD, DT, MaxRecurse)) + return V; + + return 0; +} + +/// SimplifyShlInst - Given operands for an Shl, see if we can +/// fold the result. If not, this returns null. +static Value *SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW, + const TargetData *TD, const DominatorTree *DT, + unsigned MaxRecurse) { + if (Value *V = SimplifyShift(Instruction::Shl, Op0, Op1, TD, DT, MaxRecurse)) + return V; + + // undef << X -> 0 + if (match(Op0, m_Undef())) + return Constant::getNullValue(Op0->getType()); + + // (X >> A) << A -> X + Value *X; + if (match(Op0, m_Shr(m_Value(X), m_Specific(Op1))) && + cast(Op0)->isExact()) + return X; + return 0; +} + +Value *llvm::SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW, + const TargetData *TD, const DominatorTree *DT) { + return ::SimplifyShlInst(Op0, Op1, isNSW, isNUW, TD, DT, RecursionLimit); +} + +/// SimplifyLShrInst - Given operands for an LShr, see if we can +/// fold the result. If not, this returns null. +static Value *SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact, + const TargetData *TD, const DominatorTree *DT, + unsigned MaxRecurse) { + if (Value *V = SimplifyShift(Instruction::LShr, Op0, Op1, TD, DT, MaxRecurse)) + return V; + + // undef >>l X -> 0 + if (match(Op0, m_Undef())) + return Constant::getNullValue(Op0->getType()); + + // (X << A) >> A -> X + Value *X; + if (match(Op0, m_Shl(m_Value(X), m_Specific(Op1))) && + cast(Op0)->hasNoUnsignedWrap()) + return X; + return 0; } +Value *llvm::SimplifyLShrInst(Value *Op0, Value *Op1, bool isExact, + const TargetData *TD, const DominatorTree *DT) { + return ::SimplifyLShrInst(Op0, Op1, isExact, TD, DT, RecursionLimit); +} + +/// SimplifyAShrInst - Given operands for an AShr, see if we can +/// fold the result. If not, this returns null. +static Value *SimplifyAShrInst(Value *Op0, Value *Op1, bool isExact, + const TargetData *TD, const DominatorTree *DT, + unsigned MaxRecurse) { + if (Value *V = SimplifyShift(Instruction::AShr, Op0, Op1, TD, DT, MaxRecurse)) + return V; + + // all ones >>a X -> all ones + if (match(Op0, m_AllOnes())) + return Op0; + + // undef >>a X -> all ones + if (match(Op0, m_Undef())) + return Constant::getAllOnesValue(Op0->getType()); + + // (X << A) >> A -> X + Value *X; + if (match(Op0, m_Shl(m_Value(X), m_Specific(Op1))) && + cast(Op0)->hasNoSignedWrap()) + return X; + + return 0; +} + +Value *llvm::SimplifyAShrInst(Value *Op0, Value *Op1, bool isExact, + const TargetData *TD, const DominatorTree *DT) { + return ::SimplifyAShrInst(Op0, Op1, isExact, TD, DT, RecursionLimit); +} + /// SimplifyAndInst - Given operands for an And, see if we can /// fold the result. If not, this returns null. -Value *llvm::SimplifyAndInst(Value *Op0, Value *Op1, const TargetData *TD) { +static Value *SimplifyAndInst(Value *Op0, Value *Op1, const TargetData *TD, + const DominatorTree *DT, unsigned MaxRecurse) { if (Constant *CLHS = dyn_cast(Op0)) { if (Constant *CRHS = dyn_cast(Op1)) { Constant *Ops[] = { CLHS, CRHS }; return ConstantFoldInstOperands(Instruction::And, CLHS->getType(), Ops, 2, TD); } - + // Canonicalize the constant to the RHS. std::swap(Op0, Op1); } - + // X & undef -> 0 - if (isa(Op1)) + if (match(Op1, m_Undef())) return Constant::getNullValue(Op0->getType()); - + // X & X = X if (Op0 == Op1) return Op0; - - // X & <0,0> = <0,0> - if (isa(Op1)) + + // X & 0 = 0 + if (match(Op1, m_Zero())) return Op1; - - // X & <-1,-1> = X - if (ConstantVector *CP = dyn_cast(Op1)) - if (CP->isAllOnesValue()) - return Op0; - - if (ConstantInt *Op1CI = dyn_cast(Op1)) { - // X & 0 = 0 - if (Op1CI->isZero()) - return Op1CI; - // X & -1 = X - if (Op1CI->isAllOnesValue()) - return Op0; - } - + + // X & -1 = X + if (match(Op1, m_AllOnes())) + return Op0; + // A & ~A = ~A & A = 0 - Value *A, *B; - if ((match(Op0, m_Not(m_Value(A))) && A == Op1) || - (match(Op1, m_Not(m_Value(A))) && A == Op0)) + if (match(Op0, m_Not(m_Specific(Op1))) || + match(Op1, m_Not(m_Specific(Op0)))) return Constant::getNullValue(Op0->getType()); - + // (A | ?) & A = A + Value *A = 0, *B = 0; if (match(Op0, m_Or(m_Value(A), m_Value(B))) && (A == Op1 || B == Op1)) return Op1; - + // A & (A | ?) = A if (match(Op1, m_Or(m_Value(A), m_Value(B))) && (A == Op0 || B == Op0)) return Op0; - + + // Try some generic simplifications for associative operations. + if (Value *V = SimplifyAssociativeBinOp(Instruction::And, Op0, Op1, TD, DT, + MaxRecurse)) + return V; + + // And distributes over Or. Try some generic simplifications based on this. + if (Value *V = ExpandBinOp(Instruction::And, Op0, Op1, Instruction::Or, + TD, DT, MaxRecurse)) + return V; + + // And distributes over Xor. Try some generic simplifications based on this. + if (Value *V = ExpandBinOp(Instruction::And, Op0, Op1, Instruction::Xor, + TD, DT, MaxRecurse)) + return V; + + // Or distributes over And. Try some generic simplifications based on this. + if (Value *V = FactorizeBinOp(Instruction::And, Op0, Op1, Instruction::Or, + TD, DT, MaxRecurse)) + return V; + + // If the operation is with the result of a select instruction, check whether + // operating on either branch of the select always yields the same value. + if (isa(Op0) || isa(Op1)) + if (Value *V = ThreadBinOpOverSelect(Instruction::And, Op0, Op1, TD, DT, + MaxRecurse)) + return V; + + // If the operation is with the result of a phi instruction, check whether + // operating on all incoming values of the phi always yields the same value. + if (isa(Op0) || isa(Op1)) + if (Value *V = ThreadBinOpOverPHI(Instruction::And, Op0, Op1, TD, DT, + MaxRecurse)) + return V; + return 0; } +Value *llvm::SimplifyAndInst(Value *Op0, Value *Op1, const TargetData *TD, + const DominatorTree *DT) { + return ::SimplifyAndInst(Op0, Op1, TD, DT, RecursionLimit); +} + /// SimplifyOrInst - Given operands for an Or, see if we can /// fold the result. If not, this returns null. -Value *llvm::SimplifyOrInst(Value *Op0, Value *Op1, const TargetData *TD) { +static Value *SimplifyOrInst(Value *Op0, Value *Op1, const TargetData *TD, + const DominatorTree *DT, unsigned MaxRecurse) { if (Constant *CLHS = dyn_cast(Op0)) { if (Constant *CRHS = dyn_cast(Op1)) { Constant *Ops[] = { CLHS, CRHS }; return ConstantFoldInstOperands(Instruction::Or, CLHS->getType(), Ops, 2, TD); } - + // Canonicalize the constant to the RHS. std::swap(Op0, Op1); } - + // X | undef -> -1 - if (isa(Op1)) + if (match(Op1, m_Undef())) return Constant::getAllOnesValue(Op0->getType()); - + // X | X = X if (Op0 == Op1) return Op0; - // X | <0,0> = X - if (isa(Op1)) + // X | 0 = X + if (match(Op1, m_Zero())) return Op0; - - // X | <-1,-1> = <-1,-1> - if (ConstantVector *CP = dyn_cast(Op1)) - if (CP->isAllOnesValue()) - return Op1; - - if (ConstantInt *Op1CI = dyn_cast(Op1)) { - // X | 0 = X - if (Op1CI->isZero()) - return Op0; - // X | -1 = -1 - if (Op1CI->isAllOnesValue()) - return Op1CI; - } - + + // X | -1 = -1 + if (match(Op1, m_AllOnes())) + return Op1; + // A | ~A = ~A | A = -1 - Value *A, *B; - if ((match(Op0, m_Not(m_Value(A))) && A == Op1) || - (match(Op1, m_Not(m_Value(A))) && A == Op0)) + if (match(Op0, m_Not(m_Specific(Op1))) || + match(Op1, m_Not(m_Specific(Op0)))) return Constant::getAllOnesValue(Op0->getType()); - + // (A & ?) | A = A + Value *A = 0, *B = 0; if (match(Op0, m_And(m_Value(A), m_Value(B))) && (A == Op1 || B == Op1)) return Op1; - + // A | (A & ?) = A if (match(Op1, m_And(m_Value(A), m_Value(B))) && (A == Op0 || B == Op0)) return Op0; - + + // Try some generic simplifications for associative operations. + if (Value *V = SimplifyAssociativeBinOp(Instruction::Or, Op0, Op1, TD, DT, + MaxRecurse)) + return V; + + // Or distributes over And. Try some generic simplifications based on this. + if (Value *V = ExpandBinOp(Instruction::Or, Op0, Op1, Instruction::And, + TD, DT, MaxRecurse)) + return V; + + // And distributes over Or. Try some generic simplifications based on this. + if (Value *V = FactorizeBinOp(Instruction::Or, Op0, Op1, Instruction::And, + TD, DT, MaxRecurse)) + return V; + + // If the operation is with the result of a select instruction, check whether + // operating on either branch of the select always yields the same value. + if (isa(Op0) || isa(Op1)) + if (Value *V = ThreadBinOpOverSelect(Instruction::Or, Op0, Op1, TD, DT, + MaxRecurse)) + return V; + + // If the operation is with the result of a phi instruction, check whether + // operating on all incoming values of the phi always yields the same value. + if (isa(Op0) || isa(Op1)) + if (Value *V = ThreadBinOpOverPHI(Instruction::Or, Op0, Op1, TD, DT, + MaxRecurse)) + return V; + return 0; } +Value *llvm::SimplifyOrInst(Value *Op0, Value *Op1, const TargetData *TD, + const DominatorTree *DT) { + return ::SimplifyOrInst(Op0, Op1, TD, DT, RecursionLimit); +} + +/// SimplifyXorInst - Given operands for a Xor, see if we can +/// fold the result. If not, this returns null. +static Value *SimplifyXorInst(Value *Op0, Value *Op1, const TargetData *TD, + const DominatorTree *DT, unsigned MaxRecurse) { + if (Constant *CLHS = dyn_cast(Op0)) { + if (Constant *CRHS = dyn_cast(Op1)) { + Constant *Ops[] = { CLHS, CRHS }; + return ConstantFoldInstOperands(Instruction::Xor, CLHS->getType(), + Ops, 2, TD); + } + + // Canonicalize the constant to the RHS. + std::swap(Op0, Op1); + } + + // A ^ undef -> undef + if (match(Op1, m_Undef())) + return Op1; + + // A ^ 0 = A + if (match(Op1, m_Zero())) + return Op0; + + // A ^ A = 0 + if (Op0 == Op1) + return Constant::getNullValue(Op0->getType()); + + // A ^ ~A = ~A ^ A = -1 + if (match(Op0, m_Not(m_Specific(Op1))) || + match(Op1, m_Not(m_Specific(Op0)))) + return Constant::getAllOnesValue(Op0->getType()); + + // Try some generic simplifications for associative operations. + if (Value *V = SimplifyAssociativeBinOp(Instruction::Xor, Op0, Op1, TD, DT, + MaxRecurse)) + return V; + + // And distributes over Xor. Try some generic simplifications based on this. + if (Value *V = FactorizeBinOp(Instruction::Xor, Op0, Op1, Instruction::And, + TD, DT, MaxRecurse)) + return V; + + // Threading Xor over selects and phi nodes is pointless, so don't bother. + // Threading over the select in "A ^ select(cond, B, C)" means evaluating + // "A^B" and "A^C" and seeing if they are equal; but they are equal if and + // only if B and C are equal. If B and C are equal then (since we assume + // that operands have already been simplified) "select(cond, B, C)" should + // have been simplified to the common value of B and C already. Analysing + // "A^B" and "A^C" thus gains nothing, but costs compile time. Similarly + // for threading over phi nodes. + + return 0; +} + +Value *llvm::SimplifyXorInst(Value *Op0, Value *Op1, const TargetData *TD, + const DominatorTree *DT) { + return ::SimplifyXorInst(Op0, Op1, TD, DT, RecursionLimit); +} static const Type *GetCompareTy(Value *Op) { return CmpInst::makeCmpResultType(Op->getType()); } - /// SimplifyICmpInst - Given operands for an ICmpInst, see if we can /// fold the result. If not, this returns null. -Value *llvm::SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS, - const TargetData *TD) { +static Value *SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS, + const TargetData *TD, const DominatorTree *DT, + unsigned MaxRecurse) { CmpInst::Predicate Pred = (CmpInst::Predicate)Predicate; assert(CmpInst::isIntPredicate(Pred) && "Not an integer compare!"); - + if (Constant *CLHS = dyn_cast(LHS)) { if (Constant *CRHS = dyn_cast(RHS)) return ConstantFoldCompareInstOperands(Pred, CLHS, CRHS, TD); @@ -189,70 +1277,400 @@ Value *llvm::SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS, std::swap(LHS, RHS); Pred = CmpInst::getSwappedPredicate(Pred); } - - // ITy - This is the return type of the compare we're considering. - const Type *ITy = GetCompareTy(LHS); - + + const Type *ITy = GetCompareTy(LHS); // The return type. + const Type *OpTy = LHS->getType(); // The operand type. + // icmp X, X -> true/false // X icmp undef -> true/false. For example, icmp ugt %X, undef -> false // because X could be 0. if (LHS == RHS || isa(RHS)) return ConstantInt::get(ITy, CmpInst::isTrueWhenEqual(Pred)); - - // icmp , - Global/Stack value - // addresses never equal each other! We already know that Op0 != Op1. - if ((isa(LHS) || isa(LHS) || - isa(LHS)) && - (isa(RHS) || isa(RHS) || - isa(RHS))) - return ConstantInt::get(ITy, CmpInst::isFalseWhenEqual(Pred)); - - // See if we are doing a comparison with a constant. - if (ConstantInt *CI = dyn_cast(RHS)) { - // If we have an icmp le or icmp ge instruction, turn it into the - // appropriate icmp lt or icmp gt instruction. This allows us to rely on - // them being folded in the code below. + + // Special case logic when the operands have i1 type. + if (OpTy->isIntegerTy(1) || (OpTy->isVectorTy() && + cast(OpTy)->getElementType()->isIntegerTy(1))) { switch (Pred) { default: break; + case ICmpInst::ICMP_EQ: + // X == 1 -> X + if (match(RHS, m_One())) + return LHS; + break; + case ICmpInst::ICMP_NE: + // X != 0 -> X + if (match(RHS, m_Zero())) + return LHS; + break; + case ICmpInst::ICMP_UGT: + // X >u 0 -> X + if (match(RHS, m_Zero())) + return LHS; + break; + case ICmpInst::ICMP_UGE: + // X >=u 1 -> X + if (match(RHS, m_One())) + return LHS; + break; + case ICmpInst::ICMP_SLT: + // X X + if (match(RHS, m_Zero())) + return LHS; + break; + case ICmpInst::ICMP_SLE: + // X <=s -1 -> X + if (match(RHS, m_One())) + return LHS; + break; + } + } + + // icmp , - Different stack variables have + // different addresses, and what's more the address of a stack variable is + // never null or equal to the address of a global. Note that generalizing + // to the case where LHS is a global variable address or null is pointless, + // since if both LHS and RHS are constants then we already constant folded + // the compare, and if only one of them is then we moved it to RHS already. + if (isa(LHS) && (isa(RHS) || isa(RHS) || + isa(RHS))) + // We already know that LHS != LHS. + return ConstantInt::get(ITy, CmpInst::isFalseWhenEqual(Pred)); + + // If we are comparing with zero then try hard since this is a common case. + if (match(RHS, m_Zero())) { + bool LHSKnownNonNegative, LHSKnownNegative; + switch (Pred) { + default: + assert(false && "Unknown ICmp predicate!"); + case ICmpInst::ICMP_ULT: + return ConstantInt::getFalse(LHS->getContext()); + case ICmpInst::ICMP_UGE: + return ConstantInt::getTrue(LHS->getContext()); + case ICmpInst::ICMP_EQ: case ICmpInst::ICMP_ULE: - if (CI->isMaxValue(false)) // A <=u MAX -> TRUE - return ConstantInt::getTrue(CI->getContext()); + if (isKnownNonZero(LHS, TD)) + return ConstantInt::getFalse(LHS->getContext()); + break; + case ICmpInst::ICMP_NE: + case ICmpInst::ICMP_UGT: + if (isKnownNonZero(LHS, TD)) + return ConstantInt::getTrue(LHS->getContext()); + break; + case ICmpInst::ICMP_SLT: + ComputeSignBit(LHS, LHSKnownNonNegative, LHSKnownNegative, TD); + if (LHSKnownNegative) + return ConstantInt::getTrue(LHS->getContext()); + if (LHSKnownNonNegative) + return ConstantInt::getFalse(LHS->getContext()); break; case ICmpInst::ICMP_SLE: - if (CI->isMaxValue(true)) // A <=s MAX -> TRUE - return ConstantInt::getTrue(CI->getContext()); + ComputeSignBit(LHS, LHSKnownNonNegative, LHSKnownNegative, TD); + if (LHSKnownNegative) + return ConstantInt::getTrue(LHS->getContext()); + if (LHSKnownNonNegative && isKnownNonZero(LHS, TD)) + return ConstantInt::getFalse(LHS->getContext()); + break; + case ICmpInst::ICMP_SGE: + ComputeSignBit(LHS, LHSKnownNonNegative, LHSKnownNegative, TD); + if (LHSKnownNegative) + return ConstantInt::getFalse(LHS->getContext()); + if (LHSKnownNonNegative) + return ConstantInt::getTrue(LHS->getContext()); + break; + case ICmpInst::ICMP_SGT: + ComputeSignBit(LHS, LHSKnownNonNegative, LHSKnownNegative, TD); + if (LHSKnownNegative) + return ConstantInt::getFalse(LHS->getContext()); + if (LHSKnownNonNegative && isKnownNonZero(LHS, TD)) + return ConstantInt::getTrue(LHS->getContext()); + break; + } + } + + // See if we are doing a comparison with a constant integer. + if (ConstantInt *CI = dyn_cast(RHS)) { + switch (Pred) { + default: break; + case ICmpInst::ICMP_UGT: + if (CI->isMaxValue(false)) // A >u MAX -> FALSE + return ConstantInt::getFalse(CI->getContext()); break; case ICmpInst::ICMP_UGE: if (CI->isMinValue(false)) // A >=u MIN -> TRUE return ConstantInt::getTrue(CI->getContext()); break; + case ICmpInst::ICMP_ULT: + if (CI->isMinValue(false)) // A FALSE + return ConstantInt::getFalse(CI->getContext()); + break; + case ICmpInst::ICMP_ULE: + if (CI->isMaxValue(false)) // A <=u MAX -> TRUE + return ConstantInt::getTrue(CI->getContext()); + break; + case ICmpInst::ICMP_SGT: + if (CI->isMaxValue(true)) // A >s MAX -> FALSE + return ConstantInt::getFalse(CI->getContext()); + break; case ICmpInst::ICMP_SGE: if (CI->isMinValue(true)) // A >=s MIN -> TRUE return ConstantInt::getTrue(CI->getContext()); break; + case ICmpInst::ICMP_SLT: + if (CI->isMinValue(true)) // A FALSE + return ConstantInt::getFalse(CI->getContext()); + break; + case ICmpInst::ICMP_SLE: + if (CI->isMaxValue(true)) // A <=s MAX -> TRUE + return ConstantInt::getTrue(CI->getContext()); + break; + } + } + + // Compare of cast, for example (zext X) != 0 -> X != 0 + if (isa(LHS) && (isa(RHS) || isa(RHS))) { + Instruction *LI = cast(LHS); + Value *SrcOp = LI->getOperand(0); + const Type *SrcTy = SrcOp->getType(); + const Type *DstTy = LI->getType(); + + // Turn icmp (ptrtoint x), (ptrtoint/constant) into a compare of the input + // if the integer type is the same size as the pointer type. + if (MaxRecurse && TD && isa(LI) && + TD->getPointerSizeInBits() == DstTy->getPrimitiveSizeInBits()) { + if (Constant *RHSC = dyn_cast(RHS)) { + // Transfer the cast to the constant. + if (Value *V = SimplifyICmpInst(Pred, SrcOp, + ConstantExpr::getIntToPtr(RHSC, SrcTy), + TD, DT, MaxRecurse-1)) + return V; + } else if (PtrToIntInst *RI = dyn_cast(RHS)) { + if (RI->getOperand(0)->getType() == SrcTy) + // Compare without the cast. + if (Value *V = SimplifyICmpInst(Pred, SrcOp, RI->getOperand(0), + TD, DT, MaxRecurse-1)) + return V; + } + } + + if (isa(LHS)) { + // Turn icmp (zext X), (zext Y) into a compare of X and Y if they have the + // same type. + if (ZExtInst *RI = dyn_cast(RHS)) { + if (MaxRecurse && SrcTy == RI->getOperand(0)->getType()) + // Compare X and Y. Note that signed predicates become unsigned. + if (Value *V = SimplifyICmpInst(ICmpInst::getUnsignedPredicate(Pred), + SrcOp, RI->getOperand(0), TD, DT, + MaxRecurse-1)) + return V; + } + // Turn icmp (zext X), Cst into a compare of X and Cst if Cst is extended + // too. If not, then try to deduce the result of the comparison. + else if (ConstantInt *CI = dyn_cast(RHS)) { + // Compute the constant that would happen if we truncated to SrcTy then + // reextended to DstTy. + Constant *Trunc = ConstantExpr::getTrunc(CI, SrcTy); + Constant *RExt = ConstantExpr::getCast(CastInst::ZExt, Trunc, DstTy); + + // If the re-extended constant didn't change then this is effectively + // also a case of comparing two zero-extended values. + if (RExt == CI && MaxRecurse) + if (Value *V = SimplifyICmpInst(ICmpInst::getUnsignedPredicate(Pred), + SrcOp, Trunc, TD, DT, MaxRecurse-1)) + return V; + + // Otherwise the upper bits of LHS are zero while RHS has a non-zero bit + // there. Use this to work out the result of the comparison. + if (RExt != CI) { + switch (Pred) { + default: + assert(false && "Unknown ICmp predicate!"); + // LHS getContext()); + + case ICmpInst::ICMP_NE: + case ICmpInst::ICMP_ULT: + case ICmpInst::ICMP_ULE: + return ConstantInt::getTrue(CI->getContext()); + + // LHS is non-negative. If RHS is negative then LHS >s LHS. If RHS + // is non-negative then LHS getValue().isNegative() ? + ConstantInt::getTrue(CI->getContext()) : + ConstantInt::getFalse(CI->getContext()); + + case ICmpInst::ICMP_SLT: + case ICmpInst::ICMP_SLE: + return CI->getValue().isNegative() ? + ConstantInt::getFalse(CI->getContext()) : + ConstantInt::getTrue(CI->getContext()); + } + } + } + } + + if (isa(LHS)) { + // Turn icmp (sext X), (sext Y) into a compare of X and Y if they have the + // same type. + if (SExtInst *RI = dyn_cast(RHS)) { + if (MaxRecurse && SrcTy == RI->getOperand(0)->getType()) + // Compare X and Y. Note that the predicate does not change. + if (Value *V = SimplifyICmpInst(Pred, SrcOp, RI->getOperand(0), + TD, DT, MaxRecurse-1)) + return V; + } + // Turn icmp (sext X), Cst into a compare of X and Cst if Cst is extended + // too. If not, then try to deduce the result of the comparison. + else if (ConstantInt *CI = dyn_cast(RHS)) { + // Compute the constant that would happen if we truncated to SrcTy then + // reextended to DstTy. + Constant *Trunc = ConstantExpr::getTrunc(CI, SrcTy); + Constant *RExt = ConstantExpr::getCast(CastInst::SExt, Trunc, DstTy); + + // If the re-extended constant didn't change then this is effectively + // also a case of comparing two sign-extended values. + if (RExt == CI && MaxRecurse) + if (Value *V = SimplifyICmpInst(Pred, SrcOp, Trunc, TD, DT, + MaxRecurse-1)) + return V; + + // Otherwise the upper bits of LHS are all equal, while RHS has varying + // bits there. Use this to work out the result of the comparison. + if (RExt != CI) { + switch (Pred) { + default: + assert(false && "Unknown ICmp predicate!"); + case ICmpInst::ICMP_EQ: + return ConstantInt::getFalse(CI->getContext()); + case ICmpInst::ICMP_NE: + return ConstantInt::getTrue(CI->getContext()); + + // If RHS is non-negative then LHS s RHS. + case ICmpInst::ICMP_SGT: + case ICmpInst::ICMP_SGE: + return CI->getValue().isNegative() ? + ConstantInt::getTrue(CI->getContext()) : + ConstantInt::getFalse(CI->getContext()); + case ICmpInst::ICMP_SLT: + case ICmpInst::ICMP_SLE: + return CI->getValue().isNegative() ? + ConstantInt::getFalse(CI->getContext()) : + ConstantInt::getTrue(CI->getContext()); + + // If LHS is non-negative then LHS u RHS. + case ICmpInst::ICMP_UGT: + case ICmpInst::ICMP_UGE: + // Comparison is true iff the LHS =s 0. + if (MaxRecurse) + if (Value *V = SimplifyICmpInst(ICmpInst::ICMP_SGE, SrcOp, + Constant::getNullValue(SrcTy), + TD, DT, MaxRecurse-1)) + return V; + break; + } + } + } } } - - + + // Special logic for binary operators. + BinaryOperator *LBO = dyn_cast(LHS); + BinaryOperator *RBO = dyn_cast(RHS); + if (MaxRecurse && (LBO || RBO)) { + // Analyze the case when either LHS or RHS is an add instruction. + Value *A = 0, *B = 0, *C = 0, *D = 0; + // LHS = A + B (or A and B are null); RHS = C + D (or C and D are null). + bool NoLHSWrapProblem = false, NoRHSWrapProblem = false; + if (LBO && LBO->getOpcode() == Instruction::Add) { + A = LBO->getOperand(0); B = LBO->getOperand(1); + NoLHSWrapProblem = ICmpInst::isEquality(Pred) || + (CmpInst::isUnsigned(Pred) && LBO->hasNoUnsignedWrap()) || + (CmpInst::isSigned(Pred) && LBO->hasNoSignedWrap()); + } + if (RBO && RBO->getOpcode() == Instruction::Add) { + C = RBO->getOperand(0); D = RBO->getOperand(1); + NoRHSWrapProblem = ICmpInst::isEquality(Pred) || + (CmpInst::isUnsigned(Pred) && RBO->hasNoUnsignedWrap()) || + (CmpInst::isSigned(Pred) && RBO->hasNoSignedWrap()); + } + + // icmp (X+Y), X -> icmp Y, 0 for equalities or if there is no overflow. + if ((A == RHS || B == RHS) && NoLHSWrapProblem) + if (Value *V = SimplifyICmpInst(Pred, A == RHS ? B : A, + Constant::getNullValue(RHS->getType()), + TD, DT, MaxRecurse-1)) + return V; + + // icmp X, (X+Y) -> icmp 0, Y for equalities or if there is no overflow. + if ((C == LHS || D == LHS) && NoRHSWrapProblem) + if (Value *V = SimplifyICmpInst(Pred, + Constant::getNullValue(LHS->getType()), + C == LHS ? D : C, TD, DT, MaxRecurse-1)) + return V; + + // icmp (X+Y), (X+Z) -> icmp Y,Z for equalities or if there is no overflow. + if (A && C && (A == C || A == D || B == C || B == D) && + NoLHSWrapProblem && NoRHSWrapProblem) { + // Determine Y and Z in the form icmp (X+Y), (X+Z). + Value *Y = (A == C || A == D) ? B : A; + Value *Z = (C == A || C == B) ? D : C; + if (Value *V = SimplifyICmpInst(Pred, Y, Z, TD, DT, MaxRecurse-1)) + return V; + } + } + + // If the comparison is with the result of a select instruction, check whether + // comparing with either branch of the select always yields the same value. + if (isa(LHS) || isa(RHS)) + if (Value *V = ThreadCmpOverSelect(Pred, LHS, RHS, TD, DT, MaxRecurse)) + return V; + + // If the comparison is with the result of a phi instruction, check whether + // doing the compare with each incoming phi value yields a common result. + if (isa(LHS) || isa(RHS)) + if (Value *V = ThreadCmpOverPHI(Pred, LHS, RHS, TD, DT, MaxRecurse)) + return V; + return 0; } +Value *llvm::SimplifyICmpInst(unsigned Predicate, Value *LHS, Value *RHS, + const TargetData *TD, const DominatorTree *DT) { + return ::SimplifyICmpInst(Predicate, LHS, RHS, TD, DT, RecursionLimit); +} + /// SimplifyFCmpInst - Given operands for an FCmpInst, see if we can /// fold the result. If not, this returns null. -Value *llvm::SimplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS, - const TargetData *TD) { +static Value *SimplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS, + const TargetData *TD, const DominatorTree *DT, + unsigned MaxRecurse) { CmpInst::Predicate Pred = (CmpInst::Predicate)Predicate; assert(CmpInst::isFPPredicate(Pred) && "Not an FP compare!"); if (Constant *CLHS = dyn_cast(LHS)) { if (Constant *CRHS = dyn_cast(RHS)) return ConstantFoldCompareInstOperands(Pred, CLHS, CRHS, TD); - + // If we have a constant, make sure it is on the RHS. std::swap(LHS, RHS); Pred = CmpInst::getSwappedPredicate(Pred); } - + // Fold trivial predicates. if (Pred == FCmpInst::FCMP_FALSE) return ConstantInt::get(GetCompareTy(LHS), 0); @@ -269,7 +1687,7 @@ Value *llvm::SimplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS, if (CmpInst::isFalseWhenEqual(Pred)) return ConstantInt::get(GetCompareTy(LHS), 0); } - + // Handle fcmp with constant RHS if (Constant *RHSC = dyn_cast(RHS)) { // If the constant is a nan, see if we can fold the comparison based on it. @@ -310,23 +1728,40 @@ Value *llvm::SimplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS, } } } - + + // If the comparison is with the result of a select instruction, check whether + // comparing with either branch of the select always yields the same value. + if (isa(LHS) || isa(RHS)) + if (Value *V = ThreadCmpOverSelect(Pred, LHS, RHS, TD, DT, MaxRecurse)) + return V; + + // If the comparison is with the result of a phi instruction, check whether + // doing the compare with each incoming phi value yields a common result. + if (isa(LHS) || isa(RHS)) + if (Value *V = ThreadCmpOverPHI(Pred, LHS, RHS, TD, DT, MaxRecurse)) + return V; + return 0; } +Value *llvm::SimplifyFCmpInst(unsigned Predicate, Value *LHS, Value *RHS, + const TargetData *TD, const DominatorTree *DT) { + return ::SimplifyFCmpInst(Predicate, LHS, RHS, TD, DT, RecursionLimit); +} + /// SimplifySelectInst - Given operands for a SelectInst, see if we can fold /// the result. If not, this returns null. Value *llvm::SimplifySelectInst(Value *CondVal, Value *TrueVal, Value *FalseVal, - const TargetData *TD) { + const TargetData *TD, const DominatorTree *) { // select true, X, Y -> X // select false, X, Y -> Y if (ConstantInt *CB = dyn_cast(CondVal)) return CB->getZExtValue() ? TrueVal : FalseVal; - + // select C, X, X -> X if (TrueVal == FalseVal) return TrueVal; - + if (isa(TrueVal)) // select C, undef, X -> X return FalseVal; if (isa(FalseVal)) // select C, X, undef -> X @@ -336,98 +1771,249 @@ Value *llvm::SimplifySelectInst(Value *CondVal, Value *TrueVal, Value *FalseVal, return TrueVal; return FalseVal; } - - - + return 0; } - /// SimplifyGEPInst - Given operands for an GetElementPtrInst, see if we can /// fold the result. If not, this returns null. Value *llvm::SimplifyGEPInst(Value *const *Ops, unsigned NumOps, - const TargetData *TD) { + const TargetData *TD, const DominatorTree *) { + // The type of the GEP pointer operand. + const PointerType *PtrTy = cast(Ops[0]->getType()); + // getelementptr P -> P. if (NumOps == 1) return Ops[0]; - // TODO. - //if (isa(Ops[0])) - // return UndefValue::get(GEP.getType()); + if (isa(Ops[0])) { + // Compute the (pointer) type returned by the GEP instruction. + const Type *LastType = GetElementPtrInst::getIndexedType(PtrTy, &Ops[1], + NumOps-1); + const Type *GEPTy = PointerType::get(LastType, PtrTy->getAddressSpace()); + return UndefValue::get(GEPTy); + } - // getelementptr P, 0 -> P. - if (NumOps == 2) + if (NumOps == 2) { + // getelementptr P, 0 -> P. if (ConstantInt *C = dyn_cast(Ops[1])) if (C->isZero()) return Ops[0]; - + // getelementptr P, N -> P if P points to a type of zero size. + if (TD) { + const Type *Ty = PtrTy->getElementType(); + if (Ty->isSized() && TD->getTypeAllocSize(Ty) == 0) + return Ops[0]; + } + } + // Check to see if this is constant foldable. for (unsigned i = 0; i != NumOps; ++i) if (!isa(Ops[i])) return 0; - + return ConstantExpr::getGetElementPtr(cast(Ops[0]), (Constant *const*)Ops+1, NumOps-1); } +/// SimplifyPHINode - See if we can fold the given phi. If not, returns null. +static Value *SimplifyPHINode(PHINode *PN, const DominatorTree *DT) { + // If all of the PHI's incoming values are the same then replace the PHI node + // with the common value. + Value *CommonValue = 0; + bool HasUndefInput = false; + for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { + Value *Incoming = PN->getIncomingValue(i); + // If the incoming value is the phi node itself, it can safely be skipped. + if (Incoming == PN) continue; + if (isa(Incoming)) { + // Remember that we saw an undef value, but otherwise ignore them. + HasUndefInput = true; + continue; + } + if (CommonValue && Incoming != CommonValue) + return 0; // Not the same, bail out. + CommonValue = Incoming; + } + + // If CommonValue is null then all of the incoming values were either undef or + // equal to the phi node itself. + if (!CommonValue) + return UndefValue::get(PN->getType()); + + // If we have a PHI node like phi(X, undef, X), where X is defined by some + // instruction, we cannot return X as the result of the PHI node unless it + // dominates the PHI block. + if (HasUndefInput) + return ValueDominatesPHI(CommonValue, PN, DT) ? CommonValue : 0; + + return CommonValue; +} + //=== Helper functions for higher up the class hierarchy. /// SimplifyBinOp - Given operands for a BinaryOperator, see if we can /// fold the result. If not, this returns null. -Value *llvm::SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS, - const TargetData *TD) { +static Value *SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS, + const TargetData *TD, const DominatorTree *DT, + unsigned MaxRecurse) { switch (Opcode) { - case Instruction::And: return SimplifyAndInst(LHS, RHS, TD); - case Instruction::Or: return SimplifyOrInst(LHS, RHS, TD); + case Instruction::Add: + return SimplifyAddInst(LHS, RHS, /*isNSW*/false, /*isNUW*/false, + TD, DT, MaxRecurse); + case Instruction::Sub: + return SimplifySubInst(LHS, RHS, /*isNSW*/false, /*isNUW*/false, + TD, DT, MaxRecurse); + case Instruction::Mul: return SimplifyMulInst (LHS, RHS, TD, DT, MaxRecurse); + case Instruction::SDiv: return SimplifySDivInst(LHS, RHS, TD, DT, MaxRecurse); + case Instruction::UDiv: return SimplifyUDivInst(LHS, RHS, TD, DT, MaxRecurse); + case Instruction::FDiv: return SimplifyFDivInst(LHS, RHS, TD, DT, MaxRecurse); + case Instruction::Shl: + return SimplifyShlInst(LHS, RHS, /*isNSW*/false, /*isNUW*/false, + TD, DT, MaxRecurse); + case Instruction::LShr: + return SimplifyLShrInst(LHS, RHS, /*isExact*/false, TD, DT, MaxRecurse); + case Instruction::AShr: + return SimplifyAShrInst(LHS, RHS, /*isExact*/false, TD, DT, MaxRecurse); + case Instruction::And: return SimplifyAndInst(LHS, RHS, TD, DT, MaxRecurse); + case Instruction::Or: return SimplifyOrInst (LHS, RHS, TD, DT, MaxRecurse); + case Instruction::Xor: return SimplifyXorInst(LHS, RHS, TD, DT, MaxRecurse); default: if (Constant *CLHS = dyn_cast(LHS)) if (Constant *CRHS = dyn_cast(RHS)) { Constant *COps[] = {CLHS, CRHS}; return ConstantFoldInstOperands(Opcode, LHS->getType(), COps, 2, TD); } + + // If the operation is associative, try some generic simplifications. + if (Instruction::isAssociative(Opcode)) + if (Value *V = SimplifyAssociativeBinOp(Opcode, LHS, RHS, TD, DT, + MaxRecurse)) + return V; + + // If the operation is with the result of a select instruction, check whether + // operating on either branch of the select always yields the same value. + if (isa(LHS) || isa(RHS)) + if (Value *V = ThreadBinOpOverSelect(Opcode, LHS, RHS, TD, DT, + MaxRecurse)) + return V; + + // If the operation is with the result of a phi instruction, check whether + // operating on all incoming values of the phi always yields the same value. + if (isa(LHS) || isa(RHS)) + if (Value *V = ThreadBinOpOverPHI(Opcode, LHS, RHS, TD, DT, MaxRecurse)) + return V; + return 0; } } +Value *llvm::SimplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS, + const TargetData *TD, const DominatorTree *DT) { + return ::SimplifyBinOp(Opcode, LHS, RHS, TD, DT, RecursionLimit); +} + /// SimplifyCmpInst - Given operands for a CmpInst, see if we can /// fold the result. -Value *llvm::SimplifyCmpInst(unsigned Predicate, Value *LHS, Value *RHS, - const TargetData *TD) { +static Value *SimplifyCmpInst(unsigned Predicate, Value *LHS, Value *RHS, + const TargetData *TD, const DominatorTree *DT, + unsigned MaxRecurse) { if (CmpInst::isIntPredicate((CmpInst::Predicate)Predicate)) - return SimplifyICmpInst(Predicate, LHS, RHS, TD); - return SimplifyFCmpInst(Predicate, LHS, RHS, TD); + return SimplifyICmpInst(Predicate, LHS, RHS, TD, DT, MaxRecurse); + return SimplifyFCmpInst(Predicate, LHS, RHS, TD, DT, MaxRecurse); } +Value *llvm::SimplifyCmpInst(unsigned Predicate, Value *LHS, Value *RHS, + const TargetData *TD, const DominatorTree *DT) { + return ::SimplifyCmpInst(Predicate, LHS, RHS, TD, DT, RecursionLimit); +} /// SimplifyInstruction - See if we can compute a simplified version of this /// instruction. If not, this returns null. -Value *llvm::SimplifyInstruction(Instruction *I, const TargetData *TD) { +Value *llvm::SimplifyInstruction(Instruction *I, const TargetData *TD, + const DominatorTree *DT) { + Value *Result; + switch (I->getOpcode()) { default: - return ConstantFoldInstruction(I, TD); + Result = ConstantFoldInstruction(I, TD); + break; case Instruction::Add: - return SimplifyAddInst(I->getOperand(0), I->getOperand(1), - cast(I)->hasNoSignedWrap(), - cast(I)->hasNoUnsignedWrap(), TD); + Result = SimplifyAddInst(I->getOperand(0), I->getOperand(1), + cast(I)->hasNoSignedWrap(), + cast(I)->hasNoUnsignedWrap(), + TD, DT); + break; + case Instruction::Sub: + Result = SimplifySubInst(I->getOperand(0), I->getOperand(1), + cast(I)->hasNoSignedWrap(), + cast(I)->hasNoUnsignedWrap(), + TD, DT); + break; + case Instruction::Mul: + Result = SimplifyMulInst(I->getOperand(0), I->getOperand(1), TD, DT); + break; + case Instruction::SDiv: + Result = SimplifySDivInst(I->getOperand(0), I->getOperand(1), TD, DT); + break; + case Instruction::UDiv: + Result = SimplifyUDivInst(I->getOperand(0), I->getOperand(1), TD, DT); + break; + case Instruction::FDiv: + Result = SimplifyFDivInst(I->getOperand(0), I->getOperand(1), TD, DT); + break; + case Instruction::Shl: + Result = SimplifyShlInst(I->getOperand(0), I->getOperand(1), + cast(I)->hasNoSignedWrap(), + cast(I)->hasNoUnsignedWrap(), + TD, DT); + break; + case Instruction::LShr: + Result = SimplifyLShrInst(I->getOperand(0), I->getOperand(1), + cast(I)->isExact(), + TD, DT); + break; + case Instruction::AShr: + Result = SimplifyAShrInst(I->getOperand(0), I->getOperand(1), + cast(I)->isExact(), + TD, DT); + break; case Instruction::And: - return SimplifyAndInst(I->getOperand(0), I->getOperand(1), TD); + Result = SimplifyAndInst(I->getOperand(0), I->getOperand(1), TD, DT); + break; case Instruction::Or: - return SimplifyOrInst(I->getOperand(0), I->getOperand(1), TD); + Result = SimplifyOrInst(I->getOperand(0), I->getOperand(1), TD, DT); + break; + case Instruction::Xor: + Result = SimplifyXorInst(I->getOperand(0), I->getOperand(1), TD, DT); + break; case Instruction::ICmp: - return SimplifyICmpInst(cast(I)->getPredicate(), - I->getOperand(0), I->getOperand(1), TD); + Result = SimplifyICmpInst(cast(I)->getPredicate(), + I->getOperand(0), I->getOperand(1), TD, DT); + break; case Instruction::FCmp: - return SimplifyFCmpInst(cast(I)->getPredicate(), - I->getOperand(0), I->getOperand(1), TD); + Result = SimplifyFCmpInst(cast(I)->getPredicate(), + I->getOperand(0), I->getOperand(1), TD, DT); + break; case Instruction::Select: - return SimplifySelectInst(I->getOperand(0), I->getOperand(1), - I->getOperand(2), TD); + Result = SimplifySelectInst(I->getOperand(0), I->getOperand(1), + I->getOperand(2), TD, DT); + break; case Instruction::GetElementPtr: { SmallVector Ops(I->op_begin(), I->op_end()); - return SimplifyGEPInst(&Ops[0], Ops.size(), TD); + Result = SimplifyGEPInst(&Ops[0], Ops.size(), TD, DT); + break; } + case Instruction::PHI: + Result = SimplifyPHINode(cast(I), DT); + break; } + + /// If called on unreachable code, the above logic may report that the + /// instruction simplified to itself. Make life easier for users by + /// detecting that case here, returning a safe value instead. + return Result == I ? UndefValue::get(I->getType()) : Result; } /// ReplaceAndSimplifyAllUses - Perform From->replaceAllUsesWith(To) and then @@ -437,15 +2023,16 @@ Value *llvm::SimplifyInstruction(Instruction *I, const TargetData *TD) { /// simplifies and deletes scalar operations, it does not change the CFG. /// void llvm::ReplaceAndSimplifyAllUses(Instruction *From, Value *To, - const TargetData *TD) { + const TargetData *TD, + const DominatorTree *DT) { assert(From != To && "ReplaceAndSimplifyAllUses(X,X) is not valid!"); - + // FromHandle/ToHandle - This keeps a WeakVH on the from/to values so that // we can know if it gets deleted out from under us or replaced in a // recursive simplification. WeakVH FromHandle(From); WeakVH ToHandle(To); - + while (!From->use_empty()) { // Update the instruction to use the new value. Use &TheUse = From->use_begin().getUse(); @@ -460,27 +2047,26 @@ void llvm::ReplaceAndSimplifyAllUses(Instruction *From, Value *To, // Sanity check to make sure 'User' doesn't dangle across // SimplifyInstruction. AssertingVH<> UserHandle(User); - - SimplifiedVal = SimplifyInstruction(User, TD); + + SimplifiedVal = SimplifyInstruction(User, TD, DT); if (SimplifiedVal == 0) continue; } - + // Recursively simplify this user to the new value. - ReplaceAndSimplifyAllUses(User, SimplifiedVal, TD); + ReplaceAndSimplifyAllUses(User, SimplifiedVal, TD, DT); From = dyn_cast_or_null((Value*)FromHandle); To = ToHandle; - + assert(ToHandle && "To value deleted by recursive simplification?"); - + // If the recursive simplification ended up revisiting and deleting // 'From' then we're done. if (From == 0) return; } - + // If 'From' has value handles referring to it, do a real RAUW to update them. From->replaceAllUsesWith(To); - + From->eraseFromParent(); } - diff --git a/lib/Analysis/IntervalPartition.cpp b/lib/Analysis/IntervalPartition.cpp index 1c9e14884316..2e259b147b8b 100644 --- a/lib/Analysis/IntervalPartition.cpp +++ b/lib/Analysis/IntervalPartition.cpp @@ -17,7 +17,7 @@ using namespace llvm; char IntervalPartition::ID = 0; INITIALIZE_PASS(IntervalPartition, "intervals", - "Interval Partition Construction", true, true); + "Interval Partition Construction", true, true) //===----------------------------------------------------------------------===// // IntervalPartition Implementation diff --git a/lib/Analysis/LazyValueInfo.cpp b/lib/Analysis/LazyValueInfo.cpp index e32dbc444713..9e7da6ce2de9 100644 --- a/lib/Analysis/LazyValueInfo.cpp +++ b/lib/Analysis/LazyValueInfo.cpp @@ -14,8 +14,10 @@ #define DEBUG_TYPE "lazy-value-info" #include "llvm/Analysis/LazyValueInfo.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/Constants.h" #include "llvm/Instructions.h" +#include "llvm/IntrinsicInst.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Target/TargetData.h" #include "llvm/Support/CFG.h" @@ -26,11 +28,14 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" +#include +#include +#include using namespace llvm; char LazyValueInfo::ID = 0; INITIALIZE_PASS(LazyValueInfo, "lazy-value-info", - "Lazy Value Information Analysis", false, true); + "Lazy Value Information Analysis", false, true) namespace llvm { FunctionPass *createLazyValueInfoPass() { return new LazyValueInfo(); } @@ -50,18 +55,18 @@ namespace llvm { namespace { class LVILatticeVal { enum LatticeValueTy { - /// undefined - This LLVM Value has no known value yet. + /// undefined - This Value has no known value yet. undefined, - /// constant - This LLVM Value has a specific constant value. + /// constant - This Value has a specific constant value. constant, - /// notconstant - This LLVM value is known to not have the specified value. + /// notconstant - This Value is known to not have the specified value. notconstant, - /// constantrange + /// constantrange - The Value falls within this range. constantrange, - /// overdefined - This instruction is not known to be constant, and we know + /// overdefined - This value is not known to be constant, and we know that /// it has a value. overdefined }; @@ -77,17 +82,13 @@ public: static LVILatticeVal get(Constant *C) { LVILatticeVal Res; - if (ConstantInt *CI = dyn_cast(C)) - Res.markConstantRange(ConstantRange(CI->getValue(), CI->getValue()+1)); - else if (!isa(C)) + if (!isa(C)) Res.markConstant(C); return Res; } static LVILatticeVal getNot(Constant *C) { LVILatticeVal Res; - if (ConstantInt *CI = dyn_cast(C)) - Res.markConstantRange(ConstantRange(CI->getValue()+1, CI->getValue())); - else + if (!isa(C)) Res.markNotConstant(C); return Res; } @@ -129,32 +130,34 @@ public: /// markConstant - Return true if this is a change in status. bool markConstant(Constant *V) { - if (isConstant()) { - assert(getConstant() == V && "Marking constant with different value"); + assert(V && "Marking constant with NULL"); + if (ConstantInt *CI = dyn_cast(V)) + return markConstantRange(ConstantRange(CI->getValue())); + if (isa(V)) return false; - } - + + assert((!isConstant() || getConstant() == V) && + "Marking constant with different value"); assert(isUndefined()); Tag = constant; - assert(V && "Marking constant with NULL"); Val = V; return true; } /// markNotConstant - Return true if this is a change in status. bool markNotConstant(Constant *V) { - if (isNotConstant()) { - assert(getNotConstant() == V && "Marking !constant with different value"); + assert(V && "Marking constant with NULL"); + if (ConstantInt *CI = dyn_cast(V)) + return markConstantRange(ConstantRange(CI->getValue()+1, CI->getValue())); + if (isa(V)) return false; - } - - if (isConstant()) - assert(getConstant() != V && "Marking not constant with different value"); - else - assert(isUndefined()); + assert((!isConstant() || getConstant() != V) && + "Marking constant !constant with same value"); + assert((!isNotConstant() || getNotConstant() == V) && + "Marking !constant with different value"); + assert(isUndefined() || isConstant()); Tag = notconstant; - assert(V && "Marking constant with NULL"); Val = V; return true; } @@ -185,63 +188,81 @@ public: if (RHS.isUndefined() || isOverdefined()) return false; if (RHS.isOverdefined()) return markOverdefined(); - if (RHS.isNotConstant()) { - if (isNotConstant()) { - if (getNotConstant() != RHS.getNotConstant() || - isa(getNotConstant()) || - isa(RHS.getNotConstant())) - return markOverdefined(); - return false; - } else if (isConstant()) { - if (getConstant() == RHS.getNotConstant() || - isa(RHS.getNotConstant()) || - isa(getConstant())) + if (isUndefined()) { + Tag = RHS.Tag; + Val = RHS.Val; + Range = RHS.Range; + return true; + } + + if (isConstant()) { + if (RHS.isConstant()) { + if (Val == RHS.Val) + return false; + return markOverdefined(); + } + + if (RHS.isNotConstant()) { + if (Val == RHS.Val) return markOverdefined(); - return markNotConstant(RHS.getNotConstant()); - } else if (isConstantRange()) { + + // Unless we can prove that the two Constants are different, we must + // move to overdefined. + // FIXME: use TargetData for smarter constant folding. + if (ConstantInt *Res = dyn_cast( + ConstantFoldCompareInstOperands(CmpInst::ICMP_NE, + getConstant(), + RHS.getNotConstant()))) + if (Res->isOne()) + return markNotConstant(RHS.getNotConstant()); + return markOverdefined(); } - - assert(isUndefined() && "Unexpected lattice"); - return markNotConstant(RHS.getNotConstant()); + + // RHS is a ConstantRange, LHS is a non-integer Constant. + + // FIXME: consider the case where RHS is a range [1, 0) and LHS is + // a function. The correct result is to pick up RHS. + + return markOverdefined(); } - - if (RHS.isConstantRange()) { - if (isConstantRange()) { - ConstantRange NewR = Range.unionWith(RHS.getConstantRange()); - if (NewR.isFullSet()) + + if (isNotConstant()) { + if (RHS.isConstant()) { + if (Val == RHS.Val) return markOverdefined(); - else - return markConstantRange(NewR); - } else if (!isUndefined()) { + + // Unless we can prove that the two Constants are different, we must + // move to overdefined. + // FIXME: use TargetData for smarter constant folding. + if (ConstantInt *Res = dyn_cast( + ConstantFoldCompareInstOperands(CmpInst::ICMP_NE, + getNotConstant(), + RHS.getConstant()))) + if (Res->isOne()) + return false; + return markOverdefined(); } - - assert(isUndefined() && "Unexpected lattice"); - return markConstantRange(RHS.getConstantRange()); - } - - // RHS must be a constant, we must be undef, constant, or notconstant. - assert(!isConstantRange() && - "Constant and ConstantRange cannot be merged."); - - if (isUndefined()) - return markConstant(RHS.getConstant()); - - if (isConstant()) { - if (getConstant() != RHS.getConstant()) + + if (RHS.isNotConstant()) { + if (Val == RHS.Val) + return false; return markOverdefined(); - return false; + } + + return markOverdefined(); } - // If we are known "!=4" and RHS is "==5", stay at "!=4". - if (getNotConstant() == RHS.getConstant() || - isa(getNotConstant()) || - isa(RHS.getConstant())) + assert(isConstantRange() && "New LVILattice type?"); + if (!RHS.isConstantRange()) return markOverdefined(); - return false; + + ConstantRange NewR = Range.unionWith(RHS.getConstantRange()); + if (NewR.isFullSet()) + return markOverdefined(); + return markConstantRange(NewR); } - }; } // end anonymous namespace. @@ -267,49 +288,136 @@ raw_ostream &operator<<(raw_ostream &OS, const LVILatticeVal &Val) { //===----------------------------------------------------------------------===// namespace { + /// LVIValueHandle - A callback value handle update the cache when + /// values are erased. + class LazyValueInfoCache; + struct LVIValueHandle : public CallbackVH { + LazyValueInfoCache *Parent; + + LVIValueHandle(Value *V, LazyValueInfoCache *P) + : CallbackVH(V), Parent(P) { } + + void deleted(); + void allUsesReplacedWith(Value *V) { + deleted(); + } + }; +} + +namespace llvm { + template<> + struct DenseMapInfo { + typedef DenseMapInfo PointerInfo; + static inline LVIValueHandle getEmptyKey() { + return LVIValueHandle(PointerInfo::getEmptyKey(), + static_cast(0)); + } + static inline LVIValueHandle getTombstoneKey() { + return LVIValueHandle(PointerInfo::getTombstoneKey(), + static_cast(0)); + } + static unsigned getHashValue(const LVIValueHandle &Val) { + return PointerInfo::getHashValue(Val); + } + static bool isEqual(const LVIValueHandle &LHS, const LVIValueHandle &RHS) { + return LHS == RHS; + } + }; + + template<> + struct DenseMapInfo, Value*> > { + typedef std::pair, Value*> PairTy; + typedef DenseMapInfo > APointerInfo; + typedef DenseMapInfo BPointerInfo; + static inline PairTy getEmptyKey() { + return std::make_pair(APointerInfo::getEmptyKey(), + BPointerInfo::getEmptyKey()); + } + static inline PairTy getTombstoneKey() { + return std::make_pair(APointerInfo::getTombstoneKey(), + BPointerInfo::getTombstoneKey()); + } + static unsigned getHashValue( const PairTy &Val) { + return APointerInfo::getHashValue(Val.first) ^ + BPointerInfo::getHashValue(Val.second); + } + static bool isEqual(const PairTy &LHS, const PairTy &RHS) { + return APointerInfo::isEqual(LHS.first, RHS.first) && + BPointerInfo::isEqual(LHS.second, RHS.second); + } + }; +} + +namespace { /// LazyValueInfoCache - This is the cache kept by LazyValueInfo which /// maintains information about queries across the clients' queries. class LazyValueInfoCache { - public: - /// BlockCacheEntryTy - This is a computed lattice value at the end of the - /// specified basic block for a Value* that depends on context. - typedef std::pair, LVILatticeVal> BlockCacheEntryTy; - /// ValueCacheEntryTy - This is all of the cached block information for /// exactly one Value*. The entries are sorted by the BasicBlock* of the /// entries, allowing us to do a lookup with a binary search. typedef std::map, LVILatticeVal> ValueCacheEntryTy; - private: - /// LVIValueHandle - A callback value handle update the cache when - /// values are erased. - struct LVIValueHandle : public CallbackVH { + /// ValueCache - This is all of the cached information for all values, + /// mapped from Value* to key information. + DenseMap ValueCache; + + /// OverDefinedCache - This tracks, on a per-block basis, the set of + /// values that are over-defined at the end of that block. This is required + /// for cache updating. + typedef std::pair, Value*> OverDefinedPairTy; + DenseSet OverDefinedCache; + + /// BlockValueStack - This stack holds the state of the value solver + /// during a query. It basically emulates the callstack of the naive + /// recursive value lookup process. + std::stack > BlockValueStack; + + friend struct LVIValueHandle; + + /// OverDefinedCacheUpdater - A helper object that ensures that the + /// OverDefinedCache is updated whenever solveBlockValue returns. + struct OverDefinedCacheUpdater { LazyValueInfoCache *Parent; + Value *Val; + BasicBlock *BB; + LVILatticeVal &BBLV; - LVIValueHandle(Value *V, LazyValueInfoCache *P) - : CallbackVH(V), Parent(P) { } + OverDefinedCacheUpdater(Value *V, BasicBlock *B, LVILatticeVal &LV, + LazyValueInfoCache *P) + : Parent(P), Val(V), BB(B), BBLV(LV) { } - void deleted(); - void allUsesReplacedWith(Value* V) { - deleted(); - } - - LVIValueHandle &operator=(Value *V) { - return *this = LVIValueHandle(V, Parent); + bool markResult(bool changed) { + if (changed && BBLV.isOverdefined()) + Parent->OverDefinedCache.insert(std::make_pair(BB, Val)); + return changed; } }; + - /// ValueCache - This is all of the cached information for all values, - /// mapped from Value* to key information. - std::map ValueCache; + + LVILatticeVal getBlockValue(Value *Val, BasicBlock *BB); + bool getEdgeValue(Value *V, BasicBlock *F, BasicBlock *T, + LVILatticeVal &Result); + bool hasBlockValue(Value *Val, BasicBlock *BB); + + // These methods process one work item and may add more. A false value + // returned means that the work item was not completely processed and must + // be revisited after going through the new items. + bool solveBlockValue(Value *Val, BasicBlock *BB); + bool solveBlockValueNonLocal(LVILatticeVal &BBLV, + Value *Val, BasicBlock *BB); + bool solveBlockValuePHINode(LVILatticeVal &BBLV, + PHINode *PN, BasicBlock *BB); + bool solveBlockValueConstantRange(LVILatticeVal &BBLV, + Instruction *BBI, BasicBlock *BB); + + void solve(); - /// OverDefinedCache - This tracks, on a per-block basis, the set of - /// values that are over-defined at the end of that block. This is required - /// for cache updating. - std::set, Value*> > OverDefinedCache; + ValueCacheEntryTy &lookup(Value *V) { + return ValueCache[LVIValueHandle(V, this)]; + } public: - /// getValueInBlock - This is the query interface to determine the lattice /// value for the specified Value* at the end of the specified block. LVILatticeVal getValueInBlock(Value *V, BasicBlock *BB); @@ -335,199 +443,112 @@ namespace { }; } // end anonymous namespace -//===----------------------------------------------------------------------===// -// LVIQuery Impl -//===----------------------------------------------------------------------===// - -namespace { - /// LVIQuery - This is a transient object that exists while a query is - /// being performed. - /// - /// TODO: Reuse LVIQuery instead of recreating it for every query, this avoids - /// reallocation of the densemap on every query. - class LVIQuery { - typedef LazyValueInfoCache::BlockCacheEntryTy BlockCacheEntryTy; - typedef LazyValueInfoCache::ValueCacheEntryTy ValueCacheEntryTy; - - /// This is the current value being queried for. - Value *Val; - - /// This is a pointer to the owning cache, for recursive queries. - LazyValueInfoCache &Parent; - - /// This is all of the cached information about this value. - ValueCacheEntryTy &Cache; - - /// This tracks, for each block, what values are overdefined. - std::set, Value*> > &OverDefinedCache; - - /// NewBlocks - This is a mapping of the new BasicBlocks which have been - /// added to cache but that are not in sorted order. - DenseSet NewBlockInfo; - - public: - - LVIQuery(Value *V, LazyValueInfoCache &P, - ValueCacheEntryTy &VC, - std::set, Value*> > &ODC) - : Val(V), Parent(P), Cache(VC), OverDefinedCache(ODC) { - } - - ~LVIQuery() { - // When the query is done, insert the newly discovered facts into the - // cache in sorted order. - if (NewBlockInfo.empty()) return; - - for (DenseSet::iterator I = NewBlockInfo.begin(), - E = NewBlockInfo.end(); I != E; ++I) { - if (Cache[*I].isOverdefined()) - OverDefinedCache.insert(std::make_pair(*I, Val)); - } - } - - LVILatticeVal getBlockValue(BasicBlock *BB); - LVILatticeVal getEdgeValue(BasicBlock *FromBB, BasicBlock *ToBB); - - private: - LVILatticeVal getCachedEntryForBlock(BasicBlock *BB); - }; -} // end anonymous namespace - -void LazyValueInfoCache::LVIValueHandle::deleted() { - for (std::set, Value*> >::iterator +void LVIValueHandle::deleted() { + typedef std::pair, Value*> OverDefinedPairTy; + + SmallVector ToErase; + for (DenseSet::iterator I = Parent->OverDefinedCache.begin(), E = Parent->OverDefinedCache.end(); - I != E; ) { - std::set, Value*> >::iterator tmp = I; - ++I; - if (tmp->second == getValPtr()) - Parent->OverDefinedCache.erase(tmp); + I != E; ++I) { + if (I->second == getValPtr()) + ToErase.push_back(*I); } + for (SmallVector::iterator I = ToErase.begin(), + E = ToErase.end(); I != E; ++I) + Parent->OverDefinedCache.erase(*I); + // This erasure deallocates *this, so it MUST happen after we're done // using any and all members of *this. Parent->ValueCache.erase(*this); } void LazyValueInfoCache::eraseBlock(BasicBlock *BB) { - for (std::set, Value*> >::iterator - I = OverDefinedCache.begin(), E = OverDefinedCache.end(); I != E; ) { - std::set, Value*> >::iterator tmp = I; - ++I; - if (tmp->first == BB) - OverDefinedCache.erase(tmp); + SmallVector ToErase; + for (DenseSet::iterator I = OverDefinedCache.begin(), + E = OverDefinedCache.end(); I != E; ++I) { + if (I->first == BB) + ToErase.push_back(*I); } + + for (SmallVector::iterator I = ToErase.begin(), + E = ToErase.end(); I != E; ++I) + OverDefinedCache.erase(*I); - for (std::map::iterator + for (DenseMap::iterator I = ValueCache.begin(), E = ValueCache.end(); I != E; ++I) I->second.erase(BB); } -/// getCachedEntryForBlock - See if we already have a value for this block. If -/// so, return it, otherwise create a new entry in the Cache map to use. -LVILatticeVal LVIQuery::getCachedEntryForBlock(BasicBlock *BB) { - NewBlockInfo.insert(BB); - return Cache[BB]; +void LazyValueInfoCache::solve() { + while (!BlockValueStack.empty()) { + std::pair &e = BlockValueStack.top(); + if (solveBlockValue(e.second, e.first)) + BlockValueStack.pop(); + } +} + +bool LazyValueInfoCache::hasBlockValue(Value *Val, BasicBlock *BB) { + // If already a constant, there is nothing to compute. + if (isa(Val)) + return true; + + LVIValueHandle ValHandle(Val, this); + if (!ValueCache.count(ValHandle)) return false; + return ValueCache[ValHandle].count(BB); +} + +LVILatticeVal LazyValueInfoCache::getBlockValue(Value *Val, BasicBlock *BB) { + // If already a constant, there is nothing to compute. + if (Constant *VC = dyn_cast(Val)) + return LVILatticeVal::get(VC); + + return lookup(Val)[BB]; } -LVILatticeVal LVIQuery::getBlockValue(BasicBlock *BB) { - // See if we already have a value for this block. - LVILatticeVal BBLV = getCachedEntryForBlock(BB); +bool LazyValueInfoCache::solveBlockValue(Value *Val, BasicBlock *BB) { + if (isa(Val)) + return true; + + ValueCacheEntryTy &Cache = lookup(Val); + LVILatticeVal &BBLV = Cache[BB]; + // OverDefinedCacheUpdater is a helper object that will update + // the OverDefinedCache for us when this method exits. Make sure to + // call markResult on it as we exist, passing a bool to indicate if the + // cache needs updating, i.e. if we have solve a new value or not. + OverDefinedCacheUpdater ODCacheUpdater(Val, BB, BBLV, this); + // If we've already computed this block's value, return it. if (!BBLV.isUndefined()) { DEBUG(dbgs() << " reuse BB '" << BB->getName() << "' val=" << BBLV <<'\n'); - return BBLV; + + // Since we're reusing a cached value here, we don't need to update the + // OverDefinedCahce. The cache will have been properly updated + // whenever the cached value was inserted. + ODCacheUpdater.markResult(false); + return true; } // Otherwise, this is the first time we're seeing this block. Reset the // lattice value to overdefined, so that cycles will terminate and be // conservatively correct. BBLV.markOverdefined(); - Cache[BB] = BBLV; Instruction *BBI = dyn_cast(Val); if (BBI == 0 || BBI->getParent() != BB) { - LVILatticeVal Result; // Start Undefined. - - // If this is a pointer, and there's a load from that pointer in this BB, - // then we know that the pointer can't be NULL. - bool NotNull = false; - if (Val->getType()->isPointerTy()) { - for (BasicBlock::iterator BI = BB->begin(), BE = BB->end();BI != BE;++BI){ - LoadInst *L = dyn_cast(BI); - if (L && L->getPointerAddressSpace() == 0 && - L->getPointerOperand()->getUnderlyingObject() == - Val->getUnderlyingObject()) { - NotNull = true; - break; - } - } - } - - unsigned NumPreds = 0; - // Loop over all of our predecessors, merging what we know from them into - // result. - for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) { - Result.mergeIn(getEdgeValue(*PI, BB)); - - // If we hit overdefined, exit early. The BlockVals entry is already set - // to overdefined. - if (Result.isOverdefined()) { - DEBUG(dbgs() << " compute BB '" << BB->getName() - << "' - overdefined because of pred.\n"); - // If we previously determined that this is a pointer that can't be null - // then return that rather than giving up entirely. - if (NotNull) { - const PointerType *PTy = cast(Val->getType()); - Result = LVILatticeVal::getNot(ConstantPointerNull::get(PTy)); - } - - return Result; - } - ++NumPreds; - } - - - // If this is the entry block, we must be asking about an argument. The - // value is overdefined. - if (NumPreds == 0 && BB == &BB->getParent()->front()) { - assert(isa(Val) && "Unknown live-in to the entry block"); - Result.markOverdefined(); - return Result; - } - - // Return the merged value, which is more precise than 'overdefined'. - assert(!Result.isOverdefined()); - return Cache[BB] = Result; + return ODCacheUpdater.markResult(solveBlockValueNonLocal(BBLV, Val, BB)); } - - // If this value is defined by an instruction in this block, we have to - // process it here somehow or return overdefined. + if (PHINode *PN = dyn_cast(BBI)) { - LVILatticeVal Result; // Start Undefined. - - // Loop over all of our predecessors, merging what we know from them into - // result. - for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) { - Value* PhiVal = PN->getIncomingValueForBlock(*PI); - Result.mergeIn(Parent.getValueOnEdge(PhiVal, *PI, BB)); - - // If we hit overdefined, exit early. The BlockVals entry is already set - // to overdefined. - if (Result.isOverdefined()) { - DEBUG(dbgs() << " compute BB '" << BB->getName() - << "' - overdefined because of pred.\n"); - return Result; - } - } - - // Return the merged value, which is more precise than 'overdefined'. - assert(!Result.isOverdefined()); - return Cache[BB] = Result; + return ODCacheUpdater.markResult(solveBlockValuePHINode(BBLV, PN, BB)); } - assert(Cache[BB].isOverdefined() && "Recursive query changed our cache?"); + if (AllocaInst *AI = dyn_cast(BBI)) { + BBLV = LVILatticeVal::getNot(ConstantPointerNull::get(AI->getType())); + return ODCacheUpdater.markResult(true); + } // We can only analyze the definitions of certain classes of instructions // (integral binops and casts at the moment), so bail if this isn't one. @@ -536,10 +557,10 @@ LVILatticeVal LVIQuery::getBlockValue(BasicBlock *BB) { !BBI->getType()->isIntegerTy()) { DEBUG(dbgs() << " compute BB '" << BB->getName() << "' - overdefined because inst def found.\n"); - Result.markOverdefined(); - return Result; + BBLV.markOverdefined(); + return ODCacheUpdater.markResult(true); } - + // FIXME: We're currently limited to binops with a constant RHS. This should // be improved. BinaryOperator *BO = dyn_cast(BBI); @@ -547,34 +568,177 @@ LVILatticeVal LVIQuery::getBlockValue(BasicBlock *BB) { DEBUG(dbgs() << " compute BB '" << BB->getName() << "' - overdefined because inst def found.\n"); - Result.markOverdefined(); - return Result; - } + BBLV.markOverdefined(); + return ODCacheUpdater.markResult(true); + } + + return ODCacheUpdater.markResult(solveBlockValueConstantRange(BBLV, BBI, BB)); +} + +static bool InstructionDereferencesPointer(Instruction *I, Value *Ptr) { + if (LoadInst *L = dyn_cast(I)) { + return L->getPointerAddressSpace() == 0 && + GetUnderlyingObject(L->getPointerOperand()) == + GetUnderlyingObject(Ptr); + } + if (StoreInst *S = dyn_cast(I)) { + return S->getPointerAddressSpace() == 0 && + GetUnderlyingObject(S->getPointerOperand()) == + GetUnderlyingObject(Ptr); + } + if (MemIntrinsic *MI = dyn_cast(I)) { + if (MI->isVolatile()) return false; + if (MI->getAddressSpace() != 0) return false; + + // FIXME: check whether it has a valuerange that excludes zero? + ConstantInt *Len = dyn_cast(MI->getLength()); + if (!Len || Len->isZero()) return false; + + if (MI->getRawDest() == Ptr || MI->getDest() == Ptr) + return true; + if (MemTransferInst *MTI = dyn_cast(MI)) + return MTI->getRawSource() == Ptr || MTI->getSource() == Ptr; + } + return false; +} + +bool LazyValueInfoCache::solveBlockValueNonLocal(LVILatticeVal &BBLV, + Value *Val, BasicBlock *BB) { + LVILatticeVal Result; // Start Undefined. + + // If this is a pointer, and there's a load from that pointer in this BB, + // then we know that the pointer can't be NULL. + bool NotNull = false; + if (Val->getType()->isPointerTy()) { + if (isa(Val)) { + NotNull = true; + } else { + for (BasicBlock::iterator BI = BB->begin(), BE = BB->end();BI != BE;++BI){ + if (InstructionDereferencesPointer(BI, Val)) { + NotNull = true; + break; + } + } + } + } + + // If this is the entry block, we must be asking about an argument. The + // value is overdefined. + if (BB == &BB->getParent()->getEntryBlock()) { + assert(isa(Val) && "Unknown live-in to the entry block"); + if (NotNull) { + const PointerType *PTy = cast(Val->getType()); + Result = LVILatticeVal::getNot(ConstantPointerNull::get(PTy)); + } else { + Result.markOverdefined(); + } + BBLV = Result; + return true; + } + + // Loop over all of our predecessors, merging what we know from them into + // result. + bool EdgesMissing = false; + for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) { + LVILatticeVal EdgeResult; + EdgesMissing |= !getEdgeValue(Val, *PI, BB, EdgeResult); + if (EdgesMissing) + continue; + Result.mergeIn(EdgeResult); + + // If we hit overdefined, exit early. The BlockVals entry is already set + // to overdefined. + if (Result.isOverdefined()) { + DEBUG(dbgs() << " compute BB '" << BB->getName() + << "' - overdefined because of pred.\n"); + // If we previously determined that this is a pointer that can't be null + // then return that rather than giving up entirely. + if (NotNull) { + const PointerType *PTy = cast(Val->getType()); + Result = LVILatticeVal::getNot(ConstantPointerNull::get(PTy)); + } + + BBLV = Result; + return true; + } + } + if (EdgesMissing) + return false; + + // Return the merged value, which is more precise than 'overdefined'. + assert(!Result.isOverdefined()); + BBLV = Result; + return true; +} + +bool LazyValueInfoCache::solveBlockValuePHINode(LVILatticeVal &BBLV, + PHINode *PN, BasicBlock *BB) { + LVILatticeVal Result; // Start Undefined. + + // Loop over all of our predecessors, merging what we know from them into + // result. + bool EdgesMissing = false; + for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { + BasicBlock *PhiBB = PN->getIncomingBlock(i); + Value *PhiVal = PN->getIncomingValue(i); + LVILatticeVal EdgeResult; + EdgesMissing |= !getEdgeValue(PhiVal, PhiBB, BB, EdgeResult); + if (EdgesMissing) + continue; + + Result.mergeIn(EdgeResult); + + // If we hit overdefined, exit early. The BlockVals entry is already set + // to overdefined. + if (Result.isOverdefined()) { + DEBUG(dbgs() << " compute BB '" << BB->getName() + << "' - overdefined because of pred.\n"); + + BBLV = Result; + return true; + } + } + if (EdgesMissing) + return false; + + // Return the merged value, which is more precise than 'overdefined'. + assert(!Result.isOverdefined() && "Possible PHI in entry block?"); + BBLV = Result; + return true; +} + +bool LazyValueInfoCache::solveBlockValueConstantRange(LVILatticeVal &BBLV, + Instruction *BBI, + BasicBlock *BB) { // Figure out the range of the LHS. If that fails, bail. - LVILatticeVal LHSVal = Parent.getValueInBlock(BBI->getOperand(0), BB); + if (!hasBlockValue(BBI->getOperand(0), BB)) { + BlockValueStack.push(std::make_pair(BB, BBI->getOperand(0))); + return false; + } + + LVILatticeVal LHSVal = getBlockValue(BBI->getOperand(0), BB); if (!LHSVal.isConstantRange()) { - Result.markOverdefined(); - return Result; + BBLV.markOverdefined(); + return true; } - ConstantInt *RHS = 0; ConstantRange LHSRange = LHSVal.getConstantRange(); ConstantRange RHSRange(1); const IntegerType *ResultTy = cast(BBI->getType()); if (isa(BBI)) { - RHS = dyn_cast(BBI->getOperand(1)); - if (!RHS) { - Result.markOverdefined(); - return Result; + if (ConstantInt *RHS = dyn_cast(BBI->getOperand(1))) { + RHSRange = ConstantRange(RHS->getValue()); + } else { + BBLV.markOverdefined(); + return true; } - - RHSRange = ConstantRange(RHS->getValue(), RHS->getValue()+1); } - + // NOTE: We're currently limited by the set of operations that ConstantRange // can evaluate symbolically. Enhancing that set will allows us to analyze // more definitions. + LVILatticeVal Result; switch (BBI->getOpcode()) { case Instruction::Add: Result.markConstantRange(LHSRange.add(RHSRange)); @@ -606,6 +770,12 @@ LVILatticeVal LVIQuery::getBlockValue(BasicBlock *BB) { case Instruction::BitCast: Result.markConstantRange(LHSRange); break; + case Instruction::And: + Result.markConstantRange(LHSRange.binaryAnd(RHSRange)); + break; + case Instruction::Or: + Result.markConstantRange(LHSRange.binaryOr(RHSRange)); + break; // Unhandled instructions are overdefined. default: @@ -615,12 +785,19 @@ LVILatticeVal LVIQuery::getBlockValue(BasicBlock *BB) { break; } - return Cache[BB] = Result; + BBLV = Result; + return true; } - /// getEdgeValue - This method attempts to infer more complex -LVILatticeVal LVIQuery::getEdgeValue(BasicBlock *BBFrom, BasicBlock *BBTo) { +bool LazyValueInfoCache::getEdgeValue(Value *Val, BasicBlock *BBFrom, + BasicBlock *BBTo, LVILatticeVal &Result) { + // If already a constant, there is nothing to compute. + if (Constant *VC = dyn_cast(Val)) { + Result = LVILatticeVal::get(VC); + return true; + } + // TODO: Handle more complex conditionals. If (v == 0 || v2 < 1) is false, we // know that v != 0. if (BranchInst *BI = dyn_cast(BBFrom->getTerminator())) { @@ -634,9 +811,11 @@ LVILatticeVal LVIQuery::getEdgeValue(BasicBlock *BBFrom, BasicBlock *BBTo) { // If V is the condition of the branch itself, then we know exactly what // it is. - if (BI->getCondition() == Val) - return LVILatticeVal::get(ConstantInt::get( + if (BI->getCondition() == Val) { + Result = LVILatticeVal::get(ConstantInt::get( Type::getInt1Ty(Val->getContext()), isTrueDest)); + return true; + } // If the condition of the branch is an equality comparison, we may be // able to infer the value. @@ -647,30 +826,40 @@ LVILatticeVal LVIQuery::getEdgeValue(BasicBlock *BBFrom, BasicBlock *BBTo) { // We know that V has the RHS constant if this is a true SETEQ or // false SETNE. if (isTrueDest == (ICI->getPredicate() == ICmpInst::ICMP_EQ)) - return LVILatticeVal::get(cast(ICI->getOperand(1))); - return LVILatticeVal::getNot(cast(ICI->getOperand(1))); + Result = LVILatticeVal::get(cast(ICI->getOperand(1))); + else + Result = LVILatticeVal::getNot(cast(ICI->getOperand(1))); + return true; } - + if (ConstantInt *CI = dyn_cast(ICI->getOperand(1))) { // Calculate the range of values that would satisfy the comparison. ConstantRange CmpRange(CI->getValue(), CI->getValue()+1); ConstantRange TrueValues = ConstantRange::makeICmpRegion(ICI->getPredicate(), CmpRange); - + // If we're interested in the false dest, invert the condition. if (!isTrueDest) TrueValues = TrueValues.inverse(); // Figure out the possible values of the query BEFORE this branch. - LVILatticeVal InBlock = getBlockValue(BBFrom); - if (!InBlock.isConstantRange()) - return LVILatticeVal::getRange(TrueValues); - + if (!hasBlockValue(Val, BBFrom)) { + BlockValueStack.push(std::make_pair(BBFrom, Val)); + return false; + } + + LVILatticeVal InBlock = getBlockValue(Val, BBFrom); + if (!InBlock.isConstantRange()) { + Result = LVILatticeVal::getRange(TrueValues); + return true; + } + // Find all potential values that satisfy both the input and output // conditions. ConstantRange PossibleValues = TrueValues.intersectWith(InBlock.getConstantRange()); - - return LVILatticeVal::getRange(PossibleValues); + + Result = LVILatticeVal::getRange(PossibleValues); + return true; } } } @@ -682,9 +871,8 @@ LVILatticeVal LVIQuery::getEdgeValue(BasicBlock *BBFrom, BasicBlock *BBTo) { if (SI->getCondition() == Val) { // We don't know anything in the default case. if (SI->getDefaultDest() == BBTo) { - LVILatticeVal Result; Result.markOverdefined(); - return Result; + return true; } // We only know something if there is exactly one value that goes from @@ -697,51 +885,48 @@ LVILatticeVal LVIQuery::getEdgeValue(BasicBlock *BBFrom, BasicBlock *BBTo) { EdgeVal = SI->getCaseValue(i); } assert(EdgeVal && "Missing successor?"); - if (NumEdges == 1) - return LVILatticeVal::get(EdgeVal); + if (NumEdges == 1) { + Result = LVILatticeVal::get(EdgeVal); + return true; + } } } // Otherwise see if the value is known in the block. - return getBlockValue(BBFrom); + if (hasBlockValue(Val, BBFrom)) { + Result = getBlockValue(Val, BBFrom); + return true; + } + BlockValueStack.push(std::make_pair(BBFrom, Val)); + return false; } - -//===----------------------------------------------------------------------===// -// LazyValueInfoCache Impl -//===----------------------------------------------------------------------===// - LVILatticeVal LazyValueInfoCache::getValueInBlock(Value *V, BasicBlock *BB) { - // If already a constant, there is nothing to compute. - if (Constant *VC = dyn_cast(V)) - return LVILatticeVal::get(VC); - DEBUG(dbgs() << "LVI Getting block end value " << *V << " at '" << BB->getName() << "'\n"); - LVILatticeVal Result = LVIQuery(V, *this, - ValueCache[LVIValueHandle(V, this)], - OverDefinedCache).getBlockValue(BB); - + BlockValueStack.push(std::make_pair(BB, V)); + solve(); + LVILatticeVal Result = getBlockValue(V, BB); + DEBUG(dbgs() << " Result = " << Result << "\n"); return Result; } LVILatticeVal LazyValueInfoCache:: getValueOnEdge(Value *V, BasicBlock *FromBB, BasicBlock *ToBB) { - // If already a constant, there is nothing to compute. - if (Constant *VC = dyn_cast(V)) - return LVILatticeVal::get(VC); - DEBUG(dbgs() << "LVI Getting edge value " << *V << " from '" << FromBB->getName() << "' to '" << ToBB->getName() << "'\n"); - LVILatticeVal Result = - LVIQuery(V, *this, ValueCache[LVIValueHandle(V, this)], - OverDefinedCache).getEdgeValue(FromBB, ToBB); - + LVILatticeVal Result; + if (!getEdgeValue(V, FromBB, ToBB, Result)) { + solve(); + bool WasFastQuery = getEdgeValue(V, FromBB, ToBB, Result); + (void)WasFastQuery; + assert(WasFastQuery && "More work to do after problem solved?"); + } + DEBUG(dbgs() << " Result = " << Result << "\n"); - return Result; } @@ -761,8 +946,8 @@ void LazyValueInfoCache::threadEdge(BasicBlock *PredBB, BasicBlock *OldSucc, worklist.push_back(OldSucc); DenseSet ClearSet; - for (std::set, Value*> >::iterator - I = OverDefinedCache.begin(), E = OverDefinedCache.end(); I != E; ++I) { + for (DenseSet::iterator I = OverDefinedCache.begin(), + E = OverDefinedCache.end(); I != E; ++I) { if (I->first == OldSucc) ClearSet.insert(I->second); } @@ -779,17 +964,17 @@ void LazyValueInfoCache::threadEdge(BasicBlock *PredBB, BasicBlock *OldSucc, if (ToUpdate == NewSucc) continue; bool changed = false; - for (DenseSet::iterator I = ClearSet.begin(),E = ClearSet.end(); + for (DenseSet::iterator I = ClearSet.begin(), E = ClearSet.end(); I != E; ++I) { // If a value was marked overdefined in OldSucc, and is here too... - std::set, Value*> >::iterator OI = + DenseSet::iterator OI = OverDefinedCache.find(std::make_pair(ToUpdate, *I)); if (OI == OverDefinedCache.end()) continue; // Remove it from the caches. ValueCacheEntryTy &Entry = ValueCache[LVIValueHandle(*I, this)]; ValueCacheEntryTy::iterator CI = Entry.find(ToUpdate); - + assert(CI != Entry.end() && "Couldn't find entry to update?"); Entry.erase(CI); OverDefinedCache.erase(OI); @@ -798,7 +983,7 @@ void LazyValueInfoCache::threadEdge(BasicBlock *PredBB, BasicBlock *OldSucc, // blocks successors too. changed = true; } - + if (!changed) continue; worklist.insert(worklist.end(), succ_begin(ToUpdate), succ_end(ToUpdate)); @@ -838,7 +1023,7 @@ Constant *LazyValueInfo::getConstant(Value *V, BasicBlock *BB) { if (Result.isConstant()) return Result.getConstant(); - else if (Result.isConstantRange()) { + if (Result.isConstantRange()) { ConstantRange CR = Result.getConstantRange(); if (const APInt *SingleVal = CR.getSingleElement()) return ConstantInt::get(V->getContext(), *SingleVal); @@ -854,7 +1039,7 @@ Constant *LazyValueInfo::getConstantOnEdge(Value *V, BasicBlock *FromBB, if (Result.isConstant()) return Result.getConstant(); - else if (Result.isConstantRange()) { + if (Result.isConstantRange()) { ConstantRange CR = Result.getConstantRange(); if (const APInt *SingleVal = CR.getSingleElement()) return ConstantInt::get(V->getContext(), *SingleVal); @@ -874,7 +1059,7 @@ LazyValueInfo::getPredicateOnEdge(unsigned Pred, Value *V, Constant *C, Constant *Res = 0; if (Result.isConstant()) { Res = ConstantFoldCompareInstOperands(Pred, Result.getConstant(), C, TD); - if (ConstantInt *ResCI = dyn_cast_or_null(Res)) + if (ConstantInt *ResCI = dyn_cast(Res)) return ResCI->isZero() ? False : True; return Unknown; } @@ -899,13 +1084,12 @@ LazyValueInfo::getPredicateOnEdge(unsigned Pred, Value *V, Constant *C, } // Handle more complex predicates. - ConstantRange RHS(CI->getValue(), CI->getValue()+1); - ConstantRange TrueValues = ConstantRange::makeICmpRegion(Pred, RHS); - if (CR.intersectWith(TrueValues).isEmptySet()) - return False; - else if (TrueValues.contains(CR)) + ConstantRange TrueValues = + ICmpInst::makeConstantRange((ICmpInst::Predicate)Pred, CI->getValue()); + if (TrueValues.contains(CR)) return True; - + if (TrueValues.inverse().contains(CR)) + return False; return Unknown; } @@ -932,7 +1116,7 @@ LazyValueInfo::getPredicateOnEdge(unsigned Pred, Value *V, Constant *C, } void LazyValueInfo::threadEdge(BasicBlock *PredBB, BasicBlock *OldSucc, - BasicBlock* NewSucc) { + BasicBlock *NewSucc) { if (PImpl) getCache(PImpl).threadEdge(PredBB, OldSucc, NewSucc); } diff --git a/lib/Analysis/LibCallAliasAnalysis.cpp b/lib/Analysis/LibCallAliasAnalysis.cpp index 7f51202ecb55..efb722bb97c4 100644 --- a/lib/Analysis/LibCallAliasAnalysis.cpp +++ b/lib/Analysis/LibCallAliasAnalysis.cpp @@ -21,7 +21,7 @@ using namespace llvm; // Register this pass... char LibCallAliasAnalysis::ID = 0; INITIALIZE_AG_PASS(LibCallAliasAnalysis, AliasAnalysis, "libcall-aa", - "LibCall Alias Analysis", false, true, false); + "LibCall Alias Analysis", false, true, false) FunctionPass *llvm::createLibCallAliasAnalysisPass(LibCallInfo *LCI) { return new LibCallAliasAnalysis(LCI); @@ -43,8 +43,8 @@ void LibCallAliasAnalysis::getAnalysisUsage(AnalysisUsage &AU) const { /// vs the specified pointer/size. AliasAnalysis::ModRefResult LibCallAliasAnalysis::AnalyzeLibCallDetails(const LibCallFunctionInfo *FI, - ImmutableCallSite CS, const Value *P, - unsigned Size) { + ImmutableCallSite CS, + const Location &Loc) { // If we have a function, check to see what kind of mod/ref effects it // has. Start by including any info globally known about the function. AliasAnalysis::ModRefResult MRInfo = FI->UniversalBehavior; @@ -64,9 +64,9 @@ LibCallAliasAnalysis::AnalyzeLibCallDetails(const LibCallFunctionInfo *FI, if (FI->DetailsType == LibCallFunctionInfo::DoesNot) { // Find out if the pointer refers to a known location. for (unsigned i = 0; Details[i].LocationID != ~0U; ++i) { - const LibCallLocationInfo &Loc = + const LibCallLocationInfo &LocInfo = LCI->getLocationInfo(Details[i].LocationID); - LibCallLocationInfo::LocResult Res = Loc.isLocation(CS, P, Size); + LibCallLocationInfo::LocResult Res = LocInfo.isLocation(CS, Loc); if (Res != LibCallLocationInfo::Yes) continue; // If we find a match against a location that we 'do not' interact with, @@ -85,9 +85,9 @@ LibCallAliasAnalysis::AnalyzeLibCallDetails(const LibCallFunctionInfo *FI, // Find out if the pointer refers to a known location. bool NoneMatch = true; for (unsigned i = 0; Details[i].LocationID != ~0U; ++i) { - const LibCallLocationInfo &Loc = + const LibCallLocationInfo &LocInfo = LCI->getLocationInfo(Details[i].LocationID); - LibCallLocationInfo::LocResult Res = Loc.isLocation(CS, P, Size); + LibCallLocationInfo::LocResult Res = LocInfo.isLocation(CS, Loc); if (Res == LibCallLocationInfo::No) continue; // If we don't know if this pointer points to the location, then we have to @@ -118,7 +118,7 @@ LibCallAliasAnalysis::AnalyzeLibCallDetails(const LibCallFunctionInfo *FI, // AliasAnalysis::ModRefResult LibCallAliasAnalysis::getModRefInfo(ImmutableCallSite CS, - const Value *P, unsigned Size) { + const Location &Loc) { ModRefResult MRInfo = ModRef; // If this is a direct call to a function that LCI knows about, get the @@ -126,12 +126,12 @@ LibCallAliasAnalysis::getModRefInfo(ImmutableCallSite CS, if (LCI) { if (const Function *F = CS.getCalledFunction()) { if (const LibCallFunctionInfo *FI = LCI->getFunctionInfo(F)) { - MRInfo = ModRefResult(MRInfo & AnalyzeLibCallDetails(FI, CS, P, Size)); + MRInfo = ModRefResult(MRInfo & AnalyzeLibCallDetails(FI, CS, Loc)); if (MRInfo == NoModRef) return NoModRef; } } } // The AliasAnalysis base class has some smarts, lets use them. - return (ModRefResult)(MRInfo | AliasAnalysis::getModRefInfo(CS, P, Size)); + return (ModRefResult)(MRInfo | AliasAnalysis::getModRefInfo(CS, Loc)); } diff --git a/lib/Analysis/Lint.cpp b/lib/Analysis/Lint.cpp index a9d972435f5f..fc7edc0525f9 100644 --- a/lib/Analysis/Lint.cpp +++ b/lib/Analysis/Lint.cpp @@ -70,7 +70,7 @@ namespace { void visitCallSite(CallSite CS); void visitMemoryReference(Instruction &I, Value *Ptr, - unsigned Size, unsigned Align, + uint64_t Size, unsigned Align, const Type *Ty, unsigned Flags); void visitCallInst(CallInst &I); @@ -108,7 +108,9 @@ namespace { raw_string_ostream MessagesStr; static char ID; // Pass identification, replacement for typeid - Lint() : FunctionPass(ID), MessagesStr(Messages) {} + Lint() : FunctionPass(ID), MessagesStr(Messages) { + initializeLintPass(*PassRegistry::getPassRegistry()); + } virtual bool runOnFunction(Function &F); @@ -129,12 +131,6 @@ namespace { } } - void WriteType(const Type *T) { - if (!T) return; - MessagesStr << ' '; - WriteTypeSymbolic(MessagesStr, T, Mod); - } - // CheckFailed - A check failed, so print out the condition and the message // that failed. This provides a nice place to put a breakpoint if you want // to see why something is not correct. @@ -147,27 +143,16 @@ namespace { WriteValue(V3); WriteValue(V4); } - - void CheckFailed(const Twine &Message, const Value *V1, - const Type *T2, const Value *V3 = 0) { - MessagesStr << Message.str() << "\n"; - WriteValue(V1); - WriteType(T2); - WriteValue(V3); - } - - void CheckFailed(const Twine &Message, const Type *T1, - const Type *T2 = 0, const Type *T3 = 0) { - MessagesStr << Message.str() << "\n"; - WriteType(T1); - WriteType(T2); - WriteType(T3); - } }; } char Lint::ID = 0; -INITIALIZE_PASS(Lint, "lint", "Statically lint-checks LLVM IR", false, true); +INITIALIZE_PASS_BEGIN(Lint, "lint", "Statically lint-checks LLVM IR", + false, true) +INITIALIZE_PASS_DEPENDENCY(DominatorTree) +INITIALIZE_AG_DEPENDENCY(AliasAnalysis) +INITIALIZE_PASS_END(Lint, "lint", "Statically lint-checks LLVM IR", + false, true) // Assert - We know that cond should be true, if not print an error message. #define Assert(C, M) \ @@ -208,7 +193,8 @@ void Lint::visitCallSite(CallSite CS) { Instruction &I = *CS.getInstruction(); Value *Callee = CS.getCalledValue(); - visitMemoryReference(I, Callee, ~0u, 0, 0, MemRef::Callee); + visitMemoryReference(I, Callee, AliasAnalysis::UnknownSize, + 0, 0, MemRef::Callee); if (Function *F = dyn_cast(findValue(Callee, /*OffsetOk=*/false))) { Assert1(CS.getCallingConv() == F->getCallingConv(), @@ -240,15 +226,17 @@ void Lint::visitCallSite(CallSite CS) { "Undefined behavior: Call argument type mismatches " "callee parameter type", &I); - // Check that noalias arguments don't alias other arguments. The - // AliasAnalysis API isn't expressive enough for what we really want - // to do. Known partial overlap is not distinguished from the case - // where nothing is known. + // Check that noalias arguments don't alias other arguments. This is + // not fully precise because we don't know the sizes of the dereferenced + // memory regions. if (Formal->hasNoAliasAttr() && Actual->getType()->isPointerTy()) - for (CallSite::arg_iterator BI = CS.arg_begin(); BI != AE; ++BI) { - Assert1(AI == BI || AA->alias(*AI, *BI) != AliasAnalysis::MustAlias, - "Unusual: noalias argument aliases another argument", &I); - } + for (CallSite::arg_iterator BI = CS.arg_begin(); BI != AE; ++BI) + if (AI != BI && (*BI)->getType()->isPointerTy()) { + AliasAnalysis::AliasResult Result = AA->alias(*AI, *BI); + Assert1(Result != AliasAnalysis::MustAlias && + Result != AliasAnalysis::PartialAlias, + "Unusual: noalias argument aliases another argument", &I); + } // Check that an sret argument points to valid memory. if (Formal->hasStructRetAttr() && Actual->getType()->isPointerTy()) { @@ -281,15 +269,17 @@ void Lint::visitCallSite(CallSite CS) { case Intrinsic::memcpy: { MemCpyInst *MCI = cast(&I); // TODO: If the size is known, use it. - visitMemoryReference(I, MCI->getDest(), ~0u, MCI->getAlignment(), 0, + visitMemoryReference(I, MCI->getDest(), AliasAnalysis::UnknownSize, + MCI->getAlignment(), 0, MemRef::Write); - visitMemoryReference(I, MCI->getSource(), ~0u, MCI->getAlignment(), 0, + visitMemoryReference(I, MCI->getSource(), AliasAnalysis::UnknownSize, + MCI->getAlignment(), 0, MemRef::Read); // Check that the memcpy arguments don't overlap. The AliasAnalysis API // isn't expressive enough for what we really want to do. Known partial // overlap is not distinguished from the case where nothing is known. - unsigned Size = 0; + uint64_t Size = 0; if (const ConstantInt *Len = dyn_cast(findValue(MCI->getLength(), /*OffsetOk=*/false))) @@ -303,16 +293,19 @@ void Lint::visitCallSite(CallSite CS) { case Intrinsic::memmove: { MemMoveInst *MMI = cast(&I); // TODO: If the size is known, use it. - visitMemoryReference(I, MMI->getDest(), ~0u, MMI->getAlignment(), 0, + visitMemoryReference(I, MMI->getDest(), AliasAnalysis::UnknownSize, + MMI->getAlignment(), 0, MemRef::Write); - visitMemoryReference(I, MMI->getSource(), ~0u, MMI->getAlignment(), 0, + visitMemoryReference(I, MMI->getSource(), AliasAnalysis::UnknownSize, + MMI->getAlignment(), 0, MemRef::Read); break; } case Intrinsic::memset: { MemSetInst *MSI = cast(&I); // TODO: If the size is known, use it. - visitMemoryReference(I, MSI->getDest(), ~0u, MSI->getAlignment(), 0, + visitMemoryReference(I, MSI->getDest(), AliasAnalysis::UnknownSize, + MSI->getAlignment(), 0, MemRef::Write); break; } @@ -322,24 +315,26 @@ void Lint::visitCallSite(CallSite CS) { "Undefined behavior: va_start called in a non-varargs function", &I); - visitMemoryReference(I, CS.getArgument(0), ~0u, 0, 0, - MemRef::Read | MemRef::Write); + visitMemoryReference(I, CS.getArgument(0), AliasAnalysis::UnknownSize, + 0, 0, MemRef::Read | MemRef::Write); break; case Intrinsic::vacopy: - visitMemoryReference(I, CS.getArgument(0), ~0u, 0, 0, MemRef::Write); - visitMemoryReference(I, CS.getArgument(1), ~0u, 0, 0, MemRef::Read); + visitMemoryReference(I, CS.getArgument(0), AliasAnalysis::UnknownSize, + 0, 0, MemRef::Write); + visitMemoryReference(I, CS.getArgument(1), AliasAnalysis::UnknownSize, + 0, 0, MemRef::Read); break; case Intrinsic::vaend: - visitMemoryReference(I, CS.getArgument(0), ~0u, 0, 0, - MemRef::Read | MemRef::Write); + visitMemoryReference(I, CS.getArgument(0), AliasAnalysis::UnknownSize, + 0, 0, MemRef::Read | MemRef::Write); break; case Intrinsic::stackrestore: // Stackrestore doesn't read or write memory, but it sets the // stack pointer, which the compiler may read from or write to // at any time, so check it for both readability and writeability. - visitMemoryReference(I, CS.getArgument(0), ~0u, 0, 0, - MemRef::Read | MemRef::Write); + visitMemoryReference(I, CS.getArgument(0), AliasAnalysis::UnknownSize, + 0, 0, MemRef::Read | MemRef::Write); break; } } @@ -368,7 +363,7 @@ void Lint::visitReturnInst(ReturnInst &I) { // TODO: Check that the reference is in bounds. // TODO: Check readnone/readonly function attributes. void Lint::visitMemoryReference(Instruction &I, - Value *Ptr, unsigned Size, unsigned Align, + Value *Ptr, uint64_t Size, unsigned Align, const Type *Ty, unsigned Flags) { // If no memory is being referenced, it doesn't matter if the pointer // is valid. @@ -512,12 +507,13 @@ void Lint::visitAllocaInst(AllocaInst &I) { } void Lint::visitVAArgInst(VAArgInst &I) { - visitMemoryReference(I, I.getOperand(0), ~0u, 0, 0, + visitMemoryReference(I, I.getOperand(0), AliasAnalysis::UnknownSize, 0, 0, MemRef::Read | MemRef::Write); } void Lint::visitIndirectBrInst(IndirectBrInst &I) { - visitMemoryReference(I, I.getAddress(), ~0u, 0, 0, MemRef::Branchee); + visitMemoryReference(I, I.getAddress(), AliasAnalysis::UnknownSize, 0, 0, + MemRef::Branchee); Assert1(I.getNumDestinations() != 0, "Undefined behavior: indirectbr with no destinations", &I); @@ -571,7 +567,7 @@ Value *Lint::findValueImpl(Value *V, bool OffsetOk, // TODO: Look through eliminable cast pairs. // TODO: Look through calls with unique return values. // TODO: Look through vector insert/extract/shuffle. - V = OffsetOk ? V->getUnderlyingObject() : V->stripPointerCasts(); + V = OffsetOk ? GetUnderlyingObject(V, TD) : V->stripPointerCasts(); if (LoadInst *L = dyn_cast(V)) { BasicBlock::iterator BBI = L; BasicBlock *BB = L->getParent(); @@ -587,8 +583,9 @@ Value *Lint::findValueImpl(Value *V, bool OffsetOk, BBI = BB->end(); } } else if (PHINode *PN = dyn_cast(V)) { - if (Value *W = PN->hasConstantValue(DT)) - return findValueImpl(W, OffsetOk, Visited); + if (Value *W = PN->hasConstantValue()) + if (W != V) + return findValueImpl(W, OffsetOk, Visited); } else if (CastInst *CI = dyn_cast(V)) { if (CI->isNoopCast(TD ? TD->getIntPtrType(V->getContext()) : Type::getInt64Ty(V->getContext()))) @@ -620,9 +617,8 @@ Value *Lint::findValueImpl(Value *V, bool OffsetOk, // As a last resort, try SimplifyInstruction or constant folding. if (Instruction *Inst = dyn_cast(V)) { - if (Value *W = SimplifyInstruction(Inst, TD)) - if (W != Inst) - return findValueImpl(W, OffsetOk, Visited); + if (Value *W = SimplifyInstruction(Inst, TD, DT)) + return findValueImpl(W, OffsetOk, Visited); } else if (ConstantExpr *CE = dyn_cast(V)) { if (Value *W = ConstantFoldConstantExpression(CE, TD)) if (W != V) diff --git a/lib/Analysis/LiveValues.cpp b/lib/Analysis/LiveValues.cpp index 0225f4fa2548..a0e603419f57 100644 --- a/lib/Analysis/LiveValues.cpp +++ b/lib/Analysis/LiveValues.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Analysis/LiveValues.h" +#include "llvm/Instructions.h" #include "llvm/Analysis/Dominators.h" #include "llvm/Analysis/LoopInfo.h" using namespace llvm; @@ -22,10 +23,16 @@ namespace llvm { } char LiveValues::ID = 0; -INITIALIZE_PASS(LiveValues, "live-values", - "Value Liveness Analysis", false, true); - -LiveValues::LiveValues() : FunctionPass(ID) {} +INITIALIZE_PASS_BEGIN(LiveValues, "live-values", + "Value Liveness Analysis", false, true) +INITIALIZE_PASS_DEPENDENCY(DominatorTree) +INITIALIZE_PASS_DEPENDENCY(LoopInfo) +INITIALIZE_PASS_END(LiveValues, "live-values", + "Value Liveness Analysis", false, true) + +LiveValues::LiveValues() : FunctionPass(ID) { + initializeLiveValuesPass(*PassRegistry::getPassRegistry()); +} void LiveValues::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); diff --git a/lib/Analysis/Loads.cpp b/lib/Analysis/Loads.cpp index 2ba1d86cdb40..2ea27fb62fcb 100644 --- a/lib/Analysis/Loads.cpp +++ b/lib/Analysis/Loads.cpp @@ -49,7 +49,7 @@ static bool AreEquivalentAddressValues(const Value *A, const Value *B) { /// getUnderlyingObjectWithOffset - Strip off up to MaxLookup GEPs and /// bitcasts to get back to the underlying object being addressed, keeping /// track of the offset in bytes from the GEPs relative to the result. -/// This is closely related to Value::getUnderlyingObject but is located +/// This is closely related to GetUnderlyingObject but is located /// here to avoid making VMCore depend on TargetData. static Value *getUnderlyingObjectWithOffset(Value *V, const TargetData *TD, uint64_t &ByteOffset, @@ -166,7 +166,7 @@ Value *llvm::FindAvailableLoadedValue(Value *Ptr, BasicBlock *ScanBB, if (MaxInstsToScan == 0) MaxInstsToScan = ~0U; // If we're using alias analysis to disambiguate get the size of *Ptr. - unsigned AccessSize = 0; + uint64_t AccessSize = 0; if (AA) { const Type *AccessTy = cast(Ptr->getType())->getElementType(); AccessSize = AA->getTypeStoreSize(AccessTy); diff --git a/lib/Analysis/LoopDependenceAnalysis.cpp b/lib/Analysis/LoopDependenceAnalysis.cpp index 82c02dcd1342..c1afe8fbd618 100644 --- a/lib/Analysis/LoopDependenceAnalysis.cpp +++ b/lib/Analysis/LoopDependenceAnalysis.cpp @@ -27,6 +27,8 @@ #include "llvm/Analysis/LoopPass.h" #include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Analysis/ScalarEvolutionExpressions.h" +#include "llvm/Analysis/ValueTracking.h" +#include "llvm/Assembly/Writer.h" #include "llvm/Instructions.h" #include "llvm/Operator.h" #include "llvm/Support/Allocator.h" @@ -46,8 +48,12 @@ LoopPass *llvm::createLoopDependenceAnalysisPass() { return new LoopDependenceAnalysis(); } -INITIALIZE_PASS(LoopDependenceAnalysis, "lda", - "Loop Dependence Analysis", false, true); +INITIALIZE_PASS_BEGIN(LoopDependenceAnalysis, "lda", + "Loop Dependence Analysis", false, true) +INITIALIZE_PASS_DEPENDENCY(ScalarEvolution) +INITIALIZE_AG_DEPENDENCY(AliasAnalysis) +INITIALIZE_PASS_END(LoopDependenceAnalysis, "lda", + "Loop Dependence Analysis", false, true) char LoopDependenceAnalysis::ID = 0; //===----------------------------------------------------------------------===// @@ -86,8 +92,8 @@ static Value *GetPointerOperand(Value *I) { static AliasAnalysis::AliasResult UnderlyingObjectsAlias(AliasAnalysis *AA, const Value *A, const Value *B) { - const Value *aObj = A->getUnderlyingObject(); - const Value *bObj = B->getUnderlyingObject(); + const Value *aObj = GetUnderlyingObject(A); + const Value *bObj = GetUnderlyingObject(B); return AA->alias(aObj, AA->getTypeStoreSize(aObj->getType()), bObj, AA->getTypeStoreSize(bObj->getType())); } @@ -128,7 +134,7 @@ void LoopDependenceAnalysis::getLoops(const SCEV *S, DenseSet* Loops) const { // Refactor this into an SCEVVisitor, if efficiency becomes a concern. for (const Loop *L = this->L; L != 0; L = L->getParentLoop()) - if (!S->isLoopInvariant(L)) + if (!SE->isLoopInvariant(S, L)) Loops->insert(L); } @@ -217,6 +223,7 @@ LoopDependenceAnalysis::analysePair(DependencePair *P) const { switch (UnderlyingObjectsAlias(AA, aPtr, bPtr)) { case AliasAnalysis::MayAlias: + case AliasAnalysis::PartialAlias: // We can not analyse objects if we do not know about their aliasing. DEBUG(dbgs() << "---> [?] may alias\n"); return Unknown; diff --git a/lib/Analysis/LoopInfo.cpp b/lib/Analysis/LoopInfo.cpp index 46219d1b6f55..05831402f409 100644 --- a/lib/Analysis/LoopInfo.cpp +++ b/lib/Analysis/LoopInfo.cpp @@ -38,7 +38,9 @@ VerifyLoopInfoX("verify-loop-info", cl::location(VerifyLoopInfo), cl::desc("Verify loop info (time consuming)")); char LoopInfo::ID = 0; -INITIALIZE_PASS(LoopInfo, "loops", "Natural Loop Information", true, true); +INITIALIZE_PASS_BEGIN(LoopInfo, "loops", "Natural Loop Information", true, true) +INITIALIZE_PASS_DEPENDENCY(DominatorTree) +INITIALIZE_PASS_END(LoopInfo, "loops", "Natural Loop Information", true, true) //===----------------------------------------------------------------------===// // Loop implementation @@ -48,15 +50,18 @@ INITIALIZE_PASS(LoopInfo, "loops", "Natural Loop Information", true, true); /// bool Loop::isLoopInvariant(Value *V) const { if (Instruction *I = dyn_cast(V)) - return isLoopInvariant(I); + return !contains(I); return true; // All non-instructions are loop invariant } -/// isLoopInvariant - Return true if the specified instruction is -/// loop-invariant. -/// -bool Loop::isLoopInvariant(Instruction *I) const { - return !contains(I); +/// hasLoopInvariantOperands - Return true if all the operands of the +/// specified instruction are loop invariant. +bool Loop::hasLoopInvariantOperands(Instruction *I) const { + for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) + if (!isLoopInvariant(I->getOperand(i))) + return false; + + return true; } /// makeLoopInvariant - If the given value is an instruciton inside of the @@ -105,6 +110,7 @@ bool Loop::makeLoopInvariant(Instruction *I, bool &Changed, for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) if (!makeLoopInvariant(I->getOperand(i), Changed, InsertPt)) return false; + // Hoist. I->moveBefore(InsertPt); Changed = true; @@ -192,7 +198,7 @@ Value *Loop::getTripCount() const { /// getSmallConstantTripCount - Returns the trip count of this loop as a /// normal unsigned value, if possible. Returns 0 if the trip count is unknown -/// of not constant. Will also return 0 if the trip count is very large +/// or not constant. Will also return 0 if the trip count is very large /// (>= 2^32) unsigned Loop::getSmallConstantTripCount() const { Value* TripCount = this->getTripCount(); diff --git a/lib/Analysis/LoopPass.cpp b/lib/Analysis/LoopPass.cpp index 15d4db8f5f98..8e1a7bfef699 100644 --- a/lib/Analysis/LoopPass.cpp +++ b/lib/Analysis/LoopPass.cpp @@ -30,7 +30,6 @@ private: public: static char ID; - PrintLoopPass() : LoopPass(ID), Out(dbgs()) {} PrintLoopPass(const std::string &B, raw_ostream &o) : LoopPass(ID), Banner(B), Out(o) {} diff --git a/lib/Analysis/MemDepPrinter.cpp b/lib/Analysis/MemDepPrinter.cpp new file mode 100644 index 000000000000..64d215c37cc7 --- /dev/null +++ b/lib/Analysis/MemDepPrinter.cpp @@ -0,0 +1,167 @@ +//===- MemDepPrinter.cpp - Printer for MemoryDependenceAnalysis -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/MemoryDependenceAnalysis.h" +#include "llvm/LLVMContext.h" +#include "llvm/Analysis/Passes.h" +#include "llvm/Assembly/Writer.h" +#include "llvm/Support/CallSite.h" +#include "llvm/Support/InstIterator.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/SetVector.h" +using namespace llvm; + +namespace { + struct MemDepPrinter : public FunctionPass { + const Function *F; + + typedef PointerIntPair InstAndClobberFlag; + typedef std::pair Dep; + typedef SmallSetVector DepSet; + typedef DenseMap DepSetMap; + DepSetMap Deps; + + static char ID; // Pass identifcation, replacement for typeid + MemDepPrinter() : FunctionPass(ID) { + initializeMemDepPrinterPass(*PassRegistry::getPassRegistry()); + } + + virtual bool runOnFunction(Function &F); + + void print(raw_ostream &OS, const Module * = 0) const; + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequiredTransitive(); + AU.addRequiredTransitive(); + AU.setPreservesAll(); + } + + virtual void releaseMemory() { + Deps.clear(); + F = 0; + } + }; +} + +char MemDepPrinter::ID = 0; +INITIALIZE_PASS_BEGIN(MemDepPrinter, "print-memdeps", + "Print MemDeps of function", false, true) +INITIALIZE_PASS_DEPENDENCY(MemoryDependenceAnalysis) +INITIALIZE_PASS_END(MemDepPrinter, "print-memdeps", + "Print MemDeps of function", false, true) + +FunctionPass *llvm::createMemDepPrinter() { + return new MemDepPrinter(); +} + +bool MemDepPrinter::runOnFunction(Function &F) { + this->F = &F; + AliasAnalysis &AA = getAnalysis(); + MemoryDependenceAnalysis &MDA = getAnalysis(); + + // All this code uses non-const interfaces because MemDep is not + // const-friendly, though nothing is actually modified. + for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) { + Instruction *Inst = &*I; + + if (!Inst->mayReadFromMemory() && !Inst->mayWriteToMemory()) + continue; + + MemDepResult Res = MDA.getDependency(Inst); + if (!Res.isNonLocal()) { + assert(Res.isClobber() != Res.isDef() && + "Local dep should be def or clobber!"); + Deps[Inst].insert(std::make_pair(InstAndClobberFlag(Res.getInst(), + Res.isClobber()), + static_cast(0))); + } else if (CallSite CS = cast(Inst)) { + const MemoryDependenceAnalysis::NonLocalDepInfo &NLDI = + MDA.getNonLocalCallDependency(CS); + + DepSet &InstDeps = Deps[Inst]; + for (MemoryDependenceAnalysis::NonLocalDepInfo::const_iterator + I = NLDI.begin(), E = NLDI.end(); I != E; ++I) { + const MemDepResult &Res = I->getResult(); + assert(Res.isClobber() != Res.isDef() && + "Resolved non-local call dep should be def or clobber!"); + InstDeps.insert(std::make_pair(InstAndClobberFlag(Res.getInst(), + Res.isClobber()), + I->getBB())); + } + } else { + SmallVector NLDI; + if (LoadInst *LI = dyn_cast(Inst)) { + // FIXME: Volatile is not handled properly here. + AliasAnalysis::Location Loc = AA.getLocation(LI); + MDA.getNonLocalPointerDependency(Loc, !LI->isVolatile(), + LI->getParent(), NLDI); + } else if (StoreInst *SI = dyn_cast(Inst)) { + // FIXME: Volatile is not handled properly here. + AliasAnalysis::Location Loc = AA.getLocation(SI); + MDA.getNonLocalPointerDependency(Loc, false, SI->getParent(), NLDI); + } else if (VAArgInst *VI = dyn_cast(Inst)) { + AliasAnalysis::Location Loc = AA.getLocation(VI); + MDA.getNonLocalPointerDependency(Loc, false, VI->getParent(), NLDI); + } else { + llvm_unreachable("Unknown memory instruction!"); + } + + DepSet &InstDeps = Deps[Inst]; + for (SmallVectorImpl::const_iterator + I = NLDI.begin(), E = NLDI.end(); I != E; ++I) { + const MemDepResult &Res = I->getResult(); + assert(Res.isClobber() != Res.isDef() && + "Resolved non-local pointer dep should be def or clobber!"); + InstDeps.insert(std::make_pair(InstAndClobberFlag(Res.getInst(), + Res.isClobber()), + I->getBB())); + } + } + } + + return false; +} + +void MemDepPrinter::print(raw_ostream &OS, const Module *M) const { + for (const_inst_iterator I = inst_begin(*F), E = inst_end(*F); I != E; ++I) { + const Instruction *Inst = &*I; + + DepSetMap::const_iterator DI = Deps.find(Inst); + if (DI == Deps.end()) + continue; + + const DepSet &InstDeps = DI->second; + + for (DepSet::const_iterator I = InstDeps.begin(), E = InstDeps.end(); + I != E; ++I) { + const Instruction *DepInst = I->first.getPointer(); + bool isClobber = I->first.getInt(); + const BasicBlock *DepBB = I->second; + + OS << " " << (isClobber ? "Clobber" : " Def"); + if (DepBB) { + OS << " in block "; + WriteAsOperand(OS, DepBB, /*PrintType=*/false, M); + } + OS << " from: "; + if (DepInst == Inst) + OS << ""; + else + DepInst->print(OS); + OS << "\n"; + } + + Inst->print(OS); + OS << "\n\n"; + } +} diff --git a/lib/Analysis/MemoryDependenceAnalysis.cpp b/lib/Analysis/MemoryDependenceAnalysis.cpp index d18d5ce0ea4c..35043bddfaf6 100644 --- a/lib/Analysis/MemoryDependenceAnalysis.cpp +++ b/lib/Analysis/MemoryDependenceAnalysis.cpp @@ -19,15 +19,18 @@ #include "llvm/Instructions.h" #include "llvm/IntrinsicInst.h" #include "llvm/Function.h" +#include "llvm/LLVMContext.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/Dominators.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/MemoryBuiltins.h" #include "llvm/Analysis/PHITransAddr.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/PredIteratorCache.h" #include "llvm/Support/Debug.h" +#include "llvm/Target/TargetData.h" using namespace llvm; STATISTIC(NumCacheNonLocal, "Number of fully cached non-local responses"); @@ -46,11 +49,15 @@ STATISTIC(NumCacheCompleteNonLocalPtr, char MemoryDependenceAnalysis::ID = 0; // Register this pass... -INITIALIZE_PASS(MemoryDependenceAnalysis, "memdep", - "Memory Dependence Analysis", false, true); +INITIALIZE_PASS_BEGIN(MemoryDependenceAnalysis, "memdep", + "Memory Dependence Analysis", false, true) +INITIALIZE_AG_DEPENDENCY(AliasAnalysis) +INITIALIZE_PASS_END(MemoryDependenceAnalysis, "memdep", + "Memory Dependence Analysis", false, true) MemoryDependenceAnalysis::MemoryDependenceAnalysis() : FunctionPass(ID), PredCache(0) { + initializeMemoryDependenceAnalysisPass(*PassRegistry::getPassRegistry()); } MemoryDependenceAnalysis::~MemoryDependenceAnalysis() { } @@ -77,6 +84,7 @@ void MemoryDependenceAnalysis::getAnalysisUsage(AnalysisUsage &AU) const { bool MemoryDependenceAnalysis::runOnFunction(Function &) { AA = &getAnalysis(); + TD = getAnalysisIfAvailable(); if (PredCache == 0) PredCache.reset(new PredIteratorCache()); return false; @@ -92,11 +100,79 @@ static void RemoveFromReverseMap(DenseMapsecond.erase(Val); - assert(Found && "Invalid reverse map!"); Found=Found; + assert(Found && "Invalid reverse map!"); (void)Found; if (InstIt->second.empty()) ReverseMap.erase(InstIt); } +/// GetLocation - If the given instruction references a specific memory +/// location, fill in Loc with the details, otherwise set Loc.Ptr to null. +/// Return a ModRefInfo value describing the general behavior of the +/// instruction. +static +AliasAnalysis::ModRefResult GetLocation(const Instruction *Inst, + AliasAnalysis::Location &Loc, + AliasAnalysis *AA) { + if (const LoadInst *LI = dyn_cast(Inst)) { + if (LI->isVolatile()) { + Loc = AliasAnalysis::Location(); + return AliasAnalysis::ModRef; + } + Loc = AA->getLocation(LI); + return AliasAnalysis::Ref; + } + + if (const StoreInst *SI = dyn_cast(Inst)) { + if (SI->isVolatile()) { + Loc = AliasAnalysis::Location(); + return AliasAnalysis::ModRef; + } + Loc = AA->getLocation(SI); + return AliasAnalysis::Mod; + } + + if (const VAArgInst *V = dyn_cast(Inst)) { + Loc = AA->getLocation(V); + return AliasAnalysis::ModRef; + } + + if (const CallInst *CI = isFreeCall(Inst)) { + // calls to free() deallocate the entire structure + Loc = AliasAnalysis::Location(CI->getArgOperand(0)); + return AliasAnalysis::Mod; + } + + if (const IntrinsicInst *II = dyn_cast(Inst)) + switch (II->getIntrinsicID()) { + case Intrinsic::lifetime_start: + case Intrinsic::lifetime_end: + case Intrinsic::invariant_start: + Loc = AliasAnalysis::Location(II->getArgOperand(1), + cast(II->getArgOperand(0)) + ->getZExtValue(), + II->getMetadata(LLVMContext::MD_tbaa)); + // These intrinsics don't really modify the memory, but returning Mod + // will allow them to be handled conservatively. + return AliasAnalysis::Mod; + case Intrinsic::invariant_end: + Loc = AliasAnalysis::Location(II->getArgOperand(2), + cast(II->getArgOperand(1)) + ->getZExtValue(), + II->getMetadata(LLVMContext::MD_tbaa)); + // These intrinsics don't really modify the memory, but returning Mod + // will allow them to be handled conservatively. + return AliasAnalysis::Mod; + default: + break; + } + + // Otherwise, just do the coarse-grained thing that always works. + if (Inst->mayWriteToMemory()) + return AliasAnalysis::ModRef; + if (Inst->mayReadFromMemory()) + return AliasAnalysis::Ref; + return AliasAnalysis::NoModRef; +} /// getCallSiteDependencyFrom - Private helper for finding the local /// dependencies of a call site. @@ -108,19 +184,16 @@ getCallSiteDependencyFrom(CallSite CS, bool isReadOnlyCall, Instruction *Inst = --ScanIt; // If this inst is a memory op, get the pointer it accessed - Value *Pointer = 0; - uint64_t PointerSize = 0; - if (StoreInst *S = dyn_cast(Inst)) { - Pointer = S->getPointerOperand(); - PointerSize = AA->getTypeStoreSize(S->getOperand(0)->getType()); - } else if (VAArgInst *V = dyn_cast(Inst)) { - Pointer = V->getOperand(0); - PointerSize = AA->getTypeStoreSize(V->getType()); - } else if (const CallInst *CI = isFreeCall(Inst)) { - Pointer = CI->getArgOperand(0); - // calls to free() erase the entire structure - PointerSize = ~0ULL; - } else if (CallSite InstCS = cast(Inst)) { + AliasAnalysis::Location Loc; + AliasAnalysis::ModRefResult MR = GetLocation(Inst, Loc, AA); + if (Loc.Ptr) { + // A simple instruction. + if (AA->getModRefInfo(CS, Loc) != AliasAnalysis::NoModRef) + return MemDepResult::getClobber(Inst); + continue; + } + + if (CallSite InstCS = cast(Inst)) { // Debug intrinsics don't cause dependences. if (isa(Inst)) continue; // If these two calls do not interfere, look past it. @@ -128,23 +201,17 @@ getCallSiteDependencyFrom(CallSite CS, bool isReadOnlyCall, case AliasAnalysis::NoModRef: // If the two calls are the same, return InstCS as a Def, so that // CS can be found redundant and eliminated. - if (isReadOnlyCall && InstCS.onlyReadsMemory() && + if (isReadOnlyCall && !(MR & AliasAnalysis::Mod) && CS.getInstruction()->isIdenticalToWhenDefined(Inst)) return MemDepResult::getDef(Inst); // Otherwise if the two calls don't interact (e.g. InstCS is readnone) // keep scanning. - continue; + break; default: return MemDepResult::getClobber(Inst); } - } else { - // Non-memory instruction. - continue; } - - if (AA->getModRefInfo(CS, Pointer, PointerSize) != AliasAnalysis::NoModRef) - return MemDepResult::getClobber(Inst); } // No dependence found. If this is the entry block of the function, it is a @@ -155,10 +222,11 @@ getCallSiteDependencyFrom(CallSite CS, bool isReadOnlyCall, } /// getPointerDependencyFrom - Return the instruction on which a memory -/// location depends. If isLoad is true, this routine ignore may-aliases with -/// read-only operations. +/// location depends. If isLoad is true, this routine ignores may-aliases with +/// read-only operations. If isLoad is false, this routine ignores may-aliases +/// with reads from read-only locations. MemDepResult MemoryDependenceAnalysis:: -getPointerDependencyFrom(Value *MemPtr, uint64_t MemSize, bool isLoad, +getPointerDependencyFrom(const AliasAnalysis::Location &MemLoc, bool isLoad, BasicBlock::iterator ScanIt, BasicBlock *BB) { Value *InvariantTag = 0; @@ -175,8 +243,8 @@ getPointerDependencyFrom(Value *MemPtr, uint64_t MemSize, bool isLoad, } if (IntrinsicInst *II = dyn_cast(Inst)) { - // Debug intrinsics don't cause dependences. - if (isa(Inst)) continue; + // Debug intrinsics don't (and can't) cause dependences. + if (isa(II)) continue; // If we pass an invariant-end marker, then we've just entered an // invariant region and can start ignoring dependencies. @@ -184,43 +252,53 @@ getPointerDependencyFrom(Value *MemPtr, uint64_t MemSize, bool isLoad, // FIXME: This only considers queries directly on the invariant-tagged // pointer, not on query pointers that are indexed off of them. It'd // be nice to handle that at some point. - AliasAnalysis::AliasResult R = AA->alias(II->getArgOperand(2), MemPtr); - if (R == AliasAnalysis::MustAlias) { + AliasAnalysis::AliasResult R = + AA->alias(AliasAnalysis::Location(II->getArgOperand(2)), MemLoc); + if (R == AliasAnalysis::MustAlias) InvariantTag = II->getArgOperand(0); - continue; - } - + + continue; + } + // If we reach a lifetime begin or end marker, then the query ends here // because the value is undefined. - } else if (II->getIntrinsicID() == Intrinsic::lifetime_start) { + if (II->getIntrinsicID() == Intrinsic::lifetime_start) { // FIXME: This only considers queries directly on the invariant-tagged // pointer, not on query pointers that are indexed off of them. It'd // be nice to handle that at some point. - AliasAnalysis::AliasResult R = AA->alias(II->getArgOperand(1), MemPtr); + AliasAnalysis::AliasResult R = + AA->alias(AliasAnalysis::Location(II->getArgOperand(1)), MemLoc); if (R == AliasAnalysis::MustAlias) return MemDepResult::getDef(II); + continue; } } // If we're querying on a load and we're in an invariant region, we're done // at this point. Nothing a load depends on can live in an invariant region. + // + // FIXME: this will prevent us from returning load/load must-aliases, so GVN + // won't remove redundant loads. if (isLoad && InvariantTag) continue; // Values depend on loads if the pointers are must aliased. This means that // a load depends on another must aliased load from the same value. if (LoadInst *LI = dyn_cast(Inst)) { - Value *Pointer = LI->getPointerOperand(); - uint64_t PointerSize = AA->getTypeStoreSize(LI->getType()); + AliasAnalysis::Location LoadLoc = AA->getLocation(LI); // If we found a pointer, check if it could be the same as our pointer. - AliasAnalysis::AliasResult R = - AA->alias(Pointer, PointerSize, MemPtr, MemSize); + AliasAnalysis::AliasResult R = AA->alias(LoadLoc, MemLoc); if (R == AliasAnalysis::NoAlias) continue; // May-alias loads don't depend on each other without a dependence. - if (isLoad && R == AliasAnalysis::MayAlias) + if (isLoad && R != AliasAnalysis::MustAlias) continue; + + // Stores don't alias loads from read-only memory. + if (!isLoad && AA->pointsToConstantMemory(LoadLoc)) + continue; + // Stores depend on may and must aliased loads, loads depend on must-alias // loads. return MemDepResult::getDef(Inst); @@ -234,23 +312,21 @@ getPointerDependencyFrom(Value *MemPtr, uint64_t MemSize, bool isLoad, // If alias analysis can tell that this store is guaranteed to not modify // the query pointer, ignore it. Use getModRefInfo to handle cases where // the query pointer points to constant memory etc. - if (AA->getModRefInfo(SI, MemPtr, MemSize) == AliasAnalysis::NoModRef) + if (AA->getModRefInfo(SI, MemLoc) == AliasAnalysis::NoModRef) continue; // Ok, this store might clobber the query pointer. Check to see if it is // a must alias: in this case, we want to return this as a def. - Value *Pointer = SI->getPointerOperand(); - uint64_t PointerSize = AA->getTypeStoreSize(SI->getOperand(0)->getType()); + AliasAnalysis::Location StoreLoc = AA->getLocation(SI); // If we found a pointer, check if it could be the same as our pointer. - AliasAnalysis::AliasResult R = - AA->alias(Pointer, PointerSize, MemPtr, MemSize); + AliasAnalysis::AliasResult R = AA->alias(StoreLoc, MemLoc); if (R == AliasAnalysis::NoAlias) continue; - if (R == AliasAnalysis::MayAlias) - return MemDepResult::getClobber(Inst); - return MemDepResult::getDef(Inst); + if (R == AliasAnalysis::MustAlias) + return MemDepResult::getDef(Inst); + return MemDepResult::getClobber(Inst); } // If this is an allocation, and if we know that the accessed pointer is to @@ -263,7 +339,7 @@ getPointerDependencyFrom(Value *MemPtr, uint64_t MemSize, bool isLoad, // need to continue scanning until the malloc call. if (isa(Inst) || (isa(Inst) && extractMallocCall(Inst))) { - Value *AccessPtr = MemPtr->getUnderlyingObject(); + const Value *AccessPtr = GetUnderlyingObject(MemLoc.Ptr, TD); if (AccessPtr == Inst || AA->alias(Inst, 1, AccessPtr, 1) == AliasAnalysis::MustAlias) @@ -272,7 +348,7 @@ getPointerDependencyFrom(Value *MemPtr, uint64_t MemSize, bool isLoad, } // See if this instruction (e.g. a call or vaarg) mod/ref's the pointer. - switch (AA->getModRefInfo(Inst, MemPtr, MemSize)) { + switch (AA->getModRefInfo(Inst, MemLoc)) { case AliasAnalysis::NoModRef: // If the call has no effect on the queried pointer, just ignore it. continue; @@ -322,9 +398,6 @@ MemDepResult MemoryDependenceAnalysis::getDependency(Instruction *QueryInst) { BasicBlock *QueryParent = QueryInst->getParent(); - Value *MemPtr = 0; - uint64_t MemSize = 0; - // Do the scan. if (BasicBlock::iterator(QueryInst) == QueryParent->begin()) { // No dependence found. If this is the entry block of the function, it is a @@ -333,65 +406,25 @@ MemDepResult MemoryDependenceAnalysis::getDependency(Instruction *QueryInst) { LocalCache = MemDepResult::getNonLocal(); else LocalCache = MemDepResult::getClobber(QueryInst); - } else if (StoreInst *SI = dyn_cast(QueryInst)) { - // If this is a volatile store, don't mess around with it. Just return the - // previous instruction as a clobber. - if (SI->isVolatile()) - LocalCache = MemDepResult::getClobber(--BasicBlock::iterator(ScanPos)); - else { - MemPtr = SI->getPointerOperand(); - MemSize = AA->getTypeStoreSize(SI->getOperand(0)->getType()); - } - } else if (LoadInst *LI = dyn_cast(QueryInst)) { - // If this is a volatile load, don't mess around with it. Just return the - // previous instruction as a clobber. - if (LI->isVolatile()) - LocalCache = MemDepResult::getClobber(--BasicBlock::iterator(ScanPos)); - else { - MemPtr = LI->getPointerOperand(); - MemSize = AA->getTypeStoreSize(LI->getType()); - } - } else if (const CallInst *CI = isFreeCall(QueryInst)) { - MemPtr = CI->getArgOperand(0); - // calls to free() erase the entire structure, not just a field. - MemSize = ~0UL; - } else if (isa(QueryInst) || isa(QueryInst)) { - int IntrinsicID = 0; // Intrinsic IDs start at 1. - IntrinsicInst *II = dyn_cast(QueryInst); - if (II) - IntrinsicID = II->getIntrinsicID(); - - switch (IntrinsicID) { - case Intrinsic::lifetime_start: - case Intrinsic::lifetime_end: - case Intrinsic::invariant_start: - MemPtr = II->getArgOperand(1); - MemSize = cast(II->getArgOperand(0))->getZExtValue(); - break; - case Intrinsic::invariant_end: - MemPtr = II->getArgOperand(2); - MemSize = cast(II->getArgOperand(1))->getZExtValue(); - break; - default: + } else { + AliasAnalysis::Location MemLoc; + AliasAnalysis::ModRefResult MR = GetLocation(QueryInst, MemLoc, AA); + if (MemLoc.Ptr) { + // If we can do a pointer scan, make it happen. + bool isLoad = !(MR & AliasAnalysis::Mod); + if (IntrinsicInst *II = dyn_cast(QueryInst)) + isLoad |= II->getIntrinsicID() == Intrinsic::lifetime_end; + + LocalCache = getPointerDependencyFrom(MemLoc, isLoad, ScanPos, + QueryParent); + } else if (isa(QueryInst) || isa(QueryInst)) { CallSite QueryCS(QueryInst); bool isReadOnly = AA->onlyReadsMemory(QueryCS); LocalCache = getCallSiteDependencyFrom(QueryCS, isReadOnly, ScanPos, QueryParent); - break; - } - } else { - // Non-memory instruction. - LocalCache = MemDepResult::getClobber(--BasicBlock::iterator(ScanPos)); - } - - // If we need to do a pointer scan, make it happen. - if (MemPtr) { - bool isLoad = !QueryInst->mayWriteToMemory(); - if (IntrinsicInst *II = dyn_cast(QueryInst)) { - isLoad |= II->getIntrinsicID() == Intrinsic::lifetime_end; - } - LocalCache = getPointerDependencyFrom(MemPtr, MemSize, isLoad, ScanPos, - QueryParent); + } else + // Non-memory instruction. + LocalCache = MemDepResult::getClobber(--BasicBlock::iterator(ScanPos)); } // Remember the result! @@ -565,31 +598,27 @@ MemoryDependenceAnalysis::getNonLocalCallDependency(CallSite QueryCS) { /// own block. /// void MemoryDependenceAnalysis:: -getNonLocalPointerDependency(Value *Pointer, bool isLoad, BasicBlock *FromBB, +getNonLocalPointerDependency(const AliasAnalysis::Location &Loc, bool isLoad, + BasicBlock *FromBB, SmallVectorImpl &Result) { - assert(Pointer->getType()->isPointerTy() && + assert(Loc.Ptr->getType()->isPointerTy() && "Can't get pointer deps of a non-pointer!"); Result.clear(); - // We know that the pointer value is live into FromBB find the def/clobbers - // from presecessors. - const Type *EltTy = cast(Pointer->getType())->getElementType(); - uint64_t PointeeSize = AA->getTypeStoreSize(EltTy); - - PHITransAddr Address(Pointer, TD); + PHITransAddr Address(const_cast(Loc.Ptr), TD); // This is the set of blocks we've inspected, and the pointer we consider in // each block. Because of critical edges, we currently bail out if querying // a block with multiple different pointers. This can happen during PHI // translation. DenseMap Visited; - if (!getNonLocalPointerDepFromBB(Address, PointeeSize, isLoad, FromBB, + if (!getNonLocalPointerDepFromBB(Address, Loc, isLoad, FromBB, Result, Visited, true)) return; Result.clear(); Result.push_back(NonLocalDepResult(FromBB, MemDepResult::getClobber(FromBB->begin()), - Pointer)); + const_cast(Loc.Ptr))); } /// GetNonLocalInfoForBlock - Compute the memdep value for BB with @@ -597,7 +626,7 @@ getNonLocalPointerDependency(Value *Pointer, bool isLoad, BasicBlock *FromBB, /// lookup (which may use dirty cache info if available). If we do a lookup, /// add the result to the cache. MemDepResult MemoryDependenceAnalysis:: -GetNonLocalInfoForBlock(Value *Pointer, uint64_t PointeeSize, +GetNonLocalInfoForBlock(const AliasAnalysis::Location &Loc, bool isLoad, BasicBlock *BB, NonLocalDepInfo *Cache, unsigned NumSortedEntries) { @@ -631,15 +660,14 @@ GetNonLocalInfoForBlock(Value *Pointer, uint64_t PointeeSize, ScanPos = ExistingResult->getResult().getInst(); // Eliminating the dirty entry from 'Cache', so update the reverse info. - ValueIsLoadPair CacheKey(Pointer, isLoad); + ValueIsLoadPair CacheKey(Loc.Ptr, isLoad); RemoveFromReverseMap(ReverseNonLocalPtrDeps, ScanPos, CacheKey); } else { ++NumUncacheNonLocalPtr; } // Scan the block for the dependency. - MemDepResult Dep = getPointerDependencyFrom(Pointer, PointeeSize, isLoad, - ScanPos, BB); + MemDepResult Dep = getPointerDependencyFrom(Loc, isLoad, ScanPos, BB); // If we had a dirty entry for the block, update it. Otherwise, just add // a new entry. @@ -658,7 +686,7 @@ GetNonLocalInfoForBlock(Value *Pointer, uint64_t PointeeSize, // update MemDep when we remove instructions. Instruction *Inst = Dep.getInst(); assert(Inst && "Didn't depend on anything?"); - ValueIsLoadPair CacheKey(Pointer, isLoad); + ValueIsLoadPair CacheKey(Loc.Ptr, isLoad); ReverseNonLocalPtrDeps[Inst].insert(CacheKey); return Dep; } @@ -712,7 +740,8 @@ SortNonLocalDepInfoCache(MemoryDependenceAnalysis::NonLocalDepInfo &Cache, /// not compute dependence information for some reason. This should be treated /// as a clobber dependence on the first instruction in the predecessor block. bool MemoryDependenceAnalysis:: -getNonLocalPointerDepFromBB(const PHITransAddr &Pointer, uint64_t PointeeSize, +getNonLocalPointerDepFromBB(const PHITransAddr &Pointer, + const AliasAnalysis::Location &Loc, bool isLoad, BasicBlock *StartBB, SmallVectorImpl &Result, DenseMap &Visited, @@ -720,14 +749,68 @@ getNonLocalPointerDepFromBB(const PHITransAddr &Pointer, uint64_t PointeeSize, // Look up the cached info for Pointer. ValueIsLoadPair CacheKey(Pointer.getAddr(), isLoad); - - std::pair *CacheInfo = - &NonLocalPointerDeps[CacheKey]; - NonLocalDepInfo *Cache = &CacheInfo->second; + + // Set up a temporary NLPI value. If the map doesn't yet have an entry for + // CacheKey, this value will be inserted as the associated value. Otherwise, + // it'll be ignored, and we'll have to check to see if the cached size and + // tbaa tag are consistent with the current query. + NonLocalPointerInfo InitialNLPI; + InitialNLPI.Size = Loc.Size; + InitialNLPI.TBAATag = Loc.TBAATag; + + // Get the NLPI for CacheKey, inserting one into the map if it doesn't + // already have one. + std::pair Pair = + NonLocalPointerDeps.insert(std::make_pair(CacheKey, InitialNLPI)); + NonLocalPointerInfo *CacheInfo = &Pair.first->second; + + // If we already have a cache entry for this CacheKey, we may need to do some + // work to reconcile the cache entry and the current query. + if (!Pair.second) { + if (CacheInfo->Size < Loc.Size) { + // The query's Size is greater than the cached one. Throw out the + // cached data and procede with the query at the greater size. + CacheInfo->Pair = BBSkipFirstBlockPair(); + CacheInfo->Size = Loc.Size; + for (NonLocalDepInfo::iterator DI = CacheInfo->NonLocalDeps.begin(), + DE = CacheInfo->NonLocalDeps.end(); DI != DE; ++DI) + if (Instruction *Inst = DI->getResult().getInst()) + RemoveFromReverseMap(ReverseNonLocalPtrDeps, Inst, CacheKey); + CacheInfo->NonLocalDeps.clear(); + } else if (CacheInfo->Size > Loc.Size) { + // This query's Size is less than the cached one. Conservatively restart + // the query using the greater size. + return getNonLocalPointerDepFromBB(Pointer, + Loc.getWithNewSize(CacheInfo->Size), + isLoad, StartBB, Result, Visited, + SkipFirstBlock); + } + + // If the query's TBAATag is inconsistent with the cached one, + // conservatively throw out the cached data and restart the query with + // no tag if needed. + if (CacheInfo->TBAATag != Loc.TBAATag) { + if (CacheInfo->TBAATag) { + CacheInfo->Pair = BBSkipFirstBlockPair(); + CacheInfo->TBAATag = 0; + for (NonLocalDepInfo::iterator DI = CacheInfo->NonLocalDeps.begin(), + DE = CacheInfo->NonLocalDeps.end(); DI != DE; ++DI) + if (Instruction *Inst = DI->getResult().getInst()) + RemoveFromReverseMap(ReverseNonLocalPtrDeps, Inst, CacheKey); + CacheInfo->NonLocalDeps.clear(); + } + if (Loc.TBAATag) + return getNonLocalPointerDepFromBB(Pointer, Loc.getWithoutTBAATag(), + isLoad, StartBB, Result, Visited, + SkipFirstBlock); + } + } + + NonLocalDepInfo *Cache = &CacheInfo->NonLocalDeps; // If we have valid cached information for exactly the block we are // investigating, just return it with no recomputation. - if (CacheInfo->first == BBSkipFirstBlockPair(StartBB, SkipFirstBlock)) { + if (CacheInfo->Pair == BBSkipFirstBlockPair(StartBB, SkipFirstBlock)) { // We have a fully cached result for this query then we can just return the // cached results and populate the visited set. However, we have to verify // that we don't already have conflicting results for these blocks. Check @@ -763,9 +846,9 @@ getNonLocalPointerDepFromBB(const PHITransAddr &Pointer, uint64_t PointeeSize, // than its valid cache info. If empty, the result will be valid cache info, // otherwise it isn't. if (Cache->empty()) - CacheInfo->first = BBSkipFirstBlockPair(StartBB, SkipFirstBlock); + CacheInfo->Pair = BBSkipFirstBlockPair(StartBB, SkipFirstBlock); else - CacheInfo->first = BBSkipFirstBlockPair(); + CacheInfo->Pair = BBSkipFirstBlockPair(); SmallVector Worklist; Worklist.push_back(StartBB); @@ -790,8 +873,7 @@ getNonLocalPointerDepFromBB(const PHITransAddr &Pointer, uint64_t PointeeSize, // Get the dependency info for Pointer in BB. If we have cached // information, we will use it, otherwise we compute it. DEBUG(AssertSorted(*Cache, NumSortedEntries)); - MemDepResult Dep = GetNonLocalInfoForBlock(Pointer.getAddr(), PointeeSize, - isLoad, BB, Cache, + MemDepResult Dep = GetNonLocalInfoForBlock(Loc, isLoad, BB, Cache, NumSortedEntries); // If we got a Def or Clobber, add this to the list of results. @@ -888,7 +970,8 @@ getNonLocalPointerDepFromBB(const PHITransAddr &Pointer, uint64_t PointeeSize, // queries. Mark this in NonLocalPointerDeps by setting the // BBSkipFirstBlockPair pointer to null. This requires reuse of the // cached value to do more work but not miss the phi trans failure. - NonLocalPointerDeps[CacheKey].first = BBSkipFirstBlockPair(); + NonLocalPointerInfo &NLPI = NonLocalPointerDeps[CacheKey]; + NLPI.Pair = BBSkipFirstBlockPair(); continue; } @@ -899,21 +982,23 @@ getNonLocalPointerDepFromBB(const PHITransAddr &Pointer, uint64_t PointeeSize, // If we have a problem phi translating, fall through to the code below // to handle the failure condition. - if (getNonLocalPointerDepFromBB(PredPointer, PointeeSize, isLoad, Pred, + if (getNonLocalPointerDepFromBB(PredPointer, + Loc.getWithNewPtr(PredPointer.getAddr()), + isLoad, Pred, Result, Visited)) goto PredTranslationFailure; } // Refresh the CacheInfo/Cache pointer so that it isn't invalidated. CacheInfo = &NonLocalPointerDeps[CacheKey]; - Cache = &CacheInfo->second; + Cache = &CacheInfo->NonLocalDeps; NumSortedEntries = Cache->size(); // Since we did phi translation, the "Cache" set won't contain all of the // results for the query. This is ok (we can still use it to accelerate // specific block queries) but we can't do the fastpath "return all // results from the set" Clear out the indicator for this. - CacheInfo->first = BBSkipFirstBlockPair(); + CacheInfo->Pair = BBSkipFirstBlockPair(); SkipFirstBlock = false; continue; @@ -922,7 +1007,7 @@ getNonLocalPointerDepFromBB(const PHITransAddr &Pointer, uint64_t PointeeSize, if (Cache == 0) { // Refresh the CacheInfo/Cache pointer if it got invalidated. CacheInfo = &NonLocalPointerDeps[CacheKey]; - Cache = &CacheInfo->second; + Cache = &CacheInfo->NonLocalDeps; NumSortedEntries = Cache->size(); } @@ -930,7 +1015,7 @@ getNonLocalPointerDepFromBB(const PHITransAddr &Pointer, uint64_t PointeeSize, // results for the query. This is ok (we can still use it to accelerate // specific block queries) but we can't do the fastpath "return all // results from the set". Clear out the indicator for this. - CacheInfo->first = BBSkipFirstBlockPair(); + CacheInfo->Pair = BBSkipFirstBlockPair(); // If *nothing* works, mark the pointer as being clobbered by the first // instruction in this block. @@ -972,7 +1057,7 @@ RemoveCachedNonLocalPointerDependencies(ValueIsLoadPair P) { // Remove all of the entries in the BB->val map. This involves removing // instructions from the reverse map. - NonLocalDepInfo &PInfo = It->second.second; + NonLocalDepInfo &PInfo = It->second.NonLocalDeps; for (unsigned i = 0, e = PInfo.size(); i != e; ++i) { Instruction *Target = PInfo[i].getResult().getInst(); @@ -1143,10 +1228,10 @@ void MemoryDependenceAnalysis::removeInstruction(Instruction *RemInst) { assert(P.getPointer() != RemInst && "Already removed NonLocalPointerDeps info for RemInst"); - NonLocalDepInfo &NLPDI = NonLocalPointerDeps[P].second; + NonLocalDepInfo &NLPDI = NonLocalPointerDeps[P].NonLocalDeps; // The cache is not valid for any specific block anymore. - NonLocalPointerDeps[P].first = BBSkipFirstBlockPair(); + NonLocalPointerDeps[P].Pair = BBSkipFirstBlockPair(); // Update any entries for RemInst to use the instruction after it. for (NonLocalDepInfo::iterator DI = NLPDI.begin(), DE = NLPDI.end(); @@ -1192,7 +1277,7 @@ void MemoryDependenceAnalysis::verifyRemoved(Instruction *D) const { for (CachedNonLocalPointerInfo::const_iterator I =NonLocalPointerDeps.begin(), E = NonLocalPointerDeps.end(); I != E; ++I) { assert(I->first.getPointer() != D && "Inst occurs in NLPD map key"); - const NonLocalDepInfo &Val = I->second.second; + const NonLocalDepInfo &Val = I->second.NonLocalDeps; for (NonLocalDepInfo::const_iterator II = Val.begin(), E = Val.end(); II != E; ++II) assert(II->getResult().getInst() != D && "Inst occurs as NLPD value"); diff --git a/lib/Analysis/ModuleDebugInfoPrinter.cpp b/lib/Analysis/ModuleDebugInfoPrinter.cpp index 2cc1c2aa005c..e7e999cebeb9 100644 --- a/lib/Analysis/ModuleDebugInfoPrinter.cpp +++ b/lib/Analysis/ModuleDebugInfoPrinter.cpp @@ -30,7 +30,9 @@ namespace { DebugInfoFinder Finder; public: static char ID; // Pass identification, replacement for typeid - ModuleDebugInfoPrinter() : ModulePass(ID) {} + ModuleDebugInfoPrinter() : ModulePass(ID) { + initializeModuleDebugInfoPrinterPass(*PassRegistry::getPassRegistry()); + } virtual bool runOnModule(Module &M); @@ -43,7 +45,7 @@ namespace { char ModuleDebugInfoPrinter::ID = 0; INITIALIZE_PASS(ModuleDebugInfoPrinter, "module-debuginfo", - "Decodes module-level debug info", false, true); + "Decodes module-level debug info", false, true) ModulePass *llvm::createModuleDebugInfoPrinterPass() { return new ModuleDebugInfoPrinter(); diff --git a/lib/Analysis/NoAliasAnalysis.cpp b/lib/Analysis/NoAliasAnalysis.cpp new file mode 100644 index 000000000000..101c2d5b0285 --- /dev/null +++ b/lib/Analysis/NoAliasAnalysis.cpp @@ -0,0 +1,88 @@ +//===- NoAliasAnalysis.cpp - Minimal Alias Analysis Impl ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the default implementation of the Alias Analysis interface +// that simply returns "I don't know" for all queries. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/Passes.h" +#include "llvm/Pass.h" +#include "llvm/Target/TargetData.h" +using namespace llvm; + +namespace { + /// NoAA - This class implements the -no-aa pass, which always returns "I + /// don't know" for alias queries. NoAA is unlike other alias analysis + /// implementations, in that it does not chain to a previous analysis. As + /// such it doesn't follow many of the rules that other alias analyses must. + /// + struct NoAA : public ImmutablePass, public AliasAnalysis { + static char ID; // Class identification, replacement for typeinfo + NoAA() : ImmutablePass(ID) { + initializeNoAAPass(*PassRegistry::getPassRegistry()); + } + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + } + + virtual void initializePass() { + // Note: NoAA does not call InitializeAliasAnalysis because it's + // special and does not support chaining. + TD = getAnalysisIfAvailable(); + } + + virtual AliasResult alias(const Location &LocA, const Location &LocB) { + return MayAlias; + } + + virtual ModRefBehavior getModRefBehavior(ImmutableCallSite CS) { + return UnknownModRefBehavior; + } + virtual ModRefBehavior getModRefBehavior(const Function *F) { + return UnknownModRefBehavior; + } + + virtual bool pointsToConstantMemory(const Location &Loc, + bool OrLocal) { + return false; + } + virtual ModRefResult getModRefInfo(ImmutableCallSite CS, + const Location &Loc) { + return ModRef; + } + virtual ModRefResult getModRefInfo(ImmutableCallSite CS1, + ImmutableCallSite CS2) { + return ModRef; + } + + virtual void deleteValue(Value *V) {} + virtual void copyValue(Value *From, Value *To) {} + virtual void addEscapingUse(Use &U) {} + + /// getAdjustedAnalysisPointer - This method is used when a pass implements + /// an analysis interface through multiple inheritance. If needed, it + /// should override this to adjust the this pointer as needed for the + /// specified pass info. + virtual void *getAdjustedAnalysisPointer(const void *ID) { + if (ID == &AliasAnalysis::ID) + return (AliasAnalysis*)this; + return this; + } + }; +} // End of anonymous namespace + +// Register this pass... +char NoAA::ID = 0; +INITIALIZE_AG_PASS(NoAA, AliasAnalysis, "no-aa", + "No Alias Analysis (always returns 'may' alias)", + true, true, true) + +ImmutablePass *llvm::createNoAAPass() { return new NoAA(); } diff --git a/lib/Analysis/PHITransAddr.cpp b/lib/Analysis/PHITransAddr.cpp index 8e4fa03f2134..93da5a48518d 100644 --- a/lib/Analysis/PHITransAddr.cpp +++ b/lib/Analysis/PHITransAddr.cpp @@ -12,22 +12,27 @@ //===----------------------------------------------------------------------===// #include "llvm/Analysis/PHITransAddr.h" +#include "llvm/Instructions.h" #include "llvm/Analysis/Dominators.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; static bool CanPHITrans(Instruction *Inst) { if (isa(Inst) || - isa(Inst) || isa(Inst)) return true; - + + if (isa(Inst) && + Inst->isSafeToSpeculativelyExecute()) + return true; + if (Inst->getOpcode() == Instruction::Add && isa(Inst->getOperand(1))) return true; - + // cerr << "MEMDEP: Could not PHI translate: " << *Pointer; // if (isa(PtrInst) || isa(PtrInst)) // cerr << "OP:\t\t\t\t" << *PtrInst->getOperand(0); @@ -50,7 +55,7 @@ static bool VerifySubExpr(Value *Expr, // If this is a non-instruction value, there is nothing to do. Instruction *I = dyn_cast(Expr); if (I == 0) return true; - + // If it's an instruction, it is either in Tmp or its operands recursively // are. SmallVectorImpl::iterator Entry = @@ -59,16 +64,17 @@ static bool VerifySubExpr(Value *Expr, InstInputs.erase(Entry); return true; } - + // If it isn't in the InstInputs list it is a subexpr incorporated into the // address. Sanity check that it is phi translatable. if (!CanPHITrans(I)) { - errs() << "Non phi translatable instruction found in PHITransAddr, either " - "something is missing from InstInputs or CanPHITrans is wrong:\n"; + errs() << "Non phi translatable instruction found in PHITransAddr:\n"; errs() << *I << '\n'; + llvm_unreachable("Either something is missing from InstInputs or " + "CanPHITrans is wrong."); return false; } - + // Validate the operands of the instruction. for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) if (!VerifySubExpr(I->getOperand(i), InstInputs)) @@ -82,19 +88,20 @@ static bool VerifySubExpr(Value *Expr, /// returns false. bool PHITransAddr::Verify() const { if (Addr == 0) return true; - - SmallVector Tmp(InstInputs.begin(), InstInputs.end()); - + + SmallVector Tmp(InstInputs.begin(), InstInputs.end()); + if (!VerifySubExpr(Addr, Tmp)) return false; - + if (!Tmp.empty()) { - errs() << "PHITransAddr inconsistent, contains extra instructions:\n"; + errs() << "PHITransAddr contains extra instructions:\n"; for (unsigned i = 0, e = InstInputs.size(); i != e; ++i) errs() << " InstInput #" << i << " is " << *InstInputs[i] << "\n"; + llvm_unreachable("This is unexpected."); return false; } - + // a-ok. return true; } @@ -111,11 +118,11 @@ bool PHITransAddr::IsPotentiallyPHITranslatable() const { } -static void RemoveInstInputs(Value *V, +static void RemoveInstInputs(Value *V, SmallVectorImpl &InstInputs) { Instruction *I = dyn_cast(V); if (I == 0) return; - + // If the instruction is in the InstInputs list, remove it. SmallVectorImpl::iterator Entry = std::find(InstInputs.begin(), InstInputs.end(), I); @@ -123,9 +130,9 @@ static void RemoveInstInputs(Value *V, InstInputs.erase(Entry); return; } - + assert(!isa(I) && "Error, removing something that isn't an input"); - + // Otherwise, it must have instruction inputs itself. Zap them recursively. for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) { if (Instruction *Op = dyn_cast(I->getOperand(i))) @@ -139,7 +146,7 @@ Value *PHITransAddr::PHITranslateSubExpr(Value *V, BasicBlock *CurBB, // If this is a non-instruction value, it can't require PHI translation. Instruction *Inst = dyn_cast(V); if (Inst == 0) return V; - + // Determine whether 'Inst' is an input to our PHI translatable expression. bool isInput = std::count(InstInputs.begin(), InstInputs.end(), Inst); @@ -156,16 +163,16 @@ Value *PHITransAddr::PHITranslateSubExpr(Value *V, BasicBlock *CurBB, // In either case, the instruction itself isn't an input any longer. InstInputs.erase(std::find(InstInputs.begin(), InstInputs.end(), Inst)); - + // If this is a PHI, go ahead and translate it. if (PHINode *PN = dyn_cast(Inst)) return AddAsInput(PN->getIncomingValueForBlock(PredBB)); - + // If this is a non-phi value, and it is analyzable, we can incorporate it // into the expression by making all instruction operands be inputs. if (!CanPHITrans(Inst)) return 0; - + // All instruction operands are now inputs (and of course, they may also be // defined in this block, so they may need to be phi translated themselves. for (unsigned i = 0, e = Inst->getNumOperands(); i != e; ++i) @@ -176,31 +183,34 @@ Value *PHITransAddr::PHITranslateSubExpr(Value *V, BasicBlock *CurBB, // Ok, it must be an intermediate result (either because it started that way // or because we just incorporated it into the expression). See if its // operands need to be phi translated, and if so, reconstruct it. - - if (BitCastInst *BC = dyn_cast(Inst)) { - Value *PHIIn = PHITranslateSubExpr(BC->getOperand(0), CurBB, PredBB, DT); + + if (CastInst *Cast = dyn_cast(Inst)) { + if (!Cast->isSafeToSpeculativelyExecute()) return 0; + Value *PHIIn = PHITranslateSubExpr(Cast->getOperand(0), CurBB, PredBB, DT); if (PHIIn == 0) return 0; - if (PHIIn == BC->getOperand(0)) - return BC; - + if (PHIIn == Cast->getOperand(0)) + return Cast; + // Find an available version of this cast. - + // Constants are trivial to find. if (Constant *C = dyn_cast(PHIIn)) - return AddAsInput(ConstantExpr::getBitCast(C, BC->getType())); - - // Otherwise we have to see if a bitcasted version of the incoming pointer + return AddAsInput(ConstantExpr::getCast(Cast->getOpcode(), + C, Cast->getType())); + + // Otherwise we have to see if a casted version of the incoming pointer // is available. If so, we can use it, otherwise we have to fail. for (Value::use_iterator UI = PHIIn->use_begin(), E = PHIIn->use_end(); UI != E; ++UI) { - if (BitCastInst *BCI = dyn_cast(*UI)) - if (BCI->getType() == BC->getType() && - (!DT || DT->dominates(BCI->getParent(), PredBB))) - return BCI; + if (CastInst *CastI = dyn_cast(*UI)) + if (CastI->getOpcode() == Cast->getOpcode() && + CastI->getType() == Cast->getType() && + (!DT || DT->dominates(CastI->getParent(), PredBB))) + return CastI; } return 0; } - + // Handle getelementptr with at least one PHI translatable operand. if (GetElementPtrInst *GEP = dyn_cast(Inst)) { SmallVector GEPOps; @@ -208,22 +218,22 @@ Value *PHITransAddr::PHITranslateSubExpr(Value *V, BasicBlock *CurBB, for (unsigned i = 0, e = GEP->getNumOperands(); i != e; ++i) { Value *GEPOp = PHITranslateSubExpr(GEP->getOperand(i), CurBB, PredBB, DT); if (GEPOp == 0) return 0; - + AnyChanged |= GEPOp != GEP->getOperand(i); GEPOps.push_back(GEPOp); } - + if (!AnyChanged) return GEP; - + // Simplify the GEP to handle 'gep x, 0' -> x etc. - if (Value *V = SimplifyGEPInst(&GEPOps[0], GEPOps.size(), TD)) { + if (Value *V = SimplifyGEPInst(&GEPOps[0], GEPOps.size(), TD, DT)) { for (unsigned i = 0, e = GEPOps.size(); i != e; ++i) RemoveInstInputs(GEPOps[i], InstInputs); - + return AddAsInput(V); } - + // Scan to see if we have this GEP available. Value *APHIOp = GEPOps[0]; for (Value::use_iterator UI = APHIOp->use_begin(), E = APHIOp->use_end(); @@ -245,7 +255,7 @@ Value *PHITransAddr::PHITranslateSubExpr(Value *V, BasicBlock *CurBB, } return 0; } - + // Handle add with a constant RHS. if (Inst->getOpcode() == Instruction::Add && isa(Inst->getOperand(1))) { @@ -253,10 +263,10 @@ Value *PHITransAddr::PHITranslateSubExpr(Value *V, BasicBlock *CurBB, Constant *RHS = cast(Inst->getOperand(1)); bool isNSW = cast(Inst)->hasNoSignedWrap(); bool isNUW = cast(Inst)->hasNoUnsignedWrap(); - + Value *LHS = PHITranslateSubExpr(Inst->getOperand(0), CurBB, PredBB, DT); if (LHS == 0) return 0; - + // If the PHI translated LHS is an add of a constant, fold the immediates. if (BinaryOperator *BOp = dyn_cast(LHS)) if (BOp->getOpcode() == Instruction::Add) @@ -264,16 +274,16 @@ Value *PHITransAddr::PHITranslateSubExpr(Value *V, BasicBlock *CurBB, LHS = BOp->getOperand(0); RHS = ConstantExpr::getAdd(RHS, CI); isNSW = isNUW = false; - + // If the old 'LHS' was an input, add the new 'LHS' as an input. if (std::count(InstInputs.begin(), InstInputs.end(), BOp)) { RemoveInstInputs(BOp, InstInputs); AddAsInput(LHS); } } - + // See if the add simplifies away. - if (Value *Res = SimplifyAddInst(LHS, RHS, isNSW, isNUW, TD)) { + if (Value *Res = SimplifyAddInst(LHS, RHS, isNSW, isNUW, TD, DT)) { // If we simplified the operands, the LHS is no longer an input, but Res // is. RemoveInstInputs(LHS, InstInputs); @@ -283,7 +293,7 @@ Value *PHITransAddr::PHITranslateSubExpr(Value *V, BasicBlock *CurBB, // If we didn't modify the add, just return it. if (LHS == Inst->getOperand(0) && RHS == Inst->getOperand(1)) return Inst; - + // Otherwise, see if we have this add available somewhere. for (Value::use_iterator UI = LHS->use_begin(), E = LHS->use_end(); UI != E; ++UI) { @@ -294,10 +304,10 @@ Value *PHITransAddr::PHITranslateSubExpr(Value *V, BasicBlock *CurBB, (!DT || DT->dominates(BO->getParent(), PredBB))) return BO; } - + return 0; } - + // Otherwise, we failed. return 0; } @@ -335,13 +345,13 @@ PHITranslateWithInsertion(BasicBlock *CurBB, BasicBlock *PredBB, const DominatorTree &DT, SmallVectorImpl &NewInsts) { unsigned NISize = NewInsts.size(); - + // Attempt to PHI translate with insertion. Addr = InsertPHITranslatedSubExpr(Addr, CurBB, PredBB, DT, NewInsts); - + // If successful, return the new value. if (Addr) return Addr; - + // If not, destroy any intermediate instructions inserted. while (NewInsts.size() != NISize) NewInsts.pop_back_val()->eraseFromParent(); @@ -367,21 +377,23 @@ InsertPHITranslatedSubExpr(Value *InVal, BasicBlock *CurBB, // If we don't have an available version of this value, it must be an // instruction. Instruction *Inst = cast(InVal); - - // Handle bitcast of PHI translatable value. - if (BitCastInst *BC = dyn_cast(Inst)) { - Value *OpVal = InsertPHITranslatedSubExpr(BC->getOperand(0), + + // Handle cast of PHI translatable value. + if (CastInst *Cast = dyn_cast(Inst)) { + if (!Cast->isSafeToSpeculativelyExecute()) return 0; + Value *OpVal = InsertPHITranslatedSubExpr(Cast->getOperand(0), CurBB, PredBB, DT, NewInsts); if (OpVal == 0) return 0; - - // Otherwise insert a bitcast at the end of PredBB. - BitCastInst *New = new BitCastInst(OpVal, InVal->getType(), - InVal->getName()+".phi.trans.insert", - PredBB->getTerminator()); + + // Otherwise insert a cast at the end of PredBB. + CastInst *New = CastInst::Create(Cast->getOpcode(), + OpVal, InVal->getType(), + InVal->getName()+".phi.trans.insert", + PredBB->getTerminator()); NewInsts.push_back(New); return New; } - + // Handle getelementptr with at least one PHI operand. if (GetElementPtrInst *GEP = dyn_cast(Inst)) { SmallVector GEPOps; @@ -392,8 +404,8 @@ InsertPHITranslatedSubExpr(Value *InVal, BasicBlock *CurBB, if (OpVal == 0) return 0; GEPOps.push_back(OpVal); } - - GetElementPtrInst *Result = + + GetElementPtrInst *Result = GetElementPtrInst::Create(GEPOps[0], GEPOps.begin()+1, GEPOps.end(), InVal->getName()+".phi.trans.insert", PredBB->getTerminator()); @@ -401,12 +413,12 @@ InsertPHITranslatedSubExpr(Value *InVal, BasicBlock *CurBB, NewInsts.push_back(Result); return Result; } - + #if 0 // FIXME: This code works, but it is unclear that we actually want to insert // a big chain of computation in order to make a value available in a block. // This needs to be evaluated carefully to consider its cost trade offs. - + // Handle add with a constant RHS. if (Inst->getOpcode() == Instruction::Add && isa(Inst->getOperand(1))) { @@ -414,7 +426,7 @@ InsertPHITranslatedSubExpr(Value *InVal, BasicBlock *CurBB, Value *OpVal = InsertPHITranslatedSubExpr(Inst->getOperand(0), CurBB, PredBB, DT, NewInsts); if (OpVal == 0) return 0; - + BinaryOperator *Res = BinaryOperator::CreateAdd(OpVal, Inst->getOperand(1), InVal->getName()+".phi.trans.insert", PredBB->getTerminator()); @@ -424,6 +436,6 @@ InsertPHITranslatedSubExpr(Value *InVal, BasicBlock *CurBB, return Res; } #endif - + return 0; } diff --git a/lib/Analysis/PathNumbering.cpp b/lib/Analysis/PathNumbering.cpp new file mode 100644 index 000000000000..5d3f6bbc7b6e --- /dev/null +++ b/lib/Analysis/PathNumbering.cpp @@ -0,0 +1,525 @@ +//===- PathNumbering.cpp --------------------------------------*- C++ -*---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Ball-Larus path numbers uniquely identify paths through a directed acyclic +// graph (DAG) [Ball96]. For a CFG backedges are removed and replaced by phony +// edges to obtain a DAG, and thus the unique path numbers [Ball96]. +// +// The purpose of this analysis is to enumerate the edges in a CFG in order +// to obtain paths from path numbers in a convenient manner. As described in +// [Ball96] edges can be enumerated such that given a path number by following +// the CFG and updating the path number, the path is obtained. +// +// [Ball96] +// T. Ball and J. R. Larus. "Efficient Path Profiling." +// International Symposium on Microarchitecture, pages 46-57, 1996. +// http://portal.acm.org/citation.cfm?id=243857 +// +//===----------------------------------------------------------------------===// +#define DEBUG_TYPE "ball-larus-numbering" + +#include "llvm/Analysis/PathNumbering.h" +#include "llvm/Constants.h" +#include "llvm/DerivedTypes.h" +#include "llvm/InstrTypes.h" +#include "llvm/Instructions.h" +#include "llvm/Module.h" +#include "llvm/Pass.h" +#include "llvm/Support/CFG.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/TypeBuilder.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace llvm; + +// Are we enabling early termination +static cl::opt ProcessEarlyTermination( + "path-profile-early-termination", cl::Hidden, + cl::desc("In path profiling, insert extra instrumentation to account for " + "unexpected function termination.")); + +// Returns the basic block for the BallLarusNode +BasicBlock* BallLarusNode::getBlock() { + return(_basicBlock); +} + +// Returns the number of paths to the exit starting at the node. +unsigned BallLarusNode::getNumberPaths() { + return(_numberPaths); +} + +// Sets the number of paths to the exit starting at the node. +void BallLarusNode::setNumberPaths(unsigned numberPaths) { + _numberPaths = numberPaths; +} + +// Gets the NodeColor used in graph algorithms. +BallLarusNode::NodeColor BallLarusNode::getColor() { + return(_color); +} + +// Sets the NodeColor used in graph algorithms. +void BallLarusNode::setColor(BallLarusNode::NodeColor color) { + _color = color; +} + +// Returns an iterator over predecessor edges. Includes phony and +// backedges. +BLEdgeIterator BallLarusNode::predBegin() { + return(_predEdges.begin()); +} + +// Returns the end sentinel for the predecessor iterator. +BLEdgeIterator BallLarusNode::predEnd() { + return(_predEdges.end()); +} + +// Returns the number of predecessor edges. Includes phony and +// backedges. +unsigned BallLarusNode::getNumberPredEdges() { + return(_predEdges.size()); +} + +// Returns an iterator over successor edges. Includes phony and +// backedges. +BLEdgeIterator BallLarusNode::succBegin() { + return(_succEdges.begin()); +} + +// Returns the end sentinel for the successor iterator. +BLEdgeIterator BallLarusNode::succEnd() { + return(_succEdges.end()); +} + +// Returns the number of successor edges. Includes phony and +// backedges. +unsigned BallLarusNode::getNumberSuccEdges() { + return(_succEdges.size()); +} + +// Add an edge to the predecessor list. +void BallLarusNode::addPredEdge(BallLarusEdge* edge) { + _predEdges.push_back(edge); +} + +// Remove an edge from the predecessor list. +void BallLarusNode::removePredEdge(BallLarusEdge* edge) { + removeEdge(_predEdges, edge); +} + +// Add an edge to the successor list. +void BallLarusNode::addSuccEdge(BallLarusEdge* edge) { + _succEdges.push_back(edge); +} + +// Remove an edge from the successor list. +void BallLarusNode::removeSuccEdge(BallLarusEdge* edge) { + removeEdge(_succEdges, edge); +} + +// Returns the name of the BasicBlock being represented. If BasicBlock +// is null then returns "". If BasicBlock has no name, then +// "" is returned. Intended for use with debug output. +std::string BallLarusNode::getName() { + std::stringstream name; + + if(getBlock() != NULL) { + if(getBlock()->hasName()) { + std::string tempName(getBlock()->getName()); + name << tempName.c_str() << " (" << _uid << ")"; + } else + name << " (" << _uid << ")"; + } else + name << " (" << _uid << ")"; + + return name.str(); +} + +// Removes an edge from an edgeVector. Used by removePredEdge and +// removeSuccEdge. +void BallLarusNode::removeEdge(BLEdgeVector& v, BallLarusEdge* e) { + // TODO: Avoid linear scan by using a set instead + for(BLEdgeIterator i = v.begin(), + end = v.end(); + i != end; + ++i) { + if((*i) == e) { + v.erase(i); + break; + } + } +} + +// Returns the source node of this edge. +BallLarusNode* BallLarusEdge::getSource() const { + return(_source); +} + +// Returns the target node of this edge. +BallLarusNode* BallLarusEdge::getTarget() const { + return(_target); +} + +// Sets the type of the edge. +BallLarusEdge::EdgeType BallLarusEdge::getType() const { + return _edgeType; +} + +// Gets the type of the edge. +void BallLarusEdge::setType(EdgeType type) { + _edgeType = type; +} + +// Returns the weight of this edge. Used to decode path numbers to sequences +// of basic blocks. +unsigned BallLarusEdge::getWeight() { + return(_weight); +} + +// Sets the weight of the edge. Used during path numbering. +void BallLarusEdge::setWeight(unsigned weight) { + _weight = weight; +} + +// Gets the phony edge originating at the root. +BallLarusEdge* BallLarusEdge::getPhonyRoot() { + return _phonyRoot; +} + +// Sets the phony edge originating at the root. +void BallLarusEdge::setPhonyRoot(BallLarusEdge* phonyRoot) { + _phonyRoot = phonyRoot; +} + +// Gets the phony edge terminating at the exit. +BallLarusEdge* BallLarusEdge::getPhonyExit() { + return _phonyExit; +} + +// Sets the phony edge terminating at the exit. +void BallLarusEdge::setPhonyExit(BallLarusEdge* phonyExit) { + _phonyExit = phonyExit; +} + +// Gets the associated real edge if this is a phony edge. +BallLarusEdge* BallLarusEdge::getRealEdge() { + return _realEdge; +} + +// Sets the associated real edge if this is a phony edge. +void BallLarusEdge::setRealEdge(BallLarusEdge* realEdge) { + _realEdge = realEdge; +} + +// Returns the duplicate number of the edge. +unsigned BallLarusEdge::getDuplicateNumber() { + return(_duplicateNumber); +} + +// Initialization that requires virtual functions which are not fully +// functional in the constructor. +void BallLarusDag::init() { + BLBlockNodeMap inDag; + std::stack dfsStack; + + _root = addNode(&(_function.getEntryBlock())); + _exit = addNode(NULL); + + // start search from root + dfsStack.push(getRoot()); + + // dfs to add each bb into the dag + while(dfsStack.size()) + buildNode(inDag, dfsStack); + + // put in the final edge + addEdge(getExit(),getRoot(),0); +} + +// Frees all memory associated with the DAG. +BallLarusDag::~BallLarusDag() { + for(BLEdgeIterator edge = _edges.begin(), end = _edges.end(); edge != end; + ++edge) + delete (*edge); + + for(BLNodeIterator node = _nodes.begin(), end = _nodes.end(); node != end; + ++node) + delete (*node); +} + +// Calculate the path numbers by assigning edge increments as prescribed +// in Ball-Larus path profiling. +void BallLarusDag::calculatePathNumbers() { + BallLarusNode* node; + std::queue bfsQueue; + bfsQueue.push(getExit()); + + while(bfsQueue.size() > 0) { + node = bfsQueue.front(); + + DEBUG(dbgs() << "calculatePathNumbers on " << node->getName() << "\n"); + + bfsQueue.pop(); + unsigned prevPathNumber = node->getNumberPaths(); + calculatePathNumbersFrom(node); + + // Check for DAG splitting + if( node->getNumberPaths() > 100000000 && node != getRoot() ) { + // Add new phony edge from the split-node to the DAG's exit + BallLarusEdge* exitEdge = addEdge(node, getExit(), 0); + exitEdge->setType(BallLarusEdge::SPLITEDGE_PHONY); + + // Counters to handle the possibilty of a multi-graph + BasicBlock* oldTarget = 0; + unsigned duplicateNumber = 0; + + // Iterate through each successor edge, adding phony edges + for( BLEdgeIterator succ = node->succBegin(), end = node->succEnd(); + succ != end; oldTarget = (*succ)->getTarget()->getBlock(), succ++ ) { + + if( (*succ)->getType() == BallLarusEdge::NORMAL ) { + // is this edge a duplicate? + if( oldTarget != (*succ)->getTarget()->getBlock() ) + duplicateNumber = 0; + + // create the new phony edge: root -> succ + BallLarusEdge* rootEdge = + addEdge(getRoot(), (*succ)->getTarget(), duplicateNumber++); + rootEdge->setType(BallLarusEdge::SPLITEDGE_PHONY); + rootEdge->setRealEdge(*succ); + + // split on this edge and reference it's exit/root phony edges + (*succ)->setType(BallLarusEdge::SPLITEDGE); + (*succ)->setPhonyRoot(rootEdge); + (*succ)->setPhonyExit(exitEdge); + (*succ)->setWeight(0); + } + } + + calculatePathNumbersFrom(node); + } + + DEBUG(dbgs() << "prev, new number paths " << prevPathNumber << ", " + << node->getNumberPaths() << ".\n"); + + if(prevPathNumber == 0 && node->getNumberPaths() != 0) { + DEBUG(dbgs() << "node ready : " << node->getName() << "\n"); + for(BLEdgeIterator pred = node->predBegin(), end = node->predEnd(); + pred != end; pred++) { + if( (*pred)->getType() == BallLarusEdge::BACKEDGE || + (*pred)->getType() == BallLarusEdge::SPLITEDGE ) + continue; + + BallLarusNode* nextNode = (*pred)->getSource(); + // not yet visited? + if(nextNode->getNumberPaths() == 0) + bfsQueue.push(nextNode); + } + } + } + + DEBUG(dbgs() << "\tNumber of paths: " << getRoot()->getNumberPaths() << "\n"); +} + +// Returns the number of paths for the Dag. +unsigned BallLarusDag::getNumberOfPaths() { + return(getRoot()->getNumberPaths()); +} + +// Returns the root (i.e. entry) node for the DAG. +BallLarusNode* BallLarusDag::getRoot() { + return _root; +} + +// Returns the exit node for the DAG. +BallLarusNode* BallLarusDag::getExit() { + return _exit; +} + +// Returns the function for the DAG. +Function& BallLarusDag::getFunction() { + return(_function); +} + +// Clears the node colors. +void BallLarusDag::clearColors(BallLarusNode::NodeColor color) { + for (BLNodeIterator nodeIt = _nodes.begin(); nodeIt != _nodes.end(); nodeIt++) + (*nodeIt)->setColor(color); +} + +// Processes one node and its imediate edges for building the DAG. +void BallLarusDag::buildNode(BLBlockNodeMap& inDag, BLNodeStack& dfsStack) { + BallLarusNode* currentNode = dfsStack.top(); + BasicBlock* currentBlock = currentNode->getBlock(); + + if(currentNode->getColor() != BallLarusNode::WHITE) { + // we have already visited this node + dfsStack.pop(); + currentNode->setColor(BallLarusNode::BLACK); + } else { + // are there any external procedure calls? + if( ProcessEarlyTermination ) { + for( BasicBlock::iterator bbCurrent = currentNode->getBlock()->begin(), + bbEnd = currentNode->getBlock()->end(); bbCurrent != bbEnd; + bbCurrent++ ) { + Instruction& instr = *bbCurrent; + if( instr.getOpcode() == Instruction::Call ) { + BallLarusEdge* callEdge = addEdge(currentNode, getExit(), 0); + callEdge->setType(BallLarusEdge::CALLEDGE_PHONY); + break; + } + } + } + + TerminatorInst* terminator = currentNode->getBlock()->getTerminator(); + if(isa(terminator) || isa(terminator) + || isa(terminator)) + addEdge(currentNode, getExit(),0); + + currentNode->setColor(BallLarusNode::GRAY); + inDag[currentBlock] = currentNode; + + BasicBlock* oldSuccessor = 0; + unsigned duplicateNumber = 0; + + // iterate through this node's successors + for(succ_iterator successor = succ_begin(currentBlock), + succEnd = succ_end(currentBlock); successor != succEnd; + oldSuccessor = *successor, ++successor ) { + BasicBlock* succBB = *successor; + + // is this edge a duplicate? + if (oldSuccessor == succBB) + duplicateNumber++; + else + duplicateNumber = 0; + + buildEdge(inDag, dfsStack, currentNode, succBB, duplicateNumber); + } + } +} + +// Process an edge in the CFG for DAG building. +void BallLarusDag::buildEdge(BLBlockNodeMap& inDag, std::stack& + dfsStack, BallLarusNode* currentNode, + BasicBlock* succBB, unsigned duplicateCount) { + BallLarusNode* succNode = inDag[succBB]; + + if(succNode && succNode->getColor() == BallLarusNode::BLACK) { + // visited node and forward edge + addEdge(currentNode, succNode, duplicateCount); + } else if(succNode && succNode->getColor() == BallLarusNode::GRAY) { + // visited node and back edge + DEBUG(dbgs() << "Backedge detected.\n"); + addBackedge(currentNode, succNode, duplicateCount); + } else { + BallLarusNode* childNode; + // not visited node and forward edge + if(succNode) // an unvisited node that is child of a gray node + childNode = succNode; + else { // an unvisited node that is a child of a an unvisted node + childNode = addNode(succBB); + inDag[succBB] = childNode; + } + addEdge(currentNode, childNode, duplicateCount); + dfsStack.push(childNode); + } +} + +// The weight on each edge is the increment required along any path that +// contains that edge. +void BallLarusDag::calculatePathNumbersFrom(BallLarusNode* node) { + if(node == getExit()) + // The Exit node must be base case + node->setNumberPaths(1); + else { + unsigned sumPaths = 0; + BallLarusNode* succNode; + + for(BLEdgeIterator succ = node->succBegin(), end = node->succEnd(); + succ != end; succ++) { + if( (*succ)->getType() == BallLarusEdge::BACKEDGE || + (*succ)->getType() == BallLarusEdge::SPLITEDGE ) + continue; + + (*succ)->setWeight(sumPaths); + succNode = (*succ)->getTarget(); + + if( !succNode->getNumberPaths() ) + return; + sumPaths += succNode->getNumberPaths(); + } + + node->setNumberPaths(sumPaths); + } +} + +// Allows subclasses to determine which type of Node is created. +// Override this method to produce subclasses of BallLarusNode if +// necessary. The destructor of BallLarusDag will call free on each +// pointer created. +BallLarusNode* BallLarusDag::createNode(BasicBlock* BB) { + return( new BallLarusNode(BB) ); +} + +// Allows subclasses to determine which type of Edge is created. +// Override this method to produce subclasses of BallLarusEdge if +// necessary. The destructor of BallLarusDag will call free on each +// pointer created. +BallLarusEdge* BallLarusDag::createEdge(BallLarusNode* source, + BallLarusNode* target, + unsigned duplicateCount) { + return( new BallLarusEdge(source, target, duplicateCount) ); +} + +// Proxy to node's constructor. Updates the DAG state. +BallLarusNode* BallLarusDag::addNode(BasicBlock* BB) { + BallLarusNode* newNode = createNode(BB); + _nodes.push_back(newNode); + return( newNode ); +} + +// Proxy to edge's constructor. Updates the DAG state. +BallLarusEdge* BallLarusDag::addEdge(BallLarusNode* source, + BallLarusNode* target, + unsigned duplicateCount) { + BallLarusEdge* newEdge = createEdge(source, target, duplicateCount); + _edges.push_back(newEdge); + source->addSuccEdge(newEdge); + target->addPredEdge(newEdge); + return(newEdge); +} + +// Adds a backedge with its phony edges. Updates the DAG state. +void BallLarusDag::addBackedge(BallLarusNode* source, BallLarusNode* target, + unsigned duplicateCount) { + BallLarusEdge* childEdge = addEdge(source, target, duplicateCount); + childEdge->setType(BallLarusEdge::BACKEDGE); + + childEdge->setPhonyRoot(addEdge(getRoot(), target,0)); + childEdge->setPhonyExit(addEdge(source, getExit(),0)); + + childEdge->getPhonyRoot()->setRealEdge(childEdge); + childEdge->getPhonyRoot()->setType(BallLarusEdge::BACKEDGE_PHONY); + + childEdge->getPhonyExit()->setRealEdge(childEdge); + childEdge->getPhonyExit()->setType(BallLarusEdge::BACKEDGE_PHONY); + _backEdges.push_back(childEdge); +} diff --git a/lib/Analysis/PathProfileInfo.cpp b/lib/Analysis/PathProfileInfo.cpp new file mode 100644 index 000000000000..b361d3f4fa94 --- /dev/null +++ b/lib/Analysis/PathProfileInfo.cpp @@ -0,0 +1,434 @@ +//===- PathProfileInfo.cpp ------------------------------------*- C++ -*---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface used by optimizers to load path profiles, +// and provides a loader pass which reads a path profile file. +// +//===----------------------------------------------------------------------===// +#define DEBUG_TYPE "path-profile-info" + +#include "llvm/Module.h" +#include "llvm/Pass.h" +#include "llvm/Analysis/Passes.h" +#include "llvm/Analysis/ProfileInfoTypes.h" +#include "llvm/Analysis/PathProfileInfo.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +#include + +using namespace llvm; + +// command line option for loading path profiles +static cl::opt +PathProfileInfoFilename("path-profile-loader-file", cl::init("llvmprof.out"), + cl::value_desc("filename"), + cl::desc("Path profile file loaded by -path-profile-loader"), cl::Hidden); + +namespace { + class PathProfileLoaderPass : public ModulePass, public PathProfileInfo { + public: + PathProfileLoaderPass() : ModulePass(ID) { } + ~PathProfileLoaderPass(); + + // this pass doesn't change anything (only loads information) + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + } + + // the full name of the loader pass + virtual const char* getPassName() const { + return "Path Profiling Information Loader"; + } + + // required since this pass implements multiple inheritance + virtual void *getAdjustedAnalysisPointer(AnalysisID PI) { + if (PI == &PathProfileInfo::ID) + return (PathProfileInfo*)this; + return this; + } + + // entry point to run the pass + bool runOnModule(Module &M); + + // pass identification + static char ID; + + private: + // make a reference table to refer to function by number + void buildFunctionRefs(Module &M); + + // process argument info of a program from the input file + void handleArgumentInfo(); + + // process path number information from the input file + void handlePathInfo(); + + // array of references to the functions in the module + std::vector _functions; + + // path profile file handle + FILE* _file; + + // path profile file name + std::string _filename; + }; +} + +// register PathLoader +char PathProfileLoaderPass::ID = 0; + +INITIALIZE_ANALYSIS_GROUP(PathProfileInfo, "Path Profile Information", + NoPathProfileInfo) +INITIALIZE_AG_PASS(PathProfileLoaderPass, PathProfileInfo, + "path-profile-loader", + "Load path profile information from file", + false, true, false) + +char &llvm::PathProfileLoaderPassID = PathProfileLoaderPass::ID; + +// link PathLoader as a pass, and make it available as an optimisation +ModulePass *llvm::createPathProfileLoaderPass() { + return new PathProfileLoaderPass; +} + +// ---------------------------------------------------------------------------- +// PathEdge implementation +// +ProfilePathEdge::ProfilePathEdge (BasicBlock* source, BasicBlock* target, + unsigned duplicateNumber) + : _source(source), _target(target), _duplicateNumber(duplicateNumber) {} + +// ---------------------------------------------------------------------------- +// Path implementation +// + +ProfilePath::ProfilePath (unsigned int number, unsigned int count, + double countStdDev, PathProfileInfo* ppi) + : _number(number) , _count(count), _countStdDev(countStdDev), _ppi(ppi) {} + +double ProfilePath::getFrequency() const { + return 100 * double(_count) / + double(_ppi->_functionPathCounts[_ppi->_currentFunction]); +} + +static BallLarusEdge* getNextEdge (BallLarusNode* node, + unsigned int pathNumber) { + BallLarusEdge* best = 0; + + for( BLEdgeIterator next = node->succBegin(), + end = node->succEnd(); next != end; next++ ) { + if( (*next)->getType() != BallLarusEdge::BACKEDGE && // no backedges + (*next)->getType() != BallLarusEdge::SPLITEDGE && // no split edges + (*next)->getWeight() <= pathNumber && // weight must be <= pathNumber + (!best || (best->getWeight() < (*next)->getWeight())) ) // best one? + best = *next; + } + + return best; +} + +ProfilePathEdgeVector* ProfilePath::getPathEdges() const { + BallLarusNode* currentNode = _ppi->_currentDag->getRoot (); + unsigned int increment = _number; + ProfilePathEdgeVector* pev = new ProfilePathEdgeVector; + + while (currentNode != _ppi->_currentDag->getExit()) { + BallLarusEdge* next = getNextEdge(currentNode, increment); + + increment -= next->getWeight(); + + if( next->getType() != BallLarusEdge::BACKEDGE_PHONY && + next->getType() != BallLarusEdge::SPLITEDGE_PHONY && + next->getTarget() != _ppi->_currentDag->getExit() ) + pev->push_back(ProfilePathEdge( + next->getSource()->getBlock(), + next->getTarget()->getBlock(), + next->getDuplicateNumber())); + + if( next->getType() == BallLarusEdge::BACKEDGE_PHONY && + next->getTarget() == _ppi->_currentDag->getExit() ) + pev->push_back(ProfilePathEdge( + next->getRealEdge()->getSource()->getBlock(), + next->getRealEdge()->getTarget()->getBlock(), + next->getDuplicateNumber())); + + if( next->getType() == BallLarusEdge::SPLITEDGE_PHONY && + next->getSource() == _ppi->_currentDag->getRoot() ) + pev->push_back(ProfilePathEdge( + next->getRealEdge()->getSource()->getBlock(), + next->getRealEdge()->getTarget()->getBlock(), + next->getDuplicateNumber())); + + // set the new node + currentNode = next->getTarget(); + } + + return pev; +} + +ProfilePathBlockVector* ProfilePath::getPathBlocks() const { + BallLarusNode* currentNode = _ppi->_currentDag->getRoot (); + unsigned int increment = _number; + ProfilePathBlockVector* pbv = new ProfilePathBlockVector; + + while (currentNode != _ppi->_currentDag->getExit()) { + BallLarusEdge* next = getNextEdge(currentNode, increment); + increment -= next->getWeight(); + + // add block to the block list if it is a real edge + if( next->getType() == BallLarusEdge::NORMAL) + pbv->push_back (currentNode->getBlock()); + // make the back edge the last edge since we are at the end + else if( next->getTarget() == _ppi->_currentDag->getExit() ) { + pbv->push_back (currentNode->getBlock()); + pbv->push_back (next->getRealEdge()->getTarget()->getBlock()); + } + + // set the new node + currentNode = next->getTarget(); + } + + return pbv; +} + +BasicBlock* ProfilePath::getFirstBlockInPath() const { + BallLarusNode* root = _ppi->_currentDag->getRoot(); + BallLarusEdge* edge = getNextEdge(root, _number); + + if( edge && (edge->getType() == BallLarusEdge::BACKEDGE_PHONY || + edge->getType() == BallLarusEdge::SPLITEDGE_PHONY) ) + return edge->getTarget()->getBlock(); + + return root->getBlock(); +} + +// ---------------------------------------------------------------------------- +// PathProfileInfo implementation +// + +// Pass identification +char llvm::PathProfileInfo::ID = 0; + +PathProfileInfo::PathProfileInfo () : _currentDag(0) , _currentFunction(0) { +} + +PathProfileInfo::~PathProfileInfo() { + if (_currentDag) + delete _currentDag; +} + +// set the function for which paths are currently begin processed +void PathProfileInfo::setCurrentFunction(Function* F) { + // Make sure it exists + if (!F) return; + + if (_currentDag) + delete _currentDag; + + _currentFunction = F; + _currentDag = new BallLarusDag(*F); + _currentDag->init(); + _currentDag->calculatePathNumbers(); +} + +// get the function for which paths are currently being processed +Function* PathProfileInfo::getCurrentFunction() const { + return _currentFunction; +} + +// get the entry block of the function +BasicBlock* PathProfileInfo::getCurrentFunctionEntry() { + return _currentDag->getRoot()->getBlock(); +} + +// return the path based on its number +ProfilePath* PathProfileInfo::getPath(unsigned int number) { + return _functionPaths[_currentFunction][number]; +} + +// return the number of paths which a function may potentially execute +unsigned int PathProfileInfo::getPotentialPathCount() { + return _currentDag ? _currentDag->getNumberOfPaths() : 0; +} + +// return an iterator for the beginning of a functions executed paths +ProfilePathIterator PathProfileInfo::pathBegin() { + return _functionPaths[_currentFunction].begin(); +} + +// return an iterator for the end of a functions executed paths +ProfilePathIterator PathProfileInfo::pathEnd() { + return _functionPaths[_currentFunction].end(); +} + +// returns the total number of paths run in the function +unsigned int PathProfileInfo::pathsRun() { + return _currentFunction ? _functionPaths[_currentFunction].size() : 0; +} + +// ---------------------------------------------------------------------------- +// PathLoader implementation +// + +// remove all generated paths +PathProfileLoaderPass::~PathProfileLoaderPass() { + for( FunctionPathIterator funcNext = _functionPaths.begin(), + funcEnd = _functionPaths.end(); funcNext != funcEnd; funcNext++) + for( ProfilePathIterator pathNext = funcNext->second.begin(), + pathEnd = funcNext->second.end(); pathNext != pathEnd; pathNext++) + delete pathNext->second; +} + +// entry point of the pass; this loads and parses a file +bool PathProfileLoaderPass::runOnModule(Module &M) { + // get the filename and setup the module's function references + _filename = PathProfileInfoFilename; + buildFunctionRefs (M); + + if (!(_file = fopen(_filename.c_str(), "rb"))) { + errs () << "error: input '" << _filename << "' file does not exist.\n"; + return false; + } + + ProfilingType profType; + + while( fread(&profType, sizeof(ProfilingType), 1, _file) ) { + switch (profType) { + case ArgumentInfo: + handleArgumentInfo (); + break; + case PathInfo: + handlePathInfo (); + break; + default: + errs () << "error: bad path profiling file syntax, " << profType << "\n"; + fclose (_file); + return false; + } + } + + fclose (_file); + + return true; +} + +// create a reference table for functions defined in the path profile file +void PathProfileLoaderPass::buildFunctionRefs (Module &M) { + _functions.push_back(0); // make the 0 index a null pointer + + for (Module::iterator F = M.begin(), E = M.end(); F != E; F++) { + if (F->isDeclaration()) + continue; + _functions.push_back(F); + } +} + +// handle command like argument infor in the output file +void PathProfileLoaderPass::handleArgumentInfo() { + // get the argument list's length + unsigned savedArgsLength; + if( fread(&savedArgsLength, sizeof(unsigned), 1, _file) != 1 ) { + errs() << "warning: argument info header/data mismatch\n"; + return; + } + + // allocate a buffer, and get the arguments + char* args = new char[savedArgsLength+1]; + if( fread(args, 1, savedArgsLength, _file) != savedArgsLength ) + errs() << "warning: argument info header/data mismatch\n"; + + args[savedArgsLength] = '\0'; + argList = std::string(args); + delete [] args; // cleanup dynamic string + + // byte alignment + if (savedArgsLength & 3) + fseek(_file, 4-(savedArgsLength&3), SEEK_CUR); +} + +// Handle path profile information in the output file +void PathProfileLoaderPass::handlePathInfo () { + // get the number of functions in this profile + unsigned functionCount; + if( fread(&functionCount, sizeof(functionCount), 1, _file) != 1 ) { + errs() << "warning: path info header/data mismatch\n"; + return; + } + + // gather path information for each function + for (unsigned i = 0; i < functionCount; i++) { + PathProfileHeader pathHeader; + if( fread(&pathHeader, sizeof(pathHeader), 1, _file) != 1 ) { + errs() << "warning: bad header for path function info\n"; + break; + } + + Function* f = _functions[pathHeader.fnNumber]; + + // dynamically allocate a table to store path numbers + PathProfileTableEntry* pathTable = + new PathProfileTableEntry[pathHeader.numEntries]; + + if( fread(pathTable, sizeof(PathProfileTableEntry), + pathHeader.numEntries, _file) != pathHeader.numEntries) { + delete [] pathTable; + errs() << "warning: path function info header/data mismatch\n"; + return; + } + + // Build a new path for the current function + unsigned int totalPaths = 0; + for (unsigned int j = 0; j < pathHeader.numEntries; j++) { + totalPaths += pathTable[j].pathCounter; + _functionPaths[f][pathTable[j].pathNumber] + = new ProfilePath(pathTable[j].pathNumber, pathTable[j].pathCounter, + 0, this); + } + + _functionPathCounts[f] = totalPaths; + + delete [] pathTable; + } +} + +//===----------------------------------------------------------------------===// +// NoProfile PathProfileInfo implementation +// + +namespace { + struct NoPathProfileInfo : public ImmutablePass, public PathProfileInfo { + static char ID; // Class identification, replacement for typeinfo + NoPathProfileInfo() : ImmutablePass(ID) { + initializeNoPathProfileInfoPass(*PassRegistry::getPassRegistry()); + } + + /// getAdjustedAnalysisPointer - This method is used when a pass implements + /// an analysis interface through multiple inheritance. If needed, it + /// should override this to adjust the this pointer as needed for the + /// specified pass info. + virtual void *getAdjustedAnalysisPointer(AnalysisID PI) { + if (PI == &PathProfileInfo::ID) + return (PathProfileInfo*)this; + return this; + } + + virtual const char *getPassName() const { + return "NoPathProfileInfo"; + } + }; +} // End of anonymous namespace + +char NoPathProfileInfo::ID = 0; +// Register this pass... +INITIALIZE_AG_PASS(NoPathProfileInfo, PathProfileInfo, "no-path-profile", + "No Path Profile Information", false, true, true) + +ImmutablePass *llvm::createNoPathProfileInfoPass() { return new NoPathProfileInfo(); } diff --git a/lib/Analysis/PathProfileVerifier.cpp b/lib/Analysis/PathProfileVerifier.cpp new file mode 100644 index 000000000000..c54977314207 --- /dev/null +++ b/lib/Analysis/PathProfileVerifier.cpp @@ -0,0 +1,207 @@ +//===- PathProfileVerifier.cpp --------------------------------*- C++ -*---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This verifier derives an edge profile file from current path profile +// information +// +//===----------------------------------------------------------------------===// +#define DEBUG_TYPE "path-profile-verifier" + +#include "llvm/Module.h" +#include "llvm/Pass.h" +#include "llvm/Analysis/Passes.h" +#include "llvm/Analysis/ProfileInfoTypes.h" +#include "llvm/Analysis/PathProfileInfo.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" + +#include + +using namespace llvm; + +namespace { + class PathProfileVerifier : public ModulePass { + private: + bool runOnModule(Module &M); + + public: + static char ID; // Pass identification, replacement for typeid + PathProfileVerifier() : ModulePass(ID) { + initializePathProfileVerifierPass(*PassRegistry::getPassRegistry()); + } + + + virtual const char *getPassName() const { + return "Path Profiler Verifier"; + } + + // The verifier requires the path profile and edge profile. + virtual void getAnalysisUsage(AnalysisUsage& AU) const; + }; +} + +static cl::opt +EdgeProfileFilename("path-profile-verifier-file", + cl::init("edgefrompath.llvmprof.out"), + cl::value_desc("filename"), + cl::desc("Edge profile file generated by -path-profile-verifier"), + cl::Hidden); + +char PathProfileVerifier::ID = 0; +INITIALIZE_PASS(PathProfileVerifier, "path-profile-verifier", + "Compare the path profile derived edge profile against the " + "edge profile.", true, true) + +ModulePass *llvm::createPathProfileVerifierPass() { + return new PathProfileVerifier(); +} + +// The verifier requires the path profile and edge profile. +void PathProfileVerifier::getAnalysisUsage(AnalysisUsage& AU) const { + AU.addRequired(); + AU.addPreserved(); +} + +typedef std::map DuplicateToIndexMap; +typedef std::map BlockToDuplicateMap; +typedef std::map NestedBlockToIndexMap; + +// the verifier iterates through each path to gather the total +// number of edge frequencies +bool PathProfileVerifier::runOnModule (Module &M) { + PathProfileInfo& pathProfileInfo = getAnalysis(); + + // setup a data structure to map path edges which index an + // array of edge counters + NestedBlockToIndexMap arrayMap; + unsigned i = 0; + for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) { + if (F->isDeclaration()) continue; + + arrayMap[0][F->begin()][0] = i++; + + for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { + TerminatorInst *TI = BB->getTerminator(); + + unsigned duplicate = 0; + BasicBlock* prev = 0; + for (unsigned s = 0, e = TI->getNumSuccessors(); s != e; + prev = TI->getSuccessor(s), ++s) { + if (prev == TI->getSuccessor(s)) + duplicate++; + else duplicate = 0; + + arrayMap[BB][TI->getSuccessor(s)][duplicate] = i++; + } + } + } + + std::vector edgeArray(i); + + // iterate through each path and increment the edge counters as needed + for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) { + if (F->isDeclaration()) continue; + + pathProfileInfo.setCurrentFunction(F); + + DEBUG(dbgs() << "function '" << F->getName() << "' ran " + << pathProfileInfo.pathsRun() + << "/" << pathProfileInfo.getPotentialPathCount() + << " potential paths\n"); + + for( ProfilePathIterator nextPath = pathProfileInfo.pathBegin(), + endPath = pathProfileInfo.pathEnd(); + nextPath != endPath; nextPath++ ) { + ProfilePath* currentPath = nextPath->second; + + ProfilePathEdgeVector* pev = currentPath->getPathEdges(); + DEBUG(dbgs () << "path #" << currentPath->getNumber() << ": " + << currentPath->getCount() << "\n"); + // setup the entry edge (normally path profiling doens't care about this) + if (currentPath->getFirstBlockInPath() == &F->getEntryBlock()) + edgeArray[arrayMap[0][currentPath->getFirstBlockInPath()][0]] + += currentPath->getCount(); + + for( ProfilePathEdgeIterator nextEdge = pev->begin(), + endEdge = pev->end(); nextEdge != endEdge; nextEdge++ ) { + if (nextEdge != pev->begin()) + DEBUG(dbgs() << " :: "); + + BasicBlock* source = nextEdge->getSource(); + BasicBlock* target = nextEdge->getTarget(); + unsigned duplicateNumber = nextEdge->getDuplicateNumber(); + DEBUG(dbgs () << source->getNameStr() << " --{" << duplicateNumber + << "}--> " << target->getNameStr()); + + // Ensure all the referenced edges exist + // TODO: make this a separate function + if( !arrayMap.count(source) ) { + errs() << " error [" << F->getNameStr() << "()]: source '" + << source->getNameStr() + << "' does not exist in the array map.\n"; + } else if( !arrayMap[source].count(target) ) { + errs() << " error [" << F->getNameStr() << "()]: target '" + << target->getNameStr() + << "' does not exist in the array map.\n"; + } else if( !arrayMap[source][target].count(duplicateNumber) ) { + errs() << " error [" << F->getNameStr() << "()]: edge " + << source->getNameStr() << " -> " << target->getNameStr() + << " duplicate number " << duplicateNumber + << " does not exist in the array map.\n"; + } else { + edgeArray[arrayMap[source][target][duplicateNumber]] + += currentPath->getCount(); + } + } + + DEBUG(errs() << "\n"); + + delete pev; + } + } + + std::string errorInfo; + std::string filename = EdgeProfileFilename; + + // Open a handle to the file + FILE* edgeFile = fopen(filename.c_str(),"wb"); + + if (!edgeFile) { + errs() << "error: unable to open file '" << filename << "' for output.\n"; + return false; + } + + errs() << "Generating edge profile '" << filename << "' ...\n"; + + // write argument info + unsigned type = ArgumentInfo; + unsigned num = pathProfileInfo.argList.size(); + int zeros = 0; + + fwrite(&type,sizeof(unsigned),1,edgeFile); + fwrite(&num,sizeof(unsigned),1,edgeFile); + fwrite(pathProfileInfo.argList.c_str(),1,num,edgeFile); + if (num&3) + fwrite(&zeros, 1, 4-(num&3), edgeFile); + + type = EdgeInfo; + num = edgeArray.size(); + fwrite(&type,sizeof(unsigned),1,edgeFile); + fwrite(&num,sizeof(unsigned),1,edgeFile); + + // write each edge to the file + for( std::vector::iterator s = edgeArray.begin(), + e = edgeArray.end(); s != e; s++) + fwrite(&*s, sizeof (unsigned), 1, edgeFile); + + fclose (edgeFile); + + return true; +} diff --git a/lib/Analysis/PointerTracking.cpp b/lib/Analysis/PointerTracking.cpp deleted file mode 100644 index 07f46824700a..000000000000 --- a/lib/Analysis/PointerTracking.cpp +++ /dev/null @@ -1,316 +0,0 @@ -//===- PointerTracking.cpp - Pointer Bounds Tracking ------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements tracking of pointer bounds. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Analysis/ConstantFolding.h" -#include "llvm/Analysis/Dominators.h" -#include "llvm/Analysis/LoopInfo.h" -#include "llvm/Analysis/MemoryBuiltins.h" -#include "llvm/Analysis/PointerTracking.h" -#include "llvm/Analysis/ScalarEvolution.h" -#include "llvm/Analysis/ScalarEvolutionExpressions.h" -#include "llvm/Constants.h" -#include "llvm/Module.h" -#include "llvm/Value.h" -#include "llvm/Support/CallSite.h" -#include "llvm/Support/InstIterator.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetData.h" -using namespace llvm; - -char PointerTracking::ID = 0; -PointerTracking::PointerTracking() : FunctionPass(ID) {} - -bool PointerTracking::runOnFunction(Function &F) { - predCache.clear(); - assert(analyzing.empty()); - FF = &F; - TD = getAnalysisIfAvailable(); - SE = &getAnalysis(); - LI = &getAnalysis(); - DT = &getAnalysis(); - return false; -} - -void PointerTracking::getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequiredTransitive(); - AU.addRequiredTransitive(); - AU.addRequiredTransitive(); - AU.setPreservesAll(); -} - -bool PointerTracking::doInitialization(Module &M) { - const Type *PTy = Type::getInt8PtrTy(M.getContext()); - - // Find calloc(i64, i64) or calloc(i32, i32). - callocFunc = M.getFunction("calloc"); - if (callocFunc) { - const FunctionType *Ty = callocFunc->getFunctionType(); - - std::vector args, args2; - args.push_back(Type::getInt64Ty(M.getContext())); - args.push_back(Type::getInt64Ty(M.getContext())); - args2.push_back(Type::getInt32Ty(M.getContext())); - args2.push_back(Type::getInt32Ty(M.getContext())); - const FunctionType *Calloc1Type = - FunctionType::get(PTy, args, false); - const FunctionType *Calloc2Type = - FunctionType::get(PTy, args2, false); - if (Ty != Calloc1Type && Ty != Calloc2Type) - callocFunc = 0; // Give up - } - - // Find realloc(i8*, i64) or realloc(i8*, i32). - reallocFunc = M.getFunction("realloc"); - if (reallocFunc) { - const FunctionType *Ty = reallocFunc->getFunctionType(); - std::vector args, args2; - args.push_back(PTy); - args.push_back(Type::getInt64Ty(M.getContext())); - args2.push_back(PTy); - args2.push_back(Type::getInt32Ty(M.getContext())); - - const FunctionType *Realloc1Type = - FunctionType::get(PTy, args, false); - const FunctionType *Realloc2Type = - FunctionType::get(PTy, args2, false); - if (Ty != Realloc1Type && Ty != Realloc2Type) - reallocFunc = 0; // Give up - } - return false; -} - -// Calculates the number of elements allocated for pointer P, -// the type of the element is stored in Ty. -const SCEV *PointerTracking::computeAllocationCount(Value *P, - const Type *&Ty) const { - Value *V = P->stripPointerCasts(); - if (AllocaInst *AI = dyn_cast(V)) { - Value *arraySize = AI->getArraySize(); - Ty = AI->getAllocatedType(); - // arraySize elements of type Ty. - return SE->getSCEV(arraySize); - } - - if (CallInst *CI = extractMallocCall(V)) { - Value *arraySize = getMallocArraySize(CI, TD); - const Type* AllocTy = getMallocAllocatedType(CI); - if (!AllocTy || !arraySize) return SE->getCouldNotCompute(); - Ty = AllocTy; - // arraySize elements of type Ty. - return SE->getSCEV(arraySize); - } - - if (GlobalVariable *GV = dyn_cast(V)) { - if (GV->hasDefinitiveInitializer()) { - Constant *C = GV->getInitializer(); - if (const ArrayType *ATy = dyn_cast(C->getType())) { - Ty = ATy->getElementType(); - return SE->getConstant(Type::getInt32Ty(P->getContext()), - ATy->getNumElements()); - } - } - Ty = GV->getType(); - return SE->getConstant(Type::getInt32Ty(P->getContext()), 1); - //TODO: implement more tracking for globals - } - - if (CallInst *CI = dyn_cast(V)) { - CallSite CS(CI); - Function *F = dyn_cast(CS.getCalledValue()->stripPointerCasts()); - const Loop *L = LI->getLoopFor(CI->getParent()); - if (F == callocFunc) { - Ty = Type::getInt8Ty(P->getContext()); - // calloc allocates arg0*arg1 bytes. - return SE->getSCEVAtScope(SE->getMulExpr(SE->getSCEV(CS.getArgument(0)), - SE->getSCEV(CS.getArgument(1))), - L); - } else if (F == reallocFunc) { - Ty = Type::getInt8Ty(P->getContext()); - // realloc allocates arg1 bytes. - return SE->getSCEVAtScope(CS.getArgument(1), L); - } - } - - return SE->getCouldNotCompute(); -} - -Value *PointerTracking::computeAllocationCountValue(Value *P, const Type *&Ty) const -{ - Value *V = P->stripPointerCasts(); - if (AllocaInst *AI = dyn_cast(V)) { - Ty = AI->getAllocatedType(); - // arraySize elements of type Ty. - return AI->getArraySize(); - } - - if (CallInst *CI = extractMallocCall(V)) { - Ty = getMallocAllocatedType(CI); - if (!Ty) - return 0; - Value *arraySize = getMallocArraySize(CI, TD); - if (!arraySize) { - Ty = Type::getInt8Ty(P->getContext()); - return CI->getArgOperand(0); - } - // arraySize elements of type Ty. - return arraySize; - } - - if (GlobalVariable *GV = dyn_cast(V)) { - if (GV->hasDefinitiveInitializer()) { - Constant *C = GV->getInitializer(); - if (const ArrayType *ATy = dyn_cast(C->getType())) { - Ty = ATy->getElementType(); - return ConstantInt::get(Type::getInt32Ty(P->getContext()), - ATy->getNumElements()); - } - } - Ty = cast(GV->getType())->getElementType(); - return ConstantInt::get(Type::getInt32Ty(P->getContext()), 1); - //TODO: implement more tracking for globals - } - - if (CallInst *CI = dyn_cast(V)) { - CallSite CS(CI); - Function *F = dyn_cast(CS.getCalledValue()->stripPointerCasts()); - if (F == reallocFunc) { - Ty = Type::getInt8Ty(P->getContext()); - // realloc allocates arg1 bytes. - return CS.getArgument(1); - } - } - - return 0; -} - -// Calculates the number of elements of type Ty allocated for P. -const SCEV *PointerTracking::computeAllocationCountForType(Value *P, - const Type *Ty) - const { - const Type *elementTy; - const SCEV *Count = computeAllocationCount(P, elementTy); - if (isa(Count)) - return Count; - if (elementTy == Ty) - return Count; - - if (!TD) // need TargetData from this point forward - return SE->getCouldNotCompute(); - - uint64_t elementSize = TD->getTypeAllocSize(elementTy); - uint64_t wantSize = TD->getTypeAllocSize(Ty); - if (elementSize == wantSize) - return Count; - if (elementSize % wantSize) //fractional counts not possible - return SE->getCouldNotCompute(); - return SE->getMulExpr(Count, SE->getConstant(Count->getType(), - elementSize/wantSize)); -} - -const SCEV *PointerTracking::getAllocationElementCount(Value *V) const { - // We only deal with pointers. - const PointerType *PTy = cast(V->getType()); - return computeAllocationCountForType(V, PTy->getElementType()); -} - -const SCEV *PointerTracking::getAllocationSizeInBytes(Value *V) const { - return computeAllocationCountForType(V, Type::getInt8Ty(V->getContext())); -} - -// Helper for isLoopGuardedBy that checks the swapped and inverted predicate too -enum SolverResult PointerTracking::isLoopGuardedBy(const Loop *L, - Predicate Pred, - const SCEV *A, - const SCEV *B) const { - if (SE->isLoopEntryGuardedByCond(L, Pred, A, B)) - return AlwaysTrue; - Pred = ICmpInst::getSwappedPredicate(Pred); - if (SE->isLoopEntryGuardedByCond(L, Pred, B, A)) - return AlwaysTrue; - - Pred = ICmpInst::getInversePredicate(Pred); - if (SE->isLoopEntryGuardedByCond(L, Pred, B, A)) - return AlwaysFalse; - Pred = ICmpInst::getSwappedPredicate(Pred); - if (SE->isLoopEntryGuardedByCond(L, Pred, A, B)) - return AlwaysTrue; - return Unknown; -} - -enum SolverResult PointerTracking::checkLimits(const SCEV *Offset, - const SCEV *Limit, - BasicBlock *BB) -{ - //FIXME: merge implementation - return Unknown; -} - -void PointerTracking::getPointerOffset(Value *Pointer, Value *&Base, - const SCEV *&Limit, - const SCEV *&Offset) const -{ - Pointer = Pointer->stripPointerCasts(); - Base = Pointer->getUnderlyingObject(); - Limit = getAllocationSizeInBytes(Base); - if (isa(Limit)) { - Base = 0; - Offset = Limit; - return; - } - - Offset = SE->getMinusSCEV(SE->getSCEV(Pointer), SE->getSCEV(Base)); - if (isa(Offset)) { - Base = 0; - Limit = Offset; - } -} - -void PointerTracking::print(raw_ostream &OS, const Module* M) const { - // Calling some PT methods may cause caches to be updated, however - // this should be safe for the same reason its safe for SCEV. - PointerTracking &PT = *const_cast(this); - for (inst_iterator I=inst_begin(*FF), E=inst_end(*FF); I != E; ++I) { - if (!I->getType()->isPointerTy()) - continue; - Value *Base; - const SCEV *Limit, *Offset; - getPointerOffset(&*I, Base, Limit, Offset); - if (!Base) - continue; - - if (Base == &*I) { - const SCEV *S = getAllocationElementCount(Base); - OS << *Base << " ==> " << *S << " elements, "; - OS << *Limit << " bytes allocated\n"; - continue; - } - OS << &*I << " -- base: " << *Base; - OS << " offset: " << *Offset; - - enum SolverResult res = PT.checkLimits(Offset, Limit, I->getParent()); - switch (res) { - case AlwaysTrue: - OS << " always safe\n"; - break; - case AlwaysFalse: - OS << " always unsafe\n"; - break; - case Unknown: - OS << " <>\n"; - break; - } - } -} - -INITIALIZE_PASS(PointerTracking, "pointertracking", - "Track pointer bounds", false, true); diff --git a/lib/Analysis/PostDominators.cpp b/lib/Analysis/PostDominators.cpp index cbe8d1867e4f..3f0deab9ea87 100644 --- a/lib/Analysis/PostDominators.cpp +++ b/lib/Analysis/PostDominators.cpp @@ -19,6 +19,7 @@ #include "llvm/Support/Debug.h" #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/SetOperations.h" +#include "llvm/Assembly/Writer.h" #include "llvm/Analysis/DominatorInternals.h" using namespace llvm; @@ -29,7 +30,7 @@ using namespace llvm; char PostDominatorTree::ID = 0; char PostDominanceFrontier::ID = 0; INITIALIZE_PASS(PostDominatorTree, "postdomtree", - "Post-Dominator Tree Construction", true, true); + "Post-Dominator Tree Construction", true, true) bool PostDominatorTree::runOnFunction(Function &F) { DT->recalculate(F); @@ -53,8 +54,11 @@ FunctionPass* llvm::createPostDomTree() { // PostDominanceFrontier Implementation //===----------------------------------------------------------------------===// -INITIALIZE_PASS(PostDominanceFrontier, "postdomfrontier", - "Post-Dominance Frontier Construction", true, true); +INITIALIZE_PASS_BEGIN(PostDominanceFrontier, "postdomfrontier", + "Post-Dominance Frontier Construction", true, true) +INITIALIZE_PASS_DEPENDENCY(PostDominatorTree) +INITIALIZE_PASS_END(PostDominanceFrontier, "postdomfrontier", + "Post-Dominance Frontier Construction", true, true) const DominanceFrontier::DomSetType & PostDominanceFrontier::calculate(const PostDominatorTree &DT, diff --git a/lib/Analysis/ProfileEstimatorPass.cpp b/lib/Analysis/ProfileEstimatorPass.cpp index ecc0a1845307..667ee1cc348a 100644 --- a/lib/Analysis/ProfileEstimatorPass.cpp +++ b/lib/Analysis/ProfileEstimatorPass.cpp @@ -39,7 +39,8 @@ namespace { public: static char ID; // Class identification, replacement for typeinfo explicit ProfileEstimatorPass(const double execcount = 0) - : FunctionPass(ID), ExecCount(execcount) { + : FunctionPass(ID), ExecCount(execcount) { + initializeProfileEstimatorPassPass(*PassRegistry::getPassRegistry()); if (execcount == 0) ExecCount = LoopWeight; } @@ -72,8 +73,11 @@ namespace { } // End of anonymous namespace char ProfileEstimatorPass::ID = 0; -INITIALIZE_AG_PASS(ProfileEstimatorPass, ProfileInfo, "profile-estimator", - "Estimate profiling information", false, true, false); +INITIALIZE_AG_PASS_BEGIN(ProfileEstimatorPass, ProfileInfo, "profile-estimator", + "Estimate profiling information", false, true, false) +INITIALIZE_PASS_DEPENDENCY(LoopInfo) +INITIALIZE_AG_PASS_END(ProfileEstimatorPass, ProfileInfo, "profile-estimator", + "Estimate profiling information", false, true, false) namespace llvm { char &ProfileEstimatorPassID = ProfileEstimatorPass::ID; @@ -319,6 +323,7 @@ bool ProfileEstimatorPass::runOnFunction(Function &F) { FunctionInformation.erase(&F); BlockInformation[&F].clear(); EdgeInformation[&F].clear(); + BBToVisit.clear(); // Mark all blocks as to visit. for (Function::iterator bi = F.begin(), be = F.end(); bi != be; ++bi) diff --git a/lib/Analysis/ProfileInfo.cpp b/lib/Analysis/ProfileInfo.cpp index fc7f28662c01..36f211e858d2 100644 --- a/lib/Analysis/ProfileInfo.cpp +++ b/lib/Analysis/ProfileInfo.cpp @@ -24,8 +24,12 @@ #include using namespace llvm; +namespace llvm { + template<> char ProfileInfoT::ID = 0; +} + // Register the ProfileInfo interface, providing a nice name to refer to. -static RegisterAnalysisGroup Z("Profile Information"); +INITIALIZE_ANALYSIS_GROUP(ProfileInfo, "Profile Information", NoProfileInfo) namespace llvm { @@ -43,9 +47,6 @@ ProfileInfoT::~ProfileInfoT() { if (MachineProfile) delete MachineProfile; } -template<> -char ProfileInfoT::ID = 0; - template<> char ProfileInfoT::ID = 0; @@ -888,7 +889,7 @@ void ProfileInfoT::repair(const Function *F) { FI = Unvisited.begin(), FE = Unvisited.end(); while(FI != FE && !FoundPath) { const BasicBlock *BB = *FI; ++FI; - const BasicBlock *Dest; + const BasicBlock *Dest = 0; Path P; bool BackEdgeFound = false; for (const_pred_iterator NBB = pred_begin(BB), End = pred_end(BB); @@ -1076,7 +1077,9 @@ raw_ostream& operator<<(raw_ostream &O, std::pair(&*i)) { FType *F = CI->getCalledFunction(); - if (F && (F->getNameStr() == "_setjmp")) { + if (F && (F->getName() == "_setjmp")) { isSetJmpTarget = true; break; } } @@ -366,8 +368,11 @@ namespace llvm { char ProfileVerifierPassT::ID = 0; } -INITIALIZE_PASS(ProfileVerifierPass, "profile-verifier", - "Verify profiling information", false, true); +INITIALIZE_PASS_BEGIN(ProfileVerifierPass, "profile-verifier", + "Verify profiling information", false, true) +INITIALIZE_AG_DEPENDENCY(ProfileInfo) +INITIALIZE_PASS_END(ProfileVerifierPass, "profile-verifier", + "Verify profiling information", false, true) namespace llvm { FunctionPass *createProfileVerifierPass() { diff --git a/lib/Analysis/RegionInfo.cpp b/lib/Analysis/RegionInfo.cpp index abc057a773a9..e2f6a8bf5d9a 100644 --- a/lib/Analysis/RegionInfo.cpp +++ b/lib/Analysis/RegionInfo.cpp @@ -16,8 +16,8 @@ #include "llvm/ADT/Statistic.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Analysis/LoopInfo.h" +#include "llvm/Assembly/Writer.h" #define DEBUG_TYPE "region" #include "llvm/Support/Debug.h" @@ -45,7 +45,7 @@ STATISTIC(numSimpleRegions, "The # of simple regions"); /// PrintStyle - Print region in difference ways. enum PrintStyle { PrintNone, PrintBB, PrintRN }; -cl::opt printStyle("print-region-style", cl::Hidden, +static cl::opt printStyle("print-region-style", cl::Hidden, cl::desc("style of printing regions"), cl::values( clEnumValN(PrintNone, "none", "print no details"), @@ -72,6 +72,15 @@ Region::~Region() { delete *I; } +void Region::replaceEntry(BasicBlock *BB) { + entry.setPointer(BB); +} + +void Region::replaceExit(BasicBlock *BB) { + assert(exit && "No exit to replace!"); + exit = BB; +} + bool Region::contains(const BasicBlock *B) const { BasicBlock *BB = const_cast(B); @@ -125,41 +134,49 @@ Loop *Region::outermostLoopInRegion(LoopInfo *LI, BasicBlock* BB) const { return outermostLoopInRegion(L); } -bool Region::isSimple() const { - bool isSimple = true; - bool found = false; - - BasicBlock *entry = getEntry(), *exit = getExit(); - - // TopLevelRegion - if (!exit) - return false; +BasicBlock *Region::getEnteringBlock() const { + BasicBlock *entry = getEntry(); + BasicBlock *Pred; + BasicBlock *enteringBlock = 0; for (pred_iterator PI = pred_begin(entry), PE = pred_end(entry); PI != PE; ++PI) { - BasicBlock *Pred = *PI; + Pred = *PI; if (DT->getNode(Pred) && !contains(Pred)) { - if (found) { - isSimple = false; - break; - } - found = true; + if (enteringBlock) + return 0; + + enteringBlock = Pred; } } - found = false; + return enteringBlock; +} + +BasicBlock *Region::getExitingBlock() const { + BasicBlock *exit = getExit(); + BasicBlock *Pred; + BasicBlock *exitingBlock = 0; + + if (!exit) + return 0; for (pred_iterator PI = pred_begin(exit), PE = pred_end(exit); PI != PE; - ++PI) - if (contains(*PI)) { - if (found) { - isSimple = false; - break; - } - found = true; + ++PI) { + Pred = *PI; + if (contains(Pred)) { + if (exitingBlock) + return 0; + + exitingBlock = Pred; } + } - return isSimple; + return exitingBlock; +} + +bool Region::isSimple() const { + return !isTopLevelRegion() && getEnteringBlock() && getExitingBlock(); } std::string Region::getNameStr() const { @@ -311,13 +328,38 @@ void Region::transferChildrenTo(Region *To) { children.clear(); } -void Region::addSubRegion(Region *SubRegion) { +void Region::addSubRegion(Region *SubRegion, bool moveChildren) { assert(SubRegion->parent == 0 && "SubRegion already has a parent!"); + assert(std::find(begin(), end(), SubRegion) == children.end() + && "Subregion already exists!"); + SubRegion->parent = this; - // Set up the region node. - assert(std::find(children.begin(), children.end(), SubRegion) == children.end() - && "Node already exist!"); children.push_back(SubRegion); + + if (!moveChildren) + return; + + assert(SubRegion->children.size() == 0 + && "SubRegions that contain children are not supported"); + + for (element_iterator I = element_begin(), E = element_end(); I != E; ++I) + if (!(*I)->isSubRegion()) { + BasicBlock *BB = (*I)->getNodeAs(); + + if (SubRegion->contains(BB)) + RI->setRegionFor(BB, SubRegion); + } + + std::vector Keep; + for (iterator I = begin(), E = end(); I != E; ++I) + if (SubRegion->contains(*I) && *I != SubRegion) { + SubRegion->children.push_back(*I); + (*I)->parent = SubRegion; + } else + Keep.push_back(*I); + + children.clear(); + children.insert(children.begin(), Keep.begin(), Keep.end()); } @@ -339,6 +381,38 @@ unsigned Region::getDepth() const { return Depth; } +Region *Region::getExpandedRegion() const { + unsigned NumSuccessors = exit->getTerminator()->getNumSuccessors(); + + if (NumSuccessors == 0) + return NULL; + + for (pred_iterator PI = pred_begin(getExit()), PE = pred_end(getExit()); + PI != PE; ++PI) + if (!DT->dominates(getEntry(), *PI)) + return NULL; + + Region *R = RI->getRegionFor(exit); + + if (R->getEntry() != exit) { + if (exit->getTerminator()->getNumSuccessors() == 1) + return new Region(getEntry(), *succ_begin(exit), RI, DT); + else + return NULL; + } + + while (R->getParent() && R->getParent()->getEntry() == exit) + R = R->getParent(); + + if (!DT->dominates(getEntry(), R->getExit())) + for (pred_iterator PI = pred_begin(getExit()), PE = pred_end(getExit()); + PI != PE; ++PI) + if (!DT->dominates(R->getExit(), *PI)) + return NULL; + + return new Region(getEntry(), R->getExit(), RI, DT); +} + void Region::print(raw_ostream &OS, bool print_tree, unsigned level) const { if (print_tree) OS.indent(level*2) << "[" << level << "] " << getNameStr(); @@ -376,6 +450,11 @@ void Region::dump() const { } void Region::clearNodeCache() { + // Free the cached nodes. + for (BBNodeMapT::iterator I = BBNodeMap.begin(), + IE = BBNodeMap.end(); I != IE; ++I) + delete I->second; + BBNodeMap.clear(); for (Region::iterator RI = begin(), RE = end(); RI != RE; ++RI) (*RI)->clearNodeCache(); @@ -592,6 +671,7 @@ void RegionInfo::releaseMemory() { } RegionInfo::RegionInfo() : FunctionPass(ID) { + initializeRegionInfoPass(*PassRegistry::getPassRegistry()); TopLevelRegion = 0; } @@ -654,11 +734,14 @@ Region *RegionInfo::getRegionFor(BasicBlock *BB) const { return I != BBtoRegion.end() ? I->second : 0; } +void RegionInfo::setRegionFor(BasicBlock *BB, Region *R) { + BBtoRegion[BB] = R; +} + Region *RegionInfo::operator[](BasicBlock *BB) const { return getRegionFor(BB); } - BasicBlock *RegionInfo::getMaxRegionExit(BasicBlock *BB) const { BasicBlock *Exit = NULL; @@ -733,9 +816,28 @@ RegionInfo::getCommonRegion(SmallVectorImpl &BBs) const { return ret; } +void RegionInfo::splitBlock(BasicBlock* NewBB, BasicBlock *OldBB) +{ + Region *R = getRegionFor(OldBB); + + setRegionFor(NewBB, R); + + while (R->getEntry() == OldBB && !R->isTopLevelRegion()) { + R->replaceEntry(NewBB); + R = R->getParent(); + } + + setRegionFor(OldBB, R); +} + char RegionInfo::ID = 0; -INITIALIZE_PASS(RegionInfo, "regions", - "Detect single entry single exit regions", true, true); +INITIALIZE_PASS_BEGIN(RegionInfo, "regions", + "Detect single entry single exit regions", true, true) +INITIALIZE_PASS_DEPENDENCY(DominatorTree) +INITIALIZE_PASS_DEPENDENCY(PostDominatorTree) +INITIALIZE_PASS_DEPENDENCY(DominanceFrontier) +INITIALIZE_PASS_END(RegionInfo, "regions", + "Detect single entry single exit regions", true, true) // Create methods available outside of this file, to use them // "include/llvm/LinkAllPasses.h". Otherwise the pass would be deleted by diff --git a/lib/Analysis/RegionPass.cpp b/lib/Analysis/RegionPass.cpp new file mode 100644 index 000000000000..3269dcc63d5e --- /dev/null +++ b/lib/Analysis/RegionPass.cpp @@ -0,0 +1,275 @@ +//===- RegionPass.cpp - Region Pass and Region Pass Manager ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements RegionPass and RGPassManager. All region optimization +// and transformation passes are derived from RegionPass. RGPassManager is +// responsible for managing RegionPasses. +// most of these codes are COPY from LoopPass.cpp +// +//===----------------------------------------------------------------------===// +#include "llvm/Analysis/RegionPass.h" +#include "llvm/Analysis/RegionIterator.h" +#include "llvm/Support/Timer.h" + +#define DEBUG_TYPE "regionpassmgr" +#include "llvm/Support/Debug.h" +using namespace llvm; + +//===----------------------------------------------------------------------===// +// RGPassManager +// + +char RGPassManager::ID = 0; + +RGPassManager::RGPassManager(int Depth) + : FunctionPass(ID), PMDataManager(Depth) { + skipThisRegion = false; + redoThisRegion = false; + RI = NULL; + CurrentRegion = NULL; +} + +// Recurse through all subregions and all regions into RQ. +static void addRegionIntoQueue(Region *R, std::deque &RQ) { + RQ.push_back(R); + for (Region::iterator I = R->begin(), E = R->end(); I != E; ++I) + addRegionIntoQueue(*I, RQ); +} + +/// Pass Manager itself does not invalidate any analysis info. +void RGPassManager::getAnalysisUsage(AnalysisUsage &Info) const { + Info.addRequired(); + Info.setPreservesAll(); +} + +/// run - Execute all of the passes scheduled for execution. Keep track of +/// whether any of the passes modifies the function, and if so, return true. +bool RGPassManager::runOnFunction(Function &F) { + RI = &getAnalysis(); + bool Changed = false; + + // Collect inherited analysis from Module level pass manager. + populateInheritedAnalysis(TPM->activeStack); + + addRegionIntoQueue(RI->getTopLevelRegion(), RQ); + + if (RQ.empty()) // No regions, skip calling finalizers + return false; + + // Initialization + for (std::deque::const_iterator I = RQ.begin(), E = RQ.end(); + I != E; ++I) { + Region *R = *I; + for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) { + RegionPass *RP = (RegionPass *)getContainedPass(Index); + Changed |= RP->doInitialization(R, *this); + } + } + + // Walk Regions + while (!RQ.empty()) { + + CurrentRegion = RQ.back(); + skipThisRegion = false; + redoThisRegion = false; + + // Run all passes on the current Region. + for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) { + RegionPass *P = (RegionPass*)getContainedPass(Index); + + dumpPassInfo(P, EXECUTION_MSG, ON_REGION_MSG, + CurrentRegion->getNameStr()); + dumpRequiredSet(P); + + initializeAnalysisImpl(P); + + { + PassManagerPrettyStackEntry X(P, *CurrentRegion->getEntry()); + + TimeRegion PassTimer(getPassTimer(P)); + Changed |= P->runOnRegion(CurrentRegion, *this); + } + + if (Changed) + dumpPassInfo(P, MODIFICATION_MSG, ON_REGION_MSG, + skipThisRegion ? "" : + CurrentRegion->getNameStr()); + dumpPreservedSet(P); + + if (!skipThisRegion) { + // Manually check that this region is still healthy. This is done + // instead of relying on RegionInfo::verifyRegion since RegionInfo + // is a function pass and it's really expensive to verify every + // Region in the function every time. That level of checking can be + // enabled with the -verify-region-info option. + { + TimeRegion PassTimer(getPassTimer(P)); + CurrentRegion->verifyRegion(); + } + + // Then call the regular verifyAnalysis functions. + verifyPreservedAnalysis(P); + } + + removeNotPreservedAnalysis(P); + recordAvailableAnalysis(P); + removeDeadPasses(P, + skipThisRegion ? "" : + CurrentRegion->getNameStr(), + ON_REGION_MSG); + + if (skipThisRegion) + // Do not run other passes on this region. + break; + } + + // If the region was deleted, release all the region passes. This frees up + // some memory, and avoids trouble with the pass manager trying to call + // verifyAnalysis on them. + if (skipThisRegion) + for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) { + Pass *P = getContainedPass(Index); + freePass(P, "", ON_REGION_MSG); + } + + // Pop the region from queue after running all passes. + RQ.pop_back(); + + if (redoThisRegion) + RQ.push_back(CurrentRegion); + + // Free all region nodes created in region passes. + RI->clearNodeCache(); + } + + // Finalization + for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) { + RegionPass *P = (RegionPass*)getContainedPass(Index); + Changed |= P->doFinalization(); + } + + // Print the region tree after all pass. + DEBUG( + dbgs() << "\nRegion tree of function " << F.getName() + << " after all region Pass:\n"; + RI->dump(); + dbgs() << "\n"; + ); + + return Changed; +} + +/// Print passes managed by this manager +void RGPassManager::dumpPassStructure(unsigned Offset) { + errs().indent(Offset*2) << "Region Pass Manager\n"; + for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) { + Pass *P = getContainedPass(Index); + P->dumpPassStructure(Offset + 1); + dumpLastUses(P, Offset+1); + } +} + +namespace { +//===----------------------------------------------------------------------===// +// PrintRegionPass +class PrintRegionPass : public RegionPass { +private: + std::string Banner; + raw_ostream &Out; // raw_ostream to print on. + +public: + static char ID; + PrintRegionPass() : RegionPass(ID), Out(dbgs()) {} + PrintRegionPass(const std::string &B, raw_ostream &o) + : RegionPass(ID), Banner(B), Out(o) {} + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + } + + virtual bool runOnRegion(Region *R, RGPassManager &RGM) { + Out << Banner; + for (Region::block_iterator I = R->block_begin(), E = R->block_end(); + I != E; ++I) + (*I)->getEntry()->print(Out); + + return false; + } +}; + +char PrintRegionPass::ID = 0; +} //end anonymous namespace + +//===----------------------------------------------------------------------===// +// RegionPass + +// Check if this pass is suitable for the current RGPassManager, if +// available. This pass P is not suitable for a RGPassManager if P +// is not preserving higher level analysis info used by other +// RGPassManager passes. In such case, pop RGPassManager from the +// stack. This will force assignPassManager() to create new +// LPPassManger as expected. +void RegionPass::preparePassManager(PMStack &PMS) { + + // Find RGPassManager + while (!PMS.empty() && + PMS.top()->getPassManagerType() > PMT_RegionPassManager) + PMS.pop(); + + + // If this pass is destroying high level information that is used + // by other passes that are managed by LPM then do not insert + // this pass in current LPM. Use new RGPassManager. + if (PMS.top()->getPassManagerType() == PMT_RegionPassManager && + !PMS.top()->preserveHigherLevelAnalysis(this)) + PMS.pop(); +} + +/// Assign pass manager to manage this pass. +void RegionPass::assignPassManager(PMStack &PMS, + PassManagerType PreferredType) { + // Find RGPassManager + while (!PMS.empty() && + PMS.top()->getPassManagerType() > PMT_RegionPassManager) + PMS.pop(); + + RGPassManager *RGPM; + + // Create new Region Pass Manager if it does not exist. + if (PMS.top()->getPassManagerType() == PMT_RegionPassManager) + RGPM = (RGPassManager*)PMS.top(); + else { + + assert (!PMS.empty() && "Unable to create Region Pass Manager"); + PMDataManager *PMD = PMS.top(); + + // [1] Create new Call Graph Pass Manager + RGPM = new RGPassManager(PMD->getDepth() + 1); + RGPM->populateInheritedAnalysis(PMS); + + // [2] Set up new manager's top level manager + PMTopLevelManager *TPM = PMD->getTopLevelManager(); + TPM->addIndirectPassManager(RGPM); + + // [3] Assign manager to manage this new manager. This may create + // and push new managers into PMS + TPM->schedulePass(RGPM); + + // [4] Push new manager into PMS + PMS.push(RGPM); + } + + RGPM->add(this); +} + +/// Get the printer pass +Pass *RegionPass::createPrinterPass(raw_ostream &O, + const std::string &Banner) const { + return new PrintRegionPass(Banner, O); +} diff --git a/lib/Analysis/RegionPrinter.cpp b/lib/Analysis/RegionPrinter.cpp index fee5c1bae976..0cf0f9050504 100644 --- a/lib/Analysis/RegionPrinter.cpp +++ b/lib/Analysis/RegionPrinter.cpp @@ -121,35 +121,41 @@ namespace { struct RegionViewer : public DOTGraphTraitsViewer { static char ID; - RegionViewer() : DOTGraphTraitsViewer("reg", ID){} + RegionViewer() : DOTGraphTraitsViewer("reg", ID){ + initializeRegionViewerPass(*PassRegistry::getPassRegistry()); + } }; - char RegionViewer::ID = 0; -INITIALIZE_PASS(RegionViewer, "view-regions", "View regions of function", - true, true); struct RegionOnlyViewer : public DOTGraphTraitsViewer { static char ID; - RegionOnlyViewer() : DOTGraphTraitsViewer("regonly", ID){} + RegionOnlyViewer() : DOTGraphTraitsViewer("regonly", ID) { + initializeRegionOnlyViewerPass(*PassRegistry::getPassRegistry()); + } }; - char RegionOnlyViewer::ID = 0; -INITIALIZE_PASS(RegionOnlyViewer, "view-regions-only", - "View regions of function (with no function bodies)", - true, true); struct RegionPrinter : public DOTGraphTraitsPrinter { static char ID; RegionPrinter() : - DOTGraphTraitsPrinter("reg", ID) {} + DOTGraphTraitsPrinter("reg", ID) { + initializeRegionPrinterPass(*PassRegistry::getPassRegistry()); + } }; +char RegionPrinter::ID = 0; } //end anonymous namespace -char RegionPrinter::ID = 0; INITIALIZE_PASS(RegionPrinter, "dot-regions", - "Print regions of function to 'dot' file", true, true); + "Print regions of function to 'dot' file", true, true) + +INITIALIZE_PASS(RegionViewer, "view-regions", "View regions of function", + true, true) + +INITIALIZE_PASS(RegionOnlyViewer, "view-regions-only", + "View regions of function (with no function bodies)", + true, true) namespace { @@ -157,7 +163,9 @@ struct RegionOnlyPrinter : public DOTGraphTraitsPrinter { static char ID; RegionOnlyPrinter() : - DOTGraphTraitsPrinter("reg", ID) {} + DOTGraphTraitsPrinter("reg", ID) { + initializeRegionOnlyPrinterPass(*PassRegistry::getPassRegistry()); + } }; } @@ -166,7 +174,7 @@ char RegionOnlyPrinter::ID = 0; INITIALIZE_PASS(RegionOnlyPrinter, "dot-regions-only", "Print regions of function to 'dot' file " "(with no function bodies)", - true, true); + true, true) FunctionPass* llvm::createRegionViewerPass() { return new RegionViewer(); diff --git a/lib/Analysis/ScalarEvolution.cpp b/lib/Analysis/ScalarEvolution.cpp index b892d85f9f4a..62244ccb3a03 100644 --- a/lib/Analysis/ScalarEvolution.cpp +++ b/lib/Analysis/ScalarEvolution.cpp @@ -69,6 +69,7 @@ #include "llvm/Operator.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/Dominators.h" +#include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/Assembly/Writer.h" @@ -103,8 +104,12 @@ MaxBruteForceIterations("scalar-evolution-max-iterations", cl::ReallyHidden, "derived loop"), cl::init(100)); -INITIALIZE_PASS(ScalarEvolution, "scalar-evolution", - "Scalar Evolution Analysis", false, true); +INITIALIZE_PASS_BEGIN(ScalarEvolution, "scalar-evolution", + "Scalar Evolution Analysis", false, true) +INITIALIZE_PASS_DEPENDENCY(LoopInfo) +INITIALIZE_PASS_DEPENDENCY(DominatorTree) +INITIALIZE_PASS_END(ScalarEvolution, "scalar-evolution", + "Scalar Evolution Analysis", false, true) char ScalarEvolution::ID = 0; //===----------------------------------------------------------------------===// @@ -115,13 +120,139 @@ char ScalarEvolution::ID = 0; // Implementation of the SCEV class. // -SCEV::~SCEV() {} - void SCEV::dump() const { print(dbgs()); dbgs() << '\n'; } +void SCEV::print(raw_ostream &OS) const { + switch (getSCEVType()) { + case scConstant: + WriteAsOperand(OS, cast(this)->getValue(), false); + return; + case scTruncate: { + const SCEVTruncateExpr *Trunc = cast(this); + const SCEV *Op = Trunc->getOperand(); + OS << "(trunc " << *Op->getType() << " " << *Op << " to " + << *Trunc->getType() << ")"; + return; + } + case scZeroExtend: { + const SCEVZeroExtendExpr *ZExt = cast(this); + const SCEV *Op = ZExt->getOperand(); + OS << "(zext " << *Op->getType() << " " << *Op << " to " + << *ZExt->getType() << ")"; + return; + } + case scSignExtend: { + const SCEVSignExtendExpr *SExt = cast(this); + const SCEV *Op = SExt->getOperand(); + OS << "(sext " << *Op->getType() << " " << *Op << " to " + << *SExt->getType() << ")"; + return; + } + case scAddRecExpr: { + const SCEVAddRecExpr *AR = cast(this); + OS << "{" << *AR->getOperand(0); + for (unsigned i = 1, e = AR->getNumOperands(); i != e; ++i) + OS << ",+," << *AR->getOperand(i); + OS << "}<"; + if (AR->hasNoUnsignedWrap()) + OS << "nuw><"; + if (AR->hasNoSignedWrap()) + OS << "nsw><"; + WriteAsOperand(OS, AR->getLoop()->getHeader(), /*PrintType=*/false); + OS << ">"; + return; + } + case scAddExpr: + case scMulExpr: + case scUMaxExpr: + case scSMaxExpr: { + const SCEVNAryExpr *NAry = cast(this); + const char *OpStr = 0; + switch (NAry->getSCEVType()) { + case scAddExpr: OpStr = " + "; break; + case scMulExpr: OpStr = " * "; break; + case scUMaxExpr: OpStr = " umax "; break; + case scSMaxExpr: OpStr = " smax "; break; + } + OS << "("; + for (SCEVNAryExpr::op_iterator I = NAry->op_begin(), E = NAry->op_end(); + I != E; ++I) { + OS << **I; + if (llvm::next(I) != E) + OS << OpStr; + } + OS << ")"; + return; + } + case scUDivExpr: { + const SCEVUDivExpr *UDiv = cast(this); + OS << "(" << *UDiv->getLHS() << " /u " << *UDiv->getRHS() << ")"; + return; + } + case scUnknown: { + const SCEVUnknown *U = cast(this); + const Type *AllocTy; + if (U->isSizeOf(AllocTy)) { + OS << "sizeof(" << *AllocTy << ")"; + return; + } + if (U->isAlignOf(AllocTy)) { + OS << "alignof(" << *AllocTy << ")"; + return; + } + + const Type *CTy; + Constant *FieldNo; + if (U->isOffsetOf(CTy, FieldNo)) { + OS << "offsetof(" << *CTy << ", "; + WriteAsOperand(OS, FieldNo, false); + OS << ")"; + return; + } + + // Otherwise just print it normally. + WriteAsOperand(OS, U->getValue(), false); + return; + } + case scCouldNotCompute: + OS << "***COULDNOTCOMPUTE***"; + return; + default: break; + } + llvm_unreachable("Unknown SCEV kind!"); +} + +const Type *SCEV::getType() const { + switch (getSCEVType()) { + case scConstant: + return cast(this)->getType(); + case scTruncate: + case scZeroExtend: + case scSignExtend: + return cast(this)->getType(); + case scAddRecExpr: + case scMulExpr: + case scUMaxExpr: + case scSMaxExpr: + return cast(this)->getType(); + case scAddExpr: + return cast(this)->getType(); + case scUDivExpr: + return cast(this)->getType(); + case scUnknown: + return cast(this)->getType(); + case scCouldNotCompute: + llvm_unreachable("Attempt to use a SCEVCouldNotCompute object!"); + return 0; + default: break; + } + llvm_unreachable("Unknown SCEV kind!"); + return 0; +} + bool SCEV::isZero() const { if (const SCEVConstant *SC = dyn_cast(this)) return SC->getValue()->isZero(); @@ -143,30 +274,6 @@ bool SCEV::isAllOnesValue() const { SCEVCouldNotCompute::SCEVCouldNotCompute() : SCEV(FoldingSetNodeIDRef(), scCouldNotCompute) {} -bool SCEVCouldNotCompute::isLoopInvariant(const Loop *L) const { - llvm_unreachable("Attempt to use a SCEVCouldNotCompute object!"); - return false; -} - -const Type *SCEVCouldNotCompute::getType() const { - llvm_unreachable("Attempt to use a SCEVCouldNotCompute object!"); - return 0; -} - -bool SCEVCouldNotCompute::hasComputableLoopEvolution(const Loop *L) const { - llvm_unreachable("Attempt to use a SCEVCouldNotCompute object!"); - return false; -} - -bool SCEVCouldNotCompute::hasOperand(const SCEV *) const { - llvm_unreachable("Attempt to use a SCEVCouldNotCompute object!"); - return false; -} - -void SCEVCouldNotCompute::print(raw_ostream &OS) const { - OS << "***COULDNOTCOMPUTE***"; -} - bool SCEVCouldNotCompute::classof(const SCEV *S) { return S->getSCEVType() == scCouldNotCompute; } @@ -192,24 +299,10 @@ ScalarEvolution::getConstant(const Type *Ty, uint64_t V, bool isSigned) { return getConstant(ConstantInt::get(ITy, V, isSigned)); } -const Type *SCEVConstant::getType() const { return V->getType(); } - -void SCEVConstant::print(raw_ostream &OS) const { - WriteAsOperand(OS, V, false); -} - SCEVCastExpr::SCEVCastExpr(const FoldingSetNodeIDRef ID, unsigned SCEVTy, const SCEV *op, const Type *ty) : SCEV(ID, SCEVTy), Op(op), Ty(ty) {} -bool SCEVCastExpr::dominates(BasicBlock *BB, DominatorTree *DT) const { - return Op->dominates(BB, DT); -} - -bool SCEVCastExpr::properlyDominates(BasicBlock *BB, DominatorTree *DT) const { - return Op->properlyDominates(BB, DT); -} - SCEVTruncateExpr::SCEVTruncateExpr(const FoldingSetNodeIDRef ID, const SCEV *op, const Type *ty) : SCEVCastExpr(ID, scTruncate, op, ty) { @@ -218,10 +311,6 @@ SCEVTruncateExpr::SCEVTruncateExpr(const FoldingSetNodeIDRef ID, "Cannot truncate non-integer value!"); } -void SCEVTruncateExpr::print(raw_ostream &OS) const { - OS << "(trunc " << *Op->getType() << " " << *Op << " to " << *Ty << ")"; -} - SCEVZeroExtendExpr::SCEVZeroExtendExpr(const FoldingSetNodeIDRef ID, const SCEV *op, const Type *ty) : SCEVCastExpr(ID, scZeroExtend, op, ty) { @@ -230,10 +319,6 @@ SCEVZeroExtendExpr::SCEVZeroExtendExpr(const FoldingSetNodeIDRef ID, "Cannot zero extend non-integer value!"); } -void SCEVZeroExtendExpr::print(raw_ostream &OS) const { - OS << "(zext " << *Op->getType() << " " << *Op << " to " << *Ty << ")"; -} - SCEVSignExtendExpr::SCEVSignExtendExpr(const FoldingSetNodeIDRef ID, const SCEV *op, const Type *ty) : SCEVCastExpr(ID, scSignExtend, op, ty) { @@ -242,139 +327,9 @@ SCEVSignExtendExpr::SCEVSignExtendExpr(const FoldingSetNodeIDRef ID, "Cannot sign extend non-integer value!"); } -void SCEVSignExtendExpr::print(raw_ostream &OS) const { - OS << "(sext " << *Op->getType() << " " << *Op << " to " << *Ty << ")"; -} - -void SCEVCommutativeExpr::print(raw_ostream &OS) const { - const char *OpStr = getOperationStr(); - OS << "("; - for (op_iterator I = op_begin(), E = op_end(); I != E; ++I) { - OS << **I; - if (llvm::next(I) != E) - OS << OpStr; - } - OS << ")"; -} - -bool SCEVNAryExpr::dominates(BasicBlock *BB, DominatorTree *DT) const { - for (op_iterator I = op_begin(), E = op_end(); I != E; ++I) - if (!(*I)->dominates(BB, DT)) - return false; - return true; -} - -bool SCEVNAryExpr::properlyDominates(BasicBlock *BB, DominatorTree *DT) const { - for (op_iterator I = op_begin(), E = op_end(); I != E; ++I) - if (!(*I)->properlyDominates(BB, DT)) - return false; - return true; -} - -bool SCEVNAryExpr::isLoopInvariant(const Loop *L) const { - for (op_iterator I = op_begin(), E = op_end(); I != E; ++I) - if (!(*I)->isLoopInvariant(L)) - return false; - return true; -} - -// hasComputableLoopEvolution - N-ary expressions have computable loop -// evolutions iff they have at least one operand that varies with the loop, -// but that all varying operands are computable. -bool SCEVNAryExpr::hasComputableLoopEvolution(const Loop *L) const { - bool HasVarying = false; - for (op_iterator I = op_begin(), E = op_end(); I != E; ++I) { - const SCEV *S = *I; - if (!S->isLoopInvariant(L)) { - if (S->hasComputableLoopEvolution(L)) - HasVarying = true; - else - return false; - } - } - return HasVarying; -} - -bool SCEVNAryExpr::hasOperand(const SCEV *O) const { - for (op_iterator I = op_begin(), E = op_end(); I != E; ++I) { - const SCEV *S = *I; - if (O == S || S->hasOperand(O)) - return true; - } - return false; -} - -bool SCEVUDivExpr::dominates(BasicBlock *BB, DominatorTree *DT) const { - return LHS->dominates(BB, DT) && RHS->dominates(BB, DT); -} - -bool SCEVUDivExpr::properlyDominates(BasicBlock *BB, DominatorTree *DT) const { - return LHS->properlyDominates(BB, DT) && RHS->properlyDominates(BB, DT); -} - -void SCEVUDivExpr::print(raw_ostream &OS) const { - OS << "(" << *LHS << " /u " << *RHS << ")"; -} - -const Type *SCEVUDivExpr::getType() const { - // In most cases the types of LHS and RHS will be the same, but in some - // crazy cases one or the other may be a pointer. ScalarEvolution doesn't - // depend on the type for correctness, but handling types carefully can - // avoid extra casts in the SCEVExpander. The LHS is more likely to be - // a pointer type than the RHS, so use the RHS' type here. - return RHS->getType(); -} - -bool SCEVAddRecExpr::isLoopInvariant(const Loop *QueryLoop) const { - // Add recurrences are never invariant in the function-body (null loop). - if (!QueryLoop) - return false; - - // This recurrence is variant w.r.t. QueryLoop if QueryLoop contains L. - if (QueryLoop->contains(L)) - return false; - - // This recurrence is invariant w.r.t. QueryLoop if L contains QueryLoop. - if (L->contains(QueryLoop)) - return true; - - // This recurrence is variant w.r.t. QueryLoop if any of its operands - // are variant. - for (op_iterator I = op_begin(), E = op_end(); I != E; ++I) - if (!(*I)->isLoopInvariant(QueryLoop)) - return false; - - // Otherwise it's loop-invariant. - return true; -} - -bool -SCEVAddRecExpr::dominates(BasicBlock *BB, DominatorTree *DT) const { - return DT->dominates(L->getHeader(), BB) && - SCEVNAryExpr::dominates(BB, DT); -} - -bool -SCEVAddRecExpr::properlyDominates(BasicBlock *BB, DominatorTree *DT) const { - // This uses a "dominates" query instead of "properly dominates" query because - // the instruction which produces the addrec's value is a PHI, and a PHI - // effectively properly dominates its entire containing block. - return DT->dominates(L->getHeader(), BB) && - SCEVNAryExpr::properlyDominates(BB, DT); -} - -void SCEVAddRecExpr::print(raw_ostream &OS) const { - OS << "{" << *Operands[0]; - for (unsigned i = 1, e = NumOperands; i != e; ++i) - OS << ",+," << *Operands[i]; - OS << "}<"; - WriteAsOperand(OS, L->getHeader(), /*PrintType=*/false); - OS << ">"; -} - void SCEVUnknown::deleted() { - // Clear this SCEVUnknown from ValuesAtScopes. - SE->ValuesAtScopes.erase(this); + // Clear this SCEVUnknown from various maps. + SE->forgetMemoizedResults(this); // Remove this SCEVUnknown from the uniquing map. SE->UniqueSCEVs.RemoveNode(this); @@ -384,8 +339,8 @@ void SCEVUnknown::deleted() { } void SCEVUnknown::allUsesReplacedWith(Value *New) { - // Clear this SCEVUnknown from ValuesAtScopes. - SE->ValuesAtScopes.erase(this); + // Clear this SCEVUnknown from various maps. + SE->forgetMemoizedResults(this); // Remove this SCEVUnknown from the uniquing map. SE->UniqueSCEVs.RemoveNode(this); @@ -396,32 +351,6 @@ void SCEVUnknown::allUsesReplacedWith(Value *New) { setValPtr(New); } -bool SCEVUnknown::isLoopInvariant(const Loop *L) const { - // All non-instruction values are loop invariant. All instructions are loop - // invariant if they are not contained in the specified loop. - // Instructions are never considered invariant in the function body - // (null loop) because they are defined within the "loop". - if (Instruction *I = dyn_cast(getValue())) - return L && !L->contains(I); - return true; -} - -bool SCEVUnknown::dominates(BasicBlock *BB, DominatorTree *DT) const { - if (Instruction *I = dyn_cast(getValue())) - return DT->dominates(I->getParent(), BB); - return true; -} - -bool SCEVUnknown::properlyDominates(BasicBlock *BB, DominatorTree *DT) const { - if (Instruction *I = dyn_cast(getValue())) - return DT->properlyDominates(I->getParent(), BB); - return true; -} - -const Type *SCEVUnknown::getType() const { - return getValue()->getType(); -} - bool SCEVUnknown::isSizeOf(const Type *&AllocTy) const { if (ConstantExpr *VCE = dyn_cast(getValue())) if (VCE->getOpcode() == Instruction::PtrToInt) @@ -486,30 +415,6 @@ bool SCEVUnknown::isOffsetOf(const Type *&CTy, Constant *&FieldNo) const { return false; } -void SCEVUnknown::print(raw_ostream &OS) const { - const Type *AllocTy; - if (isSizeOf(AllocTy)) { - OS << "sizeof(" << *AllocTy << ")"; - return; - } - if (isAlignOf(AllocTy)) { - OS << "alignof(" << *AllocTy << ")"; - return; - } - - const Type *CTy; - Constant *FieldNo; - if (isOffsetOf(CTy, FieldNo)) { - OS << "offsetof(" << *CTy << ", "; - WriteAsOperand(OS, FieldNo, false); - OS << ")"; - return; - } - - // Otherwise just print it normally. - WriteAsOperand(OS, getValue(), false); -} - //===----------------------------------------------------------------------===// // SCEV Utilities //===----------------------------------------------------------------------===// @@ -914,6 +819,36 @@ const SCEV *ScalarEvolution::getTruncateExpr(const SCEV *Op, if (const SCEVZeroExtendExpr *SZ = dyn_cast(Op)) return getTruncateOrZeroExtend(SZ->getOperand(), Ty); + // trunc(x1+x2+...+xN) --> trunc(x1)+trunc(x2)+...+trunc(xN) if we can + // eliminate all the truncates. + if (const SCEVAddExpr *SA = dyn_cast(Op)) { + SmallVector Operands; + bool hasTrunc = false; + for (unsigned i = 0, e = SA->getNumOperands(); i != e && !hasTrunc; ++i) { + const SCEV *S = getTruncateExpr(SA->getOperand(i), Ty); + hasTrunc = isa(S); + Operands.push_back(S); + } + if (!hasTrunc) + return getAddExpr(Operands, false, false); + UniqueSCEVs.FindNodeOrInsertPos(ID, IP); // Mutates IP, returns NULL. + } + + // trunc(x1*x2*...*xN) --> trunc(x1)*trunc(x2)*...*trunc(xN) if we can + // eliminate all the truncates. + if (const SCEVMulExpr *SM = dyn_cast(Op)) { + SmallVector Operands; + bool hasTrunc = false; + for (unsigned i = 0, e = SM->getNumOperands(); i != e && !hasTrunc; ++i) { + const SCEV *S = getTruncateExpr(SM->getOperand(i), Ty); + hasTrunc = isa(S); + Operands.push_back(S); + } + if (!hasTrunc) + return getMulExpr(Operands, false, false); + UniqueSCEVs.FindNodeOrInsertPos(ID, IP); // Mutates IP, returns NULL. + } + // If the input value is a chrec scev, truncate the chrec's operands. if (const SCEVAddRecExpr *AddRec = dyn_cast(Op)) { SmallVector Operands; @@ -965,6 +900,19 @@ const SCEV *ScalarEvolution::getZeroExtendExpr(const SCEV *Op, void *IP = 0; if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) return S; + // zext(trunc(x)) --> zext(x) or x or trunc(x) + if (const SCEVTruncateExpr *ST = dyn_cast(Op)) { + // It's possible the bits taken off by the truncate were all zero bits. If + // so, we should be able to simplify this further. + const SCEV *X = ST->getOperand(); + ConstantRange CR = getUnsignedRange(X); + unsigned TruncBits = getTypeSizeInBits(ST->getType()); + unsigned NewBits = getTypeSizeInBits(Ty); + if (CR.truncate(TruncBits).zeroExtend(NewBits).contains( + CR.zextOrTrunc(NewBits))) + return getTruncateOrZeroExtend(X, Ty); + } + // If the input value is a chrec scev, and we can prove that the value // did not overflow the old, smaller, value, we can zero extend all of the // operands (often constants). This allows analysis of something like @@ -1089,6 +1037,10 @@ const SCEV *ScalarEvolution::getSignExtendExpr(const SCEV *Op, if (const SCEVSignExtendExpr *SS = dyn_cast(Op)) return getSignExtendExpr(SS->getOperand(), Ty); + // sext(zext(x)) --> zext(x) + if (const SCEVZeroExtendExpr *SZ = dyn_cast(Op)) + return getZeroExtendExpr(SZ->getOperand(), Ty); + // Before doing any expensive analysis, check to see if we've already // computed a SCEV for this Op and Ty. FoldingSetNodeID ID; @@ -1098,6 +1050,23 @@ const SCEV *ScalarEvolution::getSignExtendExpr(const SCEV *Op, void *IP = 0; if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) return S; + // If the input value is provably positive, build a zext instead. + if (isKnownNonNegative(Op)) + return getZeroExtendExpr(Op, Ty); + + // sext(trunc(x)) --> sext(x) or x or trunc(x) + if (const SCEVTruncateExpr *ST = dyn_cast(Op)) { + // It's possible the bits taken off by the truncate were all sign bits. If + // so, we should be able to simplify this further. + const SCEV *X = ST->getOperand(); + ConstantRange CR = getSignedRange(X); + unsigned TruncBits = getTypeSizeInBits(ST->getType()); + unsigned NewBits = getTypeSizeInBits(Ty); + if (CR.truncate(TruncBits).signExtend(NewBits).contains( + CR.sextOrTrunc(NewBits))) + return getTruncateOrSignExtend(X, Ty); + } + // If the input value is a chrec scev, and we can prove that the value // did not overflow the old, smaller, value, we can sign extend all of the // operands (often constants). This allows analysis of something like @@ -1639,7 +1608,7 @@ const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl &Ops, const SCEVAddRecExpr *AddRec = cast(Ops[Idx]); const Loop *AddRecLoop = AddRec->getLoop(); for (unsigned i = 0, e = Ops.size(); i != e; ++i) - if (Ops[i]->isLoopInvariant(AddRecLoop)) { + if (isLoopInvariant(Ops[i], AddRecLoop)) { LIOps.push_back(Ops[i]); Ops.erase(Ops.begin()+i); --i; --e; @@ -1711,7 +1680,6 @@ const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl &Ops, // already have one, otherwise create a new one. FoldingSetNodeID ID; ID.AddInteger(scAddExpr); - ID.AddInteger(Ops.size()); for (unsigned i = 0, e = Ops.size(); i != e; ++i) ID.AddPointer(Ops[i]); void *IP = 0; @@ -1846,7 +1814,7 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl &Ops, const SCEVAddRecExpr *AddRec = cast(Ops[Idx]); const Loop *AddRecLoop = AddRec->getLoop(); for (unsigned i = 0, e = Ops.size(); i != e; ++i) - if (Ops[i]->isLoopInvariant(AddRecLoop)) { + if (isLoopInvariant(Ops[i], AddRecLoop)) { LIOps.push_back(Ops[i]); Ops.erase(Ops.begin()+i); --i; --e; @@ -1917,7 +1885,6 @@ const SCEV *ScalarEvolution::getMulExpr(SmallVectorImpl &Ops, // already have one, otherwise create a new one. FoldingSetNodeID ID; ID.AddInteger(scMulExpr); - ID.AddInteger(Ops.size()); for (unsigned i = 0, e = Ops.size(); i != e; ++i) ID.AddPointer(Ops[i]); void *IP = 0; @@ -2066,6 +2033,9 @@ ScalarEvolution::getAddRecExpr(SmallVectorImpl &Operands, for (unsigned i = 1, e = Operands.size(); i != e; ++i) assert(getEffectiveSCEVType(Operands[i]->getType()) == ETy && "SCEVAddRecExpr operand types don't match!"); + for (unsigned i = 0, e = Operands.size(); i != e; ++i) + assert(isLoopInvariant(Operands[i], L) && + "SCEVAddRecExpr operand is not loop-invariant!"); #endif if (Operands.back()->isZero()) { @@ -2106,7 +2076,7 @@ ScalarEvolution::getAddRecExpr(SmallVectorImpl &Operands, // requirement. bool AllInvariant = true; for (unsigned i = 0, e = Operands.size(); i != e; ++i) - if (!Operands[i]->isLoopInvariant(L)) { + if (!isLoopInvariant(Operands[i], L)) { AllInvariant = false; break; } @@ -2114,7 +2084,7 @@ ScalarEvolution::getAddRecExpr(SmallVectorImpl &Operands, NestedOperands[0] = getAddRecExpr(Operands, L); AllInvariant = true; for (unsigned i = 0, e = NestedOperands.size(); i != e; ++i) - if (!NestedOperands[i]->isLoopInvariant(NestedLoop)) { + if (!isLoopInvariant(NestedOperands[i], NestedLoop)) { AllInvariant = false; break; } @@ -2131,7 +2101,6 @@ ScalarEvolution::getAddRecExpr(SmallVectorImpl &Operands, // already have one, otherwise create a new one. FoldingSetNodeID ID; ID.AddInteger(scAddRecExpr); - ID.AddInteger(Operands.size()); for (unsigned i = 0, e = Operands.size(); i != e; ++i) ID.AddPointer(Operands[i]); ID.AddPointer(L); @@ -2242,7 +2211,6 @@ ScalarEvolution::getSMaxExpr(SmallVectorImpl &Ops) { // already have one, otherwise create a new one. FoldingSetNodeID ID; ID.AddInteger(scSMaxExpr); - ID.AddInteger(Ops.size()); for (unsigned i = 0, e = Ops.size(); i != e; ++i) ID.AddPointer(Ops[i]); void *IP = 0; @@ -2347,7 +2315,6 @@ ScalarEvolution::getUMaxExpr(SmallVectorImpl &Ops) { // already have one, otherwise create a new one. FoldingSetNodeID ID; ID.AddInteger(scUMaxExpr); - ID.AddInteger(Ops.size()); for (unsigned i = 0, e = Ops.size(); i != e; ++i) ID.AddPointer(Ops[i]); void *IP = 0; @@ -2543,24 +2510,24 @@ const SCEV *ScalarEvolution::getNotSCEV(const SCEV *V) { return getMinusSCEV(AllOnes, V); } -/// getMinusSCEV - Return a SCEV corresponding to LHS - RHS. -/// -const SCEV *ScalarEvolution::getMinusSCEV(const SCEV *LHS, - const SCEV *RHS) { +/// getMinusSCEV - Return LHS-RHS. Minus is represented in SCEV as A+B*-1, +/// and thus the HasNUW and HasNSW bits apply to the resultant add, not +/// whether the sub would have overflowed. +const SCEV *ScalarEvolution::getMinusSCEV(const SCEV *LHS, const SCEV *RHS, + bool HasNUW, bool HasNSW) { // Fast path: X - X --> 0. if (LHS == RHS) return getConstant(LHS->getType(), 0); // X - Y --> X + -Y - return getAddExpr(LHS, getNegativeSCEV(RHS)); + return getAddExpr(LHS, getNegativeSCEV(RHS), HasNUW, HasNSW); } /// getTruncateOrZeroExtend - Return a SCEV corresponding to a conversion of the /// input value to the specified type. If the type must be extended, it is zero /// extended. const SCEV * -ScalarEvolution::getTruncateOrZeroExtend(const SCEV *V, - const Type *Ty) { +ScalarEvolution::getTruncateOrZeroExtend(const SCEV *V, const Type *Ty) { const Type *SrcTy = V->getType(); assert((SrcTy->isIntegerTy() || SrcTy->isPointerTy()) && (Ty->isIntegerTy() || Ty->isPointerTy()) && @@ -2714,9 +2681,11 @@ ScalarEvolution::ForgetSymbolicName(Instruction *PN, const SCEV *SymName) { ValueExprMapType::iterator It = ValueExprMap.find(static_cast(I)); if (It != ValueExprMap.end()) { + const SCEV *Old = It->second; + // Short-circuit the def-use traversal if the symbolic name // ceases to appear in expressions. - if (It->second != SymName && !It->second->hasOperand(SymName)) + if (Old != SymName && !hasOperand(Old, SymName)) continue; // SCEVUnknown for a PHI either means that it has an unrecognized @@ -2727,9 +2696,9 @@ ScalarEvolution::ForgetSymbolicName(Instruction *PN, const SCEV *SymName) { // updates on its own when it gets to that point. In the third, we do // want to forget the SCEVUnknown. if (!isa(I) || - !isa(It->second) || - (I != PN && It->second == SymName)) { - ValuesAtScopes.erase(It->second); + !isa(Old) || + (I != PN && Old == SymName)) { + forgetMemoizedResults(Old); ValueExprMap.erase(It); } } @@ -2801,7 +2770,7 @@ const SCEV *ScalarEvolution::createNodeForPHI(PHINode *PN) { // This is not a valid addrec if the step amount is varying each // loop iteration, but is not itself an addrec in this loop. - if (Accum->isLoopInvariant(L) || + if (isLoopInvariant(Accum, L) || (isa(Accum) && cast(Accum)->getLoop() == L)) { bool HasNUW = false; @@ -2814,6 +2783,23 @@ const SCEV *ScalarEvolution::createNodeForPHI(PHINode *PN) { HasNUW = true; if (OBO->hasNoSignedWrap()) HasNSW = true; + } else if (const GEPOperator *GEP = + dyn_cast(BEValueV)) { + // If the increment is a GEP, then we know it won't perform a + // signed overflow, because the address space cannot be + // wrapped around. + // + // NOTE: This isn't strictly true, because you could have an + // object straddling the 2G address boundary in a 32-bit address + // space (for example). We really want to model this as a "has + // no signed/unsigned wrap" where the base pointer is treated as + // unsigned and the increment is known to not have signed + // wrapping. + // + // This is a highly theoretical concern though, and this is good + // enough for all cases we know of at this point. :) + // + HasNSW |= GEP->isInBounds(); } const SCEV *StartVal = getSCEV(StartValueV); @@ -2822,7 +2808,7 @@ const SCEV *ScalarEvolution::createNodeForPHI(PHINode *PN) { // Since the no-wrap flags are on the increment, they apply to the // post-incremented value as well. - if (Accum->isLoopInvariant(L)) + if (isLoopInvariant(Accum, L)) (void)getAddRecExpr(getAddExpr(StartVal, Accum), Accum, L, HasNUW, HasNSW); @@ -2867,17 +2853,9 @@ const SCEV *ScalarEvolution::createNodeForPHI(PHINode *PN) { // PHI's incoming blocks are in a different loop, in which case doing so // risks breaking LCSSA form. Instcombine would normally zap these, but // it doesn't have DominatorTree information, so it may miss cases. - if (Value *V = PN->hasConstantValue(DT)) { - bool AllSameLoop = true; - Loop *PNLoop = LI->getLoopFor(PN->getParent()); - for (size_t i = 0, e = PN->getNumIncomingValues(); i != e; ++i) - if (LI->getLoopFor(PN->getIncomingBlock(i)) != PNLoop) { - AllSameLoop = false; - break; - } - if (AllSameLoop) + if (Value *V = SimplifyInstruction(PN, TD, DT)) + if (LI->replacementPreservesLCSSAForm(PN, V)) return getSCEV(V); - } // If it's not a loop phi, we can't handle it yet. return getUnknown(PN); @@ -2892,6 +2870,7 @@ const SCEV *ScalarEvolution::createNodeForGEP(GEPOperator *GEP) { // Add expression, because the Instruction may be guarded by control flow // and the no-overflow bits may not be valid for the expression in any // context. + bool isInBounds = GEP->isInBounds(); const Type *IntPtrTy = getEffectiveSCEVType(GEP->getType()); Value *Base = GEP->getOperand(0); @@ -2920,7 +2899,8 @@ const SCEV *ScalarEvolution::createNodeForGEP(GEPOperator *GEP) { IndexS = getTruncateOrSignExtend(IndexS, IntPtrTy); // Multiply the index by the element size to compute the element offset. - const SCEV *LocalOffset = getMulExpr(IndexS, ElementSize); + const SCEV *LocalOffset = getMulExpr(IndexS, ElementSize, /*NUW*/ false, + /*NSW*/ isInBounds); // Add the element offset to the running total offset. TotalOffset = getAddExpr(TotalOffset, LocalOffset); @@ -2931,7 +2911,8 @@ const SCEV *ScalarEvolution::createNodeForGEP(GEPOperator *GEP) { const SCEV *BaseS = getSCEV(Base); // Add the total offset from all the GEP indices to the base. - return getAddExpr(BaseS, TotalOffset); + return getAddExpr(BaseS, TotalOffset, /*NUW*/ false, + /*NSW*/ isInBounds); } /// GetMinTrailingZeros - Determine the minimum number of zero bits that S is @@ -3019,9 +3000,13 @@ ScalarEvolution::GetMinTrailingZeros(const SCEV *S) { /// ConstantRange ScalarEvolution::getUnsignedRange(const SCEV *S) { + // See if we've computed this range already. + DenseMap::iterator I = UnsignedRanges.find(S); + if (I != UnsignedRanges.end()) + return I->second; if (const SCEVConstant *C = dyn_cast(S)) - return ConstantRange(C->getValue()->getValue()); + return setUnsignedRange(C, ConstantRange(C->getValue()->getValue())); unsigned BitWidth = getTypeSizeInBits(S->getType()); ConstantRange ConservativeResult(BitWidth, /*isFullSet=*/true); @@ -3038,49 +3023,52 @@ ScalarEvolution::getUnsignedRange(const SCEV *S) { ConstantRange X = getUnsignedRange(Add->getOperand(0)); for (unsigned i = 1, e = Add->getNumOperands(); i != e; ++i) X = X.add(getUnsignedRange(Add->getOperand(i))); - return ConservativeResult.intersectWith(X); + return setUnsignedRange(Add, ConservativeResult.intersectWith(X)); } if (const SCEVMulExpr *Mul = dyn_cast(S)) { ConstantRange X = getUnsignedRange(Mul->getOperand(0)); for (unsigned i = 1, e = Mul->getNumOperands(); i != e; ++i) X = X.multiply(getUnsignedRange(Mul->getOperand(i))); - return ConservativeResult.intersectWith(X); + return setUnsignedRange(Mul, ConservativeResult.intersectWith(X)); } if (const SCEVSMaxExpr *SMax = dyn_cast(S)) { ConstantRange X = getUnsignedRange(SMax->getOperand(0)); for (unsigned i = 1, e = SMax->getNumOperands(); i != e; ++i) X = X.smax(getUnsignedRange(SMax->getOperand(i))); - return ConservativeResult.intersectWith(X); + return setUnsignedRange(SMax, ConservativeResult.intersectWith(X)); } if (const SCEVUMaxExpr *UMax = dyn_cast(S)) { ConstantRange X = getUnsignedRange(UMax->getOperand(0)); for (unsigned i = 1, e = UMax->getNumOperands(); i != e; ++i) X = X.umax(getUnsignedRange(UMax->getOperand(i))); - return ConservativeResult.intersectWith(X); + return setUnsignedRange(UMax, ConservativeResult.intersectWith(X)); } if (const SCEVUDivExpr *UDiv = dyn_cast(S)) { ConstantRange X = getUnsignedRange(UDiv->getLHS()); ConstantRange Y = getUnsignedRange(UDiv->getRHS()); - return ConservativeResult.intersectWith(X.udiv(Y)); + return setUnsignedRange(UDiv, ConservativeResult.intersectWith(X.udiv(Y))); } if (const SCEVZeroExtendExpr *ZExt = dyn_cast(S)) { ConstantRange X = getUnsignedRange(ZExt->getOperand()); - return ConservativeResult.intersectWith(X.zeroExtend(BitWidth)); + return setUnsignedRange(ZExt, + ConservativeResult.intersectWith(X.zeroExtend(BitWidth))); } if (const SCEVSignExtendExpr *SExt = dyn_cast(S)) { ConstantRange X = getUnsignedRange(SExt->getOperand()); - return ConservativeResult.intersectWith(X.signExtend(BitWidth)); + return setUnsignedRange(SExt, + ConservativeResult.intersectWith(X.signExtend(BitWidth))); } if (const SCEVTruncateExpr *Trunc = dyn_cast(S)) { ConstantRange X = getUnsignedRange(Trunc->getOperand()); - return ConservativeResult.intersectWith(X.truncate(BitWidth)); + return setUnsignedRange(Trunc, + ConservativeResult.intersectWith(X.truncate(BitWidth))); } if (const SCEVAddRecExpr *AddRec = dyn_cast(S)) { @@ -3120,19 +3108,20 @@ ScalarEvolution::getUnsignedRange(const SCEV *S) { ConstantRange ExtEndRange = EndRange.zextOrTrunc(BitWidth*2+1); if (ExtStartRange.add(ExtMaxBECountRange.multiply(ExtStepRange)) != ExtEndRange) - return ConservativeResult; + return setUnsignedRange(AddRec, ConservativeResult); APInt Min = APIntOps::umin(StartRange.getUnsignedMin(), EndRange.getUnsignedMin()); APInt Max = APIntOps::umax(StartRange.getUnsignedMax(), EndRange.getUnsignedMax()); if (Min.isMinValue() && Max.isMaxValue()) - return ConservativeResult; - return ConservativeResult.intersectWith(ConstantRange(Min, Max+1)); + return setUnsignedRange(AddRec, ConservativeResult); + return setUnsignedRange(AddRec, + ConservativeResult.intersectWith(ConstantRange(Min, Max+1))); } } - return ConservativeResult; + return setUnsignedRange(AddRec, ConservativeResult); } if (const SCEVUnknown *U = dyn_cast(S)) { @@ -3141,20 +3130,25 @@ ScalarEvolution::getUnsignedRange(const SCEV *S) { APInt Zeros(BitWidth, 0), Ones(BitWidth, 0); ComputeMaskedBits(U->getValue(), Mask, Zeros, Ones, TD); if (Ones == ~Zeros + 1) - return ConservativeResult; - return ConservativeResult.intersectWith(ConstantRange(Ones, ~Zeros + 1)); + return setUnsignedRange(U, ConservativeResult); + return setUnsignedRange(U, + ConservativeResult.intersectWith(ConstantRange(Ones, ~Zeros + 1))); } - return ConservativeResult; + return setUnsignedRange(S, ConservativeResult); } /// getSignedRange - Determine the signed range for a particular SCEV. /// ConstantRange ScalarEvolution::getSignedRange(const SCEV *S) { + // See if we've computed this range already. + DenseMap::iterator I = SignedRanges.find(S); + if (I != SignedRanges.end()) + return I->second; if (const SCEVConstant *C = dyn_cast(S)) - return ConstantRange(C->getValue()->getValue()); + return setSignedRange(C, ConstantRange(C->getValue()->getValue())); unsigned BitWidth = getTypeSizeInBits(S->getType()); ConstantRange ConservativeResult(BitWidth, /*isFullSet=*/true); @@ -3171,49 +3165,52 @@ ScalarEvolution::getSignedRange(const SCEV *S) { ConstantRange X = getSignedRange(Add->getOperand(0)); for (unsigned i = 1, e = Add->getNumOperands(); i != e; ++i) X = X.add(getSignedRange(Add->getOperand(i))); - return ConservativeResult.intersectWith(X); + return setSignedRange(Add, ConservativeResult.intersectWith(X)); } if (const SCEVMulExpr *Mul = dyn_cast(S)) { ConstantRange X = getSignedRange(Mul->getOperand(0)); for (unsigned i = 1, e = Mul->getNumOperands(); i != e; ++i) X = X.multiply(getSignedRange(Mul->getOperand(i))); - return ConservativeResult.intersectWith(X); + return setSignedRange(Mul, ConservativeResult.intersectWith(X)); } if (const SCEVSMaxExpr *SMax = dyn_cast(S)) { ConstantRange X = getSignedRange(SMax->getOperand(0)); for (unsigned i = 1, e = SMax->getNumOperands(); i != e; ++i) X = X.smax(getSignedRange(SMax->getOperand(i))); - return ConservativeResult.intersectWith(X); + return setSignedRange(SMax, ConservativeResult.intersectWith(X)); } if (const SCEVUMaxExpr *UMax = dyn_cast(S)) { ConstantRange X = getSignedRange(UMax->getOperand(0)); for (unsigned i = 1, e = UMax->getNumOperands(); i != e; ++i) X = X.umax(getSignedRange(UMax->getOperand(i))); - return ConservativeResult.intersectWith(X); + return setSignedRange(UMax, ConservativeResult.intersectWith(X)); } if (const SCEVUDivExpr *UDiv = dyn_cast(S)) { ConstantRange X = getSignedRange(UDiv->getLHS()); ConstantRange Y = getSignedRange(UDiv->getRHS()); - return ConservativeResult.intersectWith(X.udiv(Y)); + return setSignedRange(UDiv, ConservativeResult.intersectWith(X.udiv(Y))); } if (const SCEVZeroExtendExpr *ZExt = dyn_cast(S)) { ConstantRange X = getSignedRange(ZExt->getOperand()); - return ConservativeResult.intersectWith(X.zeroExtend(BitWidth)); + return setSignedRange(ZExt, + ConservativeResult.intersectWith(X.zeroExtend(BitWidth))); } if (const SCEVSignExtendExpr *SExt = dyn_cast(S)) { ConstantRange X = getSignedRange(SExt->getOperand()); - return ConservativeResult.intersectWith(X.signExtend(BitWidth)); + return setSignedRange(SExt, + ConservativeResult.intersectWith(X.signExtend(BitWidth))); } if (const SCEVTruncateExpr *Trunc = dyn_cast(S)) { ConstantRange X = getSignedRange(Trunc->getOperand()); - return ConservativeResult.intersectWith(X.truncate(BitWidth)); + return setSignedRange(Trunc, + ConservativeResult.intersectWith(X.truncate(BitWidth))); } if (const SCEVAddRecExpr *AddRec = dyn_cast(S)) { @@ -3263,34 +3260,35 @@ ScalarEvolution::getSignedRange(const SCEV *S) { ConstantRange ExtEndRange = EndRange.sextOrTrunc(BitWidth*2+1); if (ExtStartRange.add(ExtMaxBECountRange.multiply(ExtStepRange)) != ExtEndRange) - return ConservativeResult; + return setSignedRange(AddRec, ConservativeResult); APInt Min = APIntOps::smin(StartRange.getSignedMin(), EndRange.getSignedMin()); APInt Max = APIntOps::smax(StartRange.getSignedMax(), EndRange.getSignedMax()); if (Min.isMinSignedValue() && Max.isMaxSignedValue()) - return ConservativeResult; - return ConservativeResult.intersectWith(ConstantRange(Min, Max+1)); + return setSignedRange(AddRec, ConservativeResult); + return setSignedRange(AddRec, + ConservativeResult.intersectWith(ConstantRange(Min, Max+1))); } } - return ConservativeResult; + return setSignedRange(AddRec, ConservativeResult); } if (const SCEVUnknown *U = dyn_cast(S)) { // For a SCEVUnknown, ask ValueTracking. if (!U->getValue()->getType()->isIntegerTy() && !TD) - return ConservativeResult; + return setSignedRange(U, ConservativeResult); unsigned NS = ComputeNumSignBits(U->getValue(), TD); if (NS == 1) - return ConservativeResult; - return ConservativeResult.intersectWith( + return setSignedRange(U, ConservativeResult); + return setSignedRange(U, ConservativeResult.intersectWith( ConstantRange(APInt::getSignedMinValue(BitWidth).ashr(NS - 1), - APInt::getSignedMaxValue(BitWidth).ashr(NS - 1)+1)); + APInt::getSignedMaxValue(BitWidth).ashr(NS - 1)+1))); } - return ConservativeResult; + return setSignedRange(S, ConservativeResult); } /// createSCEV - We know that there is no SCEV for the specified value. @@ -3458,8 +3456,8 @@ const SCEV *ScalarEvolution::createSCEV(Value *V) { // If C is a single bit, it may be in the sign-bit position // before the zero-extend. In this case, represent the xor // using an add, which is equivalent, and re-apply the zext. - APInt Trunc = APInt(CI->getValue()).trunc(Z0TySize); - if (APInt(Trunc).zext(getTypeSizeInBits(UTy)) == CI->getValue() && + APInt Trunc = CI->getValue().trunc(Z0TySize); + if (Trunc.zext(getTypeSizeInBits(UTy)) == CI->getValue() && Trunc.isSignBit()) return getZeroExtendExpr(getAddExpr(Z0, getConstant(Trunc)), UTy); @@ -3699,58 +3697,61 @@ ScalarEvolution::getBackedgeTakenInfo(const Loop *L) { // backedge-taken count, which could result in infinite recursion. std::pair::iterator, bool> Pair = BackedgeTakenCounts.insert(std::make_pair(L, getCouldNotCompute())); - if (Pair.second) { - BackedgeTakenInfo BECount = ComputeBackedgeTakenCount(L); - if (BECount.Exact != getCouldNotCompute()) { - assert(BECount.Exact->isLoopInvariant(L) && - BECount.Max->isLoopInvariant(L) && - "Computed backedge-taken count isn't loop invariant for loop!"); - ++NumTripCountsComputed; + if (!Pair.second) + return Pair.first->second; + BackedgeTakenInfo BECount = ComputeBackedgeTakenCount(L); + if (BECount.Exact != getCouldNotCompute()) { + assert(isLoopInvariant(BECount.Exact, L) && + isLoopInvariant(BECount.Max, L) && + "Computed backedge-taken count isn't loop invariant for loop!"); + ++NumTripCountsComputed; + + // Update the value in the map. + Pair.first->second = BECount; + } else { + if (BECount.Max != getCouldNotCompute()) // Update the value in the map. Pair.first->second = BECount; - } else { - if (BECount.Max != getCouldNotCompute()) - // Update the value in the map. - Pair.first->second = BECount; - if (isa(L->getHeader()->begin())) - // Only count loops that have phi nodes as not being computable. - ++NumTripCountsNotComputed; - } - - // Now that we know more about the trip count for this loop, forget any - // existing SCEV values for PHI nodes in this loop since they are only - // conservative estimates made without the benefit of trip count - // information. This is similar to the code in forgetLoop, except that - // it handles SCEVUnknown PHI nodes specially. - if (BECount.hasAnyInfo()) { - SmallVector Worklist; - PushLoopPHIs(L, Worklist); - - SmallPtrSet Visited; - while (!Worklist.empty()) { - Instruction *I = Worklist.pop_back_val(); - if (!Visited.insert(I)) continue; - - ValueExprMapType::iterator It = - ValueExprMap.find(static_cast(I)); - if (It != ValueExprMap.end()) { - // SCEVUnknown for a PHI either means that it has an unrecognized - // structure, or it's a PHI that's in the progress of being computed - // by createNodeForPHI. In the former case, additional loop trip - // count information isn't going to change anything. In the later - // case, createNodeForPHI will perform the necessary updates on its - // own when it gets to that point. - if (!isa(I) || !isa(It->second)) { - ValuesAtScopes.erase(It->second); - ValueExprMap.erase(It); - } - if (PHINode *PN = dyn_cast(I)) - ConstantEvolutionLoopExitValue.erase(PN); + if (isa(L->getHeader()->begin())) + // Only count loops that have phi nodes as not being computable. + ++NumTripCountsNotComputed; + } + + // Now that we know more about the trip count for this loop, forget any + // existing SCEV values for PHI nodes in this loop since they are only + // conservative estimates made without the benefit of trip count + // information. This is similar to the code in forgetLoop, except that + // it handles SCEVUnknown PHI nodes specially. + if (BECount.hasAnyInfo()) { + SmallVector Worklist; + PushLoopPHIs(L, Worklist); + + SmallPtrSet Visited; + while (!Worklist.empty()) { + Instruction *I = Worklist.pop_back_val(); + if (!Visited.insert(I)) continue; + + ValueExprMapType::iterator It = + ValueExprMap.find(static_cast(I)); + if (It != ValueExprMap.end()) { + const SCEV *Old = It->second; + + // SCEVUnknown for a PHI either means that it has an unrecognized + // structure, or it's a PHI that's in the progress of being computed + // by createNodeForPHI. In the former case, additional loop trip + // count information isn't going to change anything. In the later + // case, createNodeForPHI will perform the necessary updates on its + // own when it gets to that point. + if (!isa(I) || !isa(Old)) { + forgetMemoizedResults(Old); + ValueExprMap.erase(It); } - - PushDefUseChildren(I, Worklist); + if (PHINode *PN = dyn_cast(I)) + ConstantEvolutionLoopExitValue.erase(PN); } + + PushDefUseChildren(I, Worklist); } } return Pair.first->second; @@ -3774,7 +3775,7 @@ void ScalarEvolution::forgetLoop(const Loop *L) { ValueExprMapType::iterator It = ValueExprMap.find(static_cast(I)); if (It != ValueExprMap.end()) { - ValuesAtScopes.erase(It->second); + forgetMemoizedResults(It->second); ValueExprMap.erase(It); if (PHINode *PN = dyn_cast(I)) ConstantEvolutionLoopExitValue.erase(PN); @@ -3782,6 +3783,11 @@ void ScalarEvolution::forgetLoop(const Loop *L) { PushDefUseChildren(I, Worklist); } + + // Forget all contained loops too, to avoid dangling entries in the + // ValuesAtScopes map. + for (Loop::iterator I = L->begin(), E = L->end(); I != E; ++I) + forgetLoop(*I); } /// forgetValue - This method should be called by the client when it has @@ -3802,7 +3808,7 @@ void ScalarEvolution::forgetValue(Value *V) { ValueExprMapType::iterator It = ValueExprMap.find(static_cast(I)); if (It != ValueExprMap.end()) { - ValuesAtScopes.erase(It->second); + forgetMemoizedResults(It->second); ValueExprMap.erase(It); if (PHINode *PN = dyn_cast(I)) ConstantEvolutionLoopExitValue.erase(PN); @@ -4016,6 +4022,105 @@ ScalarEvolution::ComputeBackedgeTakenCountFromExitCond(const Loop *L, return ComputeBackedgeTakenCountExhaustively(L, ExitCond, !L->contains(TBB)); } +static const SCEVAddRecExpr * +isSimpleUnwrappingAddRec(const SCEV *S, const Loop *L) { + const SCEVAddRecExpr *SA = dyn_cast(S); + + // The SCEV must be an addrec of this loop. + if (!SA || SA->getLoop() != L || !SA->isAffine()) + return 0; + + // The SCEV must be known to not wrap in some way to be interesting. + if (!SA->hasNoUnsignedWrap() && !SA->hasNoSignedWrap()) + return 0; + + // The stride must be a constant so that we know if it is striding up or down. + if (!isa(SA->getOperand(1))) + return 0; + return SA; +} + +/// getMinusSCEVForExitTest - When considering an exit test for a loop with a +/// "x != y" exit test, we turn this into a computation that evaluates x-y != 0, +/// and this function returns the expression to use for x-y. We know and take +/// advantage of the fact that this subtraction is only being used in a +/// comparison by zero context. +/// +static const SCEV *getMinusSCEVForExitTest(const SCEV *LHS, const SCEV *RHS, + const Loop *L, ScalarEvolution &SE) { + // If either LHS or RHS is an AddRec SCEV (of this loop) that is known to not + // wrap (either NSW or NUW), then we know that the value will either become + // the other one (and thus the loop terminates), that the loop will terminate + // through some other exit condition first, or that the loop has undefined + // behavior. This information is useful when the addrec has a stride that is + // != 1 or -1, because it means we can't "miss" the exit value. + // + // In any of these three cases, it is safe to turn the exit condition into a + // "counting down" AddRec (to zero) by subtracting the two inputs as normal, + // but since we know that the "end cannot be missed" we can force the + // resulting AddRec to be a NUW addrec. Since it is counting down, this means + // that the AddRec *cannot* pass zero. + + // See if LHS and RHS are addrec's we can handle. + const SCEVAddRecExpr *LHSA = isSimpleUnwrappingAddRec(LHS, L); + const SCEVAddRecExpr *RHSA = isSimpleUnwrappingAddRec(RHS, L); + + // If neither addrec is interesting, just return a minus. + if (RHSA == 0 && LHSA == 0) + return SE.getMinusSCEV(LHS, RHS); + + // If only one of LHS and RHS are an AddRec of this loop, make sure it is LHS. + if (RHSA && LHSA == 0) { + // Safe because a-b === b-a for comparisons against zero. + std::swap(LHS, RHS); + std::swap(LHSA, RHSA); + } + + // Handle the case when only one is advancing in a non-overflowing way. + if (RHSA == 0) { + // If RHS is loop varying, then we can't predict when LHS will cross it. + if (!SE.isLoopInvariant(RHS, L)) + return SE.getMinusSCEV(LHS, RHS); + + // If LHS has a positive stride, then we compute RHS-LHS, because the loop + // is counting up until it crosses RHS (which must be larger than LHS). If + // it is negative, we compute LHS-RHS because we're counting down to RHS. + const ConstantInt *Stride = + cast(LHSA->getOperand(1))->getValue(); + if (Stride->getValue().isNegative()) + std::swap(LHS, RHS); + + return SE.getMinusSCEV(RHS, LHS, true /*HasNUW*/); + } + + // If both LHS and RHS are interesting, we have something like: + // a+i*4 != b+i*8. + const ConstantInt *LHSStride = + cast(LHSA->getOperand(1))->getValue(); + const ConstantInt *RHSStride = + cast(RHSA->getOperand(1))->getValue(); + + // If the strides are equal, then this is just a (complex) loop invariant + // comparison of a and b. + if (LHSStride == RHSStride) + return SE.getMinusSCEV(LHSA->getStart(), RHSA->getStart()); + + // If the signs of the strides differ, then the negative stride is counting + // down to the positive stride. + if (LHSStride->getValue().isNegative() != RHSStride->getValue().isNegative()){ + if (RHSStride->getValue().isNegative()) + std::swap(LHS, RHS); + } else { + // If LHS's stride is smaller than RHS's stride, then "b" must be less than + // "a" and "b" is RHS is counting up (catching up) to LHS. This is true + // whether the strides are positive or negative. + if (RHSStride->getValue().slt(LHSStride->getValue())) + std::swap(LHS, RHS); + } + + return SE.getMinusSCEV(LHS, RHS, true /*HasNUW*/); +} + /// ComputeBackedgeTakenCountFromExitCondICmp - Compute the number of times the /// backedge of the specified loop will execute if its exit condition /// were a conditional branch of the ICmpInst ExitCond, TBB, and FBB. @@ -4050,7 +4155,7 @@ ScalarEvolution::ComputeBackedgeTakenCountFromExitCondICmp(const Loop *L, // At this point, we would like to compute how many iterations of the // loop the predicate will return true for these inputs. - if (LHS->isLoopInvariant(L) && !RHS->isLoopInvariant(L)) { + if (isLoopInvariant(LHS, L) && !isLoopInvariant(RHS, L)) { // If there is a loop-invariant, force it into the RHS. std::swap(LHS, RHS); Cond = ICmpInst::getSwappedPredicate(Cond); @@ -4075,7 +4180,8 @@ ScalarEvolution::ComputeBackedgeTakenCountFromExitCondICmp(const Loop *L, switch (Cond) { case ICmpInst::ICMP_NE: { // while (X != Y) // Convert to: while (X-Y != 0) - BackedgeTakenInfo BTI = HowFarToZero(getMinusSCEV(LHS, RHS), L); + BackedgeTakenInfo BTI = HowFarToZero(getMinusSCEVForExitTest(LHS, RHS, L, + *this), L); if (BTI.hasAnyInfo()) return BTI; break; } @@ -4212,7 +4318,7 @@ ScalarEvolution::ComputeLoadConstantCompareBackedgeTakenCount( // We can only recognize very limited forms of loop index expressions, in // particular, only affine AddRec's like {C1,+,C2}. const SCEVAddRecExpr *IdxExpr = dyn_cast(Idx); - if (!IdxExpr || !IdxExpr->isAffine() || IdxExpr->isLoopInvariant(L) || + if (!IdxExpr || !IdxExpr->isAffine() || isLoopInvariant(IdxExpr, L) || !isa(IdxExpr->getOperand(0)) || !isa(IdxExpr->getOperand(1))) return getCouldNotCompute(); @@ -4686,7 +4792,7 @@ static const SCEV *SolveLinEquationWithOverflow(const APInt &A, const APInt &B, // bit width during computations. APInt AD = A.lshr(Mult2).zext(BW + 1); // AD = A / D APInt Mod(BW + 1, 0); - Mod.set(BW - Mult2); // Mod = N / D + Mod.setBit(BW - Mult2); // Mod = N / D APInt I = AD.multiplicativeInverse(Mod); // 4. Compute the minimum unsigned root of the equation: @@ -4778,58 +4884,26 @@ ScalarEvolution::HowFarToZero(const SCEV *V, const Loop *L) { if (!AddRec || AddRec->getLoop() != L) return getCouldNotCompute(); - if (AddRec->isAffine()) { - // If this is an affine expression, the execution count of this branch is - // the minimum unsigned root of the following equation: - // - // Start + Step*N = 0 (mod 2^BW) - // - // equivalent to: - // - // Step*N = -Start (mod 2^BW) - // - // where BW is the common bit width of Start and Step. - - // Get the initial value for the loop. - const SCEV *Start = getSCEVAtScope(AddRec->getStart(), - L->getParentLoop()); - const SCEV *Step = getSCEVAtScope(AddRec->getOperand(1), - L->getParentLoop()); - - if (const SCEVConstant *StepC = dyn_cast(Step)) { - // For now we handle only constant steps. - - // First, handle unitary steps. - if (StepC->getValue()->equalsInt(1)) // 1*N = -Start (mod 2^BW), so: - return getNegativeSCEV(Start); // N = -Start (as unsigned) - if (StepC->getValue()->isAllOnesValue()) // -1*N = -Start (mod 2^BW), so: - return Start; // N = Start (as unsigned) - - // Then, try to solve the above equation provided that Start is constant. - if (const SCEVConstant *StartC = dyn_cast(Start)) - return SolveLinEquationWithOverflow(StepC->getValue()->getValue(), - -StartC->getValue()->getValue(), - *this); - } - } else if (AddRec->isQuadratic() && AddRec->getType()->isIntegerTy()) { - // If this is a quadratic (3-term) AddRec {L,+,M,+,N}, find the roots of - // the quadratic equation to solve it. - std::pair Roots = SolveQuadraticEquation(AddRec, - *this); + // If this is a quadratic (3-term) AddRec {L,+,M,+,N}, find the roots of + // the quadratic equation to solve it. + if (AddRec->isQuadratic() && AddRec->getType()->isIntegerTy()) { + std::pair Roots = + SolveQuadraticEquation(AddRec, *this); const SCEVConstant *R1 = dyn_cast(Roots.first); const SCEVConstant *R2 = dyn_cast(Roots.second); - if (R1) { + if (R1 && R2) { #if 0 dbgs() << "HFTZ: " << *V << " - sol#1: " << *R1 << " sol#2: " << *R2 << "\n"; #endif // Pick the smallest positive root value. if (ConstantInt *CB = - dyn_cast(ConstantExpr::getICmp(ICmpInst::ICMP_ULT, - R1->getValue(), R2->getValue()))) { + dyn_cast(ConstantExpr::getICmp(CmpInst::ICMP_ULT, + R1->getValue(), + R2->getValue()))) { if (CB->getZExtValue() == false) std::swap(R1, R2); // R1 is the minimum root now. - + // We can only use this value if the chrec ends up with an exact zero // value at this index. When solving for "X*X != 5", for example, we // should not accept a root of 2. @@ -4838,8 +4912,54 @@ ScalarEvolution::HowFarToZero(const SCEV *V, const Loop *L) { return R1; // We found a quadratic root! } } + return getCouldNotCompute(); } + // Otherwise we can only handle this if it is affine. + if (!AddRec->isAffine()) + return getCouldNotCompute(); + + // If this is an affine expression, the execution count of this branch is + // the minimum unsigned root of the following equation: + // + // Start + Step*N = 0 (mod 2^BW) + // + // equivalent to: + // + // Step*N = -Start (mod 2^BW) + // + // where BW is the common bit width of Start and Step. + + // Get the initial value for the loop. + const SCEV *Start = getSCEVAtScope(AddRec->getStart(), L->getParentLoop()); + const SCEV *Step = getSCEVAtScope(AddRec->getOperand(1), L->getParentLoop()); + + // If the AddRec is NUW, then (in an unsigned sense) it cannot be counting up + // to wrap to 0, it must be counting down to equal 0. Also, while counting + // down, it cannot "miss" 0 (which would cause it to wrap), regardless of what + // the stride is. As such, NUW addrec's will always become zero in + // "start / -stride" steps, and we know that the division is exact. + if (AddRec->hasNoUnsignedWrap()) + // FIXME: We really want an "isexact" bit for udiv. + return getUDivExpr(Start, getNegativeSCEV(Step)); + + // For now we handle only constant steps. + const SCEVConstant *StepC = dyn_cast(Step); + if (StepC == 0) + return getCouldNotCompute(); + + // First, handle unitary steps. + if (StepC->getValue()->equalsInt(1)) // 1*N = -Start (mod 2^BW), so: + return getNegativeSCEV(Start); // N = -Start (as unsigned) + + if (StepC->getValue()->isAllOnesValue()) // -1*N = -Start (mod 2^BW), so: + return Start; // N = Start (as unsigned) + + // Then, try to solve the above equation provided that Start is constant. + if (const SCEVConstant *StartC = dyn_cast(Start)) + return SolveLinEquationWithOverflow(StepC->getValue()->getValue(), + -StartC->getValue()->getValue(), + *this); return getCouldNotCompute(); } @@ -4939,7 +5059,7 @@ bool ScalarEvolution::SimplifyICmpOperands(ICmpInst::Predicate &Pred, // as both operands could be addrecs loop-invariant in each other's loop. if (const SCEVAddRecExpr *AR = dyn_cast(RHS)) { const Loop *L = AR->getLoop(); - if (LHS->isLoopInvariant(L) && LHS->properlyDominates(L->getHeader(), DT)) { + if (isLoopInvariant(LHS, L) && properlyDominates(LHS, L->getHeader())) { std::swap(LHS, RHS); Pred = ICmpInst::getSwappedPredicate(Pred); Changed = true; @@ -5159,13 +5279,13 @@ bool ScalarEvolution::SimplifyICmpOperands(ICmpInst::Predicate &Pred, trivially_true: // Return 0 == 0. - LHS = RHS = getConstant(Type::getInt1Ty(getContext()), 0); + LHS = RHS = getConstant(ConstantInt::getFalse(getContext())); Pred = ICmpInst::ICMP_EQ; return true; trivially_false: // Return 0 != 0. - LHS = RHS = getConstant(Type::getInt1Ty(getContext()), 0); + LHS = RHS = getConstant(ConstantInt::getFalse(getContext())); Pred = ICmpInst::ICMP_NE; return true; } @@ -5556,7 +5676,7 @@ ScalarEvolution::BackedgeTakenInfo ScalarEvolution::HowManyLessThans(const SCEV *LHS, const SCEV *RHS, const Loop *L, bool isSigned) { // Only handle: "ADDREC < LoopInvariant". - if (!RHS->isLoopInvariant(L)) return getCouldNotCompute(); + if (!isLoopInvariant(RHS, L)) return getCouldNotCompute(); const SCEVAddRecExpr *AddRec = dyn_cast(LHS); if (!AddRec || AddRec->getLoop() != L) @@ -5836,6 +5956,7 @@ ScalarEvolution::SCEVCallbackVH::SCEVCallbackVH(Value *V, ScalarEvolution *se) ScalarEvolution::ScalarEvolution() : FunctionPass(ID), FirstUnknown(0) { + initializeScalarEvolutionPass(*PassRegistry::getPassRegistry()); } bool ScalarEvolution::runOnFunction(Function &F) { @@ -5857,6 +5978,10 @@ void ScalarEvolution::releaseMemory() { BackedgeTakenCounts.clear(); ConstantEvolutionLoopExitValue.clear(); ValuesAtScopes.clear(); + LoopDispositions.clear(); + BlockDispositions.clear(); + UnsignedRanges.clear(); + SignedRanges.clear(); UniqueSCEVs.clear(); SCEVAllocator.Reset(); } @@ -5936,7 +6061,7 @@ void ScalarEvolution::print(raw_ostream &OS, const Module *) const { if (L) { OS << "\t\t" "Exits: "; const SCEV *ExitValue = SE.getSCEVAtScope(SV, L->getParentLoop()); - if (!ExitValue->isLoopInvariant(L)) { + if (!SE.isLoopInvariant(ExitValue, L)) { OS << "<>"; } else { OS << *ExitValue; @@ -5953,3 +6078,240 @@ void ScalarEvolution::print(raw_ostream &OS, const Module *) const { PrintLoopInfo(OS, &SE, *I); } +ScalarEvolution::LoopDisposition +ScalarEvolution::getLoopDisposition(const SCEV *S, const Loop *L) { + std::map &Values = LoopDispositions[S]; + std::pair::iterator, bool> Pair = + Values.insert(std::make_pair(L, LoopVariant)); + if (!Pair.second) + return Pair.first->second; + + LoopDisposition D = computeLoopDisposition(S, L); + return LoopDispositions[S][L] = D; +} + +ScalarEvolution::LoopDisposition +ScalarEvolution::computeLoopDisposition(const SCEV *S, const Loop *L) { + switch (S->getSCEVType()) { + case scConstant: + return LoopInvariant; + case scTruncate: + case scZeroExtend: + case scSignExtend: + return getLoopDisposition(cast(S)->getOperand(), L); + case scAddRecExpr: { + const SCEVAddRecExpr *AR = cast(S); + + // If L is the addrec's loop, it's computable. + if (AR->getLoop() == L) + return LoopComputable; + + // Add recurrences are never invariant in the function-body (null loop). + if (!L) + return LoopVariant; + + // This recurrence is variant w.r.t. L if L contains AR's loop. + if (L->contains(AR->getLoop())) + return LoopVariant; + + // This recurrence is invariant w.r.t. L if AR's loop contains L. + if (AR->getLoop()->contains(L)) + return LoopInvariant; + + // This recurrence is variant w.r.t. L if any of its operands + // are variant. + for (SCEVAddRecExpr::op_iterator I = AR->op_begin(), E = AR->op_end(); + I != E; ++I) + if (!isLoopInvariant(*I, L)) + return LoopVariant; + + // Otherwise it's loop-invariant. + return LoopInvariant; + } + case scAddExpr: + case scMulExpr: + case scUMaxExpr: + case scSMaxExpr: { + const SCEVNAryExpr *NAry = cast(S); + bool HasVarying = false; + for (SCEVNAryExpr::op_iterator I = NAry->op_begin(), E = NAry->op_end(); + I != E; ++I) { + LoopDisposition D = getLoopDisposition(*I, L); + if (D == LoopVariant) + return LoopVariant; + if (D == LoopComputable) + HasVarying = true; + } + return HasVarying ? LoopComputable : LoopInvariant; + } + case scUDivExpr: { + const SCEVUDivExpr *UDiv = cast(S); + LoopDisposition LD = getLoopDisposition(UDiv->getLHS(), L); + if (LD == LoopVariant) + return LoopVariant; + LoopDisposition RD = getLoopDisposition(UDiv->getRHS(), L); + if (RD == LoopVariant) + return LoopVariant; + return (LD == LoopInvariant && RD == LoopInvariant) ? + LoopInvariant : LoopComputable; + } + case scUnknown: + // All non-instruction values are loop invariant. All instructions are loop + // invariant if they are not contained in the specified loop. + // Instructions are never considered invariant in the function body + // (null loop) because they are defined within the "loop". + if (Instruction *I = dyn_cast(cast(S)->getValue())) + return (L && !L->contains(I)) ? LoopInvariant : LoopVariant; + return LoopInvariant; + case scCouldNotCompute: + llvm_unreachable("Attempt to use a SCEVCouldNotCompute object!"); + return LoopVariant; + default: break; + } + llvm_unreachable("Unknown SCEV kind!"); + return LoopVariant; +} + +bool ScalarEvolution::isLoopInvariant(const SCEV *S, const Loop *L) { + return getLoopDisposition(S, L) == LoopInvariant; +} + +bool ScalarEvolution::hasComputableLoopEvolution(const SCEV *S, const Loop *L) { + return getLoopDisposition(S, L) == LoopComputable; +} + +ScalarEvolution::BlockDisposition +ScalarEvolution::getBlockDisposition(const SCEV *S, const BasicBlock *BB) { + std::map &Values = BlockDispositions[S]; + std::pair::iterator, bool> + Pair = Values.insert(std::make_pair(BB, DoesNotDominateBlock)); + if (!Pair.second) + return Pair.first->second; + + BlockDisposition D = computeBlockDisposition(S, BB); + return BlockDispositions[S][BB] = D; +} + +ScalarEvolution::BlockDisposition +ScalarEvolution::computeBlockDisposition(const SCEV *S, const BasicBlock *BB) { + switch (S->getSCEVType()) { + case scConstant: + return ProperlyDominatesBlock; + case scTruncate: + case scZeroExtend: + case scSignExtend: + return getBlockDisposition(cast(S)->getOperand(), BB); + case scAddRecExpr: { + // This uses a "dominates" query instead of "properly dominates" query + // to test for proper dominance too, because the instruction which + // produces the addrec's value is a PHI, and a PHI effectively properly + // dominates its entire containing block. + const SCEVAddRecExpr *AR = cast(S); + if (!DT->dominates(AR->getLoop()->getHeader(), BB)) + return DoesNotDominateBlock; + } + // FALL THROUGH into SCEVNAryExpr handling. + case scAddExpr: + case scMulExpr: + case scUMaxExpr: + case scSMaxExpr: { + const SCEVNAryExpr *NAry = cast(S); + bool Proper = true; + for (SCEVNAryExpr::op_iterator I = NAry->op_begin(), E = NAry->op_end(); + I != E; ++I) { + BlockDisposition D = getBlockDisposition(*I, BB); + if (D == DoesNotDominateBlock) + return DoesNotDominateBlock; + if (D == DominatesBlock) + Proper = false; + } + return Proper ? ProperlyDominatesBlock : DominatesBlock; + } + case scUDivExpr: { + const SCEVUDivExpr *UDiv = cast(S); + const SCEV *LHS = UDiv->getLHS(), *RHS = UDiv->getRHS(); + BlockDisposition LD = getBlockDisposition(LHS, BB); + if (LD == DoesNotDominateBlock) + return DoesNotDominateBlock; + BlockDisposition RD = getBlockDisposition(RHS, BB); + if (RD == DoesNotDominateBlock) + return DoesNotDominateBlock; + return (LD == ProperlyDominatesBlock && RD == ProperlyDominatesBlock) ? + ProperlyDominatesBlock : DominatesBlock; + } + case scUnknown: + if (Instruction *I = + dyn_cast(cast(S)->getValue())) { + if (I->getParent() == BB) + return DominatesBlock; + if (DT->properlyDominates(I->getParent(), BB)) + return ProperlyDominatesBlock; + return DoesNotDominateBlock; + } + return ProperlyDominatesBlock; + case scCouldNotCompute: + llvm_unreachable("Attempt to use a SCEVCouldNotCompute object!"); + return DoesNotDominateBlock; + default: break; + } + llvm_unreachable("Unknown SCEV kind!"); + return DoesNotDominateBlock; +} + +bool ScalarEvolution::dominates(const SCEV *S, const BasicBlock *BB) { + return getBlockDisposition(S, BB) >= DominatesBlock; +} + +bool ScalarEvolution::properlyDominates(const SCEV *S, const BasicBlock *BB) { + return getBlockDisposition(S, BB) == ProperlyDominatesBlock; +} + +bool ScalarEvolution::hasOperand(const SCEV *S, const SCEV *Op) const { + switch (S->getSCEVType()) { + case scConstant: + return false; + case scTruncate: + case scZeroExtend: + case scSignExtend: { + const SCEVCastExpr *Cast = cast(S); + const SCEV *CastOp = Cast->getOperand(); + return Op == CastOp || hasOperand(CastOp, Op); + } + case scAddRecExpr: + case scAddExpr: + case scMulExpr: + case scUMaxExpr: + case scSMaxExpr: { + const SCEVNAryExpr *NAry = cast(S); + for (SCEVNAryExpr::op_iterator I = NAry->op_begin(), E = NAry->op_end(); + I != E; ++I) { + const SCEV *NAryOp = *I; + if (NAryOp == Op || hasOperand(NAryOp, Op)) + return true; + } + return false; + } + case scUDivExpr: { + const SCEVUDivExpr *UDiv = cast(S); + const SCEV *LHS = UDiv->getLHS(), *RHS = UDiv->getRHS(); + return LHS == Op || hasOperand(LHS, Op) || + RHS == Op || hasOperand(RHS, Op); + } + case scUnknown: + return false; + case scCouldNotCompute: + llvm_unreachable("Attempt to use a SCEVCouldNotCompute object!"); + return false; + default: break; + } + llvm_unreachable("Unknown SCEV kind!"); + return false; +} + +void ScalarEvolution::forgetMemoizedResults(const SCEV *S) { + ValuesAtScopes.erase(S); + LoopDispositions.erase(S); + BlockDispositions.erase(S); + UnsignedRanges.erase(S); + SignedRanges.erase(S); +} diff --git a/lib/Analysis/ScalarEvolutionAliasAnalysis.cpp b/lib/Analysis/ScalarEvolutionAliasAnalysis.cpp index 93b2a8b06fbe..e9edb3e083de 100644 --- a/lib/Analysis/ScalarEvolutionAliasAnalysis.cpp +++ b/lib/Analysis/ScalarEvolutionAliasAnalysis.cpp @@ -34,7 +34,10 @@ namespace { public: static char ID; // Class identification, replacement for typeinfo - ScalarEvolutionAliasAnalysis() : FunctionPass(ID), SE(0) {} + ScalarEvolutionAliasAnalysis() : FunctionPass(ID), SE(0) { + initializeScalarEvolutionAliasAnalysisPass( + *PassRegistry::getPassRegistry()); + } /// getAdjustedAnalysisPointer - This method is used when a pass implements /// an analysis interface through multiple inheritance. If needed, it @@ -49,8 +52,7 @@ namespace { private: virtual void getAnalysisUsage(AnalysisUsage &AU) const; virtual bool runOnFunction(Function &F); - virtual AliasResult alias(const Value *V1, unsigned V1Size, - const Value *V2, unsigned V2Size); + virtual AliasResult alias(const Location &LocA, const Location &LocB); Value *GetBaseValue(const SCEV *S); }; @@ -58,8 +60,11 @@ namespace { // Register this pass... char ScalarEvolutionAliasAnalysis::ID = 0; -INITIALIZE_AG_PASS(ScalarEvolutionAliasAnalysis, AliasAnalysis, "scev-aa", - "ScalarEvolution-based Alias Analysis", false, true, false); +INITIALIZE_AG_PASS_BEGIN(ScalarEvolutionAliasAnalysis, AliasAnalysis, "scev-aa", + "ScalarEvolution-based Alias Analysis", false, true, false) +INITIALIZE_PASS_DEPENDENCY(ScalarEvolution) +INITIALIZE_AG_PASS_END(ScalarEvolutionAliasAnalysis, AliasAnalysis, "scev-aa", + "ScalarEvolution-based Alias Analysis", false, true, false) FunctionPass *llvm::createScalarEvolutionAliasAnalysisPass() { return new ScalarEvolutionAliasAnalysis(); @@ -101,17 +106,17 @@ ScalarEvolutionAliasAnalysis::GetBaseValue(const SCEV *S) { } AliasAnalysis::AliasResult -ScalarEvolutionAliasAnalysis::alias(const Value *A, unsigned ASize, - const Value *B, unsigned BSize) { +ScalarEvolutionAliasAnalysis::alias(const Location &LocA, + const Location &LocB) { // If either of the memory references is empty, it doesn't matter what the // pointer values are. This allows the code below to ignore this special // case. - if (ASize == 0 || BSize == 0) + if (LocA.Size == 0 || LocB.Size == 0) return NoAlias; // This is ScalarEvolutionAliasAnalysis. Get the SCEVs! - const SCEV *AS = SE->getSCEV(const_cast(A)); - const SCEV *BS = SE->getSCEV(const_cast(B)); + const SCEV *AS = SE->getSCEV(const_cast(LocA.Ptr)); + const SCEV *BS = SE->getSCEV(const_cast(LocB.Ptr)); // If they evaluate to the same expression, it's a MustAlias. if (AS == BS) return MustAlias; @@ -121,8 +126,8 @@ ScalarEvolutionAliasAnalysis::alias(const Value *A, unsigned ASize, if (SE->getEffectiveSCEVType(AS->getType()) == SE->getEffectiveSCEVType(BS->getType())) { unsigned BitWidth = SE->getTypeSizeInBits(AS->getType()); - APInt ASizeInt(BitWidth, ASize); - APInt BSizeInt(BitWidth, BSize); + APInt ASizeInt(BitWidth, LocA.Size); + APInt BSizeInt(BitWidth, LocB.Size); // Compute the difference between the two pointers. const SCEV *BA = SE->getMinusSCEV(BS, AS); @@ -154,11 +159,15 @@ ScalarEvolutionAliasAnalysis::alias(const Value *A, unsigned ASize, // inttoptr and ptrtoint operators. Value *AO = GetBaseValue(AS); Value *BO = GetBaseValue(BS); - if ((AO && AO != A) || (BO && BO != B)) - if (alias(AO ? AO : A, AO ? UnknownSize : ASize, - BO ? BO : B, BO ? UnknownSize : BSize) == NoAlias) + if ((AO && AO != LocA.Ptr) || (BO && BO != LocB.Ptr)) + if (alias(Location(AO ? AO : LocA.Ptr, + AO ? +UnknownSize : LocA.Size, + AO ? 0 : LocA.TBAATag), + Location(BO ? BO : LocB.Ptr, + BO ? +UnknownSize : LocB.Size, + BO ? 0 : LocB.TBAATag)) == NoAlias) return NoAlias; // Forward the query to the next analysis. - return AliasAnalysis::alias(A, ASize, B, BSize); + return AliasAnalysis::alias(LocA, LocB); } diff --git a/lib/Analysis/ScalarEvolutionExpander.cpp b/lib/Analysis/ScalarEvolutionExpander.cpp index 66a06aeac43c..b7c110f28cf9 100644 --- a/lib/Analysis/ScalarEvolutionExpander.cpp +++ b/lib/Analysis/ScalarEvolutionExpander.cpp @@ -608,15 +608,22 @@ static const Loop *PickMostRelevantLoop(const Loop *A, const Loop *B, return A; // Arbitrarily break the tie. } -/// GetRelevantLoop - Get the most relevant loop associated with the given +/// getRelevantLoop - Get the most relevant loop associated with the given /// expression, according to PickMostRelevantLoop. -static const Loop *GetRelevantLoop(const SCEV *S, LoopInfo &LI, - DominatorTree &DT) { +const Loop *SCEVExpander::getRelevantLoop(const SCEV *S) { + // Test whether we've already computed the most relevant loop for this SCEV. + std::pair::iterator, bool> Pair = + RelevantLoops.insert(std::make_pair(S, static_cast(0))); + if (!Pair.second) + return Pair.first->second; + if (isa(S)) + // A constant has no relevant loops. return 0; if (const SCEVUnknown *U = dyn_cast(S)) { if (const Instruction *I = dyn_cast(U->getValue())) - return LI.getLoopFor(I->getParent()); + return Pair.first->second = SE.LI->getLoopFor(I->getParent()); + // A non-instruction has no relevant loops. return 0; } if (const SCEVNAryExpr *N = dyn_cast(S)) { @@ -625,16 +632,22 @@ static const Loop *GetRelevantLoop(const SCEV *S, LoopInfo &LI, L = AR->getLoop(); for (SCEVNAryExpr::op_iterator I = N->op_begin(), E = N->op_end(); I != E; ++I) - L = PickMostRelevantLoop(L, GetRelevantLoop(*I, LI, DT), DT); - return L; + L = PickMostRelevantLoop(L, getRelevantLoop(*I), *SE.DT); + return RelevantLoops[N] = L; + } + if (const SCEVCastExpr *C = dyn_cast(S)) { + const Loop *Result = getRelevantLoop(C->getOperand()); + return RelevantLoops[C] = Result; + } + if (const SCEVUDivExpr *D = dyn_cast(S)) { + const Loop *Result = + PickMostRelevantLoop(getRelevantLoop(D->getLHS()), + getRelevantLoop(D->getRHS()), + *SE.DT); + return RelevantLoops[D] = Result; } - if (const SCEVCastExpr *C = dyn_cast(S)) - return GetRelevantLoop(C->getOperand(), LI, DT); - if (const SCEVUDivExpr *D = dyn_cast(S)) - return PickMostRelevantLoop(GetRelevantLoop(D->getLHS(), LI, DT), - GetRelevantLoop(D->getRHS(), LI, DT), - DT); llvm_unreachable("Unexpected SCEV type!"); + return 0; } namespace { @@ -682,8 +695,7 @@ Value *SCEVExpander::visitAddExpr(const SCEVAddExpr *S) { SmallVector, 8> OpsAndLoops; for (std::reverse_iterator I(S->op_end()), E(S->op_begin()); I != E; ++I) - OpsAndLoops.push_back(std::make_pair(GetRelevantLoop(*I, *SE.LI, *SE.DT), - *I)); + OpsAndLoops.push_back(std::make_pair(getRelevantLoop(*I), *I)); // Sort by loop. Use a stable sort so that constants follow non-constants and // pointer operands precede non-pointer operands. @@ -752,8 +764,7 @@ Value *SCEVExpander::visitMulExpr(const SCEVMulExpr *S) { SmallVector, 8> OpsAndLoops; for (std::reverse_iterator I(S->op_end()), E(S->op_begin()); I != E; ++I) - OpsAndLoops.push_back(std::make_pair(GetRelevantLoop(*I, *SE.LI, *SE.DT), - *I)); + OpsAndLoops.push_back(std::make_pair(getRelevantLoop(*I), *I)); // Sort by loop. Use a stable sort so that constants follow non-constants. std::stable_sort(OpsAndLoops.begin(), OpsAndLoops.end(), LoopCompare(*SE.DT)); @@ -990,7 +1001,7 @@ Value *SCEVExpander::expandAddRecExprLiterally(const SCEVAddRecExpr *S) { // Strip off any non-loop-dominating component from the addrec start. const SCEV *Start = Normalized->getStart(); const SCEV *PostLoopOffset = 0; - if (!Start->properlyDominates(L->getHeader(), SE.DT)) { + if (!SE.properlyDominates(Start, L->getHeader())) { PostLoopOffset = Start; Start = SE.getConstant(Normalized->getType(), 0); Normalized = @@ -1002,7 +1013,7 @@ Value *SCEVExpander::expandAddRecExprLiterally(const SCEVAddRecExpr *S) { // Strip off any non-loop-dominating component from the addrec step. const SCEV *Step = Normalized->getStepRecurrence(SE); const SCEV *PostLoopScale = 0; - if (!Step->dominates(L->getHeader(), SE.DT)) { + if (!SE.dominates(Step, L->getHeader())) { PostLoopScale = Step; Step = SE.getConstant(Normalized->getType(), 1); Normalized = @@ -1278,7 +1289,7 @@ Value *SCEVExpander::expand(const SCEV *S) { Instruction *InsertPt = Builder.GetInsertPoint(); for (Loop *L = SE.LI->getLoopFor(Builder.GetInsertBlock()); ; L = L->getParentLoop()) - if (S->isLoopInvariant(L)) { + if (SE.isLoopInvariant(S, L)) { if (!L) break; if (BasicBlock *Preheader = L->getLoopPreheader()) InsertPt = Preheader->getTerminator(); @@ -1286,7 +1297,7 @@ Value *SCEVExpander::expand(const SCEV *S) { // If the SCEV is computable at this level, insert it into the header // after the PHIs (and after any other instructions that we've inserted // there) so that it is guaranteed to dominate any user inside the loop. - if (L && S->hasComputableLoopEvolution(L) && !PostIncLoops.count(L)) + if (L && SE.hasComputableLoopEvolution(S, L) && !PostIncLoops.count(L)) InsertPt = L->getHeader()->getFirstNonPHI(); while (isInsertedInstruction(InsertPt) || isa(InsertPt)) InsertPt = llvm::next(BasicBlock::iterator(InsertPt)); diff --git a/lib/Analysis/TypeBasedAliasAnalysis.cpp b/lib/Analysis/TypeBasedAliasAnalysis.cpp index bbfdcec3f9b4..40e18ab2fbfa 100644 --- a/lib/Analysis/TypeBasedAliasAnalysis.cpp +++ b/lib/Analysis/TypeBasedAliasAnalysis.cpp @@ -12,29 +12,65 @@ // // In LLVM IR, memory does not have types, so LLVM's own type system is not // suitable for doing TBAA. Instead, metadata is added to the IR to describe -// a type system of a higher level language. +// a type system of a higher level language. This can be used to implement +// typical C/C++ TBAA, but it can also be used to implement custom alias +// analysis behavior for other languages. // -// This pass is language-independent. The type system is encoded in -// metadata. This allows this pass to support typical C and C++ TBAA, but -// it can also support custom aliasing behavior for other languages. +// The current metadata format is very simple. TBAA MDNodes have up to +// three fields, e.g.: +// !0 = metadata !{ metadata !"an example type tree" } +// !1 = metadata !{ metadata !"int", metadata !0 } +// !2 = metadata !{ metadata !"float", metadata !0 } +// !3 = metadata !{ metadata !"const float", metadata !2, i64 1 } // -// This is a work-in-progress. It doesn't work yet, and the metadata -// format isn't stable. +// The first field is an identity field. It can be any value, usually +// an MDString, which uniquely identifies the type. The most important +// name in the tree is the name of the root node. Two trees with +// different root node names are entirely disjoint, even if they +// have leaves with common names. // -// TODO: getModRefBehavior. The AliasAnalysis infrastructure will need to -// be extended. -// TODO: AA chaining -// TODO: struct fields +// The second field identifies the type's parent node in the tree, or +// is null or omitted for a root node. A type is considered to alias +// all of its decendents and all of its ancestors in the tree. Also, +// a type is considered to alias all types in other trees, so that +// bitcode produced from multiple front-ends is handled conservatively. +// +// If the third field is present, it's an integer which if equal to 1 +// indicates that the type is "constant" (meaning pointsToConstantMemory +// should return true; see +// http://llvm.org/docs/AliasAnalysis.html#OtherItfs). +// +// TODO: The current metadata format doesn't support struct +// fields. For example: +// struct X { +// double d; +// int i; +// }; +// void foo(struct X *x, struct X *y, double *p) { +// *x = *y; +// *p = 0.0; +// } +// Struct X has a double member, so the store to *x can alias the store to *p. +// Currently it's not possible to precisely describe all the things struct X +// aliases, so struct assignments must use conservative TBAA nodes. There's +// no scheme for attaching metadata to @llvm.memcpy yet either. // //===----------------------------------------------------------------------===// #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/Passes.h" +#include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/Metadata.h" #include "llvm/Pass.h" +#include "llvm/Support/CommandLine.h" using namespace llvm; +// A handy option for disabling TBAA functionality. The same effect can also be +// achieved by stripping the !tbaa tags from IR, but this option is sometimes +// more convenient. +static cl::opt EnableTBAA("enable-tbaa", cl::init(true)); + namespace { /// TBAANode - This is a simple wrapper around an MDNode which provides a /// higher-level interface by hiding the details of how alias analysis @@ -44,16 +80,16 @@ namespace { public: TBAANode() : Node(0) {} - explicit TBAANode(MDNode *N) : Node(N) {} + explicit TBAANode(const MDNode *N) : Node(N) {} /// getNode - Get the MDNode for this TBAANode. const MDNode *getNode() const { return Node; } - /// getParent - Get this TBAANode's Alias DAG parent. + /// getParent - Get this TBAANode's Alias tree parent. TBAANode getParent() const { if (Node->getNumOperands() < 2) return TBAANode(); - MDNode *P = dyn_cast(Node->getOperand(1)); + MDNode *P = dyn_cast_or_null(Node->getOperand(1)); if (!P) return TBAANode(); // Ok, this node has a valid parent. Return it. @@ -69,8 +105,7 @@ namespace { ConstantInt *CI = dyn_cast(Node->getOperand(2)); if (!CI) return false; - // TODO: Think about the encoding. - return CI->isOne(); + return CI->getValue()[0]; } }; } @@ -82,7 +117,13 @@ namespace { public AliasAnalysis { public: static char ID; // Class identification, replacement for typeinfo - TypeBasedAliasAnalysis() : ImmutablePass(ID) {} + TypeBasedAliasAnalysis() : ImmutablePass(ID) { + initializeTypeBasedAliasAnalysisPass(*PassRegistry::getPassRegistry()); + } + + virtual void initializePass() { + InitializeAliasAnalysis(this); + } /// getAdjustedAnalysisPointer - This method is used when a pass implements /// an analysis interface through multiple inheritance. If needed, it @@ -94,18 +135,25 @@ namespace { return this; } + bool Aliases(const MDNode *A, const MDNode *B) const; + private: virtual void getAnalysisUsage(AnalysisUsage &AU) const; - virtual AliasResult alias(const Value *V1, unsigned V1Size, - const Value *V2, unsigned V2Size); - virtual bool pointsToConstantMemory(const Value *P); + virtual AliasResult alias(const Location &LocA, const Location &LocB); + virtual bool pointsToConstantMemory(const Location &Loc, bool OrLocal); + virtual ModRefBehavior getModRefBehavior(ImmutableCallSite CS); + virtual ModRefBehavior getModRefBehavior(const Function *F); + virtual ModRefResult getModRefInfo(ImmutableCallSite CS, + const Location &Loc); + virtual ModRefResult getModRefInfo(ImmutableCallSite CS1, + ImmutableCallSite CS2); }; } // End of anonymous namespace // Register this pass... char TypeBasedAliasAnalysis::ID = 0; INITIALIZE_AG_PASS(TypeBasedAliasAnalysis, AliasAnalysis, "tbaa", - "Type-Based Alias Analysis", false, true, false); + "Type-Based Alias Analysis", false, true, false) ImmutablePass *llvm::createTypeBasedAliasAnalysisPass() { return new TypeBasedAliasAnalysis(); @@ -117,34 +165,19 @@ TypeBasedAliasAnalysis::getAnalysisUsage(AnalysisUsage &AU) const { AliasAnalysis::getAnalysisUsage(AU); } -AliasAnalysis::AliasResult -TypeBasedAliasAnalysis::alias(const Value *A, unsigned ASize, - const Value *B, unsigned BSize) { - // Currently, metadata can only be attached to Instructions. - const Instruction *AI = dyn_cast(A); - if (!AI) return MayAlias; - const Instruction *BI = dyn_cast(B); - if (!BI) return MayAlias; - - // Get the attached MDNodes. If either value lacks a tbaa MDNode, we must - // be conservative. - MDNode *AM = - AI->getMetadata(AI->getParent()->getParent()->getParent() - ->getMDKindID("tbaa")); - if (!AM) return MayAlias; - MDNode *BM = - BI->getMetadata(BI->getParent()->getParent()->getParent() - ->getMDKindID("tbaa")); - if (!BM) return MayAlias; - +/// Aliases - Test whether the type represented by A may alias the +/// type represented by B. +bool +TypeBasedAliasAnalysis::Aliases(const MDNode *A, + const MDNode *B) const { // Keep track of the root node for A and B. TBAANode RootA, RootB; - // Climb the DAG from A to see if we reach B. - for (TBAANode T(AM); ; ) { - if (T.getNode() == BM) + // Climb the tree from A to see if we reach B. + for (TBAANode T(A); ; ) { + if (T.getNode() == B) // B is an ancestor of A. - return MayAlias; + return true; RootA = T; T = T.getParent(); @@ -152,11 +185,11 @@ TypeBasedAliasAnalysis::alias(const Value *A, unsigned ASize, break; } - // Climb the DAG from B to see if we reach A. - for (TBAANode T(BM); ; ) { - if (T.getNode() == AM) + // Climb the tree from B to see if we reach A. + for (TBAANode T(B); ; ) { + if (T.getNode() == A) // A is an ancestor of B. - return MayAlias; + return true; RootB = T; T = T.getParent(); @@ -166,26 +199,101 @@ TypeBasedAliasAnalysis::alias(const Value *A, unsigned ASize, // Neither node is an ancestor of the other. - // If they have the same root, then we've proved there's no alias. - if (RootA.getNode() == RootB.getNode()) - return NoAlias; - // If they have different roots, they're part of different potentially // unrelated type systems, so we must be conservative. - return MayAlias; + if (RootA.getNode() != RootB.getNode()) + return true; + + // If they have the same root, then we've proved there's no alias. + return false; +} + +AliasAnalysis::AliasResult +TypeBasedAliasAnalysis::alias(const Location &LocA, + const Location &LocB) { + if (!EnableTBAA) + return AliasAnalysis::alias(LocA, LocB); + + // Get the attached MDNodes. If either value lacks a tbaa MDNode, we must + // be conservative. + const MDNode *AM = LocA.TBAATag; + if (!AM) return AliasAnalysis::alias(LocA, LocB); + const MDNode *BM = LocB.TBAATag; + if (!BM) return AliasAnalysis::alias(LocA, LocB); + + // If they may alias, chain to the next AliasAnalysis. + if (Aliases(AM, BM)) + return AliasAnalysis::alias(LocA, LocB); + + // Otherwise return a definitive result. + return NoAlias; } -bool TypeBasedAliasAnalysis::pointsToConstantMemory(const Value *P) { - // Currently, metadata can only be attached to Instructions. - const Instruction *I = dyn_cast(P); - if (!I) return false; +bool TypeBasedAliasAnalysis::pointsToConstantMemory(const Location &Loc, + bool OrLocal) { + if (!EnableTBAA) + return AliasAnalysis::pointsToConstantMemory(Loc, OrLocal); - MDNode *M = - I->getMetadata(I->getParent()->getParent()->getParent() - ->getMDKindID("tbaa")); - if (!M) return false; + const MDNode *M = Loc.TBAATag; + if (!M) return AliasAnalysis::pointsToConstantMemory(Loc, OrLocal); // If this is an "immutable" type, we can assume the pointer is pointing // to constant memory. - return TBAANode(M).TypeIsImmutable(); + if (TBAANode(M).TypeIsImmutable()) + return true; + + return AliasAnalysis::pointsToConstantMemory(Loc, OrLocal); +} + +AliasAnalysis::ModRefBehavior +TypeBasedAliasAnalysis::getModRefBehavior(ImmutableCallSite CS) { + if (!EnableTBAA) + return AliasAnalysis::getModRefBehavior(CS); + + ModRefBehavior Min = UnknownModRefBehavior; + + // If this is an "immutable" type, we can assume the call doesn't write + // to memory. + if (const MDNode *M = CS.getInstruction()->getMetadata(LLVMContext::MD_tbaa)) + if (TBAANode(M).TypeIsImmutable()) + Min = OnlyReadsMemory; + + return ModRefBehavior(AliasAnalysis::getModRefBehavior(CS) & Min); +} + +AliasAnalysis::ModRefBehavior +TypeBasedAliasAnalysis::getModRefBehavior(const Function *F) { + // Functions don't have metadata. Just chain to the next implementation. + return AliasAnalysis::getModRefBehavior(F); +} + +AliasAnalysis::ModRefResult +TypeBasedAliasAnalysis::getModRefInfo(ImmutableCallSite CS, + const Location &Loc) { + if (!EnableTBAA) + return AliasAnalysis::getModRefInfo(CS, Loc); + + if (const MDNode *L = Loc.TBAATag) + if (const MDNode *M = + CS.getInstruction()->getMetadata(LLVMContext::MD_tbaa)) + if (!Aliases(L, M)) + return NoModRef; + + return AliasAnalysis::getModRefInfo(CS, Loc); +} + +AliasAnalysis::ModRefResult +TypeBasedAliasAnalysis::getModRefInfo(ImmutableCallSite CS1, + ImmutableCallSite CS2) { + if (!EnableTBAA) + return AliasAnalysis::getModRefInfo(CS1, CS2); + + if (const MDNode *M1 = + CS1.getInstruction()->getMetadata(LLVMContext::MD_tbaa)) + if (const MDNode *M2 = + CS2.getInstruction()->getMetadata(LLVMContext::MD_tbaa)) + if (!Aliases(M1, M2)) + return NoModRef; + + return AliasAnalysis::getModRefInfo(CS1, CS2); } diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index 181c9b01980c..1060bc5349e4 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/lib/Analysis/ValueTracking.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Analysis/ValueTracking.h" +#include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Constants.h" #include "llvm/Instructions.h" #include "llvm/GlobalVariable.h" @@ -23,9 +24,22 @@ #include "llvm/Target/TargetData.h" #include "llvm/Support/GetElementPtrTypeIterator.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/PatternMatch.h" #include "llvm/ADT/SmallPtrSet.h" #include using namespace llvm; +using namespace llvm::PatternMatch; + +const unsigned MaxDepth = 6; + +/// getBitWidth - Returns the bitwidth of the given scalar or pointer type (if +/// unknown returns 0). For vector types, returns the element type's bitwidth. +static unsigned getBitWidth(const Type *Ty, const TargetData *TD) { + if (unsigned BitWidth = Ty->getScalarSizeInBits()) + return BitWidth; + assert(isa(Ty) && "Expected a pointer type!"); + return TD ? TD->getPointerSizeInBits() : 0; +} /// ComputeMaskedBits - Determine which of the bits specified in Mask are /// known to be either zero or one and return them in the KnownZero/KnownOne @@ -46,7 +60,6 @@ using namespace llvm; void llvm::ComputeMaskedBits(Value *V, const APInt &Mask, APInt &KnownZero, APInt &KnownOne, const TargetData *TD, unsigned Depth) { - const unsigned MaxDepth = 6; assert(V && "No Value?"); assert(Depth <= MaxDepth && "Limit Search Depth"); unsigned BitWidth = Mask.getBitWidth(); @@ -69,14 +82,14 @@ void llvm::ComputeMaskedBits(Value *V, const APInt &Mask, // Null and aggregate-zero are all-zeros. if (isa(V) || isa(V)) { - KnownOne.clear(); + KnownOne.clearAllBits(); KnownZero = Mask; return; } // Handle a constant vector by taking the intersection of the known bits of // each element. if (ConstantVector *CV = dyn_cast(V)) { - KnownZero.set(); KnownOne.set(); + KnownZero.setAllBits(); KnownOne.setAllBits(); for (unsigned i = 0, e = CV->getNumOperands(); i != e; ++i) { APInt KnownZero2(BitWidth, 0), KnownOne2(BitWidth, 0); ComputeMaskedBits(CV->getOperand(i), Mask, KnownZero2, KnownOne2, @@ -103,15 +116,15 @@ void llvm::ComputeMaskedBits(Value *V, const APInt &Mask, KnownZero = Mask & APInt::getLowBitsSet(BitWidth, CountTrailingZeros_32(Align)); else - KnownZero.clear(); - KnownOne.clear(); + KnownZero.clearAllBits(); + KnownOne.clearAllBits(); return; } // A weak GlobalAlias is totally unknown. A non-weak GlobalAlias has // the bits of its aliasee. if (GlobalAlias *GA = dyn_cast(V)) { if (GA->mayBeOverridden()) { - KnownZero.clear(); KnownOne.clear(); + KnownZero.clearAllBits(); KnownOne.clearAllBits(); } else { ComputeMaskedBits(GA->getAliasee(), Mask, KnownZero, KnownOne, TD, Depth+1); @@ -119,7 +132,7 @@ void llvm::ComputeMaskedBits(Value *V, const APInt &Mask, return; } - KnownZero.clear(); KnownOne.clear(); // Start out not knowing anything. + KnownZero.clearAllBits(); KnownOne.clearAllBits(); // Start out not knowing anything. if (Depth == MaxDepth || Mask == 0) return; // Limit search depth. @@ -185,7 +198,7 @@ void llvm::ComputeMaskedBits(Value *V, const APInt &Mask, // Also compute a conserative estimate for high known-0 bits. // More trickiness is possible, but this is sufficient for the // interesting case of alignment computation. - KnownOne.clear(); + KnownOne.clearAllBits(); unsigned TrailZ = KnownZero.countTrailingOnes() + KnownZero2.countTrailingOnes(); unsigned LeadZ = std::max(KnownZero.countLeadingOnes() + @@ -208,8 +221,8 @@ void llvm::ComputeMaskedBits(Value *V, const APInt &Mask, AllOnes, KnownZero2, KnownOne2, TD, Depth+1); unsigned LeadZ = KnownZero2.countLeadingOnes(); - KnownOne2.clear(); - KnownZero2.clear(); + KnownOne2.clearAllBits(); + KnownZero2.clearAllBits(); ComputeMaskedBits(I->getOperand(1), AllOnes, KnownZero2, KnownOne2, TD, Depth+1); unsigned RHSUnknownLeadingOnes = KnownOne2.countLeadingZeros(); @@ -255,14 +268,13 @@ void llvm::ComputeMaskedBits(Value *V, const APInt &Mask, else SrcBitWidth = SrcTy->getScalarSizeInBits(); - APInt MaskIn(Mask); - MaskIn.zextOrTrunc(SrcBitWidth); - KnownZero.zextOrTrunc(SrcBitWidth); - KnownOne.zextOrTrunc(SrcBitWidth); + APInt MaskIn = Mask.zextOrTrunc(SrcBitWidth); + KnownZero = KnownZero.zextOrTrunc(SrcBitWidth); + KnownOne = KnownOne.zextOrTrunc(SrcBitWidth); ComputeMaskedBits(I->getOperand(0), MaskIn, KnownZero, KnownOne, TD, Depth+1); - KnownZero.zextOrTrunc(BitWidth); - KnownOne.zextOrTrunc(BitWidth); + KnownZero = KnownZero.zextOrTrunc(BitWidth); + KnownOne = KnownOne.zextOrTrunc(BitWidth); // Any top bits are known to be zero. if (BitWidth > SrcBitWidth) KnownZero |= APInt::getHighBitsSet(BitWidth, BitWidth - SrcBitWidth); @@ -284,15 +296,14 @@ void llvm::ComputeMaskedBits(Value *V, const APInt &Mask, // Compute the bits in the result that are not present in the input. unsigned SrcBitWidth = I->getOperand(0)->getType()->getScalarSizeInBits(); - APInt MaskIn(Mask); - MaskIn.trunc(SrcBitWidth); - KnownZero.trunc(SrcBitWidth); - KnownOne.trunc(SrcBitWidth); + APInt MaskIn = Mask.trunc(SrcBitWidth); + KnownZero = KnownZero.trunc(SrcBitWidth); + KnownOne = KnownOne.trunc(SrcBitWidth); ComputeMaskedBits(I->getOperand(0), MaskIn, KnownZero, KnownOne, TD, Depth+1); assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); - KnownZero.zext(BitWidth); - KnownOne.zext(BitWidth); + KnownZero = KnownZero.zext(BitWidth); + KnownOne = KnownOne.zext(BitWidth); // If the sign bit of the input is known set or clear, then we know the // top bits of the result. @@ -338,7 +349,7 @@ void llvm::ComputeMaskedBits(Value *V, const APInt &Mask, // (ashr X, C1) & C2 == 0 iff (-1 >> C1) & C2 == 0 if (ConstantInt *SA = dyn_cast(I->getOperand(1))) { // Compute the new bits that are at the top now. - uint64_t ShiftAmt = SA->getLimitedValue(BitWidth); + uint64_t ShiftAmt = SA->getLimitedValue(BitWidth-1); // Signed shift right. APInt Mask2(Mask.shl(ShiftAmt)); @@ -474,7 +485,7 @@ void llvm::ComputeMaskedBits(Value *V, const APInt &Mask, unsigned Leaders = std::max(KnownZero.countLeadingOnes(), KnownZero2.countLeadingOnes()); - KnownOne.clear(); + KnownOne.clearAllBits(); KnownZero = APInt::getHighBitsSet(BitWidth, Leaders) & Mask; break; } @@ -579,6 +590,10 @@ void llvm::ComputeMaskedBits(Value *V, const APInt &Mask, } } + // Unreachable blocks may have zero-operand PHI nodes. + if (P->getNumIncomingValues() == 0) + return; + // Otherwise take the unions of the known bit sets of the operands, // taking conservative care to avoid excessive recursion. if (Depth < MaxDepth - 1 && !KnownZero && !KnownOne) { @@ -621,6 +636,156 @@ void llvm::ComputeMaskedBits(Value *V, const APInt &Mask, } } +/// ComputeSignBit - Determine whether the sign bit is known to be zero or +/// one. Convenience wrapper around ComputeMaskedBits. +void llvm::ComputeSignBit(Value *V, bool &KnownZero, bool &KnownOne, + const TargetData *TD, unsigned Depth) { + unsigned BitWidth = getBitWidth(V->getType(), TD); + if (!BitWidth) { + KnownZero = false; + KnownOne = false; + return; + } + APInt ZeroBits(BitWidth, 0); + APInt OneBits(BitWidth, 0); + ComputeMaskedBits(V, APInt::getSignBit(BitWidth), ZeroBits, OneBits, TD, + Depth); + KnownOne = OneBits[BitWidth - 1]; + KnownZero = ZeroBits[BitWidth - 1]; +} + +/// isPowerOfTwo - Return true if the given value is known to have exactly one +/// bit set when defined. For vectors return true if every element is known to +/// be a power of two when defined. Supports values with integer or pointer +/// types and vectors of integers. +bool llvm::isPowerOfTwo(Value *V, const TargetData *TD, unsigned Depth) { + if (ConstantInt *CI = dyn_cast(V)) + return CI->getValue().isPowerOf2(); + // TODO: Handle vector constants. + + // 1 << X is clearly a power of two if the one is not shifted off the end. If + // it is shifted off the end then the result is undefined. + if (match(V, m_Shl(m_One(), m_Value()))) + return true; + + // (signbit) >>l X is clearly a power of two if the one is not shifted off the + // bottom. If it is shifted off the bottom then the result is undefined. + if (match(V, m_LShr(m_SignBit(), m_Value()))) + return true; + + // The remaining tests are all recursive, so bail out if we hit the limit. + if (Depth++ == MaxDepth) + return false; + + if (ZExtInst *ZI = dyn_cast(V)) + return isPowerOfTwo(ZI->getOperand(0), TD, Depth); + + if (SelectInst *SI = dyn_cast(V)) + return isPowerOfTwo(SI->getTrueValue(), TD, Depth) && + isPowerOfTwo(SI->getFalseValue(), TD, Depth); + + return false; +} + +/// isKnownNonZero - Return true if the given value is known to be non-zero +/// when defined. For vectors return true if every element is known to be +/// non-zero when defined. Supports values with integer or pointer type and +/// vectors of integers. +bool llvm::isKnownNonZero(Value *V, const TargetData *TD, unsigned Depth) { + if (Constant *C = dyn_cast(V)) { + if (C->isNullValue()) + return false; + if (isa(C)) + // Must be non-zero due to null test above. + return true; + // TODO: Handle vectors + return false; + } + + // The remaining tests are all recursive, so bail out if we hit the limit. + if (Depth++ == MaxDepth) + return false; + + unsigned BitWidth = getBitWidth(V->getType(), TD); + + // X | Y != 0 if X != 0 or Y != 0. + Value *X = 0, *Y = 0; + if (match(V, m_Or(m_Value(X), m_Value(Y)))) + return isKnownNonZero(X, TD, Depth) || isKnownNonZero(Y, TD, Depth); + + // ext X != 0 if X != 0. + if (isa(V) || isa(V)) + return isKnownNonZero(cast(V)->getOperand(0), TD, Depth); + + // shl X, Y != 0 if X is odd. Note that the value of the shift is undefined + // if the lowest bit is shifted off the end. + if (BitWidth && match(V, m_Shl(m_Value(X), m_Value(Y)))) { + APInt KnownZero(BitWidth, 0); + APInt KnownOne(BitWidth, 0); + ComputeMaskedBits(X, APInt(BitWidth, 1), KnownZero, KnownOne, TD, Depth); + if (KnownOne[0]) + return true; + } + // shr X, Y != 0 if X is negative. Note that the value of the shift is not + // defined if the sign bit is shifted off the end. + else if (match(V, m_Shr(m_Value(X), m_Value(Y)))) { + bool XKnownNonNegative, XKnownNegative; + ComputeSignBit(X, XKnownNonNegative, XKnownNegative, TD, Depth); + if (XKnownNegative) + return true; + } + // X + Y. + else if (match(V, m_Add(m_Value(X), m_Value(Y)))) { + bool XKnownNonNegative, XKnownNegative; + bool YKnownNonNegative, YKnownNegative; + ComputeSignBit(X, XKnownNonNegative, XKnownNegative, TD, Depth); + ComputeSignBit(Y, YKnownNonNegative, YKnownNegative, TD, Depth); + + // If X and Y are both non-negative (as signed values) then their sum is not + // zero unless both X and Y are zero. + if (XKnownNonNegative && YKnownNonNegative) + if (isKnownNonZero(X, TD, Depth) || isKnownNonZero(Y, TD, Depth)) + return true; + + // If X and Y are both negative (as signed values) then their sum is not + // zero unless both X and Y equal INT_MIN. + if (BitWidth && XKnownNegative && YKnownNegative) { + APInt KnownZero(BitWidth, 0); + APInt KnownOne(BitWidth, 0); + APInt Mask = APInt::getSignedMaxValue(BitWidth); + // The sign bit of X is set. If some other bit is set then X is not equal + // to INT_MIN. + ComputeMaskedBits(X, Mask, KnownZero, KnownOne, TD, Depth); + if ((KnownOne & Mask) != 0) + return true; + // The sign bit of Y is set. If some other bit is set then Y is not equal + // to INT_MIN. + ComputeMaskedBits(Y, Mask, KnownZero, KnownOne, TD, Depth); + if ((KnownOne & Mask) != 0) + return true; + } + + // The sum of a non-negative number and a power of two is not zero. + if (XKnownNonNegative && isPowerOfTwo(Y, TD, Depth)) + return true; + if (YKnownNonNegative && isPowerOfTwo(X, TD, Depth)) + return true; + } + // (C ? X : Y) != 0 if X != 0 and Y != 0. + else if (SelectInst *SI = dyn_cast(V)) { + if (isKnownNonZero(SI->getTrueValue(), TD, Depth) && + isKnownNonZero(SI->getFalseValue(), TD, Depth)) + return true; + } + + if (!BitWidth) return false; + APInt KnownZero(BitWidth, 0); + APInt KnownOne(BitWidth, 0); + ComputeMaskedBits(V, APInt::getAllOnesValue(BitWidth), KnownZero, KnownOne, + TD, Depth); + return KnownOne != 0; +} + /// MaskedValueIsZero - Return true if 'V & Mask' is known to be zero. We use /// this predicate to simplify operations downstream. Mask is known to be zero /// for bits that V cannot have. @@ -679,6 +844,13 @@ unsigned llvm::ComputeNumSignBits(Value *V, const TargetData *TD, Tmp += C->getZExtValue(); if (Tmp > TyBits) Tmp = TyBits; } + // vector ashr X, -> adds C sign bits + if (ConstantVector *C = dyn_cast(U->getOperand(1))) { + if (ConstantInt *CI = dyn_cast_or_null(C->getSplatValue())) { + Tmp += CI->getZExtValue(); + if (Tmp > TyBits) Tmp = TyBits; + } + } return Tmp; case Instruction::Shl: if (ConstantInt *C = dyn_cast(U->getOperand(1))) { @@ -875,8 +1047,9 @@ bool llvm::ComputeMultiple(Value *V, unsigned Base, Value *&Multiple, // Turn Op0 << Op1 into Op0 * 2^Op1 APInt Op1Int = Op1CI->getValue(); uint64_t BitToSet = Op1Int.getLimitedValue(Op1Int.getBitWidth() - 1); - Op1 = ConstantInt::get(V->getContext(), - APInt(Op1Int.getBitWidth(), 0).set(BitToSet)); + APInt API(Op1Int.getBitWidth(), 0); + API.setBit(BitToSet); + Op1 = ConstantInt::get(V->getContext(), API); } Value *Mul0 = NULL; @@ -982,6 +1155,80 @@ bool llvm::CannotBeNegativeZero(const Value *V, unsigned Depth) { return false; } +/// isBytewiseValue - If the specified value can be set by repeating the same +/// byte in memory, return the i8 value that it is represented with. This is +/// true for all i8 values obviously, but is also true for i32 0, i32 -1, +/// i16 0xF0F0, double 0.0 etc. If the value can't be handled with a repeated +/// byte store (e.g. i16 0x1234), return null. +Value *llvm::isBytewiseValue(Value *V) { + // All byte-wide stores are splatable, even of arbitrary variables. + if (V->getType()->isIntegerTy(8)) return V; + + // Handle 'null' ConstantArrayZero etc. + if (Constant *C = dyn_cast(V)) + if (C->isNullValue()) + return Constant::getNullValue(Type::getInt8Ty(V->getContext())); + + // Constant float and double values can be handled as integer values if the + // corresponding integer value is "byteable". An important case is 0.0. + if (ConstantFP *CFP = dyn_cast(V)) { + if (CFP->getType()->isFloatTy()) + V = ConstantExpr::getBitCast(CFP, Type::getInt32Ty(V->getContext())); + if (CFP->getType()->isDoubleTy()) + V = ConstantExpr::getBitCast(CFP, Type::getInt64Ty(V->getContext())); + // Don't handle long double formats, which have strange constraints. + } + + // We can handle constant integers that are power of two in size and a + // multiple of 8 bits. + if (ConstantInt *CI = dyn_cast(V)) { + unsigned Width = CI->getBitWidth(); + if (isPowerOf2_32(Width) && Width > 8) { + // We can handle this value if the recursive binary decomposition is the + // same at all levels. + APInt Val = CI->getValue(); + APInt Val2; + while (Val.getBitWidth() != 8) { + unsigned NextWidth = Val.getBitWidth()/2; + Val2 = Val.lshr(NextWidth); + Val2 = Val2.trunc(Val.getBitWidth()/2); + Val = Val.trunc(Val.getBitWidth()/2); + + // If the top/bottom halves aren't the same, reject it. + if (Val != Val2) + return 0; + } + return ConstantInt::get(V->getContext(), Val); + } + } + + // A ConstantArray is splatable if all its members are equal and also + // splatable. + if (ConstantArray *CA = dyn_cast(V)) { + if (CA->getNumOperands() == 0) + return 0; + + Value *Val = isBytewiseValue(CA->getOperand(0)); + if (!Val) + return 0; + + for (unsigned I = 1, E = CA->getNumOperands(); I != E; ++I) + if (CA->getOperand(I-1) != CA->getOperand(I)) + return 0; + + return Val; + } + + // Conceptually, we could handle things like: + // %a = zext i8 %X to i16 + // %b = shl i16 %a, 8 + // %c = or i16 %a, %b + // but until there is an example that actually needs this, it doesn't seem + // worth worrying about. + return 0; +} + + // This is the recursive version of BuildSubAggregate. It takes a few different // arguments. Idxs is the index within the nested struct From that we are // looking at now (which is of type IndexedType). IdxSkip is the number of @@ -1159,6 +1406,47 @@ Value *llvm::FindInsertedValue(Value *V, const unsigned *idx_begin, return 0; } +/// GetPointerBaseWithConstantOffset - Analyze the specified pointer to see if +/// it can be expressed as a base pointer plus a constant offset. Return the +/// base and offset to the caller. +Value *llvm::GetPointerBaseWithConstantOffset(Value *Ptr, int64_t &Offset, + const TargetData &TD) { + Operator *PtrOp = dyn_cast(Ptr); + if (PtrOp == 0) return Ptr; + + // Just look through bitcasts. + if (PtrOp->getOpcode() == Instruction::BitCast) + return GetPointerBaseWithConstantOffset(PtrOp->getOperand(0), Offset, TD); + + // If this is a GEP with constant indices, we can look through it. + GEPOperator *GEP = dyn_cast(PtrOp); + if (GEP == 0 || !GEP->hasAllConstantIndices()) return Ptr; + + gep_type_iterator GTI = gep_type_begin(GEP); + for (User::op_iterator I = GEP->idx_begin(), E = GEP->idx_end(); I != E; + ++I, ++GTI) { + ConstantInt *OpC = cast(*I); + if (OpC->isZero()) continue; + + // Handle a struct and array indices which add their offset to the pointer. + if (const StructType *STy = dyn_cast(*GTI)) { + Offset += TD.getStructLayout(STy)->getElementOffset(OpC->getZExtValue()); + } else { + uint64_t Size = TD.getTypeAllocSize(GTI.getIndexedType()); + Offset += OpC->getSExtValue()*Size; + } + } + + // Re-sign extend from the pointer size if needed to get overflow edge cases + // right. + unsigned PtrSize = TD.getPointerSizeInBits(); + if (PtrSize < 64) + Offset = (Offset << (64-PtrSize)) >> (64-PtrSize); + + return GetPointerBaseWithConstantOffset(GEP->getPointerOperand(), Offset, TD); +} + + /// GetConstantStringInfo - This function computes the length of a /// null-terminated C string pointed to by V. If successful, it returns true /// and returns the string in Str. If unsuccessful, it returns false. @@ -1386,3 +1674,32 @@ uint64_t llvm::GetStringLength(Value *V) { // an empty string as a length. return Len == ~0ULL ? 1 : Len; } + +Value * +llvm::GetUnderlyingObject(Value *V, const TargetData *TD, unsigned MaxLookup) { + if (!V->getType()->isPointerTy()) + return V; + for (unsigned Count = 0; MaxLookup == 0 || Count < MaxLookup; ++Count) { + if (GEPOperator *GEP = dyn_cast(V)) { + V = GEP->getPointerOperand(); + } else if (Operator::getOpcode(V) == Instruction::BitCast) { + V = cast(V)->getOperand(0); + } else if (GlobalAlias *GA = dyn_cast(V)) { + if (GA->mayBeOverridden()) + return V; + V = GA->getAliasee(); + } else { + // See if InstructionSimplify knows any relevant tricks. + if (Instruction *I = dyn_cast(V)) + // TODO: Aquire a DominatorTree and use it. + if (Value *Simplified = SimplifyInstruction(I, TD, 0)) { + V = Simplified; + continue; + } + + return V; + } + assert(V->getType()->isPointerTy() && "Unexpected operand type!"); + } + return V; +} diff --git a/lib/Archive/Archive.cpp b/lib/Archive/Archive.cpp index 54c715c604d2..1eab27d3eba3 100644 --- a/lib/Archive/Archive.cpp +++ b/lib/Archive/Archive.cpp @@ -15,8 +15,10 @@ #include "ArchiveInternals.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/Module.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/System/Process.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/system_error.h" #include #include using namespace llvm; @@ -65,8 +67,9 @@ ArchiveMember::ArchiveMember(Archive* PAR) // different file, presumably as an update to the member. It also makes sure // the flags are reset correctly. bool ArchiveMember::replaceWith(const sys::Path& newFile, std::string* ErrMsg) { - if (!newFile.exists()) { - if (ErrMsg) + bool Exists; + if (sys::fs::exists(newFile.str(), Exists) || !Exists) { + if (ErrMsg) *ErrMsg = "Can not replace an archive member with a non-existent file"; return true; } @@ -113,11 +116,10 @@ bool ArchiveMember::replaceWith(const sys::Path& newFile, std::string* ErrMsg) { // Get the signature and status info const char* signature = (const char*) data; - std::string magic; + SmallString<4> magic; if (!signature) { - path.getMagicNumber(magic,4); + sys::fs::get_magic(path.str(), magic.capacity(), magic); signature = magic.c_str(); - std::string err; const sys::FileStatus *FSinfo = path.getFileStatus(false, ErrMsg); if (FSinfo) info = *FSinfo; @@ -147,9 +149,13 @@ Archive::Archive(const sys::Path& filename, LLVMContext& C) bool Archive::mapToMemory(std::string* ErrMsg) { - mapfile = MemoryBuffer::getFile(archPath.c_str(), ErrMsg); - if (mapfile == 0) + OwningPtr File; + if (error_code ec = MemoryBuffer::getFile(archPath.c_str(), File)) { + if (ErrMsg) + *ErrMsg = ec.message(); return true; + } + mapfile = File.take(); base = mapfile->getBufferStart(); return false; } @@ -159,19 +165,19 @@ void Archive::cleanUpMemory() { delete mapfile; mapfile = 0; base = 0; - + // Forget the entire symbol table symTab.clear(); symTabSize = 0; - + firstFileOffset = 0; - + // Free the foreign symbol table member if (foreignST) { delete foreignST; foreignST = 0; } - + // Delete any Modules and ArchiveMember's we've allocated as a result of // symbol table searches. for (ModuleMap::iterator I=modules.begin(), E=modules.end(); I != E; ++I ) { @@ -193,7 +199,7 @@ static void getSymbols(Module*M, std::vector& symbols) { if (!GI->isDeclaration() && !GI->hasLocalLinkage()) if (!GI->getName().empty()) symbols.push_back(GI->getName()); - + // Loop over functions for (Module::iterator FI = M->begin(), FE = M->end(); FI != FE; ++FI) if (!FI->isDeclaration() && !FI->hasLocalLinkage()) @@ -213,20 +219,20 @@ bool llvm::GetBitcodeSymbols(const sys::Path& fName, LLVMContext& Context, std::vector& symbols, std::string* ErrMsg) { - std::auto_ptr Buffer( - MemoryBuffer::getFileOrSTDIN(fName.c_str())); - if (!Buffer.get()) { - if (ErrMsg) *ErrMsg = "Could not open file '" + fName.str() + "'"; + OwningPtr Buffer; + if (error_code ec = MemoryBuffer::getFileOrSTDIN(fName.c_str(), Buffer)) { + if (ErrMsg) *ErrMsg = "Could not open file '" + fName.str() + "'" + ": " + + ec.message(); return true; } - + Module *M = ParseBitcodeFile(Buffer.get(), Context, ErrMsg); if (!M) return true; - + // Get the symbols getSymbols(M, symbols); - + // Done with the module. delete M; return true; @@ -239,16 +245,16 @@ llvm::GetBitcodeSymbols(const char *BufPtr, unsigned Length, std::vector& symbols, std::string* ErrMsg) { // Get the module. - std::auto_ptr Buffer( + OwningPtr Buffer( MemoryBuffer::getMemBufferCopy(StringRef(BufPtr, Length),ModuleID.c_str())); - + Module *M = ParseBitcodeFile(Buffer.get(), Context, ErrMsg); if (!M) return 0; - + // Get the symbols getSymbols(M, symbols); - + // Done with the module. Note that it's the caller's responsibility to delete // the Module. return M; diff --git a/lib/Archive/ArchiveInternals.h b/lib/Archive/ArchiveInternals.h index 08f20e74811e..55684f7023d2 100644 --- a/lib/Archive/ArchiveInternals.h +++ b/lib/Archive/ArchiveInternals.h @@ -15,7 +15,7 @@ #define LIB_ARCHIVE_ARCHIVEINTERNALS_H #include "llvm/Bitcode/Archive.h" -#include "llvm/System/TimeValue.h" +#include "llvm/Support/TimeValue.h" #include "llvm/ADT/StringExtras.h" #include diff --git a/lib/Archive/ArchiveWriter.cpp b/lib/Archive/ArchiveWriter.cpp index 7eeeb59896d3..c5ad5fc41cd1 100644 --- a/lib/Archive/ArchiveWriter.cpp +++ b/lib/Archive/ArchiveWriter.cpp @@ -15,9 +15,12 @@ #include "llvm/Module.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/System/Process.h" -#include "llvm/System/Signals.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/system_error.h" #include #include #include @@ -25,7 +28,7 @@ using namespace llvm; // Write an integer using variable bit rate encoding. This saves a few bytes // per entry in the symbol table. -static inline void writeInteger(unsigned num, std::ofstream& ARFile) { +static inline void writeInteger(unsigned num, raw_ostream& ARFile) { while (1) { if (num < 0x80) { // done? ARFile << (unsigned char)num; @@ -153,9 +156,10 @@ Archive::fillHeader(const ArchiveMember &mbr, ArchiveMemberHeader& hdr, // Insert a file into the archive before some other member. This also takes care // of extracting the necessary flags and information from the file. bool -Archive::addFileBefore(const sys::Path& filePath, iterator where, +Archive::addFileBefore(const sys::Path& filePath, iterator where, std::string* ErrMsg) { - if (!filePath.exists()) { + bool Exists; + if (sys::fs::exists(filePath.str(), Exists) || !Exists) { if (ErrMsg) *ErrMsg = "Can not add a non-existent file to archive"; return true; @@ -178,9 +182,11 @@ Archive::addFileBefore(const sys::Path& filePath, iterator where, flags |= ArchiveMember::HasPathFlag; if (hasSlash || filePath.str().length() > 15) flags |= ArchiveMember::HasLongFilenameFlag; - std::string magic; - mbr->path.getMagicNumber(magic,4); - switch (sys::IdentifyFileType(magic.c_str(),4)) { + + sys::LLVMFileType type; + if (sys::fs::identify_magic(mbr->path.str(), type)) + type = sys::Unknown_FileType; + switch (type) { case sys::Bitcode_FileType: flags |= ArchiveMember::BitcodeFlag; break; @@ -196,14 +202,14 @@ Archive::addFileBefore(const sys::Path& filePath, iterator where, bool Archive::writeMember( const ArchiveMember& member, - std::ofstream& ARFile, + raw_ostream& ARFile, bool CreateSymbolTable, bool TruncateNames, bool ShouldCompress, std::string* ErrMsg ) { - unsigned filepos = ARFile.tellp(); + unsigned filepos = ARFile.tell(); filepos -= 8; // Get the data and its size either from the @@ -212,9 +218,13 @@ Archive::writeMember( const char *data = (const char*)member.getData(); MemoryBuffer *mFile = 0; if (!data) { - mFile = MemoryBuffer::getFile(member.getPath().c_str(), ErrMsg); - if (mFile == 0) + OwningPtr File; + if (error_code ec = MemoryBuffer::getFile(member.getPath().c_str(), File)) { + if (ErrMsg) + *ErrMsg = ec.message(); return true; + } + mFile = File.take(); data = mFile->getBufferStart(); fSize = mFile->getBufferSize(); } @@ -225,7 +235,7 @@ Archive::writeMember( std::vector symbols; std::string FullMemberName = archPath.str() + "(" + member.getPath().str() + ")"; - Module* M = + Module* M = GetBitcodeSymbols(data, fSize, FullMemberName, Context, symbols, ErrMsg); // If the bitcode parsed successfully @@ -272,7 +282,7 @@ Archive::writeMember( ARFile.write(data,fSize); // Make sure the member is an even length - if ((ARFile.tellp() & 1) == 1) + if ((ARFile.tell() & 1) == 1) ARFile << ARFILE_PAD; // Close the mapped file if it was opened @@ -282,7 +292,7 @@ Archive::writeMember( // Write out the LLVM symbol table as an archive member to the file. void -Archive::writeSymbolTable(std::ofstream& ARFile) { +Archive::writeSymbolTable(raw_ostream& ARFile) { // Construct the symbol table's header ArchiveMemberHeader Hdr; @@ -306,7 +316,7 @@ Archive::writeSymbolTable(std::ofstream& ARFile) { #ifndef NDEBUG // Save the starting position of the symbol tables data content. - unsigned startpos = ARFile.tellp(); + unsigned startpos = ARFile.tell(); #endif // Write out the symbols sequentially @@ -323,7 +333,7 @@ Archive::writeSymbolTable(std::ofstream& ARFile) { #ifndef NDEBUG // Now that we're done with the symbol table, get the ending file position - unsigned endpos = ARFile.tellp(); + unsigned endpos = ARFile.tell(); #endif // Make sure that the amount we wrote is what we pre-computed. This is @@ -352,25 +362,20 @@ Archive::writeToDisk(bool CreateSymbolTable, bool TruncateNames, bool Compress, } // Create a temporary file to store the archive in - sys::Path TmpArchive = archPath; - if (TmpArchive.createTemporaryFileOnDisk(ErrMsg)) + SmallString<128> TempArchivePath; + int ArchFD; + if (error_code ec = + sys::fs::unique_file("%%-%%-%%-%%-" + sys::path::filename(archPath.str()), + ArchFD, TempArchivePath)) { + if (ErrMsg) *ErrMsg = ec.message(); return true; + } // Make sure the temporary gets removed if we crash - sys::RemoveFileOnSignal(TmpArchive); + sys::RemoveFileOnSignal(sys::Path(TempArchivePath.str())); // Create archive file for output. - std::ios::openmode io_mode = std::ios::out | std::ios::trunc | - std::ios::binary; - std::ofstream ArchiveFile(TmpArchive.c_str(), io_mode); - - // Check for errors opening or creating archive file. - if (!ArchiveFile.is_open() || ArchiveFile.bad()) { - TmpArchive.eraseFromDisk(); - if (ErrMsg) - *ErrMsg = "Error opening archive file: " + archPath.str(); - return true; - } + raw_fd_ostream ArchiveFile(ArchFD, true); // If we're creating a symbol table, reset it now if (CreateSymbolTable) { @@ -386,8 +391,9 @@ Archive::writeToDisk(bool CreateSymbolTable, bool TruncateNames, bool Compress, for (MembersList::iterator I = begin(), E = end(); I != E; ++I) { if (writeMember(*I, ArchiveFile, CreateSymbolTable, TruncateNames, Compress, ErrMsg)) { - TmpArchive.eraseFromDisk(); ArchiveFile.close(); + bool existed; + sys::fs::remove(TempArchivePath.str(), existed); return true; } } @@ -402,27 +408,29 @@ Archive::writeToDisk(bool CreateSymbolTable, bool TruncateNames, bool Compress, // ensure compatibility with other archivers we need to put the symbol // table first in the file. Unfortunately, this means mapping the file // we just wrote back in and copying it to the destination file. - sys::Path FinalFilePath = archPath; + SmallString<128> TempArchiveWithSymbolTablePath; // Map in the archive we just wrote. { - OwningPtr arch(MemoryBuffer::getFile(TmpArchive.c_str())); - if (arch == 0) return true; + OwningPtr arch; + if (error_code ec = MemoryBuffer::getFile(TempArchivePath.c_str(), arch)) { + if (ErrMsg) + *ErrMsg = ec.message(); + return true; + } const char* base = arch->getBufferStart(); - // Open another temporary file in order to avoid invalidating the + // Open another temporary file in order to avoid invalidating the // mmapped data - if (FinalFilePath.createTemporaryFileOnDisk(ErrMsg)) - return true; - sys::RemoveFileOnSignal(FinalFilePath); - - std::ofstream FinalFile(FinalFilePath.c_str(), io_mode); - if (!FinalFile.is_open() || FinalFile.bad()) { - TmpArchive.eraseFromDisk(); - if (ErrMsg) - *ErrMsg = "Error opening archive file: " + FinalFilePath.str(); + if (error_code ec = + sys::fs::unique_file("%%-%%-%%-%%-" + sys::path::filename(archPath.str()), + ArchFD, TempArchiveWithSymbolTablePath)) { + if (ErrMsg) *ErrMsg = ec.message(); return true; } + sys::RemoveFileOnSignal(sys::Path(TempArchiveWithSymbolTablePath.str())); + + raw_fd_ostream FinalFile(ArchFD, true); // Write the file magic number FinalFile << ARFILE_MAGIC; @@ -435,7 +443,8 @@ Archive::writeToDisk(bool CreateSymbolTable, bool TruncateNames, bool Compress, if (foreignST) { if (writeMember(*foreignST, FinalFile, false, false, false, ErrMsg)) { FinalFile.close(); - TmpArchive.eraseFromDisk(); + bool existed; + sys::fs::remove(TempArchiveWithSymbolTablePath.str(), existed); return true; } } @@ -451,19 +460,25 @@ Archive::writeToDisk(bool CreateSymbolTable, bool TruncateNames, bool Compress, // Close up shop FinalFile.close(); } // free arch. - + // Move the final file over top of TmpArchive - if (FinalFilePath.renamePathOnDisk(TmpArchive, ErrMsg)) + if (error_code ec = sys::fs::rename(TempArchiveWithSymbolTablePath.str(), + TempArchivePath.str())) { + if (ErrMsg) *ErrMsg = ec.message(); return true; + } } - + // Before we replace the actual archive, we need to forget all the // members, since they point to data in that old archive. We need to do // this because we cannot replace an open file on Windows. cleanUpMemory(); - - if (TmpArchive.renamePathOnDisk(archPath, ErrMsg)) + + if (error_code ec = sys::fs::rename(TempArchivePath.str(), + archPath.str())) { + if (ErrMsg) *ErrMsg = ec.message(); return true; + } // Set correct read and write permissions after temporary file is moved // to final destination path. diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp index 032753a3b2c6..857fa1ef626f 100644 --- a/lib/AsmParser/LLLexer.cpp +++ b/lib/AsmParser/LLLexer.cpp @@ -15,18 +15,20 @@ #include "llvm/DerivedTypes.h" #include "llvm/Instruction.h" #include "llvm/LLVMContext.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Assembly/Parser.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Assembly/Parser.h" +#include #include #include #include using namespace llvm; -bool LLLexer::Error(LocTy ErrorLoc, const std::string &Msg) const { +bool LLLexer::Error(LocTy ErrorLoc, const Twine &Msg) const { ErrorInfo = SM.GetMessage(ErrorLoc, Msg, "error"); return true; } @@ -507,6 +509,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(default); KEYWORD(hidden); KEYWORD(protected); + KEYWORD(unnamed_addr); KEYWORD(extern_weak); KEYWORD(external); KEYWORD(thread_local); @@ -544,6 +547,8 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(arm_aapcscc); KEYWORD(arm_aapcs_vfpcc); KEYWORD(msp430_intrcc); + KEYWORD(ptx_kernel); + KEYWORD(ptx_device); KEYWORD(cc); KEYWORD(c); @@ -570,6 +575,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(noredzone); KEYWORD(noimplicitfloat); KEYWORD(naked); + KEYWORD(hotpatch); KEYWORD(type); KEYWORD(opaque); @@ -595,6 +601,7 @@ lltok::Kind LLLexer::LexIdentifier() { TYPEKEYWORD("ppc_fp128", Type::getPPC_FP128Ty(Context)); TYPEKEYWORD("label", Type::getLabelTy(Context)); TYPEKEYWORD("metadata", Type::getMetadataTy(Context)); + TYPEKEYWORD("x86_mmx", Type::getX86_MMXTy(Context)); #undef TYPEKEYWORD // Handle special forms for autoupgrading. Drop these in LLVM 3.0. This is @@ -677,7 +684,7 @@ lltok::Kind LLLexer::LexIdentifier() { APInt Tmp(bits, StringRef(TokStart+3, len), 16); uint32_t activeBits = Tmp.getActiveBits(); if (activeBits > 0 && activeBits < bits) - Tmp.trunc(activeBits); + Tmp = Tmp.trunc(activeBits); APSIntVal = APSInt(Tmp, TokStart[0] == 'u'); return lltok::APSInt; } @@ -804,12 +811,12 @@ lltok::Kind LLLexer::LexDigitOrNegative() { if (TokStart[0] == '-') { uint32_t minBits = Tmp.getMinSignedBits(); if (minBits > 0 && minBits < numBits) - Tmp.trunc(minBits); + Tmp = Tmp.trunc(minBits); APSIntVal = APSInt(Tmp, false); } else { uint32_t activeBits = Tmp.getActiveBits(); if (activeBits > 0 && activeBits < numBits) - Tmp.trunc(activeBits); + Tmp = Tmp.trunc(activeBits); APSIntVal = APSInt(Tmp, true); } return lltok::APSInt; @@ -828,7 +835,7 @@ lltok::Kind LLLexer::LexDigitOrNegative() { } } - APFloatVal = APFloat(atof(TokStart)); + APFloatVal = APFloat(std::atof(TokStart)); return lltok::APFloat; } @@ -862,6 +869,6 @@ lltok::Kind LLLexer::LexPositive() { } } - APFloatVal = APFloat(atof(TokStart)); + APFloatVal = APFloat(std::atof(TokStart)); return lltok::APFloat; } diff --git a/lib/AsmParser/LLLexer.h b/lib/AsmParser/LLLexer.h index 70f1cfdbfd8c..09ae8017f404 100644 --- a/lib/AsmParser/LLLexer.h +++ b/lib/AsmParser/LLLexer.h @@ -62,8 +62,8 @@ namespace llvm { const APFloat &getAPFloatVal() const { return APFloatVal; } - bool Error(LocTy L, const std::string &Msg) const; - bool Error(const std::string &Msg) const { return Error(getLoc(), Msg); } + bool Error(LocTy L, const Twine &Msg) const; + bool Error(const Twine &Msg) const { return Error(getLoc(), Msg); } std::string getFilename() const; private: diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index f21a065473b6..cdfacbebbfc3 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -22,7 +22,6 @@ #include "llvm/Operator.h" #include "llvm/ValueSymbolTable.h" #include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -52,7 +51,7 @@ bool LLParser::ValidateEndOfModule() { if (SlotNo >= NumberedMetadata.size() || NumberedMetadata[SlotNo] == 0) return Error(MDList[i].Loc, "use of undefined metadata '!" + - utostr(SlotNo) + "'"); + Twine(SlotNo) + "'"); Inst->setMetadata(MDList[i].MDKind, NumberedMetadata[SlotNo]); } } @@ -109,7 +108,7 @@ bool LLParser::ValidateEndOfModule() { if (!ForwardRefTypeIDs.empty()) return Error(ForwardRefTypeIDs.begin()->second.second, "use of undefined type '%" + - utostr(ForwardRefTypeIDs.begin()->first) + "'"); + Twine(ForwardRefTypeIDs.begin()->first) + "'"); if (!ForwardRefVals.empty()) return Error(ForwardRefVals.begin()->second.second, @@ -119,12 +118,12 @@ bool LLParser::ValidateEndOfModule() { if (!ForwardRefValIDs.empty()) return Error(ForwardRefValIDs.begin()->second.second, "use of undefined value '@" + - utostr(ForwardRefValIDs.begin()->first) + "'"); + Twine(ForwardRefValIDs.begin()->first) + "'"); if (!ForwardRefMDNodes.empty()) return Error(ForwardRefMDNodes.begin()->second.second, "use of undefined metadata '!" + - utostr(ForwardRefMDNodes.begin()->first) + "'"); + Twine(ForwardRefMDNodes.begin()->first) + "'"); // Look for intrinsic functions and CallInst that need to be upgraded @@ -195,7 +194,8 @@ bool LLParser::ParseTopLevelEntities() { // The Global variable production with no name can have many different // optional leading prefixes, the production is: // GlobalVar ::= OptionalLinkage OptionalVisibility OptionalThreadLocal - // OptionalAddrSpace ('constant'|'global') ... + // OptionalAddrSpace OptionalUnNammedAddr + // ('constant'|'global') ... case lltok::kw_private: // OptionalLinkage case lltok::kw_linker_private: // OptionalLinkage case lltok::kw_linker_private_weak: // OptionalLinkage @@ -317,7 +317,7 @@ bool LLParser::ParseUnnamedType() { if (Lex.getKind() == lltok::LocalVarID) { if (Lex.getUIntVal() != TypeID) return Error(Lex.getLoc(), "type expected to be numbered '%" + - utostr(TypeID) + "'"); + Twine(TypeID) + "'"); Lex.Lex(); // eat LocalVarID; if (ParseToken(lltok::equal, "expected '=' after name")) @@ -444,7 +444,7 @@ bool LLParser::ParseUnnamedGlobal() { if (Lex.getKind() == lltok::GlobalID) { if (Lex.getUIntVal() != VarID) return Error(Lex.getLoc(), "variable expected to be numbered '%" + - utostr(VarID) + "'"); + Twine(VarID) + "'"); Lex.Lex(); // eat GlobalID; if (ParseToken(lltok::equal, "expected '=' after name")) @@ -676,16 +676,16 @@ bool LLParser::ParseAlias(const std::string &Name, LocTy NameLoc, // Insert into the module, we know its name won't collide now. M->getAliasList().push_back(GA); - assert(GA->getNameStr() == Name && "Should not be a name conflict!"); + assert(GA->getName() == Name && "Should not be a name conflict!"); return false; } /// ParseGlobal /// ::= GlobalVar '=' OptionalLinkage OptionalVisibility OptionalThreadLocal -/// OptionalAddrSpace GlobalType Type Const +/// OptionalAddrSpace OptionalUnNammedAddr GlobalType Type Const /// ::= OptionalLinkage OptionalVisibility OptionalThreadLocal -/// OptionalAddrSpace GlobalType Type Const +/// OptionalAddrSpace OptionalUnNammedAddr GlobalType Type Const /// /// Everything through visibility has been parsed already. /// @@ -693,12 +693,15 @@ bool LLParser::ParseGlobal(const std::string &Name, LocTy NameLoc, unsigned Linkage, bool HasLinkage, unsigned Visibility) { unsigned AddrSpace; - bool ThreadLocal, IsConstant; + bool ThreadLocal, IsConstant, UnnamedAddr; + LocTy UnnamedAddrLoc; LocTy TyLoc; PATypeHolder Ty(Type::getVoidTy(Context)); if (ParseOptionalToken(lltok::kw_thread_local, ThreadLocal) || ParseOptionalAddrSpace(AddrSpace) || + ParseOptionalToken(lltok::kw_unnamed_addr, UnnamedAddr, + &UnnamedAddrLoc) || ParseGlobalType(IsConstant) || ParseType(Ty, TyLoc)) return true; @@ -756,6 +759,7 @@ bool LLParser::ParseGlobal(const std::string &Name, LocTy NameLoc, GV->setLinkage((GlobalValue::LinkageTypes)Linkage); GV->setVisibility((GlobalValue::VisibilityTypes)Visibility); GV->setThreadLocal(ThreadLocal); + GV->setUnnamedAddr(UnnamedAddr); // Parse attributes on the global. while (Lex.getKind() == lltok::comma) { @@ -855,7 +859,7 @@ GlobalValue *LLParser::GetGlobalVal(unsigned ID, const Type *Ty, LocTy Loc) { // If we have the value in the symbol table or fwd-ref table, return it. if (Val) { if (Val->getType() == Ty) return Val; - Error(Loc, "'@" + utostr(ID) + "' defined with type '" + + Error(Loc, "'@" + Twine(ID) + "' defined with type '" + Val->getType()->getDescription() + "'"); return 0; } @@ -983,6 +987,7 @@ bool LLParser::ParseOptionalAttrs(unsigned &Attrs, unsigned AttrKind) { case lltok::kw_noredzone: Attrs |= Attribute::NoRedZone; break; case lltok::kw_noimplicitfloat: Attrs |= Attribute::NoImplicitFloat; break; case lltok::kw_naked: Attrs |= Attribute::Naked; break; + case lltok::kw_hotpatch: Attrs |= Attribute::Hotpatch; break; case lltok::kw_alignstack: { unsigned Alignment; @@ -1084,6 +1089,8 @@ bool LLParser::ParseOptionalVisibility(unsigned &Res) { /// ::= 'arm_aapcscc' /// ::= 'arm_aapcs_vfpcc' /// ::= 'msp430_intrcc' +/// ::= 'ptx_kernel' +/// ::= 'ptx_device' /// ::= 'cc' UINT /// bool LLParser::ParseOptionalCallingConv(CallingConv::ID &CC) { @@ -1099,6 +1106,8 @@ bool LLParser::ParseOptionalCallingConv(CallingConv::ID &CC) { case lltok::kw_arm_aapcscc: CC = CallingConv::ARM_AAPCS; break; case lltok::kw_arm_aapcs_vfpcc:CC = CallingConv::ARM_AAPCS_VFP; break; case lltok::kw_msp430_intrcc: CC = CallingConv::MSP430_INTR; break; + case lltok::kw_ptx_kernel: CC = CallingConv::PTX_Kernel; break; + case lltok::kw_ptx_device: CC = CallingConv::PTX_Device; break; case lltok::kw_cc: { unsigned ArbitraryCC; Lex.Lex(); @@ -1128,7 +1137,6 @@ bool LLParser::ParseInstructionMetadata(Instruction *Inst, Lex.Lex(); MDNode *Node; - unsigned NodeID; SMLoc Loc = Lex.getLoc(); if (ParseToken(lltok::exclaim, "expected '!' here")) @@ -1145,6 +1153,7 @@ bool LLParser::ParseInstructionMetadata(Instruction *Inst, assert(ID.Kind == ValID::t_MDNode); Inst->setMetadata(MDK, ID.MDNodeVal); } else { + unsigned NodeID = 0; if (ParseMDNodeID(Node, NodeID)) return true; if (Node) { @@ -1196,8 +1205,7 @@ bool LLParser::ParseOptionalCommaAlign(unsigned &Alignment, if (Lex.getKind() != lltok::kw_align) return Error(Lex.getLoc(), "expected metadata or 'align'"); - - LocTy AlignLoc = Lex.getLoc(); + if (ParseOptionalAlignment(Alignment)) return true; } @@ -1245,7 +1253,7 @@ bool LLParser::ParseIndexList(SmallVectorImpl &Indices, AteExtraComma = true; return false; } - unsigned Idx; + unsigned Idx = 0; if (ParseUInt32(Idx)) return true; Indices.push_back(Idx); } @@ -1778,7 +1786,7 @@ bool LLParser::PerFunctionState::FinishFunction() { if (!ForwardRefValIDs.empty()) return P.Error(ForwardRefValIDs.begin()->second.second, "use of undefined value '%" + - utostr(ForwardRefValIDs.begin()->first) + "'"); + Twine(ForwardRefValIDs.begin()->first) + "'"); return false; } @@ -1846,9 +1854,9 @@ Value *LLParser::PerFunctionState::GetVal(unsigned ID, const Type *Ty, if (Val) { if (Val->getType() == Ty) return Val; if (Ty->isLabelTy()) - P.Error(Loc, "'%" + utostr(ID) + "' is not a basic block"); + P.Error(Loc, "'%" + Twine(ID) + "' is not a basic block"); else - P.Error(Loc, "'%" + utostr(ID) + "' defined with type '" + + P.Error(Loc, "'%" + Twine(ID) + "' defined with type '" + Val->getType()->getDescription() + "'"); return 0; } @@ -1890,7 +1898,7 @@ bool LLParser::PerFunctionState::SetInstName(int NameID, if (unsigned(NameID) != NumberedVals.size()) return P.Error(NameLoc, "instruction expected to be numbered '%" + - utostr(NumberedVals.size()) + "'"); + Twine(NumberedVals.size()) + "'"); std::map >::iterator FI = ForwardRefValIDs.find(NameID); @@ -1922,7 +1930,7 @@ bool LLParser::PerFunctionState::SetInstName(int NameID, // Set the name on the instruction. Inst->setName(NameStr); - if (Inst->getNameStr() != NameStr) + if (Inst->getName() != NameStr) return P.Error(NameLoc, "multiple definition of local value named '" + NameStr + "'"); return false; @@ -2068,10 +2076,10 @@ bool LLParser::ParseValID(ValID &ID, PerFunctionState *PFS) { for (unsigned i = 1, e = Elts.size(); i != e; ++i) if (Elts[i]->getType() != Elts[0]->getType()) return Error(FirstEltLoc, - "vector element #" + utostr(i) + + "vector element #" + Twine(i) + " is not of type '" + Elts[0]->getType()->getDescription()); - ID.ConstantVal = ConstantVector::get(Elts.data(), Elts.size()); + ID.ConstantVal = ConstantVector::get(Elts); ID.Kind = ValID::t_Constant; return false; } @@ -2101,7 +2109,7 @@ bool LLParser::ParseValID(ValID &ID, PerFunctionState *PFS) { for (unsigned i = 0, e = Elts.size(); i != e; ++i) { if (Elts[i]->getType() != Elts[0]->getType()) return Error(FirstEltLoc, - "array element #" + utostr(i) + + "array element #" + Twine(i) + " is not of type '" +Elts[0]->getType()->getDescription()); } @@ -2278,7 +2286,10 @@ bool LLParser::ParseValID(ValID &ID, PerFunctionState *PFS) { case lltok::kw_fdiv: case lltok::kw_urem: case lltok::kw_srem: - case lltok::kw_frem: { + case lltok::kw_frem: + case lltok::kw_shl: + case lltok::kw_lshr: + case lltok::kw_ashr: { bool NUW = false; bool NSW = false; bool Exact = false; @@ -2286,9 +2297,8 @@ bool LLParser::ParseValID(ValID &ID, PerFunctionState *PFS) { Constant *Val0, *Val1; Lex.Lex(); LocTy ModifierLoc = Lex.getLoc(); - if (Opc == Instruction::Add || - Opc == Instruction::Sub || - Opc == Instruction::Mul) { + if (Opc == Instruction::Add || Opc == Instruction::Sub || + Opc == Instruction::Mul || Opc == Instruction::Shl) { if (EatIfPresent(lltok::kw_nuw)) NUW = true; if (EatIfPresent(lltok::kw_nsw)) { @@ -2296,7 +2306,8 @@ bool LLParser::ParseValID(ValID &ID, PerFunctionState *PFS) { if (EatIfPresent(lltok::kw_nuw)) NUW = true; } - } else if (Opc == Instruction::SDiv) { + } else if (Opc == Instruction::SDiv || Opc == Instruction::UDiv || + Opc == Instruction::LShr || Opc == Instruction::AShr) { if (EatIfPresent(lltok::kw_exact)) Exact = true; } @@ -2323,6 +2334,9 @@ bool LLParser::ParseValID(ValID &ID, PerFunctionState *PFS) { case Instruction::SDiv: case Instruction::URem: case Instruction::SRem: + case Instruction::Shl: + case Instruction::AShr: + case Instruction::LShr: if (!Val0->getType()->isIntOrIntVectorTy()) return Error(ID.Loc, "constexpr requires integer operands"); break; @@ -2339,7 +2353,7 @@ bool LLParser::ParseValID(ValID &ID, PerFunctionState *PFS) { unsigned Flags = 0; if (NUW) Flags |= OverflowingBinaryOperator::NoUnsignedWrap; if (NSW) Flags |= OverflowingBinaryOperator::NoSignedWrap; - if (Exact) Flags |= SDivOperator::IsExact; + if (Exact) Flags |= PossiblyExactOperator::IsExact; Constant *C = ConstantExpr::get(Opc, Val0, Val1, Flags); ID.ConstantVal = C; ID.Kind = ValID::t_Constant; @@ -2347,9 +2361,6 @@ bool LLParser::ParseValID(ValID &ID, PerFunctionState *PFS) { } // Logical Operations - case lltok::kw_shl: - case lltok::kw_lshr: - case lltok::kw_ashr: case lltok::kw_and: case lltok::kw_or: case lltok::kw_xor: { @@ -2572,7 +2583,7 @@ bool LLParser::ConvertValIDToValue(const Type *Ty, ValID &ID, Value *&V, case ValID::t_APSInt: if (!Ty->isIntegerTy()) return Error(ID.Loc, "integer constant must have integer type"); - ID.APSIntVal.extOrTrunc(Ty->getPrimitiveSizeInBits()); + ID.APSIntVal = ID.APSIntVal.extOrTrunc(Ty->getPrimitiveSizeInBits()); V = ConstantInt::get(Context, ID.APSIntVal); return false; case ValID::t_APFloat: @@ -2654,7 +2665,7 @@ bool LLParser::ParseTypeAndBasicBlock(BasicBlock *&BB, LocTy &Loc, /// FunctionHeader /// ::= OptionalLinkage OptionalVisibility OptionalCallingConv OptRetAttrs -/// Type GlobalName '(' ArgList ')' OptFuncAttrs OptSection +/// OptUnnamedAddr Type GlobalName '(' ArgList ')' OptFuncAttrs OptSection /// OptionalAlign OptGC bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) { // Parse the linkage. @@ -2714,7 +2725,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) { if (NameID != NumberedVals.size()) return TokError("function expected to be numbered '%" + - utostr(NumberedVals.size()) + "'"); + Twine(NumberedVals.size()) + "'"); } else { return TokError("expected function name"); } @@ -2730,8 +2741,12 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) { std::string Section; unsigned Alignment; std::string GC; + bool UnnamedAddr; + LocTy UnnamedAddrLoc; if (ParseArgumentList(ArgList, isVarArg, false) || + ParseOptionalToken(lltok::kw_unnamed_addr, UnnamedAddr, + &UnnamedAddrLoc) || ParseOptionalAttrs(FuncAttrs, 2) || (EatIfPresent(lltok::kw_section) && ParseStringConstant(Section)) || @@ -2821,7 +2836,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) { Fn = cast(I->second.first); if (Fn->getType() != PFT) return Error(NameLoc, "type of definition and forward reference of '@" + - utostr(NumberedVals.size()) +"' disagree"); + Twine(NumberedVals.size()) + "' disagree"); ForwardRefValIDs.erase(I); } } @@ -2838,6 +2853,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) { Fn->setVisibility((GlobalValue::VisibilityTypes)Visibility); Fn->setCallingConv(CC); Fn->setAttributes(PAL); + Fn->setUnnamedAddr(UnnamedAddr); Fn->setAlignment(Alignment); Fn->setSection(Section); if (!GC.empty()) Fn->setGC(GC.c_str()); @@ -2855,7 +2871,7 @@ bool LLParser::ParseFunctionHeader(Function *&Fn, bool isDefine) { // Set the name, if it conflicted, it will be auto-renamed. ArgIt->setName(ArgList[i].Name); - if (ArgIt->getNameStr() != ArgList[i].Name) + if (ArgIt->getName() != ArgList[i].Name) return Error(ArgList[i].Loc, "redefinition of argument '%" + ArgList[i].Name + "'"); } @@ -2989,55 +3005,38 @@ int LLParser::ParseInstruction(Instruction *&Inst, BasicBlock *BB, // Binary Operators. case lltok::kw_add: case lltok::kw_sub: - case lltok::kw_mul: { - bool NUW = false; - bool NSW = false; + case lltok::kw_mul: + case lltok::kw_shl: { LocTy ModifierLoc = Lex.getLoc(); - if (EatIfPresent(lltok::kw_nuw)) - NUW = true; - if (EatIfPresent(lltok::kw_nsw)) { - NSW = true; - if (EatIfPresent(lltok::kw_nuw)) - NUW = true; - } - bool Result = ParseArithmetic(Inst, PFS, KeywordVal, 1); - if (!Result) { - if (!Inst->getType()->isIntOrIntVectorTy()) { - if (NUW) - return Error(ModifierLoc, "nuw only applies to integer operations"); - if (NSW) - return Error(ModifierLoc, "nsw only applies to integer operations"); - } - if (NUW) - cast(Inst)->setHasNoUnsignedWrap(true); - if (NSW) - cast(Inst)->setHasNoSignedWrap(true); - } - return Result; + bool NUW = EatIfPresent(lltok::kw_nuw); + bool NSW = EatIfPresent(lltok::kw_nsw); + if (!NUW) NUW = EatIfPresent(lltok::kw_nuw); + + if (ParseArithmetic(Inst, PFS, KeywordVal, 1)) return true; + + if (NUW) cast(Inst)->setHasNoUnsignedWrap(true); + if (NSW) cast(Inst)->setHasNoSignedWrap(true); + return false; } case lltok::kw_fadd: case lltok::kw_fsub: case lltok::kw_fmul: return ParseArithmetic(Inst, PFS, KeywordVal, 2); - case lltok::kw_sdiv: { - bool Exact = false; - if (EatIfPresent(lltok::kw_exact)) - Exact = true; - bool Result = ParseArithmetic(Inst, PFS, KeywordVal, 1); - if (!Result) - if (Exact) - cast(Inst)->setIsExact(true); - return Result; + case lltok::kw_sdiv: + case lltok::kw_udiv: + case lltok::kw_lshr: + case lltok::kw_ashr: { + bool Exact = EatIfPresent(lltok::kw_exact); + + if (ParseArithmetic(Inst, PFS, KeywordVal, 1)) return true; + if (Exact) cast(Inst)->setIsExact(true); + return false; } - case lltok::kw_udiv: case lltok::kw_urem: case lltok::kw_srem: return ParseArithmetic(Inst, PFS, KeywordVal, 1); case lltok::kw_fdiv: case lltok::kw_frem: return ParseArithmetic(Inst, PFS, KeywordVal, 2); - case lltok::kw_shl: - case lltok::kw_lshr: - case lltok::kw_ashr: case lltok::kw_and: case lltok::kw_or: case lltok::kw_xor: return ParseLogical(Inst, PFS, KeywordVal); diff --git a/lib/AsmParser/LLParser.h b/lib/AsmParser/LLParser.h index 404cec3ed7c7..93e7f778ebcb 100644 --- a/lib/AsmParser/LLParser.h +++ b/lib/AsmParser/LLParser.h @@ -142,10 +142,10 @@ namespace llvm { private: - bool Error(LocTy L, const std::string &Msg) const { + bool Error(LocTy L, const Twine &Msg) const { return Lex.Error(L, Msg); } - bool TokError(const std::string &Msg) const { + bool TokError(const Twine &Msg) const { return Error(Lex.getLoc(), Msg); } @@ -162,10 +162,12 @@ namespace llvm { Lex.Lex(); return true; } - bool ParseOptionalToken(lltok::Kind T, bool &Present) { + bool ParseOptionalToken(lltok::Kind T, bool &Present, LocTy *Loc = 0) { if (Lex.getKind() != T) { Present = false; } else { + if (Loc) + *Loc = Lex.getLoc(); Lex.Lex(); Present = true; } diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h index 61f93a427498..576da191aecf 100644 --- a/lib/AsmParser/LLToken.h +++ b/lib/AsmParser/LLToken.h @@ -42,6 +42,7 @@ namespace lltok { kw_linkonce, kw_linkonce_odr, kw_weak, kw_weak_odr, kw_appending, kw_dllimport, kw_dllexport, kw_common, kw_available_externally, kw_default, kw_hidden, kw_protected, + kw_unnamed_addr, kw_extern_weak, kw_external, kw_thread_local, kw_zeroinitializer, @@ -72,6 +73,7 @@ namespace lltok { kw_x86_stdcallcc, kw_x86_fastcallcc, kw_x86_thiscallcc, kw_arm_apcscc, kw_arm_aapcscc, kw_arm_aapcs_vfpcc, kw_msp430_intrcc, + kw_ptx_kernel, kw_ptx_device, kw_signext, kw_zeroext, @@ -95,6 +97,7 @@ namespace lltok { kw_noredzone, kw_noimplicitfloat, kw_naked, + kw_hotpatch, kw_type, kw_opaque, diff --git a/lib/AsmParser/Parser.cpp b/lib/AsmParser/Parser.cpp index e7cef9b5c3c5..59fb471f2b93 100644 --- a/lib/AsmParser/Parser.cpp +++ b/lib/AsmParser/Parser.cpp @@ -18,6 +18,7 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" #include using namespace llvm; @@ -41,15 +42,14 @@ Module *llvm::ParseAssembly(MemoryBuffer *F, Module *llvm::ParseAssemblyFile(const std::string &Filename, SMDiagnostic &Err, LLVMContext &Context) { - std::string ErrorStr; - MemoryBuffer *F = MemoryBuffer::getFileOrSTDIN(Filename.c_str(), &ErrorStr); - if (F == 0) { + OwningPtr File; + if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename.c_str(), File)) { Err = SMDiagnostic(Filename, - "Could not open input file: " + ErrorStr); + "Could not open input file: " + ec.message()); return 0; } - return ParseAssembly(F, 0, Err, Context); + return ParseAssembly(File.take(), 0, Err, Context); } Module *llvm::ParseAssemblyString(const char *AsmString, Module *M, diff --git a/lib/Bitcode/CMakeLists.txt b/lib/Bitcode/CMakeLists.txt new file mode 100644 index 000000000000..ff7e290cad1b --- /dev/null +++ b/lib/Bitcode/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(Reader) +add_subdirectory(Writer) diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index 830c79aa3b54..dbf8da027996 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -136,7 +136,6 @@ namespace { /// @brief A class for maintaining the slot number definition /// as a placeholder for the actual definition for forward constants defs. class ConstantPlaceHolder : public ConstantExpr { - ConstantPlaceHolder(); // DO NOT IMPLEMENT void operator=(const ConstantPlaceHolder &); // DO NOT IMPLEMENT public: // allocate space for exactly one operand @@ -149,7 +148,7 @@ namespace { } /// @brief Methods to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const ConstantPlaceHolder *) { return true; } + //static inline bool classof(const ConstantPlaceHolder *) { return true; } static bool classof(const Value *V) { return isa(V) && cast(V)->getOpcode() == Instruction::UserOp1; @@ -163,7 +162,8 @@ namespace { // FIXME: can we inherit this from ConstantExpr? template <> -struct OperandTraits : public FixedNumOperandTraits<1> { +struct OperandTraits : + public FixedNumOperandTraits { }; } @@ -298,7 +298,7 @@ void BitcodeReaderValueList::ResolveConstantForwardRefs() { NewC = ConstantStruct::get(Context, &NewOps[0], NewOps.size(), UserCS->getType()->isPacked()); } else if (isa(UserC)) { - NewC = ConstantVector::get(&NewOps[0], NewOps.size()); + NewC = ConstantVector::get(NewOps); } else { assert(isa(UserC) && "Must be a ConstantExpr."); NewC = cast(UserC)->getWithOperands(&NewOps[0], @@ -550,6 +550,9 @@ bool BitcodeReader::ParseTypeTable() { case bitc::TYPE_CODE_METADATA: // METADATA ResultTy = Type::getMetadataTy(Context); break; + case bitc::TYPE_CODE_X86_MMX: // X86_MMX + ResultTy = Type::getX86_MMXTy(Context); + break; case bitc::TYPE_CODE_INTEGER: // INTEGER: [width] if (Record.size() < 1) return Error("Invalid Integer type record"); @@ -794,7 +797,7 @@ bool BitcodeReader::ParseMetadata() { if (NextBitCode == bitc::METADATA_NAMED_NODE) { LLVM2_7MetadataDetected = true; } else if (NextBitCode != bitc::METADATA_NAMED_NODE2) - assert ( 0 && "Inavlid Named Metadata record"); + assert ( 0 && "Invalid Named Metadata record"); // Read named metadata elements. unsigned Size = Record.size(); @@ -832,7 +835,8 @@ bool BitcodeReader::ParseMetadata() { unsigned Size = Record.size(); SmallVector Elts; for (unsigned i = 0; i != Size; i += 2) { - const Type *Ty = getTypeByID(Record[i], false); + const Type *Ty = getTypeByID(Record[i]); + if (!Ty) return Error("Invalid METADATA_NODE2 record"); if (Ty->isMetadataTy()) Elts.push_back(MDValueList.getValueFwdRef(Record[i+1])); else if (!Ty->isVoidTy()) @@ -1081,13 +1085,17 @@ bool BitcodeReader::ParseConstants() { if (Record.size() >= 4) { if (Opc == Instruction::Add || Opc == Instruction::Sub || - Opc == Instruction::Mul) { + Opc == Instruction::Mul || + Opc == Instruction::Shl) { if (Record[3] & (1 << bitc::OBO_NO_SIGNED_WRAP)) Flags |= OverflowingBinaryOperator::NoSignedWrap; if (Record[3] & (1 << bitc::OBO_NO_UNSIGNED_WRAP)) Flags |= OverflowingBinaryOperator::NoUnsignedWrap; - } else if (Opc == Instruction::SDiv) { - if (Record[3] & (1 << bitc::SDIV_EXACT)) + } else if (Opc == Instruction::SDiv || + Opc == Instruction::UDiv || + Opc == Instruction::LShr || + Opc == Instruction::AShr) { + if (Record[3] & (1 << bitc::PEO_EXACT)) Flags |= SDivOperator::IsExact; } } @@ -1167,7 +1175,8 @@ bool BitcodeReader::ParseConstants() { } case bitc::CST_CODE_CE_SHUFVEC_EX: { // [opty, opval, opval, opval] const VectorType *RTy = dyn_cast(CurTy); - const VectorType *OpTy = dyn_cast(getTypeByID(Record[0])); + const VectorType *OpTy = + dyn_cast_or_null(getTypeByID(Record[0])); if (Record.size() < 4 || RTy == 0 || OpTy == 0) return Error("Invalid CE_SHUFVEC_EX record"); Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy); @@ -1418,11 +1427,13 @@ bool BitcodeReader::ParseModule() { break; } // GLOBALVAR: [pointer type, isconst, initid, - // linkage, alignment, section, visibility, threadlocal] + // linkage, alignment, section, visibility, threadlocal, + // unnamed_addr] case bitc::MODULE_CODE_GLOBALVAR: { if (Record.size() < 6) return Error("Invalid MODULE_CODE_GLOBALVAR record"); const Type *Ty = getTypeByID(Record[0]); + if (!Ty) return Error("Invalid MODULE_CODE_GLOBALVAR record"); if (!Ty->isPointerTy()) return Error("Global not a pointer type!"); unsigned AddressSpace = cast(Ty)->getAddressSpace(); @@ -1444,6 +1455,10 @@ bool BitcodeReader::ParseModule() { if (Record.size() > 7) isThreadLocal = Record[7]; + bool UnnamedAddr = false; + if (Record.size() > 8) + UnnamedAddr = Record[8]; + GlobalVariable *NewGV = new GlobalVariable(*TheModule, Ty, isConstant, Linkage, 0, "", 0, isThreadLocal, AddressSpace); @@ -1452,6 +1467,7 @@ bool BitcodeReader::ParseModule() { NewGV->setSection(Section); NewGV->setVisibility(Visibility); NewGV->setThreadLocal(isThreadLocal); + NewGV->setUnnamedAddr(UnnamedAddr); ValueList.push_back(NewGV); @@ -1461,11 +1477,12 @@ bool BitcodeReader::ParseModule() { break; } // FUNCTION: [type, callingconv, isproto, linkage, paramattr, - // alignment, section, visibility, gc] + // alignment, section, visibility, gc, unnamed_addr] case bitc::MODULE_CODE_FUNCTION: { if (Record.size() < 8) return Error("Invalid MODULE_CODE_FUNCTION record"); const Type *Ty = getTypeByID(Record[0]); + if (!Ty) return Error("Invalid MODULE_CODE_FUNCTION record"); if (!Ty->isPointerTy()) return Error("Function not a pointer type!"); const FunctionType *FTy = @@ -1493,6 +1510,10 @@ bool BitcodeReader::ParseModule() { return Error("Invalid GC ID"); Func->setGC(GCTable[Record[8]-1].c_str()); } + bool UnnamedAddr = false; + if (Record.size() > 9) + UnnamedAddr = Record[9]; + Func->setUnnamedAddr(UnnamedAddr); ValueList.push_back(Func); // If this is a function with a body, remember the prototype we are @@ -1507,6 +1528,7 @@ bool BitcodeReader::ParseModule() { if (Record.size() < 3) return Error("Invalid MODULE_ALIAS record"); const Type *Ty = getTypeByID(Record[0]); + if (!Ty) return Error("Invalid MODULE_ALIAS record"); if (!Ty->isPointerTy()) return Error("Function not a pointer type!"); @@ -1598,6 +1620,112 @@ bool BitcodeReader::ParseBitcodeInto(Module *M) { return false; } +bool BitcodeReader::ParseModuleTriple(std::string &Triple) { + if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) + return Error("Malformed block record"); + + SmallVector Record; + + // Read all the records for this module. + while (!Stream.AtEndOfStream()) { + unsigned Code = Stream.ReadCode(); + if (Code == bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) + return Error("Error at end of module block"); + + return false; + } + + if (Code == bitc::ENTER_SUBBLOCK) { + switch (Stream.ReadSubBlockID()) { + default: // Skip unknown content. + if (Stream.SkipBlock()) + return Error("Malformed block record"); + break; + } + continue; + } + + if (Code == bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + // Read a record. + switch (Stream.ReadRecord(Code, Record)) { + default: break; // Default behavior, ignore unknown content. + case bitc::MODULE_CODE_VERSION: // VERSION: [version#] + if (Record.size() < 1) + return Error("Malformed MODULE_CODE_VERSION"); + // Only version #0 is supported so far. + if (Record[0] != 0) + return Error("Unknown bitstream version!"); + break; + case bitc::MODULE_CODE_TRIPLE: { // TRIPLE: [strchr x N] + std::string S; + if (ConvertToString(Record, 0, S)) + return Error("Invalid MODULE_CODE_TRIPLE record"); + Triple = S; + break; + } + } + Record.clear(); + } + + return Error("Premature end of bitstream"); +} + +bool BitcodeReader::ParseTriple(std::string &Triple) { + if (Buffer->getBufferSize() & 3) + return Error("Bitcode stream should be a multiple of 4 bytes in length"); + + unsigned char *BufPtr = (unsigned char *)Buffer->getBufferStart(); + unsigned char *BufEnd = BufPtr+Buffer->getBufferSize(); + + // If we have a wrapper header, parse it and ignore the non-bc file contents. + // The magic number is 0x0B17C0DE stored in little endian. + if (isBitcodeWrapper(BufPtr, BufEnd)) + if (SkipBitcodeWrapperHeader(BufPtr, BufEnd)) + return Error("Invalid bitcode wrapper header"); + + StreamFile.init(BufPtr, BufEnd); + Stream.init(StreamFile); + + // Sniff for the signature. + if (Stream.Read(8) != 'B' || + Stream.Read(8) != 'C' || + Stream.Read(4) != 0x0 || + Stream.Read(4) != 0xC || + Stream.Read(4) != 0xE || + Stream.Read(4) != 0xD) + return Error("Invalid bitcode signature"); + + // We expect a number of well-defined blocks, though we don't necessarily + // need to understand them all. + while (!Stream.AtEndOfStream()) { + unsigned Code = Stream.ReadCode(); + + if (Code != bitc::ENTER_SUBBLOCK) + return Error("Invalid record at top-level"); + + unsigned BlockID = Stream.ReadSubBlockID(); + + // We only know the MODULE subblock ID. + switch (BlockID) { + case bitc::MODULE_BLOCK_ID: + if (ParseModuleTriple(Triple)) + return true; + break; + default: + if (Stream.SkipBlock()) + return Error("Malformed block record"); + break; + } + } + + return false; +} + /// ParseMetadataAttachment - Parse metadata attachments. bool BitcodeReader::ParseMetadataAttachment() { if (Stream.EnterSubBlock(bitc::METADATA_ATTACHMENT_ID)) @@ -1776,13 +1904,17 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { if (OpNum < Record.size()) { if (Opc == Instruction::Add || Opc == Instruction::Sub || - Opc == Instruction::Mul) { + Opc == Instruction::Mul || + Opc == Instruction::Shl) { if (Record[OpNum] & (1 << bitc::OBO_NO_SIGNED_WRAP)) cast(I)->setHasNoSignedWrap(true); if (Record[OpNum] & (1 << bitc::OBO_NO_UNSIGNED_WRAP)) cast(I)->setHasNoUnsignedWrap(true); - } else if (Opc == Instruction::SDiv) { - if (Record[OpNum] & (1 << bitc::SDIV_EXACT)) + } else if (Opc == Instruction::SDiv || + Opc == Instruction::UDiv || + Opc == Instruction::LShr || + Opc == Instruction::AShr) { + if (Record[OpNum] & (1 << bitc::PEO_EXACT)) cast(I)->setIsExact(true); } } @@ -2535,7 +2667,24 @@ Module *llvm::ParseBitcodeFile(MemoryBuffer *Buffer, LLVMContext& Context, // Read in the entire module, and destroy the BitcodeReader. if (M->MaterializeAllPermanently(ErrMsg)) { delete M; - return NULL; + return 0; } + return M; } + +std::string llvm::getBitcodeTargetTriple(MemoryBuffer *Buffer, + LLVMContext& Context, + std::string *ErrMsg) { + BitcodeReader *R = new BitcodeReader(Buffer, Context); + // Don't let the BitcodeReader dtor delete 'Buffer'. + R->setBufferOwned(false); + + std::string Triple(""); + if (R->ParseTriple(Triple)) + if (ErrMsg) + *ErrMsg = R->getErrorString(); + + delete R; + return Triple; +} diff --git a/lib/Bitcode/Reader/BitcodeReader.h b/lib/Bitcode/Reader/BitcodeReader.h index 053121bdad6e..f8fc079c73d9 100644 --- a/lib/Bitcode/Reader/BitcodeReader.h +++ b/lib/Bitcode/Reader/BitcodeReader.h @@ -212,6 +212,10 @@ public: /// @brief Main interface to parsing a bitcode buffer. /// @returns true if an error occurred. bool ParseBitcodeInto(Module *M); + + /// @brief Cheap mechanism to just extract module triple + /// @returns true if an error occurred. + bool ParseTriple(std::string &Triple); private: const Type *getTypeByID(unsigned ID, bool isTypeTable = false); Value *getFnValueByID(unsigned ID, const Type *Ty) { @@ -270,6 +274,7 @@ private: bool ResolveGlobalAndAliasInits(); bool ParseMetadata(); bool ParseMetadataAttachment(); + bool ParseModuleTriple(std::string &Triple); }; } // End llvm namespace diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index 7b6fc6cd928d..f8ef8c668c47 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -26,7 +26,8 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Program.h" +#include "llvm/Support/Program.h" +#include using namespace llvm; /// These are manifest constants used by the bitcode writer. They do not need to @@ -211,6 +212,7 @@ static void WriteTypeTable(const ValueEnumerator &VE, BitstreamWriter &Stream) { case Type::LabelTyID: Code = bitc::TYPE_CODE_LABEL; break; case Type::OpaqueTyID: Code = bitc::TYPE_CODE_OPAQUE; break; case Type::MetadataTyID: Code = bitc::TYPE_CODE_METADATA; break; + case Type::X86_MMXTyID: Code = bitc::TYPE_CODE_X86_MMX; break; case Type::IntegerTyID: // INTEGER: [width] Code = bitc::TYPE_CODE_INTEGER; @@ -402,7 +404,8 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE, unsigned AbbrevToUse = 0; // GLOBALVAR: [type, isconst, initid, - // linkage, alignment, section, visibility, threadlocal] + // linkage, alignment, section, visibility, threadlocal, + // unnamed_addr] Vals.push_back(VE.getTypeID(GV->getType())); Vals.push_back(GV->isConstant()); Vals.push_back(GV->isDeclaration() ? 0 : @@ -411,9 +414,11 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE, Vals.push_back(Log2_32(GV->getAlignment())+1); Vals.push_back(GV->hasSection() ? SectionMap[GV->getSection()] : 0); if (GV->isThreadLocal() || - GV->getVisibility() != GlobalValue::DefaultVisibility) { + GV->getVisibility() != GlobalValue::DefaultVisibility || + GV->hasUnnamedAddr()) { Vals.push_back(getEncodedVisibility(GV)); Vals.push_back(GV->isThreadLocal()); + Vals.push_back(GV->hasUnnamedAddr()); } else { AbbrevToUse = SimpleGVarAbbrev; } @@ -425,7 +430,7 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE, // Emit the function proto information. for (Module::const_iterator F = M->begin(), E = M->end(); F != E; ++F) { // FUNCTION: [type, callingconv, isproto, paramattr, - // linkage, alignment, section, visibility, gc] + // linkage, alignment, section, visibility, gc, unnamed_addr] Vals.push_back(VE.getTypeID(F->getType())); Vals.push_back(F->getCallingConv()); Vals.push_back(F->isDeclaration()); @@ -435,6 +440,7 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE, Vals.push_back(F->hasSection() ? SectionMap[F->getSection()] : 0); Vals.push_back(getEncodedVisibility(F)); Vals.push_back(F->hasGC() ? GCMap[F->getGC()] : 0); + Vals.push_back(F->hasUnnamedAddr()); unsigned AbbrevToUse = 0; Stream.EmitRecord(bitc::MODULE_CODE_FUNCTION, Vals, AbbrevToUse); @@ -464,9 +470,10 @@ static uint64_t GetOptimizationFlags(const Value *V) { Flags |= 1 << bitc::OBO_NO_SIGNED_WRAP; if (OBO->hasNoUnsignedWrap()) Flags |= 1 << bitc::OBO_NO_UNSIGNED_WRAP; - } else if (const SDivOperator *Div = dyn_cast(V)) { - if (Div->isExact()) - Flags |= 1 << bitc::SDIV_EXACT; + } else if (const PossiblyExactOperator *PEO = + dyn_cast(V)) { + if (PEO->isExact()) + Flags |= 1 << bitc::PEO_EXACT; } return Flags; @@ -1641,9 +1648,12 @@ void llvm::WriteBitcodeToFile(const Module *M, raw_ostream &Out) { /// WriteBitcodeToStream - Write the specified module to the specified output /// stream. void llvm::WriteBitcodeToStream(const Module *M, BitstreamWriter &Stream) { - // If this is darwin, emit a file header and trailer if needed. - bool isDarwin = M->getTargetTriple().find("-darwin") != std::string::npos; - if (isDarwin) + // If this is darwin or another generic macho target, emit a file header and + // trailer if needed. + bool isMacho = + M->getTargetTriple().find("-darwin") != std::string::npos || + M->getTargetTriple().find("-macho") != std::string::npos; + if (isMacho) EmitDarwinBCHeader(Stream, M->getTargetTriple()); // Emit the file header. @@ -1657,6 +1667,6 @@ void llvm::WriteBitcodeToStream(const Module *M, BitstreamWriter &Stream) { // Emit the module. WriteModule(M, Stream); - if (isDarwin) + if (isMacho) EmitDarwinBCTrailer(Stream, Stream.getBuffer().size()); } diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 000000000000..e2838c373a39 --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,14 @@ +# `Support' library is added on the top-level CMakeLists.txt + +add_subdirectory(VMCore) +add_subdirectory(CodeGen) +add_subdirectory(Bitcode) +add_subdirectory(Transforms) +add_subdirectory(Linker) +add_subdirectory(Analysis) +add_subdirectory(MC) +add_subdirectory(Object) +add_subdirectory(ExecutionEngine) +add_subdirectory(Target) +add_subdirectory(AsmParser) +add_subdirectory(Archive) diff --git a/lib/CodeGen/AggressiveAntiDepBreaker.cpp b/lib/CodeGen/AggressiveAntiDepBreaker.cpp index 5a634d6ccb01..b520d8fcedc0 100644 --- a/lib/CodeGen/AggressiveAntiDepBreaker.cpp +++ b/lib/CodeGen/AggressiveAntiDepBreaker.cpp @@ -155,16 +155,11 @@ void AggressiveAntiDepBreaker::StartBlock(MachineBasicBlock *BB) { // In a return block, examine the function live-out regs. for (MachineRegisterInfo::liveout_iterator I = MRI.liveout_begin(), E = MRI.liveout_end(); I != E; ++I) { - unsigned Reg = *I; - State->UnionGroups(Reg, 0); - KillIndices[Reg] = BB->size(); - DefIndices[Reg] = ~0u; - // Repeat, for all aliases. - for (const unsigned *Alias = TRI->getAliasSet(Reg); *Alias; ++Alias) { - unsigned AliasReg = *Alias; - State->UnionGroups(AliasReg, 0); - KillIndices[AliasReg] = BB->size(); - DefIndices[AliasReg] = ~0u; + for (const unsigned *Alias = TRI->getOverlaps(*I); + unsigned Reg = *Alias; ++Alias) { + State->UnionGroups(Reg, 0); + KillIndices[Reg] = BB->size(); + DefIndices[Reg] = ~0u; } } } @@ -176,16 +171,11 @@ void AggressiveAntiDepBreaker::StartBlock(MachineBasicBlock *BB) { SE = BB->succ_end(); SI != SE; ++SI) for (MachineBasicBlock::livein_iterator I = (*SI)->livein_begin(), E = (*SI)->livein_end(); I != E; ++I) { - unsigned Reg = *I; - State->UnionGroups(Reg, 0); - KillIndices[Reg] = BB->size(); - DefIndices[Reg] = ~0u; - // Repeat, for all aliases. - for (const unsigned *Alias = TRI->getAliasSet(Reg); *Alias; ++Alias) { - unsigned AliasReg = *Alias; - State->UnionGroups(AliasReg, 0); - KillIndices[AliasReg] = BB->size(); - DefIndices[AliasReg] = ~0u; + for (const unsigned *Alias = TRI->getOverlaps(*I); + unsigned Reg = *Alias; ++Alias) { + State->UnionGroups(Reg, 0); + KillIndices[Reg] = BB->size(); + DefIndices[Reg] = ~0u; } } @@ -197,12 +187,8 @@ void AggressiveAntiDepBreaker::StartBlock(MachineBasicBlock *BB) { for (const unsigned *I = TRI->getCalleeSavedRegs(); *I; ++I) { unsigned Reg = *I; if (!IsReturnBlock && !Pristine.test(Reg)) continue; - State->UnionGroups(Reg, 0); - KillIndices[Reg] = BB->size(); - DefIndices[Reg] = ~0u; - // Repeat, for all aliases. - for (const unsigned *Alias = TRI->getAliasSet(Reg); *Alias; ++Alias) { - unsigned AliasReg = *Alias; + for (const unsigned *Alias = TRI->getOverlaps(Reg); + unsigned AliasReg = *Alias; ++Alias) { State->UnionGroups(AliasReg, 0); KillIndices[AliasReg] = BB->size(); DefIndices[AliasReg] = ~0u; @@ -435,12 +421,9 @@ void AggressiveAntiDepBreaker::PrescanInstruction(MachineInstr *MI, continue; // Update def for Reg and aliases. - DefIndices[Reg] = Count; - for (const unsigned *Alias = TRI->getAliasSet(Reg); - *Alias; ++Alias) { - unsigned AliasReg = *Alias; + for (const unsigned *Alias = TRI->getOverlaps(Reg); + unsigned AliasReg = *Alias; ++Alias) DefIndices[AliasReg] = Count; - } } } diff --git a/lib/CodeGen/AllocationOrder.cpp b/lib/CodeGen/AllocationOrder.cpp new file mode 100644 index 000000000000..20c7625f3253 --- /dev/null +++ b/lib/CodeGen/AllocationOrder.cpp @@ -0,0 +1,68 @@ +//===-- llvm/CodeGen/AllocationOrder.cpp - Allocation Order ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements an allocation order for virtual registers. +// +// The preferred allocation order for a virtual register depends on allocation +// hints and target hooks. The AllocationOrder class encapsulates all of that. +// +//===----------------------------------------------------------------------===// + +#include "AllocationOrder.h" +#include "VirtRegMap.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" + +using namespace llvm; + +// Compare VirtRegMap::getRegAllocPref(). +AllocationOrder::AllocationOrder(unsigned VirtReg, + const VirtRegMap &VRM, + const BitVector &ReservedRegs) + : Pos(0), Reserved(ReservedRegs) { + const TargetRegisterClass *RC = VRM.getRegInfo().getRegClass(VirtReg); + std::pair HintPair = + VRM.getRegInfo().getRegAllocationHint(VirtReg); + + // HintPair.second is a register, phys or virt. + Hint = HintPair.second; + + // Translate to physreg, or 0 if not assigned yet. + if (TargetRegisterInfo::isVirtualRegister(Hint)) + Hint = VRM.getPhys(Hint); + + // The remaining allocation order may depend on the hint. + tie(Begin, End) = VRM.getTargetRegInfo() + .getAllocationOrder(RC, HintPair.first, Hint, VRM.getMachineFunction()); + + // Target-dependent hints require resolution. + if (HintPair.first) + Hint = VRM.getTargetRegInfo().ResolveRegAllocHint(HintPair.first, Hint, + VRM.getMachineFunction()); + + // The hint must be a valid physreg for allocation. + if (Hint && (!TargetRegisterInfo::isPhysicalRegister(Hint) || + !RC->contains(Hint) || ReservedRegs.test(Hint))) + Hint = 0; +} + +unsigned AllocationOrder::next() { + // First take the hint. + if (!Pos) { + Pos = Begin; + if (Hint) + return Hint; + } + // Then look at the order from TRI. + while(Pos != End) { + unsigned Reg = *Pos++; + if (Reg != Hint && !Reserved.test(Reg)) + return Reg; + } + return 0; +} diff --git a/lib/CodeGen/AllocationOrder.h b/lib/CodeGen/AllocationOrder.h new file mode 100644 index 000000000000..3db4b6925fca --- /dev/null +++ b/lib/CodeGen/AllocationOrder.h @@ -0,0 +1,54 @@ +//===-- llvm/CodeGen/AllocationOrder.h - Allocation Order -*- C++ -*-------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements an allocation order for virtual registers. +// +// The preferred allocation order for a virtual register depends on allocation +// hints and target hooks. The AllocationOrder class encapsulates all of that. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_ALLOCATIONORDER_H +#define LLVM_CODEGEN_ALLOCATIONORDER_H + +namespace llvm { + +class BitVector; +class VirtRegMap; + +class AllocationOrder { + const unsigned *Begin; + const unsigned *End; + const unsigned *Pos; + const BitVector &Reserved; + unsigned Hint; +public: + + /// AllocationOrder - Create a new AllocationOrder for VirtReg. + /// @param VirtReg Virtual register to allocate for. + /// @param VRM Virtual register map for function. + /// @param ReservedRegs Set of reserved registers as returned by + /// TargetRegisterInfo::getReservedRegs(). + AllocationOrder(unsigned VirtReg, + const VirtRegMap &VRM, + const BitVector &ReservedRegs); + + /// next - Return the next physical register in the allocation order, or 0. + /// It is safe to call next again after it returned 0. + /// It will keep returning 0 until rewind() is called. + unsigned next(); + + /// rewind - Start over from the beginning. + void rewind() { Pos = 0; } + +}; + +} // end namespace llvm + +#endif diff --git a/lib/CodeGen/Analysis.cpp b/lib/CodeGen/Analysis.cpp index e3dd646c952e..36638c36de67 100644 --- a/lib/CodeGen/Analysis.cpp +++ b/lib/CodeGen/Analysis.cpp @@ -19,6 +19,7 @@ #include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/SelectionDAG.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetOptions.h" @@ -30,7 +31,7 @@ using namespace llvm; /// of insertvalue or extractvalue indices that identify a member, return /// the linearized index of the start of the member. /// -unsigned llvm::ComputeLinearIndex(const TargetLowering &TLI, const Type *Ty, +unsigned llvm::ComputeLinearIndex(const Type *Ty, const unsigned *Indices, const unsigned *IndicesEnd, unsigned CurIndex) { @@ -45,8 +46,8 @@ unsigned llvm::ComputeLinearIndex(const TargetLowering &TLI, const Type *Ty, EE = STy->element_end(); EI != EE; ++EI) { if (Indices && *Indices == unsigned(EI - EB)) - return ComputeLinearIndex(TLI, *EI, Indices+1, IndicesEnd, CurIndex); - CurIndex = ComputeLinearIndex(TLI, *EI, 0, 0, CurIndex); + return ComputeLinearIndex(*EI, Indices+1, IndicesEnd, CurIndex); + CurIndex = ComputeLinearIndex(*EI, 0, 0, CurIndex); } return CurIndex; } @@ -55,8 +56,8 @@ unsigned llvm::ComputeLinearIndex(const TargetLowering &TLI, const Type *Ty, const Type *EltTy = ATy->getElementType(); for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i) { if (Indices && *Indices == i) - return ComputeLinearIndex(TLI, EltTy, Indices+1, IndicesEnd, CurIndex); - CurIndex = ComputeLinearIndex(TLI, EltTy, 0, 0, CurIndex); + return ComputeLinearIndex(EltTy, Indices+1, IndicesEnd, CurIndex); + CurIndex = ComputeLinearIndex(EltTy, 0, 0, CurIndex); } return CurIndex; } @@ -125,7 +126,7 @@ GlobalVariable *llvm::ExtractTypeInfo(Value *V) { /// hasInlineAsmMemConstraint - Return true if the inline asm instruction being /// processed uses a memory 'm' constraint. bool -llvm::hasInlineAsmMemConstraint(std::vector &CInfos, +llvm::hasInlineAsmMemConstraint(InlineAsm::ConstraintInfoVector &CInfos, const TargetLowering &TLI) { for (unsigned i = 0, e = CInfos.size(); i != e; ++i) { InlineAsm::ConstraintInfo &CI = CInfos[i]; @@ -283,3 +284,20 @@ bool llvm::isInTailCallPosition(ImmutableCallSite CS, Attributes CalleeRetAttr, return true; } +bool llvm::isInTailCallPosition(SelectionDAG &DAG, SDNode *Node, + const TargetLowering &TLI) { + const Function *F = DAG.getMachineFunction().getFunction(); + + // Conservatively require the attributes of the call to match those of + // the return. Ignore noalias because it doesn't affect the call sequence. + unsigned CallerRetAttr = F->getAttributes().getRetAttributes(); + if (CallerRetAttr & ~Attribute::NoAlias) + return false; + + // It's not safe to eliminate the sign / zero extension of the return value. + if ((CallerRetAttr & Attribute::ZExt) || (CallerRetAttr & Attribute::SExt)) + return false; + + // Check if the only use is a function return node. + return TLI.isUsedByReturnOnly(Node); +} diff --git a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index d358ab20ffc5..43e8990a9da1 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -38,6 +38,7 @@ #include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Assembly/Writer.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/ErrorHandling.h" @@ -178,16 +179,24 @@ bool AsmPrinter::doInitialization(Module &M) { if (!M.getModuleInlineAsm().empty()) { OutStreamer.AddComment("Start of file scope inline assembly"); OutStreamer.AddBlankLine(); - EmitInlineAsm(M.getModuleInlineAsm()+"\n", 0/*no loc cookie*/); + EmitInlineAsm(M.getModuleInlineAsm()+"\n"); OutStreamer.AddComment("End of file scope inline assembly"); OutStreamer.AddBlankLine(); } if (MAI->doesSupportDebugInformation()) DD = new DwarfDebug(this, &M); - + if (MAI->doesSupportExceptionHandling()) - DE = new DwarfException(this); + switch (MAI->getExceptionHandlingType()) { + default: + case ExceptionHandling::DwarfTable: + DE = new DwarfTableException(this); + break; + case ExceptionHandling::DwarfCFI: + DE = new DwarfCFIException(this); + break; + } return false; } @@ -282,8 +291,12 @@ void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { // Handle common symbols. if (GVKind.isCommon()) { + unsigned Align = 1 << AlignLog; + if (!getObjFileLowering().getCommDirectiveSupportsAlignment()) + Align = 0; + // .comm _foo, 42, 4 - OutStreamer.EmitCommonSymbol(GVSym, Size, 1 << AlignLog); + OutStreamer.EmitCommonSymbol(GVSym, Size, Align); return; } @@ -301,11 +314,15 @@ void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { OutStreamer.EmitLocalCommonSymbol(GVSym, Size); return; } + + unsigned Align = 1 << AlignLog; + if (!getObjFileLowering().getCommDirectiveSupportsAlignment()) + Align = 0; // .local _foo OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Local); // .comm _foo, 42, 4 - OutStreamer.EmitCommonSymbol(GVSym, Size, 1 << AlignLog); + OutStreamer.EmitCommonSymbol(GVSym, Size, Align); return; } @@ -327,6 +344,13 @@ void AsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) { // Handle thread local data for mach-o which requires us to output an // additional structure of data and mangle the original symbol so that we // can reference it later. + // + // TODO: This should become an "emit thread local global" method on TLOF. + // All of this macho specific stuff should be sunk down into TLOFMachO and + // stuff like "TLSExtraDataSection" should no longer be part of the parent + // TLOF class. This will also make it more obvious that stuff like + // MCStreamer::EmitTBSSSymbol is macho specific and only called from macho + // specific code. if (GVKind.isThreadLocal() && MAI->hasMachoTBSSDirective()) { // Emit the .tbss symbol MCSymbol *MangSym = @@ -623,7 +647,7 @@ void AsmPrinter::EmitFunctionBody() { if (ShouldPrintDebugScopes) { NamedRegionTimer T(DbgTimerName, DWARFGroupName, TimePassesIsEnabled); - DD->beginScope(II); + DD->beginInstruction(II); } if (isVerbose()) @@ -657,7 +681,7 @@ void AsmPrinter::EmitFunctionBody() { if (ShouldPrintDebugScopes) { NamedRegionTimer T(DbgTimerName, DWARFGroupName, TimePassesIsEnabled); - DD->endScope(II); + DD->endInstruction(II); } } } @@ -729,7 +753,20 @@ bool AsmPrinter::doFinalization(Module &M) { for (Module::const_global_iterator I = M.global_begin(), E = M.global_end(); I != E; ++I) EmitGlobalVariable(I); - + + // Emit visibility info for declarations + for (Module::const_iterator I = M.begin(), E = M.end(); I != E; ++I) { + const Function &F = *I; + if (!F.isDeclaration()) + continue; + GlobalValue::VisibilityTypes V = F.getVisibility(); + if (V == GlobalValue::DefaultVisibility) + continue; + + MCSymbol *Name = Mang->getSymbol(&F); + EmitVisibility(Name, V); + } + // Finalize debug and EH information. if (DE) { { @@ -905,14 +942,6 @@ void AsmPrinter::EmitConstantPool() { const Type *Ty = CPE.getType(); Offset = NewOffset + TM.getTargetData()->getTypeAllocSize(Ty); - - // Emit the label with a comment on it. - if (isVerbose()) { - OutStreamer.GetCommentOS() << "constant pool "; - WriteTypeSymbolic(OutStreamer.GetCommentOS(), CPE.getType(), - MF->getFunction()->getParent()); - OutStreamer.GetCommentOS() << '\n'; - } OutStreamer.EmitLabel(GetCPISymbol(CPI)); if (CPE.isMachineConstantPoolEntry()) @@ -983,7 +1012,7 @@ void AsmPrinter::EmitJumpTableInfo() { } } - // On some targets (e.g. Darwin) we want to emit two consequtive labels + // On some targets (e.g. Darwin) we want to emit two consecutive labels // before each jump table. The first label is never referenced, but tells // the assembler and linker the extents of the jump table object. The // second label is actually referenced by the code. @@ -1004,6 +1033,7 @@ void AsmPrinter::EmitJumpTableInfo() { void AsmPrinter::EmitJumpTableEntry(const MachineJumpTableInfo *MJTI, const MachineBasicBlock *MBB, unsigned UID) const { + assert(MBB && MBB->getNumber() >= 0 && "Invalid basic block"); const MCExpr *Value = 0; switch (MJTI->getEntryKind()) { case MachineJumpTableInfo::EK_Inline: diff --git a/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp b/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp index ce4519c541e3..98a1bf2f1ce4 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp @@ -19,7 +19,7 @@ #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Target/TargetData.h" -#include "llvm/Target/TargetFrameInfo.h" +#include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetRegisterInfo.h" @@ -36,9 +36,8 @@ void AsmPrinter::EmitSLEB128(int Value, const char *Desc) const { if (isVerbose() && Desc) OutStreamer.AddComment(Desc); - if (MAI->hasLEB128() && OutStreamer.hasRawTextSupport()) { - // FIXME: MCize. - OutStreamer.EmitRawText("\t.sleb128\t" + Twine(Value)); + if (MAI->hasLEB128()) { + OutStreamer.EmitSLEB128IntValue(Value); return; } @@ -60,10 +59,10 @@ void AsmPrinter::EmitULEB128(unsigned Value, const char *Desc, unsigned PadTo) const { if (isVerbose() && Desc) OutStreamer.AddComment(Desc); - - if (MAI->hasLEB128() && PadTo == 0 && OutStreamer.hasRawTextSupport()) { - // FIXME: MCize. - OutStreamer.EmitRawText("\t.uleb128\t" + Twine(Value)); + + // FIXME: Should we add a PadTo option to the streamer? + if (MAI->hasLEB128() && PadTo == 0) { + OutStreamer.EmitULEB128IntValue(Value); return; } @@ -157,7 +156,7 @@ void AsmPrinter::EmitReference(const MCSymbol *Sym, unsigned Encoding) const { const MCExpr *Exp = TLOF.getExprForDwarfReference(Sym, Mang, MMI, Encoding, OutStreamer); - OutStreamer.EmitValue(Exp, GetSizeOfEncodedValue(Encoding), /*addrspace*/0); + OutStreamer.EmitAbsValue(Exp, GetSizeOfEncodedValue(Encoding)); } void AsmPrinter::EmitReference(const GlobalValue *GV, unsigned Encoding)const{ @@ -215,8 +214,8 @@ void AsmPrinter::EmitFrameMoves(const std::vector &Moves, const TargetRegisterInfo *RI = TM.getRegisterInfo(); int stackGrowth = TM.getTargetData()->getPointerSize(); - if (TM.getFrameInfo()->getStackGrowthDirection() != - TargetFrameInfo::StackGrowsUp) + if (TM.getFrameLowering()->getStackGrowthDirection() != + TargetFrameLowering::StackGrowsUp) stackGrowth *= -1; for (unsigned i = 0, N = Moves.size(); i < N; ++i) { @@ -277,3 +276,43 @@ void AsmPrinter::EmitFrameMoves(const std::vector &Moves, } } } + +/// EmitFrameMoves - Emit frame instructions to describe the layout of the +/// frame. +void AsmPrinter::EmitCFIFrameMoves(const std::vector &Moves) const { + const TargetRegisterInfo *RI = TM.getRegisterInfo(); + + int stackGrowth = TM.getTargetData()->getPointerSize(); + if (TM.getFrameLowering()->getStackGrowthDirection() != + TargetFrameLowering::StackGrowsUp) + stackGrowth *= -1; + + for (unsigned i = 0, N = Moves.size(); i < N; ++i) { + const MachineMove &Move = Moves[i]; + MCSymbol *Label = Move.getLabel(); + // Throw out move if the label is invalid. + if (Label && !Label->isDefined()) continue; // Not emitted, in dead code. + + const MachineLocation &Dst = Move.getDestination(); + const MachineLocation &Src = Move.getSource(); + + // If advancing cfa. + if (Dst.isReg() && Dst.getReg() == MachineLocation::VirtualFP) { + assert(!Src.isReg() && "Machine move not supported yet."); + + if (Src.getReg() == MachineLocation::VirtualFP) { + OutStreamer.EmitCFIDefCfaOffset(-Src.getOffset()); + } else { + assert("Machine move not supported yet"); + // Reg + Offset + } + } else if (Src.isReg() && Src.getReg() == MachineLocation::VirtualFP) { + assert(Dst.isReg() && "Machine move not supported yet."); + OutStreamer.EmitCFIDefCfaRegister(RI->getDwarfRegNum(Dst.getReg(), true)); + } else { + assert(!Dst.isReg() && "Machine move not supported yet."); + OutStreamer.EmitCFIOffset(RI->getDwarfRegNum(Src.getReg(), true), + Dst.getOffset()); + } + } +} diff --git a/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp b/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp index df0316814c08..c6166e2365a5 100644 --- a/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp +++ b/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp @@ -34,15 +34,47 @@ #include "llvm/Support/raw_ostream.h" using namespace llvm; +namespace { + struct SrcMgrDiagInfo { + const MDNode *LocInfo; + LLVMContext::InlineAsmDiagHandlerTy DiagHandler; + void *DiagContext; + }; +} + +/// SrcMgrDiagHandler - This callback is invoked when the SourceMgr for an +/// inline asm has an error in it. diagInfo is a pointer to the SrcMgrDiagInfo +/// struct above. +static void SrcMgrDiagHandler(const SMDiagnostic &Diag, void *diagInfo) { + SrcMgrDiagInfo *DiagInfo = static_cast(diagInfo); + assert(DiagInfo && "Diagnostic context not passed down?"); + + // If the inline asm had metadata associated with it, pull out a location + // cookie corresponding to which line the error occurred on. + unsigned LocCookie = 0; + if (const MDNode *LocInfo = DiagInfo->LocInfo) { + unsigned ErrorLine = Diag.getLineNo()-1; + if (ErrorLine >= LocInfo->getNumOperands()) + ErrorLine = 0; + + if (LocInfo->getNumOperands() != 0) + if (const ConstantInt *CI = + dyn_cast(LocInfo->getOperand(ErrorLine))) + LocCookie = CI->getZExtValue(); + } + + DiagInfo->DiagHandler(Diag, DiagInfo->DiagContext, LocCookie); +} + /// EmitInlineAsm - Emit a blob of inline asm to the output streamer. -void AsmPrinter::EmitInlineAsm(StringRef Str, unsigned LocCookie) const { +void AsmPrinter::EmitInlineAsm(StringRef Str, const MDNode *LocMDNode) const { assert(!Str.empty() && "Can't emit empty inline asm block"); - + // Remember if the buffer is nul terminated or not so we can avoid a copy. bool isNullTerminated = Str.back() == 0; if (isNullTerminated) Str = Str.substr(0, Str.size()-1); - + // If the output streamer is actually a .s file, just emit the blob textually. // This is useful in case the asm parser doesn't handle something but the // system assembler does. @@ -50,18 +82,23 @@ void AsmPrinter::EmitInlineAsm(StringRef Str, unsigned LocCookie) const { OutStreamer.EmitRawText(Str); return; } - + SourceMgr SrcMgr; - + SrcMgrDiagInfo DiagInfo; + // If the current LLVMContext has an inline asm handler, set it in SourceMgr. LLVMContext &LLVMCtx = MMI->getModule()->getContext(); bool HasDiagHandler = false; - if (void *DiagHandler = LLVMCtx.getInlineAsmDiagnosticHandler()) { - SrcMgr.setDiagHandler((SourceMgr::DiagHandlerTy)(intptr_t)DiagHandler, - LLVMCtx.getInlineAsmDiagnosticContext(), LocCookie); + if (LLVMCtx.getInlineAsmDiagnosticHandler() != 0) { + // If the source manager has an issue, we arrange for SrcMgrDiagHandler + // to be invoked, getting DiagInfo passed into it. + DiagInfo.LocInfo = LocMDNode; + DiagInfo.DiagHandler = LLVMCtx.getInlineAsmDiagnosticHandler(); + DiagInfo.DiagContext = LLVMCtx.getInlineAsmDiagnosticContext(); + SrcMgr.setDiagHandler(SrcMgrDiagHandler, &DiagInfo); HasDiagHandler = true; } - + MemoryBuffer *Buffer; if (isNullTerminated) Buffer = MemoryBuffer::getMemBuffer(Str, ""); @@ -70,7 +107,7 @@ void AsmPrinter::EmitInlineAsm(StringRef Str, unsigned LocCookie) const { // Tell SrcMgr about this buffer, it takes ownership of the buffer. SrcMgr.AddNewSourceBuffer(Buffer, SMLoc()); - + OwningPtr Parser(createMCAsmParser(TM.getTarget(), SrcMgr, OutContext, OutStreamer, *MAI)); @@ -92,15 +129,15 @@ void AsmPrinter::EmitInlineAsm(StringRef Str, unsigned LocCookie) const { /// instruction that is an inline asm. void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { assert(MI->isInlineAsm() && "printInlineAsm only works on inline asms"); - + unsigned NumOperands = MI->getNumOperands(); - + // Count the number of register definitions to find the asm string. unsigned NumDefs = 0; for (; MI->getOperand(NumDefs).isReg() && MI->getOperand(NumDefs).isDef(); ++NumDefs) assert(NumDefs != NumOperands-2 && "No asm string?"); - + assert(MI->getOperand(NumDefs).isSymbol() && "No asm string?"); // Disassemble the AsmStr, printing out the literal pieces, the operands, etc. @@ -128,22 +165,23 @@ void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { // Get the !srcloc metadata node if we have it, and decode the loc cookie from // it. unsigned LocCookie = 0; + const MDNode *LocMD = 0; for (unsigned i = MI->getNumOperands(); i != 0; --i) { - if (MI->getOperand(i-1).isMetadata()) - if (const MDNode *SrcLoc = MI->getOperand(i-1).getMetadata()) - if (SrcLoc->getNumOperands() != 0) - if (const ConstantInt *CI = - dyn_cast(SrcLoc->getOperand(0))) { - LocCookie = CI->getZExtValue(); - break; - } + if (MI->getOperand(i-1).isMetadata() && + (LocMD = MI->getOperand(i-1).getMetadata()) && + LocMD->getNumOperands() != 0) { + if (const ConstantInt *CI = dyn_cast(LocMD->getOperand(0))) { + LocCookie = CI->getZExtValue(); + break; + } + } } - + // Emit the inline asm to a temporary string so we can emit it through // EmitInlineAsm. SmallString<256> StringData; raw_svector_ostream OS(StringData); - + OS << '\t'; // The variant of the current asmprinter. @@ -151,7 +189,7 @@ void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { int CurVariant = -1; // The number of the {.|.|.} region we are in. const char *LastEmitted = AsmStr; // One past the last character emitted. - + while (*LastEmitted) { switch (*LastEmitted) { default: { @@ -199,18 +237,18 @@ void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { ++LastEmitted; // consume ')' character. if (CurVariant == -1) OS << '}'; // this is gcc's behavior for } outside a variant - else + else CurVariant = -1; break; } if (Done) break; - + bool HasCurlyBraces = false; if (*LastEmitted == '{') { // ${variable} ++LastEmitted; // Consume '{' character. HasCurlyBraces = true; } - + // If we have ${:foo}, then this is not a real operand reference, it is a // "magic" string reference, just like in .td files. Arrange to call // PrintSpecial. @@ -221,25 +259,25 @@ void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { if (StrEnd == 0) report_fatal_error("Unterminated ${:foo} operand in inline asm" " string: '" + Twine(AsmStr) + "'"); - + std::string Val(StrStart, StrEnd); PrintSpecial(MI, OS, Val.c_str()); LastEmitted = StrEnd+1; break; } - + const char *IDStart = LastEmitted; const char *IDEnd = IDStart; - while (*IDEnd >= '0' && *IDEnd <= '9') ++IDEnd; - + while (*IDEnd >= '0' && *IDEnd <= '9') ++IDEnd; + unsigned Val; if (StringRef(IDStart, IDEnd-IDStart).getAsInteger(10, Val)) report_fatal_error("Bad $ operand number in inline asm string: '" + Twine(AsmStr) + "'"); LastEmitted = IDEnd; - + char Modifier[2] = { 0, 0 }; - + if (HasCurlyBraces) { // If we have curly braces, check for a modifier character. This // supports syntax like ${0:u}, which correspond to "%u0" in GCC asm. @@ -248,25 +286,25 @@ void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { if (*LastEmitted == 0) report_fatal_error("Bad ${:} expression in inline asm string: '" + Twine(AsmStr) + "'"); - + Modifier[0] = *LastEmitted; ++LastEmitted; // Consume modifier character. } - + if (*LastEmitted != '}') report_fatal_error("Bad ${} expression in inline asm string: '" + Twine(AsmStr) + "'"); ++LastEmitted; // Consume '}' character. } - + if (Val >= NumOperands-1) report_fatal_error("Invalid $ operand number in inline asm string: '" + Twine(AsmStr) + "'"); - + // Okay, we finally have a value number. Ask the target to print this // operand! if (CurVariant == -1 || CurVariant == AsmPrinterVariant) { - unsigned OpNo = 2; + unsigned OpNo = InlineAsm::MIOp_FirstOperand; bool Error = false; @@ -310,8 +348,8 @@ void AsmPrinter::EmitInlineAsm(const MachineInstr *MI) const { } } OS << '\n' << (char)0; // null terminate string. - EmitInlineAsm(OS.str(), LocCookie); - + EmitInlineAsm(OS.str(), LocMD); + // Emit the #NOAPP end marker. This has to happen even if verbose-asm isn't // enabled, so we use EmitRawText. if (OutStreamer.hasRawTextSupport()) @@ -335,7 +373,7 @@ void AsmPrinter::PrintSpecial(const MachineInstr *MI, raw_ostream &OS, } else if (!strcmp(Code, "uid")) { // Comparing the address of MI isn't sufficient, because machineinstrs may // be allocated to the same address across functions. - + // If this is a new LastFn instruction, bump the counter. if (LastMI != MI || LastFn != getFunctionNumber()) { ++Counter; @@ -349,7 +387,7 @@ void AsmPrinter::PrintSpecial(const MachineInstr *MI, raw_ostream &OS, Msg << "Unknown special formatter '" << Code << "' for machine instr: " << *MI; report_fatal_error(Msg.str()); - } + } } /// PrintAsmOperand - Print the specified operand of MI, an INLINEASM diff --git a/lib/CodeGen/AsmPrinter/CMakeLists.txt b/lib/CodeGen/AsmPrinter/CMakeLists.txt index ca8b8436c11f..306efade7d92 100644 --- a/lib/CodeGen/AsmPrinter/CMakeLists.txt +++ b/lib/CodeGen/AsmPrinter/CMakeLists.txt @@ -3,9 +3,10 @@ add_llvm_library(LLVMAsmPrinter AsmPrinterDwarf.cpp AsmPrinterInlineAsm.cpp DIE.cpp + DwarfCFIException.cpp DwarfDebug.cpp DwarfException.cpp + DwarfTableException.cpp OcamlGCPrinter.cpp ) -target_link_libraries (LLVMAsmPrinter LLVMMCParser) diff --git a/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp b/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp new file mode 100644 index 000000000000..68be2eed8f0e --- /dev/null +++ b/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp @@ -0,0 +1,138 @@ +//===-- CodeGen/AsmPrinter/DwarfException.cpp - Dwarf Exception Impl ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains support for writing DWARF exception info into asm files. +// +//===----------------------------------------------------------------------===// + +#include "DwarfException.h" +#include "llvm/Module.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineLocation.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Target/Mangler.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetLoweringObjectFile.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Twine.h" +using namespace llvm; + +DwarfCFIException::DwarfCFIException(AsmPrinter *A) + : DwarfException(A), + shouldEmitTable(false), shouldEmitMoves(false), shouldEmitTableModule(false) + {} + +DwarfCFIException::~DwarfCFIException() {} + +/// EndModule - Emit all exception information that should come after the +/// content. +void DwarfCFIException::EndModule() { + if (!Asm->MAI->isExceptionHandlingDwarf()) + return; + + if (!shouldEmitTableModule) + return; + + const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); + unsigned PerEncoding = TLOF.getPersonalityEncoding(); + + // Begin eh frame section. + Asm->OutStreamer.SwitchSection(TLOF.getEHFrameSection()); + + // Emit references to all used personality functions + const std::vector &Personalities = MMI->getPersonalities(); + for (size_t i = 0, e = Personalities.size(); i != e; ++i) { + Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("personality", i)); + Asm->EmitReference(Personalities[i], PerEncoding); + } +} + +/// BeginFunction - Gather pre-function exception information. Assumes it's +/// being emitted immediately after the function entry point. +void DwarfCFIException::BeginFunction(const MachineFunction *MF) { + shouldEmitTable = shouldEmitMoves = false; + + // If any landing pads survive, we need an EH table. + shouldEmitTable = !MMI->getLandingPads().empty(); + + // See if we need frame move info. + shouldEmitMoves = + !Asm->MF->getFunction()->doesNotThrow() || UnwindTablesMandatory; + + if (shouldEmitMoves || shouldEmitTable) + // Assumes in correct section after the entry point. + Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_func_begin", + Asm->getFunctionNumber())); + + shouldEmitTableModule |= shouldEmitTable; + + if (shouldEmitMoves) { + const TargetFrameLowering *TFL = Asm->TM.getFrameLowering(); + Asm->OutStreamer.EmitCFIStartProc(); + + // Indicate locations of general callee saved registers in frame. + std::vector Moves; + TFL->getInitialFrameState(Moves); + Asm->EmitCFIFrameMoves(Moves); + Asm->EmitCFIFrameMoves(MMI->getFrameMoves()); + } + + if (!shouldEmitTable) + return; + + const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); + + // Provide LSDA information. + unsigned LSDAEncoding = TLOF.getLSDAEncoding(); + if (LSDAEncoding != dwarf::DW_EH_PE_omit) + Asm->OutStreamer.EmitCFILsda(Asm->GetTempSymbol("exception", + Asm->getFunctionNumber()), + LSDAEncoding); + + // Indicate personality routine, if any. + unsigned PerEncoding = TLOF.getPersonalityEncoding(); + if (PerEncoding != dwarf::DW_EH_PE_omit && + MMI->getPersonalities()[MMI->getPersonalityIndex()]) + Asm->OutStreamer.EmitCFIPersonality(Asm->GetTempSymbol("personality", + MMI->getPersonalityIndex()), + PerEncoding); +} + +/// EndFunction - Gather and emit post-function exception information. +/// +void DwarfCFIException::EndFunction() { + if (!shouldEmitMoves && !shouldEmitTable) return; + + if (shouldEmitMoves) + Asm->OutStreamer.EmitCFIEndProc(); + + Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_func_end", + Asm->getFunctionNumber())); + + // Map all labels and get rid of any dead landing pads. + MMI->TidyLandingPads(); + + if (shouldEmitTable) + EmitExceptionTable(); +} diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index c886a5ecc615..5106d5778c29 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -16,6 +16,7 @@ #include "DIE.h" #include "llvm/Constants.h" #include "llvm/Module.h" +#include "llvm/Instructions.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/MC/MCAsmInfo.h" @@ -24,12 +25,13 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/Target/Mangler.h" #include "llvm/Target/TargetData.h" -#include "llvm/Target/TargetFrameInfo.h" +#include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Analysis/DebugInfo.h" +#include "llvm/ADT/Statistic.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/CommandLine.h" @@ -38,7 +40,7 @@ #include "llvm/Support/ValueHandle.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/Timer.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Path.h" using namespace llvm; static cl::opt PrintDbgScope("print-dbgscope", cl::Hidden, @@ -52,6 +54,10 @@ static cl::opt UnknownLocations("use-unknown-locations", cl::Hidden, cl::desc("Make an absense of debug location information explicit."), cl::init(false)); +#ifndef NDEBUG +STATISTIC(BlocksWithoutLineNo, "Number of blocks without any line number"); +#endif + namespace { const char *DWARFGroupName = "DWARF Emission"; const char *DbgTimerName = "DWARF Debug Writer"; @@ -507,8 +513,9 @@ void DwarfDebug::addSourceLine(DIE *Die, DIVariable V) { return; unsigned Line = V.getLineNumber(); - unsigned FileID = GetOrCreateSourceID(V.getContext().getDirectory(), - V.getContext().getFilename()); + if (Line == 0) + return; + unsigned FileID = GetOrCreateSourceID(V.getContext().getFilename()); assert(FileID && "Invalid file id"); addUInt(Die, dwarf::DW_AT_decl_file, 0, FileID); addUInt(Die, dwarf::DW_AT_decl_line, 0, Line); @@ -522,8 +529,9 @@ void DwarfDebug::addSourceLine(DIE *Die, DIGlobalVariable G) { return; unsigned Line = G.getLineNumber(); - unsigned FileID = GetOrCreateSourceID(G.getContext().getDirectory(), - G.getContext().getFilename()); + if (Line == 0) + return; + unsigned FileID = GetOrCreateSourceID(G.getContext().getFilename()); assert(FileID && "Invalid file id"); addUInt(Die, dwarf::DW_AT_decl_file, 0, FileID); addUInt(Die, dwarf::DW_AT_decl_line, 0, Line); @@ -542,8 +550,7 @@ void DwarfDebug::addSourceLine(DIE *Die, DISubprogram SP) { unsigned Line = SP.getLineNumber(); if (!SP.getContext().Verify()) return; - unsigned FileID = GetOrCreateSourceID(SP.getDirectory(), - SP.getFilename()); + unsigned FileID = GetOrCreateSourceID(SP.getFilename()); assert(FileID && "Invalid file id"); addUInt(Die, dwarf::DW_AT_decl_file, 0, FileID); addUInt(Die, dwarf::DW_AT_decl_line, 0, Line); @@ -557,10 +564,9 @@ void DwarfDebug::addSourceLine(DIE *Die, DIType Ty) { return; unsigned Line = Ty.getLineNumber(); - if (!Ty.getContext().Verify()) + if (Line == 0 || !Ty.getContext().Verify()) return; - unsigned FileID = GetOrCreateSourceID(Ty.getContext().getDirectory(), - Ty.getContext().getFilename()); + unsigned FileID = GetOrCreateSourceID(Ty.getFilename()); assert(FileID && "Invalid file id"); addUInt(Die, dwarf::DW_AT_decl_file, 0, FileID); addUInt(Die, dwarf::DW_AT_decl_line, 0, Line); @@ -574,10 +580,11 @@ void DwarfDebug::addSourceLine(DIE *Die, DINameSpace NS) { return; unsigned Line = NS.getLineNumber(); + if (Line == 0) + return; StringRef FN = NS.getFilename(); - StringRef Dir = NS.getDirectory(); - unsigned FileID = GetOrCreateSourceID(Dir, FN); + unsigned FileID = GetOrCreateSourceID(FN); assert(FileID && "Invalid file id"); addUInt(Die, dwarf::DW_AT_decl_file, 0, FileID); addUInt(Die, dwarf::DW_AT_decl_line, 0, Line); @@ -588,8 +595,8 @@ void DwarfDebug::addSourceLine(DIE *Die, DINameSpace NS) { void DwarfDebug::addVariableAddress(DbgVariable *&DV, DIE *Die, int64_t FI) { MachineLocation Location; unsigned FrameReg; - const TargetRegisterInfo *RI = Asm->TM.getRegisterInfo(); - int Offset = RI->getFrameIndexReference(*Asm->MF, FI, FrameReg); + const TargetFrameLowering *TFI = Asm->TM.getFrameLowering(); + int Offset = TFI->getFrameIndexReference(*Asm->MF, FI, FrameReg); Location.set(FrameReg, Offset); if (DV->variableHasComplexAddress()) @@ -620,8 +627,7 @@ void DwarfDebug::addComplexAddress(DbgVariable *&DV, DIE *Die, if (Reg < 32) { addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_reg0 + Reg); } else { - Reg = Reg - dwarf::DW_OP_reg0; - addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_breg0 + Reg); + addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_regx); addUInt(Block, 0, dwarf::DW_FORM_udata, Reg); } } else { @@ -760,8 +766,7 @@ void DwarfDebug::addBlockByrefAddress(DbgVariable *&DV, DIE *Die, if (Reg < 32) addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_reg0 + Reg); else { - Reg = Reg - dwarf::DW_OP_reg0; - addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_breg0 + Reg); + addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_regx); addUInt(Block, 0, dwarf::DW_FORM_udata, Reg); } } else { @@ -812,6 +817,15 @@ void DwarfDebug::addAddress(DIE *Die, unsigned Attribute, unsigned Reg = RI->getDwarfRegNum(Location.getReg(), false); DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); + if (RI->getFrameRegister(*Asm->MF) == Location.getReg() + && Location.getOffset()) { + // If variable offset is based in frame register then use fbreg. + addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_fbreg); + addSInt(Block, 0, dwarf::DW_FORM_sdata, Location.getOffset()); + addBlock(Die, Attribute, 0, Block); + return; + } + if (Location.isReg()) { if (Reg < 32) { addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_reg0 + Reg); @@ -834,35 +848,28 @@ void DwarfDebug::addAddress(DIE *Die, unsigned Attribute, } /// addRegisterAddress - Add register location entry in variable DIE. -bool DwarfDebug::addRegisterAddress(DIE *Die, const MCSymbol *VS, - const MachineOperand &MO) { +bool DwarfDebug::addRegisterAddress(DIE *Die, const MachineOperand &MO) { assert (MO.isReg() && "Invalid machine operand!"); if (!MO.getReg()) return false; MachineLocation Location; Location.set(MO.getReg()); addAddress(Die, dwarf::DW_AT_location, Location); - if (VS) - addLabel(Die, dwarf::DW_AT_start_scope, dwarf::DW_FORM_addr, VS); return true; } /// addConstantValue - Add constant value entry in variable DIE. -bool DwarfDebug::addConstantValue(DIE *Die, const MCSymbol *VS, - const MachineOperand &MO) { +bool DwarfDebug::addConstantValue(DIE *Die, const MachineOperand &MO) { assert (MO.isImm() && "Invalid machine operand!"); DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); unsigned Imm = MO.getImm(); addUInt(Block, 0, dwarf::DW_FORM_udata, Imm); addBlock(Die, dwarf::DW_AT_const_value, 0, Block); - if (VS) - addLabel(Die, dwarf::DW_AT_start_scope, dwarf::DW_FORM_addr, VS); return true; } /// addConstantFPValue - Add constant value entry in variable DIE. -bool DwarfDebug::addConstantFPValue(DIE *Die, const MCSymbol *VS, - const MachineOperand &MO) { +bool DwarfDebug::addConstantFPValue(DIE *Die, const MachineOperand &MO) { assert (MO.isFPImm() && "Invalid machine operand!"); DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); APFloat FPImm = MO.getFPImm()->getValueAPF(); @@ -883,11 +890,42 @@ bool DwarfDebug::addConstantFPValue(DIE *Die, const MCSymbol *VS, (unsigned char)0xFF & FltPtr[Start]); addBlock(Die, dwarf::DW_AT_const_value, 0, Block); - if (VS) - addLabel(Die, dwarf::DW_AT_start_scope, dwarf::DW_FORM_addr, VS); return true; } +/// addConstantValue - Add constant value entry in variable DIE. +bool DwarfDebug::addConstantValue(DIE *Die, ConstantInt *CI, + bool Unsigned) { + if (CI->getBitWidth() <= 64) { + if (Unsigned) + addUInt(Die, dwarf::DW_AT_const_value, dwarf::DW_FORM_udata, + CI->getZExtValue()); + else + addSInt(Die, dwarf::DW_AT_const_value, dwarf::DW_FORM_sdata, + CI->getSExtValue()); + return true; + } + + DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); + + // Get the raw data form of the large APInt. + const APInt Val = CI->getValue(); + const char *Ptr = (const char*)Val.getRawData(); + + int NumBytes = Val.getBitWidth() / 8; // 8 bits per byte. + bool LittleEndian = Asm->getTargetData().isLittleEndian(); + int Incr = (LittleEndian ? 1 : -1); + int Start = (LittleEndian ? 0 : NumBytes - 1); + int Stop = (LittleEndian ? NumBytes : -1); + + // Output the constant to DWARF one byte at a time. + for (; Start != Stop; Start += Incr) + addUInt(Block, 0, dwarf::DW_FORM_data1, + (unsigned char)0xFF & Ptr[Start]); + + addBlock(Die, dwarf::DW_AT_const_value, 0, Block); + return true; +} /// addToContextOwner - Add Die into the list of its context owner's children. void DwarfDebug::addToContextOwner(DIE *Die, DIDescriptor Context) { @@ -898,8 +936,7 @@ void DwarfDebug::addToContextOwner(DIE *Die, DIDescriptor Context) { DIE *ContextDIE = getOrCreateNameSpace(DINameSpace(Context)); ContextDIE->addChild(Die); } else if (Context.isSubprogram()) { - DIE *ContextDIE = createSubprogramDIE(DISubprogram(Context), - /*MakeDecl=*/false); + DIE *ContextDIE = createSubprogramDIE(DISubprogram(Context)); ContextDIE->addChild(Die); } else if (DIE *ContextDIE = getCompileUnit(Context)->getDIE(Context)) ContextDIE->addChild(Die); @@ -1033,16 +1070,23 @@ void DwarfDebug::constructTypeDIE(DIE &Buffer, DICompositeType CTy) { DIDescriptor RTy = Elements.getElement(0); addType(&Buffer, DIType(RTy)); - // Add prototype flag. - addUInt(&Buffer, dwarf::DW_AT_prototyped, dwarf::DW_FORM_flag, 1); - + bool isPrototyped = true; // Add arguments. for (unsigned i = 1, N = Elements.getNumElements(); i < N; ++i) { - DIE *Arg = new DIE(dwarf::DW_TAG_formal_parameter); DIDescriptor Ty = Elements.getElement(i); - addType(Arg, DIType(Ty)); - Buffer.addChild(Arg); + if (Ty.isUnspecifiedParameter()) { + DIE *Arg = new DIE(dwarf::DW_TAG_unspecified_parameters); + Buffer.addChild(Arg); + isPrototyped = false; + } else { + DIE *Arg = new DIE(dwarf::DW_TAG_formal_parameter); + addType(Arg, DIType(Ty)); + Buffer.addChild(Arg); + } } + // Add prototype flag. + if (isPrototyped) + addUInt(&Buffer, dwarf::DW_AT_prototyped, dwarf::DW_FORM_flag, 1); } break; case dwarf::DW_TAG_structure_type: @@ -1060,8 +1104,21 @@ void DwarfDebug::constructTypeDIE(DIE &Buffer, DICompositeType CTy) { for (unsigned i = 0; i < N; ++i) { DIDescriptor Element = Elements.getElement(i); DIE *ElemDie = NULL; - if (Element.isSubprogram()) + if (Element.isSubprogram()) { + DISubprogram SP(Element); ElemDie = createSubprogramDIE(DISubprogram(Element)); + if (SP.isProtected()) + addUInt(ElemDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_flag, + dwarf::DW_ACCESS_protected); + else if (SP.isPrivate()) + addUInt(ElemDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_flag, + dwarf::DW_ACCESS_private); + else + addUInt(ElemDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_flag, + dwarf::DW_ACCESS_public); + if (SP.isExplicit()) + addUInt(ElemDie, dwarf::DW_AT_explicit, dwarf::DW_FORM_flag, 1); + } else if (Element.isVariable()) { DIVariable DV(Element); ElemDie = new DIE(dwarf::DW_TAG_variable); @@ -1094,6 +1151,21 @@ void DwarfDebug::constructTypeDIE(DIE &Buffer, DICompositeType CTy) { DIDescriptor Context = CTy.getContext(); addToContextOwner(&Buffer, Context); } + + if (Tag == dwarf::DW_TAG_class_type) { + DIArray TParams = CTy.getTemplateParams(); + unsigned N = TParams.getNumElements(); + // Add template parameters. + for (unsigned i = 0; i < N; ++i) { + DIDescriptor Element = TParams.getElement(i); + if (Element.isTemplateTypeParameter()) + Buffer.addChild(getOrCreateTemplateTypeParameterDIE( + DITemplateTypeParameter(Element))); + else if (Element.isTemplateValueParameter()) + Buffer.addChild(getOrCreateTemplateValueParameterDIE( + DITemplateValueParameter(Element))); + } + } break; } default: @@ -1124,6 +1196,38 @@ void DwarfDebug::constructTypeDIE(DIE &Buffer, DICompositeType CTy) { } } +/// getOrCreateTemplateTypeParameterDIE - Find existing DIE or create new DIE +/// for the given DITemplateTypeParameter. +DIE * +DwarfDebug::getOrCreateTemplateTypeParameterDIE(DITemplateTypeParameter TP) { + CompileUnit *TypeCU = getCompileUnit(TP); + DIE *ParamDIE = TypeCU->getDIE(TP); + if (ParamDIE) + return ParamDIE; + + ParamDIE = new DIE(dwarf::DW_TAG_template_type_parameter); + addType(ParamDIE, TP.getType()); + addString(ParamDIE, dwarf::DW_AT_name, dwarf::DW_FORM_string, TP.getName()); + return ParamDIE; +} + +/// getOrCreateTemplateValueParameterDIE - Find existing DIE or create new DIE +/// for the given DITemplateValueParameter. +DIE * +DwarfDebug::getOrCreateTemplateValueParameterDIE(DITemplateValueParameter TPV) { + CompileUnit *TVCU = getCompileUnit(TPV); + DIE *ParamDIE = TVCU->getDIE(TPV); + if (ParamDIE) + return ParamDIE; + + ParamDIE = new DIE(dwarf::DW_TAG_template_value_parameter); + addType(ParamDIE, TPV.getType()); + addString(ParamDIE, dwarf::DW_AT_name, dwarf::DW_FORM_string, TPV.getName()); + addUInt(ParamDIE, dwarf::DW_AT_const_value, dwarf::DW_FORM_udata, + TPV.getValue()); + return ParamDIE; +} + /// constructSubrangeDIE - Construct subrange DIE from DISubrange. void DwarfDebug::constructSubrangeDIE(DIE &Buffer, DISubrange SR, DIE *IndexTy){ int64_t L = SR.getLo(); @@ -1258,7 +1362,8 @@ DIE *DwarfDebug::createMemberDIE(DIDerivedType DT) { else if (DT.isPrivate()) addUInt(MemberDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_flag, dwarf::DW_ACCESS_private); - else if (DT.getTag() == dwarf::DW_TAG_inheritance) + // Otherwise C++ member and base classes are considered public. + else if (DT.getCompileUnit().getLanguage() == dwarf::DW_LANG_C_plus_plus) addUInt(MemberDie, dwarf::DW_AT_accessibility, dwarf::DW_FORM_flag, dwarf::DW_ACCESS_public); if (DT.isVirtual()) @@ -1268,7 +1373,7 @@ DIE *DwarfDebug::createMemberDIE(DIDerivedType DT) { } /// createSubprogramDIE - Create new DIE using SP. -DIE *DwarfDebug::createSubprogramDIE(DISubprogram SP, bool MakeDecl) { +DIE *DwarfDebug::createSubprogramDIE(DISubprogram SP) { CompileUnit *SPCU = getCompileUnit(SP); DIE *SPDie = SPCU->getDIE(SP); if (SPDie) @@ -1286,10 +1391,7 @@ DIE *DwarfDebug::createSubprogramDIE(DISubprogram SP, bool MakeDecl) { addSourceLine(SPDie, SP); - // Add prototyped tag, if C or ObjC. - unsigned Lang = SP.getCompileUnit().getLanguage(); - if (Lang == dwarf::DW_LANG_C99 || Lang == dwarf::DW_LANG_C89 || - Lang == dwarf::DW_LANG_ObjC) + if (SP.isPrototyped()) addUInt(SPDie, dwarf::DW_AT_prototyped, dwarf::DW_FORM_flag, 1); // Add Return Type. @@ -1307,13 +1409,13 @@ DIE *DwarfDebug::createSubprogramDIE(DISubprogram SP, bool MakeDecl) { addUInt(SPDie, dwarf::DW_AT_virtuality, dwarf::DW_FORM_flag, VK); DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_constu); - addUInt(Block, 0, dwarf::DW_FORM_data1, SP.getVirtualIndex()); + addUInt(Block, 0, dwarf::DW_FORM_udata, SP.getVirtualIndex()); addBlock(SPDie, dwarf::DW_AT_vtable_elem_location, 0, Block); ContainingTypeMap.insert(std::make_pair(SPDie, SP.getContainingType())); } - if (MakeDecl || !SP.isDefinition()) { + if (!SP.isDefinition()) { addUInt(SPDie, dwarf::DW_AT_declaration, dwarf::DW_FORM_flag, 1); // Add arguments. Do not add arguments for subprogram definition. They will @@ -1603,6 +1705,8 @@ DIE *DwarfDebug::constructVariableDIE(DbgVariable *DV, DbgScope *Scope) { if (Tag == dwarf::DW_TAG_formal_parameter && DV->getType().isArtificial()) addUInt(VariableDie, dwarf::DW_AT_artificial, dwarf::DW_FORM_flag, 1); + else if (DIVariable(DV->getVariable()).isArtificial()) + addUInt(VariableDie, dwarf::DW_AT_artificial, dwarf::DW_FORM_flag, 1); if (Scope->isAbstractScope()) { DV->setDIE(VariableDie); @@ -1625,7 +1729,6 @@ DIE *DwarfDebug::constructVariableDIE(DbgVariable *DV, DbgScope *Scope) { DbgVariableToDbgInstMap.find(DV); if (DVI != DbgVariableToDbgInstMap.end()) { const MachineInstr *DVInsn = DVI->second; - const MCSymbol *DVLabel = findVariableLabel(DV); bool updated = false; // FIXME : Handle getNumOperands != 3 if (DVInsn->getNumOperands() == 3) { @@ -1637,20 +1740,17 @@ DIE *DwarfDebug::constructVariableDIE(DbgVariable *DV, DbgScope *Scope) { addVariableAddress(DV, VariableDie, DVInsn->getOperand(1).getImm()); updated = true; } else - updated = addRegisterAddress(VariableDie, DVLabel, RegOp); + updated = addRegisterAddress(VariableDie, RegOp); } else if (DVInsn->getOperand(0).isImm()) - updated = addConstantValue(VariableDie, DVLabel, DVInsn->getOperand(0)); + updated = addConstantValue(VariableDie, DVInsn->getOperand(0)); else if (DVInsn->getOperand(0).isFPImm()) updated = - addConstantFPValue(VariableDie, DVLabel, DVInsn->getOperand(0)); + addConstantFPValue(VariableDie, DVInsn->getOperand(0)); } else { MachineLocation Location = Asm->getDebugValueLocation(DVInsn); if (Location.getReg()) { addAddress(VariableDie, dwarf::DW_AT_location, Location); - if (DVLabel) - addLabel(VariableDie, dwarf::DW_AT_start_scope, dwarf::DW_FORM_addr, - DVLabel); updated = true; } } @@ -1700,6 +1800,16 @@ DIE *DwarfDebug::constructScopeDIE(DbgScope *Scope) { if (!Scope || !Scope->getScopeNode()) return NULL; + SmallVector Children; + // Collect lexical scope childrens first. + const SmallVector &Variables = Scope->getDbgVariables(); + for (unsigned i = 0, N = Variables.size(); i < N; ++i) + if (DIE *Variable = constructVariableDIE(Variables[i], Scope)) + Children.push_back(Variable); + const SmallVector &Scopes = Scope->getScopes(); + for (unsigned j = 0, M = Scopes.size(); j < M; ++j) + if (DIE *Nested = constructScopeDIE(Scopes[j])) + Children.push_back(Nested); DIScope DS(Scope->getScopeNode()); DIE *ScopeDIE = NULL; if (Scope->getInlinedAt()) @@ -1715,26 +1825,19 @@ DIE *DwarfDebug::constructScopeDIE(DbgScope *Scope) { else ScopeDIE = updateSubprogramScopeDIE(DS); } - else + else { + // There is no need to emit empty lexical block DIE. + if (Children.empty()) + return NULL; ScopeDIE = constructLexicalScopeDIE(Scope); - if (!ScopeDIE) return NULL; - - // Add variables to scope. - const SmallVector &Variables = Scope->getDbgVariables(); - for (unsigned i = 0, N = Variables.size(); i < N; ++i) { - DIE *VariableDIE = constructVariableDIE(Variables[i], Scope); - if (VariableDIE) - ScopeDIE->addChild(VariableDIE); } + + if (!ScopeDIE) return NULL; - // Add nested scopes. - const SmallVector &Scopes = Scope->getScopes(); - for (unsigned j = 0, M = Scopes.size(); j < M; ++j) { - // Define the Scope debug information entry. - DIE *NestedDIE = constructScopeDIE(Scopes[j]); - if (NestedDIE) - ScopeDIE->addChild(NestedDIE); - } + // Add children + for (SmallVector::iterator I = Children.begin(), + E = Children.end(); I != E; ++I) + ScopeDIE->addChild(*I); if (DS.isSubprogram()) addPubTypes(DISubprogram(DS)); @@ -1746,37 +1849,21 @@ DIE *DwarfDebug::constructScopeDIE(DbgScope *Scope) { /// source file names. If none currently exists, create a new id and insert it /// in the SourceIds map. This can update DirectoryNames and SourceFileNames /// maps as well. -unsigned DwarfDebug::GetOrCreateSourceID(StringRef DirName, StringRef FileName){ - unsigned DId; - assert (DirName.empty() == false && "Invalid directory name!"); - StringMap::iterator DI = DirectoryIdMap.find(DirName); - if (DI != DirectoryIdMap.end()) { - DId = DI->getValue(); - } else { - DId = DirectoryNames.size() + 1; - DirectoryIdMap[DirName] = DId; - DirectoryNames.push_back(DirName); - } +unsigned DwarfDebug::GetOrCreateSourceID(StringRef FileName){ + // If FE did not provide a file name, then assume stdin. + if (FileName.empty()) + return GetOrCreateSourceID(""); - unsigned FId; - StringMap::iterator FI = SourceFileIdMap.find(FileName); - if (FI != SourceFileIdMap.end()) { - FId = FI->getValue(); - } else { - FId = SourceFileNames.size() + 1; - SourceFileIdMap[FileName] = FId; - SourceFileNames.push_back(FileName); - } + StringMapEntry &Entry = SourceIdMap.GetOrCreateValue(FileName); + if (Entry.getValue()) + return Entry.getValue(); - DenseMap, unsigned>::iterator SI = - SourceIdMap.find(std::make_pair(DId, FId)); - if (SI != SourceIdMap.end()) - return SI->second; + unsigned SrcId = SourceIdMap.size(); + Entry.setValue(SrcId); - unsigned SrcId = SourceIds.size() + 1; // DW_AT_decl_file cannot be 0. - SourceIdMap[std::make_pair(DId, FId)] = SrcId; - SourceIds.push_back(std::make_pair(DId, FId)); + // Print out a .file directive to specify files for .loc directives. + Asm->OutStreamer.EmitDwarfFileDirective(SrcId, FileName); return SrcId; } @@ -1802,7 +1889,7 @@ void DwarfDebug::constructCompileUnit(const MDNode *N) { DICompileUnit DIUnit(N); StringRef FN = DIUnit.getFilename(); StringRef Dir = DIUnit.getDirectory(); - unsigned ID = GetOrCreateSourceID(Dir, FN); + unsigned ID = GetOrCreateSourceID(FN); DIE *Die = new DIE(dwarf::DW_TAG_compile_unit); addString(Die, dwarf::DW_AT_producer, dwarf::DW_FORM_string, @@ -1886,6 +1973,32 @@ static bool isUnsignedDIType(DIType Ty) { return false; } +// Return const exprssion if value is a GEP to access merged global +// constant. e.g. +// i8* getelementptr ({ i8, i8, i8, i8 }* @_MergedGlobals, i32 0, i32 0) +static const ConstantExpr *getMergedGlobalExpr(const Value *V) { + const ConstantExpr *CE = dyn_cast_or_null(V); + if (!CE || CE->getNumOperands() != 3 || + CE->getOpcode() != Instruction::GetElementPtr) + return NULL; + + // First operand points to a global value. + if (!isa(CE->getOperand(0))) + return NULL; + + // Second operand is zero. + const ConstantInt *CI = + dyn_cast_or_null(CE->getOperand(1)); + if (!CI || !CI->isZero()) + return NULL; + + // Third operand is offset. + if (!isa(CE->getOperand(2))) + return NULL; + + return CE; +} + /// constructGlobalVariableDIE - Construct global variable DIE. void DwarfDebug::constructGlobalVariableDIE(const MDNode *N) { DIGlobalVariable GV(N); @@ -1952,16 +2065,22 @@ void DwarfDebug::constructGlobalVariableDIE(const MDNode *N) { } else { addBlock(VariableDIE, dwarf::DW_AT_location, 0, Block); } - } else if (Constant *C = GV.getConstant()) { - if (ConstantInt *CI = dyn_cast(C)) { - if (isUnsignedDIType(GTy)) - addUInt(VariableDIE, dwarf::DW_AT_const_value, dwarf::DW_FORM_udata, - CI->getZExtValue()); - else - addSInt(VariableDIE, dwarf::DW_AT_const_value, dwarf::DW_FORM_sdata, - CI->getSExtValue()); - } + } else if (ConstantInt *CI = + dyn_cast_or_null(GV.getConstant())) + addConstantValue(VariableDIE, CI, isUnsignedDIType(GTy)); + else if (const ConstantExpr *CE = getMergedGlobalExpr(N->getOperand(11))) { + // GV is a merged global. + DIEBlock *Block = new (DIEValueAllocator) DIEBlock(); + addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_addr); + addLabel(Block, 0, dwarf::DW_FORM_udata, + Asm->Mang->getSymbol(cast(CE->getOperand(0)))); + ConstantInt *CII = cast(CE->getOperand(2)); + addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_constu); + addUInt(Block, 0, dwarf::DW_FORM_udata, CII->getZExtValue()); + addUInt(Block, 0, dwarf::DW_FORM_data1, dwarf::DW_OP_plus); + addBlock(VariableDIE, dwarf::DW_AT_location, 0, Block); } + return; } @@ -2043,25 +2162,12 @@ void DwarfDebug::beginModule(Module *M) { for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) getOrCreateTypeDIE(DIType(NMD->getOperand(i))); + if (NamedMDNode *NMD = M->getNamedMetadata("llvm.dbg.ty")) + for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) + getOrCreateTypeDIE(DIType(NMD->getOperand(i))); + // Prime section data. SectionMap.insert(Asm->getObjFileLowering().getTextSection()); - - // Print out .file directives to specify files for .loc directives. These are - // printed out early so that they precede any .loc directives. - if (Asm->MAI->hasDotLocAndDotFile()) { - for (unsigned i = 1, e = getNumSourceIds()+1; i != e; ++i) { - // Remember source id starts at 1. - std::pair Id = getSourceDirectoryAndFileIds(i); - // FIXME: don't use sys::path for this! This should not depend on the - // host. - sys::Path FullPath(getSourceDirectoryName(Id.first)); - bool AppendOk = - FullPath.appendComponent(getSourceFileName(Id.second)); - assert(AppendOk && "Could not append filename to directory!"); - AppendOk = false; - Asm->OutStreamer.EmitDwarfFileDirective(i, FullPath.str()); - } - } } /// endModule - Emit all Dwarf sections that should come after the content. @@ -2081,8 +2187,7 @@ void DwarfDebug::endModule() { StringRef FName = SP.getLinkageName(); if (FName.empty()) FName = SP.getName(); - NamedMDNode *NMD = - M->getNamedMetadata(Twine("llvm.dbg.lv.", getRealLinkageName(FName))); + NamedMDNode *NMD = getFnSpecificMDNode(*(MMI->getModule()), FName); if (!NMD) continue; unsigned E = NMD->getNumOperands(); if (!E) continue; @@ -2152,9 +2257,6 @@ void DwarfDebug::endModule() { // Corresponding abbreviations into a abbrev section. emitAbbreviations(); - // Emit source line correspondence into a debug line section. - emitDebugLines(); - // Emit info into a debug pubnames section. emitDebugPubNames(); @@ -2242,15 +2344,6 @@ DwarfDebug::collectVariableInfoFromMMITable(const MachineFunction * MF, } } -/// isDbgValueInUndefinedReg - Return true if debug value, encoded by -/// DBG_VALUE instruction, is in undefined reg. -static bool isDbgValueInUndefinedReg(const MachineInstr *MI) { - assert (MI->isDebugValue() && "Invalid DBG_VALUE machine instruction!"); - if (MI->getOperand(0).isReg() && !MI->getOperand(0).getReg()) - return true; - return false; -} - /// isDbgValueInDefinedReg - Return true if debug value, encoded by /// DBG_VALUE instruction, is in a defined reg. static bool isDbgValueInDefinedReg(const MachineInstr *MI) { @@ -2275,7 +2368,7 @@ DwarfDebug::collectVariableInfo(const MachineFunction *MF, for (MachineBasicBlock::const_iterator II = I->begin(), IE = I->end(); II != IE; ++II) { const MachineInstr *MInsn = II; - if (!MInsn->isDebugValue() || isDbgValueInUndefinedReg(MInsn)) + if (!MInsn->isDebugValue()) continue; DbgValues.push_back(MInsn); } @@ -2297,19 +2390,18 @@ DwarfDebug::collectVariableInfo(const MachineFunction *MF, ME = DbgValues.end(); MI != ME; ++MI) { const MDNode *Var = (*MI)->getOperand((*MI)->getNumOperands()-1).getMetadata(); - if (Var == DV && isDbgValueInDefinedReg(*MI) && + if (Var == DV && !PrevMI->isIdenticalTo(*MI)) MultipleValues.push_back(*MI); PrevMI = *MI; } - DbgScope *Scope = findDbgScope(MInsn); - bool CurFnArg = false; + DbgScope *Scope = NULL; if (DV.getTag() == dwarf::DW_TAG_arg_variable && DISubprogram(DV.getContext()).describes(MF->getFunction())) - CurFnArg = true; - if (!Scope && CurFnArg) Scope = CurrentFnDbgScope; + else + Scope = findDbgScope(MInsn); // If variable scope is not found then skip this variable. if (!Scope) continue; @@ -2317,8 +2409,6 @@ DwarfDebug::collectVariableInfo(const MachineFunction *MF, Processed.insert(DV); DbgVariable *RegVar = new DbgVariable(DV); Scope->addVariable(RegVar); - if (!CurFnArg) - DbgVariableLabelsMap[RegVar] = getLabelBeforeInsn(MInsn); if (DbgVariable *AbsVar = findAbstractVariable(DV, MInsn->getDebugLoc())) { DbgVariableToDbgInstMap[AbsVar] = MInsn; VarToAbstractVarMap[RegVar] = AbsVar; @@ -2375,10 +2465,7 @@ DwarfDebug::collectVariableInfo(const MachineFunction *MF, // Collect info for variables that were optimized out. const Function *F = MF->getFunction(); - const Module *M = F->getParent(); - if (NamedMDNode *NMD = - M->getNamedMetadata(Twine("llvm.dbg.lv.", - getRealLinkageName(F->getName())))) { + if (NamedMDNode *NMD = getFnSpecificMDNode(*(F->getParent()), F->getName())) { for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { DIVariable DV(cast(NMD->getOperand(i))); if (!DV || !Processed.insert(DV)) @@ -2409,8 +2496,8 @@ const MCSymbol *DwarfDebug::getLabelAfterInsn(const MachineInstr *MI) { return I->second; } -/// beginScope - Process beginning of a scope. -void DwarfDebug::beginScope(const MachineInstr *MI) { +/// beginInstruction - Process beginning of an instruction. +void DwarfDebug::beginInstruction(const MachineInstr *MI) { if (InsnNeedsLabel.count(MI) == 0) { LabelsBeforeInsn[MI] = PrevLabel; return; @@ -2444,8 +2531,8 @@ void DwarfDebug::beginScope(const MachineInstr *MI) { assert (0 && "Instruction is not processed!"); } -/// endScope - Process end of a scope. -void DwarfDebug::endScope(const MachineInstr *MI) { +/// endInstruction - Process end of an instruction. +void DwarfDebug::endInstruction(const MachineInstr *MI) { if (InsnsEndScopeSet.count(MI) != 0) { // Emit a label if this instruction ends a scope. MCSymbol *Label = MMI->getContext().CreateTempSymbol(); @@ -2624,6 +2711,10 @@ bool DwarfDebug::extractScopeInformation() { continue; } + // Ignore DBG_VALUE. It does not contribute any instruction in output. + if (MInsn->isDebugValue()) + continue; + if (RangeBeginMI) { // If we have alread seen a beginning of a instruction range and // current instruction scope does not match scope of first instruction @@ -2727,12 +2818,37 @@ static DebugLoc FindFirstDebugLoc(const MachineFunction *MF) { return DebugLoc(); } +#ifndef NDEBUG +/// CheckLineNumbers - Count basicblocks whose instructions do not have any +/// line number information. +static void CheckLineNumbers(const MachineFunction *MF) { + for (MachineFunction::const_iterator I = MF->begin(), E = MF->end(); + I != E; ++I) { + bool FoundLineNo = false; + for (MachineBasicBlock::const_iterator II = I->begin(), IE = I->end(); + II != IE; ++II) { + const MachineInstr *MI = II; + if (!MI->getDebugLoc().isUnknown()) { + FoundLineNo = true; + break; + } + } + if (!FoundLineNo && I->size()) + ++BlocksWithoutLineNo; + } +} +#endif + /// beginFunction - Gather pre-function debug information. Assumes being /// emitted immediately after the function entry point. void DwarfDebug::beginFunction(const MachineFunction *MF) { if (!MMI->hasDebugInfo()) return; if (!extractScopeInformation()) return; +#ifndef NDEBUG + CheckLineNumbers(MF); +#endif + FunctionBeginSym = Asm->GetTempSymbol("func_begin", Asm->getFunctionNumber()); // Assumes in correct section after the entry point. @@ -2775,16 +2891,14 @@ void DwarfDebug::beginFunction(const MachineFunction *MF) { DIVariable DV(MI->getOperand(MI->getNumOperands() - 1).getMetadata()); if (!DV.Verify()) continue; // If DBG_VALUE is for a local variable then it needs a label. - if (DV.getTag() != dwarf::DW_TAG_arg_variable - && isDbgValueInUndefinedReg(MI) == false) + if (DV.getTag() != dwarf::DW_TAG_arg_variable) InsnNeedsLabel.insert(MI); // DBG_VALUE for inlined functions argument needs a label. else if (!DISubprogram(getDISubprogram(DV.getContext())). describes(MF->getFunction())) InsnNeedsLabel.insert(MI); // DBG_VALUE indicating argument location change needs a label. - else if (isDbgValueInUndefinedReg(MI) == false - && !ProcessedArgs.insert(DV)) + else if (!ProcessedArgs.insert(DV)) InsnNeedsLabel.insert(MI); } else { // If location is unknown then instruction needs a location only if @@ -2820,17 +2934,6 @@ void DwarfDebug::endFunction(const MachineFunction *MF) { SmallPtrSet ProcessedVars; collectVariableInfo(MF, ProcessedVars); - // Get function line info. - if (!Lines.empty()) { - // Get section line info. - unsigned ID = SectionMap.insert(Asm->getCurrentSection()); - if (SectionSourceLines.size() < ID) SectionSourceLines.resize(ID); - std::vector &SectionLineInfos = SectionSourceLines[ID-1]; - // Append the function info to section info. - SectionLineInfos.insert(SectionLineInfos.end(), - Lines.begin(), Lines.end()); - } - // Construct abstract scopes. for (SmallVector::iterator AI = AbstractScopesList.begin(), AE = AbstractScopesList.end(); AI != AE; ++AI) { @@ -2840,10 +2943,8 @@ void DwarfDebug::endFunction(const MachineFunction *MF) { StringRef FName = SP.getLinkageName(); if (FName.empty()) FName = SP.getName(); - const Module *M = MF->getFunction()->getParent(); - if (NamedMDNode *NMD = - M->getNamedMetadata(Twine("llvm.dbg.lv.", - getRealLinkageName(FName)))) { + if (NamedMDNode *NMD = + getFnSpecificMDNode(*(MF->getFunction()->getParent()), FName)) { for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { DIVariable DV(cast(NMD->getOperand(i))); if (!DV || !ProcessedVars.insert(DV)) @@ -2875,7 +2976,6 @@ void DwarfDebug::endFunction(const MachineFunction *MF) { DbgVariableToFrameIndexMap.clear(); VarToAbstractVarMap.clear(); DbgVariableToDbgInstMap.clear(); - DbgVariableLabelsMap.clear(); DeleteContainerSeconds(DbgScopeMap); InsnsEndScopeSet.clear(); ConcreteScopes.clear(); @@ -2884,7 +2984,6 @@ void DwarfDebug::endFunction(const MachineFunction *MF) { AbstractVariables.clear(); LabelsBeforeInsn.clear(); LabelsAfterInsn.clear(); - Lines.clear(); PrevLabel = NULL; } @@ -2906,15 +3005,6 @@ bool DwarfDebug::findVariableFrameIndex(const DbgVariable *V, int *FI) { return true; } -/// findVariableLabel - Find MCSymbol for the variable. -const MCSymbol *DwarfDebug::findVariableLabel(const DbgVariable *V) { - DenseMap::iterator I - = DbgVariableLabelsMap.find(V); - if (I == DbgVariableLabelsMap.end()) - return NULL; - else return I->second; -} - /// findDbgScope - Find DbgScope for the debug loc attached with an /// instruction. DbgScope *DwarfDebug::findDbgScope(const MachineInstr *MInsn) { @@ -2940,7 +3030,6 @@ DbgScope *DwarfDebug::findDbgScope(const MachineInstr *MInsn) { /// the source line list. MCSymbol *DwarfDebug::recordSourceLine(unsigned Line, unsigned Col, const MDNode *S) { - StringRef Dir; StringRef Fn; unsigned Src = 1; @@ -2949,25 +3038,26 @@ MCSymbol *DwarfDebug::recordSourceLine(unsigned Line, unsigned Col, if (Scope.isCompileUnit()) { DICompileUnit CU(S); - Dir = CU.getDirectory(); Fn = CU.getFilename(); + } else if (Scope.isFile()) { + DIFile F(S); + Fn = F.getFilename(); } else if (Scope.isSubprogram()) { DISubprogram SP(S); - Dir = SP.getDirectory(); Fn = SP.getFilename(); } else if (Scope.isLexicalBlock()) { DILexicalBlock DB(S); - Dir = DB.getDirectory(); Fn = DB.getFilename(); } else assert(0 && "Unexpected scope info"); - Src = GetOrCreateSourceID(Dir, Fn); + Src = GetOrCreateSourceID(Fn); } - MCSymbol *Label = MMI->getContext().CreateTempSymbol(); - Lines.push_back(SrcLineInfo(Line, Col, Src, Label)); + Asm->OutStreamer.EmitDwarfLocDirective(Src, Line, Col, DWARF2_FLAG_IS_STMT, + 0, 0); + MCSymbol *Label = MMI->getContext().CreateTempSymbol(); Asm->OutStreamer.EmitLabel(Label); return Label; } @@ -3151,6 +3241,14 @@ void DwarfDebug::emitDIE(DIE *Die) { Values[i]->EmitValue(Asm, Form); break; } + case dwarf::DW_AT_accessibility: { + if (Asm->isVerbose()) { + DIEInteger *V = cast(Values[i]); + Asm->OutStreamer.AddComment(dwarf::AccessibilityString(V->getValue())); + } + Values[i]->EmitValue(Asm, Form); + break; + } default: // Emit an attribute using the defined form. Values[i]->EmitValue(Asm, Form); @@ -3270,185 +3368,6 @@ void DwarfDebug::emitEndOfLineMatrix(unsigned SectionEnd) { Asm->EmitInt8(1); } -/// emitDebugLines - Emit source line information. -/// -void DwarfDebug::emitDebugLines() { - // If the target is using .loc/.file, the assembler will be emitting the - // .debug_line table automatically. - if (Asm->MAI->hasDotLocAndDotFile()) - return; - - // Minimum line delta, thus ranging from -10..(255-10). - const int MinLineDelta = -(dwarf::DW_LNS_fixed_advance_pc + 1); - // Maximum line delta, thus ranging from -10..(255-10). - const int MaxLineDelta = 255 + MinLineDelta; - - // Start the dwarf line section. - Asm->OutStreamer.SwitchSection( - Asm->getObjFileLowering().getDwarfLineSection()); - - // Construct the section header. - Asm->OutStreamer.AddComment("Length of Source Line Info"); - Asm->EmitLabelDifference(Asm->GetTempSymbol("line_end"), - Asm->GetTempSymbol("line_begin"), 4); - Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("line_begin")); - - Asm->OutStreamer.AddComment("DWARF version number"); - Asm->EmitInt16(dwarf::DWARF_VERSION); - - Asm->OutStreamer.AddComment("Prolog Length"); - Asm->EmitLabelDifference(Asm->GetTempSymbol("line_prolog_end"), - Asm->GetTempSymbol("line_prolog_begin"), 4); - Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("line_prolog_begin")); - - Asm->OutStreamer.AddComment("Minimum Instruction Length"); - Asm->EmitInt8(1); - Asm->OutStreamer.AddComment("Default is_stmt_start flag"); - Asm->EmitInt8(1); - Asm->OutStreamer.AddComment("Line Base Value (Special Opcodes)"); - Asm->EmitInt8(MinLineDelta); - Asm->OutStreamer.AddComment("Line Range Value (Special Opcodes)"); - Asm->EmitInt8(MaxLineDelta); - Asm->OutStreamer.AddComment("Special Opcode Base"); - Asm->EmitInt8(-MinLineDelta); - - // Line number standard opcode encodings argument count - Asm->OutStreamer.AddComment("DW_LNS_copy arg count"); - Asm->EmitInt8(0); - Asm->OutStreamer.AddComment("DW_LNS_advance_pc arg count"); - Asm->EmitInt8(1); - Asm->OutStreamer.AddComment("DW_LNS_advance_line arg count"); - Asm->EmitInt8(1); - Asm->OutStreamer.AddComment("DW_LNS_set_file arg count"); - Asm->EmitInt8(1); - Asm->OutStreamer.AddComment("DW_LNS_set_column arg count"); - Asm->EmitInt8(1); - Asm->OutStreamer.AddComment("DW_LNS_negate_stmt arg count"); - Asm->EmitInt8(0); - Asm->OutStreamer.AddComment("DW_LNS_set_basic_block arg count"); - Asm->EmitInt8(0); - Asm->OutStreamer.AddComment("DW_LNS_const_add_pc arg count"); - Asm->EmitInt8(0); - Asm->OutStreamer.AddComment("DW_LNS_fixed_advance_pc arg count"); - Asm->EmitInt8(1); - - // Emit directories. - for (unsigned DI = 1, DE = getNumSourceDirectories()+1; DI != DE; ++DI) { - const std::string &Dir = getSourceDirectoryName(DI); - if (Asm->isVerbose()) Asm->OutStreamer.AddComment("Directory"); - Asm->OutStreamer.EmitBytes(StringRef(Dir.c_str(), Dir.size()+1), 0); - } - - Asm->OutStreamer.AddComment("End of directories"); - Asm->EmitInt8(0); - - // Emit files. - for (unsigned SI = 1, SE = getNumSourceIds()+1; SI != SE; ++SI) { - // Remember source id starts at 1. - std::pair Id = getSourceDirectoryAndFileIds(SI); - const std::string &FN = getSourceFileName(Id.second); - if (Asm->isVerbose()) Asm->OutStreamer.AddComment("Source"); - Asm->OutStreamer.EmitBytes(StringRef(FN.c_str(), FN.size()+1), 0); - - Asm->EmitULEB128(Id.first, "Directory #"); - Asm->EmitULEB128(0, "Mod date"); - Asm->EmitULEB128(0, "File size"); - } - - Asm->OutStreamer.AddComment("End of files"); - Asm->EmitInt8(0); - - Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("line_prolog_end")); - - // A sequence for each text section. - unsigned SecSrcLinesSize = SectionSourceLines.size(); - - for (unsigned j = 0; j < SecSrcLinesSize; ++j) { - // Isolate current sections line info. - const std::vector &LineInfos = SectionSourceLines[j]; - - // Dwarf assumes we start with first line of first source file. - unsigned Source = 1; - unsigned Line = 1; - - // Construct rows of the address, source, line, column matrix. - for (unsigned i = 0, N = LineInfos.size(); i < N; ++i) { - const SrcLineInfo &LineInfo = LineInfos[i]; - MCSymbol *Label = LineInfo.getLabel(); - if (!Label->isDefined()) continue; // Not emitted, in dead code. - - if (Asm->isVerbose()) { - std::pair SrcID = - getSourceDirectoryAndFileIds(LineInfo.getSourceID()); - Asm->OutStreamer.AddComment(Twine(getSourceDirectoryName(SrcID.first)) + - "/" + - Twine(getSourceFileName(SrcID.second)) + - ":" + Twine(LineInfo.getLine())); - } - - // Define the line address. - Asm->OutStreamer.AddComment("Extended Op"); - Asm->EmitInt8(0); - Asm->OutStreamer.AddComment("Op size"); - Asm->EmitInt8(Asm->getTargetData().getPointerSize() + 1); - - Asm->OutStreamer.AddComment("DW_LNE_set_address"); - Asm->EmitInt8(dwarf::DW_LNE_set_address); - - Asm->OutStreamer.AddComment("Location label"); - Asm->OutStreamer.EmitSymbolValue(Label, - Asm->getTargetData().getPointerSize(), - 0/*AddrSpace*/); - - // If change of source, then switch to the new source. - if (Source != LineInfo.getSourceID()) { - Source = LineInfo.getSourceID(); - Asm->OutStreamer.AddComment("DW_LNS_set_file"); - Asm->EmitInt8(dwarf::DW_LNS_set_file); - Asm->EmitULEB128(Source, "New Source"); - } - - // If change of line. - if (Line != LineInfo.getLine()) { - // Determine offset. - int Offset = LineInfo.getLine() - Line; - int Delta = Offset - MinLineDelta; - - // Update line. - Line = LineInfo.getLine(); - - // If delta is small enough and in range... - if (Delta >= 0 && Delta < (MaxLineDelta - 1)) { - // ... then use fast opcode. - Asm->OutStreamer.AddComment("Line Delta"); - Asm->EmitInt8(Delta - MinLineDelta); - } else { - // ... otherwise use long hand. - Asm->OutStreamer.AddComment("DW_LNS_advance_line"); - Asm->EmitInt8(dwarf::DW_LNS_advance_line); - Asm->EmitSLEB128(Offset, "Line Offset"); - Asm->OutStreamer.AddComment("DW_LNS_copy"); - Asm->EmitInt8(dwarf::DW_LNS_copy); - } - } else { - // Copy the previous row (different address or source) - Asm->OutStreamer.AddComment("DW_LNS_copy"); - Asm->EmitInt8(dwarf::DW_LNS_copy); - } - } - - emitEndOfLineMatrix(j + 1); - } - - if (SecSrcLinesSize == 0) - // Because we're emitting a debug_line section, we still need a line - // table. The linker and friends expect it to exist. If there's nothing to - // put into it, emit an empty table. - emitEndOfLineMatrix(1); - - Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("line_end")); -} - /// emitCommonDebugFrame - Emit common frame info into a debug frame section. /// void DwarfDebug::emitCommonDebugFrame() { @@ -3456,8 +3375,8 @@ void DwarfDebug::emitCommonDebugFrame() { return; int stackGrowth = Asm->getTargetData().getPointerSize(); - if (Asm->TM.getFrameInfo()->getStackGrowthDirection() == - TargetFrameInfo::StackGrowsDown) + if (Asm->TM.getFrameLowering()->getStackGrowthDirection() == + TargetFrameLowering::StackGrowsDown) stackGrowth *= -1; // Start the dwarf frame section. @@ -3480,10 +3399,11 @@ void DwarfDebug::emitCommonDebugFrame() { Asm->EmitSLEB128(stackGrowth, "CIE Data Alignment Factor"); Asm->OutStreamer.AddComment("CIE RA Column"); const TargetRegisterInfo *RI = Asm->TM.getRegisterInfo(); + const TargetFrameLowering *TFI = Asm->TM.getFrameLowering(); Asm->EmitInt8(RI->getDwarfRegNum(RI->getRARegister(), false)); std::vector Moves; - RI->getInitialFrameState(Moves); + TFI->getInitialFrameState(Moves); Asm->EmitFrameMoves(Moves, 0, false); @@ -3667,6 +3587,14 @@ void DwarfDebug::emitDebugLoc() { if (DotDebugLocEntries.empty()) return; + for (SmallVector::iterator + I = DotDebugLocEntries.begin(), E = DotDebugLocEntries.end(); + I != E; ++I) { + DotDebugLocEntry &Entry = *I; + if (I + 1 != DotDebugLocEntries.end()) + Entry.Merge(I+1); + } + // Start the dwarf loc section. Asm->OutStreamer.SwitchSection( Asm->getObjFileLowering().getDwarfLocSection()); @@ -3676,7 +3604,8 @@ void DwarfDebug::emitDebugLoc() { for (SmallVector::iterator I = DotDebugLocEntries.begin(), E = DotDebugLocEntries.end(); I != E; ++I, ++index) { - DotDebugLocEntry Entry = *I; + DotDebugLocEntry &Entry = *I; + if (Entry.isMerged()) continue; if (Entry.isEmpty()) { Asm->OutStreamer.EmitIntValue(0, Size, /*addrspace*/0); Asm->OutStreamer.EmitIntValue(0, Size, /*addrspace*/0); diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.h b/lib/CodeGen/AsmPrinter/DwarfDebug.h index f0ff3bc71699..7df0510fbfba 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.h +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -23,6 +23,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/UniqueVector.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/DebugLoc.h" namespace llvm { @@ -51,6 +52,8 @@ class DIType; class DINameSpace; class DISubrange; class DICompositeType; +class DITemplateTypeParameter; +class DITemplateValueParameter; //===----------------------------------------------------------------------===// /// SrcLineInfo - This class is used to record source line correspondence. @@ -71,6 +74,28 @@ public: MCSymbol *getLabel() const { return Label; } }; +/// DotDebugLocEntry - This struct describes location entries emitted in +/// .debug_loc section. +typedef struct DotDebugLocEntry { + const MCSymbol *Begin; + const MCSymbol *End; + MachineLocation Loc; + bool Merged; + DotDebugLocEntry() : Begin(0), End(0), Merged(false) {} + DotDebugLocEntry(const MCSymbol *B, const MCSymbol *E, MachineLocation &L) + : Begin(B), End(E), Loc(L), Merged(false) {} + /// Empty entries are also used as a trigger to emit temp label. Such + /// labels are referenced is used to find debug_loc offset for a given DIE. + bool isEmpty() { return Begin == 0 && End == 0; } + bool isMerged() { return Merged; } + void Merge(DotDebugLocEntry *Next) { + if (!(Begin && Loc == Next->Loc && End == Next->Begin)) + return; + Next->Begin = Begin; + Merged = true; + } +} DotDebugLocEntry; + class DwarfDebug { /// Asm - Target of Dwarf emission. AsmPrinter *Asm; @@ -93,30 +118,9 @@ class DwarfDebug { /// std::vector Abbreviations; - /// DirectoryIdMap - Directory name to directory id map. - /// - StringMap DirectoryIdMap; - - /// DirectoryNames - A list of directory names. - SmallVector DirectoryNames; - - /// SourceFileIdMap - Source file name to source file id map. - /// - StringMap SourceFileIdMap; - - /// SourceFileNames - A list of source file names. - SmallVector SourceFileNames; - /// SourceIdMap - Source id map, i.e. pair of directory id and source file /// id mapped to a unique id. - DenseMap, unsigned> SourceIdMap; - - /// SourceIds - Reverse map from source id to directory id + file id pair. - /// - SmallVector, 8> SourceIds; - - /// Lines - List of source line correspondence. - std::vector Lines; + StringMap SourceIdMap; /// DIEBlocks - A list of all the DIEBlocks in use. std::vector DIEBlocks; @@ -135,10 +139,6 @@ class DwarfDebug { /// UniqueVector SectionMap; - /// SectionSourceLines - Tracks line numbers per text section. - /// - std::vector > SectionSourceLines; - // CurrentFnDbgScope - Top level scope for the current function. // DbgScope *CurrentFnDbgScope; @@ -175,23 +175,6 @@ class DwarfDebug { /// machine instruction. DenseMap DbgVariableToDbgInstMap; - /// DbgVariableLabelsMap - Maps DbgVariable to corresponding MCSymbol. - DenseMap DbgVariableLabelsMap; - - /// DotDebugLocEntry - This struct describes location entries emitted in - /// .debug_loc section. - typedef struct DotDebugLocEntry { - const MCSymbol *Begin; - const MCSymbol *End; - MachineLocation Loc; - DotDebugLocEntry() : Begin(0), End(0) {} - DotDebugLocEntry(const MCSymbol *B, const MCSymbol *E, - MachineLocation &L) : Begin(B), End(E), Loc(L) {} - /// Empty entries are also used as a trigger to emit temp label. Such - /// labels are referenced is used to find debug_loc offset for a given DIE. - bool isEmpty() { return Begin == 0 && End == 0; } - } DotDebugLocEntry; - /// DotDebugLocEntries - Collection of DotDebugLocEntry. SmallVector DotDebugLocEntries; @@ -265,35 +248,10 @@ class DwarfDebug { DIEInteger *DIEIntegerOne; private: - - /// getSourceDirectoryAndFileIds - Return the directory and file ids that - /// maps to the source id. Source id starts at 1. - std::pair - getSourceDirectoryAndFileIds(unsigned SId) const { - return SourceIds[SId-1]; - } - - /// getNumSourceDirectories - Return the number of source directories in the - /// debug info. - unsigned getNumSourceDirectories() const { - return DirectoryNames.size(); - } - - /// getSourceDirectoryName - Return the name of the directory corresponding - /// to the id. - const std::string &getSourceDirectoryName(unsigned Id) const { - return DirectoryNames[Id - 1]; - } - - /// getSourceFileName - Return the name of the source file corresponding - /// to the id. - const std::string &getSourceFileName(unsigned Id) const { - return SourceFileNames[Id - 1]; - } /// getNumSourceIds - Return the number of unique source ids. unsigned getNumSourceIds() const { - return SourceIds.size(); + return SourceIdMap.size(); } /// assignAbbrevNumber - Define a unique number for the abbreviation. @@ -349,13 +307,14 @@ private: const MachineLocation &Location); /// addRegisterAddress - Add register location entry in variable DIE. - bool addRegisterAddress(DIE *Die, const MCSymbol *VS, const MachineOperand &MO); + bool addRegisterAddress(DIE *Die, const MachineOperand &MO); /// addConstantValue - Add constant value entry in variable DIE. - bool addConstantValue(DIE *Die, const MCSymbol *VS, const MachineOperand &MO); + bool addConstantValue(DIE *Die, const MachineOperand &MO); + bool addConstantValue(DIE *Die, ConstantInt *CI, bool Unsigned); /// addConstantFPValue - Add constant value entry in variable DIE. - bool addConstantFPValue(DIE *Die, const MCSymbol *VS, const MachineOperand &MO); + bool addConstantFPValue(DIE *Die, const MachineOperand &MO); /// addComplexAddress - Start with the address based on the location provided, /// and generate the DWARF information necessary to find the actual variable @@ -393,6 +352,14 @@ private: /// given DIType. DIE *getOrCreateTypeDIE(DIType Ty); + /// getOrCreateTemplateTypeParameterDIE - Find existing DIE or create new DIE + /// for the given DITemplateTypeParameter. + DIE *getOrCreateTemplateTypeParameterDIE(DITemplateTypeParameter TP); + + /// getOrCreateTemplateValueParameterDIE - Find existing DIE or create new DIE + /// for the given DITemplateValueParameter. + DIE *getOrCreateTemplateValueParameterDIE(DITemplateValueParameter TVP); + void addPubTypes(DISubprogram SP); /// constructTypeDIE - Construct basic type die from DIBasicType. @@ -421,7 +388,7 @@ private: DIE *createMemberDIE(DIDerivedType DT); /// createSubprogramDIE - Create new DIE using SP. - DIE *createSubprogramDIE(DISubprogram SP, bool MakeDecl = false); + DIE *createSubprogramDIE(DISubprogram SP); /// getOrCreateDbgScope - Create DbgScope for the scope. DbgScope *getOrCreateDbgScope(const MDNode *Scope, const MDNode *InlinedAt); @@ -481,10 +448,6 @@ private: /// void emitEndOfLineMatrix(unsigned SectionEnd); - /// emitDebugLines - Emit source line information. - /// - void emitDebugLines(); - /// emitCommonDebugFrame - Emit common frame info into a debug frame section. /// void emitCommonDebugFrame(); @@ -543,9 +506,8 @@ private: /// GetOrCreateSourceID - Look up the source id with the given directory and /// source file names. If none currently exists, create a new id and insert it - /// in the SourceIds map. This can update DirectoryNames and SourceFileNames - /// maps as well. - unsigned GetOrCreateSourceID(StringRef DirName, StringRef FileName); + /// in the SourceIds map. + unsigned GetOrCreateSourceID(StringRef FullName); /// constructCompileUnit - Create new CompileUnit for the given /// metadata node with tag DW_TAG_compile_unit. @@ -565,12 +527,6 @@ private: /// the source line list. MCSymbol *recordSourceLine(unsigned Line, unsigned Col, const MDNode *Scope); - /// getSourceLineCount - Return the number of source lines in the debug - /// info. - unsigned getSourceLineCount() const { - return Lines.size(); - } - /// recordVariableFrameIndex - Record a variable's index. void recordVariableFrameIndex(const DbgVariable *V, int Index); @@ -578,9 +534,6 @@ private: /// is found. Update FI to hold value of the index. bool findVariableFrameIndex(const DbgVariable *V, int *FI); - /// findVariableLabel - Find MCSymbol for the variable. - const MCSymbol *findVariableLabel(const DbgVariable *V); - /// findDbgScope - Find DbgScope for the debug loc attached with an /// instruction. DbgScope *findDbgScope(const MachineInstr *MI); @@ -630,11 +583,11 @@ public: /// getLabelAfterInsn - Return Label immediately following the instruction. const MCSymbol *getLabelAfterInsn(const MachineInstr *MI); - /// beginScope - Process beginning of a scope. - void beginScope(const MachineInstr *MI); + /// beginInstruction - Process beginning of an instruction. + void beginInstruction(const MachineInstr *MI); - /// endScope - Prcess end of a scope. - void endScope(const MachineInstr *MI); + /// endInstruction - Prcess end of an instruction. + void endInstruction(const MachineInstr *MI); }; } // End of namespace llvm diff --git a/lib/CodeGen/AsmPrinter/DwarfException.cpp b/lib/CodeGen/AsmPrinter/DwarfException.cpp index 86a368831e0e..967a2783da14 100644 --- a/lib/CodeGen/AsmPrinter/DwarfException.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfException.cpp @@ -26,7 +26,7 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/Target/Mangler.h" #include "llvm/Target/TargetData.h" -#include "llvm/Target/TargetFrameInfo.h" +#include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" @@ -39,238 +39,10 @@ using namespace llvm; DwarfException::DwarfException(AsmPrinter *A) - : Asm(A), MMI(Asm->MMI), shouldEmitTable(false), shouldEmitMoves(false), - shouldEmitTableModule(false), shouldEmitMovesModule(false) {} + : Asm(A), MMI(Asm->MMI) {} DwarfException::~DwarfException() {} -/// EmitCIE - Emit a Common Information Entry (CIE). This holds information that -/// is shared among many Frame Description Entries. There is at least one CIE -/// in every non-empty .debug_frame section. -void DwarfException::EmitCIE(const Function *PersonalityFn, unsigned Index) { - // Size and sign of stack growth. - int stackGrowth = Asm->getTargetData().getPointerSize(); - if (Asm->TM.getFrameInfo()->getStackGrowthDirection() == - TargetFrameInfo::StackGrowsDown) - stackGrowth *= -1; - - const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); - - // Begin eh frame section. - Asm->OutStreamer.SwitchSection(TLOF.getEHFrameSection()); - - MCSymbol *EHFrameSym; - if (TLOF.isFunctionEHFrameSymbolPrivate()) - EHFrameSym = Asm->GetTempSymbol("EH_frame", Index); - else - EHFrameSym = Asm->OutContext.GetOrCreateSymbol(Twine("EH_frame") + - Twine(Index)); - Asm->OutStreamer.EmitLabel(EHFrameSym); - - Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("section_eh_frame", Index)); - - // Define base labels. - Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_frame_common", Index)); - - // Define the eh frame length. - Asm->OutStreamer.AddComment("Length of Common Information Entry"); - Asm->EmitLabelDifference(Asm->GetTempSymbol("eh_frame_common_end", Index), - Asm->GetTempSymbol("eh_frame_common_begin", Index), - 4); - - // EH frame header. - Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_frame_common_begin",Index)); - Asm->OutStreamer.AddComment("CIE Identifier Tag"); - Asm->OutStreamer.EmitIntValue(0, 4/*size*/, 0/*addrspace*/); - Asm->OutStreamer.AddComment("DW_CIE_VERSION"); - Asm->OutStreamer.EmitIntValue(dwarf::DW_CIE_VERSION, 1/*size*/, 0/*addr*/); - - // The personality presence indicates that language specific information will - // show up in the eh frame. Find out how we are supposed to lower the - // personality function reference: - - unsigned LSDAEncoding = TLOF.getLSDAEncoding(); - unsigned FDEEncoding = TLOF.getFDEEncoding(); - unsigned PerEncoding = TLOF.getPersonalityEncoding(); - - char Augmentation[6] = { 0 }; - unsigned AugmentationSize = 0; - char *APtr = Augmentation + 1; - - if (PersonalityFn) { - // There is a personality function. - *APtr++ = 'P'; - AugmentationSize += 1 + Asm->GetSizeOfEncodedValue(PerEncoding); - } - - if (UsesLSDA[Index]) { - // An LSDA pointer is in the FDE augmentation. - *APtr++ = 'L'; - ++AugmentationSize; - } - - if (FDEEncoding != dwarf::DW_EH_PE_absptr) { - // A non-default pointer encoding for the FDE. - *APtr++ = 'R'; - ++AugmentationSize; - } - - if (APtr != Augmentation + 1) - Augmentation[0] = 'z'; - - Asm->OutStreamer.AddComment("CIE Augmentation"); - Asm->OutStreamer.EmitBytes(StringRef(Augmentation, strlen(Augmentation)+1),0); - - // Round out reader. - Asm->EmitULEB128(1, "CIE Code Alignment Factor"); - Asm->EmitSLEB128(stackGrowth, "CIE Data Alignment Factor"); - Asm->OutStreamer.AddComment("CIE Return Address Column"); - - const TargetRegisterInfo *RI = Asm->TM.getRegisterInfo(); - Asm->EmitInt8(RI->getDwarfRegNum(RI->getRARegister(), true)); - - if (Augmentation[0]) { - Asm->EmitULEB128(AugmentationSize, "Augmentation Size"); - - // If there is a personality, we need to indicate the function's location. - if (PersonalityFn) { - Asm->EmitEncodingByte(PerEncoding, "Personality"); - Asm->OutStreamer.AddComment("Personality"); - Asm->EmitReference(PersonalityFn, PerEncoding); - } - if (UsesLSDA[Index]) - Asm->EmitEncodingByte(LSDAEncoding, "LSDA"); - if (FDEEncoding != dwarf::DW_EH_PE_absptr) - Asm->EmitEncodingByte(FDEEncoding, "FDE"); - } - - // Indicate locations of general callee saved registers in frame. - std::vector Moves; - RI->getInitialFrameState(Moves); - Asm->EmitFrameMoves(Moves, 0, true); - - // On Darwin the linker honors the alignment of eh_frame, which means it must - // be 8-byte on 64-bit targets to match what gcc does. Otherwise you get - // holes which confuse readers of eh_frame. - Asm->EmitAlignment(Asm->getTargetData().getPointerSize() == 4 ? 2 : 3); - Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_frame_common_end", Index)); -} - -/// EmitFDE - Emit the Frame Description Entry (FDE) for the function. -void DwarfException::EmitFDE(const FunctionEHFrameInfo &EHFrameInfo) { - assert(!EHFrameInfo.function->hasAvailableExternallyLinkage() && - "Should not emit 'available externally' functions at all"); - - const Function *TheFunc = EHFrameInfo.function; - const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); - - unsigned LSDAEncoding = TLOF.getLSDAEncoding(); - unsigned FDEEncoding = TLOF.getFDEEncoding(); - - Asm->OutStreamer.SwitchSection(TLOF.getEHFrameSection()); - - // Externally visible entry into the functions eh frame info. If the - // corresponding function is static, this should not be externally visible. - if (!TheFunc->hasLocalLinkage() && TLOF.isFunctionEHSymbolGlobal()) - Asm->OutStreamer.EmitSymbolAttribute(EHFrameInfo.FunctionEHSym,MCSA_Global); - - // If corresponding function is weak definition, this should be too. - if (TheFunc->isWeakForLinker() && Asm->MAI->getWeakDefDirective()) - Asm->OutStreamer.EmitSymbolAttribute(EHFrameInfo.FunctionEHSym, - MCSA_WeakDefinition); - - // If corresponding function is hidden, this should be too. - if (TheFunc->hasHiddenVisibility()) - if (MCSymbolAttr HiddenAttr = Asm->MAI->getHiddenVisibilityAttr()) - Asm->OutStreamer.EmitSymbolAttribute(EHFrameInfo.FunctionEHSym, - HiddenAttr); - - // If there are no calls then you can't unwind. This may mean we can omit the - // EH Frame, but some environments do not handle weak absolute symbols. If - // UnwindTablesMandatory is set we cannot do this optimization; the unwind - // info is to be available for non-EH uses. - if (!EHFrameInfo.adjustsStack && !UnwindTablesMandatory && - (!TheFunc->isWeakForLinker() || - !Asm->MAI->getWeakDefDirective() || - TLOF.getSupportsWeakOmittedEHFrame())) { - Asm->OutStreamer.EmitAssignment(EHFrameInfo.FunctionEHSym, - MCConstantExpr::Create(0, Asm->OutContext)); - // This name has no connection to the function, so it might get - // dead-stripped when the function is not, erroneously. Prohibit - // dead-stripping unconditionally. - if (Asm->MAI->hasNoDeadStrip()) - Asm->OutStreamer.EmitSymbolAttribute(EHFrameInfo.FunctionEHSym, - MCSA_NoDeadStrip); - } else { - Asm->OutStreamer.EmitLabel(EHFrameInfo.FunctionEHSym); - - // EH frame header. - Asm->OutStreamer.AddComment("Length of Frame Information Entry"); - Asm->EmitLabelDifference( - Asm->GetTempSymbol("eh_frame_end", EHFrameInfo.Number), - Asm->GetTempSymbol("eh_frame_begin", EHFrameInfo.Number), 4); - - Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_frame_begin", - EHFrameInfo.Number)); - - Asm->OutStreamer.AddComment("FDE CIE offset"); - Asm->EmitLabelDifference( - Asm->GetTempSymbol("eh_frame_begin", EHFrameInfo.Number), - Asm->GetTempSymbol("eh_frame_common", - EHFrameInfo.PersonalityIndex), 4); - - MCSymbol *EHFuncBeginSym = - Asm->GetTempSymbol("eh_func_begin", EHFrameInfo.Number); - - Asm->OutStreamer.AddComment("FDE initial location"); - Asm->EmitReference(EHFuncBeginSym, FDEEncoding); - - Asm->OutStreamer.AddComment("FDE address range"); - Asm->EmitLabelDifference(Asm->GetTempSymbol("eh_func_end", - EHFrameInfo.Number), - EHFuncBeginSym, - Asm->GetSizeOfEncodedValue(FDEEncoding)); - - // If there is a personality and landing pads then point to the language - // specific data area in the exception table. - if (MMI->getPersonalities()[0] != NULL) { - unsigned Size = Asm->GetSizeOfEncodedValue(LSDAEncoding); - - Asm->EmitULEB128(Size, "Augmentation size"); - Asm->OutStreamer.AddComment("Language Specific Data Area"); - if (EHFrameInfo.hasLandingPads) - Asm->EmitReference(Asm->GetTempSymbol("exception", EHFrameInfo.Number), - LSDAEncoding); - else - Asm->OutStreamer.EmitIntValue(0, Size/*size*/, 0/*addrspace*/); - - } else { - Asm->EmitULEB128(0, "Augmentation size"); - } - - // Indicate locations of function specific callee saved registers in frame. - Asm->EmitFrameMoves(EHFrameInfo.Moves, EHFuncBeginSym, true); - - // On Darwin the linker honors the alignment of eh_frame, which means it - // must be 8-byte on 64-bit targets to match what gcc does. Otherwise you - // get holes which confuse readers of eh_frame. - Asm->EmitAlignment(Asm->getTargetData().getPointerSize() == 4 ? 2 : 3); - Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_frame_end", - EHFrameInfo.Number)); - - // If the function is marked used, this table should be also. We cannot - // make the mark unconditional in this case, since retaining the table also - // retains the function in this case, and there is code around that depends - // on unused functions (calling undefined externals) being dead-stripped to - // link correctly. Yes, there really is. - if (MMI->isUsedFunction(EHFrameInfo.function)) - if (Asm->MAI->hasNoDeadStrip()) - Asm->OutStreamer.EmitSymbolAttribute(EHFrameInfo.FunctionEHSym, - MCSA_NoDeadStrip); - } - Asm->OutStreamer.AddBlankLine(); -} - /// SharedTypeIds - How many leading type ids two landing pads have in common. unsigned DwarfException::SharedTypeIds(const LandingPadInfo *L, const LandingPadInfo *R) { @@ -422,7 +194,7 @@ bool DwarfException::CallToNoUnwindFunction(const MachineInstr *MI) { const MachineOperand &MO = MI->getOperand(I); if (!MO.isGlobal()) continue; - + const Function *F = dyn_cast(MO.getGlobal()); if (F == 0) continue; @@ -430,7 +202,7 @@ bool DwarfException::CallToNoUnwindFunction(const MachineInstr *MI) { // Be conservative. If we have more than one function operand for this // call, then we can't make the assumption that it's the callee and // not a parameter to the call. - // + // // FIXME: Determine if there's a way to say that `F' is the callee or // parameter. MarkedNoUnwind = false; @@ -497,8 +269,7 @@ ComputeCallSiteTable(SmallVectorImpl &CallSites, // instruction between the previous try-range and this one may throw, // create a call-site entry with no landing pad for the region between the // try-ranges. - if (SawPotentiallyThrowing && - Asm->MAI->getExceptionHandlingType() == ExceptionHandling::Dwarf) { + if (SawPotentiallyThrowing && Asm->MAI->isExceptionHandlingDwarf()) { CallSiteEntry Site = { LastLabel, BeginLabel, 0, 0 }; CallSites.push_back(Site); PreviousIsInvoke = false; @@ -520,8 +291,7 @@ ComputeCallSiteTable(SmallVectorImpl &CallSites, }; // Try to merge with the previous call-site. SJLJ doesn't do this - if (PreviousIsInvoke && - Asm->MAI->getExceptionHandlingType() == ExceptionHandling::Dwarf) { + if (PreviousIsInvoke && Asm->MAI->isExceptionHandlingDwarf()) { CallSiteEntry &Prev = CallSites.back(); if (Site.PadLabel == Prev.PadLabel && Site.Action == Prev.Action) { // Extend the range of the previous entry. @@ -531,7 +301,7 @@ ComputeCallSiteTable(SmallVectorImpl &CallSites, } // Otherwise, create a new call-site. - if (Asm->MAI->getExceptionHandlingType() == ExceptionHandling::Dwarf) + if (Asm->MAI->isExceptionHandlingDwarf()) CallSites.push_back(Site); else { // SjLj EH must maintain the call sites in the order assigned @@ -549,8 +319,7 @@ ComputeCallSiteTable(SmallVectorImpl &CallSites, // If some instruction between the previous try-range and the end of the // function may throw, create a call-site entry with no landing pad for the // region following the try-range. - if (SawPotentiallyThrowing && - Asm->MAI->getExceptionHandlingType() == ExceptionHandling::Dwarf) { + if (SawPotentiallyThrowing && Asm->MAI->isExceptionHandlingDwarf()) { CallSiteEntry Site = { LastLabel, 0, 0, 0 }; CallSites.push_back(Site); } @@ -620,7 +389,7 @@ void DwarfException::EmitExceptionTable() { // Call sites. bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj; bool HaveTTData = IsSJLJ ? (!TypeInfos.empty() || !FilterIds.empty()) : true; - + unsigned CallSiteTableLength; if (IsSJLJ) CallSiteTableLength = 0; @@ -628,7 +397,7 @@ void DwarfException::EmitExceptionTable() { unsigned SiteStartSize = 4; // dwarf::DW_EH_PE_udata4 unsigned SiteLengthSize = 4; // dwarf::DW_EH_PE_udata4 unsigned LandingPadSize = 4; // dwarf::DW_EH_PE_udata4 - CallSiteTableLength = + CallSiteTableLength = CallSites.size() * (SiteStartSize + SiteLengthSize + LandingPadSize); } @@ -656,15 +425,15 @@ void DwarfException::EmitExceptionTable() { // mode, this reference will require a relocation by the dynamic linker. // // Because of this, we have a couple of options: - // + // // 1) If we are in -static mode, we can always use an absolute reference // from the LSDA, because the static linker will resolve it. - // + // // 2) Otherwise, if the LSDA section is writable, we can output the direct // reference to the typeinfo and allow the dynamic linker to relocate // it. Since it is in a writable section, the dynamic linker won't // have a problem. - // + // // 3) Finally, if we're in PIC mode and the LDSA section isn't writable, // we need to use some form of indirection. For example, on Darwin, // we can output a statically-relocatable reference to a dyld stub. The @@ -682,11 +451,14 @@ void DwarfException::EmitExceptionTable() { } // Begin the exception table. - Asm->OutStreamer.SwitchSection(LSDASection); + // Sometimes we want not to emit the data into separate section (e.g. ARM + // EHABI). In this case LSDASection will be NULL. + if (LSDASection) + Asm->OutStreamer.SwitchSection(LSDASection); Asm->EmitAlignment(2); // Emit the LSDA. - MCSymbol *GCCETSym = + MCSymbol *GCCETSym = Asm->OutContext.GetOrCreateSymbol(Twine("GCC_except_table")+ Twine(Asm->getFunctionNumber())); Asm->OutStreamer.EmitLabel(GCCETSym); @@ -764,7 +536,7 @@ void DwarfException::EmitExceptionTable() { } } else { // DWARF Exception handling - assert(Asm->MAI->getExceptionHandlingType() == ExceptionHandling::Dwarf); + assert(Asm->MAI->isExceptionHandlingDwarf()); // The call-site table is a list of all call sites that may throw an // exception (including C++ 'throw' statements) in the procedure @@ -793,23 +565,23 @@ void DwarfException::EmitExceptionTable() { for (SmallVectorImpl::const_iterator I = CallSites.begin(), E = CallSites.end(); I != E; ++I) { const CallSiteEntry &S = *I; - + MCSymbol *EHFuncBeginSym = Asm->GetTempSymbol("eh_func_begin", Asm->getFunctionNumber()); - + MCSymbol *BeginLabel = S.BeginLabel; if (BeginLabel == 0) BeginLabel = EHFuncBeginSym; MCSymbol *EndLabel = S.EndLabel; if (EndLabel == 0) EndLabel = Asm->GetTempSymbol("eh_func_end", Asm->getFunctionNumber()); - + // Offset of the call site relative to the previous call site, counted in // number of 16-byte bundles. The first call site is counted relative to // the start of the procedure fragment. Asm->OutStreamer.AddComment("Region start"); Asm->EmitLabelDifference(BeginLabel, EHFuncBeginSym, 4); - + Asm->OutStreamer.AddComment("Region length"); Asm->EmitLabelDifference(EndLabel, BeginLabel, 4); @@ -834,7 +606,7 @@ void DwarfException::EmitExceptionTable() { Asm->OutStreamer.AddComment("-- Action Record Table --"); Asm->OutStreamer.AddBlankLine(); } - + for (SmallVectorImpl::const_iterator I = Actions.begin(), E = Actions.end(); I != E; ++I) { const ActionEntry &Action = *I; @@ -888,73 +660,17 @@ void DwarfException::EmitExceptionTable() { /// EndModule - Emit all exception information that should come after the /// content. void DwarfException::EndModule() { - if (Asm->MAI->getExceptionHandlingType() != ExceptionHandling::Dwarf) - return; - - if (!shouldEmitMovesModule && !shouldEmitTableModule) - return; - - const std::vector &Personalities = MMI->getPersonalities(); - - for (unsigned I = 0, E = Personalities.size(); I < E; ++I) - EmitCIE(Personalities[I], I); - - for (std::vector::iterator - I = EHFrames.begin(), E = EHFrames.end(); I != E; ++I) - EmitFDE(*I); + assert(0 && "Should be implemented"); } /// BeginFunction - Gather pre-function exception information. Assumes it's /// being emitted immediately after the function entry point. void DwarfException::BeginFunction(const MachineFunction *MF) { - shouldEmitTable = shouldEmitMoves = false; - - // If any landing pads survive, we need an EH table. - shouldEmitTable = !MMI->getLandingPads().empty(); - - // See if we need frame move info. - shouldEmitMoves = - !Asm->MF->getFunction()->doesNotThrow() || UnwindTablesMandatory; - - if (shouldEmitMoves || shouldEmitTable) - // Assumes in correct section after the entry point. - Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_func_begin", - Asm->getFunctionNumber())); - - shouldEmitTableModule |= shouldEmitTable; - shouldEmitMovesModule |= shouldEmitMoves; + assert(0 && "Should be implemented"); } /// EndFunction - Gather and emit post-function exception information. /// void DwarfException::EndFunction() { - if (!shouldEmitMoves && !shouldEmitTable) return; - - Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_func_end", - Asm->getFunctionNumber())); - - // Record if this personality index uses a landing pad. - bool HasLandingPad = !MMI->getLandingPads().empty(); - UsesLSDA[MMI->getPersonalityIndex()] |= HasLandingPad; - - // Map all labels and get rid of any dead landing pads. - MMI->TidyLandingPads(); - - if (HasLandingPad) - EmitExceptionTable(); - - const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); - MCSymbol *FunctionEHSym = - Asm->GetSymbolWithGlobalValueBase(Asm->MF->getFunction(), ".eh", - TLOF.isFunctionEHFrameSymbolPrivate()); - - // Save EH frame information - EHFrames. - push_back(FunctionEHFrameInfo(FunctionEHSym, - Asm->getFunctionNumber(), - MMI->getPersonalityIndex(), - Asm->MF->getFrameInfo()->adjustsStack(), - !MMI->getLandingPads().empty(), - MMI->getFrameMoves(), - Asm->MF->getFunction())); + assert(0 && "Should be implemented"); } diff --git a/lib/CodeGen/AsmPrinter/DwarfException.h b/lib/CodeGen/AsmPrinter/DwarfException.h index bc311e67054e..a172e53f8ac7 100644 --- a/lib/CodeGen/AsmPrinter/DwarfException.h +++ b/lib/CodeGen/AsmPrinter/DwarfException.h @@ -35,60 +35,13 @@ class AsmPrinter; /// DwarfException - Emits Dwarf exception handling directives. /// class DwarfException { +protected: /// Asm - Target of Dwarf emission. AsmPrinter *Asm; /// MMI - Collected machine module information. MachineModuleInfo *MMI; - struct FunctionEHFrameInfo { - MCSymbol *FunctionEHSym; // L_foo.eh - unsigned Number; - unsigned PersonalityIndex; - bool adjustsStack; - bool hasLandingPads; - std::vector Moves; - const Function *function; - - FunctionEHFrameInfo(MCSymbol *EHSym, unsigned Num, unsigned P, - bool hC, bool hL, - const std::vector &M, - const Function *f): - FunctionEHSym(EHSym), Number(Num), PersonalityIndex(P), - adjustsStack(hC), hasLandingPads(hL), Moves(M), function (f) { } - }; - - std::vector EHFrames; - - /// UsesLSDA - Indicates whether an FDE that uses the CIE at the given index - /// uses an LSDA. If so, then we need to encode that information in the CIE's - /// augmentation. - DenseMap UsesLSDA; - - /// shouldEmitTable - Per-function flag to indicate if EH tables should - /// be emitted. - bool shouldEmitTable; - - /// shouldEmitMoves - Per-function flag to indicate if frame moves info - /// should be emitted. - bool shouldEmitMoves; - - /// shouldEmitTableModule - Per-module flag to indicate if EH tables - /// should be emitted. - bool shouldEmitTableModule; - - /// shouldEmitFrameModule - Per-module flag to indicate if frame moves - /// should be emitted. - bool shouldEmitMovesModule; - - /// EmitCIE - Emit a Common Information Entry (CIE). This holds information - /// that is shared among many Frame Description Entries. There is at least - /// one CIE in every non-empty .debug_frame section. - void EmitCIE(const Function *Personality, unsigned Index); - - /// EmitFDE - Emit the Frame Description Entry (FDE) for the function. - void EmitFDE(const FunctionEHFrameInfo &EHFrameInfo); - /// EmitExceptionTable - Emit landing pads and actions. /// /// The general organization of the table is complex, but the basic concepts @@ -172,18 +125,116 @@ public: // Main entry points. // DwarfException(AsmPrinter *A); - ~DwarfException(); + virtual ~DwarfException(); + + /// EndModule - Emit all exception information that should come after the + /// content. + virtual void EndModule(); + + /// BeginFunction - Gather pre-function exception information. Assumes being + /// emitted immediately after the function entry point. + virtual void BeginFunction(const MachineFunction *MF); + + /// EndFunction - Gather and emit post-function exception information. + virtual void EndFunction(); +}; + +class DwarfCFIException : public DwarfException { + /// shouldEmitTable - Per-function flag to indicate if EH tables should + /// be emitted. + bool shouldEmitTable; + + /// shouldEmitMoves - Per-function flag to indicate if frame moves info + /// should be emitted. + bool shouldEmitMoves; + + /// shouldEmitTableModule - Per-module flag to indicate if EH tables + /// should be emitted. + bool shouldEmitTableModule; +public: + //===--------------------------------------------------------------------===// + // Main entry points. + // + DwarfCFIException(AsmPrinter *A); + virtual ~DwarfCFIException(); + + /// EndModule - Emit all exception information that should come after the + /// content. + virtual void EndModule(); + + /// BeginFunction - Gather pre-function exception information. Assumes being + /// emitted immediately after the function entry point. + virtual void BeginFunction(const MachineFunction *MF); + + /// EndFunction - Gather and emit post-function exception information. + virtual void EndFunction(); +}; + +class DwarfTableException : public DwarfException { + /// shouldEmitTable - Per-function flag to indicate if EH tables should + /// be emitted. + bool shouldEmitTable; + + /// shouldEmitMoves - Per-function flag to indicate if frame moves info + /// should be emitted. + bool shouldEmitMoves; + + /// shouldEmitTableModule - Per-module flag to indicate if EH tables + /// should be emitted. + bool shouldEmitTableModule; + + /// shouldEmitMovesModule - Per-module flag to indicate if frame moves + /// should be emitted. + bool shouldEmitMovesModule; + + struct FunctionEHFrameInfo { + MCSymbol *FunctionEHSym; // L_foo.eh + unsigned Number; + unsigned PersonalityIndex; + bool adjustsStack; + bool hasLandingPads; + std::vector Moves; + const Function *function; + + FunctionEHFrameInfo(MCSymbol *EHSym, unsigned Num, unsigned P, + bool hC, bool hL, + const std::vector &M, + const Function *f): + FunctionEHSym(EHSym), Number(Num), PersonalityIndex(P), + adjustsStack(hC), hasLandingPads(hL), Moves(M), function (f) { } + }; + + std::vector EHFrames; + + /// UsesLSDA - Indicates whether an FDE that uses the CIE at the given index + /// uses an LSDA. If so, then we need to encode that information in the CIE's + /// augmentation. + DenseMap UsesLSDA; + + /// EmitCIE - Emit a Common Information Entry (CIE). This holds information + /// that is shared among many Frame Description Entries. There is at least + /// one CIE in every non-empty .debug_frame section. + void EmitCIE(const Function *Personality, unsigned Index); + + /// EmitFDE - Emit the Frame Description Entry (FDE) for the function. + void EmitFDE(const FunctionEHFrameInfo &EHFrameInfo); +public: + //===--------------------------------------------------------------------===// + // Main entry points. + // + DwarfTableException(AsmPrinter *A); + virtual ~DwarfTableException(); /// EndModule - Emit all exception information that should come after the /// content. - void EndModule(); + virtual void EndModule(); /// BeginFunction - Gather pre-function exception information. Assumes being /// emitted immediately after the function entry point. - void BeginFunction(const MachineFunction *MF); + virtual void BeginFunction(const MachineFunction *MF); /// EndFunction - Gather and emit post-function exception information. - void EndFunction(); + virtual void EndFunction(); }; } // End of namespace llvm diff --git a/lib/CodeGen/AsmPrinter/DwarfTableException.cpp b/lib/CodeGen/AsmPrinter/DwarfTableException.cpp new file mode 100644 index 000000000000..751901183cd0 --- /dev/null +++ b/lib/CodeGen/AsmPrinter/DwarfTableException.cpp @@ -0,0 +1,349 @@ +//===-- CodeGen/AsmPrinter/DwarfTableException.cpp - Dwarf Exception Impl --==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains support for writing DWARF exception info into asm files. +// The implementation emits all the necessary tables "by hands". +// +//===----------------------------------------------------------------------===// + +#include "DwarfException.h" +#include "llvm/Module.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineLocation.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Target/Mangler.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetFrameLowering.h" +#include "llvm/Target/TargetLoweringObjectFile.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Twine.h" +using namespace llvm; + +DwarfTableException::DwarfTableException(AsmPrinter *A) + : DwarfException(A), + shouldEmitTable(false), shouldEmitMoves(false), + shouldEmitTableModule(false), shouldEmitMovesModule(false) {} + +DwarfTableException::~DwarfTableException() {} + +/// EmitCIE - Emit a Common Information Entry (CIE). This holds information that +/// is shared among many Frame Description Entries. There is at least one CIE +/// in every non-empty .debug_frame section. +void DwarfTableException::EmitCIE(const Function *PersonalityFn, unsigned Index) { + // Size and sign of stack growth. + int stackGrowth = Asm->getTargetData().getPointerSize(); + if (Asm->TM.getFrameLowering()->getStackGrowthDirection() == + TargetFrameLowering::StackGrowsDown) + stackGrowth *= -1; + + const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); + + // Begin eh frame section. + Asm->OutStreamer.SwitchSection(TLOF.getEHFrameSection()); + + MCSymbol *EHFrameSym; + if (TLOF.isFunctionEHFrameSymbolPrivate()) + EHFrameSym = Asm->GetTempSymbol("EH_frame", Index); + else + EHFrameSym = Asm->OutContext.GetOrCreateSymbol(Twine("EH_frame") + + Twine(Index)); + Asm->OutStreamer.EmitLabel(EHFrameSym); + + Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("section_eh_frame", Index)); + + // Define base labels. + Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_frame_common", Index)); + + // Define the eh frame length. + Asm->OutStreamer.AddComment("Length of Common Information Entry"); + Asm->EmitLabelDifference(Asm->GetTempSymbol("eh_frame_common_end", Index), + Asm->GetTempSymbol("eh_frame_common_begin", Index), + 4); + + // EH frame header. + Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_frame_common_begin",Index)); + Asm->OutStreamer.AddComment("CIE Identifier Tag"); + Asm->OutStreamer.EmitIntValue(0, 4/*size*/, 0/*addrspace*/); + Asm->OutStreamer.AddComment("DW_CIE_VERSION"); + Asm->OutStreamer.EmitIntValue(dwarf::DW_CIE_VERSION, 1/*size*/, 0/*addr*/); + + // The personality presence indicates that language specific information will + // show up in the eh frame. Find out how we are supposed to lower the + // personality function reference: + + unsigned LSDAEncoding = TLOF.getLSDAEncoding(); + unsigned FDEEncoding = TLOF.getFDEEncoding(); + unsigned PerEncoding = TLOF.getPersonalityEncoding(); + + char Augmentation[6] = { 0 }; + unsigned AugmentationSize = 0; + char *APtr = Augmentation + 1; + + if (PersonalityFn) { + // There is a personality function. + *APtr++ = 'P'; + AugmentationSize += 1 + Asm->GetSizeOfEncodedValue(PerEncoding); + } + + if (UsesLSDA[Index]) { + // An LSDA pointer is in the FDE augmentation. + *APtr++ = 'L'; + ++AugmentationSize; + } + + if (FDEEncoding != dwarf::DW_EH_PE_absptr) { + // A non-default pointer encoding for the FDE. + *APtr++ = 'R'; + ++AugmentationSize; + } + + if (APtr != Augmentation + 1) + Augmentation[0] = 'z'; + + Asm->OutStreamer.AddComment("CIE Augmentation"); + Asm->OutStreamer.EmitBytes(StringRef(Augmentation, strlen(Augmentation)+1),0); + + // Round out reader. + Asm->EmitULEB128(1, "CIE Code Alignment Factor"); + Asm->EmitSLEB128(stackGrowth, "CIE Data Alignment Factor"); + Asm->OutStreamer.AddComment("CIE Return Address Column"); + + const TargetRegisterInfo *RI = Asm->TM.getRegisterInfo(); + const TargetFrameLowering *TFI = Asm->TM.getFrameLowering(); + Asm->EmitInt8(RI->getDwarfRegNum(RI->getRARegister(), true)); + + if (Augmentation[0]) { + Asm->EmitULEB128(AugmentationSize, "Augmentation Size"); + + // If there is a personality, we need to indicate the function's location. + if (PersonalityFn) { + Asm->EmitEncodingByte(PerEncoding, "Personality"); + Asm->OutStreamer.AddComment("Personality"); + Asm->EmitReference(PersonalityFn, PerEncoding); + } + if (UsesLSDA[Index]) + Asm->EmitEncodingByte(LSDAEncoding, "LSDA"); + if (FDEEncoding != dwarf::DW_EH_PE_absptr) + Asm->EmitEncodingByte(FDEEncoding, "FDE"); + } + + // Indicate locations of general callee saved registers in frame. + std::vector Moves; + TFI->getInitialFrameState(Moves); + Asm->EmitFrameMoves(Moves, 0, true); + + // On Darwin the linker honors the alignment of eh_frame, which means it must + // be 8-byte on 64-bit targets to match what gcc does. Otherwise you get + // holes which confuse readers of eh_frame. + Asm->EmitAlignment(Asm->getTargetData().getPointerSize() == 4 ? 2 : 3); + Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_frame_common_end", Index)); +} + +/// EmitFDE - Emit the Frame Description Entry (FDE) for the function. +void DwarfTableException::EmitFDE(const FunctionEHFrameInfo &EHFrameInfo) { + assert(!EHFrameInfo.function->hasAvailableExternallyLinkage() && + "Should not emit 'available externally' functions at all"); + + const Function *TheFunc = EHFrameInfo.function; + const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); + + unsigned LSDAEncoding = TLOF.getLSDAEncoding(); + unsigned FDEEncoding = TLOF.getFDEEncoding(); + + Asm->OutStreamer.SwitchSection(TLOF.getEHFrameSection()); + + // Externally visible entry into the functions eh frame info. If the + // corresponding function is static, this should not be externally visible. + if (!TheFunc->hasLocalLinkage() && TLOF.isFunctionEHSymbolGlobal()) + Asm->OutStreamer.EmitSymbolAttribute(EHFrameInfo.FunctionEHSym,MCSA_Global); + + // If corresponding function is weak definition, this should be too. + if (TheFunc->isWeakForLinker() && Asm->MAI->getWeakDefDirective()) + Asm->OutStreamer.EmitSymbolAttribute(EHFrameInfo.FunctionEHSym, + MCSA_WeakDefinition); + + // If corresponding function is hidden, this should be too. + if (TheFunc->hasHiddenVisibility()) + if (MCSymbolAttr HiddenAttr = Asm->MAI->getHiddenVisibilityAttr()) + Asm->OutStreamer.EmitSymbolAttribute(EHFrameInfo.FunctionEHSym, + HiddenAttr); + + // If there are no calls then you can't unwind. This may mean we can omit the + // EH Frame, but some environments do not handle weak absolute symbols. If + // UnwindTablesMandatory is set we cannot do this optimization; the unwind + // info is to be available for non-EH uses. + if (!EHFrameInfo.adjustsStack && !UnwindTablesMandatory && + (!TheFunc->isWeakForLinker() || + !Asm->MAI->getWeakDefDirective() || + TLOF.getSupportsWeakOmittedEHFrame())) { + Asm->OutStreamer.EmitAssignment(EHFrameInfo.FunctionEHSym, + MCConstantExpr::Create(0, Asm->OutContext)); + // This name has no connection to the function, so it might get + // dead-stripped when the function is not, erroneously. Prohibit + // dead-stripping unconditionally. + if (Asm->MAI->hasNoDeadStrip()) + Asm->OutStreamer.EmitSymbolAttribute(EHFrameInfo.FunctionEHSym, + MCSA_NoDeadStrip); + } else { + Asm->OutStreamer.EmitLabel(EHFrameInfo.FunctionEHSym); + + // EH frame header. + Asm->OutStreamer.AddComment("Length of Frame Information Entry"); + Asm->EmitLabelDifference( + Asm->GetTempSymbol("eh_frame_end", EHFrameInfo.Number), + Asm->GetTempSymbol("eh_frame_begin", EHFrameInfo.Number), 4); + + Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_frame_begin", + EHFrameInfo.Number)); + + Asm->OutStreamer.AddComment("FDE CIE offset"); + Asm->EmitLabelDifference( + Asm->GetTempSymbol("eh_frame_begin", EHFrameInfo.Number), + Asm->GetTempSymbol("eh_frame_common", + EHFrameInfo.PersonalityIndex), 4); + + MCSymbol *EHFuncBeginSym = + Asm->GetTempSymbol("eh_func_begin", EHFrameInfo.Number); + + Asm->OutStreamer.AddComment("FDE initial location"); + Asm->EmitReference(EHFuncBeginSym, FDEEncoding); + + Asm->OutStreamer.AddComment("FDE address range"); + Asm->EmitLabelDifference(Asm->GetTempSymbol("eh_func_end", + EHFrameInfo.Number), + EHFuncBeginSym, + Asm->GetSizeOfEncodedValue(FDEEncoding)); + + // If there is a personality and landing pads then point to the language + // specific data area in the exception table. + if (MMI->getPersonalities()[0] != NULL) { + unsigned Size = Asm->GetSizeOfEncodedValue(LSDAEncoding); + + Asm->EmitULEB128(Size, "Augmentation size"); + Asm->OutStreamer.AddComment("Language Specific Data Area"); + if (EHFrameInfo.hasLandingPads) + Asm->EmitReference(Asm->GetTempSymbol("exception", EHFrameInfo.Number), + LSDAEncoding); + else + Asm->OutStreamer.EmitIntValue(0, Size/*size*/, 0/*addrspace*/); + + } else { + Asm->EmitULEB128(0, "Augmentation size"); + } + + // Indicate locations of function specific callee saved registers in frame. + Asm->EmitFrameMoves(EHFrameInfo.Moves, EHFuncBeginSym, true); + + // On Darwin the linker honors the alignment of eh_frame, which means it + // must be 8-byte on 64-bit targets to match what gcc does. Otherwise you + // get holes which confuse readers of eh_frame. + Asm->EmitAlignment(Asm->getTargetData().getPointerSize() == 4 ? 2 : 3); + Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_frame_end", + EHFrameInfo.Number)); + + // If the function is marked used, this table should be also. We cannot + // make the mark unconditional in this case, since retaining the table also + // retains the function in this case, and there is code around that depends + // on unused functions (calling undefined externals) being dead-stripped to + // link correctly. Yes, there really is. + if (MMI->isUsedFunction(EHFrameInfo.function)) + if (Asm->MAI->hasNoDeadStrip()) + Asm->OutStreamer.EmitSymbolAttribute(EHFrameInfo.FunctionEHSym, + MCSA_NoDeadStrip); + } + Asm->OutStreamer.AddBlankLine(); +} + +/// EndModule - Emit all exception information that should come after the +/// content. +void DwarfTableException::EndModule() { + if (!Asm->MAI->isExceptionHandlingDwarf()) + return; + + if (!shouldEmitMovesModule && !shouldEmitTableModule) + return; + + const std::vector &Personalities = MMI->getPersonalities(); + + for (unsigned I = 0, E = Personalities.size(); I < E; ++I) + EmitCIE(Personalities[I], I); + + for (std::vector::iterator + I = EHFrames.begin(), E = EHFrames.end(); I != E; ++I) + EmitFDE(*I); +} + +/// BeginFunction - Gather pre-function exception information. Assumes it's +/// being emitted immediately after the function entry point. +void DwarfTableException::BeginFunction(const MachineFunction *MF) { + shouldEmitTable = shouldEmitMoves = false; + + // If any landing pads survive, we need an EH table. + shouldEmitTable = !MMI->getLandingPads().empty(); + + // See if we need frame move info. + shouldEmitMoves = + !Asm->MF->getFunction()->doesNotThrow() || UnwindTablesMandatory; + + if (shouldEmitMoves || shouldEmitTable) + // Assumes in correct section after the entry point. + Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_func_begin", + Asm->getFunctionNumber())); + + shouldEmitTableModule |= shouldEmitTable; + shouldEmitMovesModule |= shouldEmitMoves; +} + +/// EndFunction - Gather and emit post-function exception information. +/// +void DwarfTableException::EndFunction() { + if (!shouldEmitMoves && !shouldEmitTable) return; + + Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_func_end", + Asm->getFunctionNumber())); + + // Record if this personality index uses a landing pad. + bool HasLandingPad = !MMI->getLandingPads().empty(); + UsesLSDA[MMI->getPersonalityIndex()] |= HasLandingPad; + + // Map all labels and get rid of any dead landing pads. + MMI->TidyLandingPads(); + + if (HasLandingPad) + EmitExceptionTable(); + + const TargetLoweringObjectFile &TLOF = Asm->getObjFileLowering(); + MCSymbol *FunctionEHSym = + Asm->GetSymbolWithGlobalValueBase(Asm->MF->getFunction(), ".eh", + TLOF.isFunctionEHFrameSymbolPrivate()); + + // Save EH frame information + EHFrames. + push_back(FunctionEHFrameInfo(FunctionEHSym, + Asm->getFunctionNumber(), + MMI->getPersonalityIndex(), + Asm->MF->getFrameInfo()->adjustsStack(), + !MMI->getLandingPads().empty(), + MMI->getFrameMoves(), + Asm->MF->getFunction())); +} diff --git a/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp b/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp index c8a63cf2393b..115381767751 100644 --- a/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp +++ b/lib/CodeGen/AsmPrinter/OcamlGCPrinter.cpp @@ -26,6 +26,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormattedStream.h" +#include using namespace llvm; namespace { diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt index 2ef115dbd205..d7d0e1b3812b 100644 --- a/lib/CodeGen/CMakeLists.txt +++ b/lib/CodeGen/CMakeLists.txt @@ -1,15 +1,19 @@ add_llvm_library(LLVMCodeGen AggressiveAntiDepBreaker.cpp + AllocationOrder.cpp Analysis.cpp BranchFolding.cpp CalcSpillWeights.cpp CallingConvLower.cpp + CodeGen.cpp CodePlacementOpt.cpp CriticalAntiDepBreaker.cpp DeadMachineInstructionElim.cpp DwarfEHPrepare.cpp + EdgeBundles.cpp ELFCodeEmitter.cpp ELFWriter.cpp + ExpandISelPseudos.cpp GCMetadata.cpp GCMetadataPrinter.cpp GCStrategy.cpp @@ -18,10 +22,13 @@ add_llvm_library(LLVMCodeGen IntrinsicLowering.cpp LLVMTargetMachine.cpp LatencyPriorityQueue.cpp + LiveDebugVariables.cpp LiveInterval.cpp LiveIntervalAnalysis.cpp + LiveIntervalUnion.cpp LiveStackAnalysis.cpp LiveVariables.cpp + LiveRangeEdit.cpp LocalStackSlotAllocation.cpp LowerSubregs.cpp MachineBasicBlock.cpp @@ -34,6 +41,7 @@ add_llvm_library(LLVMCodeGen MachineInstr.cpp MachineLICM.cpp MachineLoopInfo.cpp + MachineLoopRanges.cpp MachineModuleInfo.cpp MachineModuleInfoImpls.cpp MachinePassRegistry.cpp @@ -45,15 +53,17 @@ add_llvm_library(LLVMCodeGen OcamlGC.cpp OptimizePHIs.cpp PHIElimination.cpp + PHIEliminationUtils.cpp Passes.cpp PeepholeOptimizer.cpp - PostRAHazardRecognizer.cpp PostRASchedulerList.cpp PreAllocSplitting.cpp ProcessImplicitDefs.cpp PrologEpilogInserter.cpp PseudoSourceValue.cpp + RegAllocBasic.cpp RegAllocFast.cpp + RegAllocGreedy.cpp RegAllocLinearScan.cpp RegAllocPBQP.cpp RegisterCoalescer.cpp @@ -63,12 +73,14 @@ add_llvm_library(LLVMCodeGen ScheduleDAGEmit.cpp ScheduleDAGInstrs.cpp ScheduleDAGPrinter.cpp + ScoreboardHazardRecognizer.cpp ShadowStackGC.cpp ShrinkWrapping.cpp SimpleRegisterCoalescing.cpp SjLjEHPrepare.cpp SlotIndexes.cpp Spiller.cpp + SpillPlacement.cpp SplitKit.cpp Splitter.cpp StackProtector.cpp @@ -83,4 +95,5 @@ add_llvm_library(LLVMCodeGen VirtRegRewriter.cpp ) -target_link_libraries (LLVMCodeGen LLVMCore LLVMScalarOpts) +add_subdirectory(SelectionDAG) +add_subdirectory(AsmPrinter) diff --git a/lib/CodeGen/CalcSpillWeights.cpp b/lib/CodeGen/CalcSpillWeights.cpp index 1b7e08a8b6bb..76bb3d148b0b 100644 --- a/lib/CodeGen/CalcSpillWeights.cpp +++ b/lib/CodeGen/CalcSpillWeights.cpp @@ -25,8 +25,12 @@ using namespace llvm; char CalculateSpillWeights::ID = 0; -INITIALIZE_PASS(CalculateSpillWeights, "calcspillweights", - "Calculate spill weights", false, false); +INITIALIZE_PASS_BEGIN(CalculateSpillWeights, "calcspillweights", + "Calculate spill weights", false, false) +INITIALIZE_PASS_DEPENDENCY(LiveIntervals) +INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo) +INITIALIZE_PASS_END(CalculateSpillWeights, "calcspillweights", + "Calculate spill weights", false, false) void CalculateSpillWeights::getAnalysisUsage(AnalysisUsage &au) const { au.addRequired(); @@ -170,8 +174,7 @@ void VirtRegAuxInfo::CalculateWeightAndHint(LiveInterval &li) { totalWeight *= 0.5F; } - li.weight = totalWeight; - lis_.normalizeSpillWeight(li); + li.weight = normalizeSpillWeight(totalWeight, li.getSize()); } void VirtRegAuxInfo::CalculateRegClass(unsigned reg) { @@ -218,7 +221,7 @@ void VirtRegAuxInfo::CalculateRegClass(unsigned reg) { if (rc == orc) return; - DEBUG(dbgs() << "Inflating " << orc->getName() << ":%reg" << reg << " to " - << rc->getName() <<".\n"); + DEBUG(dbgs() << "Inflating " << orc->getName() << ':' << PrintReg(reg) + << " to " << rc->getName() <<".\n"); mri.setRegClass(reg, rc); } diff --git a/lib/CodeGen/CallingConvLower.cpp b/lib/CodeGen/CallingConvLower.cpp index 62ad8171a9d4..2ad80b4d3a75 100644 --- a/lib/CodeGen/CallingConvLower.cpp +++ b/lib/CodeGen/CallingConvLower.cpp @@ -34,8 +34,8 @@ CCState::CCState(CallingConv::ID CC, bool isVarArg, const TargetMachine &tm, // HandleByVal - Allocate a stack slot large enough to pass an argument by // value. The size and alignment information of the argument is encoded in its // parameter attribute. -void CCState::HandleByVal(unsigned ValNo, EVT ValVT, - EVT LocVT, CCValAssign::LocInfo LocInfo, +void CCState::HandleByVal(unsigned ValNo, MVT ValVT, + MVT LocVT, CCValAssign::LocInfo LocInfo, int MinSize, int MinAlign, ISD::ArgFlagsTy ArgFlags) { unsigned Align = ArgFlags.getByValAlign(); @@ -51,11 +51,9 @@ void CCState::HandleByVal(unsigned ValNo, EVT ValVT, /// MarkAllocated - Mark a register and all of its aliases as allocated. void CCState::MarkAllocated(unsigned Reg) { - UsedRegs[Reg/32] |= 1 << (Reg&31); - - if (const unsigned *RegAliases = TRI.getAliasSet(Reg)) - for (; (Reg = *RegAliases); ++RegAliases) - UsedRegs[Reg/32] |= 1 << (Reg&31); + for (const unsigned *Alias = TRI.getOverlaps(Reg); + unsigned Reg = *Alias; ++Alias) + UsedRegs[Reg/32] |= 1 << (Reg&31); } /// AnalyzeFormalArguments - Analyze an array of argument values, @@ -66,12 +64,12 @@ CCState::AnalyzeFormalArguments(const SmallVectorImpl &Ins, unsigned NumArgs = Ins.size(); for (unsigned i = 0; i != NumArgs; ++i) { - EVT ArgVT = Ins[i].VT; + MVT ArgVT = Ins[i].VT; ISD::ArgFlagsTy ArgFlags = Ins[i].Flags; if (Fn(i, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, *this)) { #ifndef NDEBUG dbgs() << "Formal argument #" << i << " has unhandled type " - << ArgVT.getEVTString(); + << EVT(ArgVT).getEVTString(); #endif llvm_unreachable(0); } @@ -84,7 +82,7 @@ bool CCState::CheckReturn(const SmallVectorImpl &Outs, CCAssignFn Fn) { // Determine which register each value should be copied into. for (unsigned i = 0, e = Outs.size(); i != e; ++i) { - EVT VT = Outs[i].VT; + MVT VT = Outs[i].VT; ISD::ArgFlagsTy ArgFlags = Outs[i].Flags; if (Fn(i, VT, VT, CCValAssign::Full, ArgFlags, *this)) return false; @@ -98,12 +96,12 @@ void CCState::AnalyzeReturn(const SmallVectorImpl &Outs, CCAssignFn Fn) { // Determine which register each value should be copied into. for (unsigned i = 0, e = Outs.size(); i != e; ++i) { - EVT VT = Outs[i].VT; + MVT VT = Outs[i].VT; ISD::ArgFlagsTy ArgFlags = Outs[i].Flags; if (Fn(i, VT, VT, CCValAssign::Full, ArgFlags, *this)) { #ifndef NDEBUG dbgs() << "Return operand #" << i << " has unhandled type " - << VT.getEVTString(); + << EVT(VT).getEVTString(); #endif llvm_unreachable(0); } @@ -116,12 +114,12 @@ void CCState::AnalyzeCallOperands(const SmallVectorImpl &Outs, CCAssignFn Fn) { unsigned NumOps = Outs.size(); for (unsigned i = 0; i != NumOps; ++i) { - EVT ArgVT = Outs[i].VT; + MVT ArgVT = Outs[i].VT; ISD::ArgFlagsTy ArgFlags = Outs[i].Flags; if (Fn(i, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, *this)) { #ifndef NDEBUG dbgs() << "Call operand #" << i << " has unhandled type " - << ArgVT.getEVTString(); + << EVT(ArgVT).getEVTString(); #endif llvm_unreachable(0); } @@ -130,17 +128,17 @@ void CCState::AnalyzeCallOperands(const SmallVectorImpl &Outs, /// AnalyzeCallOperands - Same as above except it takes vectors of types /// and argument flags. -void CCState::AnalyzeCallOperands(SmallVectorImpl &ArgVTs, +void CCState::AnalyzeCallOperands(SmallVectorImpl &ArgVTs, SmallVectorImpl &Flags, CCAssignFn Fn) { unsigned NumOps = ArgVTs.size(); for (unsigned i = 0; i != NumOps; ++i) { - EVT ArgVT = ArgVTs[i]; + MVT ArgVT = ArgVTs[i]; ISD::ArgFlagsTy ArgFlags = Flags[i]; if (Fn(i, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, *this)) { #ifndef NDEBUG dbgs() << "Call operand #" << i << " has unhandled type " - << ArgVT.getEVTString(); + << EVT(ArgVT).getEVTString(); #endif llvm_unreachable(0); } @@ -152,12 +150,12 @@ void CCState::AnalyzeCallOperands(SmallVectorImpl &ArgVTs, void CCState::AnalyzeCallResult(const SmallVectorImpl &Ins, CCAssignFn Fn) { for (unsigned i = 0, e = Ins.size(); i != e; ++i) { - EVT VT = Ins[i].VT; + MVT VT = Ins[i].VT; ISD::ArgFlagsTy Flags = Ins[i].Flags; if (Fn(i, VT, VT, CCValAssign::Full, Flags, *this)) { #ifndef NDEBUG dbgs() << "Call result #" << i << " has unhandled type " - << VT.getEVTString(); + << EVT(VT).getEVTString(); #endif llvm_unreachable(0); } @@ -166,11 +164,11 @@ void CCState::AnalyzeCallResult(const SmallVectorImpl &Ins, /// AnalyzeCallResult - Same as above except it's specialized for calls which /// produce a single value. -void CCState::AnalyzeCallResult(EVT VT, CCAssignFn Fn) { +void CCState::AnalyzeCallResult(MVT VT, CCAssignFn Fn) { if (Fn(0, VT, VT, CCValAssign::Full, ISD::ArgFlagsTy(), *this)) { #ifndef NDEBUG dbgs() << "Call result has unhandled type " - << VT.getEVTString(); + << EVT(VT).getEVTString(); #endif llvm_unreachable(0); } diff --git a/lib/CodeGen/CodeGen.cpp b/lib/CodeGen/CodeGen.cpp new file mode 100644 index 000000000000..515e6f9fde87 --- /dev/null +++ b/lib/CodeGen/CodeGen.cpp @@ -0,0 +1,61 @@ +//===-- CodeGen.cpp -------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the common initialization routines for the +// CodeGen library. +// +//===----------------------------------------------------------------------===// + +#include "llvm/InitializePasses.h" +#include "llvm-c/Initialization.h" + +using namespace llvm; + +/// initializeCodeGen - Initialize all passes linked into the CodeGen library. +void llvm::initializeCodeGen(PassRegistry &Registry) { + initializeCalculateSpillWeightsPass(Registry); + initializeDeadMachineInstructionElimPass(Registry); + initializeGCModuleInfoPass(Registry); + initializeIfConverterPass(Registry); + initializeLiveDebugVariablesPass(Registry); + initializeLiveIntervalsPass(Registry); + initializeLiveStacksPass(Registry); + initializeLiveVariablesPass(Registry); + initializeMachineCSEPass(Registry); + initializeMachineDominatorTreePass(Registry); + initializeMachineLICMPass(Registry); + initializeMachineLoopInfoPass(Registry); + initializeMachineModuleInfoPass(Registry); + initializeMachineSinkingPass(Registry); + initializeMachineVerifierPassPass(Registry); + initializeOptimizePHIsPass(Registry); + initializePHIEliminationPass(Registry); + initializePeepholeOptimizerPass(Registry); + initializePreAllocSplittingPass(Registry); + initializeProcessImplicitDefsPass(Registry); + initializePEIPass(Registry); + initializeRALinScanPass(Registry); + initializeRegisterCoalescerAnalysisGroup(Registry); + initializeRenderMachineFunctionPass(Registry); + initializeSimpleRegisterCoalescingPass(Registry); + initializeSlotIndexesPass(Registry); + initializeLoopSplitterPass(Registry); + initializeStackProtectorPass(Registry); + initializeStackSlotColoringPass(Registry); + initializeStrongPHIEliminationPass(Registry); + initializeTwoAddressInstructionPassPass(Registry); + initializeUnreachableBlockElimPass(Registry); + initializeUnreachableMachineBlockElimPass(Registry); + initializeVirtRegMapPass(Registry); + initializeLowerIntrinsicsPass(Registry); +} + +void LLVMInitializeCodeGen(LLVMPassRegistryRef R) { + initializeCodeGen(*unwrap(R)); +} diff --git a/lib/CodeGen/CriticalAntiDepBreaker.cpp b/lib/CodeGen/CriticalAntiDepBreaker.cpp index 335d2d8e9bac..f79598de1d9e 100644 --- a/lib/CodeGen/CriticalAntiDepBreaker.cpp +++ b/lib/CodeGen/CriticalAntiDepBreaker.cpp @@ -130,21 +130,25 @@ void CriticalAntiDepBreaker::Observe(MachineInstr *MI, unsigned Count, return; assert(Count < InsertPosIndex && "Instruction index out of expected range!"); - // Any register which was defined within the previous scheduling region - // may have been rescheduled and its lifetime may overlap with registers - // in ways not reflected in our current liveness state. For each such - // register, adjust the liveness state to be conservatively correct. - for (unsigned Reg = 0; Reg != TRI->getNumRegs(); ++Reg) - if (DefIndices[Reg] < InsertPosIndex && DefIndices[Reg] >= Count) { - assert(KillIndices[Reg] == ~0u && "Clobbered register is live!"); - - // Mark this register to be non-renamable. + for (unsigned Reg = 0; Reg != TRI->getNumRegs(); ++Reg) { + if (KillIndices[Reg] != ~0u) { + // If Reg is currently live, then mark that it can't be renamed as + // we don't know the extent of its live-range anymore (now that it + // has been scheduled). + Classes[Reg] = reinterpret_cast(-1); + KillIndices[Reg] = Count; + } else if (DefIndices[Reg] < InsertPosIndex && DefIndices[Reg] >= Count) { + // Any register which was defined within the previous scheduling region + // may have been rescheduled and its lifetime may overlap with registers + // in ways not reflected in our current liveness state. For each such + // register, adjust the liveness state to be conservatively correct. Classes[Reg] = reinterpret_cast(-1); // Move the def index to the end of the previous region, to reflect // that the def could theoretically have been scheduled at the end. DefIndices[Reg] = InsertPosIndex; } + } PrescanInstruction(MI); ScanInstruction(MI, Count); @@ -177,7 +181,7 @@ void CriticalAntiDepBreaker::PrescanInstruction(MachineInstr *MI) { // that have special allocation requirements. Also assume all registers // used in a call must not be changed (ABI). // FIXME: The issue with predicated instruction is more complex. We are being - // conservatively here because the kill markers cannot be trusted after + // conservative here because the kill markers cannot be trusted after // if-conversion: // %R6 = LDR %SP, %reg0, 92, pred:14, pred:%reg0; mem:LD4[FixedStack14] // ... @@ -321,8 +325,62 @@ void CriticalAntiDepBreaker::ScanInstruction(MachineInstr *MI, } } +// Check all machine operands that reference the antidependent register and must +// be replaced by NewReg. Return true if any of their parent instructions may +// clobber the new register. +// +// Note: AntiDepReg may be referenced by a two-address instruction such that +// it's use operand is tied to a def operand. We guard against the case in which +// the two-address instruction also defines NewReg, as may happen with +// pre/postincrement loads. In this case, both the use and def operands are in +// RegRefs because the def is inserted by PrescanInstruction and not erased +// during ScanInstruction. So checking for an instructions with definitions of +// both NewReg and AntiDepReg covers it. +bool +CriticalAntiDepBreaker::isNewRegClobberedByRefs(RegRefIter RegRefBegin, + RegRefIter RegRefEnd, + unsigned NewReg) +{ + for (RegRefIter I = RegRefBegin; I != RegRefEnd; ++I ) { + MachineOperand *RefOper = I->second; + + // Don't allow the instruction defining AntiDepReg to earlyclobber its + // operands, in case they may be assigned to NewReg. In this case antidep + // breaking must fail, but it's too rare to bother optimizing. + if (RefOper->isDef() && RefOper->isEarlyClobber()) + return true; + + // Handle cases in which this instructions defines NewReg. + MachineInstr *MI = RefOper->getParent(); + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + const MachineOperand &CheckOper = MI->getOperand(i); + + if (!CheckOper.isReg() || !CheckOper.isDef() || + CheckOper.getReg() != NewReg) + continue; + + // Don't allow the instruction to define NewReg and AntiDepReg. + // When AntiDepReg is renamed it will be an illegal op. + if (RefOper->isDef()) + return true; + + // Don't allow an instruction using AntiDepReg to be earlyclobbered by + // NewReg + if (CheckOper.isEarlyClobber()) + return true; + + // Don't allow inline asm to define NewReg at all. Who know what it's + // doing with it. + if (MI->isInlineAsm()) + return true; + } + } + return false; +} + unsigned -CriticalAntiDepBreaker::findSuitableFreeRegister(MachineInstr *MI, +CriticalAntiDepBreaker::findSuitableFreeRegister(RegRefIter RegRefBegin, + RegRefIter RegRefEnd, unsigned AntiDepReg, unsigned LastNewReg, const TargetRegisterClass *RC) @@ -338,10 +396,10 @@ CriticalAntiDepBreaker::findSuitableFreeRegister(MachineInstr *MI, // an anti-dependence with this AntiDepReg, because that would // re-introduce that anti-dependence. if (NewReg == LastNewReg) continue; - // If the instruction already has a def of the NewReg, it's not suitable. - // For example, Instruction with multiple definitions can result in this - // condition. - if (MI->modifiesRegister(NewReg, TRI)) continue; + // If any instructions that define AntiDepReg also define the NewReg, it's + // not suitable. For example, Instruction with multiple definitions can + // result in this condition. + if (isNewRegClobberedByRefs(RegRefBegin, RegRefEnd, NewReg)) continue; // If NewReg is dead and NewReg's most recent def is not before // AntiDepReg's kill, it's safe to replace AntiDepReg with NewReg. assert(((KillIndices[AntiDepReg] == ~0u) != (DefIndices[AntiDepReg] == ~0u)) @@ -548,7 +606,11 @@ BreakAntiDependencies(const std::vector& SUnits, // TODO: Instead of picking the first free register, consider which might // be the best. if (AntiDepReg != 0) { - if (unsigned NewReg = findSuitableFreeRegister(MI, AntiDepReg, + std::pair::iterator, + std::multimap::iterator> + Range = RegRefs.equal_range(AntiDepReg); + if (unsigned NewReg = findSuitableFreeRegister(Range.first, Range.second, + AntiDepReg, LastNewReg[AntiDepReg], RC)) { DEBUG(dbgs() << "Breaking anti-dependence edge on " @@ -558,9 +620,6 @@ BreakAntiDependencies(const std::vector& SUnits, // Update the references to the old register to refer to the new // register. - std::pair::iterator, - std::multimap::iterator> - Range = RegRefs.equal_range(AntiDepReg); for (std::multimap::iterator Q = Range.first, QE = Range.second; Q != QE; ++Q) { Q->second->setReg(NewReg); @@ -580,7 +639,7 @@ BreakAntiDependencies(const std::vector& SUnits, } // We just went back in time and modified history; the - // liveness information for the anti-depenence reg is now + // liveness information for the anti-dependence reg is now // inconsistent. Set the state as if it were dead. Classes[NewReg] = Classes[AntiDepReg]; DefIndices[NewReg] = DefIndices[AntiDepReg]; diff --git a/lib/CodeGen/CriticalAntiDepBreaker.h b/lib/CodeGen/CriticalAntiDepBreaker.h index 0ed7c35b0f0c..0daaef273448 100644 --- a/lib/CodeGen/CriticalAntiDepBreaker.h +++ b/lib/CodeGen/CriticalAntiDepBreaker.h @@ -48,8 +48,10 @@ class TargetRegisterInfo; /// pointer. std::vector Classes; - /// RegRegs - Map registers to all their references within a live range. + /// RegRefs - Map registers to all their references within a live range. std::multimap RegRefs; + typedef std::multimap::const_iterator + RegRefIter; /// KillIndices - The index of the most recent kill (proceding bottom-up), /// or ~0u if the register is not live. @@ -90,10 +92,14 @@ class TargetRegisterInfo; private: void PrescanInstruction(MachineInstr *MI); void ScanInstruction(MachineInstr *MI, unsigned Count); - unsigned findSuitableFreeRegister(MachineInstr *MI, + bool isNewRegClobberedByRefs(RegRefIter RegRefBegin, + RegRefIter RegRefEnd, + unsigned NewReg); + unsigned findSuitableFreeRegister(RegRefIter RegRefBegin, + RegRefIter RegRefEnd, unsigned AntiDepReg, unsigned LastNewReg, - const TargetRegisterClass *); + const TargetRegisterClass *RC); }; } diff --git a/lib/CodeGen/DeadMachineInstructionElim.cpp b/lib/CodeGen/DeadMachineInstructionElim.cpp index 318d922adebf..fdc1d9142140 100644 --- a/lib/CodeGen/DeadMachineInstructionElim.cpp +++ b/lib/CodeGen/DeadMachineInstructionElim.cpp @@ -36,7 +36,9 @@ namespace { public: static char ID; // Pass identification, replacement for typeid - DeadMachineInstructionElim() : MachineFunctionPass(ID) {} + DeadMachineInstructionElim() : MachineFunctionPass(ID) { + initializeDeadMachineInstructionElimPass(*PassRegistry::getPassRegistry()); + } private: bool isDead(const MachineInstr *MI) const; @@ -45,13 +47,19 @@ namespace { char DeadMachineInstructionElim::ID = 0; INITIALIZE_PASS(DeadMachineInstructionElim, "dead-mi-elimination", - "Remove dead machine instructions", false, false); + "Remove dead machine instructions", false, false) FunctionPass *llvm::createDeadMachineInstructionElimPass() { return new DeadMachineInstructionElim(); } bool DeadMachineInstructionElim::isDead(const MachineInstr *MI) const { + // Technically speaking inline asm without side effects and no defs can still + // be deleted. But there is so much bad inline asm code out there, we should + // let them be. + if (MI->isInlineAsm()) + return false; + // Don't delete instructions with side effects. bool SawStore = false; if (!MI->isSafeToMove(TII, 0, SawStore) && !MI->isPHI()) @@ -151,7 +159,7 @@ bool DeadMachineInstructionElim::runOnMachineFunction(MachineFunction &MF) { const MachineOperand &MO = MI->getOperand(i); if (MO.isReg() && MO.isDef()) { unsigned Reg = MO.getReg(); - if (Reg != 0 && TargetRegisterInfo::isPhysicalRegister(Reg)) { + if (TargetRegisterInfo::isPhysicalRegister(Reg)) { LivePhysRegs.reset(Reg); // Check the subreg set, not the alias set, because a def // of a super-register may still be partially live after @@ -168,7 +176,7 @@ bool DeadMachineInstructionElim::runOnMachineFunction(MachineFunction &MF) { const MachineOperand &MO = MI->getOperand(i); if (MO.isReg() && MO.isUse()) { unsigned Reg = MO.getReg(); - if (Reg != 0 && TargetRegisterInfo::isPhysicalRegister(Reg)) { + if (TargetRegisterInfo::isPhysicalRegister(Reg)) { LivePhysRegs.set(Reg); for (const unsigned *AliasSet = TRI->getAliasSet(Reg); *AliasSet; ++AliasSet) diff --git a/lib/CodeGen/DwarfEHPrepare.cpp b/lib/CodeGen/DwarfEHPrepare.cpp index 550fd3e25fb7..0ebb5b0db70e 100644 --- a/lib/CodeGen/DwarfEHPrepare.cpp +++ b/lib/CodeGen/DwarfEHPrepare.cpp @@ -43,7 +43,7 @@ namespace { // The eh.selector intrinsic. Function *SelectorIntrinsic; - // _Unwind_Resume_or_Rethrow call. + // _Unwind_Resume_or_Rethrow or _Unwind_SjLj_Resume call. Constant *URoR; // The EH language-specific catch-all type. @@ -82,11 +82,11 @@ namespace { /// FindAllURoRInvokes - Find all URoR invokes in the function. void FindAllURoRInvokes(SmallPtrSet &URoRInvokes); - /// HandleURoRInvokes - Handle invokes of "_Unwind_Resume_or_Rethrow" - /// calls. The "unwind" part of these invokes jump to a landing pad within - /// the current function. This is a candidate to merge the selector - /// associated with the URoR invoke with the one from the URoR's landing - /// pad. + /// HandleURoRInvokes - Handle invokes of "_Unwind_Resume_or_Rethrow" or + /// "_Unwind_SjLj_Resume" calls. The "unwind" part of these invokes jump to + /// a landing pad within the current function. This is a candidate to merge + /// the selector associated with the URoR invoke with the one from the + /// URoR's landing pad. bool HandleURoRInvokes(); /// FindSelectorAndURoR - Find the eh.selector call and URoR call associated @@ -100,7 +100,9 @@ namespace { DwarfEHPrepare(const TargetMachine *tm) : FunctionPass(ID), TM(tm), TLI(TM->getTargetLowering()), ExceptionValueIntrinsic(0), SelectorIntrinsic(0), - URoR(0), EHCatchAllValue(0), RewindFunction(0) {} + URoR(0), EHCatchAllValue(0), RewindFunction(0) { + initializeDominatorTreePass(*PassRegistry::getPassRegistry()); + } virtual bool runOnFunction(Function &Fn); @@ -224,10 +226,11 @@ DwarfEHPrepare::FindSelectorAndURoR(Instruction *Inst, bool &URoRInvoke, return Changed; } -/// HandleURoRInvokes - Handle invokes of "_Unwind_Resume_or_Rethrow" calls. The -/// "unwind" part of these invokes jump to a landing pad within the current -/// function. This is a candidate to merge the selector associated with the URoR -/// invoke with the one from the URoR's landing pad. +/// HandleURoRInvokes - Handle invokes of "_Unwind_Resume_or_Rethrow" or +/// "_Unwind_SjLj_Resume" calls. The "unwind" part of these invokes jump to a +/// landing pad within the current function. This is a candidate to merge the +/// selector associated with the URoR invoke with the one from the URoR's +/// landing pad. bool DwarfEHPrepare::HandleURoRInvokes() { if (!EHCatchAllValue) { EHCatchAllValue = @@ -247,7 +250,10 @@ bool DwarfEHPrepare::HandleURoRInvokes() { if (!URoR) { URoR = F->getParent()->getFunction("_Unwind_Resume_or_Rethrow"); - if (!URoR) return CleanupSelectors(CatchAllSels); + if (!URoR) { + URoR = F->getParent()->getFunction("_Unwind_SjLj_Resume"); + if (!URoR) return CleanupSelectors(CatchAllSels); + } } SmallPtrSet URoRInvokes; diff --git a/lib/CodeGen/ELF.h b/lib/CodeGen/ELF.h index fb884c9e8b71..e08feeb27539 100644 --- a/lib/CodeGen/ELF.h +++ b/lib/CodeGen/ELF.h @@ -23,7 +23,7 @@ #include "llvm/CodeGen/BinaryObject.h" #include "llvm/CodeGen/MachineRelocation.h" #include "llvm/Support/ELF.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { class GlobalValue; diff --git a/lib/CodeGen/ELFWriter.cpp b/lib/CodeGen/ELFWriter.cpp index d14728d8a36c..0fd1e8e83bd7 100644 --- a/lib/CodeGen/ELFWriter.cpp +++ b/lib/CodeGen/ELFWriter.cpp @@ -45,6 +45,7 @@ #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/Target/Mangler.h" +#include "llvm/Target/TargetAsmInfo.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetELFWriterInfo.h" #include "llvm/Target/TargetLowering.h" @@ -64,7 +65,7 @@ char ELFWriter::ID = 0; ELFWriter::ELFWriter(raw_ostream &o, TargetMachine &tm) : MachineFunctionPass(ID), O(o), TM(tm), - OutContext(*new MCContext(*TM.getMCAsmInfo())), + OutContext(*new MCContext(*TM.getMCAsmInfo(), new TargetAsmInfo(tm))), TLOF(TM.getTargetLowering()->getObjFileLowering()), is64Bit(TM.getTargetData()->getPointerSizeInBits() == 64), isLittleEndian(TM.getTargetData()->isLittleEndian()), @@ -327,6 +328,18 @@ void ELFWriter::AddToSymbolList(ELFSym *GblSym) { } } +/// HasCommonSymbols - True if this section holds common symbols, this is +/// indicated on the ELF object file by a symbol with SHN_COMMON section +/// header index. +static bool HasCommonSymbols(const MCSectionELF &S) { + // FIXME: this is wrong, a common symbol can be in .data for example. + if (StringRef(S.getSectionName()).startswith(".gnu.linkonce.")) + return true; + + return false; +} + + // EmitGlobal - Choose the right section for global and emit it void ELFWriter::EmitGlobal(const GlobalValue *GV) { @@ -363,7 +376,7 @@ void ELFWriter::EmitGlobal(const GlobalValue *GV) { unsigned Size = TD->getTypeAllocSize(GVar->getInitializer()->getType()); GblSym->Size = Size; - if (S->HasCommonSymbols()) { // Symbol must go to a common section + if (HasCommonSymbols(*S)) { // Symbol must go to a common section GblSym->SectionIdx = ELF::SHN_COMMON; // A new linkonce section is created for each global in the diff --git a/lib/CodeGen/EdgeBundles.cpp b/lib/CodeGen/EdgeBundles.cpp new file mode 100644 index 000000000000..aed8bc947991 --- /dev/null +++ b/lib/CodeGen/EdgeBundles.cpp @@ -0,0 +1,86 @@ +//===-------- EdgeBundles.cpp - Bundles of CFG edges ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the implementation of the EdgeBundles analysis. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/EdgeBundles.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/GraphWriter.h" + +using namespace llvm; + +static cl::opt +ViewEdgeBundles("view-edge-bundles", cl::Hidden, + cl::desc("Pop up a window to show edge bundle graphs")); + +char EdgeBundles::ID = 0; + +INITIALIZE_PASS(EdgeBundles, "edge-bundles", "Bundle Machine CFG Edges", + /* cfg = */true, /* analysis = */ true) + +char &llvm::EdgeBundlesID = EdgeBundles::ID; + +void EdgeBundles::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + MachineFunctionPass::getAnalysisUsage(AU); +} + +bool EdgeBundles::runOnMachineFunction(MachineFunction &mf) { + MF = &mf; + EC.clear(); + EC.grow(2 * MF->size()); + + for (MachineFunction::const_iterator I = MF->begin(), E = MF->end(); I != E; + ++I) { + const MachineBasicBlock &MBB = *I; + unsigned OutE = 2 * MBB.getNumber() + 1; + // Join the outgoing bundle with the ingoing bundles of all successors. + for (MachineBasicBlock::const_succ_iterator SI = MBB.succ_begin(), + SE = MBB.succ_end(); SI != SE; ++SI) + EC.join(OutE, 2 * (*SI)->getNumber()); + } + EC.compress(); + if (ViewEdgeBundles) + view(); + return false; +} + +/// view - Visualize the annotated bipartite CFG with Graphviz. +void EdgeBundles::view() const { + ViewGraph(*this, "EdgeBundles"); +} + +/// Specialize WriteGraph, the standard implementation won't work. +raw_ostream &llvm::WriteGraph(raw_ostream &O, const EdgeBundles &G, + bool ShortNames, + const std::string &Title) { + const MachineFunction *MF = G.getMachineFunction(); + + O << "digraph {\n"; + for (MachineFunction::const_iterator I = MF->begin(), E = MF->end(); + I != E; ++I) { + unsigned BB = I->getNumber(); + O << "\t\"BB#" << BB << "\" [ shape=box ]\n" + << '\t' << G.getBundle(BB, false) << " -> \"BB#" << BB << "\"\n" + << "\t\"BB#" << BB << "\" -> " << G.getBundle(BB, true) << '\n'; + for (MachineBasicBlock::const_succ_iterator SI = I->succ_begin(), + SE = I->succ_end(); SI != SE; ++SI) + O << "\t\"BB#" << BB << "\" -> \"BB#" << (*SI)->getNumber() + << "\" [ color=lightgray ]\n"; + } + O << "}\n"; + return O; +} + + diff --git a/lib/CodeGen/ExpandISelPseudos.cpp b/lib/CodeGen/ExpandISelPseudos.cpp new file mode 100644 index 000000000000..b5ec303f5d93 --- /dev/null +++ b/lib/CodeGen/ExpandISelPseudos.cpp @@ -0,0 +1,82 @@ +//===-- llvm/CodeGen/ExpandISelPseudos.cpp ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Expand Psuedo-instructions produced by ISel. These are usually to allow +// the expansion to contain control flow, such as a conditional move +// implemented with a conditional branch and a phi, or an atomic operation +// implemented with a loop. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "expand-isel-pseudos" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Target/TargetLowering.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Support/Debug.h" +using namespace llvm; + +namespace { + class ExpandISelPseudos : public MachineFunctionPass { + public: + static char ID; // Pass identification, replacement for typeid + ExpandISelPseudos() : MachineFunctionPass(ID) {} + + private: + virtual bool runOnMachineFunction(MachineFunction &MF); + + const char *getPassName() const { + return "Expand ISel Pseudo-instructions"; + } + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + MachineFunctionPass::getAnalysisUsage(AU); + } + }; +} // end anonymous namespace + +char ExpandISelPseudos::ID = 0; +INITIALIZE_PASS(ExpandISelPseudos, "expand-isel-pseudos", + "Expand CodeGen Pseudo-instructions", false, false) + +FunctionPass *llvm::createExpandISelPseudosPass() { + return new ExpandISelPseudos(); +} + +bool ExpandISelPseudos::runOnMachineFunction(MachineFunction &MF) { + bool Changed = false; + const TargetLowering *TLI = MF.getTarget().getTargetLowering(); + + // Iterate through each instruction in the function, looking for pseudos. + for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) { + MachineBasicBlock *MBB = I; + for (MachineBasicBlock::iterator MBBI = MBB->begin(), MBBE = MBB->end(); + MBBI != MBBE; ) { + MachineInstr *MI = MBBI++; + + // If MI is a pseudo, expand it. + const TargetInstrDesc &TID = MI->getDesc(); + if (TID.usesCustomInsertionHook()) { + Changed = true; + MachineBasicBlock *NewMBB = + TLI->EmitInstrWithCustomInserter(MI, MBB); + // The expansion may involve new basic blocks. + if (NewMBB != MBB) { + MBB = NewMBB; + I = NewMBB; + MBBI = NewMBB->begin(); + MBBE = NewMBB->end(); + } + } + } + } + + return Changed; +} diff --git a/lib/CodeGen/GCMetadata.cpp b/lib/CodeGen/GCMetadata.cpp index 0f6e882a7be4..d757cf409d50 100644 --- a/lib/CodeGen/GCMetadata.cpp +++ b/lib/CodeGen/GCMetadata.cpp @@ -30,7 +30,6 @@ namespace { raw_ostream &OS; public: - Printer() : FunctionPass(ID), OS(errs()) {} explicit Printer(raw_ostream &OS) : FunctionPass(ID), OS(OS) {} @@ -56,7 +55,7 @@ namespace { } INITIALIZE_PASS(GCModuleInfo, "collector-metadata", - "Create Garbage Collector Module Metadata", false, false); + "Create Garbage Collector Module Metadata", false, false) // ----------------------------------------------------------------------------- @@ -70,7 +69,9 @@ GCFunctionInfo::~GCFunctionInfo() {} char GCModuleInfo::ID = 0; GCModuleInfo::GCModuleInfo() - : ImmutablePass(ID) {} + : ImmutablePass(ID) { + initializeGCModuleInfoPass(*PassRegistry::getPassRegistry()); +} GCModuleInfo::~GCModuleInfo() { clear(); diff --git a/lib/CodeGen/GCStrategy.cpp b/lib/CodeGen/GCStrategy.cpp index 719fa194d8da..766c6ee542a9 100644 --- a/lib/CodeGen/GCStrategy.cpp +++ b/lib/CodeGen/GCStrategy.cpp @@ -19,11 +19,12 @@ #include "llvm/CodeGen/Passes.h" #include "llvm/IntrinsicInst.h" #include "llvm/Module.h" +#include "llvm/Analysis/Dominators.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineModuleInfo.h" -#include "llvm/Target/TargetFrameInfo.h" +#include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetRegisterInfo.h" @@ -123,6 +124,11 @@ GCFunctionInfo *GCStrategy::insertFunctionInfo(const Function &F) { // ----------------------------------------------------------------------------- +INITIALIZE_PASS_BEGIN(LowerIntrinsics, "gc-lowering", "GC Lowering", + false, false) +INITIALIZE_PASS_DEPENDENCY(GCModuleInfo) +INITIALIZE_PASS_END(LowerIntrinsics, "gc-lowering", "GC Lowering", false, false) + FunctionPass *llvm::createGCLoweringPass() { return new LowerIntrinsics(); } @@ -130,7 +136,9 @@ FunctionPass *llvm::createGCLoweringPass() { char LowerIntrinsics::ID = 0; LowerIntrinsics::LowerIntrinsics() - : FunctionPass(ID) {} + : FunctionPass(ID) { + initializeLowerIntrinsicsPass(*PassRegistry::getPassRegistry()); + } const char *LowerIntrinsics::getPassName() const { return "Lower Garbage Collection Instructions"; @@ -139,6 +147,7 @@ const char *LowerIntrinsics::getPassName() const { void LowerIntrinsics::getAnalysisUsage(AnalysisUsage &AU) const { FunctionPass::getAnalysisUsage(AU); AU.addRequired(); + AU.addPreserved(); } /// doInitialization - If this module uses the GC intrinsics, find them now. @@ -249,9 +258,16 @@ bool LowerIntrinsics::runOnFunction(Function &F) { if (NeedsDefaultLoweringPass(S)) MadeChange |= PerformDefaultLowering(F, S); - if (NeedsCustomLoweringPass(S)) + bool UseCustomLoweringPass = NeedsCustomLoweringPass(S); + if (UseCustomLoweringPass) MadeChange |= S.performCustomLowering(F); - + + // Custom lowering may modify the CFG, so dominators must be recomputed. + if (UseCustomLoweringPass) { + if (DominatorTree *DT = getAnalysisIfAvailable()) + DT->DT->recalculate(F); + } + return MadeChange; } @@ -345,13 +361,15 @@ void MachineCodeAnalysis::VisitCallPoint(MachineBasicBlock::iterator CI) { MachineBasicBlock::iterator RAI = CI; ++RAI; - if (FI->getStrategy().needsSafePoint(GC::PreCall)) - FI->addSafePoint(GC::PreCall, InsertLabel(*CI->getParent(), CI, - CI->getDebugLoc())); + if (FI->getStrategy().needsSafePoint(GC::PreCall)) { + MCSymbol* Label = InsertLabel(*CI->getParent(), CI, CI->getDebugLoc()); + FI->addSafePoint(GC::PreCall, Label, CI->getDebugLoc()); + } - if (FI->getStrategy().needsSafePoint(GC::PostCall)) - FI->addSafePoint(GC::PostCall, InsertLabel(*CI->getParent(), RAI, - CI->getDebugLoc())); + if (FI->getStrategy().needsSafePoint(GC::PostCall)) { + MCSymbol* Label = InsertLabel(*CI->getParent(), RAI, CI->getDebugLoc()); + FI->addSafePoint(GC::PostCall, Label, CI->getDebugLoc()); + } } void MachineCodeAnalysis::FindSafePoints(MachineFunction &MF) { @@ -364,12 +382,12 @@ void MachineCodeAnalysis::FindSafePoints(MachineFunction &MF) { } void MachineCodeAnalysis::FindStackOffsets(MachineFunction &MF) { - const TargetRegisterInfo *TRI = TM->getRegisterInfo(); - assert(TRI && "TargetRegisterInfo not available!"); + const TargetFrameLowering *TFI = TM->getFrameLowering(); + assert(TFI && "TargetRegisterInfo not available!"); for (GCFunctionInfo::roots_iterator RI = FI->roots_begin(), RE = FI->roots_end(); RI != RE; ++RI) - RI->StackOffset = TRI->getFrameIndexOffset(MF, RI->Num); + RI->StackOffset = TFI->getFrameIndexOffset(MF, RI->Num); } bool MachineCodeAnalysis::runOnMachineFunction(MachineFunction &MF) { diff --git a/lib/CodeGen/IfConversion.cpp b/lib/CodeGen/IfConversion.cpp index 0ea30d7a7929..db53b0473a9a 100644 --- a/lib/CodeGen/IfConversion.cpp +++ b/lib/CodeGen/IfConversion.cpp @@ -17,7 +17,9 @@ #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineLoopInfo.h" #include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetInstrItineraries.h" #include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetRegisterInfo.h" @@ -26,6 +28,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/DepthFirstIterator.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/STLExtras.h" using namespace llvm; @@ -91,6 +94,8 @@ namespace { /// ClobbersPred - True if BB could modify predicates (e.g. has /// cmp, call, etc.) /// NonPredSize - Number of non-predicated instructions. + /// ExtraCost - Extra cost for multi-cycle instructions. + /// ExtraCost2 - Some instructions are slower when predicated /// BB - Corresponding MachineBasicBlock. /// TrueBB / FalseBB- See AnalyzeBranch(). /// BrCond - Conditions for end of block conditional branches. @@ -106,6 +111,8 @@ namespace { bool CannotBeCopied : 1; bool ClobbersPred : 1; unsigned NonPredSize; + unsigned ExtraCost; + unsigned ExtraCost2; MachineBasicBlock *BB; MachineBasicBlock *TrueBB; MachineBasicBlock *FalseBB; @@ -115,7 +122,7 @@ namespace { IsAnalyzed(false), IsEnqueued(false), IsBrAnalyzable(false), HasFallThrough(false), IsUnpredicable(false), CannotBeCopied(false), ClobbersPred(false), NonPredSize(0), - BB(0), TrueBB(0), FalseBB(0) {} + ExtraCost(0), ExtraCost2(0), BB(0), TrueBB(0), FalseBB(0) {} }; /// IfcvtToken - Record information about pending if-conversions to attempt: @@ -150,20 +157,31 @@ namespace { const TargetLowering *TLI; const TargetInstrInfo *TII; const TargetRegisterInfo *TRI; + const InstrItineraryData *InstrItins; + const MachineLoopInfo *MLI; bool MadeChange; int FnNum; public: static char ID; - IfConverter() : MachineFunctionPass(ID), FnNum(-1) {} + IfConverter() : MachineFunctionPass(ID), FnNum(-1) { + initializeIfConverterPass(*PassRegistry::getPassRegistry()); + } + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired(); + MachineFunctionPass::getAnalysisUsage(AU); + } virtual bool runOnMachineFunction(MachineFunction &MF); virtual const char *getPassName() const { return "If Converter"; } private: bool ReverseBranchCondition(BBInfo &BBI); - bool ValidSimple(BBInfo &TrueBBI, unsigned &Dups) const; + bool ValidSimple(BBInfo &TrueBBI, unsigned &Dups, + float Prediction, float Confidence) const; bool ValidTriangle(BBInfo &TrueBBI, BBInfo &FalseBBI, - bool FalseBranch, unsigned &Dups) const; + bool FalseBranch, unsigned &Dups, + float Prediction, float Confidence) const; bool ValidDiamond(BBInfo &TrueBBI, BBInfo &FalseBBI, unsigned &Dups1, unsigned &Dups2) const; void ScanInstructions(BBInfo &BBI); @@ -188,14 +206,21 @@ namespace { bool IgnoreBr = false); void MergeBlocks(BBInfo &ToBBI, BBInfo &FromBBI, bool AddEdges = true); - bool MeetIfcvtSizeLimit(MachineBasicBlock &BB, unsigned Size) const { - return Size > 0 && TII->isProfitableToIfCvt(BB, Size); + bool MeetIfcvtSizeLimit(MachineBasicBlock &BB, + unsigned Cycle, unsigned Extra, + float Prediction, float Confidence) const { + return Cycle > 0 && TII->isProfitableToIfCvt(BB, Cycle, Extra, + Prediction, Confidence); } - bool MeetIfcvtSizeLimit(MachineBasicBlock &TBB, unsigned TSize, - MachineBasicBlock &FBB, unsigned FSize) const { - return TSize > 0 && FSize > 0 && - TII->isProfitableToIfCvt(TBB, TSize, FBB, FSize); + bool MeetIfcvtSizeLimit(MachineBasicBlock &TBB, + unsigned TCycle, unsigned TExtra, + MachineBasicBlock &FBB, + unsigned FCycle, unsigned FExtra, + float Prediction, float Confidence) const { + return TCycle > 0 && FCycle > 0 && + TII->isProfitableToIfCvt(TBB, TCycle, TExtra, FBB, FCycle, FExtra, + Prediction, Confidence); } // blockAlwaysFallThrough - Block ends without a terminator. @@ -230,7 +255,9 @@ namespace { char IfConverter::ID = 0; } -INITIALIZE_PASS(IfConverter, "if-converter", "If Converter", false, false); +INITIALIZE_PASS_BEGIN(IfConverter, "if-converter", "If Converter", false, false) +INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo) +INITIALIZE_PASS_END(IfConverter, "if-converter", "If Converter", false, false) FunctionPass *llvm::createIfConverterPass() { return new IfConverter(); } @@ -238,6 +265,8 @@ bool IfConverter::runOnMachineFunction(MachineFunction &MF) { TLI = MF.getTarget().getTargetLowering(); TII = MF.getTarget().getInstrInfo(); TRI = MF.getTarget().getRegisterInfo(); + MLI = &getAnalysis(); + InstrItins = MF.getTarget().getInstrItineraryData(); if (!TII) return false; // Tail merge tend to expose more if-conversion opportunities. @@ -431,7 +460,8 @@ static inline MachineBasicBlock *getNextBlock(MachineBasicBlock *BB) { /// predecessor) forms a valid simple shape for ifcvt. It also returns the /// number of instructions that the ifcvt would need to duplicate if performed /// in Dups. -bool IfConverter::ValidSimple(BBInfo &TrueBBI, unsigned &Dups) const { +bool IfConverter::ValidSimple(BBInfo &TrueBBI, unsigned &Dups, + float Prediction, float Confidence) const { Dups = 0; if (TrueBBI.IsBeingAnalyzed || TrueBBI.IsDone) return false; @@ -441,7 +471,8 @@ bool IfConverter::ValidSimple(BBInfo &TrueBBI, unsigned &Dups) const { if (TrueBBI.BB->pred_size() > 1) { if (TrueBBI.CannotBeCopied || - !TII->isProfitableToDupForIfCvt(*TrueBBI.BB, TrueBBI.NonPredSize)) + !TII->isProfitableToDupForIfCvt(*TrueBBI.BB, TrueBBI.NonPredSize, + Prediction, Confidence)) return false; Dups = TrueBBI.NonPredSize; } @@ -456,7 +487,8 @@ bool IfConverter::ValidSimple(BBInfo &TrueBBI, unsigned &Dups) const { /// returns the number of instructions that the ifcvt would need to duplicate /// if performed in 'Dups'. bool IfConverter::ValidTriangle(BBInfo &TrueBBI, BBInfo &FalseBBI, - bool FalseBranch, unsigned &Dups) const { + bool FalseBranch, unsigned &Dups, + float Prediction, float Confidence) const { Dups = 0; if (TrueBBI.IsBeingAnalyzed || TrueBBI.IsDone) return false; @@ -478,7 +510,8 @@ bool IfConverter::ValidTriangle(BBInfo &TrueBBI, BBInfo &FalseBBI, ++Size; } } - if (!TII->isProfitableToDupForIfCvt(*TrueBBI.BB, Size)) + if (!TII->isProfitableToDupForIfCvt(*TrueBBI.BB, Size, + Prediction, Confidence)) return false; Dups = Size; } @@ -493,18 +526,6 @@ bool IfConverter::ValidTriangle(BBInfo &TrueBBI, BBInfo &FalseBBI, return TExit && TExit == FalseBBI.BB; } -static -MachineBasicBlock::iterator firstNonBranchInst(MachineBasicBlock *BB, - const TargetInstrInfo *TII) { - MachineBasicBlock::iterator I = BB->end(); - while (I != BB->begin()) { - --I; - if (!I->getDesc().isBranch()) - break; - } - return I; -} - /// ValidDiamond - Returns true if the 'true' and 'false' blocks (along /// with their common predecessor) forms a valid diamond shape for ifcvt. bool IfConverter::ValidDiamond(BBInfo &TrueBBI, BBInfo &FalseBBI, @@ -533,64 +554,70 @@ bool IfConverter::ValidDiamond(BBInfo &TrueBBI, BBInfo &FalseBBI, (TrueBBI.ClobbersPred && FalseBBI.ClobbersPred)) return false; - MachineBasicBlock::iterator TI = TrueBBI.BB->begin(); - MachineBasicBlock::iterator FI = FalseBBI.BB->begin(); + // Count duplicate instructions at the beginning of the true and false blocks. + MachineBasicBlock::iterator TIB = TrueBBI.BB->begin(); + MachineBasicBlock::iterator FIB = FalseBBI.BB->begin(); MachineBasicBlock::iterator TIE = TrueBBI.BB->end(); MachineBasicBlock::iterator FIE = FalseBBI.BB->end(); - // Skip dbg_value instructions - while (TI != TIE && TI->isDebugValue()) - ++TI; - while (FI != FIE && FI->isDebugValue()) - ++FI; - while (TI != TIE && FI != FIE) { + while (TIB != TIE && FIB != FIE) { // Skip dbg_value instructions. These do not count. - if (TI->isDebugValue()) { - while (TI != TIE && TI->isDebugValue()) - ++TI; - if (TI == TIE) + if (TIB->isDebugValue()) { + while (TIB != TIE && TIB->isDebugValue()) + ++TIB; + if (TIB == TIE) break; } - if (FI->isDebugValue()) { - while (FI != FIE && FI->isDebugValue()) - ++FI; - if (FI == FIE) + if (FIB->isDebugValue()) { + while (FIB != FIE && FIB->isDebugValue()) + ++FIB; + if (FIB == FIE) break; } - if (!TI->isIdenticalTo(FI)) + if (!TIB->isIdenticalTo(FIB)) break; ++Dups1; - ++TI; - ++FI; + ++TIB; + ++FIB; } - TI = firstNonBranchInst(TrueBBI.BB, TII); - FI = firstNonBranchInst(FalseBBI.BB, TII); - MachineBasicBlock::iterator TIB = TrueBBI.BB->begin(); - MachineBasicBlock::iterator FIB = FalseBBI.BB->begin(); - // Skip dbg_value instructions at end of the bb's. - while (TI != TIB && TI->isDebugValue()) - --TI; - while (FI != FIB && FI->isDebugValue()) - --FI; - while (TI != TIB && FI != FIB) { + // Now, in preparation for counting duplicate instructions at the ends of the + // blocks, move the end iterators up past any branch instructions. + while (TIE != TIB) { + --TIE; + if (!TIE->getDesc().isBranch()) + break; + } + while (FIE != FIB) { + --FIE; + if (!FIE->getDesc().isBranch()) + break; + } + + // If Dups1 includes all of a block, then don't count duplicate + // instructions at the end of the blocks. + if (TIB == TIE || FIB == FIE) + return true; + + // Count duplicate instructions at the ends of the blocks. + while (TIE != TIB && FIE != FIB) { // Skip dbg_value instructions. These do not count. - if (TI->isDebugValue()) { - while (TI != TIB && TI->isDebugValue()) - --TI; - if (TI == TIB) + if (TIE->isDebugValue()) { + while (TIE != TIB && TIE->isDebugValue()) + --TIE; + if (TIE == TIB) break; } - if (FI->isDebugValue()) { - while (FI != FIB && FI->isDebugValue()) - --FI; - if (FI == FIB) + if (FIE->isDebugValue()) { + while (FIE != FIB && FIE->isDebugValue()) + --FIE; + if (FIE == FIB) break; } - if (!TI->isIdenticalTo(FI)) + if (!TIE->isIdenticalTo(FIE)) break; ++Dups2; - --TI; - --FI; + --TIE; + --FIE; } return true; @@ -627,6 +654,8 @@ void IfConverter::ScanInstructions(BBInfo &BBI) { // Then scan all the instructions. BBI.NonPredSize = 0; + BBI.ExtraCost = 0; + BBI.ExtraCost2 = 0; BBI.ClobbersPred = false; for (MachineBasicBlock::iterator I = BBI.BB->begin(), E = BBI.BB->end(); I != E; ++I) { @@ -641,9 +670,15 @@ void IfConverter::ScanInstructions(BBInfo &BBI) { bool isCondBr = BBI.IsBrAnalyzable && TID.isConditionalBranch(); if (!isCondBr) { - if (!isPredicated) + if (!isPredicated) { BBI.NonPredSize++; - else if (!AlreadyPredicated) { + unsigned ExtraPredCost = 0; + unsigned NumCycles = TII->getInstrLatency(InstrItins, &*I, + &ExtraPredCost); + if (NumCycles > 1) + BBI.ExtraCost += NumCycles-1; + BBI.ExtraCost2 += ExtraPredCost; + } else if (!AlreadyPredicated) { // FIXME: This instruction is already predicated before the // if-conversion pass. It's probably something like a conditional move. // Mark this block unpredicable for now. @@ -765,9 +800,35 @@ IfConverter::BBInfo &IfConverter::AnalyzeBlock(MachineBasicBlock *BB, bool TNeedSub = TrueBBI.Predicate.size() > 0; bool FNeedSub = FalseBBI.Predicate.size() > 0; bool Enqueued = false; + + // Try to predict the branch, using loop info to guide us. + // General heuristics are: + // - backedge -> 90% taken + // - early exit -> 20% taken + // - branch predictor confidence -> 90% + float Prediction = 0.5f; + float Confidence = 0.9f; + MachineLoop *Loop = MLI->getLoopFor(BB); + if (Loop) { + if (TrueBBI.BB == Loop->getHeader()) + Prediction = 0.9f; + else if (FalseBBI.BB == Loop->getHeader()) + Prediction = 0.1f; + + MachineLoop *TrueLoop = MLI->getLoopFor(TrueBBI.BB); + MachineLoop *FalseLoop = MLI->getLoopFor(FalseBBI.BB); + if (!TrueLoop || TrueLoop->getParentLoop() == Loop) + Prediction = 0.2f; + else if (!FalseLoop || FalseLoop->getParentLoop() == Loop) + Prediction = 0.8f; + } + if (CanRevCond && ValidDiamond(TrueBBI, FalseBBI, Dups, Dups2) && - MeetIfcvtSizeLimit(*TrueBBI.BB, TrueBBI.NonPredSize - (Dups + Dups2), - *FalseBBI.BB, FalseBBI.NonPredSize - (Dups + Dups2)) && + MeetIfcvtSizeLimit(*TrueBBI.BB, (TrueBBI.NonPredSize - (Dups + Dups2) + + TrueBBI.ExtraCost), TrueBBI.ExtraCost2, + *FalseBBI.BB, (FalseBBI.NonPredSize - (Dups + Dups2) + + FalseBBI.ExtraCost),FalseBBI.ExtraCost2, + Prediction, Confidence) && FeasibilityAnalysis(TrueBBI, BBI.BrCond) && FeasibilityAnalysis(FalseBBI, RevCond)) { // Diamond: @@ -783,8 +844,9 @@ IfConverter::BBInfo &IfConverter::AnalyzeBlock(MachineBasicBlock *BB, Enqueued = true; } - if (ValidTriangle(TrueBBI, FalseBBI, false, Dups) && - MeetIfcvtSizeLimit(*TrueBBI.BB, TrueBBI.NonPredSize) && + if (ValidTriangle(TrueBBI, FalseBBI, false, Dups, Prediction, Confidence) && + MeetIfcvtSizeLimit(*TrueBBI.BB, TrueBBI.NonPredSize + TrueBBI.ExtraCost, + TrueBBI.ExtraCost2, Prediction, Confidence) && FeasibilityAnalysis(TrueBBI, BBI.BrCond, true)) { // Triangle: // EBB @@ -797,15 +859,17 @@ IfConverter::BBInfo &IfConverter::AnalyzeBlock(MachineBasicBlock *BB, Enqueued = true; } - if (ValidTriangle(TrueBBI, FalseBBI, true, Dups) && - MeetIfcvtSizeLimit(*TrueBBI.BB, TrueBBI.NonPredSize) && + if (ValidTriangle(TrueBBI, FalseBBI, true, Dups, Prediction, Confidence) && + MeetIfcvtSizeLimit(*TrueBBI.BB, TrueBBI.NonPredSize + TrueBBI.ExtraCost, + TrueBBI.ExtraCost2, Prediction, Confidence) && FeasibilityAnalysis(TrueBBI, BBI.BrCond, true, true)) { Tokens.push_back(new IfcvtToken(BBI, ICTriangleRev, TNeedSub, Dups)); Enqueued = true; } - if (ValidSimple(TrueBBI, Dups) && - MeetIfcvtSizeLimit(*TrueBBI.BB, TrueBBI.NonPredSize) && + if (ValidSimple(TrueBBI, Dups, Prediction, Confidence) && + MeetIfcvtSizeLimit(*TrueBBI.BB, TrueBBI.NonPredSize + TrueBBI.ExtraCost, + TrueBBI.ExtraCost2, Prediction, Confidence) && FeasibilityAnalysis(TrueBBI, BBI.BrCond)) { // Simple (split, no rejoin): // EBB @@ -820,22 +884,30 @@ IfConverter::BBInfo &IfConverter::AnalyzeBlock(MachineBasicBlock *BB, if (CanRevCond) { // Try the other path... - if (ValidTriangle(FalseBBI, TrueBBI, false, Dups) && - MeetIfcvtSizeLimit(*FalseBBI.BB, FalseBBI.NonPredSize) && + if (ValidTriangle(FalseBBI, TrueBBI, false, Dups, + 1.0-Prediction, Confidence) && + MeetIfcvtSizeLimit(*FalseBBI.BB, + FalseBBI.NonPredSize + FalseBBI.ExtraCost, + FalseBBI.ExtraCost2, 1.0-Prediction, Confidence) && FeasibilityAnalysis(FalseBBI, RevCond, true)) { Tokens.push_back(new IfcvtToken(BBI, ICTriangleFalse, FNeedSub, Dups)); Enqueued = true; } - if (ValidTriangle(FalseBBI, TrueBBI, true, Dups) && - MeetIfcvtSizeLimit(*FalseBBI.BB, FalseBBI.NonPredSize) && + if (ValidTriangle(FalseBBI, TrueBBI, true, Dups, + 1.0-Prediction, Confidence) && + MeetIfcvtSizeLimit(*FalseBBI.BB, + FalseBBI.NonPredSize + FalseBBI.ExtraCost, + FalseBBI.ExtraCost2, 1.0-Prediction, Confidence) && FeasibilityAnalysis(FalseBBI, RevCond, true, true)) { Tokens.push_back(new IfcvtToken(BBI, ICTriangleFRev, FNeedSub, Dups)); Enqueued = true; } - if (ValidSimple(FalseBBI, Dups) && - MeetIfcvtSizeLimit(*FalseBBI.BB, FalseBBI.NonPredSize) && + if (ValidSimple(FalseBBI, Dups, 1.0-Prediction, Confidence) && + MeetIfcvtSizeLimit(*FalseBBI.BB, + FalseBBI.NonPredSize + FalseBBI.ExtraCost, + FalseBBI.ExtraCost2, 1.0-Prediction, Confidence) && FeasibilityAnalysis(FalseBBI, RevCond)) { Tokens.push_back(new IfcvtToken(BBI, ICSimpleFalse, FNeedSub, Dups)); Enqueued = true; @@ -1365,6 +1437,11 @@ void IfConverter::CopyAndPredicateBlock(BBInfo &ToBBI, BBInfo &FromBBI, MachineInstr *MI = MF.CloneMachineInstr(I); ToBBI.BB->insert(ToBBI.BB->end(), MI); ToBBI.NonPredSize++; + unsigned ExtraPredCost = 0; + unsigned NumCycles = TII->getInstrLatency(InstrItins, &*I, &ExtraPredCost); + if (NumCycles > 1) + ToBBI.ExtraCost += NumCycles-1; + ToBBI.ExtraCost2 += ExtraPredCost; if (!TII->isPredicated(I) && !MI->isDebugValue()) { if (!TII->PredicateInstruction(MI, Cond)) { @@ -1438,7 +1515,11 @@ void IfConverter::MergeBlocks(BBInfo &ToBBI, BBInfo &FromBBI, bool AddEdges) { FromBBI.Predicate.clear(); ToBBI.NonPredSize += FromBBI.NonPredSize; + ToBBI.ExtraCost += FromBBI.ExtraCost; + ToBBI.ExtraCost2 += FromBBI.ExtraCost2; FromBBI.NonPredSize = 0; + FromBBI.ExtraCost = 0; + FromBBI.ExtraCost2 = 0; ToBBI.ClobbersPred |= FromBBI.ClobbersPred; ToBBI.HasFallThrough = FromBBI.HasFallThrough; diff --git a/lib/CodeGen/InlineSpiller.cpp b/lib/CodeGen/InlineSpiller.cpp index b965bfdcf3b8..a1bd972d38e2 100644 --- a/lib/CodeGen/InlineSpiller.cpp +++ b/lib/CodeGen/InlineSpiller.cpp @@ -12,28 +12,34 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "spiller" +#define DEBUG_TYPE "regalloc" #include "Spiller.h" -#include "SplitKit.h" +#include "LiveRangeEdit.h" #include "VirtRegMap.h" +#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/CodeGen/LiveIntervalAnalysis.h" +#include "llvm/CodeGen/LiveStackAnalysis.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineLoopInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; +static cl::opt +VerifySpills("verify-spills", cl::desc("Verify after each spill/split")); + namespace { class InlineSpiller : public Spiller { MachineFunctionPass &pass_; MachineFunction &mf_; LiveIntervals &lis_; - MachineLoopInfo &loops_; + LiveStacks &lss_; + AliasAnalysis *aa_; VirtRegMap &vrm_; MachineFrameInfo &mfi_; MachineRegisterInfo &mri_; @@ -41,19 +47,12 @@ class InlineSpiller : public Spiller { const TargetRegisterInfo &tri_; const BitVector reserved_; - SplitAnalysis splitAnalysis_; - // Variables that are valid during spill(), but used by multiple methods. - LiveInterval *li_; - SmallVectorImpl *newIntervals_; + LiveRangeEdit *edit_; const TargetRegisterClass *rc_; int stackSlot_; - const SmallVectorImpl *spillIs_; - // Values of the current interval that can potentially remat. - SmallPtrSet reMattable_; - - // Values in reMattable_ that failed to remat at some point. + // Values that failed to remat at some point. SmallPtrSet usedValues_; ~InlineSpiller() {} @@ -65,30 +64,29 @@ public: : pass_(pass), mf_(mf), lis_(pass.getAnalysis()), - loops_(pass.getAnalysis()), + lss_(pass.getAnalysis()), + aa_(&pass.getAnalysis()), vrm_(vrm), mfi_(*mf.getFrameInfo()), mri_(mf.getRegInfo()), tii_(*mf.getTarget().getInstrInfo()), tri_(*mf.getTarget().getRegisterInfo()), - reserved_(tri_.getReservedRegs(mf_)), - splitAnalysis_(mf, lis_, loops_) {} + reserved_(tri_.getReservedRegs(mf_)) {} void spill(LiveInterval *li, SmallVectorImpl &newIntervals, - SmallVectorImpl &spillIs); + const SmallVectorImpl &spillIs); -private: - bool split(); + void spill(LiveRangeEdit &); - bool allUsesAvailableAt(const MachineInstr *OrigMI, SlotIndex OrigIdx, - SlotIndex UseIdx); +private: bool reMaterializeFor(MachineBasicBlock::iterator MI); void reMaterializeAll(); bool coalesceStackAccess(MachineInstr *MI); bool foldMemoryOperand(MachineBasicBlock::iterator MI, - const SmallVectorImpl &Ops); + const SmallVectorImpl &Ops, + MachineInstr *LoadMI = 0); void insertReload(LiveInterval &NewLI, MachineBasicBlock::iterator MI); void insertSpill(LiveInterval &NewLI, MachineBasicBlock::iterator MI); }; @@ -98,106 +96,41 @@ namespace llvm { Spiller *createInlineSpiller(MachineFunctionPass &pass, MachineFunction &mf, VirtRegMap &vrm) { + if (VerifySpills) + mf.verify(&pass, "When creating inline spiller"); return new InlineSpiller(pass, mf, vrm); } } -/// split - try splitting the current interval into pieces that may allocate -/// separately. Return true if successful. -bool InlineSpiller::split() { - splitAnalysis_.analyze(li_); - - if (const MachineLoop *loop = splitAnalysis_.getBestSplitLoop()) { - // We can split, but li_ may be left intact with fewer uses. - if (SplitEditor(splitAnalysis_, lis_, vrm_, *newIntervals_) - .splitAroundLoop(loop)) - return true; - } - - // Try splitting into single block intervals. - SplitAnalysis::BlockPtrSet blocks; - if (splitAnalysis_.getMultiUseBlocks(blocks)) { - if (SplitEditor(splitAnalysis_, lis_, vrm_, *newIntervals_) - .splitSingleBlocks(blocks)) - return true; - } - - // Try splitting inside a basic block. - if (const MachineBasicBlock *MBB = splitAnalysis_.getBlockForInsideSplit()) { - if (SplitEditor(splitAnalysis_, lis_, vrm_, *newIntervals_) - .splitInsideBlock(MBB)) - return true; - } - - // We may have been able to split out some uses, but the original interval is - // intact, and it should still be spilled. - return false; -} - -/// allUsesAvailableAt - Return true if all registers used by OrigMI at -/// OrigIdx are also available with the same value at UseIdx. -bool InlineSpiller::allUsesAvailableAt(const MachineInstr *OrigMI, - SlotIndex OrigIdx, - SlotIndex UseIdx) { - OrigIdx = OrigIdx.getUseIndex(); - UseIdx = UseIdx.getUseIndex(); - for (unsigned i = 0, e = OrigMI->getNumOperands(); i != e; ++i) { - const MachineOperand &MO = OrigMI->getOperand(i); - if (!MO.isReg() || !MO.getReg() || MO.getReg() == li_->reg) - continue; - // Reserved registers are OK. - if (MO.isUndef() || !lis_.hasInterval(MO.getReg())) - continue; - // We don't want to move any defs. - if (MO.isDef()) - return false; - // We cannot depend on virtual registers in spillIs_. They will be spilled. - for (unsigned si = 0, se = spillIs_->size(); si != se; ++si) - if ((*spillIs_)[si]->reg == MO.getReg()) - return false; - - LiveInterval &LI = lis_.getInterval(MO.getReg()); - const VNInfo *OVNI = LI.getVNInfoAt(OrigIdx); - if (!OVNI) - continue; - if (OVNI != LI.getVNInfoAt(UseIdx)) - return false; - } - return true; -} - -/// reMaterializeFor - Attempt to rematerialize li_->reg before MI instead of +/// reMaterializeFor - Attempt to rematerialize edit_->getReg() before MI instead of /// reloading it. bool InlineSpiller::reMaterializeFor(MachineBasicBlock::iterator MI) { SlotIndex UseIdx = lis_.getInstructionIndex(MI).getUseIndex(); - VNInfo *OrigVNI = li_->getVNInfoAt(UseIdx); + VNInfo *OrigVNI = edit_->getParent().getVNInfoAt(UseIdx); + if (!OrigVNI) { DEBUG(dbgs() << "\tadding flags: "); for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { MachineOperand &MO = MI->getOperand(i); - if (MO.isReg() && MO.isUse() && MO.getReg() == li_->reg) + if (MO.isReg() && MO.isUse() && MO.getReg() == edit_->getReg()) MO.setIsUndef(); } DEBUG(dbgs() << UseIdx << '\t' << *MI); return true; } - if (!reMattable_.count(OrigVNI)) { - DEBUG(dbgs() << "\tusing non-remat valno " << OrigVNI->id << ": " - << UseIdx << '\t' << *MI); - return false; - } - MachineInstr *OrigMI = lis_.getInstructionFromIndex(OrigVNI->def); - if (!allUsesAvailableAt(OrigMI, OrigVNI->def, UseIdx)) { + + LiveRangeEdit::Remat RM(OrigVNI); + if (!edit_->canRematerializeAt(RM, UseIdx, false, lis_)) { usedValues_.insert(OrigVNI); DEBUG(dbgs() << "\tcannot remat for " << UseIdx << '\t' << *MI); return false; } - // If the instruction also writes li_->reg, it had better not require the same - // register for uses and defs. + // If the instruction also writes edit_->getReg(), it had better not require + // the same register for uses and defs. bool Reads, Writes; SmallVector Ops; - tie(Reads, Writes) = MI->readsWritesVirtualRegister(li_->reg, &Ops); + tie(Reads, Writes) = MI->readsWritesVirtualRegister(edit_->getReg(), &Ops); if (Writes) { for (unsigned i = 0, e = Ops.size(); i != e; ++i) { MachineOperand &MO = MI->getOperand(Ops[i]); @@ -209,62 +142,57 @@ bool InlineSpiller::reMaterializeFor(MachineBasicBlock::iterator MI) { } } + // Before rematerializing into a register for a single instruction, try to + // fold a load into the instruction. That avoids allocating a new register. + if (RM.OrigMI->getDesc().canFoldAsLoad() && + foldMemoryOperand(MI, Ops, RM.OrigMI)) { + edit_->markRematerialized(RM.ParentVNI); + return true; + } + // Alocate a new register for the remat. - unsigned NewVReg = mri_.createVirtualRegister(rc_); - vrm_.grow(); - LiveInterval &NewLI = lis_.getOrCreateInterval(NewVReg); + LiveInterval &NewLI = edit_->create(mri_, lis_, vrm_); NewLI.markNotSpillable(); - newIntervals_->push_back(&NewLI); + + // Rematting for a copy: Set allocation hint to be the destination register. + if (MI->isCopy()) + mri_.setRegAllocationHint(NewLI.reg, 0, MI->getOperand(0).getReg()); // Finally we can rematerialize OrigMI before MI. - MachineBasicBlock &MBB = *MI->getParent(); - tii_.reMaterialize(MBB, MI, NewLI.reg, 0, OrigMI, tri_); - MachineBasicBlock::iterator RematMI = MI; - SlotIndex DefIdx = lis_.InsertMachineInstrInMaps(--RematMI).getDefIndex(); - DEBUG(dbgs() << "\tremat: " << DefIdx << '\t' << *RematMI); + SlotIndex DefIdx = edit_->rematerializeAt(*MI->getParent(), MI, NewLI.reg, RM, + lis_, tii_, tri_); + DEBUG(dbgs() << "\tremat: " << DefIdx << '\t' + << *lis_.getInstructionFromIndex(DefIdx)); // Replace operands for (unsigned i = 0, e = Ops.size(); i != e; ++i) { MachineOperand &MO = MI->getOperand(Ops[i]); - if (MO.isReg() && MO.isUse() && MO.getReg() == li_->reg) { - MO.setReg(NewVReg); + if (MO.isReg() && MO.isUse() && MO.getReg() == edit_->getReg()) { + MO.setReg(NewLI.reg); MO.setIsKill(); } } DEBUG(dbgs() << "\t " << UseIdx << '\t' << *MI); - VNInfo *DefVNI = NewLI.getNextValue(DefIdx, 0, true, - lis_.getVNInfoAllocator()); + VNInfo *DefVNI = NewLI.getNextValue(DefIdx, 0, lis_.getVNInfoAllocator()); NewLI.addRange(LiveRange(DefIdx, UseIdx.getDefIndex(), DefVNI)); DEBUG(dbgs() << "\tinterval: " << NewLI << '\n'); return true; } -/// reMaterializeAll - Try to rematerialize as many uses of li_ as possible, +/// reMaterializeAll - Try to rematerialize as many uses as possible, /// and trim the live ranges after. void InlineSpiller::reMaterializeAll() { // Do a quick scan of the interval values to find if any are remattable. - reMattable_.clear(); - usedValues_.clear(); - for (LiveInterval::const_vni_iterator I = li_->vni_begin(), - E = li_->vni_end(); I != E; ++I) { - VNInfo *VNI = *I; - if (VNI->isUnused() || !VNI->isDefAccurate()) - continue; - MachineInstr *DefMI = lis_.getInstructionFromIndex(VNI->def); - if (!DefMI || !tii_.isTriviallyReMaterializable(DefMI)) - continue; - reMattable_.insert(VNI); - } - - // Often, no defs are remattable. - if (reMattable_.empty()) + if (!edit_->anyRematerializable(lis_, tii_, aa_)) return; - // Try to remat before all uses of li_->reg. + usedValues_.clear(); + + // Try to remat before all uses of edit_->getReg(). bool anyRemat = false; for (MachineRegisterInfo::use_nodbg_iterator - RI = mri_.use_nodbg_begin(li_->reg); + RI = mri_.use_nodbg_begin(edit_->getReg()); MachineInstr *MI = RI.skipInstruction();) anyRemat |= reMaterializeFor(MI); @@ -273,33 +201,35 @@ void InlineSpiller::reMaterializeAll() { // Remove any values that were completely rematted. bool anyRemoved = false; - for (SmallPtrSet::iterator I = reMattable_.begin(), - E = reMattable_.end(); I != E; ++I) { + for (LiveInterval::vni_iterator I = edit_->getParent().vni_begin(), + E = edit_->getParent().vni_end(); I != E; ++I) { VNInfo *VNI = *I; - if (VNI->hasPHIKill() || usedValues_.count(VNI)) + if (VNI->hasPHIKill() || !edit_->didRematerialize(VNI) || + usedValues_.count(VNI)) continue; MachineInstr *DefMI = lis_.getInstructionFromIndex(VNI->def); DEBUG(dbgs() << "\tremoving dead def: " << VNI->def << '\t' << *DefMI); lis_.RemoveMachineInstrFromMaps(DefMI); vrm_.RemoveMachineInstrFromMaps(DefMI); DefMI->eraseFromParent(); - VNI->setIsDefAccurate(false); + VNI->def = SlotIndex(); anyRemoved = true; } if (!anyRemoved) return; - // Removing values may cause debug uses where li_ is not live. - for (MachineRegisterInfo::use_iterator RI = mri_.use_begin(li_->reg); + // Removing values may cause debug uses where parent is not live. + for (MachineRegisterInfo::use_iterator RI = mri_.use_begin(edit_->getReg()); MachineInstr *MI = RI.skipInstruction();) { if (!MI->isDebugValue()) continue; - // Try to preserve the debug value if li_ is live immediately after it. + // Try to preserve the debug value if parent is live immediately after it. MachineBasicBlock::iterator NextMI = MI; ++NextMI; if (NextMI != MI->getParent()->end() && !lis_.isNotInMIMap(NextMI)) { - VNInfo *VNI = li_->getVNInfoAt(lis_.getInstructionIndex(NextMI)); + SlotIndex Idx = lis_.getInstructionIndex(NextMI); + VNInfo *VNI = edit_->getParent().getVNInfoAt(Idx); if (VNI && (VNI->hasPHIKill() || usedValues_.count(VNI))) continue; } @@ -317,7 +247,7 @@ bool InlineSpiller::coalesceStackAccess(MachineInstr *MI) { return false; // We have a stack access. Is it the right register and slot? - if (reg != li_->reg || FI != stackSlot_) + if (reg != edit_->getReg() || FI != stackSlot_) return false; DEBUG(dbgs() << "Coalescing stack access: " << *MI); @@ -327,9 +257,13 @@ bool InlineSpiller::coalesceStackAccess(MachineInstr *MI) { } /// foldMemoryOperand - Try folding stack slot references in Ops into MI. -/// Return true on success, and MI will be erased. +/// @param MI Instruction using or defining the current register. +/// @param Ops Operand indices from readsWritesVirtualRegister(). +/// @param LoadMI Load instruction to use instead of stack slot when non-null. +/// @return True on success, and MI will be erased. bool InlineSpiller::foldMemoryOperand(MachineBasicBlock::iterator MI, - const SmallVectorImpl &Ops) { + const SmallVectorImpl &Ops, + MachineInstr *LoadMI) { // TargetInstrInfo::foldMemoryOperand only expects explicit, non-tied // operands. SmallVector FoldOps; @@ -341,16 +275,22 @@ bool InlineSpiller::foldMemoryOperand(MachineBasicBlock::iterator MI, // FIXME: Teach targets to deal with subregs. if (MO.getSubReg()) return false; + // We cannot fold a load instruction into a def. + if (LoadMI && MO.isDef()) + return false; // Tied use operands should not be passed to foldMemoryOperand. if (!MI->isRegTiedToDefOperand(Idx)) FoldOps.push_back(Idx); } - MachineInstr *FoldMI = tii_.foldMemoryOperand(MI, FoldOps, stackSlot_); + MachineInstr *FoldMI = + LoadMI ? tii_.foldMemoryOperand(MI, FoldOps, LoadMI) + : tii_.foldMemoryOperand(MI, FoldOps, stackSlot_); if (!FoldMI) return false; lis_.ReplaceMachineInstrInMaps(MI, FoldMI); - vrm_.addSpillSlotUse(stackSlot_, FoldMI); + if (!LoadMI) + vrm_.addSpillSlotUse(stackSlot_, FoldMI); MI->eraseFromParent(); DEBUG(dbgs() << "\tfolded: " << *FoldMI); return true; @@ -366,7 +306,7 @@ void InlineSpiller::insertReload(LiveInterval &NewLI, SlotIndex LoadIdx = lis_.InsertMachineInstrInMaps(MI).getDefIndex(); vrm_.addSpillSlotUse(stackSlot_, MI); DEBUG(dbgs() << "\treload: " << LoadIdx << '\t' << *MI); - VNInfo *LoadVNI = NewLI.getNextValue(LoadIdx, 0, true, + VNInfo *LoadVNI = NewLI.getNextValue(LoadIdx, 0, lis_.getVNInfoAllocator()); NewLI.addRange(LiveRange(LoadIdx, Idx, LoadVNI)); } @@ -375,44 +315,58 @@ void InlineSpiller::insertReload(LiveInterval &NewLI, void InlineSpiller::insertSpill(LiveInterval &NewLI, MachineBasicBlock::iterator MI) { MachineBasicBlock &MBB = *MI->getParent(); + + // Get the defined value. It could be an early clobber so keep the def index. SlotIndex Idx = lis_.getInstructionIndex(MI).getDefIndex(); + VNInfo *VNI = edit_->getParent().getVNInfoAt(Idx); + assert(VNI && VNI->def.getDefIndex() == Idx && "Inconsistent VNInfo"); + Idx = VNI->def; + tii_.storeRegToStackSlot(MBB, ++MI, NewLI.reg, true, stackSlot_, rc_, &tri_); --MI; // Point to store instruction. SlotIndex StoreIdx = lis_.InsertMachineInstrInMaps(MI).getDefIndex(); vrm_.addSpillSlotUse(stackSlot_, MI); DEBUG(dbgs() << "\tspilled: " << StoreIdx << '\t' << *MI); - VNInfo *StoreVNI = NewLI.getNextValue(Idx, 0, true, - lis_.getVNInfoAllocator()); + VNInfo *StoreVNI = NewLI.getNextValue(Idx, 0, lis_.getVNInfoAllocator()); NewLI.addRange(LiveRange(Idx, StoreIdx, StoreVNI)); } void InlineSpiller::spill(LiveInterval *li, SmallVectorImpl &newIntervals, - SmallVectorImpl &spillIs) { - DEBUG(dbgs() << "Inline spilling " << *li << "\n"); - assert(li->isSpillable() && "Attempting to spill already spilled value."); - assert(!li->isStackSlot() && "Trying to spill a stack slot."); - - li_ = li; - newIntervals_ = &newIntervals; - rc_ = mri_.getRegClass(li->reg); - spillIs_ = &spillIs; + const SmallVectorImpl &spillIs) { + LiveRangeEdit edit(*li, newIntervals, spillIs); + spill(edit); + if (VerifySpills) + mf_.verify(&pass_, "After inline spill"); +} - if (split()) - return; +void InlineSpiller::spill(LiveRangeEdit &edit) { + edit_ = &edit; + assert(!TargetRegisterInfo::isStackSlot(edit.getReg()) + && "Trying to spill a stack slot."); + DEBUG(dbgs() << "Inline spilling " + << mri_.getRegClass(edit.getReg())->getName() + << ':' << edit.getParent() << "\n"); + assert(edit.getParent().isSpillable() && + "Attempting to spill already spilled value."); reMaterializeAll(); // Remat may handle everything. - if (li_->empty()) + if (edit_->getParent().empty()) return; - stackSlot_ = vrm_.getStackSlot(li->reg); - if (stackSlot_ == VirtRegMap::NO_STACK_SLOT) - stackSlot_ = vrm_.assignVirt2StackSlot(li->reg); + rc_ = mri_.getRegClass(edit.getReg()); + stackSlot_ = vrm_.assignVirt2StackSlot(edit_->getReg()); + + // Update LiveStacks now that we are committed to spilling. + LiveInterval &stacklvr = lss_.getOrCreateInterval(stackSlot_, rc_); + assert(stacklvr.empty() && "Just created stack slot not empty"); + stacklvr.getNextValue(SlotIndex(), 0, lss_.getVNInfoAllocator()); + stacklvr.MergeRangesInAsValue(edit_->getParent(), stacklvr.getValNumInfo(0)); // Iterate over instructions using register. - for (MachineRegisterInfo::reg_iterator RI = mri_.reg_begin(li->reg); + for (MachineRegisterInfo::reg_iterator RI = mri_.reg_begin(edit.getReg()); MachineInstr *MI = RI.skipInstruction();) { // Debug values are not allowed to affect codegen. @@ -440,7 +394,7 @@ void InlineSpiller::spill(LiveInterval *li, // Analyze instruction. bool Reads, Writes; SmallVector Ops; - tie(Reads, Writes) = MI->readsWritesVirtualRegister(li->reg, &Ops); + tie(Reads, Writes) = MI->readsWritesVirtualRegister(edit.getReg(), &Ops); // Attempt to fold memory ops. if (foldMemoryOperand(MI, Ops)) @@ -448,9 +402,7 @@ void InlineSpiller::spill(LiveInterval *li, // Allocate interval around instruction. // FIXME: Infer regclass from instruction alone. - unsigned NewVReg = mri_.createVirtualRegister(rc_); - vrm_.grow(); - LiveInterval &NewLI = lis_.getOrCreateInterval(NewVReg); + LiveInterval &NewLI = edit.create(mri_, lis_, vrm_); NewLI.markNotSpillable(); if (Reads) @@ -460,7 +412,7 @@ void InlineSpiller::spill(LiveInterval *li, bool hasLiveDef = false; for (unsigned i = 0, e = Ops.size(); i != e; ++i) { MachineOperand &MO = MI->getOperand(Ops[i]); - MO.setReg(NewVReg); + MO.setReg(NewLI.reg); if (MO.isUse()) { if (!MI->isRegTiedToDefOperand(Ops[i])) MO.setIsKill(); @@ -475,6 +427,5 @@ void InlineSpiller::spill(LiveInterval *li, insertSpill(NewLI, MI); DEBUG(dbgs() << "\tinterval: " << NewLI << '\n'); - newIntervals.push_back(&NewLI); } } diff --git a/lib/CodeGen/IntrinsicLowering.cpp b/lib/CodeGen/IntrinsicLowering.cpp index 3852ebaf6425..3861ddadf655 100644 --- a/lib/CodeGen/IntrinsicLowering.cpp +++ b/lib/CodeGen/IntrinsicLowering.cpp @@ -85,9 +85,11 @@ static CallInst *ReplaceCallWith(const char *NewFn, CallInst *CI, } // VisualStudio defines setjmp as _setjmp -#if defined(_MSC_VER) && defined(setjmp) -#define setjmp_undefined_for_visual_studio -#undef setjmp +#if defined(_MSC_VER) && defined(setjmp) && \ + !defined(setjmp_undefined_for_msvc) +# pragma push_macro("setjmp") +# undef setjmp +# define setjmp_undefined_for_msvc #endif void IntrinsicLowering::AddPrototypes(Module &M) { @@ -536,3 +538,27 @@ void IntrinsicLowering::LowerIntrinsicCall(CallInst *CI) { "Lowering should have eliminated any uses of the intrinsic call!"); CI->eraseFromParent(); } + +bool IntrinsicLowering::LowerToByteSwap(CallInst *CI) { + // Verify this is a simple bswap. + if (CI->getNumArgOperands() != 1 || + CI->getType() != CI->getArgOperand(0)->getType() || + !CI->getType()->isIntegerTy()) + return false; + + const IntegerType *Ty = dyn_cast(CI->getType()); + if (!Ty) + return false; + + // Okay, we can do this xform, do so now. + const Type *Tys[] = { Ty }; + Module *M = CI->getParent()->getParent()->getParent(); + Constant *Int = Intrinsic::getDeclaration(M, Intrinsic::bswap, Tys, 1); + + Value *Op = CI->getArgOperand(0); + Op = CallInst::Create(Int, Op, CI->getName(), CI); + + CI->replaceAllUsesWith(Op); + CI->eraseFromParent(); + return true; +} diff --git a/lib/CodeGen/LLVMTargetMachine.cpp b/lib/CodeGen/LLVMTargetMachine.cpp index 36038027b259..80dfc763af69 100644 --- a/lib/CodeGen/LLVMTargetMachine.cpp +++ b/lib/CodeGen/LLVMTargetMachine.cpp @@ -20,9 +20,11 @@ #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/GCStrategy.h" #include "llvm/CodeGen/Passes.h" +#include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetOptions.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCStreamer.h" +#include "llvm/Target/TargetAsmInfo.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetRegistry.h" #include "llvm/Transforms/Scalar.h" @@ -30,6 +32,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/StandardPasses.h" using namespace llvm; namespace llvm { @@ -140,13 +143,19 @@ bool LLVMTargetMachine::addPassesToEmitFile(PassManagerBase &PM, // Create a code emitter if asked to show the encoding. MCCodeEmitter *MCE = 0; - if (ShowMCEncoding) + TargetAsmBackend *TAB = 0; + if (ShowMCEncoding) { MCE = getTarget().createCodeEmitter(*this, *Context); - - AsmStreamer.reset(createAsmStreamer(*Context, Out, - getTargetData()->isLittleEndian(), - getVerboseAsm(), InstPrinter, - MCE, ShowMCInst)); + TAB = getTarget().createAsmBackend(TargetTriple); + } + + MCStreamer *S = getTarget().createAsmStreamer(*Context, Out, + getVerboseAsm(), + hasMCUseLoc(), + InstPrinter, + MCE, TAB, + ShowMCInst); + AsmStreamer.reset(S); break; } case CGFT_ObjectFile: { @@ -159,7 +168,9 @@ bool LLVMTargetMachine::addPassesToEmitFile(PassManagerBase &PM, AsmStreamer.reset(getTarget().createObjectStreamer(TargetTriple, *Context, *TAB, Out, MCE, - hasMCRelaxAll())); + hasMCRelaxAll(), + hasMCNoExecStack())); + AsmStreamer.get()->InitSections(); break; } case CGFT_Null: @@ -241,7 +252,7 @@ static void printAndVerify(PassManagerBase &PM, PM.add(createMachineFunctionPrinterPass(dbgs(), Banner)); if (VerifyMachineCode) - PM.add(createMachineVerifierPass()); + PM.add(createMachineVerifierPass(Banner)); } /// addCommonCodeGenPasses - Add standard LLVM codegen passes used for both @@ -253,6 +264,9 @@ bool LLVMTargetMachine::addCommonCodeGenPasses(PassManagerBase &PM, MCContext *&OutContext) { // Standard LLVM-Level Passes. + // Basic AliasAnalysis support. + createStandardAliasAnalysisPasses(&PM); + // Before running any passes, run the verifier to determine if the input // coming from the front-end and/or optimizer is valid. if (!DisableVerify) @@ -288,7 +302,8 @@ bool LLVMTargetMachine::addCommonCodeGenPasses(PassManagerBase &PM, // edge from elsewhere. PM.add(createSjLjEHPass(getTargetLowering())); // FALLTHROUGH - case ExceptionHandling::Dwarf: + case ExceptionHandling::DwarfCFI: + case ExceptionHandling::DwarfTable: PM.add(createDwarfEHPass(this)); break; case ExceptionHandling::None: @@ -320,7 +335,8 @@ bool LLVMTargetMachine::addCommonCodeGenPasses(PassManagerBase &PM, // Install a MachineModuleInfo class, which is an immutable pass that holds // all the per-module stuff we're generating, including MCContext. - MachineModuleInfo *MMI = new MachineModuleInfo(*getMCAsmInfo()); + TargetAsmInfo *TAI = new TargetAsmInfo(*this); + MachineModuleInfo *MMI = new MachineModuleInfo(*getMCAsmInfo(), TAI); PM.add(MMI); OutContext = &MMI->getContext(); // Return the MCContext specifically by-ref. @@ -339,6 +355,9 @@ bool LLVMTargetMachine::addCommonCodeGenPasses(PassManagerBase &PM, // Print the instruction selected machine code... printAndVerify(PM, "After Instruction Selection"); + // Expand pseudo-instructions emitted by ISel. + PM.add(createExpandISelPseudosPass()); + // Optimize PHIs before DCE: removing dead PHI cycles may make more // instructions dead. if (OptLevel != CodeGenOpt::None) @@ -356,13 +375,15 @@ bool LLVMTargetMachine::addCommonCodeGenPasses(PassManagerBase &PM, PM.add(createDeadMachineInstructionElimPass()); printAndVerify(PM, "After codegen DCE pass"); - PM.add(createPeepholeOptimizerPass()); if (!DisableMachineLICM) PM.add(createMachineLICMPass()); PM.add(createMachineCSEPass()); if (!DisableMachineSink) PM.add(createMachineSinkingPass()); printAndVerify(PM, "After Machine LICM, CSE and Sinking passes"); + + PM.add(createPeepholeOptimizerPass()); + printAndVerify(PM, "After codegen peephole optimization pass"); } // Pre-ra tail duplication. diff --git a/lib/CodeGen/LatencyPriorityQueue.cpp b/lib/CodeGen/LatencyPriorityQueue.cpp index b9527fafbee8..0eb009ddac29 100644 --- a/lib/CodeGen/LatencyPriorityQueue.cpp +++ b/lib/CodeGen/LatencyPriorityQueue.cpp @@ -16,6 +16,7 @@ #define DEBUG_TYPE "scheduler" #include "llvm/CodeGen/LatencyPriorityQueue.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; bool latency_sort::operator()(const SUnit *LHS, const SUnit *RHS) const { @@ -35,14 +36,14 @@ bool latency_sort::operator()(const SUnit *LHS, const SUnit *RHS) const { unsigned RHSLatency = PQ->getLatency(RHSNum); if (LHSLatency < RHSLatency) return true; if (LHSLatency > RHSLatency) return false; - + // After that, if two nodes have identical latencies, look to see if one will // unblock more other nodes than the other. unsigned LHSBlocked = PQ->getNumSolelyBlockNodes(LHSNum); unsigned RHSBlocked = PQ->getNumSolelyBlockNodes(RHSNum); if (LHSBlocked < RHSBlocked) return true; if (LHSBlocked > RHSBlocked) return false; - + // Finally, just to provide a stable ordering, use the node number as a // deciding factor. return LHSNum < RHSNum; @@ -64,7 +65,7 @@ SUnit *LatencyPriorityQueue::getSingleUnscheduledPred(SUnit *SU) { OnlyAvailablePred = &Pred; } } - + return OnlyAvailablePred; } @@ -78,7 +79,7 @@ void LatencyPriorityQueue::push(SUnit *SU) { ++NumNodesBlocking; } NumNodesSolelyBlocking[SU->NodeNum] = NumNodesBlocking; - + Queue.push_back(SU); } @@ -102,10 +103,10 @@ void LatencyPriorityQueue::ScheduledNode(SUnit *SU) { /// node of the same priority that will not make a node available. void LatencyPriorityQueue::AdjustPriorityOfUnscheduledPreds(SUnit *SU) { if (SU->isAvailable) return; // All preds scheduled. - + SUnit *OnlyAvailablePred = getSingleUnscheduledPred(SU); if (OnlyAvailablePred == 0 || !OnlyAvailablePred->isAvailable) return; - + // Okay, we found a single predecessor that is available, but not scheduled. // Since it is available, it must be in the priority queue. First remove it. remove(OnlyAvailablePred); @@ -136,3 +137,16 @@ void LatencyPriorityQueue::remove(SUnit *SU) { std::swap(*I, Queue.back()); Queue.pop_back(); } + +#ifdef NDEBUG +void LatencyPriorityQueue::dump(ScheduleDAG *DAG) const {} +#else +void LatencyPriorityQueue::dump(ScheduleDAG *DAG) const { + LatencyPriorityQueue q = *this; + while (!q.empty()) { + SUnit *su = q.pop(); + dbgs() << "Height " << su->getHeight() << ": "; + su->dump(DAG); + } +} +#endif diff --git a/lib/CodeGen/LiveDebugVariables.cpp b/lib/CodeGen/LiveDebugVariables.cpp new file mode 100644 index 000000000000..853ec1ac7c13 --- /dev/null +++ b/lib/CodeGen/LiveDebugVariables.cpp @@ -0,0 +1,711 @@ +//===- LiveDebugVariables.cpp - Tracking debug info variables -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the LiveDebugVariables analysis. +// +// Remove all DBG_VALUE instructions referencing virtual registers and replace +// them with a data structure tracking where live user variables are kept - in a +// virtual register or in a stack slot. +// +// Allow the data structure to be updated during register allocation when values +// are moved between registers and stack slots. Finally emit new DBG_VALUE +// instructions after register allocation is complete. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "livedebug" +#include "LiveDebugVariables.h" +#include "VirtRegMap.h" +#include "llvm/Constants.h" +#include "llvm/Metadata.h" +#include "llvm/Value.h" +#include "llvm/ADT/IntervalMap.h" +#include "llvm/CodeGen/LiveIntervalAnalysis.h" +#include "llvm/CodeGen/MachineDominators.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetRegisterInfo.h" + +using namespace llvm; + +static cl::opt +EnableLDV("live-debug-variables", cl::init(true), + cl::desc("Enable the live debug variables pass"), cl::Hidden); + +char LiveDebugVariables::ID = 0; + +INITIALIZE_PASS_BEGIN(LiveDebugVariables, "livedebugvars", + "Debug Variable Analysis", false, false) +INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree) +INITIALIZE_PASS_DEPENDENCY(LiveIntervals) +INITIALIZE_PASS_END(LiveDebugVariables, "livedebugvars", + "Debug Variable Analysis", false, false) + +void LiveDebugVariables::getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired(); + AU.addRequiredTransitive(); + AU.setPreservesAll(); + MachineFunctionPass::getAnalysisUsage(AU); +} + +LiveDebugVariables::LiveDebugVariables() : MachineFunctionPass(ID), pImpl(0) { + initializeLiveDebugVariablesPass(*PassRegistry::getPassRegistry()); +} + +/// LocMap - Map of where a user value is live, and its location. +typedef IntervalMap LocMap; + +/// UserValue - A user value is a part of a debug info user variable. +/// +/// A DBG_VALUE instruction notes that (a sub-register of) a virtual register +/// holds part of a user variable. The part is identified by a byte offset. +/// +/// UserValues are grouped into equivalence classes for easier searching. Two +/// user values are related if they refer to the same variable, or if they are +/// held by the same virtual register. The equivalence class is the transitive +/// closure of that relation. +namespace { +class UserValue { + const MDNode *variable; ///< The debug info variable we are part of. + unsigned offset; ///< Byte offset into variable. + DebugLoc dl; ///< The debug location for the variable. This is + ///< used by dwarf writer to find lexical scope. + UserValue *leader; ///< Equivalence class leader. + UserValue *next; ///< Next value in equivalence class, or null. + + /// Numbered locations referenced by locmap. + SmallVector locations; + + /// Map of slot indices where this value is live. + LocMap locInts; + + /// coalesceLocation - After LocNo was changed, check if it has become + /// identical to another location, and coalesce them. This may cause LocNo or + /// a later location to be erased, but no earlier location will be erased. + void coalesceLocation(unsigned LocNo); + + /// insertDebugValue - Insert a DBG_VALUE into MBB at Idx for LocNo. + void insertDebugValue(MachineBasicBlock *MBB, SlotIndex Idx, unsigned LocNo, + LiveIntervals &LIS, const TargetInstrInfo &TII); + + /// insertDebugKill - Insert an undef DBG_VALUE into MBB at Idx. + void insertDebugKill(MachineBasicBlock *MBB, SlotIndex Idx, + LiveIntervals &LIS, const TargetInstrInfo &TII); + +public: + /// UserValue - Create a new UserValue. + UserValue(const MDNode *var, unsigned o, DebugLoc L, + LocMap::Allocator &alloc) + : variable(var), offset(o), dl(L), leader(this), next(0), locInts(alloc) + {} + + /// getLeader - Get the leader of this value's equivalence class. + UserValue *getLeader() { + UserValue *l = leader; + while (l != l->leader) + l = l->leader; + return leader = l; + } + + /// getNext - Return the next UserValue in the equivalence class. + UserValue *getNext() const { return next; } + + /// match - Does this UserValue match the aprameters? + bool match(const MDNode *Var, unsigned Offset) const { + return Var == variable && Offset == offset; + } + + /// merge - Merge equivalence classes. + static UserValue *merge(UserValue *L1, UserValue *L2) { + L2 = L2->getLeader(); + if (!L1) + return L2; + L1 = L1->getLeader(); + if (L1 == L2) + return L1; + // Splice L2 before L1's members. + UserValue *End = L2; + while (End->next) + End->leader = L1, End = End->next; + End->leader = L1; + End->next = L1->next; + L1->next = L2; + return L1; + } + + /// getLocationNo - Return the location number that matches Loc. + unsigned getLocationNo(const MachineOperand &LocMO) { + if (LocMO.isReg() && LocMO.getReg() == 0) + return ~0u; + for (unsigned i = 0, e = locations.size(); i != e; ++i) + if (LocMO.isIdenticalTo(locations[i])) + return i; + locations.push_back(LocMO); + // We are storing a MachineOperand outside a MachineInstr. + locations.back().clearParent(); + return locations.size() - 1; + } + + /// addDef - Add a definition point to this value. + void addDef(SlotIndex Idx, const MachineOperand &LocMO) { + // Add a singular (Idx,Idx) -> Loc mapping. + LocMap::iterator I = locInts.find(Idx); + if (!I.valid() || I.start() != Idx) + I.insert(Idx, Idx.getNextSlot(), getLocationNo(LocMO)); + } + + /// extendDef - Extend the current definition as far as possible down the + /// dominator tree. Stop when meeting an existing def or when leaving the live + /// range of VNI. + /// @param Idx Starting point for the definition. + /// @param LocNo Location number to propagate. + /// @param LI Restrict liveness to where LI has the value VNI. May be null. + /// @param VNI When LI is not null, this is the value to restrict to. + /// @param LIS Live intervals analysis. + /// @param MDT Dominator tree. + void extendDef(SlotIndex Idx, unsigned LocNo, + LiveInterval *LI, const VNInfo *VNI, + LiveIntervals &LIS, MachineDominatorTree &MDT); + + /// computeIntervals - Compute the live intervals of all locations after + /// collecting all their def points. + void computeIntervals(LiveIntervals &LIS, MachineDominatorTree &MDT); + + /// renameRegister - Update locations to rewrite OldReg as NewReg:SubIdx. + void renameRegister(unsigned OldReg, unsigned NewReg, unsigned SubIdx, + const TargetRegisterInfo *TRI); + + /// rewriteLocations - Rewrite virtual register locations according to the + /// provided virtual register map. + void rewriteLocations(VirtRegMap &VRM, const TargetRegisterInfo &TRI); + + /// emitDebugVariables - Recreate DBG_VALUE instruction from data structures. + void emitDebugValues(VirtRegMap *VRM, + LiveIntervals &LIS, const TargetInstrInfo &TRI); + + /// findDebugLoc - Return DebugLoc used for this DBG_VALUE instruction. A + /// variable may have more than one corresponding DBG_VALUE instructions. + /// Only first one needs DebugLoc to identify variable's lexical scope + /// in source file. + DebugLoc findDebugLoc(); + void print(raw_ostream&, const TargetRegisterInfo*); +}; +} // namespace + +/// LDVImpl - Implementation of the LiveDebugVariables pass. +namespace { +class LDVImpl { + LiveDebugVariables &pass; + LocMap::Allocator allocator; + MachineFunction *MF; + LiveIntervals *LIS; + MachineDominatorTree *MDT; + const TargetRegisterInfo *TRI; + + /// userValues - All allocated UserValue instances. + SmallVector userValues; + + /// Map virtual register to eq class leader. + typedef DenseMap VRMap; + VRMap virtRegToEqClass; + + /// Map user variable to eq class leader. + typedef DenseMap UVMap; + UVMap userVarMap; + + /// getUserValue - Find or create a UserValue. + UserValue *getUserValue(const MDNode *Var, unsigned Offset, DebugLoc DL); + + /// lookupVirtReg - Find the EC leader for VirtReg or null. + UserValue *lookupVirtReg(unsigned VirtReg); + + /// mapVirtReg - Map virtual register to an equivalence class. + void mapVirtReg(unsigned VirtReg, UserValue *EC); + + /// handleDebugValue - Add DBG_VALUE instruction to our maps. + /// @param MI DBG_VALUE instruction + /// @param Idx Last valid SLotIndex before instruction. + /// @return True if the DBG_VALUE instruction should be deleted. + bool handleDebugValue(MachineInstr *MI, SlotIndex Idx); + + /// collectDebugValues - Collect and erase all DBG_VALUE instructions, adding + /// a UserValue def for each instruction. + /// @param mf MachineFunction to be scanned. + /// @return True if any debug values were found. + bool collectDebugValues(MachineFunction &mf); + + /// computeIntervals - Compute the live intervals of all user values after + /// collecting all their def points. + void computeIntervals(); + +public: + LDVImpl(LiveDebugVariables *ps) : pass(*ps) {} + bool runOnMachineFunction(MachineFunction &mf); + + /// clear - Relase all memory. + void clear() { + DeleteContainerPointers(userValues); + userValues.clear(); + virtRegToEqClass.clear(); + userVarMap.clear(); + } + + /// renameRegister - Replace all references to OldReg wiht NewReg:SubIdx. + void renameRegister(unsigned OldReg, unsigned NewReg, unsigned SubIdx); + + /// emitDebugVariables - Recreate DBG_VALUE instruction from data structures. + void emitDebugValues(VirtRegMap *VRM); + + void print(raw_ostream&); +}; +} // namespace + +void UserValue::print(raw_ostream &OS, const TargetRegisterInfo *TRI) { + if (const MDString *MDS = dyn_cast(variable->getOperand(2))) + OS << "!\"" << MDS->getString() << "\"\t"; + if (offset) + OS << '+' << offset; + for (LocMap::const_iterator I = locInts.begin(); I.valid(); ++I) { + OS << " [" << I.start() << ';' << I.stop() << "):"; + if (I.value() == ~0u) + OS << "undef"; + else + OS << I.value(); + } + for (unsigned i = 0, e = locations.size(); i != e; ++i) + OS << " Loc" << i << '=' << locations[i]; + OS << '\n'; +} + +void LDVImpl::print(raw_ostream &OS) { + OS << "********** DEBUG VARIABLES **********\n"; + for (unsigned i = 0, e = userValues.size(); i != e; ++i) + userValues[i]->print(OS, TRI); +} + +void UserValue::coalesceLocation(unsigned LocNo) { + unsigned KeepLoc = 0; + for (unsigned e = locations.size(); KeepLoc != e; ++KeepLoc) { + if (KeepLoc == LocNo) + continue; + if (locations[KeepLoc].isIdenticalTo(locations[LocNo])) + break; + } + // No matches. + if (KeepLoc == locations.size()) + return; + + // Keep the smaller location, erase the larger one. + unsigned EraseLoc = LocNo; + if (KeepLoc > EraseLoc) + std::swap(KeepLoc, EraseLoc); + locations.erase(locations.begin() + EraseLoc); + + // Rewrite values. + for (LocMap::iterator I = locInts.begin(); I.valid(); ++I) { + unsigned v = I.value(); + if (v == EraseLoc) + I.setValue(KeepLoc); // Coalesce when possible. + else if (v > EraseLoc) + I.setValueUnchecked(v-1); // Avoid coalescing with untransformed values. + } +} + +UserValue *LDVImpl::getUserValue(const MDNode *Var, unsigned Offset, + DebugLoc DL) { + UserValue *&Leader = userVarMap[Var]; + if (Leader) { + UserValue *UV = Leader->getLeader(); + Leader = UV; + for (; UV; UV = UV->getNext()) + if (UV->match(Var, Offset)) + return UV; + } + + UserValue *UV = new UserValue(Var, Offset, DL, allocator); + userValues.push_back(UV); + Leader = UserValue::merge(Leader, UV); + return UV; +} + +void LDVImpl::mapVirtReg(unsigned VirtReg, UserValue *EC) { + assert(TargetRegisterInfo::isVirtualRegister(VirtReg) && "Only map VirtRegs"); + UserValue *&Leader = virtRegToEqClass[VirtReg]; + Leader = UserValue::merge(Leader, EC); +} + +UserValue *LDVImpl::lookupVirtReg(unsigned VirtReg) { + if (UserValue *UV = virtRegToEqClass.lookup(VirtReg)) + return UV->getLeader(); + return 0; +} + +bool LDVImpl::handleDebugValue(MachineInstr *MI, SlotIndex Idx) { + // DBG_VALUE loc, offset, variable + if (MI->getNumOperands() != 3 || + !MI->getOperand(1).isImm() || !MI->getOperand(2).isMetadata()) { + DEBUG(dbgs() << "Can't handle " << *MI); + return false; + } + + // Get or create the UserValue for (variable,offset). + unsigned Offset = MI->getOperand(1).getImm(); + const MDNode *Var = MI->getOperand(2).getMetadata(); + UserValue *UV = getUserValue(Var, Offset, MI->getDebugLoc()); + + // If the location is a virtual register, make sure it is mapped. + if (MI->getOperand(0).isReg()) { + unsigned Reg = MI->getOperand(0).getReg(); + if (TargetRegisterInfo::isVirtualRegister(Reg)) + mapVirtReg(Reg, UV); + } + + UV->addDef(Idx, MI->getOperand(0)); + return true; +} + +bool LDVImpl::collectDebugValues(MachineFunction &mf) { + bool Changed = false; + for (MachineFunction::iterator MFI = mf.begin(), MFE = mf.end(); MFI != MFE; + ++MFI) { + MachineBasicBlock *MBB = MFI; + for (MachineBasicBlock::iterator MBBI = MBB->begin(), MBBE = MBB->end(); + MBBI != MBBE;) { + if (!MBBI->isDebugValue()) { + ++MBBI; + continue; + } + // DBG_VALUE has no slot index, use the previous instruction instead. + SlotIndex Idx = MBBI == MBB->begin() ? + LIS->getMBBStartIdx(MBB) : + LIS->getInstructionIndex(llvm::prior(MBBI)).getDefIndex(); + // Handle consecutive DBG_VALUE instructions with the same slot index. + do { + if (handleDebugValue(MBBI, Idx)) { + MBBI = MBB->erase(MBBI); + Changed = true; + } else + ++MBBI; + } while (MBBI != MBBE && MBBI->isDebugValue()); + } + } + return Changed; +} + +void UserValue::extendDef(SlotIndex Idx, unsigned LocNo, + LiveInterval *LI, const VNInfo *VNI, + LiveIntervals &LIS, MachineDominatorTree &MDT) { + SmallVector Todo; + Todo.push_back(Idx); + + do { + SlotIndex Start = Todo.pop_back_val(); + MachineBasicBlock *MBB = LIS.getMBBFromIndex(Start); + SlotIndex Stop = LIS.getMBBEndIdx(MBB); + LocMap::iterator I = locInts.find(Start); + + // Limit to VNI's live range. + bool ToEnd = true; + if (LI && VNI) { + LiveRange *Range = LI->getLiveRangeContaining(Start); + if (!Range || Range->valno != VNI) + continue; + if (Range->end < Stop) + Stop = Range->end, ToEnd = false; + } + + // There could already be a short def at Start. + if (I.valid() && I.start() <= Start) { + // Stop when meeting a different location or an already extended interval. + Start = Start.getNextSlot(); + if (I.value() != LocNo || I.stop() != Start) + continue; + // This is a one-slot placeholder. Just skip it. + ++I; + } + + // Limited by the next def. + if (I.valid() && I.start() < Stop) + Stop = I.start(), ToEnd = false; + + if (Start >= Stop) + continue; + + I.insert(Start, Stop, LocNo); + + // If we extended to the MBB end, propagate down the dominator tree. + if (!ToEnd) + continue; + const std::vector &Children = + MDT.getNode(MBB)->getChildren(); + for (unsigned i = 0, e = Children.size(); i != e; ++i) + Todo.push_back(LIS.getMBBStartIdx(Children[i]->getBlock())); + } while (!Todo.empty()); +} + +void +UserValue::computeIntervals(LiveIntervals &LIS, MachineDominatorTree &MDT) { + SmallVector, 16> Defs; + + // Collect all defs to be extended (Skipping undefs). + for (LocMap::const_iterator I = locInts.begin(); I.valid(); ++I) + if (I.value() != ~0u) + Defs.push_back(std::make_pair(I.start(), I.value())); + + for (unsigned i = 0, e = Defs.size(); i != e; ++i) { + SlotIndex Idx = Defs[i].first; + unsigned LocNo = Defs[i].second; + const MachineOperand &Loc = locations[LocNo]; + + // Register locations are constrained to where the register value is live. + if (Loc.isReg() && LIS.hasInterval(Loc.getReg())) { + LiveInterval *LI = &LIS.getInterval(Loc.getReg()); + const VNInfo *VNI = LI->getVNInfoAt(Idx); + extendDef(Idx, LocNo, LI, VNI, LIS, MDT); + } else + extendDef(Idx, LocNo, 0, 0, LIS, MDT); + } + + // Finally, erase all the undefs. + for (LocMap::iterator I = locInts.begin(); I.valid();) + if (I.value() == ~0u) + I.erase(); + else + ++I; +} + +void LDVImpl::computeIntervals() { + for (unsigned i = 0, e = userValues.size(); i != e; ++i) + userValues[i]->computeIntervals(*LIS, *MDT); +} + +bool LDVImpl::runOnMachineFunction(MachineFunction &mf) { + MF = &mf; + LIS = &pass.getAnalysis(); + MDT = &pass.getAnalysis(); + TRI = mf.getTarget().getRegisterInfo(); + clear(); + DEBUG(dbgs() << "********** COMPUTING LIVE DEBUG VARIABLES: " + << ((Value*)mf.getFunction())->getName() + << " **********\n"); + + bool Changed = collectDebugValues(mf); + computeIntervals(); + DEBUG(print(dbgs())); + return Changed; +} + +bool LiveDebugVariables::runOnMachineFunction(MachineFunction &mf) { + if (!EnableLDV) + return false; + if (!pImpl) + pImpl = new LDVImpl(this); + return static_cast(pImpl)->runOnMachineFunction(mf); +} + +void LiveDebugVariables::releaseMemory() { + if (pImpl) + static_cast(pImpl)->clear(); +} + +LiveDebugVariables::~LiveDebugVariables() { + if (pImpl) + delete static_cast(pImpl); +} + +void UserValue:: +renameRegister(unsigned OldReg, unsigned NewReg, unsigned SubIdx, + const TargetRegisterInfo *TRI) { + for (unsigned i = locations.size(); i; --i) { + unsigned LocNo = i - 1; + MachineOperand &Loc = locations[LocNo]; + if (!Loc.isReg() || Loc.getReg() != OldReg) + continue; + if (TargetRegisterInfo::isPhysicalRegister(NewReg)) + Loc.substPhysReg(NewReg, *TRI); + else + Loc.substVirtReg(NewReg, SubIdx, *TRI); + coalesceLocation(LocNo); + } +} + +void LDVImpl:: +renameRegister(unsigned OldReg, unsigned NewReg, unsigned SubIdx) { + UserValue *UV = lookupVirtReg(OldReg); + if (!UV) + return; + + if (TargetRegisterInfo::isVirtualRegister(NewReg)) + mapVirtReg(NewReg, UV); + virtRegToEqClass.erase(OldReg); + + do { + UV->renameRegister(OldReg, NewReg, SubIdx, TRI); + UV = UV->getNext(); + } while (UV); +} + +void LiveDebugVariables:: +renameRegister(unsigned OldReg, unsigned NewReg, unsigned SubIdx) { + if (pImpl) + static_cast(pImpl)->renameRegister(OldReg, NewReg, SubIdx); +} + +void +UserValue::rewriteLocations(VirtRegMap &VRM, const TargetRegisterInfo &TRI) { + // Iterate over locations in reverse makes it easier to handle coalescing. + for (unsigned i = locations.size(); i ; --i) { + unsigned LocNo = i-1; + MachineOperand &Loc = locations[LocNo]; + // Only virtual registers are rewritten. + if (!Loc.isReg() || !Loc.getReg() || + !TargetRegisterInfo::isVirtualRegister(Loc.getReg())) + continue; + unsigned VirtReg = Loc.getReg(); + if (VRM.isAssignedReg(VirtReg) && + TargetRegisterInfo::isPhysicalRegister(VRM.getPhys(VirtReg))) { + Loc.substPhysReg(VRM.getPhys(VirtReg), TRI); + } else if (VRM.getStackSlot(VirtReg) != VirtRegMap::NO_STACK_SLOT && + VRM.isSpillSlotUsed(VRM.getStackSlot(VirtReg))) { + // FIXME: Translate SubIdx to a stackslot offset. + Loc = MachineOperand::CreateFI(VRM.getStackSlot(VirtReg)); + } else { + Loc.setReg(0); + Loc.setSubReg(0); + } + coalesceLocation(LocNo); + } + DEBUG(print(dbgs(), &TRI)); +} + +/// findInsertLocation - Find an iterator for inserting a DBG_VALUE +/// instruction. +static MachineBasicBlock::iterator +findInsertLocation(MachineBasicBlock *MBB, SlotIndex Idx, + LiveIntervals &LIS) { + SlotIndex Start = LIS.getMBBStartIdx(MBB); + Idx = Idx.getBaseIndex(); + + // Try to find an insert location by going backwards from Idx. + MachineInstr *MI; + while (!(MI = LIS.getInstructionFromIndex(Idx))) { + // We've reached the beginning of MBB. + if (Idx == Start) { + MachineBasicBlock::iterator I = MBB->SkipPHIsAndLabels(MBB->begin()); + return I; + } + Idx = Idx.getPrevIndex(); + } + + // Don't insert anything after the first terminator, though. + return MI->getDesc().isTerminator() ? MBB->getFirstTerminator() : + llvm::next(MachineBasicBlock::iterator(MI)); +} + +DebugLoc UserValue::findDebugLoc() { + DebugLoc D = dl; + dl = DebugLoc(); + return D; +} +void UserValue::insertDebugValue(MachineBasicBlock *MBB, SlotIndex Idx, + unsigned LocNo, + LiveIntervals &LIS, + const TargetInstrInfo &TII) { + MachineBasicBlock::iterator I = findInsertLocation(MBB, Idx, LIS); + MachineOperand &Loc = locations[LocNo]; + + // Frame index locations may require a target callback. + if (Loc.isFI()) { + MachineInstr *MI = TII.emitFrameIndexDebugValue(*MBB->getParent(), + Loc.getIndex(), offset, variable, + findDebugLoc()); + if (MI) { + MBB->insert(I, MI); + return; + } + } + // This is not a frame index, or the target is happy with a standard FI. + BuildMI(*MBB, I, findDebugLoc(), TII.get(TargetOpcode::DBG_VALUE)) + .addOperand(Loc).addImm(offset).addMetadata(variable); +} + +void UserValue::insertDebugKill(MachineBasicBlock *MBB, SlotIndex Idx, + LiveIntervals &LIS, const TargetInstrInfo &TII) { + MachineBasicBlock::iterator I = findInsertLocation(MBB, Idx, LIS); + BuildMI(*MBB, I, findDebugLoc(), TII.get(TargetOpcode::DBG_VALUE)).addReg(0) + .addImm(offset).addMetadata(variable); +} + +void UserValue::emitDebugValues(VirtRegMap *VRM, LiveIntervals &LIS, + const TargetInstrInfo &TII) { + MachineFunction::iterator MFEnd = VRM->getMachineFunction().end(); + + for (LocMap::const_iterator I = locInts.begin(); I.valid();) { + SlotIndex Start = I.start(); + SlotIndex Stop = I.stop(); + unsigned LocNo = I.value(); + DEBUG(dbgs() << "\t[" << Start << ';' << Stop << "):" << LocNo); + MachineFunction::iterator MBB = LIS.getMBBFromIndex(Start); + SlotIndex MBBEnd = LIS.getMBBEndIdx(MBB); + + DEBUG(dbgs() << " BB#" << MBB->getNumber() << '-' << MBBEnd); + insertDebugValue(MBB, Start, LocNo, LIS, TII); + + // This interval may span multiple basic blocks. + // Insert a DBG_VALUE into each one. + while(Stop > MBBEnd) { + // Move to the next block. + Start = MBBEnd; + if (++MBB == MFEnd) + break; + MBBEnd = LIS.getMBBEndIdx(MBB); + DEBUG(dbgs() << " BB#" << MBB->getNumber() << '-' << MBBEnd); + insertDebugValue(MBB, Start, LocNo, LIS, TII); + } + DEBUG(dbgs() << '\n'); + if (MBB == MFEnd) + break; + + ++I; + if (Stop == MBBEnd) + continue; + // The current interval ends before MBB. + // Insert a kill if there is a gap. + if (!I.valid() || I.start() > Stop) + insertDebugKill(MBB, Stop, LIS, TII); + } +} + +void LDVImpl::emitDebugValues(VirtRegMap *VRM) { + DEBUG(dbgs() << "********** EMITTING LIVE DEBUG VARIABLES **********\n"); + const TargetInstrInfo *TII = MF->getTarget().getInstrInfo(); + for (unsigned i = 0, e = userValues.size(); i != e; ++i) { + userValues[i]->rewriteLocations(*VRM, *TRI); + userValues[i]->emitDebugValues(VRM, *LIS, *TII); + } +} + +void LiveDebugVariables::emitDebugValues(VirtRegMap *VRM) { + if (pImpl) + static_cast(pImpl)->emitDebugValues(VRM); +} + + +#ifndef NDEBUG +void LiveDebugVariables::dump() { + if (pImpl) + static_cast(pImpl)->print(dbgs()); +} +#endif + diff --git a/lib/CodeGen/LiveDebugVariables.h b/lib/CodeGen/LiveDebugVariables.h new file mode 100644 index 000000000000..a6e40a198456 --- /dev/null +++ b/lib/CodeGen/LiveDebugVariables.h @@ -0,0 +1,63 @@ +//===- LiveDebugVariables.h - Tracking debug info variables ----*- c++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the interface to the LiveDebugVariables analysis. +// +// The analysis removes DBG_VALUE instructions for virtual registers and tracks +// live user variables in a data structure that can be updated during register +// allocation. +// +// After register allocation new DBG_VALUE instructions are emitted to reflect +// the new locations of user variables. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_LIVEDEBUGVARIABLES_H +#define LLVM_CODEGEN_LIVEDEBUGVARIABLES_H + +#include "llvm/CodeGen/MachineFunctionPass.h" + +namespace llvm { + +class VirtRegMap; + +class LiveDebugVariables : public MachineFunctionPass { + void *pImpl; +public: + static char ID; // Pass identification, replacement for typeid + + LiveDebugVariables(); + ~LiveDebugVariables(); + + /// renameRegister - Move any user variables in OldReg to NewReg:SubIdx. + /// @param OldReg Old virtual register that is going away. + /// @param NewReg New register holding the user variables. + /// @param SubIdx If NewReg is a virtual register, SubIdx may indicate a sub- + /// register. + void renameRegister(unsigned OldReg, unsigned NewReg, unsigned SubIdx); + + /// emitDebugValues - Emit new DBG_VALUE instructions reflecting the changes + /// that happened during register allocation. + /// @param VRM Rename virtual registers according to map. + void emitDebugValues(VirtRegMap *VRM); + + /// dump - Print data structures to dbgs(). + void dump(); + +private: + + virtual bool runOnMachineFunction(MachineFunction &); + virtual void releaseMemory(); + virtual void getAnalysisUsage(AnalysisUsage &) const; + +}; + +} // namespace llvm + +#endif // LLVM_CODEGEN_LIVEDEBUGVARIABLES_H diff --git a/lib/CodeGen/LiveInterval.cpp b/lib/CodeGen/LiveInterval.cpp index 59f380ad2641..c2dbd6ab75a1 100644 --- a/lib/CodeGen/LiveInterval.cpp +++ b/lib/CodeGen/LiveInterval.cpp @@ -30,58 +30,19 @@ #include using namespace llvm; -// An example for liveAt(): -// -// this = [1,4), liveAt(0) will return false. The instruction defining this -// spans slots [0,3]. The interval belongs to an spilled definition of the -// variable it represents. This is because slot 1 is used (def slot) and spans -// up to slot 3 (store slot). -// -bool LiveInterval::liveAt(SlotIndex I) const { - Ranges::const_iterator r = std::upper_bound(ranges.begin(), ranges.end(), I); - - if (r == ranges.begin()) - return false; - - --r; - return r->contains(I); -} - -// liveBeforeAndAt - Check if the interval is live at the index and the index -// just before it. If index is liveAt, check if it starts a new live range. -// If it does, then check if the previous live range ends at index-1. -bool LiveInterval::liveBeforeAndAt(SlotIndex I) const { - Ranges::const_iterator r = std::upper_bound(ranges.begin(), ranges.end(), I); - - if (r == ranges.begin()) - return false; - - --r; - if (!r->contains(I)) - return false; - if (I != r->start) - return true; - // I is the start of a live range. Check if the previous live range ends - // at I-1. - if (r == ranges.begin()) - return false; - return r->end == I; +// CompEnd - Compare LiveRange ends. +namespace { +struct CompEnd { + bool operator()(const LiveRange &A, const LiveRange &B) const { + return A.end < B.end; + } +}; } -/// killedAt - Return true if a live range ends at index. Note that the kill -/// point is not contained in the half-open live range. It is usually the -/// getDefIndex() slot following its last use. -bool LiveInterval::killedAt(SlotIndex I) const { - Ranges::const_iterator r = std::lower_bound(ranges.begin(), ranges.end(), I); - - // Now r points to the first interval with start >= I, or ranges.end(). - if (r == ranges.begin()) - return false; - - --r; - // Now r points to the last interval with end <= I. - // r->end is the kill point. - return r->end == I; +LiveInterval::iterator LiveInterval::find(SlotIndex Pos) { + assert(Pos.isValid() && "Cannot search for an invalid index"); + return std::upper_bound(begin(), end(), LiveRange(SlotIndex(), Pos, 0), + CompEnd()); } /// killedInRange - Return true if the interval has kills in [Start,End). @@ -330,25 +291,14 @@ LiveInterval::addRangeFrom(LiveRange LR, iterator From) { return ranges.insert(it, LR); } -/// isInOneLiveRange - Return true if the range specified is entirely in -/// a single LiveRange of the live interval. -bool LiveInterval::isInOneLiveRange(SlotIndex Start, SlotIndex End) { - Ranges::iterator I = std::upper_bound(ranges.begin(), ranges.end(), Start); - if (I == ranges.begin()) - return false; - --I; - return I->containsRange(Start, End); -} - /// removeRange - Remove the specified range from this interval. Note that /// the range must be in a single LiveRange in its entirety. void LiveInterval::removeRange(SlotIndex Start, SlotIndex End, bool RemoveDeadValNo) { // Find the LiveRange containing this span. - Ranges::iterator I = std::upper_bound(ranges.begin(), ranges.end(), Start); - assert(I != ranges.begin() && "Range is not in interval!"); - --I; + Ranges::iterator I = find(Start); + assert(I != ranges.end() && "Range is not in interval!"); assert(I->containsRange(Start, End) && "Range is not entirely in interval!"); // If the span we are removing is at the start of the LiveRange, adjust it. @@ -405,32 +355,6 @@ void LiveInterval::removeValNo(VNInfo *ValNo) { markValNoForDeletion(ValNo); } -/// getLiveRangeContaining - Return the live range that contains the -/// specified index, or null if there is none. -LiveInterval::const_iterator -LiveInterval::FindLiveRangeContaining(SlotIndex Idx) const { - const_iterator It = std::upper_bound(begin(), end(), Idx); - if (It != ranges.begin()) { - --It; - if (It->contains(Idx)) - return It; - } - - return end(); -} - -LiveInterval::iterator -LiveInterval::FindLiveRangeContaining(SlotIndex Idx) { - iterator It = std::upper_bound(begin(), end(), Idx); - if (It != begin()) { - --It; - if (It->contains(Idx)) - return It; - } - - return end(); -} - /// findDefinedVNInfo - Find the VNInfo defined by the specified /// index (register interval). VNInfo *LiveInterval::findDefinedVNInfoForRegInt(SlotIndex Idx) const { @@ -443,17 +367,6 @@ VNInfo *LiveInterval::findDefinedVNInfoForRegInt(SlotIndex Idx) const { return 0; } -/// findDefinedVNInfo - Find the VNInfo defined by the specified -/// register (stack inteval). -VNInfo *LiveInterval::findDefinedVNInfoForStackInt(unsigned reg) const { - for (LiveInterval::const_vni_iterator i = vni_begin(), e = vni_end(); - i != e; ++i) { - if ((*i)->getReg() == reg) - return *i; - } - return 0; -} - /// join - Join two live intervals (this, and other) together. This applies /// mappings to the value numbers in the LHS/RHS intervals as specified. If /// the intervals are not joinable, this aborts. @@ -616,103 +529,6 @@ void LiveInterval::MergeValueInAsValue( } -/// MergeInClobberRanges - For any live ranges that are not defined in the -/// current interval, but are defined in the Clobbers interval, mark them -/// used with an unknown definition value. -void LiveInterval::MergeInClobberRanges(LiveIntervals &li_, - const LiveInterval &Clobbers, - VNInfo::Allocator &VNInfoAllocator) { - if (Clobbers.empty()) return; - - DenseMap ValNoMaps; - VNInfo *UnusedValNo = 0; - iterator IP = begin(); - for (const_iterator I = Clobbers.begin(), E = Clobbers.end(); I != E; ++I) { - // For every val# in the Clobbers interval, create a new "unknown" val#. - VNInfo *ClobberValNo = 0; - DenseMap::iterator VI = ValNoMaps.find(I->valno); - if (VI != ValNoMaps.end()) - ClobberValNo = VI->second; - else if (UnusedValNo) - ClobberValNo = UnusedValNo; - else { - UnusedValNo = ClobberValNo = - getNextValue(li_.getInvalidIndex(), 0, false, VNInfoAllocator); - ValNoMaps.insert(std::make_pair(I->valno, ClobberValNo)); - } - - bool Done = false; - SlotIndex Start = I->start, End = I->end; - // If a clobber range starts before an existing range and ends after - // it, the clobber range will need to be split into multiple ranges. - // Loop until the entire clobber range is handled. - while (!Done) { - Done = true; - IP = std::upper_bound(IP, end(), Start); - SlotIndex SubRangeStart = Start; - SlotIndex SubRangeEnd = End; - - // If the start of this range overlaps with an existing liverange, trim it. - if (IP != begin() && IP[-1].end > SubRangeStart) { - SubRangeStart = IP[-1].end; - // Trimmed away the whole range? - if (SubRangeStart >= SubRangeEnd) continue; - } - // If the end of this range overlaps with an existing liverange, trim it. - if (IP != end() && SubRangeEnd > IP->start) { - // If the clobber live range extends beyond the existing live range, - // it'll need at least another live range, so set the flag to keep - // iterating. - if (SubRangeEnd > IP->end) { - Start = IP->end; - Done = false; - } - SubRangeEnd = IP->start; - // If this trimmed away the whole range, ignore it. - if (SubRangeStart == SubRangeEnd) continue; - } - - // Insert the clobber interval. - IP = addRangeFrom(LiveRange(SubRangeStart, SubRangeEnd, ClobberValNo), - IP); - UnusedValNo = 0; - } - } - - if (UnusedValNo) { - // Delete the last unused val#. - valnos.pop_back(); - } -} - -void LiveInterval::MergeInClobberRange(LiveIntervals &li_, - SlotIndex Start, - SlotIndex End, - VNInfo::Allocator &VNInfoAllocator) { - // Find a value # to use for the clobber ranges. If there is already a value# - // for unknown values, use it. - VNInfo *ClobberValNo = - getNextValue(li_.getInvalidIndex(), 0, false, VNInfoAllocator); - - iterator IP = begin(); - IP = std::upper_bound(IP, end(), Start); - - // If the start of this range overlaps with an existing liverange, trim it. - if (IP != begin() && IP[-1].end > Start) { - Start = IP[-1].end; - // Trimmed away the whole range? - if (Start >= End) return; - } - // If the end of this range overlaps with an existing liverange, trim it. - if (IP != end() && End > IP->start) { - End = IP->start; - // If this trimmed away the whole range, ignore it. - if (Start == End) return; - } - - // Insert the clobber interval. - addRangeFrom(LiveRange(Start, End, ClobberValNo), IP); -} /// MergeValueNumberInto - This method is called when two value nubmers /// are found to be equivalent. This eliminates V1, replacing all @@ -767,6 +583,9 @@ VNInfo* LiveInterval::MergeValueNumberInto(VNInfo *V1, VNInfo *V2) { } } + // Merge the relevant flags. + V2->mergeFlags(V1); + // Now that V1 is dead, remove it. markValNoForDeletion(V1); @@ -831,14 +650,9 @@ void LiveRange::dump() const { } void LiveInterval::print(raw_ostream &OS, const TargetRegisterInfo *TRI) const { - if (isStackSlot()) - OS << "SS#" << getStackSlotIndex(); - else if (TRI && TargetRegisterInfo::isPhysicalRegister(reg)) - OS << TRI->getName(reg); - else - OS << "%reg" << reg; - - OS << ',' << weight; + OS << PrintReg(reg, TRI); + if (weight != 0) + OS << ',' << weight; if (empty()) OS << " EMPTY"; @@ -863,10 +677,9 @@ void LiveInterval::print(raw_ostream &OS, const TargetRegisterInfo *TRI) const { if (vni->isUnused()) { OS << "x"; } else { - if (!vni->isDefAccurate() && !vni->isPHIDef()) - OS << "?"; - else - OS << vni->def; + OS << vni->def; + if (vni->isPHIDef()) + OS << "-phidef"; if (vni->hasPHIKill()) OS << "-phikill"; if (vni->hasRedefByEC()) @@ -884,3 +697,84 @@ void LiveInterval::dump() const { void LiveRange::print(raw_ostream &os) const { os << *this; } + +unsigned ConnectedVNInfoEqClasses::Classify(const LiveInterval *LI) { + // Create initial equivalence classes. + eqClass_.clear(); + eqClass_.grow(LI->getNumValNums()); + + const VNInfo *used = 0, *unused = 0; + + // Determine connections. + for (LiveInterval::const_vni_iterator I = LI->vni_begin(), E = LI->vni_end(); + I != E; ++I) { + const VNInfo *VNI = *I; + // Group all unused values into one class. + if (VNI->isUnused()) { + if (unused) + eqClass_.join(unused->id, VNI->id); + unused = VNI; + continue; + } + used = VNI; + if (VNI->isPHIDef()) { + const MachineBasicBlock *MBB = lis_.getMBBFromIndex(VNI->def); + assert(MBB && "Phi-def has no defining MBB"); + // Connect to values live out of predecessors. + for (MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(), + PE = MBB->pred_end(); PI != PE; ++PI) + if (const VNInfo *PVNI = + LI->getVNInfoAt(lis_.getMBBEndIdx(*PI).getPrevSlot())) + eqClass_.join(VNI->id, PVNI->id); + } else { + // Normal value defined by an instruction. Check for two-addr redef. + // FIXME: This could be coincidental. Should we really check for a tied + // operand constraint? + // Note that VNI->def may be a use slot for an early clobber def. + if (const VNInfo *UVNI = LI->getVNInfoAt(VNI->def.getPrevSlot())) + eqClass_.join(VNI->id, UVNI->id); + } + } + + // Lump all the unused values in with the last used value. + if (used && unused) + eqClass_.join(used->id, unused->id); + + eqClass_.compress(); + return eqClass_.getNumClasses(); +} + +void ConnectedVNInfoEqClasses::Distribute(LiveInterval *LIV[]) { + assert(LIV[0] && "LIV[0] must be set"); + LiveInterval &LI = *LIV[0]; + + // First move runs to new intervals. + LiveInterval::iterator J = LI.begin(), E = LI.end(); + while (J != E && eqClass_[J->valno->id] == 0) + ++J; + for (LiveInterval::iterator I = J; I != E; ++I) { + if (unsigned eq = eqClass_[I->valno->id]) { + assert((LIV[eq]->empty() || LIV[eq]->expiredAt(I->start)) && + "New intervals should be empty"); + LIV[eq]->ranges.push_back(*I); + } else + *J++ = *I; + } + LI.ranges.erase(J, E); + + // Transfer VNInfos to their new owners and renumber them. + unsigned j = 0, e = LI.getNumValNums(); + while (j != e && eqClass_[j] == 0) + ++j; + for (unsigned i = j; i != e; ++i) { + VNInfo *VNI = LI.getValNumInfo(i); + if (unsigned eq = eqClass_[i]) { + VNI->id = LIV[eq]->getNumValNums(); + LIV[eq]->valnos.push_back(VNI); + } else { + VNI->id = j; + LI.valnos[j++] = VNI; + } + } + LI.valnos.resize(j); +} diff --git a/lib/CodeGen/LiveIntervalAnalysis.cpp b/lib/CodeGen/LiveIntervalAnalysis.cpp index 2726fc337539..aef5b5f77e78 100644 --- a/lib/CodeGen/LiveIntervalAnalysis.cpp +++ b/lib/CodeGen/LiveIntervalAnalysis.cpp @@ -20,6 +20,7 @@ #include "VirtRegMap.h" #include "llvm/Value.h" #include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/CodeGen/CalcSpillWeights.h" #include "llvm/CodeGen/LiveVariables.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineInstr.h" @@ -55,8 +56,17 @@ STATISTIC(numFolds , "Number of loads/stores folded into instructions"); STATISTIC(numSplits , "Number of intervals split"); char LiveIntervals::ID = 0; -INITIALIZE_PASS(LiveIntervals, "liveintervals", - "Live Interval Analysis", false, false); +INITIALIZE_PASS_BEGIN(LiveIntervals, "liveintervals", + "Live Interval Analysis", false, false) +INITIALIZE_PASS_DEPENDENCY(LiveVariables) +INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo) +INITIALIZE_PASS_DEPENDENCY(PHIElimination) +INITIALIZE_PASS_DEPENDENCY(TwoAddressInstructionPass) +INITIALIZE_PASS_DEPENDENCY(ProcessImplicitDefs) +INITIALIZE_PASS_DEPENDENCY(SlotIndexes) +INITIALIZE_AG_DEPENDENCY(AliasAnalysis) +INITIALIZE_PASS_END(LiveIntervals, "liveintervals", + "Live Interval Analysis", false, false) void LiveIntervals::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); @@ -132,19 +142,7 @@ void LiveIntervals::print(raw_ostream &OS, const Module* ) const { void LiveIntervals::printInstrs(raw_ostream &OS) const { OS << "********** MACHINEINSTRS **********\n"; - - for (MachineFunction::iterator mbbi = mf_->begin(), mbbe = mf_->end(); - mbbi != mbbe; ++mbbi) { - OS << "BB#" << mbbi->getNumber() - << ":\t\t# derived from " << mbbi->getName() << "\n"; - for (MachineBasicBlock::iterator mii = mbbi->begin(), - mie = mbbi->end(); mii != mie; ++mii) { - if (mii->isDebugValue()) - OS << " \t" << *mii; - else - OS << getInstructionIndex(mii) << '\t' << *mii; - } - } + mf_->print(OS, indexes_); } void LiveIntervals::dumpInstrs() const { @@ -248,15 +246,6 @@ bool LiveIntervals::conflictsWithAliasRef(LiveInterval &li, unsigned Reg, return false; } -#ifndef NDEBUG -static void printRegName(unsigned reg, const TargetRegisterInfo* tri_) { - if (TargetRegisterInfo::isPhysicalRegister(reg)) - dbgs() << tri_->getName(reg); - else - dbgs() << "%reg" << reg; -} -#endif - static bool MultipleDefsBySameMI(const MachineInstr &MI, unsigned MOIdx) { unsigned Reg = MI.getOperand(MOIdx).getReg(); @@ -285,8 +274,8 @@ bool LiveIntervals::isPartialRedef(SlotIndex MIIdx, MachineOperand &MO, SlotIndex RedefIndex = MIIdx.getDefIndex(); const LiveRange *OldLR = interval.getLiveRangeContaining(RedefIndex.getUseIndex()); - if (OldLR->valno->isDefAccurate()) { - MachineInstr *DefMI = getInstructionFromIndex(OldLR->valno->def); + MachineInstr *DefMI = getInstructionFromIndex(OldLR->valno->def); + if (DefMI != 0) { return DefMI->findRegisterDefOperandIdx(interval.reg) != -1; } return false; @@ -298,10 +287,7 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock *mbb, MachineOperand& MO, unsigned MOIdx, LiveInterval &interval) { - DEBUG({ - dbgs() << "\t\tregister: "; - printRegName(interval.reg, tri_); - }); + DEBUG(dbgs() << "\t\tregister: " << PrintReg(interval.reg, tri_)); // Virtual registers may be defined multiple times (due to phi // elimination and 2-addr elimination). Much of what we do only has to be @@ -326,8 +312,7 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock *mbb, CopyMI = mi; } - VNInfo *ValNo = interval.getNextValue(defIndex, CopyMI, true, - VNInfoAllocator); + VNInfo *ValNo = interval.getNextValue(defIndex, CopyMI, VNInfoAllocator); assert(ValNo->id == 0 && "First value in interval is not 0?"); // Loop over all of the blocks that the vreg is defined in. There are @@ -393,8 +378,9 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock *mbb, // Create interval with one of a NEW value number. Note that this value // number isn't actually defined by an instruction, weird huh? :) if (PHIJoin) { - ValNo = interval.getNextValue(SlotIndex(Start, true), 0, false, - VNInfoAllocator); + assert(getInstructionFromIndex(Start) == 0 && + "PHI def index points at actual instruction."); + ValNo = interval.getNextValue(Start, 0, VNInfoAllocator); ValNo->setIsPHIDef(true); } LiveRange LR(Start, killIdx, ValNo); @@ -440,10 +426,7 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock *mbb, // The new value number (#1) is defined by the instruction we claimed // defined value #0. - VNInfo *ValNo = interval.getNextValue(OldValNo->def, OldValNo->getCopy(), - false, // update at * - VNInfoAllocator); - ValNo->setFlags(OldValNo->getFlags()); // * <- updating here + VNInfo *ValNo = interval.createValueCopy(OldValNo, VNInfoAllocator); // Value#0 is now defined by the 2-addr instruction. OldValNo->def = RedefIndex; @@ -481,7 +464,7 @@ void LiveIntervals::handleVirtualRegisterDef(MachineBasicBlock *mbb, MachineInstr *CopyMI = NULL; if (mi->isCopyLike()) CopyMI = mi; - ValNo = interval.getNextValue(defIndex, CopyMI, true, VNInfoAllocator); + ValNo = interval.getNextValue(defIndex, CopyMI, VNInfoAllocator); SlotIndex killIndex = getMBBEndIdx(mbb); LiveRange LR(defIndex, killIndex, ValNo); @@ -504,10 +487,7 @@ void LiveIntervals::handlePhysicalRegisterDef(MachineBasicBlock *MBB, MachineInstr *CopyMI) { // A physical register cannot be live across basic block, so its // lifetime must end somewhere in its defining basic block. - DEBUG({ - dbgs() << "\t\tregister: "; - printRegName(interval.reg, tri_); - }); + DEBUG(dbgs() << "\t\tregister: " << PrintReg(interval.reg, tri_)); SlotIndex baseIndex = MIIdx; SlotIndex start = baseIndex.getDefIndex(); @@ -573,11 +553,11 @@ exit: assert(start < end && "did not find end of interval?"); // Already exists? Extend old live interval. - LiveInterval::iterator OldLR = interval.FindLiveRangeContaining(start); - bool Extend = OldLR != interval.end(); - VNInfo *ValNo = Extend - ? OldLR->valno : interval.getNextValue(start, CopyMI, true, VNInfoAllocator); - if (MO.isEarlyClobber() && Extend) + VNInfo *ValNo = interval.getVNInfoAt(start); + bool Extend = ValNo != 0; + if (!Extend) + ValNo = interval.getNextValue(start, CopyMI, VNInfoAllocator); + if (Extend && MO.isEarlyClobber()) ValNo->setHasRedefByEC(true); LiveRange LR(start, end, ValNo); interval.addRange(LR); @@ -611,10 +591,7 @@ void LiveIntervals::handleRegisterDef(MachineBasicBlock *MBB, void LiveIntervals::handleLiveInRegister(MachineBasicBlock *MBB, SlotIndex MIIdx, LiveInterval &interval, bool isAlias) { - DEBUG({ - dbgs() << "\t\tlivein register: "; - printRegName(interval.reg, tri_); - }); + DEBUG(dbgs() << "\t\tlivein register: " << PrintReg(interval.reg, tri_)); // Look for kills, if it reaches a def before it's killed, then it shouldn't // be considered a livein. @@ -672,9 +649,11 @@ void LiveIntervals::handleLiveInRegister(MachineBasicBlock *MBB, } } + SlotIndex defIdx = getMBBStartIdx(MBB); + assert(getInstructionFromIndex(defIdx) == 0 && + "PHI def index points at actual instruction."); VNInfo *vni = - interval.getNextValue(SlotIndex(getMBBStartIdx(MBB), true), - 0, false, VNInfoAllocator); + interval.getNextValue(defIdx, 0, VNInfoAllocator); vni->setIsPHIDef(true); LiveRange LR(start, end, vni); @@ -764,10 +743,177 @@ LiveInterval* LiveIntervals::dupInterval(LiveInterval *li) { return NewLI; } +/// shrinkToUses - After removing some uses of a register, shrink its live +/// range to just the remaining uses. This method does not compute reaching +/// defs for new uses, and it doesn't remove dead defs. +void LiveIntervals::shrinkToUses(LiveInterval *li) { + DEBUG(dbgs() << "Shrink: " << *li << '\n'); + assert(TargetRegisterInfo::isVirtualRegister(li->reg) + && "Can't only shrink physical registers"); + // Find all the values used, including PHI kills. + SmallVector, 16> WorkList; + + // Visit all instructions reading li->reg. + for (MachineRegisterInfo::reg_iterator I = mri_->reg_begin(li->reg); + MachineInstr *UseMI = I.skipInstruction();) { + if (UseMI->isDebugValue() || !UseMI->readsVirtualRegister(li->reg)) + continue; + SlotIndex Idx = getInstructionIndex(UseMI).getUseIndex(); + VNInfo *VNI = li->getVNInfoAt(Idx); + assert(VNI && "Live interval not live into reading instruction"); + if (VNI->def == Idx) { + // Special case: An early-clobber tied operand reads and writes the + // register one slot early. + Idx = Idx.getPrevSlot(); + VNI = li->getVNInfoAt(Idx); + assert(VNI && "Early-clobber tied value not available"); + } + WorkList.push_back(std::make_pair(Idx, VNI)); + } + + // Create a new live interval with only minimal live segments per def. + LiveInterval NewLI(li->reg, 0); + for (LiveInterval::vni_iterator I = li->vni_begin(), E = li->vni_end(); + I != E; ++I) { + VNInfo *VNI = *I; + if (VNI->isUnused()) + continue; + NewLI.addRange(LiveRange(VNI->def, VNI->def.getNextSlot(), VNI)); + } + + // Extend intervals to reach all uses in WorkList. + while (!WorkList.empty()) { + SlotIndex Idx = WorkList.back().first; + VNInfo *VNI = WorkList.back().second; + WorkList.pop_back(); + + // Extend the live range for VNI to be live at Idx. + LiveInterval::iterator I = NewLI.find(Idx); + + // Already got it? + if (I != NewLI.end() && I->start <= Idx) { + assert(I->valno == VNI && "Unexpected existing value number"); + continue; + } + + // Is there already a live range in the block containing Idx? + const MachineBasicBlock *MBB = getMBBFromIndex(Idx); + SlotIndex BlockStart = getMBBStartIdx(MBB); + DEBUG(dbgs() << "Shrink: Use val#" << VNI->id << " at " << Idx + << " in BB#" << MBB->getNumber() << '@' << BlockStart); + if (I != NewLI.begin() && (--I)->end > BlockStart) { + assert(I->valno == VNI && "Wrong reaching def"); + DEBUG(dbgs() << " extend [" << I->start << ';' << I->end << ")\n"); + // Is this the first use of a PHIDef in its defining block? + if (VNI->isPHIDef() && I->end == VNI->def.getNextSlot()) { + // The PHI is live, make sure the predecessors are live-out. + for (MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(), + PE = MBB->pred_end(); PI != PE; ++PI) { + SlotIndex Stop = getMBBEndIdx(*PI).getPrevSlot(); + VNInfo *PVNI = li->getVNInfoAt(Stop); + // A predecessor is not required to have a live-out value for a PHI. + if (PVNI) { + assert(PVNI->hasPHIKill() && "Missing hasPHIKill flag"); + WorkList.push_back(std::make_pair(Stop, PVNI)); + } + } + } + + // Extend the live range in the block to include Idx. + NewLI.addRange(LiveRange(I->end, Idx.getNextSlot(), VNI)); + continue; + } + + // VNI is live-in to MBB. + DEBUG(dbgs() << " live-in at " << BlockStart << '\n'); + NewLI.addRange(LiveRange(BlockStart, Idx.getNextSlot(), VNI)); + + // Make sure VNI is live-out from the predecessors. + for (MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(), + PE = MBB->pred_end(); PI != PE; ++PI) { + SlotIndex Stop = getMBBEndIdx(*PI).getPrevSlot(); + assert(li->getVNInfoAt(Stop) == VNI && "Wrong value out of predecessor"); + WorkList.push_back(std::make_pair(Stop, VNI)); + } + } + + // Handle dead values. + for (LiveInterval::vni_iterator I = li->vni_begin(), E = li->vni_end(); + I != E; ++I) { + VNInfo *VNI = *I; + if (VNI->isUnused()) + continue; + LiveInterval::iterator LII = NewLI.FindLiveRangeContaining(VNI->def); + assert(LII != NewLI.end() && "Missing live range for PHI"); + if (LII->end != VNI->def.getNextSlot()) + continue; + if (!VNI->isPHIDef()) { + // This is a dead PHI. Remove it. + VNI->setIsUnused(true); + NewLI.removeRange(*LII); + } else { + // This is a dead def. Make sure the instruction knows. + MachineInstr *MI = getInstructionFromIndex(VNI->def); + assert(MI && "No instruction defining live value"); + MI->addRegisterDead(li->reg, tri_); + } + } + + // Move the trimmed ranges back. + li->ranges.swap(NewLI.ranges); + DEBUG(dbgs() << "Shrink: " << *li << '\n'); +} + + //===----------------------------------------------------------------------===// // Register allocator hooks. // +MachineBasicBlock::iterator +LiveIntervals::getLastSplitPoint(const LiveInterval &li, + MachineBasicBlock *mbb) const { + const MachineBasicBlock *lpad = mbb->getLandingPadSuccessor(); + + // If li is not live into a landing pad, we can insert spill code before the + // first terminator. + if (!lpad || !isLiveInToMBB(li, lpad)) + return mbb->getFirstTerminator(); + + // When there is a landing pad, spill code must go before the call instruction + // that can throw. + MachineBasicBlock::iterator I = mbb->end(), B = mbb->begin(); + while (I != B) { + --I; + if (I->getDesc().isCall()) + return I; + } + // The block contains no calls that can throw, so use the first terminator. + return mbb->getFirstTerminator(); +} + +void LiveIntervals::addKillFlags() { + for (iterator I = begin(), E = end(); I != E; ++I) { + unsigned Reg = I->first; + if (TargetRegisterInfo::isPhysicalRegister(Reg)) + continue; + if (mri_->reg_nodbg_empty(Reg)) + continue; + LiveInterval *LI = I->second; + + // Every instruction that kills Reg corresponds to a live range end point. + for (LiveInterval::iterator RI = LI->begin(), RE = LI->end(); RI != RE; + ++RI) { + // A LOAD index indicates an MBB edge. + if (RI->end.isLoad()) + continue; + MachineInstr *MI = getInstructionFromIndex(RI->end); + if (!MI) + continue; + MI->addRegisterKilled(Reg, NULL); + } + } +} + /// getReMatImplicitUse - If the remat definition MI has one (for now, we only /// allow one) virtual register operand, then its uses are implicitly using /// the register. Returns the virtual register. @@ -800,18 +946,17 @@ unsigned LiveIntervals::getReMatImplicitUse(const LiveInterval &li, /// which reaches the given instruction also reaches the specified use index. bool LiveIntervals::isValNoAvailableAt(const LiveInterval &li, MachineInstr *MI, SlotIndex UseIdx) const { - SlotIndex Index = getInstructionIndex(MI); - VNInfo *ValNo = li.FindLiveRangeContaining(Index)->valno; - LiveInterval::const_iterator UI = li.FindLiveRangeContaining(UseIdx); - return UI != li.end() && UI->valno == ValNo; + VNInfo *UValNo = li.getVNInfoAt(UseIdx); + return UValNo && UValNo == li.getVNInfoAt(getInstructionIndex(MI)); } /// isReMaterializable - Returns true if the definition MI of the specified /// val# of the specified interval is re-materializable. -bool LiveIntervals::isReMaterializable(const LiveInterval &li, - const VNInfo *ValNo, MachineInstr *MI, - SmallVectorImpl &SpillIs, - bool &isLoad) { +bool +LiveIntervals::isReMaterializable(const LiveInterval &li, + const VNInfo *ValNo, MachineInstr *MI, + const SmallVectorImpl &SpillIs, + bool &isLoad) { if (DisableReMat) return false; @@ -829,7 +974,7 @@ bool LiveIntervals::isReMaterializable(const LiveInterval &li, ri != re; ++ri) { MachineInstr *UseMI = &*ri; SlotIndex UseIdx = getInstructionIndex(UseMI); - if (li.FindLiveRangeContaining(UseIdx)->valno != ValNo) + if (li.getVNInfoAt(UseIdx) != ValNo) continue; if (!isValNoAvailableAt(ImpLi, MI, UseIdx)) return false; @@ -855,9 +1000,10 @@ bool LiveIntervals::isReMaterializable(const LiveInterval &li, /// isReMaterializable - Returns true if every definition of MI of every /// val# of the specified interval is re-materializable. -bool LiveIntervals::isReMaterializable(const LiveInterval &li, - SmallVectorImpl &SpillIs, - bool &isLoad) { +bool +LiveIntervals::isReMaterializable(const LiveInterval &li, + const SmallVectorImpl &SpillIs, + bool &isLoad) { isLoad = false; for (LiveInterval::const_vni_iterator i = li.vni_begin(), e = li.vni_end(); i != e; ++i) { @@ -865,9 +1011,9 @@ bool LiveIntervals::isReMaterializable(const LiveInterval &li, if (VNI->isUnused()) continue; // Dead val#. // Is the def for the val# rematerializable? - if (!VNI->isDefAccurate()) - return false; MachineInstr *ReMatDefMI = getInstructionFromIndex(VNI->def); + if (!ReMatDefMI) + return false; bool DefIsLoad = false; if (!ReMatDefMI || !isReMaterializable(li, VNI, ReMatDefMI, SpillIs, DefIsLoad)) @@ -1010,7 +1156,7 @@ void LiveIntervals::rewriteImplicitOps(const LiveInterval &li, if (!MO.isReg()) continue; unsigned Reg = MO.getReg(); - if (Reg == 0 || TargetRegisterInfo::isPhysicalRegister(Reg)) + if (!TargetRegisterInfo::isVirtualRegister(Reg)) continue; if (!vrm.isReMaterialized(Reg)) continue; @@ -1044,7 +1190,7 @@ rewriteInstructionForSpills(const LiveInterval &li, const VNInfo *VNI, if (!mop.isReg()) continue; unsigned Reg = mop.getReg(); - if (Reg == 0 || TargetRegisterInfo::isPhysicalRegister(Reg)) + if (!TargetRegisterInfo::isVirtualRegister(Reg)) continue; if (Reg != li.reg) continue; @@ -1140,11 +1286,14 @@ rewriteInstructionForSpills(const LiveInterval &li, const VNInfo *VNI, rewriteImplicitOps(li, MI, NewVReg, vrm); // Reuse NewVReg for other reads. + bool HasEarlyClobber = false; for (unsigned j = 0, e = Ops.size(); j != e; ++j) { MachineOperand &mopj = MI->getOperand(Ops[j]); mopj.setReg(NewVReg); if (mopj.isImplicit()) rewriteImplicitOps(li, MI, NewVReg, vrm); + if (mopj.isEarlyClobber()) + HasEarlyClobber = true; } if (CreatedNewVReg) { @@ -1190,7 +1339,7 @@ rewriteInstructionForSpills(const LiveInterval &li, const VNInfo *VNI, if (HasUse) { if (CreatedNewVReg) { LiveRange LR(index.getLoadIndex(), index.getDefIndex(), - nI.getNextValue(SlotIndex(), 0, false, VNInfoAllocator)); + nI.getNextValue(SlotIndex(), 0, VNInfoAllocator)); DEBUG(dbgs() << " +" << LR); nI.addRange(LR); } else { @@ -1203,8 +1352,12 @@ rewriteInstructionForSpills(const LiveInterval &li, const VNInfo *VNI, } } if (HasDef) { - LiveRange LR(index.getDefIndex(), index.getStoreIndex(), - nI.getNextValue(SlotIndex(), 0, false, VNInfoAllocator)); + // An early clobber starts at the use slot, except for an early clobber + // tied to a use operand (yes, that is a thing). + LiveRange LR(HasEarlyClobber && !HasUse ? + index.getUseIndex() : index.getDefIndex(), + index.getStoreIndex(), + nI.getNextValue(SlotIndex(), 0, VNInfoAllocator)); DEBUG(dbgs() << " +" << LR); nI.addRange(LR); } @@ -1554,15 +1707,15 @@ LiveIntervals::getSpillWeight(bool isDef, bool isUse, unsigned loopDepth) { return (isDef + isUse) * lc; } -void -LiveIntervals::normalizeSpillWeights(std::vector &NewLIs) { +static void normalizeSpillWeights(std::vector &NewLIs) { for (unsigned i = 0, e = NewLIs.size(); i != e; ++i) - normalizeSpillWeight(*NewLIs[i]); + NewLIs[i]->weight = + normalizeSpillWeight(NewLIs[i]->weight, NewLIs[i]->getSize()); } std::vector LiveIntervals:: addIntervalsForSpills(const LiveInterval &li, - SmallVectorImpl &SpillIs, + const SmallVectorImpl &SpillIs, const MachineLoopInfo *loopInfo, VirtRegMap &vrm) { assert(li.isSpillable() && "attempt to spill already spilled interval!"); @@ -1653,8 +1806,7 @@ addIntervalsForSpills(const LiveInterval &li, if (VNI->isUnused()) continue; // Dead val#. // Is the def for the val# rematerializable? - MachineInstr *ReMatDefMI = VNI->isDefAccurate() - ? getInstructionFromIndex(VNI->def) : 0; + MachineInstr *ReMatDefMI = getInstructionFromIndex(VNI->def); bool dummy; if (ReMatDefMI && isReMaterializable(li, VNI, ReMatDefMI, SpillIs, dummy)) { // Remember how to remat the def of this val#. @@ -1926,6 +2078,9 @@ bool LiveIntervals::spillPhysRegAroundRegDefsUses(const LiveInterval &li, unsigned PhysReg, VirtRegMap &vrm) { unsigned SpillReg = getRepresentativeReg(PhysReg); + DEBUG(dbgs() << "spillPhysRegAroundRegDefsUses " << tri_->getName(PhysReg) + << " represented by " << tri_->getName(SpillReg) << '\n'); + for (const unsigned *AS = tri_->getAliasSet(PhysReg); *AS; ++AS) // If there are registers which alias PhysReg, but which are not a // sub-register of the chosen representative super register. Assert @@ -1937,15 +2092,16 @@ bool LiveIntervals::spillPhysRegAroundRegDefsUses(const LiveInterval &li, SmallVector PRegs; if (hasInterval(SpillReg)) PRegs.push_back(SpillReg); - else { - SmallSet Added; - for (const unsigned* AS = tri_->getSubRegisters(SpillReg); *AS; ++AS) - if (Added.insert(*AS) && hasInterval(*AS)) { - PRegs.push_back(*AS); - for (const unsigned* ASS = tri_->getSubRegisters(*AS); *ASS; ++ASS) - Added.insert(*ASS); - } - } + for (const unsigned *SR = tri_->getSubRegisters(SpillReg); *SR; ++SR) + if (hasInterval(*SR)) + PRegs.push_back(*SR); + + DEBUG({ + dbgs() << "Trying to spill:"; + for (unsigned i = 0, e = PRegs.size(); i != e; ++i) + dbgs() << ' ' << tri_->getName(PRegs[i]); + dbgs() << '\n'; + }); SmallPtrSet SeenMIs; for (MachineRegisterInfo::reg_iterator I = mri_->reg_begin(li.reg), @@ -1956,18 +2112,16 @@ bool LiveIntervals::spillPhysRegAroundRegDefsUses(const LiveInterval &li, continue; SeenMIs.insert(MI); SlotIndex Index = getInstructionIndex(MI); + bool LiveReg = false; for (unsigned i = 0, e = PRegs.size(); i != e; ++i) { unsigned PReg = PRegs[i]; LiveInterval &pli = getInterval(PReg); if (!pli.liveAt(Index)) continue; - vrm.addEmergencySpill(PReg, MI); + LiveReg = true; SlotIndex StartIdx = Index.getLoadIndex(); SlotIndex EndIdx = Index.getNextIndex().getBaseIndex(); - if (pli.isInOneLiveRange(StartIdx, EndIdx)) { - pli.removeRange(StartIdx, EndIdx); - Cut = true; - } else { + if (!pli.isInOneLiveRange(StartIdx, EndIdx)) { std::string msg; raw_string_ostream Msg(msg); Msg << "Ran out of registers during register allocation!"; @@ -1978,15 +2132,14 @@ bool LiveIntervals::spillPhysRegAroundRegDefsUses(const LiveInterval &li, } report_fatal_error(Msg.str()); } - for (const unsigned* AS = tri_->getSubRegisters(PReg); *AS; ++AS) { - if (!hasInterval(*AS)) - continue; - LiveInterval &spli = getInterval(*AS); - if (spli.liveAt(Index)) - spli.removeRange(Index.getLoadIndex(), - Index.getNextIndex().getBaseIndex()); - } + pli.removeRange(StartIdx, EndIdx); + LiveReg = true; } + if (!LiveReg) + continue; + DEBUG(dbgs() << "Emergency spill around " << Index << '\t' << *MI); + vrm.addEmergencySpill(SpillReg, MI); + Cut = true; } return Cut; } @@ -1996,7 +2149,7 @@ LiveRange LiveIntervals::addLiveRangeToEndOfBlock(unsigned reg, LiveInterval& Interval = getOrCreateInterval(reg); VNInfo* VN = Interval.getNextValue( SlotIndex(getInstructionIndex(startInst).getDefIndex()), - startInst, true, getVNInfoAllocator()); + startInst, getVNInfoAllocator()); VN->setHasPHIKill(true); LiveRange LR( SlotIndex(getInstructionIndex(startInst).getDefIndex()), diff --git a/lib/CodeGen/LiveIntervalUnion.cpp b/lib/CodeGen/LiveIntervalUnion.cpp new file mode 100644 index 000000000000..205f28a0d65a --- /dev/null +++ b/lib/CodeGen/LiveIntervalUnion.cpp @@ -0,0 +1,315 @@ +//===-- LiveIntervalUnion.cpp - Live interval union data structure --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// LiveIntervalUnion represents a coalesced set of live intervals. This may be +// used during coalescing to represent a congruence class, or during register +// allocation to model liveness of a physical register. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "regalloc" +#include "LiveIntervalUnion.h" +#include "llvm/ADT/SparseBitVector.h" +#include "llvm/CodeGen/MachineLoopRanges.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetRegisterInfo.h" + +using namespace llvm; + + +// Merge a LiveInterval's segments. Guarantee no overlaps. +void LiveIntervalUnion::unify(LiveInterval &VirtReg) { + if (VirtReg.empty()) + return; + ++Tag; + + // Insert each of the virtual register's live segments into the map. + LiveInterval::iterator RegPos = VirtReg.begin(); + LiveInterval::iterator RegEnd = VirtReg.end(); + SegmentIter SegPos = Segments.find(RegPos->start); + + for (;;) { + SegPos.insert(RegPos->start, RegPos->end, &VirtReg); + if (++RegPos == RegEnd) + return; + SegPos.advanceTo(RegPos->start); + } +} + +// Remove a live virtual register's segments from this union. +void LiveIntervalUnion::extract(LiveInterval &VirtReg) { + if (VirtReg.empty()) + return; + ++Tag; + + // Remove each of the virtual register's live segments from the map. + LiveInterval::iterator RegPos = VirtReg.begin(); + LiveInterval::iterator RegEnd = VirtReg.end(); + SegmentIter SegPos = Segments.find(RegPos->start); + + for (;;) { + assert(SegPos.value() == &VirtReg && "Inconsistent LiveInterval"); + SegPos.erase(); + if (!SegPos.valid()) + return; + + // Skip all segments that may have been coalesced. + RegPos = VirtReg.advanceTo(RegPos, SegPos.start()); + if (RegPos == RegEnd) + return; + + SegPos.advanceTo(RegPos->start); + } +} + +void +LiveIntervalUnion::print(raw_ostream &OS, const TargetRegisterInfo *TRI) const { + OS << "LIU " << PrintReg(RepReg, TRI); + if (empty()) { + OS << " empty\n"; + return; + } + for (LiveSegments::const_iterator SI = Segments.begin(); SI.valid(); ++SI) { + OS << " [" << SI.start() << ' ' << SI.stop() << "):" + << PrintReg(SI.value()->reg, TRI); + } + OS << '\n'; +} + +void LiveIntervalUnion::InterferenceResult::print(raw_ostream &OS, + const TargetRegisterInfo *TRI) const { + OS << '[' << start() << ';' << stop() << "):" + << PrintReg(interference()->reg, TRI); +} + +void LiveIntervalUnion::Query::print(raw_ostream &OS, + const TargetRegisterInfo *TRI) { + OS << "Interferences with "; + LiveUnion->print(OS, TRI); + InterferenceResult IR = firstInterference(); + while (isInterference(IR)) { + OS << " "; + IR.print(OS, TRI); + OS << '\n'; + nextInterference(IR); + } +} + +#ifndef NDEBUG +// Verify the live intervals in this union and add them to the visited set. +void LiveIntervalUnion::verify(LiveVirtRegBitSet& VisitedVRegs) { + for (SegmentIter SI = Segments.begin(); SI.valid(); ++SI) + VisitedVRegs.set(SI.value()->reg); +} +#endif //!NDEBUG + +// Private interface accessed by Query. +// +// Find a pair of segments that intersect, one in the live virtual register +// (LiveInterval), and the other in this LiveIntervalUnion. The caller (Query) +// is responsible for advancing the LiveIntervalUnion segments to find a +// "notable" intersection, which requires query-specific logic. +// +// This design assumes only a fast mechanism for intersecting a single live +// virtual register segment with a set of LiveIntervalUnion segments. This may +// be ok since most virtual registers have very few segments. If we had a data +// structure that optimizd MxN intersection of segments, then we would bypass +// the loop that advances within the LiveInterval. +// +// If no intersection exists, set VirtRegI = VirtRegEnd, and set SI to the first +// segment whose start point is greater than LiveInterval's end point. +// +// Assumes that segments are sorted by start position in both +// LiveInterval and LiveSegments. +void LiveIntervalUnion::Query::findIntersection(InterferenceResult &IR) const { + // Search until reaching the end of the LiveUnion segments. + LiveInterval::iterator VirtRegEnd = VirtReg->end(); + if (IR.VirtRegI == VirtRegEnd) + return; + while (IR.LiveUnionI.valid()) { + // Slowly advance the live virtual reg iterator until we surpass the next + // segment in LiveUnion. + // + // Note: If this is ever used for coalescing of fixed registers and we have + // a live vreg with thousands of segments, then change this code to use + // upperBound instead. + IR.VirtRegI = VirtReg->advanceTo(IR.VirtRegI, IR.LiveUnionI.start()); + if (IR.VirtRegI == VirtRegEnd) + break; // Retain current (nonoverlapping) LiveUnionI + + // VirtRegI may have advanced far beyond LiveUnionI, catch up. + IR.LiveUnionI.advanceTo(IR.VirtRegI->start); + + // Check if no LiveUnionI exists with VirtRegI->Start < LiveUnionI.end + if (!IR.LiveUnionI.valid()) + break; + if (IR.LiveUnionI.start() < IR.VirtRegI->end) { + assert(overlap(*IR.VirtRegI, IR.LiveUnionI) && + "upperBound postcondition"); + break; + } + } + if (!IR.LiveUnionI.valid()) + IR.VirtRegI = VirtRegEnd; +} + +// Find the first intersection, and cache interference info +// (retain segment iterators into both VirtReg and LiveUnion). +const LiveIntervalUnion::InterferenceResult & +LiveIntervalUnion::Query::firstInterference() { + if (CheckedFirstInterference) + return FirstInterference; + CheckedFirstInterference = true; + InterferenceResult &IR = FirstInterference; + + // Quickly skip interference check for empty sets. + if (VirtReg->empty() || LiveUnion->empty()) { + IR.VirtRegI = VirtReg->end(); + } else if (VirtReg->beginIndex() < LiveUnion->startIndex()) { + // VirtReg starts first, perform double binary search. + IR.VirtRegI = VirtReg->find(LiveUnion->startIndex()); + if (IR.VirtRegI != VirtReg->end()) + IR.LiveUnionI = LiveUnion->find(IR.VirtRegI->start); + } else { + // LiveUnion starts first, perform double binary search. + IR.LiveUnionI = LiveUnion->find(VirtReg->beginIndex()); + if (IR.LiveUnionI.valid()) + IR.VirtRegI = VirtReg->find(IR.LiveUnionI.start()); + else + IR.VirtRegI = VirtReg->end(); + } + findIntersection(FirstInterference); + assert((IR.VirtRegI == VirtReg->end() || IR.LiveUnionI.valid()) + && "Uninitialized iterator"); + return FirstInterference; +} + +// Treat the result as an iterator and advance to the next interfering pair +// of segments. This is a plain iterator with no filter. +bool LiveIntervalUnion::Query::nextInterference(InterferenceResult &IR) const { + assert(isInterference(IR) && "iteration past end of interferences"); + + // Advance either the VirtReg or LiveUnion segment to ensure that we visit all + // unique overlapping pairs. + if (IR.VirtRegI->end < IR.LiveUnionI.stop()) { + if (++IR.VirtRegI == VirtReg->end()) + return false; + } + else { + if (!(++IR.LiveUnionI).valid()) { + IR.VirtRegI = VirtReg->end(); + return false; + } + } + // Short-circuit findIntersection() if possible. + if (overlap(*IR.VirtRegI, IR.LiveUnionI)) + return true; + + // Find the next intersection. + findIntersection(IR); + return isInterference(IR); +} + +// Scan the vector of interfering virtual registers in this union. Assume it's +// quite small. +bool LiveIntervalUnion::Query::isSeenInterference(LiveInterval *VirtReg) const { + SmallVectorImpl::const_iterator I = + std::find(InterferingVRegs.begin(), InterferingVRegs.end(), VirtReg); + return I != InterferingVRegs.end(); +} + +// Count the number of virtual registers in this union that interfere with this +// query's live virtual register. +// +// The number of times that we either advance IR.VirtRegI or call +// LiveUnion.upperBound() will be no more than the number of holes in +// VirtReg. So each invocation of collectInterferingVRegs() takes +// time proportional to |VirtReg Holes| * time(LiveUnion.upperBound()). +// +// For comments on how to speed it up, see Query::findIntersection(). +unsigned LiveIntervalUnion::Query:: +collectInterferingVRegs(unsigned MaxInterferingRegs) { + InterferenceResult IR = firstInterference(); + LiveInterval::iterator VirtRegEnd = VirtReg->end(); + LiveInterval *RecentInterferingVReg = NULL; + if (IR.VirtRegI != VirtRegEnd) while (IR.LiveUnionI.valid()) { + // Advance the union's iterator to reach an unseen interfering vreg. + do { + if (IR.LiveUnionI.value() == RecentInterferingVReg) + continue; + + if (!isSeenInterference(IR.LiveUnionI.value())) + break; + + // Cache the most recent interfering vreg to bypass isSeenInterference. + RecentInterferingVReg = IR.LiveUnionI.value(); + + } while ((++IR.LiveUnionI).valid()); + if (!IR.LiveUnionI.valid()) + break; + + // Advance the VirtReg iterator until surpassing the next segment in + // LiveUnion. + IR.VirtRegI = VirtReg->advanceTo(IR.VirtRegI, IR.LiveUnionI.start()); + if (IR.VirtRegI == VirtRegEnd) + break; + + // Check for intersection with the union's segment. + if (overlap(*IR.VirtRegI, IR.LiveUnionI)) { + + if (!IR.LiveUnionI.value()->isSpillable()) + SeenUnspillableVReg = true; + + if (InterferingVRegs.size() == MaxInterferingRegs) + // Leave SeenAllInterferences set to false to indicate that at least one + // interference exists beyond those we collected. + return MaxInterferingRegs; + + InterferingVRegs.push_back(IR.LiveUnionI.value()); + + // Cache the most recent interfering vreg to bypass isSeenInterference. + RecentInterferingVReg = IR.LiveUnionI.value(); + ++IR.LiveUnionI; + continue; + } + // VirtRegI may have advanced far beyond LiveUnionI, + // do a fast intersection test to "catch up" + IR.LiveUnionI.advanceTo(IR.VirtRegI->start); + } + SeenAllInterferences = true; + return InterferingVRegs.size(); +} + +bool LiveIntervalUnion::Query::checkLoopInterference(MachineLoopRange *Loop) { + // VirtReg is likely live throughout the loop, so start by checking LIU-Loop + // overlaps. + IntervalMapOverlaps + Overlaps(LiveUnion->getMap(), Loop->getMap()); + if (!Overlaps.valid()) + return false; + + // The loop is overlapping an LIU assignment. Check VirtReg as well. + LiveInterval::iterator VRI = VirtReg->find(Overlaps.start()); + + for (;;) { + if (VRI == VirtReg->end()) + return false; + if (VRI->start < Overlaps.stop()) + return true; + + Overlaps.advanceTo(VRI->start); + if (!Overlaps.valid()) + return false; + if (Overlaps.start() < VRI->end) + return true; + + VRI = VirtReg->advanceTo(VRI, Overlaps.start()); + } +} diff --git a/lib/CodeGen/LiveIntervalUnion.h b/lib/CodeGen/LiveIntervalUnion.h new file mode 100644 index 000000000000..6f9c5f4455e9 --- /dev/null +++ b/lib/CodeGen/LiveIntervalUnion.h @@ -0,0 +1,258 @@ +//===-- LiveIntervalUnion.h - Live interval union data struct --*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// LiveIntervalUnion is a union of live segments across multiple live virtual +// registers. This may be used during coalescing to represent a congruence +// class, or during register allocation to model liveness of a physical +// register. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_LIVEINTERVALUNION +#define LLVM_CODEGEN_LIVEINTERVALUNION + +#include "llvm/ADT/IntervalMap.h" +#include "llvm/CodeGen/LiveInterval.h" + +#include + +namespace llvm { + +class MachineLoopRange; +class TargetRegisterInfo; + +#ifndef NDEBUG +// forward declaration +template class SparseBitVector; +typedef SparseBitVector<128> LiveVirtRegBitSet; +#endif + +/// Compare a live virtual register segment to a LiveIntervalUnion segment. +inline bool +overlap(const LiveRange &VRSeg, + const IntervalMap::const_iterator &LUSeg) { + return VRSeg.start < LUSeg.stop() && LUSeg.start() < VRSeg.end; +} + +/// Union of live intervals that are strong candidates for coalescing into a +/// single register (either physical or virtual depending on the context). We +/// expect the constituent live intervals to be disjoint, although we may +/// eventually make exceptions to handle value-based interference. +class LiveIntervalUnion { + // A set of live virtual register segments that supports fast insertion, + // intersection, and removal. + // Mapping SlotIndex intervals to virtual register numbers. + typedef IntervalMap LiveSegments; + +public: + // SegmentIter can advance to the next segment ordered by starting position + // which may belong to a different live virtual register. We also must be able + // to reach the current segment's containing virtual register. + typedef LiveSegments::iterator SegmentIter; + + // LiveIntervalUnions share an external allocator. + typedef LiveSegments::Allocator Allocator; + + class InterferenceResult; + class Query; + +private: + const unsigned RepReg; // representative register number + unsigned Tag; // unique tag for current contents. + LiveSegments Segments; // union of virtual reg segments + +public: + LiveIntervalUnion(unsigned r, Allocator &a) : RepReg(r), Tag(0), Segments(a) + {} + + // Iterate over all segments in the union of live virtual registers ordered + // by their starting position. + SegmentIter begin() { return Segments.begin(); } + SegmentIter end() { return Segments.end(); } + SegmentIter find(SlotIndex x) { return Segments.find(x); } + bool empty() const { return Segments.empty(); } + SlotIndex startIndex() const { return Segments.start(); } + + // Provide public access to the underlying map to allow overlap iteration. + typedef LiveSegments Map; + const Map &getMap() { return Segments; } + + /// getTag - Return an opaque tag representing the current state of the union. + unsigned getTag() const { return Tag; } + + /// changedSince - Return true if the union change since getTag returned tag. + bool changedSince(unsigned tag) const { return tag != Tag; } + + // Add a live virtual register to this union and merge its segments. + void unify(LiveInterval &VirtReg); + + // Remove a live virtual register's segments from this union. + void extract(LiveInterval &VirtReg); + + // Print union, using TRI to translate register names + void print(raw_ostream &OS, const TargetRegisterInfo *TRI) const; + +#ifndef NDEBUG + // Verify the live intervals in this union and add them to the visited set. + void verify(LiveVirtRegBitSet& VisitedVRegs); +#endif + + /// Cache a single interference test result in the form of two intersecting + /// segments. This allows efficiently iterating over the interferences. The + /// iteration logic is handled by LiveIntervalUnion::Query which may + /// filter interferences depending on the type of query. + class InterferenceResult { + friend class Query; + + LiveInterval::iterator VirtRegI; // current position in VirtReg + SegmentIter LiveUnionI; // current position in LiveUnion + + // Internal ctor. + InterferenceResult(LiveInterval::iterator VRegI, SegmentIter UnionI) + : VirtRegI(VRegI), LiveUnionI(UnionI) {} + + public: + // Public default ctor. + InterferenceResult(): VirtRegI(), LiveUnionI() {} + + /// start - Return the start of the current overlap. + SlotIndex start() const { + return std::max(VirtRegI->start, LiveUnionI.start()); + } + + /// stop - Return the end of the current overlap. + SlotIndex stop() const { + return std::min(VirtRegI->end, LiveUnionI.stop()); + } + + /// interference - Return the register that is interfering here. + LiveInterval *interference() const { return LiveUnionI.value(); } + + // Note: this interface provides raw access to the iterators because the + // result has no way to tell if it's valid to dereference them. + + // Access the VirtReg segment. + LiveInterval::iterator virtRegPos() const { return VirtRegI; } + + // Access the LiveUnion segment. + const SegmentIter &liveUnionPos() const { return LiveUnionI; } + + bool operator==(const InterferenceResult &IR) const { + return VirtRegI == IR.VirtRegI && LiveUnionI == IR.LiveUnionI; + } + bool operator!=(const InterferenceResult &IR) const { + return !operator==(IR); + } + + void print(raw_ostream &OS, const TargetRegisterInfo *TRI) const; + }; + + /// Query interferences between a single live virtual register and a live + /// interval union. + class Query { + LiveIntervalUnion *LiveUnion; + LiveInterval *VirtReg; + InterferenceResult FirstInterference; + SmallVector InterferingVRegs; + bool CheckedFirstInterference; + bool SeenAllInterferences; + bool SeenUnspillableVReg; + unsigned Tag; + + public: + Query(): LiveUnion(), VirtReg() {} + + Query(LiveInterval *VReg, LiveIntervalUnion *LIU): + LiveUnion(LIU), VirtReg(VReg), CheckedFirstInterference(false), + SeenAllInterferences(false), SeenUnspillableVReg(false) + {} + + void clear() { + LiveUnion = NULL; + VirtReg = NULL; + InterferingVRegs.clear(); + CheckedFirstInterference = false; + SeenAllInterferences = false; + SeenUnspillableVReg = false; + Tag = 0; + } + + void init(LiveInterval *VReg, LiveIntervalUnion *LIU) { + assert(VReg && LIU && "Invalid arguments"); + if (VirtReg == VReg && LiveUnion == LIU && !LIU->changedSince(Tag)) { + // Retain cached results, e.g. firstInterference. + return; + } + clear(); + LiveUnion = LIU; + VirtReg = VReg; + Tag = LIU->getTag(); + } + + LiveInterval &virtReg() const { + assert(VirtReg && "uninitialized"); + return *VirtReg; + } + + bool isInterference(const InterferenceResult &IR) const { + if (IR.VirtRegI != VirtReg->end()) { + assert(overlap(*IR.VirtRegI, IR.LiveUnionI) && + "invalid segment iterators"); + return true; + } + return false; + } + + // Does this live virtual register interfere with the union? + bool checkInterference() { return isInterference(firstInterference()); } + + // Get the first pair of interfering segments, or a noninterfering result. + // This initializes the firstInterference_ cache. + const InterferenceResult &firstInterference(); + + // Treat the result as an iterator and advance to the next interfering pair + // of segments. Visiting each unique interfering pairs means that the same + // VirtReg or LiveUnion segment may be visited multiple times. + bool nextInterference(InterferenceResult &IR) const; + + // Count the virtual registers in this union that interfere with this + // query's live virtual register, up to maxInterferingRegs. + unsigned collectInterferingVRegs(unsigned MaxInterferingRegs = UINT_MAX); + + // Was this virtual register visited during collectInterferingVRegs? + bool isSeenInterference(LiveInterval *VReg) const; + + // Did collectInterferingVRegs collect all interferences? + bool seenAllInterferences() const { return SeenAllInterferences; } + + // Did collectInterferingVRegs encounter an unspillable vreg? + bool seenUnspillableVReg() const { return SeenUnspillableVReg; } + + // Vector generated by collectInterferingVRegs. + const SmallVectorImpl &interferingVRegs() const { + return InterferingVRegs; + } + + /// checkLoopInterference - Return true if there is interference overlapping + /// Loop. + bool checkLoopInterference(MachineLoopRange*); + + void print(raw_ostream &OS, const TargetRegisterInfo *TRI); + private: + Query(const Query&); // DO NOT IMPLEMENT + void operator=(const Query&); // DO NOT IMPLEMENT + + // Private interface for queries + void findIntersection(InterferenceResult &IR) const; + }; +}; + +} // end namespace llvm + +#endif // !defined(LLVM_CODEGEN_LIVEINTERVALUNION) diff --git a/lib/CodeGen/LiveRangeEdit.cpp b/lib/CodeGen/LiveRangeEdit.cpp new file mode 100644 index 000000000000..3bbda1c2e609 --- /dev/null +++ b/lib/CodeGen/LiveRangeEdit.cpp @@ -0,0 +1,129 @@ +//===--- LiveRangeEdit.cpp - Basic tools for editing a register live range --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// The LiveRangeEdit class represents changes done to a virtual register when it +// is spilled or split. +//===----------------------------------------------------------------------===// + +#include "LiveRangeEdit.h" +#include "VirtRegMap.h" +#include "llvm/CodeGen/LiveIntervalAnalysis.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/Target/TargetInstrInfo.h" + +using namespace llvm; + +LiveInterval &LiveRangeEdit::create(MachineRegisterInfo &mri, + LiveIntervals &lis, + VirtRegMap &vrm) { + const TargetRegisterClass *RC = mri.getRegClass(getReg()); + unsigned VReg = mri.createVirtualRegister(RC); + vrm.grow(); + vrm.setIsSplitFromReg(VReg, vrm.getOriginal(getReg())); + LiveInterval &li = lis.getOrCreateInterval(VReg); + newRegs_.push_back(&li); + return li; +} + +void LiveRangeEdit::scanRemattable(LiveIntervals &lis, + const TargetInstrInfo &tii, + AliasAnalysis *aa) { + for (LiveInterval::vni_iterator I = parent_.vni_begin(), + E = parent_.vni_end(); I != E; ++I) { + VNInfo *VNI = *I; + if (VNI->isUnused()) + continue; + MachineInstr *DefMI = lis.getInstructionFromIndex(VNI->def); + if (!DefMI) + continue; + if (tii.isTriviallyReMaterializable(DefMI, aa)) + remattable_.insert(VNI); + } + scannedRemattable_ = true; +} + +bool LiveRangeEdit::anyRematerializable(LiveIntervals &lis, + const TargetInstrInfo &tii, + AliasAnalysis *aa) { + if (!scannedRemattable_) + scanRemattable(lis, tii, aa); + return !remattable_.empty(); +} + +/// allUsesAvailableAt - Return true if all registers used by OrigMI at +/// OrigIdx are also available with the same value at UseIdx. +bool LiveRangeEdit::allUsesAvailableAt(const MachineInstr *OrigMI, + SlotIndex OrigIdx, + SlotIndex UseIdx, + LiveIntervals &lis) { + OrigIdx = OrigIdx.getUseIndex(); + UseIdx = UseIdx.getUseIndex(); + for (unsigned i = 0, e = OrigMI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = OrigMI->getOperand(i); + if (!MO.isReg() || !MO.getReg() || MO.getReg() == getReg()) + continue; + // Reserved registers are OK. + if (MO.isUndef() || !lis.hasInterval(MO.getReg())) + continue; + // We don't want to move any defs. + if (MO.isDef()) + return false; + // We cannot depend on virtual registers in uselessRegs_. + for (unsigned ui = 0, ue = uselessRegs_.size(); ui != ue; ++ui) + if (uselessRegs_[ui]->reg == MO.getReg()) + return false; + + LiveInterval &li = lis.getInterval(MO.getReg()); + const VNInfo *OVNI = li.getVNInfoAt(OrigIdx); + if (!OVNI) + continue; + if (OVNI != li.getVNInfoAt(UseIdx)) + return false; + } + return true; +} + +bool LiveRangeEdit::canRematerializeAt(Remat &RM, + SlotIndex UseIdx, + bool cheapAsAMove, + LiveIntervals &lis) { + assert(scannedRemattable_ && "Call anyRematerializable first"); + + // Use scanRemattable info. + if (!remattable_.count(RM.ParentVNI)) + return false; + + // No defining instruction. + RM.OrigMI = lis.getInstructionFromIndex(RM.ParentVNI->def); + assert(RM.OrigMI && "Defining instruction for remattable value disappeared"); + + // If only cheap remats were requested, bail out early. + if (cheapAsAMove && !RM.OrigMI->getDesc().isAsCheapAsAMove()) + return false; + + // Verify that all used registers are available with the same values. + if (!allUsesAvailableAt(RM.OrigMI, RM.ParentVNI->def, UseIdx, lis)) + return false; + + return true; +} + +SlotIndex LiveRangeEdit::rematerializeAt(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, + const Remat &RM, + LiveIntervals &lis, + const TargetInstrInfo &tii, + const TargetRegisterInfo &tri) { + assert(RM.OrigMI && "Invalid remat"); + tii.reMaterialize(MBB, MI, DestReg, 0, RM.OrigMI, tri); + rematted_.insert(RM.ParentVNI); + return lis.InsertMachineInstrInMaps(--MI).getDefIndex(); +} + diff --git a/lib/CodeGen/LiveRangeEdit.h b/lib/CodeGen/LiveRangeEdit.h new file mode 100644 index 000000000000..73f69ed63983 --- /dev/null +++ b/lib/CodeGen/LiveRangeEdit.h @@ -0,0 +1,135 @@ +//===---- LiveRangeEdit.h - Basic tools for split and spill -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// The LiveRangeEdit class represents changes done to a virtual register when it +// is spilled or split. +// +// The parent register is never changed. Instead, a number of new virtual +// registers are created and added to the newRegs vector. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_LIVERANGEEDIT_H +#define LLVM_CODEGEN_LIVERANGEEDIT_H + +#include "llvm/CodeGen/LiveInterval.h" +#include "llvm/ADT/SmallPtrSet.h" + +namespace llvm { + +class AliasAnalysis; +class LiveIntervals; +class MachineRegisterInfo; +class VirtRegMap; + +class LiveRangeEdit { + LiveInterval &parent_; + SmallVectorImpl &newRegs_; + const SmallVectorImpl &uselessRegs_; + + /// firstNew_ - Index of the first register added to newRegs_. + const unsigned firstNew_; + + /// scannedRemattable_ - true when remattable values have been identified. + bool scannedRemattable_; + + /// remattable_ - Values defined by remattable instructions as identified by + /// tii.isTriviallyReMaterializable(). + SmallPtrSet remattable_; + + /// rematted_ - Values that were actually rematted, and so need to have their + /// live range trimmed or entirely removed. + SmallPtrSet rematted_; + + /// scanRemattable - Identify the parent_ values that may rematerialize. + void scanRemattable(LiveIntervals &lis, + const TargetInstrInfo &tii, + AliasAnalysis *aa); + + /// allUsesAvailableAt - Return true if all registers used by OrigMI at + /// OrigIdx are also available with the same value at UseIdx. + bool allUsesAvailableAt(const MachineInstr *OrigMI, SlotIndex OrigIdx, + SlotIndex UseIdx, LiveIntervals &lis); + +public: + /// Create a LiveRangeEdit for breaking down parent into smaller pieces. + /// @param parent The register being spilled or split. + /// @param newRegs List to receive any new registers created. This needn't be + /// empty initially, any existing registers are ignored. + /// @param uselessRegs List of registers that can't be used when + /// rematerializing values because they are about to be removed. + LiveRangeEdit(LiveInterval &parent, + SmallVectorImpl &newRegs, + const SmallVectorImpl &uselessRegs) + : parent_(parent), newRegs_(newRegs), uselessRegs_(uselessRegs), + firstNew_(newRegs.size()), scannedRemattable_(false) {} + + LiveInterval &getParent() const { return parent_; } + unsigned getReg() const { return parent_.reg; } + + /// Iterator for accessing the new registers added by this edit. + typedef SmallVectorImpl::const_iterator iterator; + iterator begin() const { return newRegs_.begin()+firstNew_; } + iterator end() const { return newRegs_.end(); } + unsigned size() const { return newRegs_.size()-firstNew_; } + bool empty() const { return size() == 0; } + LiveInterval *get(unsigned idx) const { return newRegs_[idx+firstNew_]; } + + /// create - Create a new register with the same class and stack slot as + /// parent. + LiveInterval &create(MachineRegisterInfo&, LiveIntervals&, VirtRegMap&); + + /// anyRematerializable - Return true if any parent values may be + /// rematerializable. + /// This function must be called before ny rematerialization is attempted. + bool anyRematerializable(LiveIntervals&, const TargetInstrInfo&, + AliasAnalysis*); + + /// Remat - Information needed to rematerialize at a specific location. + struct Remat { + VNInfo *ParentVNI; // parent_'s value at the remat location. + MachineInstr *OrigMI; // Instruction defining ParentVNI. + explicit Remat(VNInfo *ParentVNI) : ParentVNI(ParentVNI), OrigMI(0) {} + }; + + /// canRematerializeAt - Determine if ParentVNI can be rematerialized at + /// UseIdx. It is assumed that parent_.getVNINfoAt(UseIdx) == ParentVNI. + /// When cheapAsAMove is set, only cheap remats are allowed. + bool canRematerializeAt(Remat &RM, + SlotIndex UseIdx, + bool cheapAsAMove, + LiveIntervals &lis); + + /// rematerializeAt - Rematerialize RM.ParentVNI into DestReg by inserting an + /// instruction into MBB before MI. The new instruction is mapped, but + /// liveness is not updated. + /// Return the SlotIndex of the new instruction. + SlotIndex rematerializeAt(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, + const Remat &RM, + LiveIntervals&, + const TargetInstrInfo&, + const TargetRegisterInfo&); + + /// markRematerialized - explicitly mark a value as rematerialized after doing + /// it manually. + void markRematerialized(VNInfo *ParentVNI) { + rematted_.insert(ParentVNI); + } + + /// didRematerialize - Return true if ParentVNI was rematerialized anywhere. + bool didRematerialize(VNInfo *ParentVNI) const { + return rematted_.count(ParentVNI); + } +}; + +} + +#endif diff --git a/lib/CodeGen/LiveStackAnalysis.cpp b/lib/CodeGen/LiveStackAnalysis.cpp index b5c385f77239..c75196a47210 100644 --- a/lib/CodeGen/LiveStackAnalysis.cpp +++ b/lib/CodeGen/LiveStackAnalysis.cpp @@ -26,7 +26,9 @@ using namespace llvm; char LiveStacks::ID = 0; INITIALIZE_PASS(LiveStacks, "livestacks", - "Live Stack Slot Analysis", false, false); + "Live Stack Slot Analysis", false, false) + +char &llvm::LiveStacksID = LiveStacks::ID; void LiveStacks::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); @@ -48,6 +50,22 @@ bool LiveStacks::runOnMachineFunction(MachineFunction &) { return false; } +LiveInterval & +LiveStacks::getOrCreateInterval(int Slot, const TargetRegisterClass *RC) { + assert(Slot >= 0 && "Spill slot indice must be >= 0"); + SS2IntervalMap::iterator I = S2IMap.find(Slot); + if (I == S2IMap.end()) { + I = S2IMap.insert(I, std::make_pair(Slot, + LiveInterval(TargetRegisterInfo::index2StackSlot(Slot), 0.0F))); + S2RCMap.insert(std::make_pair(Slot, RC)); + } else { + // Use the largest common subclass register class. + const TargetRegisterClass *OldRC = S2RCMap[Slot]; + S2RCMap[Slot] = getCommonSubClass(OldRC, RC); + } + return I->second; +} + /// print - Implement the dump method. void LiveStacks::print(raw_ostream &OS, const Module*) const { diff --git a/lib/CodeGen/LiveVariables.cpp b/lib/CodeGen/LiveVariables.cpp index 375307b973a9..dd43ef2530c1 100644 --- a/lib/CodeGen/LiveVariables.cpp +++ b/lib/CodeGen/LiveVariables.cpp @@ -31,7 +31,6 @@ #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/Passes.h" #include "llvm/Support/Debug.h" -#include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/ADT/DepthFirstIterator.h" @@ -42,8 +41,11 @@ using namespace llvm; char LiveVariables::ID = 0; -INITIALIZE_PASS(LiveVariables, "livevars", - "Live Variable Analysis", false, false); +INITIALIZE_PASS_BEGIN(LiveVariables, "livevars", + "Live Variable Analysis", false, false) +INITIALIZE_PASS_DEPENDENCY(UnreachableMachineBlockElim) +INITIALIZE_PASS_END(LiveVariables, "livevars", + "Live Variable Analysis", false, false) void LiveVariables::getAnalysisUsage(AnalysisUsage &AU) const { @@ -79,13 +81,7 @@ void LiveVariables::VarInfo::dump() const { LiveVariables::VarInfo &LiveVariables::getVarInfo(unsigned RegIdx) { assert(TargetRegisterInfo::isVirtualRegister(RegIdx) && "getVarInfo: not a virtual register!"); - RegIdx -= TargetRegisterInfo::FirstVirtualRegister; - if (RegIdx >= VirtRegInfo.size()) { - if (RegIdx >= 2*VirtRegInfo.size()) - VirtRegInfo.resize(RegIdx*2); - else - VirtRegInfo.resize(2*VirtRegInfo.size()); - } + VirtRegInfo.grow(RegIdx); return VirtRegInfo[RegIdx]; } @@ -498,9 +494,6 @@ bool LiveVariables::runOnMachineFunction(MachineFunction &mf) { std::fill(PhysRegUse, PhysRegUse + NumRegs, (MachineInstr*)0); PHIJoins.clear(); - /// Get some space for a respectable number of registers. - VirtRegInfo.resize(64); - analyzePHINodes(mf); // Calculate live variable information in depth first order on the CFG of the @@ -628,19 +621,14 @@ bool LiveVariables::runOnMachineFunction(MachineFunction &mf) { // Convert and transfer the dead / killed information we have gathered into // VirtRegInfo onto MI's. - for (unsigned i = 0, e1 = VirtRegInfo.size(); i != e1; ++i) - for (unsigned j = 0, e2 = VirtRegInfo[i].Kills.size(); j != e2; ++j) - if (VirtRegInfo[i].Kills[j] == - MRI->getVRegDef(i + TargetRegisterInfo::FirstVirtualRegister)) - VirtRegInfo[i] - .Kills[j]->addRegisterDead(i + - TargetRegisterInfo::FirstVirtualRegister, - TRI); + for (unsigned i = 0, e1 = VirtRegInfo.size(); i != e1; ++i) { + const unsigned Reg = TargetRegisterInfo::index2VirtReg(i); + for (unsigned j = 0, e2 = VirtRegInfo[Reg].Kills.size(); j != e2; ++j) + if (VirtRegInfo[Reg].Kills[j] == MRI->getVRegDef(Reg)) + VirtRegInfo[Reg].Kills[j]->addRegisterDead(Reg, TRI); else - VirtRegInfo[i] - .Kills[j]->addRegisterKilled(i + - TargetRegisterInfo::FirstVirtualRegister, - TRI); + VirtRegInfo[Reg].Kills[j]->addRegisterKilled(Reg, TRI); + } // Check to make sure there are no unreachable blocks in the MC CFG for the // function. If so, it is due to a bug in the instruction selector or some @@ -775,8 +763,8 @@ void LiveVariables::addNewBlock(MachineBasicBlock *BB, getVarInfo(BBI->getOperand(i).getReg()).AliveBlocks.set(NumNew); // Update info for all live variables - for (unsigned Reg = TargetRegisterInfo::FirstVirtualRegister, - E = MRI->getLastVirtReg()+1; Reg != E; ++Reg) { + for (unsigned i = 0, e = MRI->getNumVirtRegs(); i != e; ++i) { + unsigned Reg = TargetRegisterInfo::index2VirtReg(i); VarInfo &VI = getVarInfo(Reg); if (!VI.AliveBlocks.test(NumNew) && VI.isLiveIn(*SuccBB, Reg, *MRI)) VI.AliveBlocks.set(NumNew); diff --git a/lib/CodeGen/LocalStackSlotAllocation.cpp b/lib/CodeGen/LocalStackSlotAllocation.cpp index 7e366f0ceec0..1318d6212497 100644 --- a/lib/CodeGen/LocalStackSlotAllocation.cpp +++ b/lib/CodeGen/LocalStackSlotAllocation.cpp @@ -9,7 +9,7 @@ // // This pass assigns local frame indices to stack slots relative to one another // and allocates additional base registers to access them when the target -// estimates the are likely to be out of range of stack pointer and frame +// estimates they are likely to be out of range of stack pointer and frame // pointer relative addressing. // //===----------------------------------------------------------------------===// @@ -34,7 +34,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetRegisterInfo.h" -#include "llvm/Target/TargetFrameInfo.h" +#include "llvm/Target/TargetFrameLowering.h" using namespace llvm; @@ -152,9 +152,9 @@ void LocalStackSlotPass::AdjustStackOffset(MachineFrameInfo *MFI, void LocalStackSlotPass::calculateFrameObjectOffsets(MachineFunction &Fn) { // Loop over all of the stack objects, assigning sequential addresses... MachineFrameInfo *MFI = Fn.getFrameInfo(); - const TargetFrameInfo &TFI = *Fn.getTarget().getFrameInfo(); + const TargetFrameLowering &TFI = *Fn.getTarget().getFrameLowering(); bool StackGrowsDown = - TFI.getStackGrowthDirection() == TargetFrameInfo::StackGrowsDown; + TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsDown; int64_t Offset = 0; unsigned MaxAlign = 0; @@ -227,27 +227,28 @@ bool LocalStackSlotPass::insertFrameReferenceRegisters(MachineFunction &Fn) { MachineFrameInfo *MFI = Fn.getFrameInfo(); const TargetRegisterInfo *TRI = Fn.getTarget().getRegisterInfo(); - const TargetFrameInfo &TFI = *Fn.getTarget().getFrameInfo(); + const TargetFrameLowering &TFI = *Fn.getTarget().getFrameLowering(); bool StackGrowsDown = - TFI.getStackGrowthDirection() == TargetFrameInfo::StackGrowsDown; - MachineBasicBlock::iterator InsertionPt = Fn.begin()->begin(); + TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsDown; // Collect all of the instructions in the block that reference // a frame index. Also store the frame index referenced to ease later // lookup. (For any insn that has more than one FI reference, we arbitrarily // choose the first one). SmallVector FrameReferenceInsns; - // A base register definition is a register+offset pair. - SmallVector, 8> BaseRegisters; + // A base register definition is a register + offset pair. + SmallVector, 8> BaseRegisters; for (MachineFunction::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB) { for (MachineBasicBlock::iterator I = BB->begin(); I != BB->end(); ++I) { MachineInstr *MI = I; + // Debug value instructions can't be out of range, so they don't need // any updates. if (MI->isDebugValue()) continue; + // For now, allocate the base register(s) within the basic block // where they're used, and don't try to keep them around outside // of that. It may be beneficial to try sharing them more broadly @@ -268,11 +269,13 @@ bool LocalStackSlotPass::insertFrameReferenceRegisters(MachineFunction &Fn) { } } } + // Sort the frame references by local offset array_pod_sort(FrameReferenceInsns.begin(), FrameReferenceInsns.end()); + MachineBasicBlock *Entry = Fn.begin(); - // Loop throught the frame references and allocate for them as necessary + // Loop through the frame references and allocate for them as necessary. for (int ref = 0, e = FrameReferenceInsns.size(); ref < e ; ++ref) { MachineBasicBlock::iterator I = FrameReferenceInsns[ref].getMachineInstr(); @@ -321,10 +324,12 @@ bool LocalStackSlotPass::insertFrameReferenceRegisters(MachineFunction &Fn) { DEBUG(dbgs() << " Materializing base register " << BaseReg << " at frame local offset " << LocalOffsets[FrameIdx] + InstrOffset << "\n"); + // Tell the target to insert the instruction to initialize // the base register. - TRI->materializeFrameBaseRegister(InsertionPt, BaseReg, - FrameIdx, InstrOffset); + // MachineBasicBlock::iterator InsertionPt = Entry->begin(); + TRI->materializeFrameBaseRegister(Entry, BaseReg, FrameIdx, + InstrOffset); // The base register already includes any offset specified // by the instruction, so account for that so it doesn't get diff --git a/lib/CodeGen/MachineBasicBlock.cpp b/lib/CodeGen/MachineBasicBlock.cpp index 50f3f672dced..ccbff0af5b2c 100644 --- a/lib/CodeGen/MachineBasicBlock.cpp +++ b/lib/CodeGen/MachineBasicBlock.cpp @@ -17,6 +17,7 @@ #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineLoopInfo.h" +#include "llvm/CodeGen/SlotIndexes.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/Target/TargetRegisterInfo.h" @@ -146,27 +147,46 @@ MachineBasicBlock::iterator MachineBasicBlock::getFirstNonPHI() { return I; } +MachineBasicBlock::iterator +MachineBasicBlock::SkipPHIsAndLabels(MachineBasicBlock::iterator I) { + while (I != end() && (I->isPHI() || I->isLabel() || I->isDebugValue())) + ++I; + return I; +} + MachineBasicBlock::iterator MachineBasicBlock::getFirstTerminator() { iterator I = end(); - while (I != begin() && (--I)->getDesc().isTerminator()) + while (I != begin() && ((--I)->getDesc().isTerminator() || I->isDebugValue())) ; /*noop */ - if (I != end() && !I->getDesc().isTerminator()) ++I; + while (I != end() && !I->getDesc().isTerminator()) + ++I; return I; } -void MachineBasicBlock::dump() const { - print(dbgs()); +MachineBasicBlock::iterator MachineBasicBlock::getLastNonDebugInstr() { + iterator B = begin(), I = end(); + while (I != B) { + --I; + if (I->isDebugValue()) + continue; + return I; + } + // The block is all debug values. + return end(); +} + +const MachineBasicBlock *MachineBasicBlock::getLandingPadSuccessor() const { + // A block with a landing pad successor only has one other successor. + if (succ_size() > 2) + return 0; + for (const_succ_iterator I = succ_begin(), E = succ_end(); I != E; ++I) + if ((*I)->isLandingPad()) + return *I; + return 0; } -static inline void OutputReg(raw_ostream &os, unsigned RegNo, - const TargetRegisterInfo *TRI = 0) { - if (RegNo != 0 && TargetRegisterInfo::isPhysicalRegister(RegNo)) { - if (TRI) - os << " %" << TRI->get(RegNo).Name; - else - os << " %physreg" << RegNo; - } else - os << " %reg" << RegNo; +void MachineBasicBlock::dump() const { + print(dbgs()); } StringRef MachineBasicBlock::getName() const { @@ -176,7 +196,7 @@ StringRef MachineBasicBlock::getName() const { return "(null)"; } -void MachineBasicBlock::print(raw_ostream &OS) const { +void MachineBasicBlock::print(raw_ostream &OS, SlotIndexes *Indexes) const { const MachineFunction *MF = getParent(); if (!MF) { OS << "Can't print out MachineBasicBlock because parent MachineFunction" @@ -186,6 +206,9 @@ void MachineBasicBlock::print(raw_ostream &OS) const { if (Alignment) { OS << "Alignment " << Alignment << "\n"; } + if (Indexes) + OS << Indexes->getMBBStartIdx(this) << '\t'; + OS << "BB#" << getNumber() << ": "; const char *Comma = ""; @@ -198,28 +221,36 @@ void MachineBasicBlock::print(raw_ostream &OS) const { if (hasAddressTaken()) { OS << Comma << "ADDRESS TAKEN"; Comma = ", "; } OS << '\n'; - const TargetRegisterInfo *TRI = MF->getTarget().getRegisterInfo(); + const TargetRegisterInfo *TRI = MF->getTarget().getRegisterInfo(); if (!livein_empty()) { + if (Indexes) OS << '\t'; OS << " Live Ins:"; for (livein_iterator I = livein_begin(),E = livein_end(); I != E; ++I) - OutputReg(OS, *I, TRI); + OS << ' ' << PrintReg(*I, TRI); OS << '\n'; } // Print the preds of this block according to the CFG. if (!pred_empty()) { + if (Indexes) OS << '\t'; OS << " Predecessors according to CFG:"; for (const_pred_iterator PI = pred_begin(), E = pred_end(); PI != E; ++PI) OS << " BB#" << (*PI)->getNumber(); OS << '\n'; } - + for (const_iterator I = begin(); I != end(); ++I) { + if (Indexes) { + if (Indexes->hasIndex(I)) + OS << Indexes->getInstructionIndex(I); + OS << '\t'; + } OS << '\t'; I->print(OS, &getParent()->getTarget()); } // Print the successors of this block according to the CFG. if (!succ_empty()) { + if (Indexes) OS << '\t'; OS << " Successors according to CFG:"; for (const_succ_iterator SI = succ_begin(), E = succ_end(); SI != E; ++SI) OS << " BB#" << (*SI)->getNumber(); @@ -431,14 +462,24 @@ MachineBasicBlock::SplitCriticalEdge(MachineBasicBlock *Succ, Pass *P) { MachineFunction *MF = getParent(); DebugLoc dl; // FIXME: this is nowhere - // We may need to update this's terminator, but we can't do that if AnalyzeBranch - // fails. If this uses a jump table, we won't touch it. + // We may need to update this's terminator, but we can't do that if + // AnalyzeBranch fails. If this uses a jump table, we won't touch it. const TargetInstrInfo *TII = MF->getTarget().getInstrInfo(); MachineBasicBlock *TBB = 0, *FBB = 0; SmallVector Cond; if (TII->AnalyzeBranch(*this, TBB, FBB, Cond)) return NULL; + // Avoid bugpoint weirdness: A block may end with a conditional branch but + // jumps to the same MBB is either case. We have duplicate CFG edges in that + // case that we can't handle. Since this never happens in properly optimized + // code, just skip those edges. + if (TBB && TBB == FBB) { + DEBUG(dbgs() << "Won't split critical edge after degenerate BB#" + << getNumber() << '\n'); + return NULL; + } + MachineBasicBlock *NMBB = MF->CreateMachineBasicBlock(); MF->insert(llvm::next(MachineFunction::iterator(this)), NMBB); DEBUG(dbgs() << "Splitting critical edge:" diff --git a/lib/CodeGen/MachineCSE.cpp b/lib/CodeGen/MachineCSE.cpp index 272b54dea1fa..07a7d27b019f 100644 --- a/lib/CodeGen/MachineCSE.cpp +++ b/lib/CodeGen/MachineCSE.cpp @@ -22,15 +22,18 @@ #include "llvm/Target/TargetInstrInfo.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/ScopedHashTable.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/RecyclingAllocator.h" using namespace llvm; STATISTIC(NumCoalesces, "Number of copies coalesced"); STATISTIC(NumCSEs, "Number of common subexpression eliminated"); -STATISTIC(NumPhysCSEs, "Number of phyreg defining common subexpr eliminated"); +STATISTIC(NumPhysCSEs, + "Number of physreg referencing common subexpr eliminated"); +STATISTIC(NumCommutes, "Number of copies coalesced after commuting"); namespace { class MachineCSE : public MachineFunctionPass { @@ -41,7 +44,9 @@ namespace { MachineRegisterInfo *MRI; public: static char ID; // Pass identification - MachineCSE() : MachineFunctionPass(ID), LookAheadLimit(5), CurrVN(0) {} + MachineCSE() : MachineFunctionPass(ID), LookAheadLimit(5), CurrVN(0) { + initializeMachineCSEPass(*PassRegistry::getPassRegistry()); + } virtual bool runOnMachineFunction(MachineFunction &MF); @@ -61,10 +66,13 @@ namespace { private: const unsigned LookAheadLimit; - typedef ScopedHashTableScope ScopeType; + typedef RecyclingAllocator > AllocatorTy; + typedef ScopedHashTable ScopedHTType; + typedef ScopedHTType::ScopeTy ScopeType; DenseMap ScopeMap; - ScopedHashTable VNT; + ScopedHTType VNT; SmallVector Exps; unsigned CurrVN; @@ -72,11 +80,11 @@ namespace { bool isPhysDefTriviallyDead(unsigned Reg, MachineBasicBlock::const_iterator I, MachineBasicBlock::const_iterator E) const ; - bool hasLivePhysRegDefUse(const MachineInstr *MI, - const MachineBasicBlock *MBB, - unsigned &PhysDef) const; - bool PhysRegDefReaches(MachineInstr *CSMI, MachineInstr *MI, - unsigned PhysDef) const; + bool hasLivePhysRegDefUses(const MachineInstr *MI, + const MachineBasicBlock *MBB, + SmallSet &PhysRefs) const; + bool PhysRegDefsReach(MachineInstr *CSMI, MachineInstr *MI, + SmallSet &PhysRefs) const; bool isCSECandidate(MachineInstr *MI); bool isProfitableToCSE(unsigned CSReg, unsigned Reg, MachineInstr *CSMI, MachineInstr *MI); @@ -91,8 +99,12 @@ namespace { } // end anonymous namespace char MachineCSE::ID = 0; -INITIALIZE_PASS(MachineCSE, "machine-cse", - "Machine Common Subexpression Elimination", false, false); +INITIALIZE_PASS_BEGIN(MachineCSE, "machine-cse", + "Machine Common Subexpression Elimination", false, false) +INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree) +INITIALIZE_AG_DEPENDENCY(AliasAnalysis) +INITIALIZE_PASS_END(MachineCSE, "machine-cse", + "Machine Common Subexpression Elimination", false, false) FunctionPass *llvm::createMachineCSEPass() { return new MachineCSE(); } @@ -104,7 +116,7 @@ bool MachineCSE::PerformTrivialCoalescing(MachineInstr *MI, if (!MO.isReg() || !MO.isUse()) continue; unsigned Reg = MO.getReg(); - if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg)) + if (!TargetRegisterInfo::isVirtualRegister(Reg)) continue; if (!MRI->hasOneNonDBGUse(Reg)) // Only coalesce single use copies. This ensure the copy will be @@ -120,17 +132,12 @@ bool MachineCSE::PerformTrivialCoalescing(MachineInstr *MI, continue; if (DefMI->getOperand(0).getSubReg() || DefMI->getOperand(1).getSubReg()) continue; - const TargetRegisterClass *SRC = MRI->getRegClass(SrcReg); - const TargetRegisterClass *RC = MRI->getRegClass(Reg); - const TargetRegisterClass *NewRC = getCommonSubClass(RC, SRC); - if (!NewRC) + if (!MRI->constrainRegClass(SrcReg, MRI->getRegClass(Reg))) continue; DEBUG(dbgs() << "Coalescing: " << *DefMI); - DEBUG(dbgs() << "*** to: " << *MI); + DEBUG(dbgs() << "*** to: " << *MI); MO.setReg(SrcReg); MRI->clearKillFlags(SrcReg); - if (NewRC != SRC) - MRI->setRegClass(SrcReg, NewRC); DefMI->eraseFromParent(); ++NumCoalesces; Changed = true; @@ -176,14 +183,14 @@ MachineCSE::isPhysDefTriviallyDead(unsigned Reg, return false; } -/// hasLivePhysRegDefUse - Return true if the specified instruction read / write +/// hasLivePhysRegDefUses - Return true if the specified instruction read/write /// physical registers (except for dead defs of physical registers). It also /// returns the physical register def by reference if it's the only one and the /// instruction does not uses a physical register. -bool MachineCSE::hasLivePhysRegDefUse(const MachineInstr *MI, - const MachineBasicBlock *MBB, - unsigned &PhysDef) const { - PhysDef = 0; +bool MachineCSE::hasLivePhysRegDefUses(const MachineInstr *MI, + const MachineBasicBlock *MBB, + SmallSet &PhysRefs) const { + MachineBasicBlock::const_iterator I = MI; I = llvm::next(I); for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { const MachineOperand &MO = MI->getOperand(i); if (!MO.isReg()) @@ -193,35 +200,22 @@ bool MachineCSE::hasLivePhysRegDefUse(const MachineInstr *MI, continue; if (TargetRegisterInfo::isVirtualRegister(Reg)) continue; - if (MO.isUse()) { - // Can't touch anything to read a physical register. - PhysDef = 0; - return true; - } - if (MO.isDead()) - // If the def is dead, it's ok. - continue; - // Ok, this is a physical register def that's not marked "dead". That's + // If the def is dead, it's ok. But the def may not marked "dead". That's // common since this pass is run before livevariables. We can scan // forward a few instructions and check if it is obviously dead. - if (PhysDef) { - // Multiple physical register defs. These are rare, forget about it. - PhysDef = 0; - return true; - } - PhysDef = Reg; + if (MO.isDef() && + (MO.isDead() || isPhysDefTriviallyDead(Reg, I, MBB->end()))) + continue; + PhysRefs.insert(Reg); + for (const unsigned *Alias = TRI->getAliasSet(Reg); *Alias; ++Alias) + PhysRefs.insert(*Alias); } - if (PhysDef) { - MachineBasicBlock::const_iterator I = MI; I = llvm::next(I); - if (!isPhysDefTriviallyDead(PhysDef, I, MBB->end())) - return true; - } - return false; + return !PhysRefs.empty(); } -bool MachineCSE::PhysRegDefReaches(MachineInstr *CSMI, MachineInstr *MI, - unsigned PhysDef) const { +bool MachineCSE::PhysRegDefsReach(MachineInstr *CSMI, MachineInstr *MI, + SmallSet &PhysRefs) const { // For now conservatively returns false if the common subexpression is // not in the same basic block as the given instruction. MachineBasicBlock *MBB = MI->getParent(); @@ -237,8 +231,17 @@ bool MachineCSE::PhysRegDefReaches(MachineInstr *CSMI, MachineInstr *MI, if (I == E) return true; - if (I->modifiesRegister(PhysDef, TRI)) - return false; + + for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = I->getOperand(i); + if (!MO.isReg() || !MO.isDef()) + continue; + unsigned MOReg = MO.getReg(); + if (TargetRegisterInfo::isVirtualRegister(MOReg)) + continue; + if (PhysRefs.count(MOReg)) + return false; + } --LookAheadLeft; ++I; @@ -259,7 +262,7 @@ bool MachineCSE::isCSECandidate(MachineInstr *MI) { // Ignore stuff that we obviously can't move. const TargetInstrDesc &TID = MI->getDesc(); if (TID.mayStore() || TID.isCall() || TID.isTerminator() || - TID.hasUnmodeledSideEffects()) + MI->hasUnmodeledSideEffects()) return false; if (TID.mayLoad()) { @@ -281,14 +284,13 @@ bool MachineCSE::isProfitableToCSE(unsigned CSReg, unsigned Reg, MachineInstr *CSMI, MachineInstr *MI) { // FIXME: Heuristics that works around the lack the live range splitting. - // Heuristics #1: Don't cse "cheap" computating if the def is not local or in an - // immediate predecessor. We don't want to increase register pressure and end up - // causing other computation to be spilled. + // Heuristics #1: Don't CSE "cheap" computation if the def is not local or in + // an immediate predecessor. We don't want to increase register pressure and + // end up causing other computation to be spilled. if (MI->getDesc().isAsCheapAsAMove()) { MachineBasicBlock *CSBB = CSMI->getParent(); MachineBasicBlock *BB = MI->getParent(); - if (CSBB != BB && - find(CSBB->succ_begin(), CSBB->succ_end(), BB) == CSBB->succ_end()) + if (CSBB != BB && !CSBB->isSuccessor(BB)) return false; } @@ -297,7 +299,7 @@ bool MachineCSE::isProfitableToCSE(unsigned CSReg, unsigned Reg, bool HasVRegUse = false; for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { const MachineOperand &MO = MI->getOperand(i); - if (MO.isReg() && MO.isUse() && MO.getReg() && + if (MO.isReg() && MO.isUse() && TargetRegisterInfo::isVirtualRegister(MO.getReg())) { HasVRegUse = true; break; @@ -359,7 +361,6 @@ bool MachineCSE::ProcessBlock(MachineBasicBlock *MBB) { if (!isCSECandidate(MI)) continue; - bool DefPhys = false; bool FoundCSE = VNT.count(MI); if (!FoundCSE) { // Look for trivial copy coalescing opportunities. @@ -370,24 +371,37 @@ bool MachineCSE::ProcessBlock(MachineBasicBlock *MBB) { FoundCSE = VNT.count(MI); } } - // FIXME: commute commutable instructions? - // If the instruction defines a physical register and the value *may* be + // Commute commutable instructions. + bool Commuted = false; + if (!FoundCSE && MI->getDesc().isCommutable()) { + MachineInstr *NewMI = TII->commuteInstruction(MI); + if (NewMI) { + Commuted = true; + FoundCSE = VNT.count(NewMI); + if (NewMI != MI) + // New instruction. It doesn't need to be kept. + NewMI->eraseFromParent(); + else if (!FoundCSE) + // MI was changed but it didn't help, commute it back! + (void)TII->commuteInstruction(MI); + } + } + + // If the instruction defines physical registers and the values *may* be // used, then it's not safe to replace it with a common subexpression. - unsigned PhysDef = 0; - if (FoundCSE && hasLivePhysRegDefUse(MI, MBB, PhysDef)) { + // It's also not safe if the instruction uses physical registers. + SmallSet PhysRefs; + if (FoundCSE && hasLivePhysRegDefUses(MI, MBB, PhysRefs)) { FoundCSE = false; // ... Unless the CS is local and it also defines the physical register - // which is not clobbered in between. - if (PhysDef) { - unsigned CSVN = VNT.lookup(MI); - MachineInstr *CSMI = Exps[CSVN]; - if (PhysRegDefReaches(CSMI, MI, PhysDef)) { - FoundCSE = true; - DefPhys = true; - } - } + // which is not clobbered in between and the physical register uses + // were not clobbered. + unsigned CSVN = VNT.lookup(MI); + MachineInstr *CSMI = Exps[CSVN]; + if (PhysRegDefsReach(CSMI, MI, PhysRefs)) + FoundCSE = true; } if (!FoundCSE) { @@ -432,8 +446,10 @@ bool MachineCSE::ProcessBlock(MachineBasicBlock *MBB) { } MI->eraseFromParent(); ++NumCSEs; - if (DefPhys) + if (!PhysRefs.empty()) ++NumPhysCSEs; + if (Commuted) + ++NumCommutes; } else { DEBUG(dbgs() << "*** Not profitable, avoid CSE!\n"); VNT.insert(MI, CurrVN++); diff --git a/lib/CodeGen/MachineDominators.cpp b/lib/CodeGen/MachineDominators.cpp index 3c674789244a..04c8ecbf9bdc 100644 --- a/lib/CodeGen/MachineDominators.cpp +++ b/lib/CodeGen/MachineDominators.cpp @@ -25,7 +25,7 @@ TEMPLATE_INSTANTIATION(class DominatorTreeBase); char MachineDominatorTree::ID = 0; INITIALIZE_PASS(MachineDominatorTree, "machinedomtree", - "MachineDominator Tree Construction", true, true); + "MachineDominator Tree Construction", true, true) char &llvm::MachineDominatorsID = MachineDominatorTree::ID; @@ -42,6 +42,7 @@ bool MachineDominatorTree::runOnMachineFunction(MachineFunction &F) { MachineDominatorTree::MachineDominatorTree() : MachineFunctionPass(ID) { + initializeMachineDominatorTreePass(*PassRegistry::getPassRegistry()); DT = new DominatorTreeBase(false); } diff --git a/lib/CodeGen/MachineFunction.cpp b/lib/CodeGen/MachineFunction.cpp index 017170076ceb..85532407ca43 100644 --- a/lib/CodeGen/MachineFunction.cpp +++ b/lib/CodeGen/MachineFunction.cpp @@ -33,7 +33,7 @@ #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetFrameInfo.h" +#include "llvm/Target/TargetFrameLowering.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/GraphWriter.h" @@ -52,14 +52,15 @@ void ilist_traits::deleteNode(MachineBasicBlock *MBB) { } MachineFunction::MachineFunction(const Function *F, const TargetMachine &TM, - unsigned FunctionNum, MachineModuleInfo &mmi) - : Fn(F), Target(TM), Ctx(mmi.getContext()), MMI(mmi) { + unsigned FunctionNum, MachineModuleInfo &mmi, + GCModuleInfo* gmi) + : Fn(F), Target(TM), Ctx(mmi.getContext()), MMI(mmi), GMI(gmi) { if (TM.getRegisterInfo()) RegInfo = new (Allocator) MachineRegisterInfo(*TM.getRegisterInfo()); else RegInfo = 0; MFInfo = 0; - FrameInfo = new (Allocator) MachineFrameInfo(*TM.getFrameInfo()); + FrameInfo = new (Allocator) MachineFrameInfo(*TM.getFrameLowering()); if (Fn->hasFnAttr(Attribute::StackAlignment)) FrameInfo->setMaxAlignment(Attribute::getStackAlignmentFromAttrs( Fn->getAttributes().getFnAttributes())); @@ -190,20 +191,21 @@ MachineFunction::DeleteMachineBasicBlock(MachineBasicBlock *MBB) { } MachineMemOperand * -MachineFunction::getMachineMemOperand(const Value *v, unsigned f, - int64_t o, uint64_t s, - unsigned base_alignment) { - return new (Allocator) MachineMemOperand(v, f, o, s, base_alignment); +MachineFunction::getMachineMemOperand(MachinePointerInfo PtrInfo, unsigned f, + uint64_t s, unsigned base_alignment, + const MDNode *TBAAInfo) { + return new (Allocator) MachineMemOperand(PtrInfo, f, s, base_alignment, + TBAAInfo); } MachineMemOperand * MachineFunction::getMachineMemOperand(const MachineMemOperand *MMO, int64_t Offset, uint64_t Size) { return new (Allocator) - MachineMemOperand(MMO->getValue(), MMO->getFlags(), - int64_t(uint64_t(MMO->getOffset()) + - uint64_t(Offset)), - Size, MMO->getBaseAlignment()); + MachineMemOperand(MachinePointerInfo(MMO->getValue(), + MMO->getOffset()+Offset), + MMO->getFlags(), Size, + MMO->getBaseAlignment(), 0); } MachineInstr::mmo_iterator @@ -231,10 +233,10 @@ MachineFunction::extractLoadMemRefs(MachineInstr::mmo_iterator Begin, else { // Clone the MMO and unset the store flag. MachineMemOperand *JustLoad = - getMachineMemOperand((*I)->getValue(), + getMachineMemOperand((*I)->getPointerInfo(), (*I)->getFlags() & ~MachineMemOperand::MOStore, - (*I)->getOffset(), (*I)->getSize(), - (*I)->getBaseAlignment()); + (*I)->getSize(), (*I)->getBaseAlignment(), + (*I)->getTBAAInfo()); Result[Index] = JustLoad; } ++Index; @@ -263,10 +265,10 @@ MachineFunction::extractStoreMemRefs(MachineInstr::mmo_iterator Begin, else { // Clone the MMO and unset the load flag. MachineMemOperand *JustStore = - getMachineMemOperand((*I)->getValue(), + getMachineMemOperand((*I)->getPointerInfo(), (*I)->getFlags() & ~MachineMemOperand::MOLoad, - (*I)->getOffset(), (*I)->getSize(), - (*I)->getBaseAlignment()); + (*I)->getSize(), (*I)->getBaseAlignment(), + (*I)->getTBAAInfo()); Result[Index] = JustStore; } ++Index; @@ -279,7 +281,7 @@ void MachineFunction::dump() const { print(dbgs()); } -void MachineFunction::print(raw_ostream &OS) const { +void MachineFunction::print(raw_ostream &OS, SlotIndexes *Indexes) const { OS << "# Machine code for function " << Fn->getName() << ":\n"; // Print Frame Information @@ -328,7 +330,7 @@ void MachineFunction::print(raw_ostream &OS) const { for (const_iterator BB = begin(), E = end(); BB != E; ++BB) { OS << '\n'; - BB->print(OS); + BB->print(OS, Indexes); } OS << "\n# End machine code for function " << Fn->getName() << ".\n\n"; @@ -346,17 +348,15 @@ namespace llvm { std::string getNodeLabel(const MachineBasicBlock *Node, const MachineFunction *Graph) { - if (isSimple () && Node->getBasicBlock() && - !Node->getBasicBlock()->getName().empty()) - return Node->getBasicBlock()->getNameStr() + ":"; - std::string OutStr; { raw_string_ostream OSS(OutStr); - - if (isSimple()) - OSS << Node->getNumber() << ':'; - else + + if (isSimple()) { + OSS << "BB#" << Node->getNumber(); + if (const BasicBlock *BB = Node->getBasicBlock()) + OSS << ": " << BB->getName(); + } else Node->print(OSS); } @@ -396,7 +396,8 @@ void MachineFunction::viewCFGOnly() const /// addLiveIn - Add the specified physical register as a live-in value and /// create a corresponding virtual register for it. unsigned MachineFunction::addLiveIn(unsigned PReg, - const TargetRegisterClass *RC) { + const TargetRegisterClass *RC, + DebugLoc DL) { MachineRegisterInfo &MRI = getRegInfo(); unsigned VReg = MRI.getLiveInVirtReg(PReg); if (VReg) { @@ -405,6 +406,7 @@ unsigned MachineFunction::addLiveIn(unsigned PReg, } VReg = MRI.createVirtualRegister(RC); MRI.addLiveIn(PReg, VReg); + MRI.addLiveInLoc(VReg, DL); return VReg; } @@ -426,6 +428,13 @@ MCSymbol *MachineFunction::getJTISymbol(unsigned JTI, MCContext &Ctx, return Ctx.GetOrCreateSymbol(Name.str()); } +/// getPICBaseSymbol - Return a function-local symbol to represent the PIC +/// base. +MCSymbol *MachineFunction::getPICBaseSymbol() const { + const MCAsmInfo &MAI = *Target.getMCAsmInfo(); + return Ctx.GetOrCreateSymbol(Twine(MAI.getPrivateGlobalPrefix())+ + Twine(getFunctionNumber())+"$pb"); +} //===----------------------------------------------------------------------===// // MachineFrameInfo implementation @@ -485,7 +494,7 @@ MachineFrameInfo::getPristineRegs(const MachineBasicBlock *MBB) const { void MachineFrameInfo::print(const MachineFunction &MF, raw_ostream &OS) const{ if (Objects.empty()) return; - const TargetFrameInfo *FI = MF.getTarget().getFrameInfo(); + const TargetFrameLowering *FI = MF.getTarget().getFrameLowering(); int ValOffset = (FI ? FI->getOffsetOfLocalArea() : 0); OS << "Frame Objects:\n"; diff --git a/lib/CodeGen/MachineFunctionAnalysis.cpp b/lib/CodeGen/MachineFunctionAnalysis.cpp index 4f84b952e061..054c750c9f2b 100644 --- a/lib/CodeGen/MachineFunctionAnalysis.cpp +++ b/lib/CodeGen/MachineFunctionAnalysis.cpp @@ -12,22 +12,17 @@ //===----------------------------------------------------------------------===// #include "llvm/CodeGen/MachineFunctionAnalysis.h" +#include "llvm/CodeGen/GCMetadata.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineModuleInfo.h" using namespace llvm; -// Register this pass with PassInfo directly to avoid having to define -// a default constructor. -static PassInfo -X("Machine Function Analysis", "machine-function-analysis", - &MachineFunctionAnalysis::ID, 0, - /*CFGOnly=*/false, /*is_analysis=*/true); - char MachineFunctionAnalysis::ID = 0; MachineFunctionAnalysis::MachineFunctionAnalysis(const TargetMachine &tm, CodeGenOpt::Level OL) : FunctionPass(ID), TM(tm), OptLevel(OL), MF(0) { + initializeMachineModuleInfoPass(*PassRegistry::getPassRegistry()); } MachineFunctionAnalysis::~MachineFunctionAnalysis() { @@ -52,7 +47,8 @@ bool MachineFunctionAnalysis::doInitialization(Module &M) { bool MachineFunctionAnalysis::runOnFunction(Function &F) { assert(!MF && "MachineFunctionAnalysis already initialized!"); MF = new MachineFunction(&F, TM, NextFnNum++, - getAnalysis()); + getAnalysis(), + getAnalysisIfAvailable()); return false; } diff --git a/lib/CodeGen/MachineInstr.cpp b/lib/CodeGen/MachineInstr.cpp index 446e461d5460..aa9ea61acec7 100644 --- a/lib/CodeGen/MachineInstr.cpp +++ b/lib/CodeGen/MachineInstr.cpp @@ -102,13 +102,13 @@ void MachineOperand::setReg(unsigned Reg) { if (MachineBasicBlock *MBB = MI->getParent()) if (MachineFunction *MF = MBB->getParent()) { RemoveRegOperandFromRegInfo(); - Contents.Reg.RegNo = Reg; + SmallContents.RegNo = Reg; AddRegOperandToRegInfo(&MF->getRegInfo()); return; } // Otherwise, just change the register, no problem. :) - Contents.Reg.RegNo = Reg; + SmallContents.RegNo = Reg; } void MachineOperand::substVirtReg(unsigned Reg, unsigned SubIdx, @@ -159,7 +159,7 @@ void MachineOperand::ChangeToRegister(unsigned Reg, bool isDef, bool isImp, } else { // Otherwise, change this to a register and set the reg#. OpKind = MO_Register; - Contents.Reg.RegNo = Reg; + SmallContents.RegNo = Reg; // If this operand is embedded in a function, add the operand to the // register's use/def list. @@ -227,24 +227,11 @@ void MachineOperand::print(raw_ostream &OS, const TargetMachine *TM) const { if (const MachineBasicBlock *MBB = MI->getParent()) if (const MachineFunction *MF = MBB->getParent()) TM = &MF->getTarget(); + const TargetRegisterInfo *TRI = TM ? TM->getRegisterInfo() : 0; switch (getType()) { case MachineOperand::MO_Register: - if (getReg() == 0 || TargetRegisterInfo::isVirtualRegister(getReg())) { - OS << "%reg" << getReg(); - } else { - if (TM) - OS << "%" << TM->getRegisterInfo()->get(getReg()).Name; - else - OS << "%physreg" << getReg(); - } - - if (getSubReg() != 0) { - if (TM) - OS << ':' << TM->getRegisterInfo()->getSubRegIndexName(getSubReg()); - else - OS << ':' << getSubReg(); - } + OS << PrintReg(getReg(), TRI, getSubReg()); if (isDef() || isKill() || isDead() || isImplicit() || isUndef() || isEarlyClobber()) { @@ -335,10 +322,45 @@ void MachineOperand::print(raw_ostream &OS, const TargetMachine *TM) const { // MachineMemOperand Implementation //===----------------------------------------------------------------------===// -MachineMemOperand::MachineMemOperand(const Value *v, unsigned int f, - int64_t o, uint64_t s, unsigned int a) - : Offset(o), Size(s), V(v), - Flags((f & ((1 << MOMaxBits) - 1)) | ((Log2_32(a) + 1) << MOMaxBits)) { +/// getAddrSpace - Return the LLVM IR address space number that this pointer +/// points into. +unsigned MachinePointerInfo::getAddrSpace() const { + if (V == 0) return 0; + return cast(V->getType())->getAddressSpace(); +} + +/// getConstantPool - Return a MachinePointerInfo record that refers to the +/// constant pool. +MachinePointerInfo MachinePointerInfo::getConstantPool() { + return MachinePointerInfo(PseudoSourceValue::getConstantPool()); +} + +/// getFixedStack - Return a MachinePointerInfo record that refers to the +/// the specified FrameIndex. +MachinePointerInfo MachinePointerInfo::getFixedStack(int FI, int64_t offset) { + return MachinePointerInfo(PseudoSourceValue::getFixedStack(FI), offset); +} + +MachinePointerInfo MachinePointerInfo::getJumpTable() { + return MachinePointerInfo(PseudoSourceValue::getJumpTable()); +} + +MachinePointerInfo MachinePointerInfo::getGOT() { + return MachinePointerInfo(PseudoSourceValue::getGOT()); +} + +MachinePointerInfo MachinePointerInfo::getStack(int64_t Offset) { + return MachinePointerInfo(PseudoSourceValue::getStack(), Offset); +} + +MachineMemOperand::MachineMemOperand(MachinePointerInfo ptrinfo, unsigned f, + uint64_t s, unsigned int a, + const MDNode *TBAAInfo) + : PtrInfo(ptrinfo), Size(s), + Flags((f & ((1 << MOMaxBits) - 1)) | ((Log2_32(a) + 1) << MOMaxBits)), + TBAAInfo(TBAAInfo) { + assert((PtrInfo.V == 0 || isa(PtrInfo.V->getType())) && + "invalid pointer value"); assert(getBaseAlignment() == a && "Alignment is not a power of 2!"); assert((isLoad() || isStore()) && "Not a load/store!"); } @@ -346,9 +368,9 @@ MachineMemOperand::MachineMemOperand(const Value *v, unsigned int f, /// Profile - Gather unique data for the object. /// void MachineMemOperand::Profile(FoldingSetNodeID &ID) const { - ID.AddInteger(Offset); + ID.AddInteger(getOffset()); ID.AddInteger(Size); - ID.AddPointer(V); + ID.AddPointer(getValue()); ID.AddInteger(Flags); } @@ -364,8 +386,7 @@ void MachineMemOperand::refineAlignment(const MachineMemOperand *MMO) { ((Log2_32(MMO->getBaseAlignment()) + 1) << MOMaxBits); // Also update the base and offset, because the new alignment may // not be applicable with the old ones. - V = MMO->getValue(); - Offset = MMO->getOffset(); + PtrInfo = MMO->PtrInfo; } } @@ -410,6 +431,16 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, const MachineMemOperand &MMO) { MMO.getBaseAlignment() != MMO.getSize()) OS << "(align=" << MMO.getAlignment() << ")"; + // Print TBAA info. + if (const MDNode *TBAAInfo = MMO.getTBAAInfo()) { + OS << "(tbaa="; + if (TBAAInfo->getNumOperands() > 0) + WriteAsOperand(OS, TBAAInfo->getOperand(0), /*PrintType=*/false); + else + OS << ""; + OS << ")"; + } + return OS; } @@ -782,6 +813,14 @@ unsigned MachineInstr::getNumExplicitOperands() const { return NumOperands; } +bool MachineInstr::isStackAligningInlineAsm() const { + if (isInlineAsm()) { + unsigned ExtraInfo = getOperand(InlineAsm::MIOp_ExtraInfo).getImm(); + if (ExtraInfo & InlineAsm::Extra_IsAlignStack) + return true; + } + return false; +} /// findRegisterUseOperandIdx() - Returns the MachineOperand that is a use of /// the specific register or -1 if it is not found. It further tightens @@ -881,14 +920,15 @@ int MachineInstr::findFirstPredOperandIdx() const { bool MachineInstr:: isRegTiedToUseOperand(unsigned DefOpIdx, unsigned *UseOpIdx) const { if (isInlineAsm()) { - assert(DefOpIdx >= 3); + assert(DefOpIdx > InlineAsm::MIOp_FirstOperand); const MachineOperand &MO = getOperand(DefOpIdx); if (!MO.isReg() || !MO.isDef() || MO.getReg() == 0) return false; // Determine the actual operand index that corresponds to this index. unsigned DefNo = 0; unsigned DefPart = 0; - for (unsigned i = 2, e = getNumOperands(); i < e; ) { + for (unsigned i = InlineAsm::MIOp_FirstOperand, e = getNumOperands(); + i < e; ) { const MachineOperand &FMO = getOperand(i); // After the normal asm operands there may be additional imp-def regs. if (!FMO.isImm()) @@ -903,7 +943,8 @@ isRegTiedToUseOperand(unsigned DefOpIdx, unsigned *UseOpIdx) const { } ++DefNo; } - for (unsigned i = 2, e = getNumOperands(); i != e; ++i) { + for (unsigned i = InlineAsm::MIOp_FirstOperand, e = getNumOperands(); + i != e; ++i) { const MachineOperand &FMO = getOperand(i); if (!FMO.isImm()) continue; @@ -946,7 +987,8 @@ isRegTiedToDefOperand(unsigned UseOpIdx, unsigned *DefOpIdx) const { // Find the flag operand corresponding to UseOpIdx unsigned FlagIdx, NumOps=0; - for (FlagIdx = 2; FlagIdx < UseOpIdx; FlagIdx += NumOps+1) { + for (FlagIdx = InlineAsm::MIOp_FirstOperand; + FlagIdx < UseOpIdx; FlagIdx += NumOps+1) { const MachineOperand &UFMO = getOperand(FlagIdx); // After the normal asm operands there may be additional imp-def regs. if (!UFMO.isImm()) @@ -964,9 +1006,9 @@ isRegTiedToDefOperand(unsigned UseOpIdx, unsigned *DefOpIdx) const { if (!DefOpIdx) return true; - unsigned DefIdx = 2; + unsigned DefIdx = InlineAsm::MIOp_FirstOperand; // Remember to adjust the index. First operand is asm string, second is - // the AlignStack bit, then there is a flag for each. + // the HasSideEffects and AlignStack bits, then there is a flag for each. while (DefNo) { const MachineOperand &FMO = getOperand(DefIdx); assert(FMO.isImm()); @@ -1071,7 +1113,9 @@ bool MachineInstr::isSafeToMove(const TargetInstrInfo *TII, SawStore = true; return false; } - if (TID->isTerminator() || TID->hasUnmodeledSideEffects()) + + if (isLabel() || isDebugValue() || + TID->isTerminator() || hasUnmodeledSideEffects()) return false; // See if this instruction does a load. If so, we have to guarantee that the @@ -1122,7 +1166,7 @@ bool MachineInstr::hasVolatileMemoryRef() const { if (!TID->mayStore() && !TID->mayLoad() && !TID->isCall() && - !TID->hasUnmodeledSideEffects()) + !hasUnmodeledSideEffects()) return false; // Otherwise, if the instruction has no memory reference information, @@ -1166,7 +1210,9 @@ bool MachineInstr::isInvariantLoad(AliasAnalysis *AA) const { if (PSV->isConstant(MFI)) continue; // If we have an AliasAnalysis, ask it whether the memory is constant. - if (AA && AA->pointsToConstantMemory(V)) + if (AA && AA->pointsToConstantMemory( + AliasAnalysis::Location(V, (*I)->getSize(), + (*I)->getTBAAInfo()))) continue; } @@ -1194,6 +1240,18 @@ unsigned MachineInstr::isConstantValuePHI() const { return Reg; } +bool MachineInstr::hasUnmodeledSideEffects() const { + if (getDesc().hasUnmodeledSideEffects()) + return true; + if (isInlineAsm()) { + unsigned ExtraInfo = getOperand(InlineAsm::MIOp_ExtraInfo).getImm(); + if (ExtraInfo & InlineAsm::Extra_HasSideEffects) + return true; + } + + return false; +} + /// allDefsAreDead - Return true if all the defs of this instruction are dead. /// bool MachineInstr::allDefsAreDead() const { @@ -1207,6 +1265,17 @@ bool MachineInstr::allDefsAreDead() const { return true; } +/// copyImplicitOps - Copy implicit register operands from specified +/// instruction to this instruction. +void MachineInstr::copyImplicitOps(const MachineInstr *MI) { + for (unsigned i = MI->getDesc().getNumOperands(), e = MI->getNumOperands(); + i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + if (MO.isReg() && MO.isImplicit()) + addOperand(MO); + } +} + void MachineInstr::dump() const { dbgs() << " " << *this; } @@ -1257,7 +1326,7 @@ void MachineInstr::print(raw_ostream &OS, const TargetMachine *TM) const { if (StartOp != 0) OS << ", "; getOperand(StartOp).print(OS, TM); unsigned Reg = getOperand(StartOp).getReg(); - if (Reg && TargetRegisterInfo::isVirtualRegister(Reg)) + if (TargetRegisterInfo::isVirtualRegister(Reg)) VirtRegs.push_back(Reg); } @@ -1270,11 +1339,28 @@ void MachineInstr::print(raw_ostream &OS, const TargetMachine *TM) const { // Print the rest of the operands. bool OmittedAnyCallClobbers = false; bool FirstOp = true; + + if (isInlineAsm()) { + // Print asm string. + OS << " "; + getOperand(InlineAsm::MIOp_AsmString).print(OS, TM); + + // Print HasSideEffects, IsAlignStack + unsigned ExtraInfo = getOperand(InlineAsm::MIOp_ExtraInfo).getImm(); + if (ExtraInfo & InlineAsm::Extra_HasSideEffects) + OS << " [sideeffect]"; + if (ExtraInfo & InlineAsm::Extra_IsAlignStack) + OS << " [alignstack]"; + + StartOp = InlineAsm::MIOp_FirstOperand; + FirstOp = false; + } + + for (unsigned i = StartOp, e = getNumOperands(); i != e; ++i) { const MachineOperand &MO = getOperand(i); - if (MO.isReg() && MO.getReg() && - TargetRegisterInfo::isVirtualRegister(MO.getReg())) + if (MO.isReg() && TargetRegisterInfo::isVirtualRegister(MO.getReg())) VirtRegs.push_back(MO.getReg()); // Omit call-clobbered registers which aren't used anywhere. This makes @@ -1284,7 +1370,7 @@ void MachineInstr::print(raw_ostream &OS, const TargetMachine *TM) const { if (MF && getDesc().isCall() && MO.isReg() && MO.isImplicit() && MO.isDef()) { unsigned Reg = MO.getReg(); - if (Reg != 0 && TargetRegisterInfo::isPhysicalRegister(Reg)) { + if (TargetRegisterInfo::isPhysicalRegister(Reg)) { const MachineRegisterInfo &MRI = MF->getRegInfo(); if (MRI.use_empty(Reg) && !MRI.isLiveOut(Reg)) { bool HasAliasLive = false; @@ -1348,14 +1434,14 @@ void MachineInstr::print(raw_ostream &OS, const TargetMachine *TM) const { if (!HaveSemi) OS << ";"; HaveSemi = true; for (unsigned i = 0; i != VirtRegs.size(); ++i) { const TargetRegisterClass *RC = MRI->getRegClass(VirtRegs[i]); - OS << " " << RC->getName() << ":%reg" << VirtRegs[i]; + OS << " " << RC->getName() << ':' << PrintReg(VirtRegs[i]); for (unsigned j = i+1; j != VirtRegs.size();) { if (MRI->getRegClass(VirtRegs[j]) != RC) { ++j; continue; } if (VirtRegs[i] != VirtRegs[j]) - OS << "," << VirtRegs[j]; + OS << "," << PrintReg(VirtRegs[j]); VirtRegs.erase(VirtRegs.begin()+j); } } @@ -1533,8 +1619,7 @@ MachineInstrExpressionTrait::getHashValue(const MachineInstr* const &MI) { switch (MO.getType()) { default: break; case MachineOperand::MO_Register: - if (MO.isDef() && MO.getReg() && - TargetRegisterInfo::isVirtualRegister(MO.getReg())) + if (MO.isDef() && TargetRegisterInfo::isVirtualRegister(MO.getReg())) continue; // Skip virtual register defs. Key |= MO.getReg(); break; diff --git a/lib/CodeGen/MachineLICM.cpp b/lib/CodeGen/MachineLICM.cpp index 1a74b747e9f2..443fc2d97bdf 100644 --- a/lib/CodeGen/MachineLICM.cpp +++ b/lib/CodeGen/MachineLICM.cpp @@ -28,8 +28,10 @@ #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/PseudoSourceValue.h" +#include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetInstrItineraries.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/ADT/DenseMap.h" @@ -40,8 +42,14 @@ using namespace llvm; -STATISTIC(NumHoisted, "Number of machine instructions hoisted out of loops"); -STATISTIC(NumCSEed, "Number of hoisted machine instructions CSEed"); +STATISTIC(NumHoisted, + "Number of machine instructions hoisted out of loops"); +STATISTIC(NumLowRP, + "Number of instructions hoisted in low reg pressure situation"); +STATISTIC(NumHighLatency, + "Number of high latency instructions hoisted"); +STATISTIC(NumCSEed, + "Number of hoisted machine instructions CSEed"); STATISTIC(NumPostRAHoisted, "Number of machine instructions hoisted out of loops post regalloc"); @@ -51,9 +59,11 @@ namespace { const TargetMachine *TM; const TargetInstrInfo *TII; + const TargetLowering *TLI; const TargetRegisterInfo *TRI; const MachineFrameInfo *MFI; - MachineRegisterInfo *RegInfo; + MachineRegisterInfo *MRI; + const InstrItineraryData *InstrItins; // Various analyses that we use... AliasAnalysis *AA; // Alias analysis info. @@ -68,23 +78,37 @@ namespace { BitVector AllocatableSet; + // Track 'estimated' register pressure. + SmallSet RegSeen; + SmallVector RegPressure; + + // Register pressure "limit" per register class. If the pressure + // is higher than the limit, then it's considered high. + SmallVector RegLimit; + + // Register pressure on path leading from loop preheader to current BB. + SmallVector, 16> BackTrace; + // For each opcode, keep a list of potential CSE instructions. DenseMap > CSEMap; public: static char ID; // Pass identification, replacement for typeid MachineLICM() : - MachineFunctionPass(ID), PreRegAlloc(true) {} + MachineFunctionPass(ID), PreRegAlloc(true) { + initializeMachineLICMPass(*PassRegistry::getPassRegistry()); + } explicit MachineLICM(bool PreRA) : - MachineFunctionPass(ID), PreRegAlloc(PreRA) {} + MachineFunctionPass(ID), PreRegAlloc(PreRA) { + initializeMachineLICMPass(*PassRegistry::getPassRegistry()); + } virtual bool runOnMachineFunction(MachineFunction &MF); const char *getPassName() const { return "Machine Instruction LICM"; } virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesCFG(); AU.addRequired(); AU.addRequired(); AU.addRequired(); @@ -94,6 +118,13 @@ namespace { } virtual void releaseMemory() { + RegSeen.clear(); + RegPressure.clear(); + RegLimit.clear(); + BackTrace.clear(); + for (DenseMap >::iterator + CI = CSEMap.begin(), CE = CSEMap.end(); CI != CE; ++CI) + CI->second.clear(); CSEMap.clear(); } @@ -138,6 +169,24 @@ namespace { /// bool IsLoopInvariantInst(MachineInstr &I); + /// HasHighOperandLatency - Compute operand latency between a def of 'Reg' + /// and an use in the current loop, return true if the target considered + /// it 'high'. + bool HasHighOperandLatency(MachineInstr &MI, unsigned DefIdx, + unsigned Reg) const; + + bool IsCheapInstruction(MachineInstr &MI) const; + + /// CanCauseHighRegPressure - Visit BBs from header to current BB, + /// check if hoisting an instruction of the given cost matrix can cause high + /// register pressure. + bool CanCauseHighRegPressure(DenseMap &Cost); + + /// UpdateBackTraceRegPressure - Traverse the back trace from header to + /// the current block and update their register pressures to reflect the + /// effect of hoisting MI from the current block to the preheader. + void UpdateBackTraceRegPressure(const MachineInstr *MI); + /// IsProfitableToHoist - Return true if it is potentially profitable to /// hoist the given loop invariant. bool IsProfitableToHoist(MachineInstr &MI); @@ -148,11 +197,16 @@ namespace { /// visit definitions before uses, allowing us to hoist a loop body in one /// pass without iteration. /// - void HoistRegion(MachineDomTreeNode *N); + void HoistRegion(MachineDomTreeNode *N, bool IsHeader = false); + + /// InitRegPressure - Find all virtual register references that are liveout + /// of the preheader to initialize the starting "register pressure". Note + /// this does not count live through (livein but not used) registers. + void InitRegPressure(MachineBasicBlock *BB); - /// isLoadFromConstantMemory - Return true if the given instruction is a - /// load from constant memory. - bool isLoadFromConstantMemory(MachineInstr *MI); + /// UpdateRegPressure - Update estimate of register pressure after the + /// specified instruction. + void UpdateRegPressure(const MachineInstr *MI); /// ExtractHoistableLoad - Unfold a load from the given machineinstr if /// the load itself could be hoisted. Return the unfolded and hoistable @@ -174,8 +228,8 @@ namespace { /// Hoist - When an instruction is found to only use loop invariant operands /// that is safe to hoist, this instruction is called to do the dirty work. - /// - void Hoist(MachineInstr *MI); + /// It returns true if the instruction is hoisted. + bool Hoist(MachineInstr *MI, MachineBasicBlock *Preheader); /// InitCSEMap - Initialize the CSE map with instructions that are in the /// current loop preheader that may become duplicates of instructions that @@ -189,8 +243,13 @@ namespace { } // end anonymous namespace char MachineLICM::ID = 0; -INITIALIZE_PASS(MachineLICM, "machinelicm", - "Machine Loop Invariant Code Motion", false, false); +INITIALIZE_PASS_BEGIN(MachineLICM, "machinelicm", + "Machine Loop Invariant Code Motion", false, false) +INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo) +INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree) +INITIALIZE_AG_DEPENDENCY(AliasAnalysis) +INITIALIZE_PASS_END(MachineLICM, "machinelicm", + "Machine Loop Invariant Code Motion", false, false) FunctionPass *llvm::createMachineLICMPass(bool PreRegAlloc) { return new MachineLICM(PreRegAlloc); @@ -212,18 +271,32 @@ static bool LoopIsOuterMostWithPredecessor(MachineLoop *CurLoop) { bool MachineLICM::runOnMachineFunction(MachineFunction &MF) { if (PreRegAlloc) - DEBUG(dbgs() << "******** Pre-regalloc Machine LICM ********\n"); + DEBUG(dbgs() << "******** Pre-regalloc Machine LICM: "); else - DEBUG(dbgs() << "******** Post-regalloc Machine LICM ********\n"); + DEBUG(dbgs() << "******** Post-regalloc Machine LICM: "); + DEBUG(dbgs() << MF.getFunction()->getName() << " ********\n"); Changed = FirstInLoop = false; TM = &MF.getTarget(); TII = TM->getInstrInfo(); + TLI = TM->getTargetLowering(); TRI = TM->getRegisterInfo(); MFI = MF.getFrameInfo(); - RegInfo = &MF.getRegInfo(); + MRI = &MF.getRegInfo(); + InstrItins = TM->getInstrItineraryData(); AllocatableSet = TRI->getAllocatableSet(MF); + if (PreRegAlloc) { + // Estimate register pressure during pre-regalloc pass. + unsigned NumRC = TRI->getNumRegClasses(); + RegPressure.resize(NumRC); + std::fill(RegPressure.begin(), RegPressure.end(), 0); + RegLimit.resize(NumRC); + for (TargetRegisterInfo::regclass_iterator I = TRI->regclass_begin(), + E = TRI->regclass_end(); I != E; ++I) + RegLimit[(*I)->getID()] = TLI->getRegPressureLimit(*I, MF); + } + // Get our Loop information... MLI = &getAnalysis(); DT = &getAnalysis(); @@ -248,7 +321,7 @@ bool MachineLICM::runOnMachineFunction(MachineFunction &MF) { // being hoisted. MachineDomTreeNode *N = DT->getNode(CurLoop->getHeader()); FirstInLoop = true; - HoistRegion(N); + HoistRegion(N, true); CSEMap.clear(); } } @@ -474,17 +547,33 @@ void MachineLICM::HoistPostRA(MachineInstr *MI, unsigned Def) { /// first order w.r.t the DominatorTree. This allows us to visit definitions /// before uses, allowing us to hoist a loop body in one pass without iteration. /// -void MachineLICM::HoistRegion(MachineDomTreeNode *N) { +void MachineLICM::HoistRegion(MachineDomTreeNode *N, bool IsHeader) { assert(N != 0 && "Null dominator tree node?"); MachineBasicBlock *BB = N->getBlock(); // If this subregion is not in the top level loop at all, exit. if (!CurLoop->contains(BB)) return; + MachineBasicBlock *Preheader = getCurPreheader(); + if (!Preheader) + return; + + if (IsHeader) { + // Compute registers which are livein into the loop headers. + RegSeen.clear(); + BackTrace.clear(); + InitRegPressure(Preheader); + } + + // Remember livein register pressure. + BackTrace.push_back(RegPressure); + for (MachineBasicBlock::iterator MII = BB->begin(), E = BB->end(); MII != E; ) { MachineBasicBlock::iterator NextMII = MII; ++NextMII; - Hoist(&*MII); + MachineInstr *MI = &*MII; + if (!Hoist(MI, Preheader)) + UpdateRegPressure(MI); MII = NextMII; } @@ -496,6 +585,99 @@ void MachineLICM::HoistRegion(MachineDomTreeNode *N) { for (unsigned I = 0, E = Children.size(); I != E; ++I) HoistRegion(Children[I]); } + + BackTrace.pop_back(); +} + +static bool isOperandKill(const MachineOperand &MO, MachineRegisterInfo *MRI) { + return MO.isKill() || MRI->hasOneNonDBGUse(MO.getReg()); +} + +/// InitRegPressure - Find all virtual register references that are liveout of +/// the preheader to initialize the starting "register pressure". Note this +/// does not count live through (livein but not used) registers. +void MachineLICM::InitRegPressure(MachineBasicBlock *BB) { + std::fill(RegPressure.begin(), RegPressure.end(), 0); + + // If the preheader has only a single predecessor and it ends with a + // fallthrough or an unconditional branch, then scan its predecessor for live + // defs as well. This happens whenever the preheader is created by splitting + // the critical edge from the loop predecessor to the loop header. + if (BB->pred_size() == 1) { + MachineBasicBlock *TBB = 0, *FBB = 0; + SmallVector Cond; + if (!TII->AnalyzeBranch(*BB, TBB, FBB, Cond, false) && Cond.empty()) + InitRegPressure(*BB->pred_begin()); + } + + for (MachineBasicBlock::iterator MII = BB->begin(), E = BB->end(); + MII != E; ++MII) { + MachineInstr *MI = &*MII; + for (unsigned i = 0, e = MI->getDesc().getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + if (!MO.isReg() || MO.isImplicit()) + continue; + unsigned Reg = MO.getReg(); + if (!TargetRegisterInfo::isVirtualRegister(Reg)) + continue; + + bool isNew = RegSeen.insert(Reg); + const TargetRegisterClass *RC = MRI->getRegClass(Reg); + EVT VT = *RC->vt_begin(); + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + if (MO.isDef()) + RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); + else { + bool isKill = isOperandKill(MO, MRI); + if (isNew && !isKill) + // Haven't seen this, it must be a livein. + RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); + else if (!isNew && isKill) + RegPressure[RCId] -= TLI->getRepRegClassCostFor(VT); + } + } + } +} + +/// UpdateRegPressure - Update estimate of register pressure after the +/// specified instruction. +void MachineLICM::UpdateRegPressure(const MachineInstr *MI) { + if (MI->isImplicitDef()) + return; + + SmallVector Defs; + for (unsigned i = 0, e = MI->getDesc().getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + if (!MO.isReg() || MO.isImplicit()) + continue; + unsigned Reg = MO.getReg(); + if (!TargetRegisterInfo::isVirtualRegister(Reg)) + continue; + + bool isNew = RegSeen.insert(Reg); + if (MO.isDef()) + Defs.push_back(Reg); + else if (!isNew && isOperandKill(MO, MRI)) { + const TargetRegisterClass *RC = MRI->getRegClass(Reg); + EVT VT = *RC->vt_begin(); + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + unsigned RCCost = TLI->getRepRegClassCostFor(VT); + + if (RCCost > RegPressure[RCId]) + RegPressure[RCId] = 0; + else + RegPressure[RCId] -= RCCost; + } + } + + while (!Defs.empty()) { + unsigned Reg = Defs.pop_back_val(); + const TargetRegisterClass *RC = MRI->getRegClass(Reg); + EVT VT = *RC->vt_begin(); + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + unsigned RCCost = TLI->getRepRegClassCostFor(VT); + RegPressure[RCId] += RCCost; + } } /// IsLICMCandidate - Returns true if the instruction may be a suitable @@ -535,14 +717,14 @@ bool MachineLICM::IsLoopInvariantInst(MachineInstr &I) { // If the physreg has no defs anywhere, it's just an ambient register // and we can freely move its uses. Alternatively, if it's allocatable, // it could get allocated to something with a def during allocation. - if (!RegInfo->def_empty(Reg)) + if (!MRI->def_empty(Reg)) return false; if (AllocatableSet.test(Reg)) return false; // Check for a def among the register's aliases too. for (const unsigned *Alias = TRI->getAliasSet(Reg); *Alias; ++Alias) { unsigned AliasReg = *Alias; - if (!RegInfo->def_empty(AliasReg)) + if (!MRI->def_empty(AliasReg)) return false; if (AllocatableSet.test(AliasReg)) return false; @@ -562,12 +744,12 @@ bool MachineLICM::IsLoopInvariantInst(MachineInstr &I) { if (!MO.isUse()) continue; - assert(RegInfo->getVRegDef(Reg) && + assert(MRI->getVRegDef(Reg) && "Machine instr not mapped for this vreg?!"); // If the loop contains the definition of an operand, then the instruction // isn't loop invariant. - if (CurLoop->contains(RegInfo->getVRegDef(Reg))) + if (CurLoop->contains(MRI->getVRegDef(Reg))) return false; } @@ -577,9 +759,9 @@ bool MachineLICM::IsLoopInvariantInst(MachineInstr &I) { /// HasPHIUses - Return true if the specified register has any PHI use. -static bool HasPHIUses(unsigned Reg, MachineRegisterInfo *RegInfo) { - for (MachineRegisterInfo::use_iterator UI = RegInfo->use_begin(Reg), - UE = RegInfo->use_end(); UI != UE; ++UI) { +static bool HasPHIUses(unsigned Reg, MachineRegisterInfo *MRI) { + for (MachineRegisterInfo::use_iterator UI = MRI->use_begin(Reg), + UE = MRI->use_end(); UI != UE; ++UI) { MachineInstr *UseMI = &*UI; if (UseMI->isPHI()) return true; @@ -587,37 +769,210 @@ static bool HasPHIUses(unsigned Reg, MachineRegisterInfo *RegInfo) { return false; } -/// isLoadFromConstantMemory - Return true if the given instruction is a -/// load from constant memory. Machine LICM will hoist these even if they are -/// not re-materializable. -bool MachineLICM::isLoadFromConstantMemory(MachineInstr *MI) { - if (!MI->getDesc().mayLoad()) return false; - if (!MI->hasOneMemOperand()) return false; - MachineMemOperand *MMO = *MI->memoperands_begin(); - if (MMO->isVolatile()) return false; - if (!MMO->getValue()) return false; - const PseudoSourceValue *PSV = dyn_cast(MMO->getValue()); - if (PSV) { - MachineFunction &MF = *MI->getParent()->getParent(); - return PSV->isConstant(MF.getFrameInfo()); - } else { - return AA->pointsToConstantMemory(MMO->getValue()); + +/// HasHighOperandLatency - Compute operand latency between a def of 'Reg' +/// and an use in the current loop, return true if the target considered +/// it 'high'. +bool MachineLICM::HasHighOperandLatency(MachineInstr &MI, + unsigned DefIdx, unsigned Reg) const { + if (!InstrItins || InstrItins->isEmpty() || MRI->use_nodbg_empty(Reg)) + return false; + + for (MachineRegisterInfo::use_nodbg_iterator I = MRI->use_nodbg_begin(Reg), + E = MRI->use_nodbg_end(); I != E; ++I) { + MachineInstr *UseMI = &*I; + if (UseMI->isCopyLike()) + continue; + if (!CurLoop->contains(UseMI->getParent())) + continue; + for (unsigned i = 0, e = UseMI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = UseMI->getOperand(i); + if (!MO.isReg() || !MO.isUse()) + continue; + unsigned MOReg = MO.getReg(); + if (MOReg != Reg) + continue; + + if (TII->hasHighOperandLatency(InstrItins, MRI, &MI, DefIdx, UseMI, i)) + return true; + } + + // Only look at the first in loop use. + break; + } + + return false; +} + +/// IsCheapInstruction - Return true if the instruction is marked "cheap" or +/// the operand latency between its def and a use is one or less. +bool MachineLICM::IsCheapInstruction(MachineInstr &MI) const { + if (MI.getDesc().isAsCheapAsAMove() || MI.isCopyLike()) + return true; + if (!InstrItins || InstrItins->isEmpty()) + return false; + + bool isCheap = false; + unsigned NumDefs = MI.getDesc().getNumDefs(); + for (unsigned i = 0, e = MI.getNumOperands(); NumDefs && i != e; ++i) { + MachineOperand &DefMO = MI.getOperand(i); + if (!DefMO.isReg() || !DefMO.isDef()) + continue; + --NumDefs; + unsigned Reg = DefMO.getReg(); + if (TargetRegisterInfo::isPhysicalRegister(Reg)) + continue; + + if (!TII->hasLowDefLatency(InstrItins, &MI, i)) + return false; + isCheap = true; + } + + return isCheap; +} + +/// CanCauseHighRegPressure - Visit BBs from header to current BB, check +/// if hoisting an instruction of the given cost matrix can cause high +/// register pressure. +bool MachineLICM::CanCauseHighRegPressure(DenseMap &Cost) { + for (DenseMap::iterator CI = Cost.begin(), CE = Cost.end(); + CI != CE; ++CI) { + if (CI->second <= 0) + continue; + + unsigned RCId = CI->first; + for (unsigned i = BackTrace.size(); i != 0; --i) { + SmallVector &RP = BackTrace[i-1]; + if (RP[RCId] + CI->second >= RegLimit[RCId]) + return true; + } + } + + return false; +} + +/// UpdateBackTraceRegPressure - Traverse the back trace from header to the +/// current block and update their register pressures to reflect the effect +/// of hoisting MI from the current block to the preheader. +void MachineLICM::UpdateBackTraceRegPressure(const MachineInstr *MI) { + if (MI->isImplicitDef()) + return; + + // First compute the 'cost' of the instruction, i.e. its contribution + // to register pressure. + DenseMap Cost; + for (unsigned i = 0, e = MI->getDesc().getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + if (!MO.isReg() || MO.isImplicit()) + continue; + unsigned Reg = MO.getReg(); + if (!TargetRegisterInfo::isVirtualRegister(Reg)) + continue; + + const TargetRegisterClass *RC = MRI->getRegClass(Reg); + EVT VT = *RC->vt_begin(); + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + unsigned RCCost = TLI->getRepRegClassCostFor(VT); + if (MO.isDef()) { + DenseMap::iterator CI = Cost.find(RCId); + if (CI != Cost.end()) + CI->second += RCCost; + else + Cost.insert(std::make_pair(RCId, RCCost)); + } else if (isOperandKill(MO, MRI)) { + DenseMap::iterator CI = Cost.find(RCId); + if (CI != Cost.end()) + CI->second -= RCCost; + else + Cost.insert(std::make_pair(RCId, -RCCost)); + } + } + + // Update register pressure of blocks from loop header to current block. + for (unsigned i = 0, e = BackTrace.size(); i != e; ++i) { + SmallVector &RP = BackTrace[i]; + for (DenseMap::iterator CI = Cost.begin(), CE = Cost.end(); + CI != CE; ++CI) { + unsigned RCId = CI->first; + RP[RCId] += CI->second; + } } } /// IsProfitableToHoist - Return true if it is potentially profitable to hoist /// the given loop invariant. bool MachineLICM::IsProfitableToHoist(MachineInstr &MI) { - // FIXME: For now, only hoist re-materilizable instructions. LICM will - // increase register pressure. We want to make sure it doesn't increase - // spilling. + if (MI.isImplicitDef()) + return true; + + // If the instruction is cheap, only hoist if it is re-materilizable. LICM + // will increase register pressure. It's probably not worth it if the + // instruction is cheap. // Also hoist loads from constant memory, e.g. load from stubs, GOT. Hoisting // these tend to help performance in low register pressure situation. The // trade off is it may cause spill in high pressure situation. It will end up // adding a store in the loop preheader. But the reload is no more expensive. // The side benefit is these loads are frequently CSE'ed. - if (!TII->isTriviallyReMaterializable(&MI, AA)) { - if (!isLoadFromConstantMemory(&MI)) + if (IsCheapInstruction(MI)) { + if (!TII->isTriviallyReMaterializable(&MI, AA)) + return false; + } else { + // Estimate register pressure to determine whether to LICM the instruction. + // In low register pressure situation, we can be more aggressive about + // hoisting. Also, favors hoisting long latency instructions even in + // moderately high pressure situation. + // FIXME: If there are long latency loop-invariant instructions inside the + // loop at this point, why didn't the optimizer's LICM hoist them? + DenseMap Cost; + for (unsigned i = 0, e = MI.getDesc().getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI.getOperand(i); + if (!MO.isReg() || MO.isImplicit()) + continue; + unsigned Reg = MO.getReg(); + if (!TargetRegisterInfo::isVirtualRegister(Reg)) + continue; + if (MO.isDef()) { + if (HasHighOperandLatency(MI, i, Reg)) { + ++NumHighLatency; + return true; + } + + const TargetRegisterClass *RC = MRI->getRegClass(Reg); + EVT VT = *RC->vt_begin(); + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + unsigned RCCost = TLI->getRepRegClassCostFor(VT); + DenseMap::iterator CI = Cost.find(RCId); + if (CI != Cost.end()) + CI->second += RCCost; + else + Cost.insert(std::make_pair(RCId, RCCost)); + } else if (isOperandKill(MO, MRI)) { + // Is a virtual register use is a kill, hoisting it out of the loop + // may actually reduce register pressure or be register pressure + // neutral. + const TargetRegisterClass *RC = MRI->getRegClass(Reg); + EVT VT = *RC->vt_begin(); + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + unsigned RCCost = TLI->getRepRegClassCostFor(VT); + DenseMap::iterator CI = Cost.find(RCId); + if (CI != Cost.end()) + CI->second -= RCCost; + else + Cost.insert(std::make_pair(RCId, -RCCost)); + } + } + + // Visit BBs from header to current BB, if hoisting this doesn't cause + // high register pressure, then it's safe to proceed. + if (!CanCauseHighRegPressure(Cost)) { + ++NumLowRP; + return true; + } + + // High register pressure situation, only hoist if the instruction is going to + // be remat'ed. + if (!TII->isTriviallyReMaterializable(&MI, AA) && + !MI.isInvariantLoad(AA)) return false; } @@ -628,7 +983,7 @@ bool MachineLICM::IsProfitableToHoist(MachineInstr &MI) { const MachineOperand &MO = MI.getOperand(i); if (!MO.isReg() || !MO.isDef()) continue; - if (HasPHIUses(MO.getReg(), RegInfo)) + if (HasPHIUses(MO.getReg(), MRI)) return false; } @@ -636,10 +991,14 @@ bool MachineLICM::IsProfitableToHoist(MachineInstr &MI) { } MachineInstr *MachineLICM::ExtractHoistableLoad(MachineInstr *MI) { + // Don't unfold simple loads. + if (MI->getDesc().canFoldAsLoad()) + return 0; + // If not, we may be able to unfold a load and hoist that. // First test whether the instruction is loading from an amenable // memory location. - if (!isLoadFromConstantMemory(MI)) + if (!MI->isInvariantLoad(AA)) return 0; // Next determine the register class for a temporary register. @@ -654,7 +1013,7 @@ MachineInstr *MachineLICM::ExtractHoistableLoad(MachineInstr *MI) { if (TID.getNumDefs() != 1) return 0; const TargetRegisterClass *RC = TID.OpInfo[LoadRegIndex].getRegClass(TRI); // Ok, we're unfolding. Create a temporary register and do the unfold. - unsigned Reg = RegInfo->createVirtualRegister(RC); + unsigned Reg = MRI->createVirtualRegister(RC); MachineFunction &MF = *MI->getParent()->getParent(); SmallVector NewMIs; @@ -678,6 +1037,10 @@ MachineInstr *MachineLICM::ExtractHoistableLoad(MachineInstr *MI) { NewMIs[1]->eraseFromParent(); return 0; } + + // Update register pressure for the unfolded instruction. + UpdateRegPressure(NewMIs[1]); + // Otherwise we successfully unfolded a load that we can hoist. MI->eraseFromParent(); return NewMIs[0]; @@ -686,20 +1049,15 @@ MachineInstr *MachineLICM::ExtractHoistableLoad(MachineInstr *MI) { void MachineLICM::InitCSEMap(MachineBasicBlock *BB) { for (MachineBasicBlock::iterator I = BB->begin(),E = BB->end(); I != E; ++I) { const MachineInstr *MI = &*I; - // FIXME: For now, only hoist re-materilizable instructions. LICM will - // increase register pressure. We want to make sure it doesn't increase - // spilling. - if (TII->isTriviallyReMaterializable(MI, AA)) { - unsigned Opcode = MI->getOpcode(); - DenseMap >::iterator - CI = CSEMap.find(Opcode); - if (CI != CSEMap.end()) - CI->second.push_back(MI); - else { - std::vector CSEMIs; - CSEMIs.push_back(MI); - CSEMap.insert(std::make_pair(Opcode, CSEMIs)); - } + unsigned Opcode = MI->getOpcode(); + DenseMap >::iterator + CI = CSEMap.find(Opcode); + if (CI != CSEMap.end()) + CI->second.push_back(MI); + else { + std::vector CSEMIs; + CSEMIs.push_back(MI); + CSEMap.insert(std::make_pair(Opcode, CSEMIs)); } } } @@ -709,7 +1067,7 @@ MachineLICM::LookForDuplicate(const MachineInstr *MI, std::vector &PrevMIs) { for (unsigned i = 0, e = PrevMIs.size(); i != e; ++i) { const MachineInstr *PrevMI = PrevMIs[i]; - if (TII->produceSameValue(MI, PrevMI)) + if (TII->produceSameValue(MI, PrevMI, (PreRegAlloc ? MRI : 0))) return PrevMI; } return 0; @@ -738,8 +1096,8 @@ bool MachineLICM::EliminateCSE(MachineInstr *MI, if (MO.isReg() && MO.isDef() && !TargetRegisterInfo::isPhysicalRegister(MO.getReg())) { - RegInfo->replaceRegWith(MO.getReg(), Dup->getOperand(i).getReg()); - RegInfo->clearKillFlags(Dup->getOperand(i).getReg()); + MRI->replaceRegWith(MO.getReg(), Dup->getOperand(i).getReg()); + MRI->clearKillFlags(Dup->getOperand(i).getReg()); } } MI->eraseFromParent(); @@ -752,15 +1110,12 @@ bool MachineLICM::EliminateCSE(MachineInstr *MI, /// Hoist - When an instruction is found to use only loop invariant operands /// that are safe to hoist, this instruction is called to do the dirty work. /// -void MachineLICM::Hoist(MachineInstr *MI) { - MachineBasicBlock *Preheader = getCurPreheader(); - if (!Preheader) return; - +bool MachineLICM::Hoist(MachineInstr *MI, MachineBasicBlock *Preheader) { // First check whether we should hoist this instruction. if (!IsLoopInvariantInst(*MI) || !IsProfitableToHoist(*MI)) { // If not, try unfolding a hoistable load. MI = ExtractHoistableLoad(MI); - if (!MI) return; + if (!MI) return false; } // Now move the instructions to the predecessor, inserting it before any @@ -791,13 +1146,16 @@ void MachineLICM::Hoist(MachineInstr *MI) { // Otherwise, splice the instruction to the preheader. Preheader->splice(Preheader->getFirstTerminator(),MI->getParent(),MI); + // Update register pressure for BBs from header to this block. + UpdateBackTraceRegPressure(MI); + // Clear the kill flags of any register this instruction defines, // since they may need to be live throughout the entire loop // rather than just live for part of it. for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { MachineOperand &MO = MI->getOperand(i); if (MO.isReg() && MO.isDef() && !MO.isDead()) - RegInfo->clearKillFlags(MO.getReg()); + MRI->clearKillFlags(MO.getReg()); } // Add to the CSE map. @@ -812,6 +1170,8 @@ void MachineLICM::Hoist(MachineInstr *MI) { ++NumHoisted; Changed = true; + + return true; } MachineBasicBlock *MachineLICM::getCurPreheader() { diff --git a/lib/CodeGen/MachineLoopInfo.cpp b/lib/CodeGen/MachineLoopInfo.cpp index bca4b0c28985..189cb2ba5d1d 100644 --- a/lib/CodeGen/MachineLoopInfo.cpp +++ b/lib/CodeGen/MachineLoopInfo.cpp @@ -30,8 +30,11 @@ TEMPLATE_INSTANTIATION(MLIB); } char MachineLoopInfo::ID = 0; -INITIALIZE_PASS(MachineLoopInfo, "machine-loops", - "Machine Natural Loop Construction", true, true); +INITIALIZE_PASS_BEGIN(MachineLoopInfo, "machine-loops", + "Machine Natural Loop Construction", true, true) +INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree) +INITIALIZE_PASS_END(MachineLoopInfo, "machine-loops", + "Machine Natural Loop Construction", true, true) char &llvm::MachineLoopInfoID = MachineLoopInfo::ID; diff --git a/lib/CodeGen/MachineLoopRanges.cpp b/lib/CodeGen/MachineLoopRanges.cpp new file mode 100644 index 000000000000..17fe67f65045 --- /dev/null +++ b/lib/CodeGen/MachineLoopRanges.cpp @@ -0,0 +1,116 @@ +//===- MachineLoopRanges.cpp - Ranges of machine loops --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the implementation of the MachineLoopRanges analysis. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/MachineLoopRanges.h" +#include "llvm/CodeGen/MachineLoopInfo.h" +#include "llvm/CodeGen/Passes.h" + +using namespace llvm; + +char MachineLoopRanges::ID = 0; +INITIALIZE_PASS_BEGIN(MachineLoopRanges, "machine-loop-ranges", + "Machine Loop Ranges", true, true) +INITIALIZE_PASS_DEPENDENCY(SlotIndexes) +INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo) +INITIALIZE_PASS_END(MachineLoopRanges, "machine-loop-ranges", + "Machine Loop Ranges", true, true) + +char &llvm::MachineLoopRangesID = MachineLoopRanges::ID; + +void MachineLoopRanges::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + AU.addRequiredTransitive(); + AU.addRequiredTransitive(); + MachineFunctionPass::getAnalysisUsage(AU); +} + +/// runOnMachineFunction - Don't do much, loop ranges are computed on demand. +bool MachineLoopRanges::runOnMachineFunction(MachineFunction &) { + releaseMemory(); + Indexes = &getAnalysis(); + return false; +} + +void MachineLoopRanges::releaseMemory() { + DeleteContainerSeconds(Cache); + Cache.clear(); +} + +MachineLoopRange *MachineLoopRanges::getLoopRange(const MachineLoop *Loop) { + MachineLoopRange *&Range = Cache[Loop]; + if (!Range) + Range = new MachineLoopRange(Loop, Allocator, *Indexes); + return Range; +} + +/// Create a MachineLoopRange, only accessible to MachineLoopRanges. +MachineLoopRange::MachineLoopRange(const MachineLoop *loop, + MachineLoopRange::Allocator &alloc, + SlotIndexes &Indexes) + : Loop(loop), Intervals(alloc), Area(0) { + // Compute loop coverage. + for (MachineLoop::block_iterator I = Loop->block_begin(), + E = Loop->block_end(); I != E; ++I) { + const std::pair &Range = Indexes.getMBBRange(*I); + Intervals.insert(Range.first, Range.second, 1u); + Area += Range.first.distance(Range.second); + } +} + +/// overlaps - Return true if this loop overlaps the given range of machine +/// instructions. +bool MachineLoopRange::overlaps(SlotIndex Start, SlotIndex Stop) { + Map::const_iterator I = Intervals.find(Start); + return I.valid() && Stop > I.start(); +} + +unsigned MachineLoopRange::getNumber() const { + return Loop->getHeader()->getNumber(); +} + +/// byNumber - Comparator for array_pod_sort that sorts a list of +/// MachineLoopRange pointers by number. +int MachineLoopRange::byNumber(const void *pa, const void *pb) { + const MachineLoopRange *a = *static_cast(pa); + const MachineLoopRange *b = *static_cast(pb); + unsigned na = a->getNumber(); + unsigned nb = b->getNumber(); + if (na < nb) + return -1; + if (na > nb) + return 1; + return 0; +} + +/// byAreaDesc - Comparator for array_pod_sort that sorts a list of +/// MachineLoopRange pointers by: +/// 1. Descending area. +/// 2. Ascending number. +int MachineLoopRange::byAreaDesc(const void *pa, const void *pb) { + const MachineLoopRange *a = *static_cast(pa); + const MachineLoopRange *b = *static_cast(pb); + if (a->getArea() != b->getArea()) + return a->getArea() > b->getArea() ? -1 : 1; + return byNumber(pa, pb); +} + +void MachineLoopRange::print(raw_ostream &OS) const { + OS << "Loop#" << getNumber() << " ="; + for (Map::const_iterator I = Intervals.begin(); I.valid(); ++I) + OS << " [" << I.start() << ';' << I.stop() << ')'; +} + +raw_ostream &llvm::operator<<(raw_ostream &OS, const MachineLoopRange &MLR) { + MLR.print(OS); + return OS; +} diff --git a/lib/CodeGen/MachineModuleInfo.cpp b/lib/CodeGen/MachineModuleInfo.cpp index b647a4dcc530..fadc594efcb2 100644 --- a/lib/CodeGen/MachineModuleInfo.cpp +++ b/lib/CodeGen/MachineModuleInfo.cpp @@ -29,7 +29,7 @@ using namespace llvm::dwarf; // Handle the Pass registration stuff necessary to use TargetData's. INITIALIZE_PASS(MachineModuleInfo, "machinemoduleinfo", - "Machine Module Information", false, false); + "Machine Module Information", false, false) char MachineModuleInfo::ID = 0; // Out of line virtual method. @@ -41,30 +41,30 @@ class MMIAddrLabelMapCallbackPtr : CallbackVH { public: MMIAddrLabelMapCallbackPtr() : Map(0) {} MMIAddrLabelMapCallbackPtr(Value *V) : CallbackVH(V), Map(0) {} - + void setPtr(BasicBlock *BB) { ValueHandleBase::operator=(BB); } - + void setMap(MMIAddrLabelMap *map) { Map = map; } - + virtual void deleted(); virtual void allUsesReplacedWith(Value *V2); }; - + class MMIAddrLabelMap { MCContext &Context; struct AddrLabelSymEntry { /// Symbols - The symbols for the label. This is a pointer union that is /// either one symbol (the common case) or a list of symbols. PointerUnion*> Symbols; - + Function *Fn; // The containing function of the BasicBlock. unsigned Index; // The index in BBCallbacks for the BasicBlock. }; - + DenseMap, AddrLabelSymEntry> AddrLabelSymbols; - + /// BBCallbacks - Callbacks for the BasicBlock's that we have entries for. We /// use this so we get notified if a block is deleted or RAUWd. std::vector BBCallbacks; @@ -76,23 +76,23 @@ class MMIAddrLabelMap { DenseMap, std::vector > DeletedAddrLabelsNeedingEmission; public: - + MMIAddrLabelMap(MCContext &context) : Context(context) {} ~MMIAddrLabelMap() { assert(DeletedAddrLabelsNeedingEmission.empty() && "Some labels for deleted blocks never got emitted"); - + // Deallocate any of the 'list of symbols' case. for (DenseMap, AddrLabelSymEntry>::iterator I = AddrLabelSymbols.begin(), E = AddrLabelSymbols.end(); I != E; ++I) if (I->second.Symbols.is*>()) delete I->second.Symbols.get*>(); } - + MCSymbol *getAddrLabelSymbol(BasicBlock *BB); std::vector getAddrLabelSymbolToEmit(BasicBlock *BB); - void takeDeletedSymbolsForFunction(Function *F, + void takeDeletedSymbolsForFunction(Function *F, std::vector &Result); void UpdateForDeletedBlock(BasicBlock *BB); @@ -104,7 +104,7 @@ MCSymbol *MMIAddrLabelMap::getAddrLabelSymbol(BasicBlock *BB) { assert(BB->hasAddressTaken() && "Shouldn't get label for block without address taken"); AddrLabelSymEntry &Entry = AddrLabelSymbols[BB]; - + // If we already had an entry for this block, just return it. if (!Entry.Symbols.isNull()) { assert(BB->getParent() == Entry.Fn && "Parent changed"); @@ -112,7 +112,7 @@ MCSymbol *MMIAddrLabelMap::getAddrLabelSymbol(BasicBlock *BB) { return Entry.Symbols.get(); return (*Entry.Symbols.get*>())[0]; } - + // Otherwise, this is a new entry, create a new symbol for it and add an // entry to BBCallbacks so we can be notified if the BB is deleted or RAUWd. BBCallbacks.push_back(BB); @@ -129,9 +129,9 @@ MMIAddrLabelMap::getAddrLabelSymbolToEmit(BasicBlock *BB) { assert(BB->hasAddressTaken() && "Shouldn't get label for block without address taken"); AddrLabelSymEntry &Entry = AddrLabelSymbols[BB]; - + std::vector Result; - + // If we already had an entry for this block, just return it. if (Entry.Symbols.isNull()) Result.push_back(getAddrLabelSymbol(BB)); @@ -152,7 +152,7 @@ takeDeletedSymbolsForFunction(Function *F, std::vector &Result) { // If there are no entries for the function, just return. if (I == DeletedAddrLabelsNeedingEmission.end()) return; - + // Otherwise, take the list. std::swap(Result, I->second); DeletedAddrLabelsNeedingEmission.erase(I); @@ -175,7 +175,7 @@ void MMIAddrLabelMap::UpdateForDeletedBlock(BasicBlock *BB) { if (MCSymbol *Sym = Entry.Symbols.dyn_cast()) { if (Sym->isDefined()) return; - + // If the block is not yet defined, we need to emit it at the end of the // function. Add the symbol to the DeletedAddrLabelsNeedingEmission list // for the containing Function. Since the block is being deleted, its @@ -187,7 +187,7 @@ void MMIAddrLabelMap::UpdateForDeletedBlock(BasicBlock *BB) { for (unsigned i = 0, e = Syms->size(); i != e; ++i) { MCSymbol *Sym = (*Syms)[i]; if (Sym->isDefined()) continue; // Ignore already emitted labels. - + // If the block is not yet defined, we need to emit it at the end of the // function. Add the symbol to the DeletedAddrLabelsNeedingEmission list // for the containing Function. Since the block is being deleted, its @@ -195,7 +195,7 @@ void MMIAddrLabelMap::UpdateForDeletedBlock(BasicBlock *BB) { // 'Entry'. DeletedAddrLabelsNeedingEmission[Entry.Fn].push_back(Sym); } - + // The entry is deleted, free the memory associated with the symbol list. delete Syms; } @@ -225,7 +225,7 @@ void MMIAddrLabelMap::UpdateForRAUWBlock(BasicBlock *Old, BasicBlock *New) { SymList->push_back(PrevSym); NewEntry.Symbols = SymList; } - + std::vector *SymList = NewEntry.Symbols.get*>(); @@ -234,7 +234,7 @@ void MMIAddrLabelMap::UpdateForRAUWBlock(BasicBlock *Old, BasicBlock *New) { SymList->push_back(Sym); return; } - + // Otherwise, concatenate the list. std::vector *Syms =OldEntry.Symbols.get*>(); SymList->insert(SymList->end(), Syms->begin(), Syms->end()); @@ -253,10 +253,13 @@ void MMIAddrLabelMapCallbackPtr::allUsesReplacedWith(Value *V2) { //===----------------------------------------------------------------------===// -MachineModuleInfo::MachineModuleInfo(const MCAsmInfo &MAI) -: ImmutablePass(ID), Context(MAI), +MachineModuleInfo::MachineModuleInfo(const MCAsmInfo &MAI, + const TargetAsmInfo *TAI) +: ImmutablePass(ID), Context(MAI, TAI), ObjFileMMI(0), - CurCallSite(0), CallsEHReturn(0), CallsUnwindInit(0), DbgInfoAvailable(false){ + CurCallSite(0), CallsEHReturn(0), CallsUnwindInit(0), DbgInfoAvailable(false), + CallsExternalVAFunctionWithFloatingPointArguments(false) { + initializeMachineModuleInfoPass(*PassRegistry::getPassRegistry()); // Always emit some info, by default "no personality" info. Personalities.push_back(NULL); AddrLabelSymbols = 0; @@ -264,7 +267,7 @@ MachineModuleInfo::MachineModuleInfo(const MCAsmInfo &MAI) } MachineModuleInfo::MachineModuleInfo() -: ImmutablePass(ID), Context(*(MCAsmInfo*)0) { +: ImmutablePass(ID), Context(*(MCAsmInfo*)0, NULL) { assert(0 && "This MachineModuleInfo constructor should never be called, MMI " "should always be explicitly constructed by LLVMTargetMachine"); abort(); @@ -272,7 +275,7 @@ MachineModuleInfo::MachineModuleInfo() MachineModuleInfo::~MachineModuleInfo() { delete ObjFileMMI; - + // FIXME: Why isn't doFinalization being called?? //assert(AddrLabelSymbols == 0 && "doFinalization not called"); delete AddrLabelSymbols; @@ -472,7 +475,7 @@ void MachineModuleInfo::TidyLandingPads(DenseMap *LPMap) { (LPMap && (*LPMap)[BeginLabel] != 0)) && (EndLabel->isDefined() || (LPMap && (*LPMap)[EndLabel] != 0))) continue; - + LandingPad.BeginLabels.erase(LandingPad.BeginLabels.begin() + j); LandingPad.EndLabels.erase(LandingPad.EndLabels.begin() + j); --j, --e; @@ -562,20 +565,3 @@ unsigned MachineModuleInfo::getPersonalityIndex() const { // in the zero index. return 0; } - -namespace { - /// VariableDebugSorter - Comparison to sort the VariableDbgInfo map - /// by source location, to avoid depending on the arbitrary order that - /// instruction selection visits variables in. - struct VariableDebugSorter { - bool operator()(const MachineModuleInfo::VariableDbgInfoMapTy::value_type &A, - const MachineModuleInfo::VariableDbgInfoMapTy::value_type &B) - const { - if (A.second.second.getLine() != B.second.second.getLine()) - return A.second.second.getLine() < B.second.second.getLine(); - if (A.second.second.getCol() != B.second.second.getCol()) - return A.second.second.getCol() < B.second.second.getCol(); - return false; - } - }; -} diff --git a/lib/CodeGen/MachineRegisterInfo.cpp b/lib/CodeGen/MachineRegisterInfo.cpp index 5d852f26beda..b3fb33736ffc 100644 --- a/lib/CodeGen/MachineRegisterInfo.cpp +++ b/lib/CodeGen/MachineRegisterInfo.cpp @@ -30,8 +30,9 @@ MachineRegisterInfo::MachineRegisterInfo(const TargetRegisterInfo &TRI) { MachineRegisterInfo::~MachineRegisterInfo() { #ifndef NDEBUG - for (unsigned i = 0, e = VRegInfo.size(); i != e; ++i) - assert(VRegInfo[i].second == 0 && "Vreg use list non-empty still?"); + for (unsigned i = 0, e = getNumVirtRegs(); i != e; ++i) + assert(VRegInfo[TargetRegisterInfo::index2VirtReg(i)].second == 0 && + "Vreg use list non-empty still?"); for (unsigned i = 0, e = UsedPhysRegs.size(); i != e; ++i) assert(!PhysRegUseDefLists[i] && "PhysRegUseDefLists has entries after all instructions are deleted"); @@ -44,20 +45,32 @@ MachineRegisterInfo::~MachineRegisterInfo() { /// void MachineRegisterInfo::setRegClass(unsigned Reg, const TargetRegisterClass *RC) { - unsigned VR = Reg; - Reg -= TargetRegisterInfo::FirstVirtualRegister; - assert(Reg < VRegInfo.size() && "Invalid vreg!"); const TargetRegisterClass *OldRC = VRegInfo[Reg].first; VRegInfo[Reg].first = RC; // Remove from old register class's vregs list. This may be slow but // fortunately this operation is rarely needed. std::vector &VRegs = RegClass2VRegMap[OldRC->getID()]; - std::vector::iterator I = std::find(VRegs.begin(), VRegs.end(), VR); + std::vector::iterator I = + std::find(VRegs.begin(), VRegs.end(), Reg); VRegs.erase(I); // Add to new register class's vregs list. - RegClass2VRegMap[RC->getID()].push_back(VR); + RegClass2VRegMap[RC->getID()].push_back(Reg); +} + +const TargetRegisterClass * +MachineRegisterInfo::constrainRegClass(unsigned Reg, + const TargetRegisterClass *RC) { + const TargetRegisterClass *OldRC = getRegClass(Reg); + if (OldRC == RC) + return RC; + const TargetRegisterClass *NewRC = getCommonSubClass(OldRC, RC); + if (!NewRC) + return 0; + if (NewRC != OldRC) + setRegClass(Reg, NewRC); + return NewRC; } /// createVirtualRegister - Create and return a new virtual register in the @@ -66,17 +79,22 @@ MachineRegisterInfo::setRegClass(unsigned Reg, const TargetRegisterClass *RC) { unsigned MachineRegisterInfo::createVirtualRegister(const TargetRegisterClass *RegClass){ assert(RegClass && "Cannot create register without RegClass!"); + + // New virtual register number. + unsigned Reg = TargetRegisterInfo::index2VirtReg(getNumVirtRegs()); + // Add a reg, but keep track of whether the vector reallocated or not. - void *ArrayBase = VRegInfo.empty() ? 0 : &VRegInfo[0]; - VRegInfo.push_back(std::make_pair(RegClass, (MachineOperand*)0)); - RegAllocHints.push_back(std::make_pair(0, 0)); + const unsigned FirstVirtReg = TargetRegisterInfo::index2VirtReg(0); + void *ArrayBase = getNumVirtRegs() == 0 ? 0 : &VRegInfo[FirstVirtReg]; + VRegInfo.grow(Reg); + VRegInfo[Reg].first = RegClass; + RegAllocHints.grow(Reg); - if (!((&VRegInfo[0] == ArrayBase || VRegInfo.size() == 1))) + if (ArrayBase && &VRegInfo[FirstVirtReg] != ArrayBase) // The vector reallocated, handle this now. HandleVRegListReallocation(); - unsigned VR = getLastVirtReg(); - RegClass2VRegMap[RegClass->getID()].push_back(VR); - return VR; + RegClass2VRegMap[RegClass->getID()].push_back(Reg); + return Reg; } /// HandleVRegListReallocation - We just added a virtual register to the @@ -85,11 +103,12 @@ MachineRegisterInfo::createVirtualRegister(const TargetRegisterClass *RegClass){ void MachineRegisterInfo::HandleVRegListReallocation() { // The back pointers for the vreg lists point into the previous vector. // Update them to point to their correct slots. - for (unsigned i = 0, e = VRegInfo.size(); i != e; ++i) { - MachineOperand *List = VRegInfo[i].second; + for (unsigned i = 0, e = getNumVirtRegs(); i != e; ++i) { + unsigned Reg = TargetRegisterInfo::index2VirtReg(i); + MachineOperand *List = VRegInfo[Reg].second; if (!List) continue; // Update the back-pointer to be accurate once more. - List->Contents.Reg.Prev = &VRegInfo[i].second; + List->Contents.Reg.Prev = &VRegInfo[Reg].second; } } @@ -112,8 +131,6 @@ void MachineRegisterInfo::replaceRegWith(unsigned FromReg, unsigned ToReg) { /// register or null if none is found. This assumes that the code is in SSA /// form, so there should only be one definition. MachineInstr *MachineRegisterInfo::getVRegDef(unsigned Reg) const { - assert(Reg-TargetRegisterInfo::FirstVirtualRegister < VRegInfo.size() && - "Invalid vreg!"); // Since we are in SSA form, we can use the first definition. if (!def_empty(Reg)) return &*def_begin(Reg); @@ -193,8 +210,15 @@ MachineRegisterInfo::EmitLiveInCopies(MachineBasicBlock *EntryMBB, LiveIns.erase(LiveIns.begin() + i); --i; --e; } else { + DebugLoc DL; + // If there is a location for this live in then use it. + DenseMap::iterator DLI = + LiveInLocs.find(LiveIns[i].second); + if (DLI != LiveInLocs.end()) + DL = DLI->second; + // Emit a copy. - BuildMI(*EntryMBB, EntryMBB->begin(), DebugLoc(), + BuildMI(*EntryMBB, EntryMBB->begin(), DL, TII.get(TargetOpcode::COPY), LiveIns[i].second) .addReg(LiveIns[i].first); diff --git a/lib/CodeGen/MachineSink.cpp b/lib/CodeGen/MachineSink.cpp index c8f8fafe227e..8a93a24287b6 100644 --- a/lib/CodeGen/MachineSink.cpp +++ b/lib/CodeGen/MachineSink.cpp @@ -25,6 +25,7 @@ #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -34,27 +35,31 @@ using namespace llvm; static cl::opt SplitEdges("machine-sink-split", cl::desc("Split critical edges during machine sinking"), - cl::init(false), cl::Hidden); -static cl::opt -SplitLimit("split-limit", - cl::init(~0u), cl::Hidden); + cl::init(true), cl::Hidden); -STATISTIC(NumSunk, "Number of machine instructions sunk"); -STATISTIC(NumSplit, "Number of critical edges split"); +STATISTIC(NumSunk, "Number of machine instructions sunk"); +STATISTIC(NumSplit, "Number of critical edges split"); +STATISTIC(NumCoalesces, "Number of copies coalesced"); namespace { class MachineSinking : public MachineFunctionPass { const TargetInstrInfo *TII; const TargetRegisterInfo *TRI; - MachineRegisterInfo *RegInfo; // Machine register information + MachineRegisterInfo *MRI; // Machine register information MachineDominatorTree *DT; // Machine dominator tree MachineLoopInfo *LI; AliasAnalysis *AA; BitVector AllocatableSet; // Which physregs are allocatable? + // Remember which edges have been considered for breaking. + SmallSet, 8> + CEBCandidates; + public: static char ID; // Pass identification - MachineSinking() : MachineFunctionPass(ID) {} + MachineSinking() : MachineFunctionPass(ID) { + initializeMachineSinkingPass(*PassRegistry::getPassRegistry()); + } virtual bool runOnMachineFunction(MachineFunction &MF); @@ -67,43 +72,125 @@ namespace { AU.addPreserved(); AU.addPreserved(); } + + virtual void releaseMemory() { + CEBCandidates.clear(); + } + private: bool ProcessBlock(MachineBasicBlock &MBB); - MachineBasicBlock *SplitCriticalEdge(MachineBasicBlock *From, - MachineBasicBlock *To); + bool isWorthBreakingCriticalEdge(MachineInstr *MI, + MachineBasicBlock *From, + MachineBasicBlock *To); + MachineBasicBlock *SplitCriticalEdge(MachineInstr *MI, + MachineBasicBlock *From, + MachineBasicBlock *To, + bool BreakPHIEdge); bool SinkInstruction(MachineInstr *MI, bool &SawStore); bool AllUsesDominatedByBlock(unsigned Reg, MachineBasicBlock *MBB, - MachineBasicBlock *DefMBB, bool &LocalUse) const; + MachineBasicBlock *DefMBB, + bool &BreakPHIEdge, bool &LocalUse) const; + bool PerformTrivialForwardCoalescing(MachineInstr *MI, + MachineBasicBlock *MBB); }; } // end anonymous namespace char MachineSinking::ID = 0; -INITIALIZE_PASS(MachineSinking, "machine-sink", - "Machine code sinking", false, false); +INITIALIZE_PASS_BEGIN(MachineSinking, "machine-sink", + "Machine code sinking", false, false) +INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree) +INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo) +INITIALIZE_AG_DEPENDENCY(AliasAnalysis) +INITIALIZE_PASS_END(MachineSinking, "machine-sink", + "Machine code sinking", false, false) FunctionPass *llvm::createMachineSinkingPass() { return new MachineSinking(); } +bool MachineSinking::PerformTrivialForwardCoalescing(MachineInstr *MI, + MachineBasicBlock *MBB) { + if (!MI->isCopy()) + return false; + + unsigned SrcReg = MI->getOperand(1).getReg(); + unsigned DstReg = MI->getOperand(0).getReg(); + if (!TargetRegisterInfo::isVirtualRegister(SrcReg) || + !TargetRegisterInfo::isVirtualRegister(DstReg) || + !MRI->hasOneNonDBGUse(SrcReg)) + return false; + + const TargetRegisterClass *SRC = MRI->getRegClass(SrcReg); + const TargetRegisterClass *DRC = MRI->getRegClass(DstReg); + if (SRC != DRC) + return false; + + MachineInstr *DefMI = MRI->getVRegDef(SrcReg); + if (DefMI->isCopyLike()) + return false; + DEBUG(dbgs() << "Coalescing: " << *DefMI); + DEBUG(dbgs() << "*** to: " << *MI); + MRI->replaceRegWith(DstReg, SrcReg); + MI->eraseFromParent(); + ++NumCoalesces; + return true; +} + /// AllUsesDominatedByBlock - Return true if all uses of the specified register /// occur in blocks dominated by the specified block. If any use is in the /// definition block, then return false since it is never legal to move def /// after uses. -bool MachineSinking::AllUsesDominatedByBlock(unsigned Reg, - MachineBasicBlock *MBB, - MachineBasicBlock *DefMBB, - bool &LocalUse) const { +bool +MachineSinking::AllUsesDominatedByBlock(unsigned Reg, + MachineBasicBlock *MBB, + MachineBasicBlock *DefMBB, + bool &BreakPHIEdge, + bool &LocalUse) const { assert(TargetRegisterInfo::isVirtualRegister(Reg) && "Only makes sense for vregs"); + + if (MRI->use_nodbg_empty(Reg)) + return true; + // Ignoring debug uses is necessary so debug info doesn't affect the code. // This may leave a referencing dbg_value in the original block, before // the definition of the vreg. Dwarf generator handles this although the // user might not get the right info at runtime. + + // BreakPHIEdge is true if all the uses are in the successor MBB being sunken + // into and they are all PHI nodes. In this case, machine-sink must break + // the critical edge first. e.g. + // + // BB#1: derived from LLVM BB %bb4.preheader + // Predecessors according to CFG: BB#0 + // ... + // %reg16385 = DEC64_32r %reg16437, %EFLAGS + // ... + // JE_4 , %EFLAGS + // Successors according to CFG: BB#37 BB#2 + // + // BB#2: derived from LLVM BB %bb.nph + // Predecessors according to CFG: BB#0 BB#1 + // %reg16386 = PHI %reg16434, , %reg16385, + BreakPHIEdge = true; for (MachineRegisterInfo::use_nodbg_iterator - I = RegInfo->use_nodbg_begin(Reg), E = RegInfo->use_nodbg_end(); + I = MRI->use_nodbg_begin(Reg), E = MRI->use_nodbg_end(); I != E; ++I) { - // Determine the block of the use. MachineInstr *UseInst = &*I; MachineBasicBlock *UseBlock = UseInst->getParent(); + if (!(UseBlock == MBB && UseInst->isPHI() && + UseInst->getOperand(I.getOperandNo()+1).getMBB() == DefMBB)) { + BreakPHIEdge = false; + break; + } + } + if (BreakPHIEdge) + return true; + for (MachineRegisterInfo::use_nodbg_iterator + I = MRI->use_nodbg_begin(Reg), E = MRI->use_nodbg_end(); + I != E; ++I) { + // Determine the block of the use. + MachineInstr *UseInst = &*I; + MachineBasicBlock *UseBlock = UseInst->getParent(); if (UseInst->isPHI()) { // PHI nodes use the operand in the predecessor block, not the block with // the PHI. @@ -127,7 +214,7 @@ bool MachineSinking::runOnMachineFunction(MachineFunction &MF) { const TargetMachine &TM = MF.getTarget(); TII = TM.getInstrInfo(); TRI = TM.getRegisterInfo(); - RegInfo = &MF.getRegInfo(); + MRI = &MF.getRegInfo(); DT = &getAnalysis(); LI = &getAnalysis(); AA = &getAnalysis(); @@ -139,6 +226,7 @@ bool MachineSinking::runOnMachineFunction(MachineFunction &MF) { bool MadeChange = false; // Process all basic blocks. + CEBCandidates.clear(); for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) MadeChange |= ProcessBlock(*I); @@ -177,6 +265,9 @@ bool MachineSinking::ProcessBlock(MachineBasicBlock &MBB) { if (MI->isDebugValue()) continue; + if (PerformTrivialForwardCoalescing(MI, &MBB)) + continue; + if (SinkInstruction(MI, SawStore)) ++NumSunk, MadeChange = true; @@ -186,51 +277,92 @@ bool MachineSinking::ProcessBlock(MachineBasicBlock &MBB) { return MadeChange; } -MachineBasicBlock *MachineSinking::SplitCriticalEdge(MachineBasicBlock *FromBB, - MachineBasicBlock *ToBB) { +bool MachineSinking::isWorthBreakingCriticalEdge(MachineInstr *MI, + MachineBasicBlock *From, + MachineBasicBlock *To) { + // FIXME: Need much better heuristics. + + // If the pass has already considered breaking this edge (during this pass + // through the function), then let's go ahead and break it. This means + // sinking multiple "cheap" instructions into the same block. + if (!CEBCandidates.insert(std::make_pair(From, To))) + return true; + + if (!MI->isCopy() && !MI->getDesc().isAsCheapAsAMove()) + return true; + + // MI is cheap, we probably don't want to break the critical edge for it. + // However, if this would allow some definitions of its source operands + // to be sunk then it's probably worth it. + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + if (!MO.isReg()) continue; + unsigned Reg = MO.getReg(); + if (Reg == 0 || !TargetRegisterInfo::isPhysicalRegister(Reg)) + continue; + if (MRI->hasOneNonDBGUse(Reg)) + return true; + } + + return false; +} + +MachineBasicBlock *MachineSinking::SplitCriticalEdge(MachineInstr *MI, + MachineBasicBlock *FromBB, + MachineBasicBlock *ToBB, + bool BreakPHIEdge) { + if (!isWorthBreakingCriticalEdge(MI, FromBB, ToBB)) + return 0; + // Avoid breaking back edge. From == To means backedge for single BB loop. - if (!SplitEdges || NumSplit == SplitLimit || FromBB == ToBB) + if (!SplitEdges || FromBB == ToBB) + return 0; + + // Check for backedges of more "complex" loops. + if (LI->getLoopFor(FromBB) == LI->getLoopFor(ToBB) && + LI->isLoopHeader(ToBB)) return 0; - // Check for more "complex" loops. - if (LI->getLoopFor(FromBB) != LI->getLoopFor(ToBB) || - !LI->isLoopHeader(ToBB)) { - // It's not always legal to break critical edges and sink the computation - // to the edge. - // - // BB#1: - // v1024 - // Beq BB#3 - // - // BB#2: - // ... no uses of v1024 - // - // BB#3: - // ... - // = v1024 - // - // If BB#1 -> BB#3 edge is broken and computation of v1024 is inserted: - // - // BB#1: - // ... - // Bne BB#2 - // BB#4: - // v1024 = - // B BB#3 - // BB#2: - // ... no uses of v1024 - // - // BB#3: - // ... - // = v1024 - // - // This is incorrect since v1024 is not computed along the BB#1->BB#2->BB#3 - // flow. We need to ensure the new basic block where the computation is - // sunk to dominates all the uses. - // It's only legal to break critical edge and sink the computation to the - // new block if all the predecessors of "To", except for "From", are - // not dominated by "From". Given SSA property, this means these - // predecessors are dominated by "To". + // It's not always legal to break critical edges and sink the computation + // to the edge. + // + // BB#1: + // v1024 + // Beq BB#3 + // + // BB#2: + // ... no uses of v1024 + // + // BB#3: + // ... + // = v1024 + // + // If BB#1 -> BB#3 edge is broken and computation of v1024 is inserted: + // + // BB#1: + // ... + // Bne BB#2 + // BB#4: + // v1024 = + // B BB#3 + // BB#2: + // ... no uses of v1024 + // + // BB#3: + // ... + // = v1024 + // + // This is incorrect since v1024 is not computed along the BB#1->BB#2->BB#3 + // flow. We need to ensure the new basic block where the computation is + // sunk to dominates all the uses. + // It's only legal to break critical edge and sink the computation to the + // new block if all the predecessors of "To", except for "From", are + // not dominated by "From". Given SSA property, this means these + // predecessors are dominated by "To". + // + // There is no need to do this check if all the uses are PHI nodes. PHI + // sources are only defined on the specific predecessor edges. + if (!BreakPHIEdge) { for (MachineBasicBlock::pred_iterator PI = ToBB->pred_begin(), E = ToBB->pred_end(); PI != E; ++PI) { if (*PI == FromBB) @@ -238,17 +370,23 @@ MachineBasicBlock *MachineSinking::SplitCriticalEdge(MachineBasicBlock *FromBB, if (!DT->dominates(ToBB, *PI)) return 0; } - - // FIXME: Determine if it's cost effective to break this edge. - return FromBB->SplitCriticalEdge(ToBB, this); } - return 0; + return FromBB->SplitCriticalEdge(ToBB, this); +} + +static bool AvoidsSinking(MachineInstr *MI, MachineRegisterInfo *MRI) { + return MI->isInsertSubreg() || MI->isSubregToReg() || MI->isRegSequence(); } /// SinkInstruction - Determine whether it is safe to sink the specified machine /// instruction out of its current block into a successor. bool MachineSinking::SinkInstruction(MachineInstr *MI, bool &SawStore) { + // Don't sink insert_subreg, subreg_to_reg, reg_sequence. These are meant to + // be close to the source to make it easier to coalesce. + if (AvoidsSinking(MI, MRI)) + return false; + // Check if it's safe to move the instruction. if (!MI->isSafeToMove(TII, AA, SawStore)) return false; @@ -269,6 +407,7 @@ bool MachineSinking::SinkInstruction(MachineInstr *MI, bool &SawStore) { // decide. MachineBasicBlock *SuccToSinkTo = 0; + bool BreakPHIEdge = false; for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { const MachineOperand &MO = MI->getOperand(i); if (!MO.isReg()) continue; // Ignore non-register operands. @@ -281,7 +420,7 @@ bool MachineSinking::SinkInstruction(MachineInstr *MI, bool &SawStore) { // If the physreg has no defs anywhere, it's just an ambient register // and we can freely move its uses. Alternatively, if it's allocatable, // it could get allocated to something with a def during allocation. - if (!RegInfo->def_empty(Reg)) + if (!MRI->def_empty(Reg)) return false; if (AllocatableSet.test(Reg)) @@ -290,7 +429,7 @@ bool MachineSinking::SinkInstruction(MachineInstr *MI, bool &SawStore) { // Check for a def among the register's aliases too. for (const unsigned *Alias = TRI->getAliasSet(Reg); *Alias; ++Alias) { unsigned AliasReg = *Alias; - if (!RegInfo->def_empty(AliasReg)) + if (!MRI->def_empty(AliasReg)) return false; if (AllocatableSet.test(AliasReg)) @@ -305,7 +444,7 @@ bool MachineSinking::SinkInstruction(MachineInstr *MI, bool &SawStore) { if (MO.isUse()) continue; // If it's not safe to move defs of the register class, then abort. - if (!TII->isSafeToMoveRegClassDefs(RegInfo->getRegClass(Reg))) + if (!TII->isSafeToMoveRegClassDefs(MRI->getRegClass(Reg))) return false; // FIXME: This picks a successor to sink into based on having one @@ -327,7 +466,8 @@ bool MachineSinking::SinkInstruction(MachineInstr *MI, bool &SawStore) { // If a previous operand picked a block to sink to, then this operand // must be sinkable to the same block. bool LocalUse = false; - if (!AllUsesDominatedByBlock(Reg, SuccToSinkTo, ParentBlock, LocalUse)) + if (!AllUsesDominatedByBlock(Reg, SuccToSinkTo, ParentBlock, + BreakPHIEdge, LocalUse)) return false; continue; @@ -338,7 +478,8 @@ bool MachineSinking::SinkInstruction(MachineInstr *MI, bool &SawStore) { for (MachineBasicBlock::succ_iterator SI = ParentBlock->succ_begin(), E = ParentBlock->succ_end(); SI != E; ++SI) { bool LocalUse = false; - if (AllUsesDominatedByBlock(Reg, *SI, ParentBlock, LocalUse)) { + if (AllUsesDominatedByBlock(Reg, *SI, ParentBlock, + BreakPHIEdge, LocalUse)) { SuccToSinkTo = *SI; break; } @@ -384,7 +525,6 @@ bool MachineSinking::SinkInstruction(MachineInstr *MI, bool &SawStore) { // If the block has multiple predecessors, this would introduce computation on // a path that it doesn't already exist. We could split the critical edge, // but for now we just punt. - // FIXME: Split critical edges if not backedges. if (SuccToSinkTo->pred_size() > 1) { // We cannot sink a load across a critical edge - there may be stores in // other code paths. @@ -412,10 +552,11 @@ bool MachineSinking::SinkInstruction(MachineInstr *MI, bool &SawStore) { if (!TryBreak) DEBUG(dbgs() << "Sinking along critical edge.\n"); else { - MachineBasicBlock *NewSucc = SplitCriticalEdge(ParentBlock, SuccToSinkTo); + MachineBasicBlock *NewSucc = + SplitCriticalEdge(MI, ParentBlock, SuccToSinkTo, BreakPHIEdge); if (!NewSucc) { - DEBUG(dbgs() << - " *** PUNTING: Not legal or profitable to break critical edge\n"); + DEBUG(dbgs() << " *** PUNTING: Not legal or profitable to " + "break critical edge\n"); return false; } else { DEBUG(dbgs() << " *** Splitting critical edge:" @@ -424,10 +565,31 @@ bool MachineSinking::SinkInstruction(MachineInstr *MI, bool &SawStore) { << " -- BB#" << SuccToSinkTo->getNumber() << '\n'); SuccToSinkTo = NewSucc; ++NumSplit; + BreakPHIEdge = false; } } } + if (BreakPHIEdge) { + // BreakPHIEdge is true if all the uses are in the successor MBB being + // sunken into and they are all PHI nodes. In this case, machine-sink must + // break the critical edge first. + MachineBasicBlock *NewSucc = SplitCriticalEdge(MI, ParentBlock, + SuccToSinkTo, BreakPHIEdge); + if (!NewSucc) { + DEBUG(dbgs() << " *** PUNTING: Not legal or profitable to " + "break critical edge\n"); + return false; + } + + DEBUG(dbgs() << " *** Splitting critical edge:" + " BB#" << ParentBlock->getNumber() + << " -- BB#" << NewSucc->getNumber() + << " -- BB#" << SuccToSinkTo->getNumber() << '\n'); + SuccToSinkTo = NewSucc; + ++NumSplit; + } + // Determine where to insert into. Skip phi nodes. MachineBasicBlock::iterator InsertPos = SuccToSinkTo->begin(); while (InsertPos != SuccToSinkTo->end() && InsertPos->isPHI()) diff --git a/lib/CodeGen/MachineVerifier.cpp b/lib/CodeGen/MachineVerifier.cpp index 1e88562935ea..7351119f4728 100644 --- a/lib/CodeGen/MachineVerifier.cpp +++ b/lib/CodeGen/MachineVerifier.cpp @@ -26,6 +26,7 @@ #include "llvm/Function.h" #include "llvm/CodeGen/LiveIntervalAnalysis.h" #include "llvm/CodeGen/LiveVariables.h" +#include "llvm/CodeGen/LiveStackAnalysis.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineMemOperand.h" @@ -45,14 +46,16 @@ using namespace llvm; namespace { struct MachineVerifier { - MachineVerifier(Pass *pass) : + MachineVerifier(Pass *pass, const char *b) : PASS(pass), + Banner(b), OutFileName(getenv("LLVM_VERIFY_MACHINEINSTRS")) {} bool runOnMachineFunction(MachineFunction &MF); Pass *const PASS; + const char *Banner; const char *const OutFileName; raw_ostream *OS; const MachineFunction *MF; @@ -71,6 +74,8 @@ namespace { RegVector regsDefined, regsDead, regsKilled; RegSet regsLiveInButUnused; + SlotIndex lastIndex; + // Add Reg and any sub-registers to RV void addRegWithSubRegs(RegVector &RV, unsigned Reg) { RV.push_back(Reg); @@ -167,7 +172,9 @@ namespace { // Analysis information if available LiveVariables *LiveVars; - const LiveIntervals *LiveInts; + LiveIntervals *LiveInts; + LiveStacks *LiveStks; + SlotIndexes *Indexes; void visitMachineFunctionBefore(); void visitMachineBasicBlockBefore(const MachineBasicBlock *MBB); @@ -193,9 +200,12 @@ namespace { struct MachineVerifierPass : public MachineFunctionPass { static char ID; // Pass ID, replacement for typeid + const char *const Banner; - MachineVerifierPass() - : MachineFunctionPass(ID) {} + MachineVerifierPass(const char *b = 0) + : MachineFunctionPass(ID), Banner(b) { + initializeMachineVerifierPassPass(*PassRegistry::getPassRegistry()); + } void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesAll(); @@ -203,7 +213,7 @@ namespace { } bool runOnMachineFunction(MachineFunction &MF) { - MF.verify(this); + MF.verify(this, Banner); return false; } }; @@ -212,14 +222,15 @@ namespace { char MachineVerifierPass::ID = 0; INITIALIZE_PASS(MachineVerifierPass, "machineverifier", - "Verify generated machine code", false, false); + "Verify generated machine code", false, false) -FunctionPass *llvm::createMachineVerifierPass() { - return new MachineVerifierPass(); +FunctionPass *llvm::createMachineVerifierPass(const char *Banner) { + return new MachineVerifierPass(Banner); } -void MachineFunction::verify(Pass *p) const { - MachineVerifier(p).runOnMachineFunction(const_cast(*this)); +void MachineFunction::verify(Pass *p, const char *Banner) const { + MachineVerifier(p, Banner) + .runOnMachineFunction(const_cast(*this)); } bool MachineVerifier::runOnMachineFunction(MachineFunction &MF) { @@ -247,11 +258,15 @@ bool MachineVerifier::runOnMachineFunction(MachineFunction &MF) { LiveVars = NULL; LiveInts = NULL; + LiveStks = NULL; + Indexes = NULL; if (PASS) { LiveInts = PASS->getAnalysisIfAvailable(); // We don't want to verify LiveVariables if LiveIntervals is available. if (!LiveInts) LiveVars = PASS->getAnalysisIfAvailable(); + LiveStks = PASS->getAnalysisIfAvailable(); + Indexes = PASS->getAnalysisIfAvailable(); } visitMachineFunctionBefore(); @@ -260,6 +275,11 @@ bool MachineVerifier::runOnMachineFunction(MachineFunction &MF) { visitMachineBasicBlockBefore(MFI); for (MachineBasicBlock::const_iterator MBBI = MFI->begin(), MBBE = MFI->end(); MBBI != MBBE; ++MBBI) { + if (MBBI->getParent() != MFI) { + report("Bad instruction parent pointer", MFI); + *OS << "Instruction: " << *MBBI; + continue; + } visitMachineInstrBefore(MBBI); for (unsigned I = 0, E = MBBI->getNumOperands(); I != E; ++I) visitMachineOperand(&MBBI->getOperand(I), I); @@ -288,8 +308,11 @@ bool MachineVerifier::runOnMachineFunction(MachineFunction &MF) { void MachineVerifier::report(const char *msg, const MachineFunction *MF) { assert(MF); *OS << '\n'; - if (!foundErrors++) - MF->print(*OS); + if (!foundErrors++) { + if (Banner) + *OS << "# " << Banner << '\n'; + MF->print(*OS, Indexes); + } *OS << "*** Bad machine code: " << msg << " ***\n" << "- function: " << MF->getFunction()->getNameStr() << "\n"; } @@ -299,13 +322,19 @@ void MachineVerifier::report(const char *msg, const MachineBasicBlock *MBB) { report(msg, MBB->getParent()); *OS << "- basic block: " << MBB->getName() << " " << (void*)MBB - << " (BB#" << MBB->getNumber() << ")\n"; + << " (BB#" << MBB->getNumber() << ")"; + if (Indexes) + *OS << " [" << Indexes->getMBBStartIdx(MBB) + << ';' << Indexes->getMBBEndIdx(MBB) << ')'; + *OS << '\n'; } void MachineVerifier::report(const char *msg, const MachineInstr *MI) { assert(MI); report(msg, MI->getParent()); *OS << "- instruction: "; + if (Indexes && Indexes->hasIndex(MI)) + *OS << Indexes->getInstructionIndex(MI) << '\t'; MI->print(*OS, TM); } @@ -329,6 +358,7 @@ void MachineVerifier::markReachable(const MachineBasicBlock *MBB) { } void MachineVerifier::visitMachineFunctionBefore() { + lastIndex = SlotIndex(); regsReserved = TRI->getReservedRegs(*MF); // A sub-register of a reserved register is also reserved @@ -357,6 +387,16 @@ void MachineVerifier::visitMachineBasicBlockBefore(const MachineBasicBlock *MBB) { const TargetInstrInfo *TII = MF->getTarget().getInstrInfo(); + // Count the number of landing pad successors. + SmallPtrSet LandingPadSuccs; + for (MachineBasicBlock::const_succ_iterator I = MBB->succ_begin(), + E = MBB->succ_end(); I != E; ++I) { + if ((*I)->isLandingPad()) + LandingPadSuccs.insert(*I); + } + if (LandingPadSuccs.size() > 1) + report("MBB has more than one landing pad successor", MBB); + // Call AnalyzeBranch. If it succeeds, there several more conditions to check. MachineBasicBlock *TBB = 0, *FBB = 0; SmallVector Cond; @@ -372,14 +412,14 @@ MachineVerifier::visitMachineBasicBlockBefore(const MachineBasicBlock *MBB) { // It's possible that the block legitimately ends with a noreturn // call or an unreachable, in which case it won't actually fall // out the bottom of the function. - } else if (MBB->succ_empty()) { + } else if (MBB->succ_size() == LandingPadSuccs.size()) { // It's possible that the block legitimately ends with a noreturn // call or an unreachable, in which case it won't actuall fall // out of the block. - } else if (MBB->succ_size() != 1) { + } else if (MBB->succ_size() != 1+LandingPadSuccs.size()) { report("MBB exits via unconditional fall-through but doesn't have " "exactly one CFG successor!", MBB); - } else if (MBB->succ_begin()[0] != MBBI) { + } else if (!MBB->isSuccessor(MBBI)) { report("MBB exits via unconditional fall-through but its successor " "differs from its CFG successor!", MBB); } @@ -394,10 +434,10 @@ MachineVerifier::visitMachineBasicBlockBefore(const MachineBasicBlock *MBB) { } } else if (TBB && !FBB && Cond.empty()) { // Block unconditionally branches somewhere. - if (MBB->succ_size() != 1) { + if (MBB->succ_size() != 1+LandingPadSuccs.size()) { report("MBB exits via unconditional branch but doesn't have " "exactly one CFG successor!", MBB); - } else if (MBB->succ_begin()[0] != TBB) { + } else if (!MBB->isSuccessor(TBB)) { report("MBB exits via unconditional branch but the CFG " "successor doesn't match the actual successor!", MBB); } @@ -487,6 +527,9 @@ MachineVerifier::visitMachineBasicBlockBefore(const MachineBasicBlock *MBB) { regsKilled.clear(); regsDefined.clear(); + + if (Indexes) + lastIndex = Indexes->getMBBStartIdx(MBB); } void MachineVerifier::visitMachineInstrBefore(const MachineInstr *MI) { @@ -525,6 +568,7 @@ void MachineVerifier::visitMachineOperand(const MachineOperand *MO, unsigned MONum) { const MachineInstr *MI = MO->getParent(); const TargetInstrDesc &TI = MI->getDesc(); + const TargetOperandInfo &TOI = TI.OpInfo[MONum]; // The first TI.NumDefs operands must be explicit register defines if (MONum < TI.getNumDefs()) { @@ -535,9 +579,11 @@ MachineVerifier::visitMachineOperand(const MachineOperand *MO, unsigned MONum) { else if (MO->isImplicit()) report("Explicit definition marked as implicit", MO, MONum); } else if (MONum < TI.getNumOperands()) { - if (MO->isReg()) { - if (MO->isDef()) - report("Explicit operand marked as def", MO, MONum); + // Don't check if it's the last operand in a variadic instruction. See, + // e.g., LDM_RET in the arm back end. + if (MO->isReg() && !(TI.isVariadic() && MONum == TI.getNumOperands()-1)) { + if (MO->isDef() && !TOI.isOptionalDef()) + report("Explicit operand marked as def", MO, MONum); if (MO->isImplicit()) report("Explicit operand marked as implicit", MO, MONum); } @@ -554,7 +600,9 @@ MachineVerifier::visitMachineOperand(const MachineOperand *MO, unsigned MONum) { return; // Check Live Variables. - if (MO->isUndef()) { + if (MI->isDebugValue()) { + // Liveness checks are not valid for debug values. + } else if (MO->isUndef()) { // An doesn't refer to any register, so just skip it. } else if (MO->isUse()) { regsLiveInButUnused.erase(Reg); @@ -566,7 +614,7 @@ MachineVerifier::visitMachineOperand(const MachineOperand *MO, unsigned MONum) { unsigned DefReg = MI->getOperand(defIdx).getReg(); if (Reg == DefReg) { isKill = true; - // ANd in that case an explicit kill flag is not allowed. + // And in that case an explicit kill flag is not allowed. if (MO->isKill()) report("Illegal kill flag on two-address instruction operand", MO, MONum); @@ -590,7 +638,8 @@ MachineVerifier::visitMachineOperand(const MachineOperand *MO, unsigned MONum) { } // Check LiveInts liveness and kill. - if (LiveInts && !LiveInts->isNotInMIMap(MI)) { + if (TargetRegisterInfo::isVirtualRegister(Reg) && + LiveInts && !LiveInts->isNotInMIMap(MI)) { SlotIndex UseIdx = LiveInts->getInstructionIndex(MI).getUseIndex(); if (LiveInts->hasInterval(Reg)) { const LiveInterval &LI = LiveInts->getInterval(Reg); @@ -598,8 +647,13 @@ MachineVerifier::visitMachineOperand(const MachineOperand *MO, unsigned MONum) { report("No live range at use", MO, MONum); *OS << UseIdx << " is not live in " << LI << '\n'; } - // TODO: Verify isKill == LI.killedAt. - } else if (TargetRegisterInfo::isVirtualRegister(Reg)) { + // Check for extra kill flags. + // Note that we allow missing kill flags for now. + if (MO->isKill() && !LI.killedAt(UseIdx.getDefIndex())) { + report("Live range continues after kill flag", MO, MONum); + *OS << "Live range: " << LI << '\n'; + } + } else { report("Virtual register has no Live interval", MO, MONum); } } @@ -636,11 +690,11 @@ MachineVerifier::visitMachineOperand(const MachineOperand *MO, unsigned MONum) { SlotIndex DefIdx = LiveInts->getInstructionIndex(MI).getDefIndex(); if (LiveInts->hasInterval(Reg)) { const LiveInterval &LI = LiveInts->getInterval(Reg); - if (const LiveRange *LR = LI.getLiveRangeContaining(DefIdx)) { - assert(LR->valno && "NULL valno is not allowed"); - if (LR->valno->def != DefIdx) { + if (const VNInfo *VNI = LI.getVNInfoAt(DefIdx)) { + assert(VNI && "NULL valno is not allowed"); + if (VNI->def != DefIdx && !MO->isEarlyClobber()) { report("Inconsistent valno->def", MO, MONum); - *OS << "Valno " << LR->valno->id << " is not defined at " + *OS << "Valno " << VNI->id << " is not defined at " << DefIdx << " in " << LI << '\n'; } } else { @@ -655,7 +709,6 @@ MachineVerifier::visitMachineOperand(const MachineOperand *MO, unsigned MONum) { // Check register classes. if (MONum < TI.getNumOperands() && !MO->isImplicit()) { - const TargetOperandInfo &TOI = TI.OpInfo[MONum]; unsigned SubIdx = MO->getSubReg(); if (TargetRegisterInfo::isPhysicalRegister(Reg)) { @@ -706,6 +759,22 @@ MachineVerifier::visitMachineOperand(const MachineOperand *MO, unsigned MONum) { report("PHI operand is not in the CFG", MO, MONum); break; + case MachineOperand::MO_FrameIndex: + if (LiveStks && LiveStks->hasInterval(MO->getIndex()) && + LiveInts && !LiveInts->isNotInMIMap(MI)) { + LiveInterval &LI = LiveStks->getInterval(MO->getIndex()); + SlotIndex Idx = LiveInts->getInstructionIndex(MI); + if (TI.mayLoad() && !LI.liveAt(Idx.getUseIndex())) { + report("Instruction loads from dead spill slot", MO, MONum); + *OS << "Live stack: " << LI << '\n'; + } + if (TI.mayStore() && !LI.liveAt(Idx.getDefIndex())) { + report("Instruction stores to dead spill slot", MO, MONum); + *OS << "Live stack: " << LI << '\n'; + } + } + break; + default: break; } @@ -717,12 +786,31 @@ void MachineVerifier::visitMachineInstrAfter(const MachineInstr *MI) { set_subtract(regsLive, regsKilled); regsKilled.clear(); set_subtract(regsLive, regsDead); regsDead.clear(); set_union(regsLive, regsDefined); regsDefined.clear(); + + if (Indexes && Indexes->hasIndex(MI)) { + SlotIndex idx = Indexes->getInstructionIndex(MI); + if (!(idx > lastIndex)) { + report("Instruction index out of order", MI); + *OS << "Last instruction was at " << lastIndex << '\n'; + } + lastIndex = idx; + } } void MachineVerifier::visitMachineBasicBlockAfter(const MachineBasicBlock *MBB) { MBBInfoMap[MBB].regsLiveOut = regsLive; regsLive.clear(); + + if (Indexes) { + SlotIndex stop = Indexes->getMBBEndIdx(MBB); + if (!(stop > lastIndex)) { + report("Block ends before last instruction index", MBB); + *OS << "Block ends at " << stop + << " last instruction was at " << lastIndex << '\n'; + } + lastIndex = stop; + } } // Calculate the largest possible vregsPassed sets. These are the registers that @@ -854,8 +942,8 @@ void MachineVerifier::visitMachineFunctionAfter() { void MachineVerifier::verifyLiveVariables() { assert(LiveVars && "Don't call verifyLiveVariables without LiveVars"); - for (unsigned Reg = TargetRegisterInfo::FirstVirtualRegister, - RegE = MRI->getLastVirtReg()-1; Reg != RegE; ++Reg) { + for (unsigned i = 0, e = MRI->getNumVirtRegs(); i != e; ++i) { + unsigned Reg = TargetRegisterInfo::index2VirtReg(i); LiveVariables::VarInfo &VI = LiveVars->getVarInfo(Reg); for (MachineFunction::const_iterator MFI = MF->begin(), MFE = MF->end(); MFI != MFE; ++MFI) { @@ -865,13 +953,13 @@ void MachineVerifier::verifyLiveVariables() { if (MInfo.vregsRequired.count(Reg)) { if (!VI.AliveBlocks.test(MFI->getNumber())) { report("LiveVariables: Block missing from AliveBlocks", MFI); - *OS << "Virtual register %reg" << Reg + *OS << "Virtual register " << PrintReg(Reg) << " must be live through the block.\n"; } } else { if (VI.AliveBlocks.test(MFI->getNumber())) { report("LiveVariables: Block should not be in AliveBlocks", MFI); - *OS << "Virtual register %reg" << Reg + *OS << "Virtual register " << PrintReg(Reg) << " is not needed live through the block.\n"; } } @@ -884,14 +972,24 @@ void MachineVerifier::verifyLiveIntervals() { for (LiveIntervals::const_iterator LVI = LiveInts->begin(), LVE = LiveInts->end(); LVI != LVE; ++LVI) { const LiveInterval &LI = *LVI->second; + + // Spilling and splitting may leave unused registers around. Skip them. + if (MRI->use_empty(LI.reg)) + continue; + + // Physical registers have much weirdness going on, mostly from coalescing. + // We should probably fix it, but for now just ignore them. + if (TargetRegisterInfo::isPhysicalRegister(LI.reg)) + continue; + assert(LVI->first == LI.reg && "Invalid reg to interval mapping"); for (LiveInterval::const_vni_iterator I = LI.vni_begin(), E = LI.vni_end(); I!=E; ++I) { VNInfo *VNI = *I; - const LiveRange *DefLR = LI.getLiveRangeContaining(VNI->def); + const VNInfo *DefVNI = LI.getVNInfoAt(VNI->def); - if (!DefLR) { + if (!DefVNI) { if (!VNI->isUnused()) { report("Valno not live at def and not marked unused", MF); *OS << "Valno #" << VNI->id << " in " << LI << '\n'; @@ -902,31 +1000,216 @@ void MachineVerifier::verifyLiveIntervals() { if (VNI->isUnused()) continue; - if (DefLR->valno != VNI) { + if (DefVNI != VNI) { report("Live range at def has different valno", MF); - DefLR->print(*OS); - *OS << " should use valno #" << VNI->id << " in " << LI << '\n'; + *OS << "Valno #" << VNI->id << " is defined at " << VNI->def + << " where valno #" << DefVNI->id << " is live in " << LI << '\n'; + continue; } + const MachineBasicBlock *MBB = LiveInts->getMBBFromIndex(VNI->def); + if (!MBB) { + report("Invalid definition index", MF); + *OS << "Valno #" << VNI->id << " is defined at " << VNI->def + << " in " << LI << '\n'; + continue; + } + + if (VNI->isPHIDef()) { + if (VNI->def != LiveInts->getMBBStartIdx(MBB)) { + report("PHIDef value is not defined at MBB start", MF); + *OS << "Valno #" << VNI->id << " is defined at " << VNI->def + << ", not at the beginning of BB#" << MBB->getNumber() + << " in " << LI << '\n'; + } + } else { + // Non-PHI def. + const MachineInstr *MI = LiveInts->getInstructionFromIndex(VNI->def); + if (!MI) { + report("No instruction at def index", MF); + *OS << "Valno #" << VNI->id << " is defined at " << VNI->def + << " in " << LI << '\n'; + } else if (!MI->modifiesRegister(LI.reg, TRI)) { + report("Defining instruction does not modify register", MI); + *OS << "Valno #" << VNI->id << " in " << LI << '\n'; + } + + bool isEarlyClobber = false; + if (MI) { + for (MachineInstr::const_mop_iterator MOI = MI->operands_begin(), + MOE = MI->operands_end(); MOI != MOE; ++MOI) { + if (MOI->isReg() && MOI->getReg() == LI.reg && MOI->isDef() && + MOI->isEarlyClobber()) { + isEarlyClobber = true; + break; + } + } + } + + // Early clobber defs begin at USE slots, but other defs must begin at + // DEF slots. + if (isEarlyClobber) { + if (!VNI->def.isUse()) { + report("Early clobber def must be at a USE slot", MF); + *OS << "Valno #" << VNI->id << " is defined at " << VNI->def + << " in " << LI << '\n'; + } + } else if (!VNI->def.isDef()) { + report("Non-PHI, non-early clobber def must be at a DEF slot", MF); + *OS << "Valno #" << VNI->id << " is defined at " << VNI->def + << " in " << LI << '\n'; + } + } } for (LiveInterval::const_iterator I = LI.begin(), E = LI.end(); I!=E; ++I) { - const LiveRange &LR = *I; - assert(LR.valno && "Live range has no valno"); + const VNInfo *VNI = I->valno; + assert(VNI && "Live range has no valno"); - if (LR.valno->id >= LI.getNumValNums() || - LR.valno != LI.getValNumInfo(LR.valno->id)) { + if (VNI->id >= LI.getNumValNums() || VNI != LI.getValNumInfo(VNI->id)) { report("Foreign valno in live range", MF); - LR.print(*OS); + I->print(*OS); *OS << " has a valno not in " << LI << '\n'; } - if (LR.valno->isUnused()) { + if (VNI->isUnused()) { report("Live range valno is marked unused", MF); - LR.print(*OS); + I->print(*OS); + *OS << " in " << LI << '\n'; + } + + const MachineBasicBlock *MBB = LiveInts->getMBBFromIndex(I->start); + if (!MBB) { + report("Bad start of live segment, no basic block", MF); + I->print(*OS); *OS << " in " << LI << '\n'; + continue; + } + SlotIndex MBBStartIdx = LiveInts->getMBBStartIdx(MBB); + if (I->start != MBBStartIdx && I->start != VNI->def) { + report("Live segment must begin at MBB entry or valno def", MBB); + I->print(*OS); + *OS << " in " << LI << '\n' << "Basic block starts at " + << MBBStartIdx << '\n'; + } + + const MachineBasicBlock *EndMBB = + LiveInts->getMBBFromIndex(I->end.getPrevSlot()); + if (!EndMBB) { + report("Bad end of live segment, no basic block", MF); + I->print(*OS); + *OS << " in " << LI << '\n'; + continue; + } + if (I->end != LiveInts->getMBBEndIdx(EndMBB)) { + // The live segment is ending inside EndMBB + const MachineInstr *MI = + LiveInts->getInstructionFromIndex(I->end.getPrevSlot()); + if (!MI) { + report("Live segment doesn't end at a valid instruction", EndMBB); + I->print(*OS); + *OS << " in " << LI << '\n' << "Basic block starts at " + << MBBStartIdx << '\n'; + } else if (TargetRegisterInfo::isVirtualRegister(LI.reg) && + !MI->readsVirtualRegister(LI.reg)) { + // A live range can end with either a redefinition, a kill flag on a + // use, or a dead flag on a def. + // FIXME: Should we check for each of these? + bool hasDeadDef = false; + for (MachineInstr::const_mop_iterator MOI = MI->operands_begin(), + MOE = MI->operands_end(); MOI != MOE; ++MOI) { + if (MOI->isReg() && MOI->getReg() == LI.reg && MOI->isDef() && MOI->isDead()) { + hasDeadDef = true; + break; + } + } + + if (!hasDeadDef) { + report("Instruction killing live segment neither defines nor reads " + "register", MI); + I->print(*OS); + *OS << " in " << LI << '\n'; + } + } + } + + // Now check all the basic blocks in this live segment. + MachineFunction::const_iterator MFI = MBB; + // Is this live range the beginning of a non-PHIDef VN? + if (I->start == VNI->def && !VNI->isPHIDef()) { + // Not live-in to any blocks. + if (MBB == EndMBB) + continue; + // Skip this block. + ++MFI; + } + for (;;) { + assert(LiveInts->isLiveInToMBB(LI, MFI)); + // We don't know how to track physregs into a landing pad. + if (TargetRegisterInfo::isPhysicalRegister(LI.reg) && + MFI->isLandingPad()) { + if (&*MFI == EndMBB) + break; + ++MFI; + continue; + } + // Check that VNI is live-out of all predecessors. + for (MachineBasicBlock::const_pred_iterator PI = MFI->pred_begin(), + PE = MFI->pred_end(); PI != PE; ++PI) { + SlotIndex PEnd = LiveInts->getMBBEndIdx(*PI).getPrevSlot(); + const VNInfo *PVNI = LI.getVNInfoAt(PEnd); + + if (VNI->isPHIDef() && VNI->def == LiveInts->getMBBStartIdx(MFI)) { + if (PVNI && !PVNI->hasPHIKill()) { + report("Value live out of predecessor doesn't have PHIKill", MF); + *OS << "Valno #" << PVNI->id << " live out of BB#" + << (*PI)->getNumber() << '@' << PEnd + << " doesn't have PHIKill, but Valno #" << VNI->id + << " is PHIDef and defined at the beginning of BB#" + << MFI->getNumber() << '@' << LiveInts->getMBBStartIdx(MFI) + << " in " << LI << '\n'; + } + continue; + } + + if (!PVNI) { + report("Register not marked live out of predecessor", *PI); + *OS << "Valno #" << VNI->id << " live into BB#" << MFI->getNumber() + << '@' << LiveInts->getMBBStartIdx(MFI) << ", not live at " + << PEnd << " in " << LI << '\n'; + continue; + } + + if (PVNI != VNI) { + report("Different value live out of predecessor", *PI); + *OS << "Valno #" << PVNI->id << " live out of BB#" + << (*PI)->getNumber() << '@' << PEnd + << "\nValno #" << VNI->id << " live into BB#" << MFI->getNumber() + << '@' << LiveInts->getMBBStartIdx(MFI) << " in " << LI << '\n'; + } + } + if (&*MFI == EndMBB) + break; + ++MFI; } + } + // Check the LI only has one connected component. + if (TargetRegisterInfo::isVirtualRegister(LI.reg)) { + ConnectedVNInfoEqClasses ConEQ(*LiveInts); + unsigned NumComp = ConEQ.Classify(&LI); + if (NumComp > 1) { + report("Multiple connected components in live interval", MF); + *OS << NumComp << " components in " << LI << '\n'; + for (unsigned comp = 0; comp != NumComp; ++comp) { + *OS << comp << ": valnos"; + for (LiveInterval::const_vni_iterator I = LI.vni_begin(), + E = LI.vni_end(); I!=E; ++I) + if (comp == ConEQ.getEqClass(*I)) + *OS << ' ' << (*I)->id; + *OS << '\n'; + } + } } } } diff --git a/lib/CodeGen/OptimizePHIs.cpp b/lib/CodeGen/OptimizePHIs.cpp index edb4eea71b8a..c05be130ec61 100644 --- a/lib/CodeGen/OptimizePHIs.cpp +++ b/lib/CodeGen/OptimizePHIs.cpp @@ -33,7 +33,9 @@ namespace { public: static char ID; // Pass identification - OptimizePHIs() : MachineFunctionPass(ID) {} + OptimizePHIs() : MachineFunctionPass(ID) { + initializeOptimizePHIsPass(*PassRegistry::getPassRegistry()); + } virtual bool runOnMachineFunction(MachineFunction &MF); @@ -55,7 +57,7 @@ namespace { char OptimizePHIs::ID = 0; INITIALIZE_PASS(OptimizePHIs, "opt-phis", - "Optimize machine instruction PHIs", false, false); + "Optimize machine instruction PHIs", false, false) FunctionPass *llvm::createOptimizePHIsPass() { return new OptimizePHIs(); } diff --git a/lib/CodeGen/PBQP/Graph.h b/lib/CodeGen/PBQP/Graph.h deleted file mode 100644 index b2224cb051dc..000000000000 --- a/lib/CodeGen/PBQP/Graph.h +++ /dev/null @@ -1,425 +0,0 @@ -//===-------------------- Graph.h - PBQP Graph ------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// PBQP Graph class. -// -//===----------------------------------------------------------------------===// - - -#ifndef LLVM_CODEGEN_PBQP_GRAPH_H -#define LLVM_CODEGEN_PBQP_GRAPH_H - -#include "Math.h" - -#include -#include -#include - -namespace PBQP { - - /// PBQP Graph class. - /// Instances of this class describe PBQP problems. - class Graph { - private: - - // ----- TYPEDEFS ----- - class NodeEntry; - class EdgeEntry; - - typedef std::list NodeList; - typedef std::list EdgeList; - - public: - - typedef NodeList::iterator NodeItr; - typedef NodeList::const_iterator ConstNodeItr; - - typedef EdgeList::iterator EdgeItr; - typedef EdgeList::const_iterator ConstEdgeItr; - - private: - - typedef std::list AdjEdgeList; - - public: - - typedef AdjEdgeList::iterator AdjEdgeItr; - - private: - - class NodeEntry { - private: - Vector costs; - AdjEdgeList adjEdges; - unsigned degree; - void *data; - public: - NodeEntry(const Vector &costs) : costs(costs), degree(0) {} - Vector& getCosts() { return costs; } - const Vector& getCosts() const { return costs; } - unsigned getDegree() const { return degree; } - AdjEdgeItr edgesBegin() { return adjEdges.begin(); } - AdjEdgeItr edgesEnd() { return adjEdges.end(); } - AdjEdgeItr addEdge(EdgeItr e) { - ++degree; - return adjEdges.insert(adjEdges.end(), e); - } - void removeEdge(AdjEdgeItr ae) { - --degree; - adjEdges.erase(ae); - } - void setData(void *data) { this->data = data; } - void* getData() { return data; } - }; - - class EdgeEntry { - private: - NodeItr node1, node2; - Matrix costs; - AdjEdgeItr node1AEItr, node2AEItr; - void *data; - public: - EdgeEntry(NodeItr node1, NodeItr node2, const Matrix &costs) - : node1(node1), node2(node2), costs(costs) {} - NodeItr getNode1() const { return node1; } - NodeItr getNode2() const { return node2; } - Matrix& getCosts() { return costs; } - const Matrix& getCosts() const { return costs; } - void setNode1AEItr(AdjEdgeItr ae) { node1AEItr = ae; } - AdjEdgeItr getNode1AEItr() { return node1AEItr; } - void setNode2AEItr(AdjEdgeItr ae) { node2AEItr = ae; } - AdjEdgeItr getNode2AEItr() { return node2AEItr; } - void setData(void *data) { this->data = data; } - void *getData() { return data; } - }; - - // ----- MEMBERS ----- - - NodeList nodes; - unsigned numNodes; - - EdgeList edges; - unsigned numEdges; - - // ----- INTERNAL METHODS ----- - - NodeEntry& getNode(NodeItr nItr) { return *nItr; } - const NodeEntry& getNode(ConstNodeItr nItr) const { return *nItr; } - - EdgeEntry& getEdge(EdgeItr eItr) { return *eItr; } - const EdgeEntry& getEdge(ConstEdgeItr eItr) const { return *eItr; } - - NodeItr addConstructedNode(const NodeEntry &n) { - ++numNodes; - return nodes.insert(nodes.end(), n); - } - - EdgeItr addConstructedEdge(const EdgeEntry &e) { - assert(findEdge(e.getNode1(), e.getNode2()) == edges.end() && - "Attempt to add duplicate edge."); - ++numEdges; - EdgeItr edgeItr = edges.insert(edges.end(), e); - EdgeEntry &ne = getEdge(edgeItr); - NodeEntry &n1 = getNode(ne.getNode1()); - NodeEntry &n2 = getNode(ne.getNode2()); - // Sanity check on matrix dimensions: - assert((n1.getCosts().getLength() == ne.getCosts().getRows()) && - (n2.getCosts().getLength() == ne.getCosts().getCols()) && - "Edge cost dimensions do not match node costs dimensions."); - ne.setNode1AEItr(n1.addEdge(edgeItr)); - ne.setNode2AEItr(n2.addEdge(edgeItr)); - return edgeItr; - } - - inline void copyFrom(const Graph &other); - public: - - /// \brief Construct an empty PBQP graph. - Graph() : numNodes(0), numEdges(0) {} - - /// \brief Copy construct this graph from "other". Note: Does not copy node - /// and edge data, only graph structure and costs. - /// @param other Source graph to copy from. - Graph(const Graph &other) : numNodes(0), numEdges(0) { - copyFrom(other); - } - - /// \brief Make this graph a copy of "other". Note: Does not copy node and - /// edge data, only graph structure and costs. - /// @param other The graph to copy from. - /// @return A reference to this graph. - /// - /// This will clear the current graph, erasing any nodes and edges added, - /// before copying from other. - Graph& operator=(const Graph &other) { - clear(); - copyFrom(other); - return *this; - } - - /// \brief Add a node with the given costs. - /// @param costs Cost vector for the new node. - /// @return Node iterator for the added node. - NodeItr addNode(const Vector &costs) { - return addConstructedNode(NodeEntry(costs)); - } - - /// \brief Add an edge between the given nodes with the given costs. - /// @param n1Itr First node. - /// @param n2Itr Second node. - /// @return Edge iterator for the added edge. - EdgeItr addEdge(Graph::NodeItr n1Itr, Graph::NodeItr n2Itr, - const Matrix &costs) { - assert(getNodeCosts(n1Itr).getLength() == costs.getRows() && - getNodeCosts(n2Itr).getLength() == costs.getCols() && - "Matrix dimensions mismatch."); - return addConstructedEdge(EdgeEntry(n1Itr, n2Itr, costs)); - } - - /// \brief Get the number of nodes in the graph. - /// @return Number of nodes in the graph. - unsigned getNumNodes() const { return numNodes; } - - /// \brief Get the number of edges in the graph. - /// @return Number of edges in the graph. - unsigned getNumEdges() const { return numEdges; } - - /// \brief Get a node's cost vector. - /// @param nItr Node iterator. - /// @return Node cost vector. - Vector& getNodeCosts(NodeItr nItr) { return getNode(nItr).getCosts(); } - - /// \brief Get a node's cost vector (const version). - /// @param nItr Node iterator. - /// @return Node cost vector. - const Vector& getNodeCosts(ConstNodeItr nItr) const { - return getNode(nItr).getCosts(); - } - - /// \brief Set a node's data pointer. - /// @param nItr Node iterator. - /// @param data Pointer to node data. - /// - /// Typically used by a PBQP solver to attach data to aid in solution. - void setNodeData(NodeItr nItr, void *data) { getNode(nItr).setData(data); } - - /// \brief Get the node's data pointer. - /// @param nItr Node iterator. - /// @return Pointer to node data. - void* getNodeData(NodeItr nItr) { return getNode(nItr).getData(); } - - /// \brief Get an edge's cost matrix. - /// @param eItr Edge iterator. - /// @return Edge cost matrix. - Matrix& getEdgeCosts(EdgeItr eItr) { return getEdge(eItr).getCosts(); } - - /// \brief Get an edge's cost matrix (const version). - /// @param eItr Edge iterator. - /// @return Edge cost matrix. - const Matrix& getEdgeCosts(ConstEdgeItr eItr) const { - return getEdge(eItr).getCosts(); - } - - /// \brief Set an edge's data pointer. - /// @param eItr Edge iterator. - /// @param data Pointer to edge data. - /// - /// Typically used by a PBQP solver to attach data to aid in solution. - void setEdgeData(EdgeItr eItr, void *data) { getEdge(eItr).setData(data); } - - /// \brief Get an edge's data pointer. - /// @param eItr Edge iterator. - /// @return Pointer to edge data. - void* getEdgeData(EdgeItr eItr) { return getEdge(eItr).getData(); } - - /// \brief Get a node's degree. - /// @param nItr Node iterator. - /// @return The degree of the node. - unsigned getNodeDegree(NodeItr nItr) const { - return getNode(nItr).getDegree(); - } - - /// \brief Begin iterator for node set. - NodeItr nodesBegin() { return nodes.begin(); } - - /// \brief Begin const iterator for node set. - ConstNodeItr nodesBegin() const { return nodes.begin(); } - - /// \brief End iterator for node set. - NodeItr nodesEnd() { return nodes.end(); } - - /// \brief End const iterator for node set. - ConstNodeItr nodesEnd() const { return nodes.end(); } - - /// \brief Begin iterator for edge set. - EdgeItr edgesBegin() { return edges.begin(); } - - /// \brief End iterator for edge set. - EdgeItr edgesEnd() { return edges.end(); } - - /// \brief Get begin iterator for adjacent edge set. - /// @param nItr Node iterator. - /// @return Begin iterator for the set of edges connected to the given node. - AdjEdgeItr adjEdgesBegin(NodeItr nItr) { - return getNode(nItr).edgesBegin(); - } - - /// \brief Get end iterator for adjacent edge set. - /// @param nItr Node iterator. - /// @return End iterator for the set of edges connected to the given node. - AdjEdgeItr adjEdgesEnd(NodeItr nItr) { - return getNode(nItr).edgesEnd(); - } - - /// \brief Get the first node connected to this edge. - /// @param eItr Edge iterator. - /// @return The first node connected to the given edge. - NodeItr getEdgeNode1(EdgeItr eItr) { - return getEdge(eItr).getNode1(); - } - - /// \brief Get the second node connected to this edge. - /// @param eItr Edge iterator. - /// @return The second node connected to the given edge. - NodeItr getEdgeNode2(EdgeItr eItr) { - return getEdge(eItr).getNode2(); - } - - /// \brief Get the "other" node connected to this edge. - /// @param eItr Edge iterator. - /// @param nItr Node iterator for the "given" node. - /// @return The iterator for the "other" node connected to this edge. - NodeItr getEdgeOtherNode(EdgeItr eItr, NodeItr nItr) { - EdgeEntry &e = getEdge(eItr); - if (e.getNode1() == nItr) { - return e.getNode2(); - } // else - return e.getNode1(); - } - - /// \brief Get the edge connecting two nodes. - /// @param n1Itr First node iterator. - /// @param n2Itr Second node iterator. - /// @return An iterator for edge (n1Itr, n2Itr) if such an edge exists, - /// otherwise returns edgesEnd(). - EdgeItr findEdge(NodeItr n1Itr, NodeItr n2Itr) { - for (AdjEdgeItr aeItr = adjEdgesBegin(n1Itr), aeEnd = adjEdgesEnd(n1Itr); - aeItr != aeEnd; ++aeItr) { - if ((getEdgeNode1(*aeItr) == n2Itr) || - (getEdgeNode2(*aeItr) == n2Itr)) { - return *aeItr; - } - } - return edges.end(); - } - - /// \brief Remove a node from the graph. - /// @param nItr Node iterator. - void removeNode(NodeItr nItr) { - NodeEntry &n = getNode(nItr); - for (AdjEdgeItr itr = n.edgesBegin(), end = n.edgesEnd(); itr != end;) { - EdgeItr eItr = *itr; - ++itr; - removeEdge(eItr); - } - nodes.erase(nItr); - --numNodes; - } - - /// \brief Remove an edge from the graph. - /// @param eItr Edge iterator. - void removeEdge(EdgeItr eItr) { - EdgeEntry &e = getEdge(eItr); - NodeEntry &n1 = getNode(e.getNode1()); - NodeEntry &n2 = getNode(e.getNode2()); - n1.removeEdge(e.getNode1AEItr()); - n2.removeEdge(e.getNode2AEItr()); - edges.erase(eItr); - --numEdges; - } - - /// \brief Remove all nodes and edges from the graph. - void clear() { - nodes.clear(); - edges.clear(); - numNodes = numEdges = 0; - } - - /// \brief Print a representation of this graph in DOT format. - /// @param os Output stream to print on. - template - void printDot(OStream &os) { - - os << "graph {\n"; - - for (NodeItr nodeItr = nodesBegin(), nodeEnd = nodesEnd(); - nodeItr != nodeEnd; ++nodeItr) { - - os << " node" << nodeItr << " [ label=\"" - << nodeItr << ": " << getNodeCosts(nodeItr) << "\" ]\n"; - } - - os << " edge [ len=" << getNumNodes() << " ]\n"; - - for (EdgeItr edgeItr = edgesBegin(), edgeEnd = edgesEnd(); - edgeItr != edgeEnd; ++edgeItr) { - - os << " node" << getEdgeNode1(edgeItr) - << " -- node" << getEdgeNode2(edgeItr) - << " [ label=\""; - - const Matrix &edgeCosts = getEdgeCosts(edgeItr); - - for (unsigned i = 0; i < edgeCosts.getRows(); ++i) { - os << edgeCosts.getRowAsVector(i) << "\\n"; - } - os << "\" ]\n"; - } - os << "}\n"; - } - - }; - - class NodeItrComparator { - public: - bool operator()(Graph::NodeItr n1, Graph::NodeItr n2) const { - return &*n1 < &*n2; - } - - bool operator()(Graph::ConstNodeItr n1, Graph::ConstNodeItr n2) const { - return &*n1 < &*n2; - } - }; - - class EdgeItrCompartor { - public: - bool operator()(Graph::EdgeItr e1, Graph::EdgeItr e2) const { - return &*e1 < &*e2; - } - - bool operator()(Graph::ConstEdgeItr e1, Graph::ConstEdgeItr e2) const { - return &*e1 < &*e2; - } - }; - - void Graph::copyFrom(const Graph &other) { - std::map nodeMap; - - for (Graph::ConstNodeItr nItr = other.nodesBegin(), - nEnd = other.nodesEnd(); - nItr != nEnd; ++nItr) { - nodeMap[nItr] = addNode(other.getNodeCosts(nItr)); - } - - } - -} - -#endif // LLVM_CODEGEN_PBQP_GRAPH_HPP diff --git a/lib/CodeGen/PBQP/HeuristicBase.h b/lib/CodeGen/PBQP/HeuristicBase.h deleted file mode 100644 index 791c227f0d07..000000000000 --- a/lib/CodeGen/PBQP/HeuristicBase.h +++ /dev/null @@ -1,246 +0,0 @@ -//===-- HeuristcBase.h --- Heuristic base class for PBQP --------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CODEGEN_PBQP_HEURISTICBASE_H -#define LLVM_CODEGEN_PBQP_HEURISTICBASE_H - -#include "HeuristicSolver.h" - -namespace PBQP { - - /// \brief Abstract base class for heuristic implementations. - /// - /// This class provides a handy base for heuristic implementations with common - /// solver behaviour implemented for a number of methods. - /// - /// To implement your own heuristic using this class as a base you'll have to - /// implement, as a minimum, the following methods: - ///
        - ///
      • void addToHeuristicList(Graph::NodeItr) : Add a node to the - /// heuristic reduction list. - ///
      • void heuristicReduce() : Perform a single heuristic reduction. - ///
      • void preUpdateEdgeCosts(Graph::EdgeItr) : Handle the (imminent) - /// change to the cost matrix on the given edge (by R2). - ///
      • void postUpdateEdgeCostts(Graph::EdgeItr) : Handle the new - /// costs on the given edge. - ///
      • void handleAddEdge(Graph::EdgeItr) : Handle the addition of a new - /// edge into the PBQP graph (by R2). - ///
      • void handleRemoveEdge(Graph::EdgeItr, Graph::NodeItr) : Handle the - /// disconnection of the given edge from the given node. - ///
      • A constructor for your derived class : to pass back a reference to - /// the solver which is using this heuristic. - ///
      - /// - /// These methods are implemented in this class for documentation purposes, - /// but will assert if called. - /// - /// Note that this class uses the curiously recursive template idiom to - /// forward calls to the derived class. These methods need not be made - /// virtual, and indeed probably shouldn't for performance reasons. - /// - /// You'll also need to provide NodeData and EdgeData structs in your class. - /// These can be used to attach data relevant to your heuristic to each - /// node/edge in the PBQP graph. - - template - class HeuristicBase { - private: - - typedef std::list OptimalList; - - HeuristicSolverImpl &s; - Graph &g; - OptimalList optimalList; - - // Return a reference to the derived heuristic. - HImpl& impl() { return static_cast(*this); } - - // Add the given node to the optimal reductions list. Keep an iterator to - // its location for fast removal. - void addToOptimalReductionList(Graph::NodeItr nItr) { - optimalList.insert(optimalList.end(), nItr); - } - - public: - - /// \brief Construct an instance with a reference to the given solver. - /// @param solver The solver which is using this heuristic instance. - HeuristicBase(HeuristicSolverImpl &solver) - : s(solver), g(s.getGraph()) { } - - /// \brief Get the solver which is using this heuristic instance. - /// @return The solver which is using this heuristic instance. - /// - /// You can use this method to get access to the solver in your derived - /// heuristic implementation. - HeuristicSolverImpl& getSolver() { return s; } - - /// \brief Get the graph representing the problem to be solved. - /// @return The graph representing the problem to be solved. - Graph& getGraph() { return g; } - - /// \brief Tell the solver to simplify the graph before the reduction phase. - /// @return Whether or not the solver should run a simplification phase - /// prior to the main setup and reduction. - /// - /// HeuristicBase returns true from this method as it's a sensible default, - /// however you can over-ride it in your derived class if you want different - /// behaviour. - bool solverRunSimplify() const { return true; } - - /// \brief Decide whether a node should be optimally or heuristically - /// reduced. - /// @return Whether or not the given node should be listed for optimal - /// reduction (via R0, R1 or R2). - /// - /// HeuristicBase returns true for any node with degree less than 3. This is - /// sane and sensible for many situations, but not all. You can over-ride - /// this method in your derived class if you want a different selection - /// criteria. Note however that your criteria for selecting optimal nodes - /// should be at least as strong as this. I.e. Nodes of degree 3 or - /// higher should not be selected under any circumstances. - bool shouldOptimallyReduce(Graph::NodeItr nItr) { - if (g.getNodeDegree(nItr) < 3) - return true; - // else - return false; - } - - /// \brief Add the given node to the list of nodes to be optimally reduced. - /// @return nItr Node iterator to be added. - /// - /// You probably don't want to over-ride this, except perhaps to record - /// statistics before calling this implementation. HeuristicBase relies on - /// its behaviour. - void addToOptimalReduceList(Graph::NodeItr nItr) { - optimalList.push_back(nItr); - } - - /// \brief Initialise the heuristic. - /// - /// HeuristicBase iterates over all nodes in the problem and adds them to - /// the appropriate list using addToOptimalReduceList or - /// addToHeuristicReduceList based on the result of shouldOptimallyReduce. - /// - /// This behaviour should be fine for most situations. - void setup() { - for (Graph::NodeItr nItr = g.nodesBegin(), nEnd = g.nodesEnd(); - nItr != nEnd; ++nItr) { - if (impl().shouldOptimallyReduce(nItr)) { - addToOptimalReduceList(nItr); - } else { - impl().addToHeuristicReduceList(nItr); - } - } - } - - /// \brief Optimally reduce one of the nodes in the optimal reduce list. - /// @return True if a reduction takes place, false if the optimal reduce - /// list is empty. - /// - /// Selects a node from the optimal reduce list and removes it, applying - /// R0, R1 or R2 as appropriate based on the selected node's degree. - bool optimalReduce() { - if (optimalList.empty()) - return false; - - Graph::NodeItr nItr = optimalList.front(); - optimalList.pop_front(); - - switch (s.getSolverDegree(nItr)) { - case 0: s.applyR0(nItr); break; - case 1: s.applyR1(nItr); break; - case 2: s.applyR2(nItr); break; - default: assert(false && - "Optimal reductions of degree > 2 nodes is invalid."); - } - - return true; - } - - /// \brief Perform the PBQP reduction process. - /// - /// Reduces the problem to the empty graph by repeated application of the - /// reduction rules R0, R1, R2 and RN. - /// R0, R1 or R2 are always applied if possible before RN is used. - void reduce() { - bool finished = false; - - while (!finished) { - if (!optimalReduce()) { - if (impl().heuristicReduce()) { - getSolver().recordRN(); - } else { - finished = true; - } - } - } - } - - /// \brief Add a node to the heuristic reduce list. - /// @param nItr Node iterator to add to the heuristic reduce list. - void addToHeuristicList(Graph::NodeItr nItr) { - assert(false && "Must be implemented in derived class."); - } - - /// \brief Heuristically reduce one of the nodes in the heuristic - /// reduce list. - /// @return True if a reduction takes place, false if the heuristic reduce - /// list is empty. - void heuristicReduce() { - assert(false && "Must be implemented in derived class."); - } - - /// \brief Prepare a change in the costs on the given edge. - /// @param eItr Edge iterator. - void preUpdateEdgeCosts(Graph::EdgeItr eItr) { - assert(false && "Must be implemented in derived class."); - } - - /// \brief Handle the change in the costs on the given edge. - /// @param eItr Edge iterator. - void postUpdateEdgeCostts(Graph::EdgeItr eItr) { - assert(false && "Must be implemented in derived class."); - } - - /// \brief Handle the addition of a new edge into the PBQP graph. - /// @param eItr Edge iterator for the added edge. - void handleAddEdge(Graph::EdgeItr eItr) { - assert(false && "Must be implemented in derived class."); - } - - /// \brief Handle disconnection of an edge from a node. - /// @param eItr Edge iterator for edge being disconnected. - /// @param nItr Node iterator for the node being disconnected from. - /// - /// Edges are frequently removed due to the removal of a node. This - /// method allows for the effect to be computed only for the remaining - /// node in the graph. - void handleRemoveEdge(Graph::EdgeItr eItr, Graph::NodeItr nItr) { - assert(false && "Must be implemented in derived class."); - } - - /// \brief Clean up any structures used by HeuristicBase. - /// - /// At present this just performs a sanity check: that the optimal reduce - /// list is empty now that reduction has completed. - /// - /// If your derived class has more complex structures which need tearing - /// down you should over-ride this method but include a call back to this - /// implementation. - void cleanup() { - assert(optimalList.empty() && "Nodes left over in optimal reduce list?"); - } - - }; - -} - - -#endif // LLVM_CODEGEN_PBQP_HEURISTICBASE_H diff --git a/lib/CodeGen/PBQP/HeuristicSolver.h b/lib/CodeGen/PBQP/HeuristicSolver.h deleted file mode 100644 index 35514f967478..000000000000 --- a/lib/CodeGen/PBQP/HeuristicSolver.h +++ /dev/null @@ -1,616 +0,0 @@ -//===-- HeuristicSolver.h - Heuristic PBQP Solver --------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Heuristic PBQP solver. This solver is able to perform optimal reductions for -// nodes of degree 0, 1 or 2. For nodes of degree >2 a plugable heuristic is -// used to select a node for reduction. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CODEGEN_PBQP_HEURISTICSOLVER_H -#define LLVM_CODEGEN_PBQP_HEURISTICSOLVER_H - -#include "Graph.h" -#include "Solution.h" -#include -#include - -namespace PBQP { - - /// \brief Heuristic PBQP solver implementation. - /// - /// This class should usually be created (and destroyed) indirectly via a call - /// to HeuristicSolver::solve(Graph&). - /// See the comments for HeuristicSolver. - /// - /// HeuristicSolverImpl provides the R0, R1 and R2 reduction rules, - /// backpropagation phase, and maintains the internal copy of the graph on - /// which the reduction is carried out (the original being kept to facilitate - /// backpropagation). - template - class HeuristicSolverImpl { - private: - - typedef typename HImpl::NodeData HeuristicNodeData; - typedef typename HImpl::EdgeData HeuristicEdgeData; - - typedef std::list SolverEdges; - - public: - - /// \brief Iterator type for edges in the solver graph. - typedef SolverEdges::iterator SolverEdgeItr; - - private: - - class NodeData { - public: - NodeData() : solverDegree(0) {} - - HeuristicNodeData& getHeuristicData() { return hData; } - - SolverEdgeItr addSolverEdge(Graph::EdgeItr eItr) { - ++solverDegree; - return solverEdges.insert(solverEdges.end(), eItr); - } - - void removeSolverEdge(SolverEdgeItr seItr) { - --solverDegree; - solverEdges.erase(seItr); - } - - SolverEdgeItr solverEdgesBegin() { return solverEdges.begin(); } - SolverEdgeItr solverEdgesEnd() { return solverEdges.end(); } - unsigned getSolverDegree() const { return solverDegree; } - void clearSolverEdges() { - solverDegree = 0; - solverEdges.clear(); - } - - private: - HeuristicNodeData hData; - unsigned solverDegree; - SolverEdges solverEdges; - }; - - class EdgeData { - public: - HeuristicEdgeData& getHeuristicData() { return hData; } - - void setN1SolverEdgeItr(SolverEdgeItr n1SolverEdgeItr) { - this->n1SolverEdgeItr = n1SolverEdgeItr; - } - - SolverEdgeItr getN1SolverEdgeItr() { return n1SolverEdgeItr; } - - void setN2SolverEdgeItr(SolverEdgeItr n2SolverEdgeItr){ - this->n2SolverEdgeItr = n2SolverEdgeItr; - } - - SolverEdgeItr getN2SolverEdgeItr() { return n2SolverEdgeItr; } - - private: - - HeuristicEdgeData hData; - SolverEdgeItr n1SolverEdgeItr, n2SolverEdgeItr; - }; - - Graph &g; - HImpl h; - Solution s; - std::vector stack; - - typedef std::list NodeDataList; - NodeDataList nodeDataList; - - typedef std::list EdgeDataList; - EdgeDataList edgeDataList; - - public: - - /// \brief Construct a heuristic solver implementation to solve the given - /// graph. - /// @param g The graph representing the problem instance to be solved. - HeuristicSolverImpl(Graph &g) : g(g), h(*this) {} - - /// \brief Get the graph being solved by this solver. - /// @return The graph representing the problem instance being solved by this - /// solver. - Graph& getGraph() { return g; } - - /// \brief Get the heuristic data attached to the given node. - /// @param nItr Node iterator. - /// @return The heuristic data attached to the given node. - HeuristicNodeData& getHeuristicNodeData(Graph::NodeItr nItr) { - return getSolverNodeData(nItr).getHeuristicData(); - } - - /// \brief Get the heuristic data attached to the given edge. - /// @param eItr Edge iterator. - /// @return The heuristic data attached to the given node. - HeuristicEdgeData& getHeuristicEdgeData(Graph::EdgeItr eItr) { - return getSolverEdgeData(eItr).getHeuristicData(); - } - - /// \brief Begin iterator for the set of edges adjacent to the given node in - /// the solver graph. - /// @param nItr Node iterator. - /// @return Begin iterator for the set of edges adjacent to the given node - /// in the solver graph. - SolverEdgeItr solverEdgesBegin(Graph::NodeItr nItr) { - return getSolverNodeData(nItr).solverEdgesBegin(); - } - - /// \brief End iterator for the set of edges adjacent to the given node in - /// the solver graph. - /// @param nItr Node iterator. - /// @return End iterator for the set of edges adjacent to the given node in - /// the solver graph. - SolverEdgeItr solverEdgesEnd(Graph::NodeItr nItr) { - return getSolverNodeData(nItr).solverEdgesEnd(); - } - - /// \brief Remove a node from the solver graph. - /// @param eItr Edge iterator for edge to be removed. - /// - /// Does not notify the heuristic of the removal. That should be - /// done manually if necessary. - void removeSolverEdge(Graph::EdgeItr eItr) { - EdgeData &eData = getSolverEdgeData(eItr); - NodeData &n1Data = getSolverNodeData(g.getEdgeNode1(eItr)), - &n2Data = getSolverNodeData(g.getEdgeNode2(eItr)); - - n1Data.removeSolverEdge(eData.getN1SolverEdgeItr()); - n2Data.removeSolverEdge(eData.getN2SolverEdgeItr()); - } - - /// \brief Compute a solution to the PBQP problem instance with which this - /// heuristic solver was constructed. - /// @return A solution to the PBQP problem. - /// - /// Performs the full PBQP heuristic solver algorithm, including setup, - /// calls to the heuristic (which will call back to the reduction rules in - /// this class), and cleanup. - Solution computeSolution() { - setup(); - h.setup(); - h.reduce(); - backpropagate(); - h.cleanup(); - cleanup(); - return s; - } - - /// \brief Add to the end of the stack. - /// @param nItr Node iterator to add to the reduction stack. - void pushToStack(Graph::NodeItr nItr) { - getSolverNodeData(nItr).clearSolverEdges(); - stack.push_back(nItr); - } - - /// \brief Returns the solver degree of the given node. - /// @param nItr Node iterator for which degree is requested. - /// @return Node degree in the solver graph (not the original graph). - unsigned getSolverDegree(Graph::NodeItr nItr) { - return getSolverNodeData(nItr).getSolverDegree(); - } - - /// \brief Set the solution of the given node. - /// @param nItr Node iterator to set solution for. - /// @param selection Selection for node. - void setSolution(const Graph::NodeItr &nItr, unsigned selection) { - s.setSelection(nItr, selection); - - for (Graph::AdjEdgeItr aeItr = g.adjEdgesBegin(nItr), - aeEnd = g.adjEdgesEnd(nItr); - aeItr != aeEnd; ++aeItr) { - Graph::EdgeItr eItr(*aeItr); - Graph::NodeItr anItr(g.getEdgeOtherNode(eItr, nItr)); - getSolverNodeData(anItr).addSolverEdge(eItr); - } - } - - /// \brief Apply rule R0. - /// @param nItr Node iterator for node to apply R0 to. - /// - /// Node will be automatically pushed to the solver stack. - void applyR0(Graph::NodeItr nItr) { - assert(getSolverNodeData(nItr).getSolverDegree() == 0 && - "R0 applied to node with degree != 0."); - - // Nothing to do. Just push the node onto the reduction stack. - pushToStack(nItr); - - s.recordR0(); - } - - /// \brief Apply rule R1. - /// @param xnItr Node iterator for node to apply R1 to. - /// - /// Node will be automatically pushed to the solver stack. - void applyR1(Graph::NodeItr xnItr) { - NodeData &nd = getSolverNodeData(xnItr); - assert(nd.getSolverDegree() == 1 && - "R1 applied to node with degree != 1."); - - Graph::EdgeItr eItr = *nd.solverEdgesBegin(); - - const Matrix &eCosts = g.getEdgeCosts(eItr); - const Vector &xCosts = g.getNodeCosts(xnItr); - - // Duplicate a little to avoid transposing matrices. - if (xnItr == g.getEdgeNode1(eItr)) { - Graph::NodeItr ynItr = g.getEdgeNode2(eItr); - Vector &yCosts = g.getNodeCosts(ynItr); - for (unsigned j = 0; j < yCosts.getLength(); ++j) { - PBQPNum min = eCosts[0][j] + xCosts[0]; - for (unsigned i = 1; i < xCosts.getLength(); ++i) { - PBQPNum c = eCosts[i][j] + xCosts[i]; - if (c < min) - min = c; - } - yCosts[j] += min; - } - h.handleRemoveEdge(eItr, ynItr); - } else { - Graph::NodeItr ynItr = g.getEdgeNode1(eItr); - Vector &yCosts = g.getNodeCosts(ynItr); - for (unsigned i = 0; i < yCosts.getLength(); ++i) { - PBQPNum min = eCosts[i][0] + xCosts[0]; - for (unsigned j = 1; j < xCosts.getLength(); ++j) { - PBQPNum c = eCosts[i][j] + xCosts[j]; - if (c < min) - min = c; - } - yCosts[i] += min; - } - h.handleRemoveEdge(eItr, ynItr); - } - removeSolverEdge(eItr); - assert(nd.getSolverDegree() == 0 && - "Degree 1 with edge removed should be 0."); - pushToStack(xnItr); - s.recordR1(); - } - - /// \brief Apply rule R2. - /// @param xnItr Node iterator for node to apply R2 to. - /// - /// Node will be automatically pushed to the solver stack. - void applyR2(Graph::NodeItr xnItr) { - assert(getSolverNodeData(xnItr).getSolverDegree() == 2 && - "R2 applied to node with degree != 2."); - - NodeData &nd = getSolverNodeData(xnItr); - const Vector &xCosts = g.getNodeCosts(xnItr); - - SolverEdgeItr aeItr = nd.solverEdgesBegin(); - Graph::EdgeItr yxeItr = *aeItr, - zxeItr = *(++aeItr); - - Graph::NodeItr ynItr = g.getEdgeOtherNode(yxeItr, xnItr), - znItr = g.getEdgeOtherNode(zxeItr, xnItr); - - bool flipEdge1 = (g.getEdgeNode1(yxeItr) == xnItr), - flipEdge2 = (g.getEdgeNode1(zxeItr) == xnItr); - - const Matrix *yxeCosts = flipEdge1 ? - new Matrix(g.getEdgeCosts(yxeItr).transpose()) : - &g.getEdgeCosts(yxeItr); - - const Matrix *zxeCosts = flipEdge2 ? - new Matrix(g.getEdgeCosts(zxeItr).transpose()) : - &g.getEdgeCosts(zxeItr); - - unsigned xLen = xCosts.getLength(), - yLen = yxeCosts->getRows(), - zLen = zxeCosts->getRows(); - - Matrix delta(yLen, zLen); - - for (unsigned i = 0; i < yLen; ++i) { - for (unsigned j = 0; j < zLen; ++j) { - PBQPNum min = (*yxeCosts)[i][0] + (*zxeCosts)[j][0] + xCosts[0]; - for (unsigned k = 1; k < xLen; ++k) { - PBQPNum c = (*yxeCosts)[i][k] + (*zxeCosts)[j][k] + xCosts[k]; - if (c < min) { - min = c; - } - } - delta[i][j] = min; - } - } - - if (flipEdge1) - delete yxeCosts; - - if (flipEdge2) - delete zxeCosts; - - Graph::EdgeItr yzeItr = g.findEdge(ynItr, znItr); - bool addedEdge = false; - - if (yzeItr == g.edgesEnd()) { - yzeItr = g.addEdge(ynItr, znItr, delta); - addedEdge = true; - } else { - Matrix &yzeCosts = g.getEdgeCosts(yzeItr); - h.preUpdateEdgeCosts(yzeItr); - if (ynItr == g.getEdgeNode1(yzeItr)) { - yzeCosts += delta; - } else { - yzeCosts += delta.transpose(); - } - } - - bool nullCostEdge = tryNormaliseEdgeMatrix(yzeItr); - - if (!addedEdge) { - // If we modified the edge costs let the heuristic know. - h.postUpdateEdgeCosts(yzeItr); - } - - if (nullCostEdge) { - // If this edge ended up null remove it. - if (!addedEdge) { - // We didn't just add it, so we need to notify the heuristic - // and remove it from the solver. - h.handleRemoveEdge(yzeItr, ynItr); - h.handleRemoveEdge(yzeItr, znItr); - removeSolverEdge(yzeItr); - } - g.removeEdge(yzeItr); - } else if (addedEdge) { - // If the edge was added, and non-null, finish setting it up, add it to - // the solver & notify heuristic. - edgeDataList.push_back(EdgeData()); - g.setEdgeData(yzeItr, &edgeDataList.back()); - addSolverEdge(yzeItr); - h.handleAddEdge(yzeItr); - } - - h.handleRemoveEdge(yxeItr, ynItr); - removeSolverEdge(yxeItr); - h.handleRemoveEdge(zxeItr, znItr); - removeSolverEdge(zxeItr); - - pushToStack(xnItr); - s.recordR2(); - } - - /// \brief Record an application of the RN rule. - /// - /// For use by the HeuristicBase. - void recordRN() { s.recordRN(); } - - private: - - NodeData& getSolverNodeData(Graph::NodeItr nItr) { - return *static_cast(g.getNodeData(nItr)); - } - - EdgeData& getSolverEdgeData(Graph::EdgeItr eItr) { - return *static_cast(g.getEdgeData(eItr)); - } - - void addSolverEdge(Graph::EdgeItr eItr) { - EdgeData &eData = getSolverEdgeData(eItr); - NodeData &n1Data = getSolverNodeData(g.getEdgeNode1(eItr)), - &n2Data = getSolverNodeData(g.getEdgeNode2(eItr)); - - eData.setN1SolverEdgeItr(n1Data.addSolverEdge(eItr)); - eData.setN2SolverEdgeItr(n2Data.addSolverEdge(eItr)); - } - - void setup() { - if (h.solverRunSimplify()) { - simplify(); - } - - // Create node data objects. - for (Graph::NodeItr nItr = g.nodesBegin(), nEnd = g.nodesEnd(); - nItr != nEnd; ++nItr) { - nodeDataList.push_back(NodeData()); - g.setNodeData(nItr, &nodeDataList.back()); - } - - // Create edge data objects. - for (Graph::EdgeItr eItr = g.edgesBegin(), eEnd = g.edgesEnd(); - eItr != eEnd; ++eItr) { - edgeDataList.push_back(EdgeData()); - g.setEdgeData(eItr, &edgeDataList.back()); - addSolverEdge(eItr); - } - } - - void simplify() { - disconnectTrivialNodes(); - eliminateIndependentEdges(); - } - - // Eliminate trivial nodes. - void disconnectTrivialNodes() { - unsigned numDisconnected = 0; - - for (Graph::NodeItr nItr = g.nodesBegin(), nEnd = g.nodesEnd(); - nItr != nEnd; ++nItr) { - - if (g.getNodeCosts(nItr).getLength() == 1) { - - std::vector edgesToRemove; - - for (Graph::AdjEdgeItr aeItr = g.adjEdgesBegin(nItr), - aeEnd = g.adjEdgesEnd(nItr); - aeItr != aeEnd; ++aeItr) { - - Graph::EdgeItr eItr = *aeItr; - - if (g.getEdgeNode1(eItr) == nItr) { - Graph::NodeItr otherNodeItr = g.getEdgeNode2(eItr); - g.getNodeCosts(otherNodeItr) += - g.getEdgeCosts(eItr).getRowAsVector(0); - } - else { - Graph::NodeItr otherNodeItr = g.getEdgeNode1(eItr); - g.getNodeCosts(otherNodeItr) += - g.getEdgeCosts(eItr).getColAsVector(0); - } - - edgesToRemove.push_back(eItr); - } - - if (!edgesToRemove.empty()) - ++numDisconnected; - - while (!edgesToRemove.empty()) { - g.removeEdge(edgesToRemove.back()); - edgesToRemove.pop_back(); - } - } - } - } - - void eliminateIndependentEdges() { - std::vector edgesToProcess; - unsigned numEliminated = 0; - - for (Graph::EdgeItr eItr = g.edgesBegin(), eEnd = g.edgesEnd(); - eItr != eEnd; ++eItr) { - edgesToProcess.push_back(eItr); - } - - while (!edgesToProcess.empty()) { - if (tryToEliminateEdge(edgesToProcess.back())) - ++numEliminated; - edgesToProcess.pop_back(); - } - } - - bool tryToEliminateEdge(Graph::EdgeItr eItr) { - if (tryNormaliseEdgeMatrix(eItr)) { - g.removeEdge(eItr); - return true; - } - return false; - } - - bool tryNormaliseEdgeMatrix(Graph::EdgeItr &eItr) { - - const PBQPNum infinity = std::numeric_limits::infinity(); - - Matrix &edgeCosts = g.getEdgeCosts(eItr); - Vector &uCosts = g.getNodeCosts(g.getEdgeNode1(eItr)), - &vCosts = g.getNodeCosts(g.getEdgeNode2(eItr)); - - for (unsigned r = 0; r < edgeCosts.getRows(); ++r) { - PBQPNum rowMin = infinity; - - for (unsigned c = 0; c < edgeCosts.getCols(); ++c) { - if (vCosts[c] != infinity && edgeCosts[r][c] < rowMin) - rowMin = edgeCosts[r][c]; - } - - uCosts[r] += rowMin; - - if (rowMin != infinity) { - edgeCosts.subFromRow(r, rowMin); - } - else { - edgeCosts.setRow(r, 0); - } - } - - for (unsigned c = 0; c < edgeCosts.getCols(); ++c) { - PBQPNum colMin = infinity; - - for (unsigned r = 0; r < edgeCosts.getRows(); ++r) { - if (uCosts[r] != infinity && edgeCosts[r][c] < colMin) - colMin = edgeCosts[r][c]; - } - - vCosts[c] += colMin; - - if (colMin != infinity) { - edgeCosts.subFromCol(c, colMin); - } - else { - edgeCosts.setCol(c, 0); - } - } - - return edgeCosts.isZero(); - } - - void backpropagate() { - while (!stack.empty()) { - computeSolution(stack.back()); - stack.pop_back(); - } - } - - void computeSolution(Graph::NodeItr nItr) { - - NodeData &nodeData = getSolverNodeData(nItr); - - Vector v(g.getNodeCosts(nItr)); - - // Solve based on existing solved edges. - for (SolverEdgeItr solvedEdgeItr = nodeData.solverEdgesBegin(), - solvedEdgeEnd = nodeData.solverEdgesEnd(); - solvedEdgeItr != solvedEdgeEnd; ++solvedEdgeItr) { - - Graph::EdgeItr eItr(*solvedEdgeItr); - Matrix &edgeCosts = g.getEdgeCosts(eItr); - - if (nItr == g.getEdgeNode1(eItr)) { - Graph::NodeItr adjNode(g.getEdgeNode2(eItr)); - unsigned adjSolution = s.getSelection(adjNode); - v += edgeCosts.getColAsVector(adjSolution); - } - else { - Graph::NodeItr adjNode(g.getEdgeNode1(eItr)); - unsigned adjSolution = s.getSelection(adjNode); - v += edgeCosts.getRowAsVector(adjSolution); - } - - } - - setSolution(nItr, v.minIndex()); - } - - void cleanup() { - h.cleanup(); - nodeDataList.clear(); - edgeDataList.clear(); - } - }; - - /// \brief PBQP heuristic solver class. - /// - /// Given a PBQP Graph g representing a PBQP problem, you can find a solution - /// by calling - /// Solution s = HeuristicSolver::solve(g); - /// - /// The choice of heuristic for the H parameter will affect both the solver - /// speed and solution quality. The heuristic should be chosen based on the - /// nature of the problem being solved. - /// Currently the only solver included with LLVM is the Briggs heuristic for - /// register allocation. - template - class HeuristicSolver { - public: - static Solution solve(Graph &g) { - HeuristicSolverImpl hs(g); - return hs.computeSolution(); - } - }; - -} - -#endif // LLVM_CODEGEN_PBQP_HEURISTICSOLVER_H diff --git a/lib/CodeGen/PBQP/Heuristics/Briggs.h b/lib/CodeGen/PBQP/Heuristics/Briggs.h deleted file mode 100644 index 18eaf7c0da9b..000000000000 --- a/lib/CodeGen/PBQP/Heuristics/Briggs.h +++ /dev/null @@ -1,460 +0,0 @@ -//===-- Briggs.h --- Briggs Heuristic for PBQP ------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This class implements the Briggs test for "allocability" of nodes in a -// PBQP graph representing a register allocation problem. Nodes which can be -// proven allocable (by a safe and relatively accurate test) are removed from -// the PBQP graph first. If no provably allocable node is present in the graph -// then the node with the minimal spill-cost to degree ratio is removed. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H -#define LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H - -#include "../HeuristicSolver.h" -#include "../HeuristicBase.h" - -#include -#include - -namespace PBQP { - namespace Heuristics { - - /// \brief PBQP Heuristic which applies an allocability test based on - /// Briggs. - /// - /// This heuristic assumes that the elements of cost vectors in the PBQP - /// problem represent storage options, with the first being the spill - /// option and subsequent elements representing legal registers for the - /// corresponding node. Edge cost matrices are likewise assumed to represent - /// register constraints. - /// If one or more nodes can be proven allocable by this heuristic (by - /// inspection of their constraint matrices) then the allocable node of - /// highest degree is selected for the next reduction and pushed to the - /// solver stack. If no nodes can be proven allocable then the node with - /// the lowest estimated spill cost is selected and push to the solver stack - /// instead. - /// - /// This implementation is built on top of HeuristicBase. - class Briggs : public HeuristicBase { - private: - - class LinkDegreeComparator { - public: - LinkDegreeComparator(HeuristicSolverImpl &s) : s(&s) {} - bool operator()(Graph::NodeItr n1Itr, Graph::NodeItr n2Itr) const { - if (s->getSolverDegree(n1Itr) > s->getSolverDegree(n2Itr)) - return true; - return false; - } - private: - HeuristicSolverImpl *s; - }; - - class SpillCostComparator { - public: - SpillCostComparator(HeuristicSolverImpl &s) - : s(&s), g(&s.getGraph()) {} - bool operator()(Graph::NodeItr n1Itr, Graph::NodeItr n2Itr) const { - PBQPNum cost1 = g->getNodeCosts(n1Itr)[0] / s->getSolverDegree(n1Itr), - cost2 = g->getNodeCosts(n2Itr)[0] / s->getSolverDegree(n2Itr); - if (cost1 < cost2) - return true; - return false; - } - - private: - HeuristicSolverImpl *s; - Graph *g; - }; - - typedef std::list RNAllocableList; - typedef RNAllocableList::iterator RNAllocableListItr; - - typedef std::list RNUnallocableList; - typedef RNUnallocableList::iterator RNUnallocableListItr; - - public: - - struct NodeData { - typedef std::vector UnsafeDegreesArray; - bool isHeuristic, isAllocable, isInitialized; - unsigned numDenied, numSafe; - UnsafeDegreesArray unsafeDegrees; - RNAllocableListItr rnaItr; - RNUnallocableListItr rnuItr; - - NodeData() - : isHeuristic(false), isAllocable(false), isInitialized(false), - numDenied(0), numSafe(0) { } - }; - - struct EdgeData { - typedef std::vector UnsafeArray; - unsigned worst, reverseWorst; - UnsafeArray unsafe, reverseUnsafe; - bool isUpToDate; - - EdgeData() : worst(0), reverseWorst(0), isUpToDate(false) {} - }; - - /// \brief Construct an instance of the Briggs heuristic. - /// @param solver A reference to the solver which is using this heuristic. - Briggs(HeuristicSolverImpl &solver) : - HeuristicBase(solver) {} - - /// \brief Determine whether a node should be reduced using optimal - /// reduction. - /// @param nItr Node iterator to be considered. - /// @return True if the given node should be optimally reduced, false - /// otherwise. - /// - /// Selects nodes of degree 0, 1 or 2 for optimal reduction, with one - /// exception. Nodes whose spill cost (element 0 of their cost vector) is - /// infinite are checked for allocability first. Allocable nodes may be - /// optimally reduced, but nodes whose allocability cannot be proven are - /// selected for heuristic reduction instead. - bool shouldOptimallyReduce(Graph::NodeItr nItr) { - if (getSolver().getSolverDegree(nItr) < 3) { - return true; - } - // else - return false; - } - - /// \brief Add a node to the heuristic reduce list. - /// @param nItr Node iterator to add to the heuristic reduce list. - void addToHeuristicReduceList(Graph::NodeItr nItr) { - NodeData &nd = getHeuristicNodeData(nItr); - initializeNode(nItr); - nd.isHeuristic = true; - if (nd.isAllocable) { - nd.rnaItr = rnAllocableList.insert(rnAllocableList.end(), nItr); - } else { - nd.rnuItr = rnUnallocableList.insert(rnUnallocableList.end(), nItr); - } - } - - /// \brief Heuristically reduce one of the nodes in the heuristic - /// reduce list. - /// @return True if a reduction takes place, false if the heuristic reduce - /// list is empty. - /// - /// If the list of allocable nodes is non-empty a node is selected - /// from it and pushed to the stack. Otherwise if the non-allocable list - /// is non-empty a node is selected from it and pushed to the stack. - /// If both lists are empty the method simply returns false with no action - /// taken. - bool heuristicReduce() { - if (!rnAllocableList.empty()) { - RNAllocableListItr rnaItr = - min_element(rnAllocableList.begin(), rnAllocableList.end(), - LinkDegreeComparator(getSolver())); - Graph::NodeItr nItr = *rnaItr; - rnAllocableList.erase(rnaItr); - handleRemoveNode(nItr); - getSolver().pushToStack(nItr); - return true; - } else if (!rnUnallocableList.empty()) { - RNUnallocableListItr rnuItr = - min_element(rnUnallocableList.begin(), rnUnallocableList.end(), - SpillCostComparator(getSolver())); - Graph::NodeItr nItr = *rnuItr; - rnUnallocableList.erase(rnuItr); - handleRemoveNode(nItr); - getSolver().pushToStack(nItr); - return true; - } - // else - return false; - } - - /// \brief Prepare a change in the costs on the given edge. - /// @param eItr Edge iterator. - void preUpdateEdgeCosts(Graph::EdgeItr eItr) { - Graph &g = getGraph(); - Graph::NodeItr n1Itr = g.getEdgeNode1(eItr), - n2Itr = g.getEdgeNode2(eItr); - NodeData &n1 = getHeuristicNodeData(n1Itr), - &n2 = getHeuristicNodeData(n2Itr); - - if (n1.isHeuristic) - subtractEdgeContributions(eItr, getGraph().getEdgeNode1(eItr)); - if (n2.isHeuristic) - subtractEdgeContributions(eItr, getGraph().getEdgeNode2(eItr)); - - EdgeData &ed = getHeuristicEdgeData(eItr); - ed.isUpToDate = false; - } - - /// \brief Handle the change in the costs on the given edge. - /// @param eItr Edge iterator. - void postUpdateEdgeCosts(Graph::EdgeItr eItr) { - // This is effectively the same as adding a new edge now, since - // we've factored out the costs of the old one. - handleAddEdge(eItr); - } - - /// \brief Handle the addition of a new edge into the PBQP graph. - /// @param eItr Edge iterator for the added edge. - /// - /// Updates allocability of any nodes connected by this edge which are - /// being managed by the heuristic. If allocability changes they are - /// moved to the appropriate list. - void handleAddEdge(Graph::EdgeItr eItr) { - Graph &g = getGraph(); - Graph::NodeItr n1Itr = g.getEdgeNode1(eItr), - n2Itr = g.getEdgeNode2(eItr); - NodeData &n1 = getHeuristicNodeData(n1Itr), - &n2 = getHeuristicNodeData(n2Itr); - - // If neither node is managed by the heuristic there's nothing to be - // done. - if (!n1.isHeuristic && !n2.isHeuristic) - return; - - // Ok - we need to update at least one node. - computeEdgeContributions(eItr); - - // Update node 1 if it's managed by the heuristic. - if (n1.isHeuristic) { - bool n1WasAllocable = n1.isAllocable; - addEdgeContributions(eItr, n1Itr); - updateAllocability(n1Itr); - if (n1WasAllocable && !n1.isAllocable) { - rnAllocableList.erase(n1.rnaItr); - n1.rnuItr = - rnUnallocableList.insert(rnUnallocableList.end(), n1Itr); - } - } - - // Likewise for node 2. - if (n2.isHeuristic) { - bool n2WasAllocable = n2.isAllocable; - addEdgeContributions(eItr, n2Itr); - updateAllocability(n2Itr); - if (n2WasAllocable && !n2.isAllocable) { - rnAllocableList.erase(n2.rnaItr); - n2.rnuItr = - rnUnallocableList.insert(rnUnallocableList.end(), n2Itr); - } - } - } - - /// \brief Handle disconnection of an edge from a node. - /// @param eItr Edge iterator for edge being disconnected. - /// @param nItr Node iterator for the node being disconnected from. - /// - /// Updates allocability of the given node and, if appropriate, moves the - /// node to a new list. - void handleRemoveEdge(Graph::EdgeItr eItr, Graph::NodeItr nItr) { - NodeData &nd = getHeuristicNodeData(nItr); - - // If the node is not managed by the heuristic there's nothing to be - // done. - if (!nd.isHeuristic) - return; - - EdgeData &ed = getHeuristicEdgeData(eItr); - (void)ed; - assert(ed.isUpToDate && "Edge data is not up to date."); - - // Update node. - bool ndWasAllocable = nd.isAllocable; - subtractEdgeContributions(eItr, nItr); - updateAllocability(nItr); - - // If the node has gone optimal... - if (shouldOptimallyReduce(nItr)) { - nd.isHeuristic = false; - addToOptimalReduceList(nItr); - if (ndWasAllocable) { - rnAllocableList.erase(nd.rnaItr); - } else { - rnUnallocableList.erase(nd.rnuItr); - } - } else { - // Node didn't go optimal, but we might have to move it - // from "unallocable" to "allocable". - if (!ndWasAllocable && nd.isAllocable) { - rnUnallocableList.erase(nd.rnuItr); - nd.rnaItr = rnAllocableList.insert(rnAllocableList.end(), nItr); - } - } - } - - private: - - NodeData& getHeuristicNodeData(Graph::NodeItr nItr) { - return getSolver().getHeuristicNodeData(nItr); - } - - EdgeData& getHeuristicEdgeData(Graph::EdgeItr eItr) { - return getSolver().getHeuristicEdgeData(eItr); - } - - // Work out what this edge will contribute to the allocability of the - // nodes connected to it. - void computeEdgeContributions(Graph::EdgeItr eItr) { - EdgeData &ed = getHeuristicEdgeData(eItr); - - if (ed.isUpToDate) - return; // Edge data is already up to date. - - Matrix &eCosts = getGraph().getEdgeCosts(eItr); - - unsigned numRegs = eCosts.getRows() - 1, - numReverseRegs = eCosts.getCols() - 1; - - std::vector rowInfCounts(numRegs, 0), - colInfCounts(numReverseRegs, 0); - - ed.worst = 0; - ed.reverseWorst = 0; - ed.unsafe.clear(); - ed.unsafe.resize(numRegs, 0); - ed.reverseUnsafe.clear(); - ed.reverseUnsafe.resize(numReverseRegs, 0); - - for (unsigned i = 0; i < numRegs; ++i) { - for (unsigned j = 0; j < numReverseRegs; ++j) { - if (eCosts[i + 1][j + 1] == - std::numeric_limits::infinity()) { - ed.unsafe[i] = 1; - ed.reverseUnsafe[j] = 1; - ++rowInfCounts[i]; - ++colInfCounts[j]; - - if (colInfCounts[j] > ed.worst) { - ed.worst = colInfCounts[j]; - } - - if (rowInfCounts[i] > ed.reverseWorst) { - ed.reverseWorst = rowInfCounts[i]; - } - } - } - } - - ed.isUpToDate = true; - } - - // Add the contributions of the given edge to the given node's - // numDenied and safe members. No action is taken other than to update - // these member values. Once updated these numbers can be used by clients - // to update the node's allocability. - void addEdgeContributions(Graph::EdgeItr eItr, Graph::NodeItr nItr) { - EdgeData &ed = getHeuristicEdgeData(eItr); - - assert(ed.isUpToDate && "Using out-of-date edge numbers."); - - NodeData &nd = getHeuristicNodeData(nItr); - unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1; - - bool nIsNode1 = nItr == getGraph().getEdgeNode1(eItr); - EdgeData::UnsafeArray &unsafe = - nIsNode1 ? ed.unsafe : ed.reverseUnsafe; - nd.numDenied += nIsNode1 ? ed.worst : ed.reverseWorst; - - for (unsigned r = 0; r < numRegs; ++r) { - if (unsafe[r]) { - if (nd.unsafeDegrees[r]==0) { - --nd.numSafe; - } - ++nd.unsafeDegrees[r]; - } - } - } - - // Subtract the contributions of the given edge to the given node's - // numDenied and safe members. No action is taken other than to update - // these member values. Once updated these numbers can be used by clients - // to update the node's allocability. - void subtractEdgeContributions(Graph::EdgeItr eItr, Graph::NodeItr nItr) { - EdgeData &ed = getHeuristicEdgeData(eItr); - - assert(ed.isUpToDate && "Using out-of-date edge numbers."); - - NodeData &nd = getHeuristicNodeData(nItr); - unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1; - - bool nIsNode1 = nItr == getGraph().getEdgeNode1(eItr); - EdgeData::UnsafeArray &unsafe = - nIsNode1 ? ed.unsafe : ed.reverseUnsafe; - nd.numDenied -= nIsNode1 ? ed.worst : ed.reverseWorst; - - for (unsigned r = 0; r < numRegs; ++r) { - if (unsafe[r]) { - if (nd.unsafeDegrees[r] == 1) { - ++nd.numSafe; - } - --nd.unsafeDegrees[r]; - } - } - } - - void updateAllocability(Graph::NodeItr nItr) { - NodeData &nd = getHeuristicNodeData(nItr); - unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1; - nd.isAllocable = nd.numDenied < numRegs || nd.numSafe > 0; - } - - void initializeNode(Graph::NodeItr nItr) { - NodeData &nd = getHeuristicNodeData(nItr); - - if (nd.isInitialized) - return; // Node data is already up to date. - - unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1; - - nd.numDenied = 0; - nd.numSafe = numRegs; - nd.unsafeDegrees.resize(numRegs, 0); - - typedef HeuristicSolverImpl::SolverEdgeItr SolverEdgeItr; - - for (SolverEdgeItr aeItr = getSolver().solverEdgesBegin(nItr), - aeEnd = getSolver().solverEdgesEnd(nItr); - aeItr != aeEnd; ++aeItr) { - - Graph::EdgeItr eItr = *aeItr; - computeEdgeContributions(eItr); - addEdgeContributions(eItr, nItr); - } - - updateAllocability(nItr); - nd.isInitialized = true; - } - - void handleRemoveNode(Graph::NodeItr xnItr) { - typedef HeuristicSolverImpl::SolverEdgeItr SolverEdgeItr; - std::vector edgesToRemove; - for (SolverEdgeItr aeItr = getSolver().solverEdgesBegin(xnItr), - aeEnd = getSolver().solverEdgesEnd(xnItr); - aeItr != aeEnd; ++aeItr) { - Graph::NodeItr ynItr = getGraph().getEdgeOtherNode(*aeItr, xnItr); - handleRemoveEdge(*aeItr, ynItr); - edgesToRemove.push_back(*aeItr); - } - while (!edgesToRemove.empty()) { - getSolver().removeSolverEdge(edgesToRemove.back()); - edgesToRemove.pop_back(); - } - } - - RNAllocableList rnAllocableList; - RNUnallocableList rnUnallocableList; - }; - - } -} - - -#endif // LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H diff --git a/lib/CodeGen/PBQP/Math.h b/lib/CodeGen/PBQP/Math.h deleted file mode 100644 index e7598bf3e3f1..000000000000 --- a/lib/CodeGen/PBQP/Math.h +++ /dev/null @@ -1,288 +0,0 @@ -//===------ Math.h - PBQP Vector and Matrix classes -------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CODEGEN_PBQP_MATH_H -#define LLVM_CODEGEN_PBQP_MATH_H - -#include -#include -#include - -namespace PBQP { - -typedef float PBQPNum; - -/// \brief PBQP Vector class. -class Vector { - public: - - /// \brief Construct a PBQP vector of the given size. - explicit Vector(unsigned length) : - length(length), data(new PBQPNum[length]) { - } - - /// \brief Construct a PBQP vector with initializer. - Vector(unsigned length, PBQPNum initVal) : - length(length), data(new PBQPNum[length]) { - std::fill(data, data + length, initVal); - } - - /// \brief Copy construct a PBQP vector. - Vector(const Vector &v) : - length(v.length), data(new PBQPNum[length]) { - std::copy(v.data, v.data + length, data); - } - - /// \brief Destroy this vector, return its memory. - ~Vector() { delete[] data; } - - /// \brief Assignment operator. - Vector& operator=(const Vector &v) { - delete[] data; - length = v.length; - data = new PBQPNum[length]; - std::copy(v.data, v.data + length, data); - return *this; - } - - /// \brief Return the length of the vector - unsigned getLength() const { - return length; - } - - /// \brief Element access. - PBQPNum& operator[](unsigned index) { - assert(index < length && "Vector element access out of bounds."); - return data[index]; - } - - /// \brief Const element access. - const PBQPNum& operator[](unsigned index) const { - assert(index < length && "Vector element access out of bounds."); - return data[index]; - } - - /// \brief Add another vector to this one. - Vector& operator+=(const Vector &v) { - assert(length == v.length && "Vector length mismatch."); - std::transform(data, data + length, v.data, data, std::plus()); - return *this; - } - - /// \brief Subtract another vector from this one. - Vector& operator-=(const Vector &v) { - assert(length == v.length && "Vector length mismatch."); - std::transform(data, data + length, v.data, data, std::minus()); - return *this; - } - - /// \brief Returns the index of the minimum value in this vector - unsigned minIndex() const { - return std::min_element(data, data + length) - data; - } - - private: - unsigned length; - PBQPNum *data; -}; - -/// \brief Output a textual representation of the given vector on the given -/// output stream. -template -OStream& operator<<(OStream &os, const Vector &v) { - assert((v.getLength() != 0) && "Zero-length vector badness."); - - os << "[ " << v[0]; - for (unsigned i = 1; i < v.getLength(); ++i) { - os << ", " << v[i]; - } - os << " ]"; - - return os; -} - - -/// \brief PBQP Matrix class -class Matrix { - public: - - /// \brief Construct a PBQP Matrix with the given dimensions. - Matrix(unsigned rows, unsigned cols) : - rows(rows), cols(cols), data(new PBQPNum[rows * cols]) { - } - - /// \brief Construct a PBQP Matrix with the given dimensions and initial - /// value. - Matrix(unsigned rows, unsigned cols, PBQPNum initVal) : - rows(rows), cols(cols), data(new PBQPNum[rows * cols]) { - std::fill(data, data + (rows * cols), initVal); - } - - /// \brief Copy construct a PBQP matrix. - Matrix(const Matrix &m) : - rows(m.rows), cols(m.cols), data(new PBQPNum[rows * cols]) { - std::copy(m.data, m.data + (rows * cols), data); - } - - /// \brief Destroy this matrix, return its memory. - ~Matrix() { delete[] data; } - - /// \brief Assignment operator. - Matrix& operator=(const Matrix &m) { - delete[] data; - rows = m.rows; cols = m.cols; - data = new PBQPNum[rows * cols]; - std::copy(m.data, m.data + (rows * cols), data); - return *this; - } - - /// \brief Return the number of rows in this matrix. - unsigned getRows() const { return rows; } - - /// \brief Return the number of cols in this matrix. - unsigned getCols() const { return cols; } - - /// \brief Matrix element access. - PBQPNum* operator[](unsigned r) { - assert(r < rows && "Row out of bounds."); - return data + (r * cols); - } - - /// \brief Matrix element access. - const PBQPNum* operator[](unsigned r) const { - assert(r < rows && "Row out of bounds."); - return data + (r * cols); - } - - /// \brief Returns the given row as a vector. - Vector getRowAsVector(unsigned r) const { - Vector v(cols); - for (unsigned c = 0; c < cols; ++c) - v[c] = (*this)[r][c]; - return v; - } - - /// \brief Returns the given column as a vector. - Vector getColAsVector(unsigned c) const { - Vector v(rows); - for (unsigned r = 0; r < rows; ++r) - v[r] = (*this)[r][c]; - return v; - } - - /// \brief Reset the matrix to the given value. - Matrix& reset(PBQPNum val = 0) { - std::fill(data, data + (rows * cols), val); - return *this; - } - - /// \brief Set a single row of this matrix to the given value. - Matrix& setRow(unsigned r, PBQPNum val) { - assert(r < rows && "Row out of bounds."); - std::fill(data + (r * cols), data + ((r + 1) * cols), val); - return *this; - } - - /// \brief Set a single column of this matrix to the given value. - Matrix& setCol(unsigned c, PBQPNum val) { - assert(c < cols && "Column out of bounds."); - for (unsigned r = 0; r < rows; ++r) - (*this)[r][c] = val; - return *this; - } - - /// \brief Matrix transpose. - Matrix transpose() const { - Matrix m(cols, rows); - for (unsigned r = 0; r < rows; ++r) - for (unsigned c = 0; c < cols; ++c) - m[c][r] = (*this)[r][c]; - return m; - } - - /// \brief Returns the diagonal of the matrix as a vector. - /// - /// Matrix must be square. - Vector diagonalize() const { - assert(rows == cols && "Attempt to diagonalize non-square matrix."); - - Vector v(rows); - for (unsigned r = 0; r < rows; ++r) - v[r] = (*this)[r][r]; - return v; - } - - /// \brief Add the given matrix to this one. - Matrix& operator+=(const Matrix &m) { - assert(rows == m.rows && cols == m.cols && - "Matrix dimensions mismatch."); - std::transform(data, data + (rows * cols), m.data, data, - std::plus()); - return *this; - } - - /// \brief Returns the minimum of the given row - PBQPNum getRowMin(unsigned r) const { - assert(r < rows && "Row out of bounds"); - return *std::min_element(data + (r * cols), data + ((r + 1) * cols)); - } - - /// \brief Returns the minimum of the given column - PBQPNum getColMin(unsigned c) const { - PBQPNum minElem = (*this)[0][c]; - for (unsigned r = 1; r < rows; ++r) - if ((*this)[r][c] < minElem) minElem = (*this)[r][c]; - return minElem; - } - - /// \brief Subtracts the given scalar from the elements of the given row. - Matrix& subFromRow(unsigned r, PBQPNum val) { - assert(r < rows && "Row out of bounds"); - std::transform(data + (r * cols), data + ((r + 1) * cols), - data + (r * cols), - std::bind2nd(std::minus(), val)); - return *this; - } - - /// \brief Subtracts the given scalar from the elements of the given column. - Matrix& subFromCol(unsigned c, PBQPNum val) { - for (unsigned r = 0; r < rows; ++r) - (*this)[r][c] -= val; - return *this; - } - - /// \brief Returns true if this is a zero matrix. - bool isZero() const { - return find_if(data, data + (rows * cols), - std::bind2nd(std::not_equal_to(), 0)) == - data + (rows * cols); - } - - private: - unsigned rows, cols; - PBQPNum *data; -}; - -/// \brief Output a textual representation of the given matrix on the given -/// output stream. -template -OStream& operator<<(OStream &os, const Matrix &m) { - - assert((m.getRows() != 0) && "Zero-row matrix badness."); - - for (unsigned i = 0; i < m.getRows(); ++i) { - os << m.getRowAsVector(i); - } - - return os; -} - -} - -#endif // LLVM_CODEGEN_PBQP_MATH_H diff --git a/lib/CodeGen/PBQP/Solution.h b/lib/CodeGen/PBQP/Solution.h deleted file mode 100644 index 047fd04c7cb8..000000000000 --- a/lib/CodeGen/PBQP/Solution.h +++ /dev/null @@ -1,89 +0,0 @@ -//===-- Solution.h ------- PBQP Solution ------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// PBQP Solution class. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CODEGEN_PBQP_SOLUTION_H -#define LLVM_CODEGEN_PBQP_SOLUTION_H - -#include "Math.h" -#include "Graph.h" - -#include - -namespace PBQP { - - /// \brief Represents a solution to a PBQP problem. - /// - /// To get the selection for each node in the problem use the getSelection method. - class Solution { - private: - - typedef std::map SelectionsMap; - SelectionsMap selections; - - unsigned r0Reductions, r1Reductions, r2Reductions, rNReductions; - - public: - - /// \brief Number of nodes for which selections have been made. - /// @return Number of nodes for which selections have been made. - unsigned numNodes() const { return selections.size(); } - - /// \brief Records a reduction via the R0 rule. Should be called from the - /// solver only. - void recordR0() { ++r0Reductions; } - - /// \brief Returns the number of R0 reductions applied to solve the problem. - unsigned numR0Reductions() const { return r0Reductions; } - - /// \brief Records a reduction via the R1 rule. Should be called from the - /// solver only. - void recordR1() { ++r1Reductions; } - - /// \brief Returns the number of R1 reductions applied to solve the problem. - unsigned numR1Reductions() const { return r1Reductions; } - - /// \brief Records a reduction via the R2 rule. Should be called from the - /// solver only. - void recordR2() { ++r2Reductions; } - - /// \brief Returns the number of R2 reductions applied to solve the problem. - unsigned numR2Reductions() const { return r2Reductions; } - - /// \brief Records a reduction via the RN rule. Should be called from the - /// solver only. - void recordRN() { ++ rNReductions; } - - /// \brief Returns the number of RN reductions applied to solve the problem. - unsigned numRNReductions() const { return rNReductions; } - - /// \brief Set the selection for a given node. - /// @param nItr Node iterator. - /// @param selection Selection for nItr. - void setSelection(Graph::NodeItr nItr, unsigned selection) { - selections[nItr] = selection; - } - - /// \brief Get a node's selection. - /// @param nItr Node iterator. - /// @return The selection for nItr; - unsigned getSelection(Graph::NodeItr nItr) const { - SelectionsMap::const_iterator sItr = selections.find(nItr); - assert(sItr != selections.end() && "No selection for node."); - return sItr->second; - } - - }; - -} - -#endif // LLVM_CODEGEN_PBQP_SOLUTION_H diff --git a/lib/CodeGen/PHIElimination.cpp b/lib/CodeGen/PHIElimination.cpp index d4df4c548711..5f7cf582c960 100644 --- a/lib/CodeGen/PHIElimination.cpp +++ b/lib/CodeGen/PHIElimination.cpp @@ -14,7 +14,7 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "phielim" -#include "PHIElimination.h" +#include "PHIEliminationUtils.h" #include "llvm/CodeGen/LiveVariables.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/MachineDominators.h" @@ -34,23 +34,72 @@ #include using namespace llvm; +namespace { + class PHIElimination : public MachineFunctionPass { + MachineRegisterInfo *MRI; // Machine register information + + public: + static char ID; // Pass identification, replacement for typeid + PHIElimination() : MachineFunctionPass(ID) { + initializePHIEliminationPass(*PassRegistry::getPassRegistry()); + } + + virtual bool runOnMachineFunction(MachineFunction &Fn); + virtual void getAnalysisUsage(AnalysisUsage &AU) const; + + private: + /// EliminatePHINodes - Eliminate phi nodes by inserting copy instructions + /// in predecessor basic blocks. + /// + bool EliminatePHINodes(MachineFunction &MF, MachineBasicBlock &MBB); + void LowerAtomicPHINode(MachineBasicBlock &MBB, + MachineBasicBlock::iterator AfterPHIsIt); + + /// analyzePHINodes - Gather information about the PHI nodes in + /// here. In particular, we want to map the number of uses of a virtual + /// register which is used in a PHI node. We map that to the BB the + /// vreg is coming from. This is used later to determine when the vreg + /// is killed in the BB. + /// + void analyzePHINodes(const MachineFunction& Fn); + + /// Split critical edges where necessary for good coalescer performance. + bool SplitPHIEdges(MachineFunction &MF, MachineBasicBlock &MBB, + LiveVariables &LV, MachineLoopInfo *MLI); + + typedef std::pair BBVRegPair; + typedef DenseMap VRegPHIUse; + + VRegPHIUse VRegPHIUseCount; + + // Defs of PHI sources which are implicit_def. + SmallPtrSet ImpDefs; + + // Map reusable lowered PHI node -> incoming join register. + typedef DenseMap LoweredPHIMap; + LoweredPHIMap LoweredPHIs; + }; +} + STATISTIC(NumAtomic, "Number of atomic phis lowered"); +STATISTIC(NumCriticalEdgesSplit, "Number of critical edges split"); STATISTIC(NumReused, "Number of reused lowered phis"); char PHIElimination::ID = 0; INITIALIZE_PASS(PHIElimination, "phi-node-elimination", - "Eliminate PHI nodes for register allocation", false, false); + "Eliminate PHI nodes for register allocation", false, false) -char &llvm::PHIEliminationID = PHIElimination::ID; +char& llvm::PHIEliminationID = PHIElimination::ID; -void llvm::PHIElimination::getAnalysisUsage(AnalysisUsage &AU) const { +void PHIElimination::getAnalysisUsage(AnalysisUsage &AU) const { AU.addPreserved(); AU.addPreserved(); AU.addPreserved(); MachineFunctionPass::getAnalysisUsage(AU); } -bool llvm::PHIElimination::runOnMachineFunction(MachineFunction &MF) { +bool PHIElimination::runOnMachineFunction(MachineFunction &MF) { MRI = &MF.getRegInfo(); bool Changed = false; @@ -93,14 +142,14 @@ bool llvm::PHIElimination::runOnMachineFunction(MachineFunction &MF) { /// EliminatePHINodes - Eliminate phi nodes by inserting copy instructions in /// predecessor basic blocks. /// -bool llvm::PHIElimination::EliminatePHINodes(MachineFunction &MF, +bool PHIElimination::EliminatePHINodes(MachineFunction &MF, MachineBasicBlock &MBB) { if (MBB.empty() || !MBB.front().isPHI()) return false; // Quick exit for basic blocks without PHIs. // Get an iterator to the first instruction after the last PHI node (this may // also be the end of the basic block). - MachineBasicBlock::iterator AfterPHIsIt = SkipPHIsAndLabels(MBB, MBB.begin()); + MachineBasicBlock::iterator AfterPHIsIt = MBB.SkipPHIsAndLabels(MBB.begin()); while (MBB.front().isPHI()) LowerAtomicPHINode(MBB, AfterPHIsIt); @@ -121,58 +170,14 @@ static bool isSourceDefinedByImplicitDef(const MachineInstr *MPhi, return true; } -// FindCopyInsertPoint - Find a safe place in MBB to insert a copy from SrcReg -// when following the CFG edge to SuccMBB. This needs to be after any def of -// SrcReg, but before any subsequent point where control flow might jump out of -// the basic block. -MachineBasicBlock::iterator -llvm::PHIElimination::FindCopyInsertPoint(MachineBasicBlock &MBB, - MachineBasicBlock &SuccMBB, - unsigned SrcReg) { - // Handle the trivial case trivially. - if (MBB.empty()) - return MBB.begin(); - - // Usually, we just want to insert the copy before the first terminator - // instruction. However, for the edge going to a landing pad, we must insert - // the copy before the call/invoke instruction. - if (!SuccMBB.isLandingPad()) - return MBB.getFirstTerminator(); - - // Discover any defs/uses in this basic block. - SmallPtrSet DefUsesInMBB; - for (MachineRegisterInfo::reg_iterator RI = MRI->reg_begin(SrcReg), - RE = MRI->reg_end(); RI != RE; ++RI) { - MachineInstr *DefUseMI = &*RI; - if (DefUseMI->getParent() == &MBB) - DefUsesInMBB.insert(DefUseMI); - } - MachineBasicBlock::iterator InsertPoint; - if (DefUsesInMBB.empty()) { - // No defs. Insert the copy at the start of the basic block. - InsertPoint = MBB.begin(); - } else if (DefUsesInMBB.size() == 1) { - // Insert the copy immediately after the def/use. - InsertPoint = *DefUsesInMBB.begin(); - ++InsertPoint; - } else { - // Insert the copy immediately after the last def/use. - InsertPoint = MBB.end(); - while (!DefUsesInMBB.count(&*--InsertPoint)) {} - ++InsertPoint; - } - - // Make sure the copy goes after any phi nodes however. - return SkipPHIsAndLabels(MBB, InsertPoint); -} /// LowerAtomicPHINode - Lower the PHI node at the top of the specified block, /// under the assuption that it needs to be lowered in a way that supports /// atomic execution of PHIs. This lowering method is always correct all of the /// time. /// -void llvm::PHIElimination::LowerAtomicPHINode( +void PHIElimination::LowerAtomicPHINode( MachineBasicBlock &MBB, MachineBasicBlock::iterator AfterPHIsIt) { ++NumAtomic; @@ -207,7 +212,7 @@ void llvm::PHIElimination::LowerAtomicPHINode( IncomingReg = entry; reusedIncoming = true; ++NumReused; - DEBUG(dbgs() << "Reusing %reg" << IncomingReg << " for " << *MPhi); + DEBUG(dbgs() << "Reusing " << PrintReg(IncomingReg) << " for " << *MPhi); } else { const TargetRegisterClass *RC = MF.getRegInfo().getRegClass(DestReg); entry = IncomingReg = MF.getRegInfo().createVirtualRegister(RC); @@ -294,7 +299,7 @@ void llvm::PHIElimination::LowerAtomicPHINode( // Find a safe location to insert the copy, this may be the first terminator // in the block (or end()). MachineBasicBlock::iterator InsertPos = - FindCopyInsertPoint(opBlock, MBB, SrcReg); + findPHICopyInsertPoint(&opBlock, &MBB, SrcReg); // Insert the copy. if (!reusedIncoming && IncomingReg) @@ -335,6 +340,8 @@ void llvm::PHIElimination::LowerAtomicPHINode( #ifndef NDEBUG for (MachineBasicBlock::iterator TI = llvm::next(Term); TI != opBlock.end(); ++TI) { + if (TI->isDebugValue()) + continue; assert(!TI->readsRegister(SrcReg) && "Terminator instructions cannot use virtual registers unless" "they are the first terminator in a block!"); @@ -343,9 +350,13 @@ void llvm::PHIElimination::LowerAtomicPHINode( } else if (reusedIncoming || !IncomingReg) { // We may have to rewind a bit if we didn't insert a copy this time. KillInst = Term; - while (KillInst != opBlock.begin()) - if ((--KillInst)->readsRegister(SrcReg)) + while (KillInst != opBlock.begin()) { + --KillInst; + if (KillInst->isDebugValue()) + continue; + if (KillInst->readsRegister(SrcReg)) break; + } } else { // We just inserted this copy. KillInst = prior(InsertPos); @@ -371,7 +382,7 @@ void llvm::PHIElimination::LowerAtomicPHINode( /// used in a PHI node. We map that to the BB the vreg is coming from. This is /// used later to determine when the vreg is killed in the BB. /// -void llvm::PHIElimination::analyzePHINodes(const MachineFunction& MF) { +void PHIElimination::analyzePHINodes(const MachineFunction& MF) { for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); I != E; ++I) for (MachineBasicBlock::const_iterator BBI = I->begin(), BBE = I->end(); @@ -381,10 +392,10 @@ void llvm::PHIElimination::analyzePHINodes(const MachineFunction& MF) { BBI->getOperand(i).getReg())]; } -bool llvm::PHIElimination::SplitPHIEdges(MachineFunction &MF, - MachineBasicBlock &MBB, - LiveVariables &LV, - MachineLoopInfo *MLI) { +bool PHIElimination::SplitPHIEdges(MachineFunction &MF, + MachineBasicBlock &MBB, + LiveVariables &LV, + MachineLoopInfo *MLI) { if (MBB.empty() || !MBB.front().isPHI() || MBB.isLandingPad()) return false; // Quick exit for basic blocks without PHIs. @@ -403,10 +414,14 @@ bool llvm::PHIElimination::SplitPHIEdges(MachineFunction &MF, !LV.isLiveIn(Reg, MBB) && LV.isLiveOut(Reg, *PreMBB)) { if (!MLI || !(MLI->getLoopFor(PreMBB) == MLI->getLoopFor(&MBB) && - MLI->isLoopHeader(&MBB))) - Changed |= PreMBB->SplitCriticalEdge(&MBB, this) != 0; + MLI->isLoopHeader(&MBB))) { + if (PreMBB->SplitCriticalEdge(&MBB, this)) { + Changed = true; + ++NumCriticalEdgesSplit; + } + } } } } - return true; + return Changed; } diff --git a/lib/CodeGen/PHIElimination.h b/lib/CodeGen/PHIElimination.h deleted file mode 100644 index 45a97182e71c..000000000000 --- a/lib/CodeGen/PHIElimination.h +++ /dev/null @@ -1,115 +0,0 @@ -//===-- lib/CodeGen/PHIElimination.h ----------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CODEGEN_PHIELIMINATION_HPP -#define LLVM_CODEGEN_PHIELIMINATION_HPP - -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/SmallSet.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/CodeGen/MachineBasicBlock.h" -#include "llvm/CodeGen/MachineFunctionPass.h" - -namespace llvm { - class LiveVariables; - class MachineRegisterInfo; - class MachineLoopInfo; - - /// Lower PHI instructions to copies. - class PHIElimination : public MachineFunctionPass { - MachineRegisterInfo *MRI; // Machine register information - - public: - static char ID; // Pass identification, replacement for typeid - PHIElimination() : MachineFunctionPass(ID) {} - - virtual bool runOnMachineFunction(MachineFunction &Fn); - - virtual void getAnalysisUsage(AnalysisUsage &AU) const; - - private: - /// EliminatePHINodes - Eliminate phi nodes by inserting copy instructions - /// in predecessor basic blocks. - /// - bool EliminatePHINodes(MachineFunction &MF, MachineBasicBlock &MBB); - void LowerAtomicPHINode(MachineBasicBlock &MBB, - MachineBasicBlock::iterator AfterPHIsIt); - - /// analyzePHINodes - Gather information about the PHI nodes in - /// here. In particular, we want to map the number of uses of a virtual - /// register which is used in a PHI node. We map that to the BB the - /// vreg is coming from. This is used later to determine when the vreg - /// is killed in the BB. - /// - void analyzePHINodes(const MachineFunction& Fn); - - /// Split critical edges where necessary for good coalescer performance. - bool SplitPHIEdges(MachineFunction &MF, MachineBasicBlock &MBB, - LiveVariables &LV, MachineLoopInfo *MLI); - - /// SplitCriticalEdge - Split a critical edge from A to B by - /// inserting a new MBB. Update branches in A and PHI instructions - /// in B. Return the new block. - MachineBasicBlock *SplitCriticalEdge(MachineBasicBlock *A, - MachineBasicBlock *B); - - /// FindCopyInsertPoint - Find a safe place in MBB to insert a copy from - /// SrcReg when following the CFG edge to SuccMBB. This needs to be after - /// any def of SrcReg, but before any subsequent point where control flow - /// might jump out of the basic block. - MachineBasicBlock::iterator FindCopyInsertPoint(MachineBasicBlock &MBB, - MachineBasicBlock &SuccMBB, - unsigned SrcReg); - - // SkipPHIsAndLabels - Copies need to be inserted after phi nodes and - // also after any exception handling labels: in landing pads execution - // starts at the label, so any copies placed before it won't be executed! - // We also deal with DBG_VALUEs, which are a bit tricky: - // PHI - // DBG_VALUE - // LABEL - // Here the DBG_VALUE needs to be skipped, and if it refers to a PHI it - // needs to be annulled or, better, moved to follow the label, as well. - // PHI - // DBG_VALUE - // no label - // Here it is not a good idea to skip the DBG_VALUE. - // FIXME: For now we skip and annul all DBG_VALUEs, maximally simple and - // maximally stupid. - MachineBasicBlock::iterator SkipPHIsAndLabels(MachineBasicBlock &MBB, - MachineBasicBlock::iterator I) { - // Rather than assuming that EH labels come before other kinds of labels, - // just skip all labels. - while (I != MBB.end() && - (I->isPHI() || I->isLabel() || I->isDebugValue())) { - if (I->isDebugValue() && I->getNumOperands()==3 && - I->getOperand(0).isReg()) - I->getOperand(0).setReg(0U); - ++I; - } - return I; - } - - typedef std::pair BBVRegPair; - typedef DenseMap VRegPHIUse; - - VRegPHIUse VRegPHIUseCount; - - // Defs of PHI sources which are implicit_def. - SmallPtrSet ImpDefs; - - // Map reusable lowered PHI node -> incoming join register. - typedef DenseMap LoweredPHIMap; - LoweredPHIMap LoweredPHIs; - }; - -} - -#endif /* LLVM_CODEGEN_PHIELIMINATION_HPP */ diff --git a/lib/CodeGen/PHIEliminationUtils.cpp b/lib/CodeGen/PHIEliminationUtils.cpp new file mode 100644 index 000000000000..10bfdcce6769 --- /dev/null +++ b/lib/CodeGen/PHIEliminationUtils.cpp @@ -0,0 +1,61 @@ +//===-- PHIEliminationUtils.cpp - Helper functions for PHI elimination ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PHIEliminationUtils.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/ADT/SmallPtrSet.h" +using namespace llvm; + +// findCopyInsertPoint - Find a safe place in MBB to insert a copy from SrcReg +// when following the CFG edge to SuccMBB. This needs to be after any def of +// SrcReg, but before any subsequent point where control flow might jump out of +// the basic block. +MachineBasicBlock::iterator +llvm::findPHICopyInsertPoint(MachineBasicBlock* MBB, MachineBasicBlock* SuccMBB, + unsigned SrcReg) { + // Handle the trivial case trivially. + if (MBB->empty()) + return MBB->begin(); + + // Usually, we just want to insert the copy before the first terminator + // instruction. However, for the edge going to a landing pad, we must insert + // the copy before the call/invoke instruction. + if (!SuccMBB->isLandingPad()) + return MBB->getFirstTerminator(); + + // Discover any defs/uses in this basic block. + SmallPtrSet DefUsesInMBB; + MachineRegisterInfo& MRI = MBB->getParent()->getRegInfo(); + for (MachineRegisterInfo::reg_iterator RI = MRI.reg_begin(SrcReg), + RE = MRI.reg_end(); RI != RE; ++RI) { + MachineInstr* DefUseMI = &*RI; + if (DefUseMI->getParent() == MBB) + DefUsesInMBB.insert(DefUseMI); + } + + MachineBasicBlock::iterator InsertPoint; + if (DefUsesInMBB.empty()) { + // No defs. Insert the copy at the start of the basic block. + InsertPoint = MBB->begin(); + } else if (DefUsesInMBB.size() == 1) { + // Insert the copy immediately after the def/use. + InsertPoint = *DefUsesInMBB.begin(); + ++InsertPoint; + } else { + // Insert the copy immediately after the last def/use. + InsertPoint = MBB->end(); + while (!DefUsesInMBB.count(&*--InsertPoint)) {} + ++InsertPoint; + } + + // Make sure the copy goes after any phi nodes however. + return MBB->SkipPHIsAndLabels(InsertPoint); +} diff --git a/lib/CodeGen/PHIEliminationUtils.h b/lib/CodeGen/PHIEliminationUtils.h new file mode 100644 index 000000000000..9ac47fb4c505 --- /dev/null +++ b/lib/CodeGen/PHIEliminationUtils.h @@ -0,0 +1,25 @@ +//=- PHIEliminationUtils.h - Helper functions for PHI elimination *- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_PHIELIMINATIONUTILS_H +#define LLVM_CODEGEN_PHIELIMINATIONUTILS_H + +#include "llvm/CodeGen/MachineBasicBlock.h" + +namespace llvm { + /// findPHICopyInsertPoint - Find a safe place in MBB to insert a copy from + /// SrcReg when following the CFG edge to SuccMBB. This needs to be after + /// any def of SrcReg, but before any subsequent point where control flow + /// might jump out of the basic block. + MachineBasicBlock::iterator + findPHICopyInsertPoint(MachineBasicBlock* MBB, MachineBasicBlock* SuccMBB, + unsigned SrcReg); +} + +#endif diff --git a/lib/CodeGen/PeepholeOptimizer.cpp b/lib/CodeGen/PeepholeOptimizer.cpp index 17cee46ca16c..5d7123caa017 100644 --- a/lib/CodeGen/PeepholeOptimizer.cpp +++ b/lib/CodeGen/PeepholeOptimizer.cpp @@ -41,7 +41,9 @@ #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Support/CommandLine.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" using namespace llvm; @@ -50,8 +52,13 @@ static cl::opt Aggressive("aggressive-ext-opt", cl::Hidden, cl::desc("Aggressive extension optimization")); +static cl::opt +DisablePeephole("disable-peephole", cl::Hidden, cl::init(false), + cl::desc("Disable the peephole optimizer")); + STATISTIC(NumReuse, "Number of extension results reused"); STATISTIC(NumEliminated, "Number of compares eliminated"); +STATISTIC(NumImmFold, "Number of move immediate foled"); namespace { class PeepholeOptimizer : public MachineFunctionPass { @@ -62,7 +69,9 @@ namespace { public: static char ID; // Pass identification - PeepholeOptimizer() : MachineFunctionPass(ID) {} + PeepholeOptimizer() : MachineFunctionPass(ID) { + initializePeepholeOptimizerPass(*PassRegistry::getPassRegistry()); + } virtual bool runOnMachineFunction(MachineFunction &MF); @@ -79,12 +88,21 @@ namespace { bool OptimizeCmpInstr(MachineInstr *MI, MachineBasicBlock *MBB); bool OptimizeExtInstr(MachineInstr *MI, MachineBasicBlock *MBB, SmallPtrSet &LocalMIs); + bool isMoveImmediate(MachineInstr *MI, + SmallSet &ImmDefRegs, + DenseMap &ImmDefMIs); + bool FoldImmediate(MachineInstr *MI, MachineBasicBlock *MBB, + SmallSet &ImmDefRegs, + DenseMap &ImmDefMIs); }; } char PeepholeOptimizer::ID = 0; -INITIALIZE_PASS(PeepholeOptimizer, "peephole-opts", - "Peephole Optimizations", false, false); +INITIALIZE_PASS_BEGIN(PeepholeOptimizer, "peephole-opts", + "Peephole Optimizations", false, false) +INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree) +INITIALIZE_PASS_END(PeepholeOptimizer, "peephole-opts", + "Peephole Optimizations", false, false) FunctionPass *llvm::createPeepholeOptimizerPass() { return new PeepholeOptimizer(); @@ -102,12 +120,10 @@ FunctionPass *llvm::createPeepholeOptimizerPass() { bool PeepholeOptimizer:: OptimizeExtInstr(MachineInstr *MI, MachineBasicBlock *MBB, SmallPtrSet &LocalMIs) { - LocalMIs.insert(MI); - unsigned SrcReg, DstReg, SubIdx; if (!TII->isCoalescableExtInstr(*MI, SrcReg, DstReg, SubIdx)) return false; - + if (TargetRegisterInfo::isPhysicalRegister(DstReg) || TargetRegisterInfo::isPhysicalRegister(SrcReg)) return false; @@ -232,22 +248,17 @@ OptimizeExtInstr(MachineInstr *MI, MachineBasicBlock *MBB, /// set) the same flag as the compare, then we can remove the comparison and use /// the flag from the previous instruction. bool PeepholeOptimizer::OptimizeCmpInstr(MachineInstr *MI, - MachineBasicBlock *MBB) { + MachineBasicBlock *MBB){ // If this instruction is a comparison against zero and isn't comparing a // physical register, we can try to optimize it. unsigned SrcReg; - int CmpValue; - if (!TII->AnalyzeCompare(MI, SrcReg, CmpValue) || - TargetRegisterInfo::isPhysicalRegister(SrcReg) || CmpValue != 0) - return false; - - MachineRegisterInfo::def_iterator DI = MRI->def_begin(SrcReg); - if (llvm::next(DI) != MRI->def_end()) - // Only support one definition. + int CmpMask, CmpValue; + if (!TII->AnalyzeCompare(MI, SrcReg, CmpMask, CmpValue) || + TargetRegisterInfo::isPhysicalRegister(SrcReg)) return false; - // Attempt to convert the defining instruction to set the "zero" flag. - if (TII->ConvertToSetZeroFlag(&*DI, MI)) { + // Attempt to optimize the comparison instruction. + if (TII->OptimizeCompareInstr(MI, SrcReg, CmpMask, CmpValue, MRI)) { ++NumEliminated; return true; } @@ -255,7 +266,53 @@ bool PeepholeOptimizer::OptimizeCmpInstr(MachineInstr *MI, return false; } +bool PeepholeOptimizer::isMoveImmediate(MachineInstr *MI, + SmallSet &ImmDefRegs, + DenseMap &ImmDefMIs) { + const TargetInstrDesc &TID = MI->getDesc(); + if (!TID.isMoveImmediate()) + return false; + if (TID.getNumDefs() != 1) + return false; + unsigned Reg = MI->getOperand(0).getReg(); + if (TargetRegisterInfo::isVirtualRegister(Reg)) { + ImmDefMIs.insert(std::make_pair(Reg, MI)); + ImmDefRegs.insert(Reg); + return true; + } + + return false; +} + +/// FoldImmediate - Try folding register operands that are defined by move +/// immediate instructions, i.e. a trivial constant folding optimization, if +/// and only if the def and use are in the same BB. +bool PeepholeOptimizer::FoldImmediate(MachineInstr *MI, MachineBasicBlock *MBB, + SmallSet &ImmDefRegs, + DenseMap &ImmDefMIs) { + for (unsigned i = 0, e = MI->getDesc().getNumOperands(); i != e; ++i) { + MachineOperand &MO = MI->getOperand(i); + if (!MO.isReg() || MO.isDef()) + continue; + unsigned Reg = MO.getReg(); + if (!TargetRegisterInfo::isVirtualRegister(Reg)) + continue; + if (ImmDefRegs.count(Reg) == 0) + continue; + DenseMap::iterator II = ImmDefMIs.find(Reg); + assert(II != ImmDefMIs.end()); + if (TII->FoldImmediate(MI, II->second, Reg, MRI)) { + ++NumImmFold; + return true; + } + } + return false; +} + bool PeepholeOptimizer::runOnMachineFunction(MachineFunction &MF) { + if (DisablePeephole) + return false; + TM = &MF.getTarget(); TII = TM->getInstrInfo(); MRI = &MF.getRegInfo(); @@ -264,22 +321,50 @@ bool PeepholeOptimizer::runOnMachineFunction(MachineFunction &MF) { bool Changed = false; SmallPtrSet LocalMIs; + SmallSet ImmDefRegs; + DenseMap ImmDefMIs; for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) { MachineBasicBlock *MBB = &*I; + + bool SeenMoveImm = false; LocalMIs.clear(); + ImmDefRegs.clear(); + ImmDefMIs.clear(); + bool First = true; + MachineBasicBlock::iterator PMII; for (MachineBasicBlock::iterator - MII = I->begin(), ME = I->end(); MII != ME; ) { + MII = I->begin(), MIE = I->end(); MII != MIE; ) { MachineInstr *MI = &*MII; + LocalMIs.insert(MI); - if (MI->getDesc().isCompare() && - !MI->getDesc().hasUnmodeledSideEffects()) { - ++MII; // The iterator may become invalid if the compare is deleted. - Changed |= OptimizeCmpInstr(MI, MBB); + if (MI->isLabel() || MI->isPHI() || MI->isImplicitDef() || + MI->isKill() || MI->isInlineAsm() || MI->isDebugValue() || + MI->hasUnmodeledSideEffects()) { + ++MII; + continue; + } + + if (MI->getDesc().isCompare()) { + if (OptimizeCmpInstr(MI, MBB)) { + // MI is deleted. + Changed = true; + MII = First ? I->begin() : llvm::next(PMII); + continue; + } + } + + if (isMoveImmediate(MI, ImmDefRegs, ImmDefMIs)) { + SeenMoveImm = true; } else { Changed |= OptimizeExtInstr(MI, MBB, LocalMIs); - ++MII; + if (SeenMoveImm) + Changed |= FoldImmediate(MI, MBB, ImmDefRegs, ImmDefMIs); } + + First = false; + PMII = MII; + ++MII; } } diff --git a/lib/CodeGen/PostRAHazardRecognizer.cpp b/lib/CodeGen/PostRAHazardRecognizer.cpp deleted file mode 100644 index cbde2b01eeaf..000000000000 --- a/lib/CodeGen/PostRAHazardRecognizer.cpp +++ /dev/null @@ -1,180 +0,0 @@ -//===----- PostRAHazardRecognizer.cpp - hazard recognizer -------- ---------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This implements a hazard recognizer using the instructions itineraries -// defined for the current target. -// -//===----------------------------------------------------------------------===// - -#define DEBUG_TYPE "post-RA-sched" -#include "llvm/CodeGen/PostRAHazardRecognizer.h" -#include "llvm/CodeGen/ScheduleDAG.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetInstrItineraries.h" - -using namespace llvm; - -PostRAHazardRecognizer:: -PostRAHazardRecognizer(const InstrItineraryData &LItinData) : - ScheduleHazardRecognizer(), ItinData(LItinData) { - // Determine the maximum depth of any itinerary. This determines the - // depth of the scoreboard. We always make the scoreboard at least 1 - // cycle deep to avoid dealing with the boundary condition. - unsigned ScoreboardDepth = 1; - if (!ItinData.isEmpty()) { - for (unsigned idx = 0; ; ++idx) { - if (ItinData.isEndMarker(idx)) - break; - - const InstrStage *IS = ItinData.beginStage(idx); - const InstrStage *E = ItinData.endStage(idx); - unsigned ItinDepth = 0; - for (; IS != E; ++IS) - ItinDepth += IS->getCycles(); - - ScoreboardDepth = std::max(ScoreboardDepth, ItinDepth); - } - } - - ReservedScoreboard.reset(ScoreboardDepth); - RequiredScoreboard.reset(ScoreboardDepth); - - DEBUG(dbgs() << "Using post-ra hazard recognizer: ScoreboardDepth = " - << ScoreboardDepth << '\n'); -} - -void PostRAHazardRecognizer::Reset() { - RequiredScoreboard.reset(); - ReservedScoreboard.reset(); -} - -void PostRAHazardRecognizer::ScoreBoard::dump() const { - dbgs() << "Scoreboard:\n"; - - unsigned last = Depth - 1; - while ((last > 0) && ((*this)[last] == 0)) - last--; - - for (unsigned i = 0; i <= last; i++) { - unsigned FUs = (*this)[i]; - dbgs() << "\t"; - for (int j = 31; j >= 0; j--) - dbgs() << ((FUs & (1 << j)) ? '1' : '0'); - dbgs() << '\n'; - } -} - -ScheduleHazardRecognizer::HazardType -PostRAHazardRecognizer::getHazardType(SUnit *SU) { - if (ItinData.isEmpty()) - return NoHazard; - - unsigned cycle = 0; - - // Use the itinerary for the underlying instruction to check for - // free FU's in the scoreboard at the appropriate future cycles. - unsigned idx = SU->getInstr()->getDesc().getSchedClass(); - for (const InstrStage *IS = ItinData.beginStage(idx), - *E = ItinData.endStage(idx); IS != E; ++IS) { - // We must find one of the stage's units free for every cycle the - // stage is occupied. FIXME it would be more accurate to find the - // same unit free in all the cycles. - for (unsigned int i = 0; i < IS->getCycles(); ++i) { - assert(((cycle + i) < RequiredScoreboard.getDepth()) && - "Scoreboard depth exceeded!"); - - unsigned freeUnits = IS->getUnits(); - switch (IS->getReservationKind()) { - default: - assert(0 && "Invalid FU reservation"); - case InstrStage::Required: - // Required FUs conflict with both reserved and required ones - freeUnits &= ~ReservedScoreboard[cycle + i]; - // FALLTHROUGH - case InstrStage::Reserved: - // Reserved FUs can conflict only with required ones. - freeUnits &= ~RequiredScoreboard[cycle + i]; - break; - } - - if (!freeUnits) { - DEBUG(dbgs() << "*** Hazard in cycle " << (cycle + i) << ", "); - DEBUG(dbgs() << "SU(" << SU->NodeNum << "): "); - DEBUG(SU->getInstr()->dump()); - return Hazard; - } - } - - // Advance the cycle to the next stage. - cycle += IS->getNextCycles(); - } - - return NoHazard; -} - -void PostRAHazardRecognizer::EmitInstruction(SUnit *SU) { - if (ItinData.isEmpty()) - return; - - unsigned cycle = 0; - - // Use the itinerary for the underlying instruction to reserve FU's - // in the scoreboard at the appropriate future cycles. - unsigned idx = SU->getInstr()->getDesc().getSchedClass(); - for (const InstrStage *IS = ItinData.beginStage(idx), - *E = ItinData.endStage(idx); IS != E; ++IS) { - // We must reserve one of the stage's units for every cycle the - // stage is occupied. FIXME it would be more accurate to reserve - // the same unit free in all the cycles. - for (unsigned int i = 0; i < IS->getCycles(); ++i) { - assert(((cycle + i) < RequiredScoreboard.getDepth()) && - "Scoreboard depth exceeded!"); - - unsigned freeUnits = IS->getUnits(); - switch (IS->getReservationKind()) { - default: - assert(0 && "Invalid FU reservation"); - case InstrStage::Required: - // Required FUs conflict with both reserved and required ones - freeUnits &= ~ReservedScoreboard[cycle + i]; - // FALLTHROUGH - case InstrStage::Reserved: - // Reserved FUs can conflict only with required ones. - freeUnits &= ~RequiredScoreboard[cycle + i]; - break; - } - - // reduce to a single unit - unsigned freeUnit = 0; - do { - freeUnit = freeUnits; - freeUnits = freeUnit & (freeUnit - 1); - } while (freeUnits); - - assert(freeUnit && "No function unit available!"); - if (IS->getReservationKind() == InstrStage::Required) - RequiredScoreboard[cycle + i] |= freeUnit; - else - ReservedScoreboard[cycle + i] |= freeUnit; - } - - // Advance the cycle to the next stage. - cycle += IS->getNextCycles(); - } - - DEBUG(ReservedScoreboard.dump()); - DEBUG(RequiredScoreboard.dump()); -} - -void PostRAHazardRecognizer::AdvanceCycle() { - ReservedScoreboard[0] = 0; ReservedScoreboard.advance(); - RequiredScoreboard[0] = 0; RequiredScoreboard.advance(); -} diff --git a/lib/CodeGen/PostRASchedulerList.cpp b/lib/CodeGen/PostRASchedulerList.cpp index f0bd6d1372be..60c24b710792 100644 --- a/lib/CodeGen/PostRASchedulerList.cpp +++ b/lib/CodeGen/PostRASchedulerList.cpp @@ -133,18 +133,12 @@ namespace { std::vector KillIndices; public: - SchedulePostRATDList(MachineFunction &MF, - const MachineLoopInfo &MLI, - const MachineDominatorTree &MDT, - ScheduleHazardRecognizer *HR, - AntiDepBreaker *ADB, - AliasAnalysis *aa) - : ScheduleDAGInstrs(MF, MLI, MDT), Topo(SUnits), - HazardRec(HR), AntiDepBreak(ADB), AA(aa), - KillIndices(TRI->getNumRegs()) {} - - ~SchedulePostRATDList() { - } + SchedulePostRATDList( + MachineFunction &MF, MachineLoopInfo &MLI, MachineDominatorTree &MDT, + AliasAnalysis *AA, TargetSubtarget::AntiDepBreakMode AntiDepMode, + SmallVectorImpl &CriticalPathRCs); + + ~SchedulePostRATDList(); /// StartBlock - Initialize register live-range state for scheduling in /// this block. @@ -183,9 +177,34 @@ namespace { }; } +SchedulePostRATDList::SchedulePostRATDList( + MachineFunction &MF, MachineLoopInfo &MLI, MachineDominatorTree &MDT, + AliasAnalysis *AA, TargetSubtarget::AntiDepBreakMode AntiDepMode, + SmallVectorImpl &CriticalPathRCs) + : ScheduleDAGInstrs(MF, MLI, MDT), Topo(SUnits), AA(AA), + KillIndices(TRI->getNumRegs()) +{ + const TargetMachine &TM = MF.getTarget(); + const InstrItineraryData *InstrItins = TM.getInstrItineraryData(); + HazardRec = + TM.getInstrInfo()->CreateTargetPostRAHazardRecognizer(InstrItins, this); + AntiDepBreak = + ((AntiDepMode == TargetSubtarget::ANTIDEP_ALL) ? + (AntiDepBreaker *)new AggressiveAntiDepBreaker(MF, CriticalPathRCs) : + ((AntiDepMode == TargetSubtarget::ANTIDEP_CRITICAL) ? + (AntiDepBreaker *)new CriticalAntiDepBreaker(MF) : NULL)); +} + +SchedulePostRATDList::~SchedulePostRATDList() { + delete HazardRec; + delete AntiDepBreak; +} + bool PostRAScheduler::runOnMachineFunction(MachineFunction &Fn) { - AA = &getAnalysis(); TII = Fn.getTarget().getInstrInfo(); + MachineLoopInfo &MLI = getAnalysis(); + MachineDominatorTree &MDT = getAnalysis(); + AliasAnalysis *AA = &getAnalysis(); // Check for explicit enable/disable of post-ra scheduling. TargetSubtarget::AntiDepBreakMode AntiDepMode = TargetSubtarget::ANTIDEP_NONE; @@ -195,6 +214,7 @@ bool PostRAScheduler::runOnMachineFunction(MachineFunction &Fn) { return false; } else { // Check that post-RA scheduling is enabled for this target. + // This may upgrade the AntiDepMode. const TargetSubtarget &ST = Fn.getTarget().getSubtarget(); if (!ST.enablePostRAScheduler(OptLevel, AntiDepMode, CriticalPathRCs)) return false; @@ -210,19 +230,8 @@ bool PostRAScheduler::runOnMachineFunction(MachineFunction &Fn) { DEBUG(dbgs() << "PostRAScheduler\n"); - const MachineLoopInfo &MLI = getAnalysis(); - const MachineDominatorTree &MDT = getAnalysis(); - const TargetMachine &TM = Fn.getTarget(); - const InstrItineraryData &InstrItins = TM.getInstrItineraryData(); - ScheduleHazardRecognizer *HR = - TM.getInstrInfo()->CreateTargetPostRAHazardRecognizer(InstrItins); - AntiDepBreaker *ADB = - ((AntiDepMode == TargetSubtarget::ANTIDEP_ALL) ? - (AntiDepBreaker *)new AggressiveAntiDepBreaker(Fn, CriticalPathRCs) : - ((AntiDepMode == TargetSubtarget::ANTIDEP_CRITICAL) ? - (AntiDepBreaker *)new CriticalAntiDepBreaker(Fn) : NULL)); - - SchedulePostRATDList Scheduler(Fn, MLI, MDT, HR, ADB, AA); + SchedulePostRATDList Scheduler(Fn, MLI, MDT, AA, AntiDepMode, + CriticalPathRCs); // Loop over all of the basic blocks for (MachineFunction::iterator MBB = Fn.begin(), MBBe = Fn.end(); @@ -270,9 +279,6 @@ bool PostRAScheduler::runOnMachineFunction(MachineFunction &Fn) { Scheduler.FixupKills(MBB); } - delete HR; - delete ADB; - return true; } @@ -617,13 +623,7 @@ void SchedulePostRATDList::ListScheduleTopDown() { MinDepth = PendingQueue[i]->getDepth(); } - DEBUG(dbgs() << "\n*** Examining Available\n"; - LatencyPriorityQueue q = AvailableQueue; - while (!q.empty()) { - SUnit *su = q.pop(); - dbgs() << "Height " << su->getHeight() << ": "; - su->dump(this); - }); + DEBUG(dbgs() << "\n*** Examining Available\n"; AvailableQueue.dump(this)); SUnit *FoundSUnit = 0; bool HasNoopHazards = false; @@ -631,7 +631,7 @@ void SchedulePostRATDList::ListScheduleTopDown() { SUnit *CurSUnit = AvailableQueue.pop(); ScheduleHazardRecognizer::HazardType HT = - HazardRec->getHazardType(CurSUnit); + HazardRec->getHazardType(CurSUnit, 0/*no stalls*/); if (HT == ScheduleHazardRecognizer::NoHazard) { FoundSUnit = CurSUnit; break; diff --git a/lib/CodeGen/PreAllocSplitting.cpp b/lib/CodeGen/PreAllocSplitting.cpp index cd9d83eeb684..d6e31dae9d13 100644 --- a/lib/CodeGen/PreAllocSplitting.cpp +++ b/lib/CodeGen/PreAllocSplitting.cpp @@ -91,8 +91,9 @@ namespace { public: static char ID; - PreAllocSplitting() - : MachineFunctionPass(ID) {} + PreAllocSplitting() : MachineFunctionPass(ID) { + initializePreAllocSplittingPass(*PassRegistry::getPassRegistry()); + } virtual bool runOnMachineFunction(MachineFunction &MF); @@ -106,10 +107,8 @@ namespace { AU.addPreserved(); AU.addPreserved(); AU.addPreserved(); - if (StrongPHIElim) - AU.addPreservedID(StrongPHIEliminationID); - else - AU.addPreservedID(PHIEliminationID); + AU.addPreservedID(StrongPHIEliminationID); + AU.addPreservedID(PHIEliminationID); AU.addRequired(); AU.addRequired(); AU.addRequired(); @@ -203,9 +202,18 @@ namespace { char PreAllocSplitting::ID = 0; -INITIALIZE_PASS(PreAllocSplitting, "pre-alloc-splitting", +INITIALIZE_PASS_BEGIN(PreAllocSplitting, "pre-alloc-splitting", + "Pre-Register Allocation Live Interval Splitting", + false, false) +INITIALIZE_PASS_DEPENDENCY(SlotIndexes) +INITIALIZE_PASS_DEPENDENCY(LiveIntervals) +INITIALIZE_PASS_DEPENDENCY(LiveStacks) +INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree) +INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo) +INITIALIZE_PASS_DEPENDENCY(VirtRegMap) +INITIALIZE_PASS_END(PreAllocSplitting, "pre-alloc-splitting", "Pre-Register Allocation Live Interval Splitting", - false, false); + false, false) char &llvm::PreAllocSplittingID = PreAllocSplitting::ID; @@ -324,7 +332,7 @@ int PreAllocSplitting::CreateSpillStackSlot(unsigned Reg, if (CurrSLI->hasAtLeastOneValue()) CurrSValNo = CurrSLI->getValNumInfo(0); else - CurrSValNo = CurrSLI->getNextValue(SlotIndex(), 0, false, + CurrSValNo = CurrSLI->getNextValue(SlotIndex(), 0, LSs->getVNInfoAllocator()); return SS; } @@ -585,7 +593,7 @@ PreAllocSplitting::PerformPHIConstructionFallBack(MachineBasicBlock::iterator Us SlotIndex StartIndex = LIs->getMBBStartIdx(MBB); VNInfo *RetVNI = Phis[MBB] = - LI->getNextValue(SlotIndex(), /*FIXME*/ 0, false, + LI->getNextValue(SlotIndex(), /*FIXME*/ 0, LIs->getVNInfoAllocator()); if (!IsIntraBlock) LiveOut[MBB] = RetVNI; @@ -674,7 +682,7 @@ void PreAllocSplitting::ReconstructLiveInterval(LiveInterval* LI) { DefIdx = DefIdx.getDefIndex(); assert(!DI->isPHI() && "PHI instr in code during pre-alloc splitting."); - VNInfo* NewVN = LI->getNextValue(DefIdx, 0, true, Alloc); + VNInfo* NewVN = LI->getNextValue(DefIdx, 0, Alloc); // If the def is a move, set the copy field. if (DI->isCopyLike() && DI->getOperand(0).getReg() == LI->reg) @@ -807,7 +815,7 @@ bool PreAllocSplitting::Rematerialize(unsigned VReg, VNInfo* ValNo, MachineBasicBlock& MBB = *RestorePt->getParent(); MachineBasicBlock::iterator KillPt = BarrierMBB->end(); - if (!ValNo->isDefAccurate() || DefMI->getParent() == BarrierMBB) + if (!DefMI || DefMI->getParent() == BarrierMBB) KillPt = findSpillPoint(BarrierMBB, Barrier, NULL, RefsInMBB); else KillPt = llvm::next(MachineBasicBlock::iterator(DefMI)); @@ -872,7 +880,7 @@ MachineInstr* PreAllocSplitting::FoldSpill(unsigned vreg, if (CurrSLI->hasAtLeastOneValue()) CurrSValNo = CurrSLI->getValNumInfo(0); else - CurrSValNo = CurrSLI->getNextValue(SlotIndex(), 0, false, + CurrSValNo = CurrSLI->getNextValue(SlotIndex(), 0, LSs->getVNInfoAllocator()); } @@ -967,8 +975,7 @@ bool PreAllocSplitting::SplitRegLiveInterval(LiveInterval *LI) { assert(!ValNo->isUnused() && "Val# is defined by a dead def?"); - MachineInstr *DefMI = ValNo->isDefAccurate() - ? LIs->getInstructionFromIndex(ValNo->def) : NULL; + MachineInstr *DefMI = LIs->getInstructionFromIndex(ValNo->def); // If this would create a new join point, do not split. if (DefMI && createsNewJoin(LR, DefMI->getParent(), Barrier->getParent())) { @@ -1005,7 +1012,7 @@ bool PreAllocSplitting::SplitRegLiveInterval(LiveInterval *LI) { SlotIndex SpillIndex; MachineInstr *SpillMI = NULL; int SS = -1; - if (!ValNo->isDefAccurate()) { + if (!DefMI) { // If we don't know where the def is we must split just before the barrier. if ((SpillMI = FoldSpill(LI->reg, RC, 0, Barrier, BarrierMBB, SS, RefsInMBB))) { @@ -1199,12 +1206,12 @@ bool PreAllocSplitting::removeDeadSpills(SmallPtrSet& split) { // We also don't try to handle the results of PHI joins, since there's // no defining instruction to analyze. - if (!CurrVN->isDefAccurate() || CurrVN->isUnused()) continue; + MachineInstr* DefMI = LIs->getInstructionFromIndex(CurrVN->def); + if (!DefMI || CurrVN->isUnused()) continue; // We're only interested in eliminating cruft introduced by the splitter, // is of the form load-use or load-use-store. First, check that the // definition is a load, and remember what stack slot we loaded it from. - MachineInstr* DefMI = LIs->getInstructionFromIndex(CurrVN->def); int FrameIndex; if (!TII->isLoadFromStackSlot(DefMI, FrameIndex)) continue; diff --git a/lib/CodeGen/ProcessImplicitDefs.cpp b/lib/CodeGen/ProcessImplicitDefs.cpp index b8831db1d118..9cd9941e56b3 100644 --- a/lib/CodeGen/ProcessImplicitDefs.cpp +++ b/lib/CodeGen/ProcessImplicitDefs.cpp @@ -26,8 +26,11 @@ using namespace llvm; char ProcessImplicitDefs::ID = 0; -INITIALIZE_PASS(ProcessImplicitDefs, "processimpdefs", - "Process Implicit Definitions.", false, false); +INITIALIZE_PASS_BEGIN(ProcessImplicitDefs, "processimpdefs", + "Process Implicit Definitions", false, false) +INITIALIZE_PASS_DEPENDENCY(LiveVariables) +INITIALIZE_PASS_END(ProcessImplicitDefs, "processimpdefs", + "Process Implicit Definitions", false, false) void ProcessImplicitDefs::getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); diff --git a/lib/CodeGen/PrologEpilogInserter.cpp b/lib/CodeGen/PrologEpilogInserter.cpp index e2802c1fdf4a..ad7b6e4aa97f 100644 --- a/lib/CodeGen/PrologEpilogInserter.cpp +++ b/lib/CodeGen/PrologEpilogInserter.cpp @@ -21,6 +21,7 @@ #define DEBUG_TYPE "pei" #include "PrologEpilogInserter.h" +#include "llvm/InlineAsm.h" #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineLoopInfo.h" #include "llvm/CodeGen/MachineInstr.h" @@ -29,7 +30,7 @@ #include "llvm/CodeGen/RegisterScavenging.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetRegisterInfo.h" -#include "llvm/Target/TargetFrameInfo.h" +#include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" @@ -44,8 +45,12 @@ using namespace llvm; char PEI::ID = 0; -INITIALIZE_PASS(PEI, "prologepilog", - "Prologue/Epilogue Insertion", false, false); +INITIALIZE_PASS_BEGIN(PEI, "prologepilog", + "Prologue/Epilogue Insertion", false, false) +INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo) +INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree) +INITIALIZE_PASS_END(PEI, "prologepilog", + "Prologue/Epilogue Insertion", false, false) STATISTIC(NumVirtualFrameRegs, "Number of virtual frame regs encountered"); STATISTIC(NumScavengedRegs, "Number of frame index regs scavenged"); @@ -61,6 +66,8 @@ FunctionPass *llvm::createPrologEpilogCodeInserter() { return new PEI(); } bool PEI::runOnMachineFunction(MachineFunction &Fn) { const Function* F = Fn.getFunction(); const TargetRegisterInfo *TRI = Fn.getTarget().getRegisterInfo(); + const TargetFrameLowering *TFI = Fn.getTarget().getFrameLowering(); + RS = TRI->requiresRegisterScavenging(Fn) ? new RegScavenger() : NULL; FrameIndexVirtualScavenging = TRI->requiresFrameIndexScavenging(Fn); @@ -71,7 +78,7 @@ bool PEI::runOnMachineFunction(MachineFunction &Fn) { // Allow the target machine to make some adjustments to the function // e.g. UsedPhysRegs before calculateCalleeSavedRegisters. - TRI->processFunctionBeforeCalleeSavedScan(Fn, RS); + TFI->processFunctionBeforeCalleeSavedScan(Fn, RS); // Scan the function for modified callee saved registers and insert spill code // for any callee saved registers that are modified. @@ -91,7 +98,7 @@ bool PEI::runOnMachineFunction(MachineFunction &Fn) { // Allow the target machine to make final modifications to the function // before the frame layout is finalized. - TRI->processFunctionBeforeFrameFinalized(Fn); + TFI->processFunctionBeforeFrameFinalized(Fn); // Calculate actual frame offsets for all abstract stack objects... calculateFrameObjectOffsets(Fn); @@ -138,6 +145,7 @@ void PEI::getAnalysisUsage(AnalysisUsage &AU) const { /// pseudo instructions. void PEI::calculateCallsInformation(MachineFunction &Fn) { const TargetRegisterInfo *RegInfo = Fn.getTarget().getRegisterInfo(); + const TargetFrameLowering *TFI = Fn.getTarget().getFrameLowering(); MachineFrameInfo *MFI = Fn.getFrameInfo(); unsigned MaxCallFrameSize = 0; @@ -165,7 +173,8 @@ void PEI::calculateCallsInformation(MachineFunction &Fn) { FrameSDOps.push_back(I); } else if (I->isInlineAsm()) { // Some inline asm's need a stack frame, as indicated by operand 1. - if (I->getOperand(1).getImm()) + unsigned ExtraInfo = I->getOperand(InlineAsm::MIOp_ExtraInfo).getImm(); + if (ExtraInfo & InlineAsm::Extra_IsAlignStack) AdjustsStack = true; } @@ -180,7 +189,7 @@ void PEI::calculateCallsInformation(MachineFunction &Fn) { // the target doesn't indicate otherwise, remove the call frame pseudos // here. The sub/add sp instruction pairs are still inserted, but we don't // need to track the SP adjustment for frame index elimination. - if (RegInfo->canSimplifyCallFramePseudos(Fn)) + if (TFI->canSimplifyCallFramePseudos(Fn)) RegInfo->eliminateCallFramePseudoInstr(Fn, *I->getParent(), I); } } @@ -190,7 +199,7 @@ void PEI::calculateCallsInformation(MachineFunction &Fn) { /// registers. void PEI::calculateCalleeSavedRegisters(MachineFunction &Fn) { const TargetRegisterInfo *RegInfo = Fn.getTarget().getRegisterInfo(); - const TargetFrameInfo *TFI = Fn.getTarget().getFrameInfo(); + const TargetFrameLowering *TFI = Fn.getTarget().getFrameLowering(); MachineFrameInfo *MFI = Fn.getFrameInfo(); // Get the callee saved register list... @@ -229,7 +238,7 @@ void PEI::calculateCalleeSavedRegisters(MachineFunction &Fn) { return; // Early exit if no callee saved registers are modified! unsigned NumFixedSpillSlots; - const TargetFrameInfo::SpillSlot *FixedSpillSlots = + const TargetFrameLowering::SpillSlot *FixedSpillSlots = TFI->getCalleeSavedSpillSlots(NumFixedSpillSlots); // Now that we know which registers need to be saved and restored, allocate @@ -247,7 +256,7 @@ void PEI::calculateCalleeSavedRegisters(MachineFunction &Fn) { // Check to see if this physreg must be spilled to a particular stack slot // on this target. - const TargetFrameInfo::SpillSlot *FixedSlot = FixedSpillSlots; + const TargetFrameLowering::SpillSlot *FixedSlot = FixedSpillSlots; while (FixedSlot != FixedSpillSlots+NumFixedSpillSlots && FixedSlot->Reg != Reg) ++FixedSlot; @@ -290,13 +299,14 @@ void PEI::insertCSRSpillsAndRestores(MachineFunction &Fn) { return; const TargetInstrInfo &TII = *Fn.getTarget().getInstrInfo(); + const TargetFrameLowering *TFI = Fn.getTarget().getFrameLowering(); const TargetRegisterInfo *TRI = Fn.getTarget().getRegisterInfo(); MachineBasicBlock::iterator I; if (! ShrinkWrapThisFunction) { // Spill using target interface. I = EntryBlock->begin(); - if (!TII.spillCalleeSavedRegisters(*EntryBlock, I, CSI, TRI)) { + if (!TFI->spillCalleeSavedRegisters(*EntryBlock, I, CSI, TRI)) { for (unsigned i = 0, e = CSI.size(); i != e; ++i) { // Add the callee-saved register as live-in. // It's killed at the spill. @@ -328,7 +338,7 @@ void PEI::insertCSRSpillsAndRestores(MachineFunction &Fn) { // Restore all registers immediately before the return and any // terminators that preceed it. - if (!TII.restoreCalleeSavedRegisters(*MBB, I, CSI, TRI)) { + if (!TFI->restoreCalleeSavedRegisters(*MBB, I, CSI, TRI)) { for (unsigned i = 0, e = CSI.size(); i != e; ++i) { unsigned Reg = CSI[i].getReg(); const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); @@ -480,10 +490,10 @@ AdjustStackOffset(MachineFrameInfo *MFI, int FrameIdx, /// abstract stack objects. /// void PEI::calculateFrameObjectOffsets(MachineFunction &Fn) { - const TargetFrameInfo &TFI = *Fn.getTarget().getFrameInfo(); + const TargetFrameLowering &TFI = *Fn.getTarget().getFrameLowering(); bool StackGrowsDown = - TFI.getStackGrowthDirection() == TargetFrameInfo::StackGrowsDown; + TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsDown; // Loop over all of the stack objects, assigning sequential addresses... MachineFrameInfo *MFI = Fn.getFrameInfo(); @@ -549,7 +559,7 @@ void PEI::calculateFrameObjectOffsets(MachineFunction &Fn) { // Make sure the special register scavenging spill slot is closest to the // frame pointer if a frame pointer is required. const TargetRegisterInfo *RegInfo = Fn.getTarget().getRegisterInfo(); - if (RS && RegInfo->hasFP(Fn) && !RegInfo->needsStackRealignment(Fn)) { + if (RS && TFI.hasFP(Fn) && !RegInfo->needsStackRealignment(Fn)) { int SFI = RS->getScavengingFrameIndex(); if (SFI >= 0) AdjustStackOffset(MFI, SFI, StackGrowsDown, Offset, MaxAlign); @@ -631,17 +641,17 @@ void PEI::calculateFrameObjectOffsets(MachineFunction &Fn) { // Make sure the special register scavenging spill slot is closest to the // stack pointer. - if (RS && (!RegInfo->hasFP(Fn) || RegInfo->needsStackRealignment(Fn))) { + if (RS && (!TFI.hasFP(Fn) || RegInfo->needsStackRealignment(Fn))) { int SFI = RS->getScavengingFrameIndex(); if (SFI >= 0) AdjustStackOffset(MFI, SFI, StackGrowsDown, Offset, MaxAlign); } - if (!RegInfo->targetHandlesStackFrameRounding()) { + if (!TFI.targetHandlesStackFrameRounding()) { // If we have reserved argument space for call sites in the function // immediately on entry to the current function, count it as part of the // overall stack size. - if (MFI->adjustsStack() && RegInfo->hasReservedCallFrame(Fn)) + if (MFI->adjustsStack() && TFI.hasReservedCallFrame(Fn)) Offset += MFI->getMaxCallFrameSize(); // Round up the size to a multiple of the alignment. If the function has @@ -672,16 +682,16 @@ void PEI::calculateFrameObjectOffsets(MachineFunction &Fn) { /// prolog and epilog code to the function. /// void PEI::insertPrologEpilogCode(MachineFunction &Fn) { - const TargetRegisterInfo *TRI = Fn.getTarget().getRegisterInfo(); + const TargetFrameLowering &TFI = *Fn.getTarget().getFrameLowering(); // Add prologue to the function... - TRI->emitPrologue(Fn); + TFI.emitPrologue(Fn); // Add epilogue to restore the callee-save registers in each exiting block for (MachineFunction::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I) { // If last instruction is a return instruction, add an epilogue if (!I->empty() && I->back().getDesc().isReturn()) - TRI->emitEpilogue(Fn, *I); + TFI.emitEpilogue(Fn, *I); } } @@ -694,9 +704,9 @@ void PEI::replaceFrameIndices(MachineFunction &Fn) { const TargetMachine &TM = Fn.getTarget(); assert(TM.getRegisterInfo() && "TM::getRegisterInfo() must be implemented!"); const TargetRegisterInfo &TRI = *TM.getRegisterInfo(); - const TargetFrameInfo *TFI = TM.getFrameInfo(); + const TargetFrameLowering *TFI = TM.getFrameLowering(); bool StackGrowsDown = - TFI->getStackGrowthDirection() == TargetFrameInfo::StackGrowsDown; + TFI->getStackGrowthDirection() == TargetFrameLowering::StackGrowsDown; int FrameSetupOpcode = TRI.getCallFrameSetupOpcode(); int FrameDestroyOpcode = TRI.getCallFrameDestroyOpcode(); @@ -755,8 +765,8 @@ void PEI::replaceFrameIndices(MachineFunction &Fn) { // If this instruction has a FrameIndex operand, we need to // use that target machine register info object to eliminate // it. - TRI.eliminateFrameIndex(MI, SPAdj, - FrameIndexVirtualScavenging ? NULL : RS); + TRI.eliminateFrameIndex(MI, SPAdj, + FrameIndexVirtualScavenging ? NULL : RS); // Reset the iterator if we were at the beginning of the BB. if (AtBeginning) { @@ -825,7 +835,7 @@ void PEI::scavengeFrameVirtualRegs(MachineFunction &Fn) { ScratchReg = RS->scavengeRegister(RC, I, SPAdj); ++NumScavengedRegs; } - // replace this reference to the virtual register with the + // Replace this reference to the virtual register with the // scratch register. assert (ScratchReg && "Missing scratch register!"); MI->getOperand(i).setReg(ScratchReg); diff --git a/lib/CodeGen/PrologEpilogInserter.h b/lib/CodeGen/PrologEpilogInserter.h index d575124a6b3e..e2391591ad06 100644 --- a/lib/CodeGen/PrologEpilogInserter.h +++ b/lib/CodeGen/PrologEpilogInserter.h @@ -36,7 +36,9 @@ namespace llvm { class PEI : public MachineFunctionPass { public: static char ID; - PEI() : MachineFunctionPass(ID) {} + PEI() : MachineFunctionPass(ID) { + initializePEIPass(*PassRegistry::getPassRegistry()); + } const char *getPassName() const { return "Prolog/Epilog Insertion & Frame Finalization"; diff --git a/lib/CodeGen/PseudoSourceValue.cpp b/lib/CodeGen/PseudoSourceValue.cpp index 5e86e5a9447e..73b66d868f3d 100644 --- a/lib/CodeGen/PseudoSourceValue.cpp +++ b/lib/CodeGen/PseudoSourceValue.cpp @@ -18,7 +18,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Mutex.h" +#include "llvm/Support/Mutex.h" #include using namespace llvm; diff --git a/lib/CodeGen/RegAllocBase.h b/lib/CodeGen/RegAllocBase.h new file mode 100644 index 000000000000..8c7e5f53b824 --- /dev/null +++ b/lib/CodeGen/RegAllocBase.h @@ -0,0 +1,181 @@ +//===-- RegAllocBase.h - basic regalloc interface and driver --*- C++ -*---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the RegAllocBase class, which is the skeleton of a basic +// register allocation algorithm and interface for extending it. It provides the +// building blocks on which to construct other experimental allocators and test +// the validity of two principles: +// +// - If virtual and physical register liveness is modeled using intervals, then +// on-the-fly interference checking is cheap. Furthermore, interferences can be +// lazily cached and reused. +// +// - Register allocation complexity, and generated code performance is +// determined by the effectiveness of live range splitting rather than optimal +// coloring. +// +// Following the first principle, interfering checking revolves around the +// LiveIntervalUnion data structure. +// +// To fulfill the second principle, the basic allocator provides a driver for +// incremental splitting. It essentially punts on the problem of register +// coloring, instead driving the assignment of virtual to physical registers by +// the cost of splitting. The basic allocator allows for heuristic reassignment +// of registers, if a more sophisticated allocator chooses to do that. +// +// This framework provides a way to engineer the compile time vs. code +// quality trade-off without relying on a particular theoretical solver. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_REGALLOCBASE +#define LLVM_CODEGEN_REGALLOCBASE + +#include "llvm/ADT/OwningPtr.h" +#include "LiveIntervalUnion.h" +#include + +namespace llvm { + +template class SmallVectorImpl; +class TargetRegisterInfo; +class VirtRegMap; +class LiveIntervals; +class Spiller; + +// Forward declare a priority queue of live virtual registers. If an +// implementation needs to prioritize by anything other than spill weight, then +// this will become an abstract base class with virtual calls to push/get. +class LiveVirtRegQueue; + +/// RegAllocBase provides the register allocation driver and interface that can +/// be extended to add interesting heuristics. +/// +/// Register allocators must override the selectOrSplit() method to implement +/// live range splitting. They may also override getPriority() which otherwise +/// defaults to the spill weight computed by CalculateSpillWeights. +class RegAllocBase { + LiveIntervalUnion::Allocator UnionAllocator; +protected: + // Array of LiveIntervalUnions indexed by physical register. + class LiveUnionArray { + unsigned NumRegs; + LiveIntervalUnion *Array; + public: + LiveUnionArray(): NumRegs(0), Array(0) {} + ~LiveUnionArray() { clear(); } + + unsigned numRegs() const { return NumRegs; } + + void init(LiveIntervalUnion::Allocator &, unsigned NRegs); + + void clear(); + + LiveIntervalUnion& operator[](unsigned PhysReg) { + assert(PhysReg < NumRegs && "physReg out of bounds"); + return Array[PhysReg]; + } + }; + + const TargetRegisterInfo *TRI; + MachineRegisterInfo *MRI; + VirtRegMap *VRM; + LiveIntervals *LIS; + LiveUnionArray PhysReg2LiveUnion; + + // Current queries, one per physreg. They must be reinitialized each time we + // query on a new live virtual register. + OwningArrayPtr Queries; + + RegAllocBase(): TRI(0), MRI(0), VRM(0), LIS(0) {} + + virtual ~RegAllocBase() {} + + // A RegAlloc pass should call this before allocatePhysRegs. + void init(VirtRegMap &vrm, LiveIntervals &lis); + + // Get an initialized query to check interferences between lvr and preg. Note + // that Query::init must be called at least once for each physical register + // before querying a new live virtual register. This ties Queries and + // PhysReg2LiveUnion together. + LiveIntervalUnion::Query &query(LiveInterval &VirtReg, unsigned PhysReg) { + Queries[PhysReg].init(&VirtReg, &PhysReg2LiveUnion[PhysReg]); + return Queries[PhysReg]; + } + + // The top-level driver. The output is a VirtRegMap that us updated with + // physical register assignments. + // + // If an implementation wants to override the LiveInterval comparator, we + // should modify this interface to allow passing in an instance derived from + // LiveVirtRegQueue. + void allocatePhysRegs(); + + // Get a temporary reference to a Spiller instance. + virtual Spiller &spiller() = 0; + + // getPriority - Calculate the allocation priority for VirtReg. + // Virtual registers with higher priorities are allocated first. + virtual float getPriority(LiveInterval *LI) = 0; + + // A RegAlloc pass should override this to provide the allocation heuristics. + // Each call must guarantee forward progess by returning an available PhysReg + // or new set of split live virtual registers. It is up to the splitter to + // converge quickly toward fully spilled live ranges. + virtual unsigned selectOrSplit(LiveInterval &VirtReg, + SmallVectorImpl &splitLVRs) = 0; + + // A RegAlloc pass should call this when PassManager releases its memory. + virtual void releaseMemory(); + + // Helper for checking interference between a live virtual register and a + // physical register, including all its register aliases. If an interference + // exists, return the interfering register, which may be preg or an alias. + unsigned checkPhysRegInterference(LiveInterval& VirtReg, unsigned PhysReg); + + /// assign - Assign VirtReg to PhysReg. + /// This should not be called from selectOrSplit for the current register. + void assign(LiveInterval &VirtReg, unsigned PhysReg); + + /// unassign - Undo a previous assignment of VirtReg to PhysReg. + /// This can be invoked from selectOrSplit, but be careful to guarantee that + /// allocation is making progress. + void unassign(LiveInterval &VirtReg, unsigned PhysReg); + + // Helper for spilling all live virtual registers currently unified under preg + // that interfere with the most recently queried lvr. Return true if spilling + // was successful, and append any new spilled/split intervals to splitLVRs. + bool spillInterferences(LiveInterval &VirtReg, unsigned PhysReg, + SmallVectorImpl &SplitVRegs); + + /// addMBBLiveIns - Add physreg liveins to basic blocks. + void addMBBLiveIns(MachineFunction *); + +#ifndef NDEBUG + // Verify each LiveIntervalUnion. + void verify(); +#endif + + // Use this group name for NamedRegionTimer. + static const char *TimerGroupName; + +public: + /// VerifyEnabled - True when -verify-regalloc is given. + static bool VerifyEnabled; + +private: + void seedLiveVirtRegs(std::priority_queue >&); + + void spillReg(LiveInterval &VirtReg, unsigned PhysReg, + SmallVectorImpl &SplitVRegs); +}; + +} // end namespace llvm + +#endif // !defined(LLVM_CODEGEN_REGALLOCBASE) diff --git a/lib/CodeGen/RegAllocBasic.cpp b/lib/CodeGen/RegAllocBasic.cpp new file mode 100644 index 000000000000..045c8db9dadb --- /dev/null +++ b/lib/CodeGen/RegAllocBasic.cpp @@ -0,0 +1,523 @@ +//===-- RegAllocBasic.cpp - basic register allocator ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the RABasic function pass, which provides a minimal +// implementation of the basic register allocator. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "regalloc" +#include "LiveIntervalUnion.h" +#include "RegAllocBase.h" +#include "RenderMachineFunction.h" +#include "Spiller.h" +#include "VirtRegMap.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Function.h" +#include "llvm/PassAnalysisSupport.h" +#include "llvm/CodeGen/CalcSpillWeights.h" +#include "llvm/CodeGen/LiveIntervalAnalysis.h" +#include "llvm/CodeGen/LiveStackAnalysis.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineLoopInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/RegAllocRegistry.h" +#include "llvm/CodeGen/RegisterCoalescer.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetRegisterInfo.h" +#ifndef NDEBUG +#include "llvm/ADT/SparseBitVector.h" +#endif +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Timer.h" + +#include + +using namespace llvm; + +STATISTIC(NumAssigned , "Number of registers assigned"); +STATISTIC(NumUnassigned , "Number of registers unassigned"); +STATISTIC(NumNewQueued , "Number of new live ranges queued"); + +static RegisterRegAlloc basicRegAlloc("basic", "basic register allocator", + createBasicRegisterAllocator); + +// Temporary verification option until we can put verification inside +// MachineVerifier. +static cl::opt +VerifyRegAlloc("verify-regalloc", cl::location(RegAllocBase::VerifyEnabled), + cl::desc("Verify during register allocation")); + +const char *RegAllocBase::TimerGroupName = "Register Allocation"; +bool RegAllocBase::VerifyEnabled = false; + +namespace { +/// RABasic provides a minimal implementation of the basic register allocation +/// algorithm. It prioritizes live virtual registers by spill weight and spills +/// whenever a register is unavailable. This is not practical in production but +/// provides a useful baseline both for measuring other allocators and comparing +/// the speed of the basic algorithm against other styles of allocators. +class RABasic : public MachineFunctionPass, public RegAllocBase +{ + // context + MachineFunction *MF; + BitVector ReservedRegs; + + // analyses + LiveStacks *LS; + RenderMachineFunction *RMF; + + // state + std::auto_ptr SpillerInstance; + +public: + RABasic(); + + /// Return the pass name. + virtual const char* getPassName() const { + return "Basic Register Allocator"; + } + + /// RABasic analysis usage. + virtual void getAnalysisUsage(AnalysisUsage &AU) const; + + virtual void releaseMemory(); + + virtual Spiller &spiller() { return *SpillerInstance; } + + virtual float getPriority(LiveInterval *LI) { return LI->weight; } + + virtual unsigned selectOrSplit(LiveInterval &VirtReg, + SmallVectorImpl &SplitVRegs); + + /// Perform register allocation. + virtual bool runOnMachineFunction(MachineFunction &mf); + + static char ID; +}; + +char RABasic::ID = 0; + +} // end anonymous namespace + +RABasic::RABasic(): MachineFunctionPass(ID) { + initializeLiveIntervalsPass(*PassRegistry::getPassRegistry()); + initializeSlotIndexesPass(*PassRegistry::getPassRegistry()); + initializeStrongPHIEliminationPass(*PassRegistry::getPassRegistry()); + initializeRegisterCoalescerAnalysisGroup(*PassRegistry::getPassRegistry()); + initializeCalculateSpillWeightsPass(*PassRegistry::getPassRegistry()); + initializeLiveStacksPass(*PassRegistry::getPassRegistry()); + initializeMachineDominatorTreePass(*PassRegistry::getPassRegistry()); + initializeMachineLoopInfoPass(*PassRegistry::getPassRegistry()); + initializeVirtRegMapPass(*PassRegistry::getPassRegistry()); + initializeRenderMachineFunctionPass(*PassRegistry::getPassRegistry()); +} + +void RABasic::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesCFG(); + AU.addRequired(); + AU.addPreserved(); + AU.addRequired(); + AU.addPreserved(); + if (StrongPHIElim) + AU.addRequiredID(StrongPHIEliminationID); + AU.addRequiredTransitive(); + AU.addRequired(); + AU.addRequired(); + AU.addPreserved(); + AU.addRequiredID(MachineDominatorsID); + AU.addPreservedID(MachineDominatorsID); + AU.addRequired(); + AU.addPreserved(); + AU.addRequired(); + AU.addPreserved(); + DEBUG(AU.addRequired()); + MachineFunctionPass::getAnalysisUsage(AU); +} + +void RABasic::releaseMemory() { + SpillerInstance.reset(0); + RegAllocBase::releaseMemory(); +} + +#ifndef NDEBUG +// Verify each LiveIntervalUnion. +void RegAllocBase::verify() { + LiveVirtRegBitSet VisitedVRegs; + OwningArrayPtr + unionVRegs(new LiveVirtRegBitSet[PhysReg2LiveUnion.numRegs()]); + + // Verify disjoint unions. + for (unsigned PhysReg = 0; PhysReg < PhysReg2LiveUnion.numRegs(); ++PhysReg) { + DEBUG(PhysReg2LiveUnion[PhysReg].print(dbgs(), TRI)); + LiveVirtRegBitSet &VRegs = unionVRegs[PhysReg]; + PhysReg2LiveUnion[PhysReg].verify(VRegs); + // Union + intersection test could be done efficiently in one pass, but + // don't add a method to SparseBitVector unless we really need it. + assert(!VisitedVRegs.intersects(VRegs) && "vreg in multiple unions"); + VisitedVRegs |= VRegs; + } + + // Verify vreg coverage. + for (LiveIntervals::iterator liItr = LIS->begin(), liEnd = LIS->end(); + liItr != liEnd; ++liItr) { + unsigned reg = liItr->first; + if (TargetRegisterInfo::isPhysicalRegister(reg)) continue; + if (!VRM->hasPhys(reg)) continue; // spilled? + unsigned PhysReg = VRM->getPhys(reg); + if (!unionVRegs[PhysReg].test(reg)) { + dbgs() << "LiveVirtReg " << reg << " not in union " << + TRI->getName(PhysReg) << "\n"; + llvm_unreachable("unallocated live vreg"); + } + } + // FIXME: I'm not sure how to verify spilled intervals. +} +#endif //!NDEBUG + +//===----------------------------------------------------------------------===// +// RegAllocBase Implementation +//===----------------------------------------------------------------------===// + +// Instantiate a LiveIntervalUnion for each physical register. +void RegAllocBase::LiveUnionArray::init(LiveIntervalUnion::Allocator &allocator, + unsigned NRegs) { + NumRegs = NRegs; + Array = + static_cast(malloc(sizeof(LiveIntervalUnion)*NRegs)); + for (unsigned r = 0; r != NRegs; ++r) + new(Array + r) LiveIntervalUnion(r, allocator); +} + +void RegAllocBase::init(VirtRegMap &vrm, LiveIntervals &lis) { + NamedRegionTimer T("Initialize", TimerGroupName, TimePassesIsEnabled); + TRI = &vrm.getTargetRegInfo(); + MRI = &vrm.getRegInfo(); + VRM = &vrm; + LIS = &lis; + PhysReg2LiveUnion.init(UnionAllocator, TRI->getNumRegs()); + // Cache an interferece query for each physical reg + Queries.reset(new LiveIntervalUnion::Query[PhysReg2LiveUnion.numRegs()]); +} + +void RegAllocBase::LiveUnionArray::clear() { + if (!Array) + return; + for (unsigned r = 0; r != NumRegs; ++r) + Array[r].~LiveIntervalUnion(); + free(Array); + NumRegs = 0; + Array = 0; +} + +void RegAllocBase::releaseMemory() { + PhysReg2LiveUnion.clear(); +} + +// Visit all the live virtual registers. If they are already assigned to a +// physical register, unify them with the corresponding LiveIntervalUnion, +// otherwise push them on the priority queue for later assignment. +void RegAllocBase:: +seedLiveVirtRegs(std::priority_queue > &VirtRegQ) { + for (LiveIntervals::iterator I = LIS->begin(), E = LIS->end(); I != E; ++I) { + unsigned RegNum = I->first; + LiveInterval &VirtReg = *I->second; + if (TargetRegisterInfo::isPhysicalRegister(RegNum)) + PhysReg2LiveUnion[RegNum].unify(VirtReg); + else + VirtRegQ.push(std::make_pair(getPriority(&VirtReg), RegNum)); + } +} + +void RegAllocBase::assign(LiveInterval &VirtReg, unsigned PhysReg) { + DEBUG(dbgs() << "assigning " << PrintReg(VirtReg.reg, TRI) + << " to " << PrintReg(PhysReg, TRI) << '\n'); + assert(!VRM->hasPhys(VirtReg.reg) && "Duplicate VirtReg assignment"); + VRM->assignVirt2Phys(VirtReg.reg, PhysReg); + PhysReg2LiveUnion[PhysReg].unify(VirtReg); + ++NumAssigned; +} + +void RegAllocBase::unassign(LiveInterval &VirtReg, unsigned PhysReg) { + DEBUG(dbgs() << "unassigning " << PrintReg(VirtReg.reg, TRI) + << " from " << PrintReg(PhysReg, TRI) << '\n'); + assert(VRM->getPhys(VirtReg.reg) == PhysReg && "Inconsistent unassign"); + PhysReg2LiveUnion[PhysReg].extract(VirtReg); + VRM->clearVirt(VirtReg.reg); + ++NumUnassigned; +} + +// Top-level driver to manage the queue of unassigned VirtRegs and call the +// selectOrSplit implementation. +void RegAllocBase::allocatePhysRegs() { + + // Push each vreg onto a queue or "precolor" by adding it to a physreg union. + std::priority_queue > VirtRegQ; + seedLiveVirtRegs(VirtRegQ); + + // Continue assigning vregs one at a time to available physical registers. + while (!VirtRegQ.empty()) { + // Pop the highest priority vreg. + LiveInterval &VirtReg = LIS->getInterval(VirtRegQ.top().second); + VirtRegQ.pop(); + + // selectOrSplit requests the allocator to return an available physical + // register if possible and populate a list of new live intervals that + // result from splitting. + DEBUG(dbgs() << "\nselectOrSplit " << MRI->getRegClass(VirtReg.reg)->getName() + << ':' << VirtReg << '\n'); + typedef SmallVector VirtRegVec; + VirtRegVec SplitVRegs; + unsigned AvailablePhysReg = selectOrSplit(VirtReg, SplitVRegs); + + if (AvailablePhysReg) + assign(VirtReg, AvailablePhysReg); + + for (VirtRegVec::iterator I = SplitVRegs.begin(), E = SplitVRegs.end(); + I != E; ++I) { + LiveInterval* SplitVirtReg = *I; + if (SplitVirtReg->empty()) continue; + DEBUG(dbgs() << "queuing new interval: " << *SplitVirtReg << "\n"); + assert(TargetRegisterInfo::isVirtualRegister(SplitVirtReg->reg) && + "expect split value in virtual register"); + VirtRegQ.push(std::make_pair(getPriority(SplitVirtReg), + SplitVirtReg->reg)); + ++NumNewQueued; + } + } +} + +// Check if this live virtual register interferes with a physical register. If +// not, then check for interference on each register that aliases with the +// physical register. Return the interfering register. +unsigned RegAllocBase::checkPhysRegInterference(LiveInterval &VirtReg, + unsigned PhysReg) { + for (const unsigned *AliasI = TRI->getOverlaps(PhysReg); *AliasI; ++AliasI) + if (query(VirtReg, *AliasI).checkInterference()) + return *AliasI; + return 0; +} + +// Helper for spillInteferences() that spills all interfering vregs currently +// assigned to this physical register. +void RegAllocBase::spillReg(LiveInterval& VirtReg, unsigned PhysReg, + SmallVectorImpl &SplitVRegs) { + LiveIntervalUnion::Query &Q = query(VirtReg, PhysReg); + assert(Q.seenAllInterferences() && "need collectInterferences()"); + const SmallVectorImpl &PendingSpills = Q.interferingVRegs(); + + for (SmallVectorImpl::const_iterator I = PendingSpills.begin(), + E = PendingSpills.end(); I != E; ++I) { + LiveInterval &SpilledVReg = **I; + DEBUG(dbgs() << "extracting from " << + TRI->getName(PhysReg) << " " << SpilledVReg << '\n'); + + // Deallocate the interfering vreg by removing it from the union. + // A LiveInterval instance may not be in a union during modification! + unassign(SpilledVReg, PhysReg); + + // Spill the extracted interval. + spiller().spill(&SpilledVReg, SplitVRegs, PendingSpills); + } + // After extracting segments, the query's results are invalid. But keep the + // contents valid until we're done accessing pendingSpills. + Q.clear(); +} + +// Spill or split all live virtual registers currently unified under PhysReg +// that interfere with VirtReg. The newly spilled or split live intervals are +// returned by appending them to SplitVRegs. +bool +RegAllocBase::spillInterferences(LiveInterval &VirtReg, unsigned PhysReg, + SmallVectorImpl &SplitVRegs) { + // Record each interference and determine if all are spillable before mutating + // either the union or live intervals. + unsigned NumInterferences = 0; + // Collect interferences assigned to any alias of the physical register. + for (const unsigned *asI = TRI->getOverlaps(PhysReg); *asI; ++asI) { + LiveIntervalUnion::Query &QAlias = query(VirtReg, *asI); + NumInterferences += QAlias.collectInterferingVRegs(); + if (QAlias.seenUnspillableVReg()) { + return false; + } + } + DEBUG(dbgs() << "spilling " << TRI->getName(PhysReg) << + " interferences with " << VirtReg << "\n"); + assert(NumInterferences > 0 && "expect interference"); + + // Spill each interfering vreg allocated to PhysReg or an alias. + for (const unsigned *AliasI = TRI->getOverlaps(PhysReg); *AliasI; ++AliasI) + spillReg(VirtReg, *AliasI, SplitVRegs); + return true; +} + +// Add newly allocated physical registers to the MBB live in sets. +void RegAllocBase::addMBBLiveIns(MachineFunction *MF) { + NamedRegionTimer T("MBB Live Ins", TimerGroupName, TimePassesIsEnabled); + typedef SmallVector MBBVec; + MBBVec liveInMBBs; + MachineBasicBlock &entryMBB = *MF->begin(); + + for (unsigned PhysReg = 0; PhysReg < PhysReg2LiveUnion.numRegs(); ++PhysReg) { + LiveIntervalUnion &LiveUnion = PhysReg2LiveUnion[PhysReg]; + if (LiveUnion.empty()) + continue; + for (LiveIntervalUnion::SegmentIter SI = LiveUnion.begin(); SI.valid(); + ++SI) { + + // Find the set of basic blocks which this range is live into... + liveInMBBs.clear(); + if (!LIS->findLiveInMBBs(SI.start(), SI.stop(), liveInMBBs)) continue; + + // And add the physreg for this interval to their live-in sets. + for (MBBVec::iterator I = liveInMBBs.begin(), E = liveInMBBs.end(); + I != E; ++I) { + MachineBasicBlock *MBB = *I; + if (MBB == &entryMBB) continue; + if (MBB->isLiveIn(PhysReg)) continue; + MBB->addLiveIn(PhysReg); + } + } + } +} + + +//===----------------------------------------------------------------------===// +// RABasic Implementation +//===----------------------------------------------------------------------===// + +// Driver for the register assignment and splitting heuristics. +// Manages iteration over the LiveIntervalUnions. +// +// This is a minimal implementation of register assignment and splitting that +// spills whenever we run out of registers. +// +// selectOrSplit can only be called once per live virtual register. We then do a +// single interference test for each register the correct class until we find an +// available register. So, the number of interference tests in the worst case is +// |vregs| * |machineregs|. And since the number of interference tests is +// minimal, there is no value in caching them outside the scope of +// selectOrSplit(). +unsigned RABasic::selectOrSplit(LiveInterval &VirtReg, + SmallVectorImpl &SplitVRegs) { + // Populate a list of physical register spill candidates. + SmallVector PhysRegSpillCands; + + // Check for an available register in this class. + const TargetRegisterClass *TRC = MRI->getRegClass(VirtReg.reg); + + for (TargetRegisterClass::iterator I = TRC->allocation_order_begin(*MF), + E = TRC->allocation_order_end(*MF); + I != E; ++I) { + + unsigned PhysReg = *I; + if (ReservedRegs.test(PhysReg)) continue; + + // Check interference and as a side effect, intialize queries for this + // VirtReg and its aliases. + unsigned interfReg = checkPhysRegInterference(VirtReg, PhysReg); + if (interfReg == 0) { + // Found an available register. + return PhysReg; + } + LiveInterval *interferingVirtReg = + Queries[interfReg].firstInterference().liveUnionPos().value(); + + // The current VirtReg must either be spillable, or one of its interferences + // must have less spill weight. + if (interferingVirtReg->weight < VirtReg.weight ) { + PhysRegSpillCands.push_back(PhysReg); + } + } + // Try to spill another interfering reg with less spill weight. + for (SmallVectorImpl::iterator PhysRegI = PhysRegSpillCands.begin(), + PhysRegE = PhysRegSpillCands.end(); PhysRegI != PhysRegE; ++PhysRegI) { + + if (!spillInterferences(VirtReg, *PhysRegI, SplitVRegs)) continue; + + assert(checkPhysRegInterference(VirtReg, *PhysRegI) == 0 && + "Interference after spill."); + // Tell the caller to allocate to this newly freed physical register. + return *PhysRegI; + } + // No other spill candidates were found, so spill the current VirtReg. + DEBUG(dbgs() << "spilling: " << VirtReg << '\n'); + SmallVector pendingSpills; + + spiller().spill(&VirtReg, SplitVRegs, pendingSpills); + + // The live virtual register requesting allocation was spilled, so tell + // the caller not to allocate anything during this round. + return 0; +} + +bool RABasic::runOnMachineFunction(MachineFunction &mf) { + DEBUG(dbgs() << "********** BASIC REGISTER ALLOCATION **********\n" + << "********** Function: " + << ((Value*)mf.getFunction())->getName() << '\n'); + + MF = &mf; + DEBUG(RMF = &getAnalysis()); + + RegAllocBase::init(getAnalysis(), getAnalysis()); + + ReservedRegs = TRI->getReservedRegs(*MF); + + SpillerInstance.reset(createSpiller(*this, *MF, *VRM)); + + allocatePhysRegs(); + + addMBBLiveIns(MF); + + // Diagnostic output before rewriting + DEBUG(dbgs() << "Post alloc VirtRegMap:\n" << *VRM << "\n"); + + // optional HTML output + DEBUG(RMF->renderMachineFunction("After basic register allocation.", VRM)); + + // FIXME: Verification currently must run before VirtRegRewriter. We should + // make the rewriter a separate pass and override verifyAnalysis instead. When + // that happens, verification naturally falls under VerifyMachineCode. +#ifndef NDEBUG + if (VerifyEnabled) { + // Verify accuracy of LiveIntervals. The standard machine code verifier + // ensures that each LiveIntervals covers all uses of the virtual reg. + + // FIXME: MachineVerifier is badly broken when using the standard + // spiller. Always use -spiller=inline with -verify-regalloc. Even with the + // inline spiller, some tests fail to verify because the coalescer does not + // always generate verifiable code. + MF->verify(this, "In RABasic::verify"); + + // Verify that LiveIntervals are partitioned into unions and disjoint within + // the unions. + verify(); + } +#endif // !NDEBUG + + // Run rewriter + VRM->rewrite(LIS->getSlotIndexes()); + + // The pass output is in VirtRegMap. Release all the transient data. + releaseMemory(); + + return true; +} + +FunctionPass* llvm::createBasicRegisterAllocator() +{ + return new RABasic(); +} diff --git a/lib/CodeGen/RegAllocFast.cpp b/lib/CodeGen/RegAllocFast.cpp index fc150d55e226..15036e38b893 100644 --- a/lib/CodeGen/RegAllocFast.cpp +++ b/lib/CodeGen/RegAllocFast.cpp @@ -48,7 +48,10 @@ namespace { public: static char ID; RAFast() : MachineFunctionPass(ID), StackSlotForVirtReg(-1), - isBulkSpilling(false) {} + isBulkSpilling(false) { + initializePHIEliminationPass(*PassRegistry::getPassRegistry()); + initializeTwoAddressInstructionPassPass(*PassRegistry::getPassRegistry()); + } private: const TargetMachine *TM; MachineFunction *MF; @@ -259,8 +262,8 @@ void RAFast::spillVirtReg(MachineBasicBlock::iterator MI, // instruction, not on the spill. bool SpillKill = LR.LastUse != MI; LR.Dirty = false; - DEBUG(dbgs() << "Spilling %reg" << LRI->first - << " in " << TRI->getName(LR.PhysReg)); + DEBUG(dbgs() << "Spilling " << PrintReg(LRI->first, TRI) + << " in " << PrintReg(LR.PhysReg, TRI)); const TargetRegisterClass *RC = MRI->getRegClass(LRI->first); int FI = getStackSpaceFor(LRI->first, RC); DEBUG(dbgs() << " to stack slot #" << FI << "\n"); @@ -331,7 +334,7 @@ void RAFast::usePhysReg(MachineOperand &MO) { MO.setIsKill(); return; default: - // The physreg was allocated to a virtual register. That means to value we + // The physreg was allocated to a virtual register. That means the value we // wanted has been clobbered. llvm_unreachable("Instruction uses an allocated register"); } @@ -458,8 +461,8 @@ unsigned RAFast::calcSpillCost(unsigned PhysReg) const { /// register must not be used for anything else when this is called. /// void RAFast::assignVirtToPhysReg(LiveRegEntry &LRE, unsigned PhysReg) { - DEBUG(dbgs() << "Assigning %reg" << LRE.first << " to " - << TRI->getName(PhysReg) << "\n"); + DEBUG(dbgs() << "Assigning " << PrintReg(LRE.first, TRI) << " to " + << PrintReg(PhysReg, TRI) << "\n"); PhysRegState[PhysReg] = LRE.first; assert(!LRE.second.PhysReg && "Already assigned a physreg"); LRE.second.PhysReg = PhysReg; @@ -503,8 +506,8 @@ void RAFast::allocVirtReg(MachineInstr *MI, LiveRegEntry &LRE, unsigned Hint) { return assignVirtToPhysReg(LRE, PhysReg); } - DEBUG(dbgs() << "Allocating %reg" << VirtReg << " from " << RC->getName() - << "\n"); + DEBUG(dbgs() << "Allocating " << PrintReg(VirtReg) << " from " + << RC->getName() << "\n"); unsigned BestReg = 0, BestCost = spillImpossible; for (TargetRegisterClass::iterator I = AOB; I != AOE; ++I) { @@ -584,8 +587,8 @@ RAFast::reloadVirtReg(MachineInstr *MI, unsigned OpNum, allocVirtReg(MI, *LRI, Hint); const TargetRegisterClass *RC = MRI->getRegClass(VirtReg); int FrameIndex = getStackSpaceFor(VirtReg, RC); - DEBUG(dbgs() << "Reloading %reg" << VirtReg << " into " - << TRI->getName(LR.PhysReg) << "\n"); + DEBUG(dbgs() << "Reloading " << PrintReg(VirtReg, TRI) << " into " + << PrintReg(LR.PhysReg, TRI) << "\n"); TII->loadRegFromStackSlot(*MBB, MI, LR.PhysReg, FrameIndex, RC, TRI); ++NumLoads; } else if (LR.Dirty) { @@ -653,11 +656,12 @@ void RAFast::handleThroughOperands(MachineInstr *MI, MachineOperand &MO = MI->getOperand(i); if (!MO.isReg()) continue; unsigned Reg = MO.getReg(); - if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg)) continue; + if (!TargetRegisterInfo::isVirtualRegister(Reg)) + continue; if (MO.isEarlyClobber() || MI->isRegTiedToDefOperand(i) || (MO.getSubReg() && MI->readsVirtualRegister(Reg))) { if (ThroughRegs.insert(Reg)) - DEBUG(dbgs() << " %reg" << Reg); + DEBUG(dbgs() << ' ' << PrintReg(Reg)); } } @@ -685,7 +689,7 @@ void RAFast::handleThroughOperands(MachineInstr *MI, MachineOperand &MO = MI->getOperand(i); if (!MO.isReg()) continue; unsigned Reg = MO.getReg(); - if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg)) continue; + if (!TargetRegisterInfo::isVirtualRegister(Reg)) continue; if (MO.isUse()) { unsigned DefIdx = 0; if (!MI->isRegTiedToDefOperand(i, &DefIdx)) continue; @@ -731,6 +735,27 @@ void RAFast::handleThroughOperands(MachineInstr *MI, void RAFast::AllocateBasicBlock() { DEBUG(dbgs() << "\nAllocating " << *MBB); + // FIXME: This should probably be added by instruction selection instead? + // If the last instruction in the block is a return, make sure to mark it as + // using all of the live-out values in the function. Things marked both call + // and return are tail calls; do not do this for them. The tail callee need + // not take the same registers as input that it produces as output, and there + // are dependencies for its input registers elsewhere. + if (!MBB->empty() && MBB->back().getDesc().isReturn() && + !MBB->back().getDesc().isCall()) { + MachineInstr *Ret = &MBB->back(); + + for (MachineRegisterInfo::liveout_iterator + I = MF->getRegInfo().liveout_begin(), + E = MF->getRegInfo().liveout_end(); I != E; ++I) { + assert(TargetRegisterInfo::isPhysicalRegister(*I) && + "Cannot have a live-out virtual register."); + + // Add live-out registers as implicit uses. + Ret->addRegisterKilled(*I, TRI, true); + } + } + PhysRegState.assign(TRI->getNumRegs(), regDisabled); assert(LiveVirtRegs.empty() && "Mapping not cleared form last block?"); @@ -761,7 +786,7 @@ void RAFast::AllocateBasicBlock() { dbgs() << "*"; break; default: - dbgs() << "=%reg" << PhysRegState[Reg]; + dbgs() << '=' << PrintReg(PhysRegState[Reg]); if (LiveVirtRegs[PhysRegState[Reg]].Dirty) dbgs() << "*"; assert(LiveVirtRegs[PhysRegState[Reg]].PhysReg == Reg && @@ -791,16 +816,18 @@ void RAFast::AllocateBasicBlock() { MachineOperand &MO = MI->getOperand(i); if (!MO.isReg()) continue; unsigned Reg = MO.getReg(); - if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg)) continue; + if (!TargetRegisterInfo::isVirtualRegister(Reg)) continue; LiveDbgValueMap[Reg] = MI; LiveRegMap::iterator LRI = LiveVirtRegs.find(Reg); if (LRI != LiveVirtRegs.end()) setPhysReg(MI, i, LRI->second.PhysReg); else { int SS = StackSlotForVirtReg[Reg]; - if (SS == -1) + if (SS == -1) { // We can't allocate a physreg for a DebugValue, sorry! + DEBUG(dbgs() << "Unable to allocate vreg used by DBG_VALUE"); MO.setReg(0); + } else { // Modify DBG_VALUE now that the value is in a spill slot. int64_t Offset = MI->getOperand(1).getImm(); @@ -817,9 +844,11 @@ void RAFast::AllocateBasicBlock() { MI = NewDV; ScanDbgValue = true; break; - } else + } else { // We can't allocate a physreg for a DebugValue; sorry! + DEBUG(dbgs() << "Unable to allocate vreg used by DBG_VALUE"); MO.setReg(0); + } } } } @@ -902,7 +931,7 @@ void RAFast::AllocateBasicBlock() { MachineOperand &MO = MI->getOperand(i); if (!MO.isReg()) continue; unsigned Reg = MO.getReg(); - if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg)) continue; + if (!TargetRegisterInfo::isVirtualRegister(Reg)) continue; if (MO.isUse()) { LiveRegMap::iterator LRI = reloadVirtReg(MI, i, Reg, CopyDst); unsigned PhysReg = LRI->second.PhysReg; @@ -1017,8 +1046,7 @@ bool RAFast::runOnMachineFunction(MachineFunction &Fn) { // initialize the virtual->physical register map to have a 'null' // mapping for all virtual registers - unsigned LastVirtReg = MRI->getLastVirtReg(); - StackSlotForVirtReg.grow(LastVirtReg); + StackSlotForVirtReg.resize(MRI->getNumVirtRegs()); // Loop over all of the basic blocks, eliminating virtual register references for (MachineFunction::iterator MBBi = Fn.begin(), MBBe = Fn.end(); diff --git a/lib/CodeGen/RegAllocGreedy.cpp b/lib/CodeGen/RegAllocGreedy.cpp new file mode 100644 index 000000000000..c1372cd038cf --- /dev/null +++ b/lib/CodeGen/RegAllocGreedy.cpp @@ -0,0 +1,1285 @@ +//===-- RegAllocGreedy.cpp - greedy register allocator --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the RAGreedy function pass for register allocation in +// optimized builds. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "regalloc" +#include "AllocationOrder.h" +#include "LiveIntervalUnion.h" +#include "LiveRangeEdit.h" +#include "RegAllocBase.h" +#include "Spiller.h" +#include "SpillPlacement.h" +#include "SplitKit.h" +#include "VirtRegMap.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Function.h" +#include "llvm/PassAnalysisSupport.h" +#include "llvm/CodeGen/CalcSpillWeights.h" +#include "llvm/CodeGen/EdgeBundles.h" +#include "llvm/CodeGen/LiveIntervalAnalysis.h" +#include "llvm/CodeGen/LiveStackAnalysis.h" +#include "llvm/CodeGen/MachineDominators.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineLoopInfo.h" +#include "llvm/CodeGen/MachineLoopRanges.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/RegAllocRegistry.h" +#include "llvm/CodeGen/RegisterCoalescer.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Timer.h" + +using namespace llvm; + +STATISTIC(NumGlobalSplits, "Number of split global live ranges"); +STATISTIC(NumLocalSplits, "Number of split local live ranges"); +STATISTIC(NumReassigned, "Number of interferences reassigned"); +STATISTIC(NumEvicted, "Number of interferences evicted"); + +static RegisterRegAlloc greedyRegAlloc("greedy", "greedy register allocator", + createGreedyRegisterAllocator); + +namespace { +class RAGreedy : public MachineFunctionPass, public RegAllocBase { + // context + MachineFunction *MF; + BitVector ReservedRegs; + + // analyses + SlotIndexes *Indexes; + LiveStacks *LS; + MachineDominatorTree *DomTree; + MachineLoopInfo *Loops; + MachineLoopRanges *LoopRanges; + EdgeBundles *Bundles; + SpillPlacement *SpillPlacer; + + // state + std::auto_ptr SpillerInstance; + std::auto_ptr SA; + + // splitting state. + + /// All basic blocks where the current register is live. + SmallVector SpillConstraints; + + /// For every instruction in SA->UseSlots, store the previous non-copy + /// instruction. + SmallVector PrevSlot; + +public: + RAGreedy(); + + /// Return the pass name. + virtual const char* getPassName() const { + return "Greedy Register Allocator"; + } + + /// RAGreedy analysis usage. + virtual void getAnalysisUsage(AnalysisUsage &AU) const; + + virtual void releaseMemory(); + + virtual Spiller &spiller() { return *SpillerInstance; } + + virtual float getPriority(LiveInterval *LI); + + virtual unsigned selectOrSplit(LiveInterval&, + SmallVectorImpl&); + + /// Perform register allocation. + virtual bool runOnMachineFunction(MachineFunction &mf); + + static char ID; + +private: + bool checkUncachedInterference(LiveInterval&, unsigned); + LiveInterval *getSingleInterference(LiveInterval&, unsigned); + bool reassignVReg(LiveInterval &InterferingVReg, unsigned OldPhysReg); + float calcInterferenceWeight(LiveInterval&, unsigned); + float calcInterferenceInfo(LiveInterval&, unsigned); + float calcGlobalSplitCost(const BitVector&); + void splitAroundRegion(LiveInterval&, unsigned, const BitVector&, + SmallVectorImpl&); + void calcGapWeights(unsigned, SmallVectorImpl&); + SlotIndex getPrevMappedIndex(const MachineInstr*); + void calcPrevSlots(); + unsigned nextSplitPoint(unsigned); + + unsigned tryReassignOrEvict(LiveInterval&, AllocationOrder&, + SmallVectorImpl&); + unsigned tryRegionSplit(LiveInterval&, AllocationOrder&, + SmallVectorImpl&); + unsigned tryLocalSplit(LiveInterval&, AllocationOrder&, + SmallVectorImpl&); + unsigned trySplit(LiveInterval&, AllocationOrder&, + SmallVectorImpl&); + unsigned trySpillInterferences(LiveInterval&, AllocationOrder&, + SmallVectorImpl&); +}; +} // end anonymous namespace + +char RAGreedy::ID = 0; + +FunctionPass* llvm::createGreedyRegisterAllocator() { + return new RAGreedy(); +} + +RAGreedy::RAGreedy(): MachineFunctionPass(ID) { + initializeSlotIndexesPass(*PassRegistry::getPassRegistry()); + initializeLiveIntervalsPass(*PassRegistry::getPassRegistry()); + initializeSlotIndexesPass(*PassRegistry::getPassRegistry()); + initializeStrongPHIEliminationPass(*PassRegistry::getPassRegistry()); + initializeRegisterCoalescerAnalysisGroup(*PassRegistry::getPassRegistry()); + initializeCalculateSpillWeightsPass(*PassRegistry::getPassRegistry()); + initializeLiveStacksPass(*PassRegistry::getPassRegistry()); + initializeMachineDominatorTreePass(*PassRegistry::getPassRegistry()); + initializeMachineLoopInfoPass(*PassRegistry::getPassRegistry()); + initializeMachineLoopRangesPass(*PassRegistry::getPassRegistry()); + initializeVirtRegMapPass(*PassRegistry::getPassRegistry()); + initializeEdgeBundlesPass(*PassRegistry::getPassRegistry()); + initializeSpillPlacementPass(*PassRegistry::getPassRegistry()); +} + +void RAGreedy::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesCFG(); + AU.addRequired(); + AU.addPreserved(); + AU.addRequired(); + AU.addRequired(); + AU.addPreserved(); + if (StrongPHIElim) + AU.addRequiredID(StrongPHIEliminationID); + AU.addRequiredTransitive(); + AU.addRequired(); + AU.addRequired(); + AU.addPreserved(); + AU.addRequired(); + AU.addPreserved(); + AU.addRequired(); + AU.addPreserved(); + AU.addRequired(); + AU.addPreserved(); + AU.addRequired(); + AU.addPreserved(); + AU.addRequired(); + AU.addRequired(); + MachineFunctionPass::getAnalysisUsage(AU); +} + +void RAGreedy::releaseMemory() { + SpillerInstance.reset(0); + RegAllocBase::releaseMemory(); +} + +float RAGreedy::getPriority(LiveInterval *LI) { + float Priority = LI->weight; + + // Prioritize hinted registers so they are allocated first. + std::pair Hint; + if (Hint.first || Hint.second) { + // The hint can be target specific, a virtual register, or a physreg. + Priority *= 2; + + // Prefer physreg hints above anything else. + if (Hint.first == 0 && TargetRegisterInfo::isPhysicalRegister(Hint.second)) + Priority *= 2; + } + return Priority; +} + + +//===----------------------------------------------------------------------===// +// Register Reassignment +//===----------------------------------------------------------------------===// + +// Check interference without using the cache. +bool RAGreedy::checkUncachedInterference(LiveInterval &VirtReg, + unsigned PhysReg) { + for (const unsigned *AliasI = TRI->getOverlaps(PhysReg); *AliasI; ++AliasI) { + LiveIntervalUnion::Query subQ(&VirtReg, &PhysReg2LiveUnion[*AliasI]); + if (subQ.checkInterference()) + return true; + } + return false; +} + +/// getSingleInterference - Return the single interfering virtual register +/// assigned to PhysReg. Return 0 if more than one virtual register is +/// interfering. +LiveInterval *RAGreedy::getSingleInterference(LiveInterval &VirtReg, + unsigned PhysReg) { + // Check physreg and aliases. + LiveInterval *Interference = 0; + for (const unsigned *AliasI = TRI->getOverlaps(PhysReg); *AliasI; ++AliasI) { + LiveIntervalUnion::Query &Q = query(VirtReg, *AliasI); + if (Q.checkInterference()) { + if (Interference) + return 0; + Q.collectInterferingVRegs(1); + if (!Q.seenAllInterferences()) + return 0; + Interference = Q.interferingVRegs().front(); + } + } + return Interference; +} + +// Attempt to reassign this virtual register to a different physical register. +// +// FIXME: we are not yet caching these "second-level" interferences discovered +// in the sub-queries. These interferences can change with each call to +// selectOrSplit. However, we could implement a "may-interfere" cache that +// could be conservatively dirtied when we reassign or split. +// +// FIXME: This may result in a lot of alias queries. We could summarize alias +// live intervals in their parent register's live union, but it's messy. +bool RAGreedy::reassignVReg(LiveInterval &InterferingVReg, + unsigned WantedPhysReg) { + assert(TargetRegisterInfo::isVirtualRegister(InterferingVReg.reg) && + "Can only reassign virtual registers"); + assert(TRI->regsOverlap(WantedPhysReg, VRM->getPhys(InterferingVReg.reg)) && + "inconsistent phys reg assigment"); + + AllocationOrder Order(InterferingVReg.reg, *VRM, ReservedRegs); + while (unsigned PhysReg = Order.next()) { + // Don't reassign to a WantedPhysReg alias. + if (TRI->regsOverlap(PhysReg, WantedPhysReg)) + continue; + + if (checkUncachedInterference(InterferingVReg, PhysReg)) + continue; + + // Reassign the interfering virtual reg to this physical reg. + unsigned OldAssign = VRM->getPhys(InterferingVReg.reg); + DEBUG(dbgs() << "reassigning: " << InterferingVReg << " from " << + TRI->getName(OldAssign) << " to " << TRI->getName(PhysReg) << '\n'); + unassign(InterferingVReg, OldAssign); + assign(InterferingVReg, PhysReg); + ++NumReassigned; + return true; + } + return false; +} + +/// tryReassignOrEvict - Try to reassign a single interferences to a different +/// physreg, or evict a single interference with a lower spill weight. +/// @param VirtReg Currently unassigned virtual register. +/// @param Order Physregs to try. +/// @return Physreg to assign VirtReg, or 0. +unsigned RAGreedy::tryReassignOrEvict(LiveInterval &VirtReg, + AllocationOrder &Order, + SmallVectorImpl &NewVRegs){ + NamedRegionTimer T("Reassign", TimerGroupName, TimePassesIsEnabled); + + // Keep track of the lightest single interference seen so far. + float BestWeight = VirtReg.weight; + LiveInterval *BestVirt = 0; + unsigned BestPhys = 0; + + Order.rewind(); + while (unsigned PhysReg = Order.next()) { + LiveInterval *InterferingVReg = getSingleInterference(VirtReg, PhysReg); + if (!InterferingVReg) + continue; + if (TargetRegisterInfo::isPhysicalRegister(InterferingVReg->reg)) + continue; + if (reassignVReg(*InterferingVReg, PhysReg)) + return PhysReg; + + // Cannot reassign, is this an eviction candidate? + if (InterferingVReg->weight < BestWeight) { + BestVirt = InterferingVReg; + BestPhys = PhysReg; + BestWeight = InterferingVReg->weight; + } + } + + // Nothing reassigned, can we evict a lighter single interference? + if (BestVirt) { + DEBUG(dbgs() << "evicting lighter " << *BestVirt << '\n'); + unassign(*BestVirt, VRM->getPhys(BestVirt->reg)); + ++NumEvicted; + NewVRegs.push_back(BestVirt); + return BestPhys; + } + + return 0; +} + + +//===----------------------------------------------------------------------===// +// Region Splitting +//===----------------------------------------------------------------------===// + +/// calcInterferenceInfo - Compute per-block outgoing and ingoing constraints +/// when considering interference from PhysReg. Also compute an optimistic local +/// cost of this interference pattern. +/// +/// The final cost of a split is the local cost + global cost of preferences +/// broken by SpillPlacement. +/// +float RAGreedy::calcInterferenceInfo(LiveInterval &VirtReg, unsigned PhysReg) { + // Reset interference dependent info. + SpillConstraints.resize(SA->LiveBlocks.size()); + for (unsigned i = 0, e = SA->LiveBlocks.size(); i != e; ++i) { + SplitAnalysis::BlockInfo &BI = SA->LiveBlocks[i]; + SpillPlacement::BlockConstraint &BC = SpillConstraints[i]; + BC.Number = BI.MBB->getNumber(); + BC.Entry = (BI.Uses && BI.LiveIn) ? + SpillPlacement::PrefReg : SpillPlacement::DontCare; + BC.Exit = (BI.Uses && BI.LiveOut) ? + SpillPlacement::PrefReg : SpillPlacement::DontCare; + BI.OverlapEntry = BI.OverlapExit = false; + } + + // Add interference info from each PhysReg alias. + for (const unsigned *AI = TRI->getOverlaps(PhysReg); *AI; ++AI) { + if (!query(VirtReg, *AI).checkInterference()) + continue; + LiveIntervalUnion::SegmentIter IntI = + PhysReg2LiveUnion[*AI].find(VirtReg.beginIndex()); + if (!IntI.valid()) + continue; + + // Determine which blocks have interference live in or after the last split + // point. + for (unsigned i = 0, e = SA->LiveBlocks.size(); i != e; ++i) { + SplitAnalysis::BlockInfo &BI = SA->LiveBlocks[i]; + SpillPlacement::BlockConstraint &BC = SpillConstraints[i]; + SlotIndex Start, Stop; + tie(Start, Stop) = Indexes->getMBBRange(BI.MBB); + + // Skip interference-free blocks. + if (IntI.start() >= Stop) + continue; + + // Is the interference live-in? + if (BI.LiveIn) { + IntI.advanceTo(Start); + if (!IntI.valid()) + break; + if (IntI.start() <= Start) + BC.Entry = SpillPlacement::MustSpill; + } + + // Is the interference overlapping the last split point? + if (BI.LiveOut) { + if (IntI.stop() < BI.LastSplitPoint) + IntI.advanceTo(BI.LastSplitPoint.getPrevSlot()); + if (!IntI.valid()) + break; + if (IntI.start() < Stop) + BC.Exit = SpillPlacement::MustSpill; + } + } + + // Rewind iterator and check other interferences. + IntI.find(VirtReg.beginIndex()); + for (unsigned i = 0, e = SA->LiveBlocks.size(); i != e; ++i) { + SplitAnalysis::BlockInfo &BI = SA->LiveBlocks[i]; + SpillPlacement::BlockConstraint &BC = SpillConstraints[i]; + SlotIndex Start, Stop; + tie(Start, Stop) = Indexes->getMBBRange(BI.MBB); + + // Skip interference-free blocks. + if (IntI.start() >= Stop) + continue; + + // Handle transparent blocks with interference separately. + // Transparent blocks never incur any fixed cost. + if (BI.LiveThrough && !BI.Uses) { + IntI.advanceTo(Start); + if (!IntI.valid()) + break; + if (IntI.start() >= Stop) + continue; + + if (BC.Entry != SpillPlacement::MustSpill) + BC.Entry = SpillPlacement::PrefSpill; + if (BC.Exit != SpillPlacement::MustSpill) + BC.Exit = SpillPlacement::PrefSpill; + continue; + } + + // Now we only have blocks with uses left. + // Check if the interference overlaps the uses. + assert(BI.Uses && "Non-transparent block without any uses"); + + // Check interference on entry. + if (BI.LiveIn && BC.Entry != SpillPlacement::MustSpill) { + IntI.advanceTo(Start); + if (!IntI.valid()) + break; + // Not live in, but before the first use. + if (IntI.start() < BI.FirstUse) + BC.Entry = SpillPlacement::PrefSpill; + } + + // Does interference overlap the uses in the entry segment + // [FirstUse;Kill)? + if (BI.LiveIn && !BI.OverlapEntry) { + IntI.advanceTo(BI.FirstUse); + if (!IntI.valid()) + break; + // A live-through interval has no kill. + // Check [FirstUse;LastUse) instead. + if (IntI.start() < (BI.LiveThrough ? BI.LastUse : BI.Kill)) + BI.OverlapEntry = true; + } + + // Does interference overlap the uses in the exit segment [Def;LastUse)? + if (BI.LiveOut && !BI.LiveThrough && !BI.OverlapExit) { + IntI.advanceTo(BI.Def); + if (!IntI.valid()) + break; + if (IntI.start() < BI.LastUse) + BI.OverlapExit = true; + } + + // Check interference on exit. + if (BI.LiveOut && BC.Exit != SpillPlacement::MustSpill) { + // Check interference between LastUse and Stop. + if (BC.Exit != SpillPlacement::PrefSpill) { + IntI.advanceTo(BI.LastUse); + if (!IntI.valid()) + break; + if (IntI.start() < Stop) + BC.Exit = SpillPlacement::PrefSpill; + } + } + } + } + + // Accumulate a local cost of this interference pattern. + float LocalCost = 0; + for (unsigned i = 0, e = SA->LiveBlocks.size(); i != e; ++i) { + SplitAnalysis::BlockInfo &BI = SA->LiveBlocks[i]; + if (!BI.Uses) + continue; + SpillPlacement::BlockConstraint &BC = SpillConstraints[i]; + unsigned Inserts = 0; + + // Do we need spill code for the entry segment? + if (BI.LiveIn) + Inserts += BI.OverlapEntry || BC.Entry != SpillPlacement::PrefReg; + + // For the exit segment? + if (BI.LiveOut) + Inserts += BI.OverlapExit || BC.Exit != SpillPlacement::PrefReg; + + // The local cost of spill code in this block is the block frequency times + // the number of spill instructions inserted. + if (Inserts) + LocalCost += Inserts * SpillPlacer->getBlockFrequency(BI.MBB); + } + DEBUG(dbgs() << "Local cost of " << PrintReg(PhysReg, TRI) << " = " + << LocalCost << '\n'); + return LocalCost; +} + +/// calcGlobalSplitCost - Return the global split cost of following the split +/// pattern in LiveBundles. This cost should be added to the local cost of the +/// interference pattern in SpillConstraints. +/// +float RAGreedy::calcGlobalSplitCost(const BitVector &LiveBundles) { + float GlobalCost = 0; + for (unsigned i = 0, e = SpillConstraints.size(); i != e; ++i) { + SpillPlacement::BlockConstraint &BC = SpillConstraints[i]; + unsigned Inserts = 0; + // Broken entry preference? + Inserts += LiveBundles[Bundles->getBundle(BC.Number, 0)] != + (BC.Entry == SpillPlacement::PrefReg); + // Broken exit preference? + Inserts += LiveBundles[Bundles->getBundle(BC.Number, 1)] != + (BC.Exit == SpillPlacement::PrefReg); + if (Inserts) + GlobalCost += + Inserts * SpillPlacer->getBlockFrequency(SA->LiveBlocks[i].MBB); + } + DEBUG(dbgs() << "Global cost = " << GlobalCost << '\n'); + return GlobalCost; +} + +/// splitAroundRegion - Split VirtReg around the region determined by +/// LiveBundles. Make an effort to avoid interference from PhysReg. +/// +/// The 'register' interval is going to contain as many uses as possible while +/// avoiding interference. The 'stack' interval is the complement constructed by +/// SplitEditor. It will contain the rest. +/// +void RAGreedy::splitAroundRegion(LiveInterval &VirtReg, unsigned PhysReg, + const BitVector &LiveBundles, + SmallVectorImpl &NewVRegs) { + DEBUG({ + dbgs() << "Splitting around region for " << PrintReg(PhysReg, TRI) + << " with bundles"; + for (int i = LiveBundles.find_first(); i>=0; i = LiveBundles.find_next(i)) + dbgs() << " EB#" << i; + dbgs() << ".\n"; + }); + + // First compute interference ranges in the live blocks. + typedef std::pair IndexPair; + SmallVector InterferenceRanges; + InterferenceRanges.resize(SA->LiveBlocks.size()); + for (const unsigned *AI = TRI->getOverlaps(PhysReg); *AI; ++AI) { + if (!query(VirtReg, *AI).checkInterference()) + continue; + LiveIntervalUnion::SegmentIter IntI = + PhysReg2LiveUnion[*AI].find(VirtReg.beginIndex()); + if (!IntI.valid()) + continue; + for (unsigned i = 0, e = SA->LiveBlocks.size(); i != e; ++i) { + const SplitAnalysis::BlockInfo &BI = SA->LiveBlocks[i]; + IndexPair &IP = InterferenceRanges[i]; + SlotIndex Start, Stop; + tie(Start, Stop) = Indexes->getMBBRange(BI.MBB); + // Skip interference-free blocks. + if (IntI.start() >= Stop) + continue; + + // First interference in block. + if (BI.LiveIn) { + IntI.advanceTo(Start); + if (!IntI.valid()) + break; + if (IntI.start() >= Stop) + continue; + if (!IP.first.isValid() || IntI.start() < IP.first) + IP.first = IntI.start(); + } + + // Last interference in block. + if (BI.LiveOut) { + IntI.advanceTo(Stop); + if (!IntI.valid() || IntI.start() >= Stop) + --IntI; + if (IntI.stop() <= Start) + continue; + if (!IP.second.isValid() || IntI.stop() > IP.second) + IP.second = IntI.stop(); + } + } + } + + SmallVector SpillRegs; + LiveRangeEdit LREdit(VirtReg, NewVRegs, SpillRegs); + SplitEditor SE(*SA, *LIS, *VRM, *DomTree, LREdit); + + // Create the main cross-block interval. + SE.openIntv(); + + // First add all defs that are live out of a block. + for (unsigned i = 0, e = SA->LiveBlocks.size(); i != e; ++i) { + SplitAnalysis::BlockInfo &BI = SA->LiveBlocks[i]; + bool RegIn = LiveBundles[Bundles->getBundle(BI.MBB->getNumber(), 0)]; + bool RegOut = LiveBundles[Bundles->getBundle(BI.MBB->getNumber(), 1)]; + + // Should the register be live out? + if (!BI.LiveOut || !RegOut) + continue; + + IndexPair &IP = InterferenceRanges[i]; + SlotIndex Start, Stop; + tie(Start, Stop) = Indexes->getMBBRange(BI.MBB); + + DEBUG(dbgs() << "BB#" << BI.MBB->getNumber() << " -> EB#" + << Bundles->getBundle(BI.MBB->getNumber(), 1) + << " intf [" << IP.first << ';' << IP.second << ')'); + + // The interference interval should either be invalid or overlap MBB. + assert((!IP.first.isValid() || IP.first < Stop) && "Bad interference"); + assert((!IP.second.isValid() || IP.second > Start) && "Bad interference"); + + // Check interference leaving the block. + if (!IP.second.isValid()) { + // Block is interference-free. + DEBUG(dbgs() << ", no interference"); + if (!BI.Uses) { + assert(BI.LiveThrough && "No uses, but not live through block?"); + // Block is live-through without interference. + DEBUG(dbgs() << ", no uses" + << (RegIn ? ", live-through.\n" : ", stack in.\n")); + if (!RegIn) + SE.enterIntvAtEnd(*BI.MBB); + continue; + } + if (!BI.LiveThrough) { + DEBUG(dbgs() << ", not live-through.\n"); + SE.useIntv(SE.enterIntvBefore(BI.Def), Stop); + continue; + } + if (!RegIn) { + // Block is live-through, but entry bundle is on the stack. + // Reload just before the first use. + DEBUG(dbgs() << ", not live-in, enter before first use.\n"); + SE.useIntv(SE.enterIntvBefore(BI.FirstUse), Stop); + continue; + } + DEBUG(dbgs() << ", live-through.\n"); + continue; + } + + // Block has interference. + DEBUG(dbgs() << ", interference to " << IP.second); + + if (!BI.LiveThrough && IP.second <= BI.Def) { + // The interference doesn't reach the outgoing segment. + DEBUG(dbgs() << " doesn't affect def from " << BI.Def << '\n'); + SE.useIntv(BI.Def, Stop); + continue; + } + + + if (!BI.Uses) { + // No uses in block, avoid interference by reloading as late as possible. + DEBUG(dbgs() << ", no uses.\n"); + SlotIndex SegStart = SE.enterIntvAtEnd(*BI.MBB); + assert(SegStart >= IP.second && "Couldn't avoid interference"); + continue; + } + + if (IP.second.getBoundaryIndex() < BI.LastUse) { + // There are interference-free uses at the end of the block. + // Find the first use that can get the live-out register. + SmallVectorImpl::const_iterator UI = + std::lower_bound(SA->UseSlots.begin(), SA->UseSlots.end(), + IP.second.getBoundaryIndex()); + assert(UI != SA->UseSlots.end() && "Couldn't find last use"); + SlotIndex Use = *UI; + assert(Use <= BI.LastUse && "Couldn't find last use"); + // Only attempt a split befroe the last split point. + if (Use.getBaseIndex() <= BI.LastSplitPoint) { + DEBUG(dbgs() << ", free use at " << Use << ".\n"); + SlotIndex SegStart = SE.enterIntvBefore(Use); + assert(SegStart >= IP.second && "Couldn't avoid interference"); + assert(SegStart < BI.LastSplitPoint && "Impossible split point"); + SE.useIntv(SegStart, Stop); + continue; + } + } + + // Interference is after the last use. + DEBUG(dbgs() << " after last use.\n"); + SlotIndex SegStart = SE.enterIntvAtEnd(*BI.MBB); + assert(SegStart >= IP.second && "Couldn't avoid interference"); + } + + // Now all defs leading to live bundles are handled, do everything else. + for (unsigned i = 0, e = SA->LiveBlocks.size(); i != e; ++i) { + SplitAnalysis::BlockInfo &BI = SA->LiveBlocks[i]; + bool RegIn = LiveBundles[Bundles->getBundle(BI.MBB->getNumber(), 0)]; + bool RegOut = LiveBundles[Bundles->getBundle(BI.MBB->getNumber(), 1)]; + + // Is the register live-in? + if (!BI.LiveIn || !RegIn) + continue; + + // We have an incoming register. Check for interference. + IndexPair &IP = InterferenceRanges[i]; + SlotIndex Start, Stop; + tie(Start, Stop) = Indexes->getMBBRange(BI.MBB); + + DEBUG(dbgs() << "EB#" << Bundles->getBundle(BI.MBB->getNumber(), 0) + << " -> BB#" << BI.MBB->getNumber()); + + // Check interference entering the block. + if (!IP.first.isValid()) { + // Block is interference-free. + DEBUG(dbgs() << ", no interference"); + if (!BI.Uses) { + assert(BI.LiveThrough && "No uses, but not live through block?"); + // Block is live-through without interference. + if (RegOut) { + DEBUG(dbgs() << ", no uses, live-through.\n"); + SE.useIntv(Start, Stop); + } else { + DEBUG(dbgs() << ", no uses, stack-out.\n"); + SE.leaveIntvAtTop(*BI.MBB); + } + continue; + } + if (!BI.LiveThrough) { + DEBUG(dbgs() << ", killed in block.\n"); + SE.useIntv(Start, SE.leaveIntvAfter(BI.Kill)); + continue; + } + if (!RegOut) { + // Block is live-through, but exit bundle is on the stack. + // Spill immediately after the last use. + if (BI.LastUse < BI.LastSplitPoint) { + DEBUG(dbgs() << ", uses, stack-out.\n"); + SE.useIntv(Start, SE.leaveIntvAfter(BI.LastUse)); + continue; + } + // The last use is after the last split point, it is probably an + // indirect jump. + DEBUG(dbgs() << ", uses at " << BI.LastUse << " after split point " + << BI.LastSplitPoint << ", stack-out.\n"); + SlotIndex SegEnd = SE.leaveIntvBefore(BI.LastSplitPoint); + SE.useIntv(Start, SegEnd); + // Run a double interval from the split to the last use. + // This makes it possible to spill the complement without affecting the + // indirect branch. + SE.overlapIntv(SegEnd, BI.LastUse); + continue; + } + // Register is live-through. + DEBUG(dbgs() << ", uses, live-through.\n"); + SE.useIntv(Start, Stop); + continue; + } + + // Block has interference. + DEBUG(dbgs() << ", interference from " << IP.first); + + if (!BI.LiveThrough && IP.first >= BI.Kill) { + // The interference doesn't reach the outgoing segment. + DEBUG(dbgs() << " doesn't affect kill at " << BI.Kill << '\n'); + SE.useIntv(Start, BI.Kill); + continue; + } + + if (!BI.Uses) { + // No uses in block, avoid interference by spilling as soon as possible. + DEBUG(dbgs() << ", no uses.\n"); + SlotIndex SegEnd = SE.leaveIntvAtTop(*BI.MBB); + assert(SegEnd <= IP.first && "Couldn't avoid interference"); + continue; + } + if (IP.first.getBaseIndex() > BI.FirstUse) { + // There are interference-free uses at the beginning of the block. + // Find the last use that can get the register. + SmallVectorImpl::const_iterator UI = + std::lower_bound(SA->UseSlots.begin(), SA->UseSlots.end(), + IP.first.getBaseIndex()); + assert(UI != SA->UseSlots.begin() && "Couldn't find first use"); + SlotIndex Use = (--UI)->getBoundaryIndex(); + DEBUG(dbgs() << ", free use at " << *UI << ".\n"); + SlotIndex SegEnd = SE.leaveIntvAfter(Use); + assert(SegEnd <= IP.first && "Couldn't avoid interference"); + SE.useIntv(Start, SegEnd); + continue; + } + + // Interference is before the first use. + DEBUG(dbgs() << " before first use.\n"); + SlotIndex SegEnd = SE.leaveIntvAtTop(*BI.MBB); + assert(SegEnd <= IP.first && "Couldn't avoid interference"); + } + + SE.closeIntv(); + + // FIXME: Should we be more aggressive about splitting the stack region into + // per-block segments? The current approach allows the stack region to + // separate into connected components. Some components may be allocatable. + SE.finish(); + ++NumGlobalSplits; + + if (VerifyEnabled) { + MF->verify(this, "After splitting live range around region"); + +#ifndef NDEBUG + // Make sure that at least one of the new intervals can allocate to PhysReg. + // That was the whole point of splitting the live range. + bool found = false; + for (LiveRangeEdit::iterator I = LREdit.begin(), E = LREdit.end(); I != E; + ++I) + if (!checkUncachedInterference(**I, PhysReg)) { + found = true; + break; + } + assert(found && "No allocatable intervals after pointless splitting"); +#endif + } +} + +unsigned RAGreedy::tryRegionSplit(LiveInterval &VirtReg, AllocationOrder &Order, + SmallVectorImpl &NewVRegs) { + BitVector LiveBundles, BestBundles; + float BestCost = 0; + unsigned BestReg = 0; + Order.rewind(); + while (unsigned PhysReg = Order.next()) { + float Cost = calcInterferenceInfo(VirtReg, PhysReg); + if (BestReg && Cost >= BestCost) + continue; + + SpillPlacer->placeSpills(SpillConstraints, LiveBundles); + // No live bundles, defer to splitSingleBlocks(). + if (!LiveBundles.any()) + continue; + + Cost += calcGlobalSplitCost(LiveBundles); + if (!BestReg || Cost < BestCost) { + BestReg = PhysReg; + BestCost = Cost; + BestBundles.swap(LiveBundles); + } + } + + if (!BestReg) + return 0; + + splitAroundRegion(VirtReg, BestReg, BestBundles, NewVRegs); + return 0; +} + + +//===----------------------------------------------------------------------===// +// Local Splitting +//===----------------------------------------------------------------------===// + + +/// calcGapWeights - Compute the maximum spill weight that needs to be evicted +/// in order to use PhysReg between two entries in SA->UseSlots. +/// +/// GapWeight[i] represents the gap between UseSlots[i] and UseSlots[i+1]. +/// +void RAGreedy::calcGapWeights(unsigned PhysReg, + SmallVectorImpl &GapWeight) { + assert(SA->LiveBlocks.size() == 1 && "Not a local interval"); + const SplitAnalysis::BlockInfo &BI = SA->LiveBlocks.front(); + const SmallVectorImpl &Uses = SA->UseSlots; + const unsigned NumGaps = Uses.size()-1; + + // Start and end points for the interference check. + SlotIndex StartIdx = BI.LiveIn ? BI.FirstUse.getBaseIndex() : BI.FirstUse; + SlotIndex StopIdx = BI.LiveOut ? BI.LastUse.getBoundaryIndex() : BI.LastUse; + + GapWeight.assign(NumGaps, 0.0f); + + // Add interference from each overlapping register. + for (const unsigned *AI = TRI->getOverlaps(PhysReg); *AI; ++AI) { + if (!query(const_cast(SA->getParent()), *AI) + .checkInterference()) + continue; + + // We know that VirtReg is a continuous interval from FirstUse to LastUse, + // so we don't need InterferenceQuery. + // + // Interference that overlaps an instruction is counted in both gaps + // surrounding the instruction. The exception is interference before + // StartIdx and after StopIdx. + // + LiveIntervalUnion::SegmentIter IntI = PhysReg2LiveUnion[*AI].find(StartIdx); + for (unsigned Gap = 0; IntI.valid() && IntI.start() < StopIdx; ++IntI) { + // Skip the gaps before IntI. + while (Uses[Gap+1].getBoundaryIndex() < IntI.start()) + if (++Gap == NumGaps) + break; + if (Gap == NumGaps) + break; + + // Update the gaps covered by IntI. + const float weight = IntI.value()->weight; + for (; Gap != NumGaps; ++Gap) { + GapWeight[Gap] = std::max(GapWeight[Gap], weight); + if (Uses[Gap+1].getBaseIndex() >= IntI.stop()) + break; + } + if (Gap == NumGaps) + break; + } + } +} + +/// getPrevMappedIndex - Return the slot index of the last non-copy instruction +/// before MI that has a slot index. If MI is the first mapped instruction in +/// its block, return the block start index instead. +/// +SlotIndex RAGreedy::getPrevMappedIndex(const MachineInstr *MI) { + assert(MI && "Missing MachineInstr"); + const MachineBasicBlock *MBB = MI->getParent(); + MachineBasicBlock::const_iterator B = MBB->begin(), I = MI; + while (I != B) + if (!(--I)->isDebugValue() && !I->isCopy()) + return Indexes->getInstructionIndex(I); + return Indexes->getMBBStartIdx(MBB); +} + +/// calcPrevSlots - Fill in the PrevSlot array with the index of the previous +/// real non-copy instruction for each instruction in SA->UseSlots. +/// +void RAGreedy::calcPrevSlots() { + const SmallVectorImpl &Uses = SA->UseSlots; + PrevSlot.clear(); + PrevSlot.reserve(Uses.size()); + for (unsigned i = 0, e = Uses.size(); i != e; ++i) { + const MachineInstr *MI = Indexes->getInstructionFromIndex(Uses[i]); + PrevSlot.push_back(getPrevMappedIndex(MI).getDefIndex()); + } +} + +/// nextSplitPoint - Find the next index into SA->UseSlots > i such that it may +/// be beneficial to split before UseSlots[i]. +/// +/// 0 is always a valid split point +unsigned RAGreedy::nextSplitPoint(unsigned i) { + const SmallVectorImpl &Uses = SA->UseSlots; + const unsigned Size = Uses.size(); + assert(i != Size && "No split points after the end"); + // Allow split before i when Uses[i] is not adjacent to the previous use. + while (++i != Size && PrevSlot[i].getBaseIndex() <= Uses[i-1].getBaseIndex()) + ; + return i; +} + +/// tryLocalSplit - Try to split VirtReg into smaller intervals inside its only +/// basic block. +/// +unsigned RAGreedy::tryLocalSplit(LiveInterval &VirtReg, AllocationOrder &Order, + SmallVectorImpl &NewVRegs) { + assert(SA->LiveBlocks.size() == 1 && "Not a local interval"); + const SplitAnalysis::BlockInfo &BI = SA->LiveBlocks.front(); + + // Note that it is possible to have an interval that is live-in or live-out + // while only covering a single block - A phi-def can use undef values from + // predecessors, and the block could be a single-block loop. + // We don't bother doing anything clever about such a case, we simply assume + // that the interval is continuous from FirstUse to LastUse. We should make + // sure that we don't do anything illegal to such an interval, though. + + const SmallVectorImpl &Uses = SA->UseSlots; + if (Uses.size() <= 2) + return 0; + const unsigned NumGaps = Uses.size()-1; + + DEBUG({ + dbgs() << "tryLocalSplit: "; + for (unsigned i = 0, e = Uses.size(); i != e; ++i) + dbgs() << ' ' << SA->UseSlots[i]; + dbgs() << '\n'; + }); + + // For every use, find the previous mapped non-copy instruction. + // We use this to detect valid split points, and to estimate new interval + // sizes. + calcPrevSlots(); + + unsigned BestBefore = NumGaps; + unsigned BestAfter = 0; + float BestDiff = 0; + + const float blockFreq = SpillPlacer->getBlockFrequency(BI.MBB); + SmallVector GapWeight; + + Order.rewind(); + while (unsigned PhysReg = Order.next()) { + // Keep track of the largest spill weight that would need to be evicted in + // order to make use of PhysReg between UseSlots[i] and UseSlots[i+1]. + calcGapWeights(PhysReg, GapWeight); + + // Try to find the best sequence of gaps to close. + // The new spill weight must be larger than any gap interference. + + // We will split before Uses[SplitBefore] and after Uses[SplitAfter]. + unsigned SplitBefore = 0, SplitAfter = nextSplitPoint(1) - 1; + + // MaxGap should always be max(GapWeight[SplitBefore..SplitAfter-1]). + // It is the spill weight that needs to be evicted. + float MaxGap = GapWeight[0]; + for (unsigned i = 1; i != SplitAfter; ++i) + MaxGap = std::max(MaxGap, GapWeight[i]); + + for (;;) { + // Live before/after split? + const bool LiveBefore = SplitBefore != 0 || BI.LiveIn; + const bool LiveAfter = SplitAfter != NumGaps || BI.LiveOut; + + DEBUG(dbgs() << PrintReg(PhysReg, TRI) << ' ' + << Uses[SplitBefore] << '-' << Uses[SplitAfter] + << " i=" << MaxGap); + + // Stop before the interval gets so big we wouldn't be making progress. + if (!LiveBefore && !LiveAfter) { + DEBUG(dbgs() << " all\n"); + break; + } + // Should the interval be extended or shrunk? + bool Shrink = true; + if (MaxGap < HUGE_VALF) { + // Estimate the new spill weight. + // + // Each instruction reads and writes the register, except the first + // instr doesn't read when !FirstLive, and the last instr doesn't write + // when !LastLive. + // + // We will be inserting copies before and after, so the total number of + // reads and writes is 2 * EstUses. + // + const unsigned EstUses = 2*(SplitAfter - SplitBefore) + + 2*(LiveBefore + LiveAfter); + + // Try to guess the size of the new interval. This should be trivial, + // but the slot index of an inserted copy can be a lot smaller than the + // instruction it is inserted before if there are many dead indexes + // between them. + // + // We measure the distance from the instruction before SplitBefore to + // get a conservative estimate. + // + // The final distance can still be different if inserting copies + // triggers a slot index renumbering. + // + const float EstWeight = normalizeSpillWeight(blockFreq * EstUses, + PrevSlot[SplitBefore].distance(Uses[SplitAfter])); + // Would this split be possible to allocate? + // Never allocate all gaps, we wouldn't be making progress. + float Diff = EstWeight - MaxGap; + DEBUG(dbgs() << " w=" << EstWeight << " d=" << Diff); + if (Diff > 0) { + Shrink = false; + if (Diff > BestDiff) { + DEBUG(dbgs() << " (best)"); + BestDiff = Diff; + BestBefore = SplitBefore; + BestAfter = SplitAfter; + } + } + } + + // Try to shrink. + if (Shrink) { + SplitBefore = nextSplitPoint(SplitBefore); + if (SplitBefore < SplitAfter) { + DEBUG(dbgs() << " shrink\n"); + // Recompute the max when necessary. + if (GapWeight[SplitBefore - 1] >= MaxGap) { + MaxGap = GapWeight[SplitBefore]; + for (unsigned i = SplitBefore + 1; i != SplitAfter; ++i) + MaxGap = std::max(MaxGap, GapWeight[i]); + } + continue; + } + MaxGap = 0; + } + + // Try to extend the interval. + if (SplitAfter >= NumGaps) { + DEBUG(dbgs() << " end\n"); + break; + } + + DEBUG(dbgs() << " extend\n"); + for (unsigned e = nextSplitPoint(SplitAfter + 1) - 1; + SplitAfter != e; ++SplitAfter) + MaxGap = std::max(MaxGap, GapWeight[SplitAfter]); + continue; + } + } + + // Didn't find any candidates? + if (BestBefore == NumGaps) + return 0; + + DEBUG(dbgs() << "Best local split range: " << Uses[BestBefore] + << '-' << Uses[BestAfter] << ", " << BestDiff + << ", " << (BestAfter - BestBefore + 1) << " instrs\n"); + + SmallVector SpillRegs; + LiveRangeEdit LREdit(VirtReg, NewVRegs, SpillRegs); + SplitEditor SE(*SA, *LIS, *VRM, *DomTree, LREdit); + + SE.openIntv(); + SlotIndex SegStart = SE.enterIntvBefore(Uses[BestBefore]); + SlotIndex SegStop = SE.leaveIntvAfter(Uses[BestAfter]); + SE.useIntv(SegStart, SegStop); + SE.closeIntv(); + SE.finish(); + ++NumLocalSplits; + + return 0; +} + +//===----------------------------------------------------------------------===// +// Live Range Splitting +//===----------------------------------------------------------------------===// + +/// trySplit - Try to split VirtReg or one of its interferences, making it +/// assignable. +/// @return Physreg when VirtReg may be assigned and/or new NewVRegs. +unsigned RAGreedy::trySplit(LiveInterval &VirtReg, AllocationOrder &Order, + SmallVectorImpl&NewVRegs) { + SA->analyze(&VirtReg); + + // Local intervals are handled separately. + if (LIS->intervalIsInOneMBB(VirtReg)) { + NamedRegionTimer T("Local Splitting", TimerGroupName, TimePassesIsEnabled); + return tryLocalSplit(VirtReg, Order, NewVRegs); + } + + NamedRegionTimer T("Global Splitting", TimerGroupName, TimePassesIsEnabled); + + // First try to split around a region spanning multiple blocks. + unsigned PhysReg = tryRegionSplit(VirtReg, Order, NewVRegs); + if (PhysReg || !NewVRegs.empty()) + return PhysReg; + + // Then isolate blocks with multiple uses. + SplitAnalysis::BlockPtrSet Blocks; + if (SA->getMultiUseBlocks(Blocks)) { + SmallVector SpillRegs; + LiveRangeEdit LREdit(VirtReg, NewVRegs, SpillRegs); + SplitEditor(*SA, *LIS, *VRM, *DomTree, LREdit).splitSingleBlocks(Blocks); + if (VerifyEnabled) + MF->verify(this, "After splitting live range around basic blocks"); + } + + // Don't assign any physregs. + return 0; +} + + +//===----------------------------------------------------------------------===// +// Spilling +//===----------------------------------------------------------------------===// + +/// calcInterferenceWeight - Calculate the combined spill weight of +/// interferences when assigning VirtReg to PhysReg. +float RAGreedy::calcInterferenceWeight(LiveInterval &VirtReg, unsigned PhysReg){ + float Sum = 0; + for (const unsigned *AI = TRI->getOverlaps(PhysReg); *AI; ++AI) { + LiveIntervalUnion::Query &Q = query(VirtReg, *AI); + Q.collectInterferingVRegs(); + if (Q.seenUnspillableVReg()) + return HUGE_VALF; + for (unsigned i = 0, e = Q.interferingVRegs().size(); i != e; ++i) + Sum += Q.interferingVRegs()[i]->weight; + } + return Sum; +} + +/// trySpillInterferences - Try to spill interfering registers instead of the +/// current one. Only do it if the accumulated spill weight is smaller than the +/// current spill weight. +unsigned RAGreedy::trySpillInterferences(LiveInterval &VirtReg, + AllocationOrder &Order, + SmallVectorImpl &NewVRegs) { + NamedRegionTimer T("Spill Interference", TimerGroupName, TimePassesIsEnabled); + unsigned BestPhys = 0; + float BestWeight = 0; + + Order.rewind(); + while (unsigned PhysReg = Order.next()) { + float Weight = calcInterferenceWeight(VirtReg, PhysReg); + if (Weight == HUGE_VALF || Weight >= VirtReg.weight) + continue; + if (!BestPhys || Weight < BestWeight) + BestPhys = PhysReg, BestWeight = Weight; + } + + // No candidates found. + if (!BestPhys) + return 0; + + // Collect all interfering registers. + SmallVector Spills; + for (const unsigned *AI = TRI->getOverlaps(BestPhys); *AI; ++AI) { + LiveIntervalUnion::Query &Q = query(VirtReg, *AI); + Spills.append(Q.interferingVRegs().begin(), Q.interferingVRegs().end()); + for (unsigned i = 0, e = Q.interferingVRegs().size(); i != e; ++i) { + LiveInterval *VReg = Q.interferingVRegs()[i]; + unassign(*VReg, *AI); + } + } + + // Spill them all. + DEBUG(dbgs() << "spilling " << Spills.size() << " interferences with weight " + << BestWeight << '\n'); + for (unsigned i = 0, e = Spills.size(); i != e; ++i) + spiller().spill(Spills[i], NewVRegs, Spills); + return BestPhys; +} + + +//===----------------------------------------------------------------------===// +// Main Entry Point +//===----------------------------------------------------------------------===// + +unsigned RAGreedy::selectOrSplit(LiveInterval &VirtReg, + SmallVectorImpl &NewVRegs) { + // First try assigning a free register. + AllocationOrder Order(VirtReg.reg, *VRM, ReservedRegs); + while (unsigned PhysReg = Order.next()) { + if (!checkPhysRegInterference(VirtReg, PhysReg)) + return PhysReg; + } + + // Try to reassign interferences. + if (unsigned PhysReg = tryReassignOrEvict(VirtReg, Order, NewVRegs)) + return PhysReg; + + assert(NewVRegs.empty() && "Cannot append to existing NewVRegs"); + + // Try splitting VirtReg or interferences. + unsigned PhysReg = trySplit(VirtReg, Order, NewVRegs); + if (PhysReg || !NewVRegs.empty()) + return PhysReg; + + // Try to spill another interfering reg with less spill weight. + PhysReg = trySpillInterferences(VirtReg, Order, NewVRegs); + if (PhysReg) + return PhysReg; + + // Finally spill VirtReg itself. + NamedRegionTimer T("Spiller", TimerGroupName, TimePassesIsEnabled); + SmallVector pendingSpills; + spiller().spill(&VirtReg, NewVRegs, pendingSpills); + + // The live virtual register requesting allocation was spilled, so tell + // the caller not to allocate anything during this round. + return 0; +} + +bool RAGreedy::runOnMachineFunction(MachineFunction &mf) { + DEBUG(dbgs() << "********** GREEDY REGISTER ALLOCATION **********\n" + << "********** Function: " + << ((Value*)mf.getFunction())->getName() << '\n'); + + MF = &mf; + if (VerifyEnabled) + MF->verify(this, "Before greedy register allocator"); + + RegAllocBase::init(getAnalysis(), getAnalysis()); + Indexes = &getAnalysis(); + DomTree = &getAnalysis(); + ReservedRegs = TRI->getReservedRegs(*MF); + SpillerInstance.reset(createInlineSpiller(*this, *MF, *VRM)); + Loops = &getAnalysis(); + LoopRanges = &getAnalysis(); + Bundles = &getAnalysis(); + SpillPlacer = &getAnalysis(); + + SA.reset(new SplitAnalysis(*VRM, *LIS, *Loops)); + + allocatePhysRegs(); + addMBBLiveIns(MF); + LIS->addKillFlags(); + + // Run rewriter + { + NamedRegionTimer T("Rewriter", TimerGroupName, TimePassesIsEnabled); + VRM->rewrite(Indexes); + } + + // The pass output is in VirtRegMap. Release all the transient data. + releaseMemory(); + + return true; +} diff --git a/lib/CodeGen/RegAllocLinearScan.cpp b/lib/CodeGen/RegAllocLinearScan.cpp index 5c62354a8872..b959878bcdba 100644 --- a/lib/CodeGen/RegAllocLinearScan.cpp +++ b/lib/CodeGen/RegAllocLinearScan.cpp @@ -12,13 +12,14 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "regalloc" +#include "LiveDebugVariables.h" #include "VirtRegMap.h" #include "VirtRegRewriter.h" #include "Spiller.h" +#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Function.h" #include "llvm/CodeGen/CalcSpillWeights.h" #include "llvm/CodeGen/LiveIntervalAnalysis.h" -#include "llvm/CodeGen/LiveStackAnalysis.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineLoopInfo.h" @@ -91,6 +92,19 @@ namespace { struct RALinScan : public MachineFunctionPass { static char ID; RALinScan() : MachineFunctionPass(ID) { + initializeLiveDebugVariablesPass(*PassRegistry::getPassRegistry()); + initializeLiveIntervalsPass(*PassRegistry::getPassRegistry()); + initializeStrongPHIEliminationPass(*PassRegistry::getPassRegistry()); + initializeRegisterCoalescerAnalysisGroup( + *PassRegistry::getPassRegistry()); + initializeCalculateSpillWeightsPass(*PassRegistry::getPassRegistry()); + initializePreAllocSplittingPass(*PassRegistry::getPassRegistry()); + initializeLiveStacksPass(*PassRegistry::getPassRegistry()); + initializeMachineDominatorTreePass(*PassRegistry::getPassRegistry()); + initializeMachineLoopInfoPass(*PassRegistry::getPassRegistry()); + initializeVirtRegMapPass(*PassRegistry::getPassRegistry()); + initializeMachineDominatorTreePass(*PassRegistry::getPassRegistry()); + // Initialize the queue to record recently-used registers. if (NumRecentlyUsedRegs > 0) RecentRegs.resize(NumRecentlyUsedRegs, 0); @@ -127,7 +141,6 @@ namespace { BitVector allocatableRegs_; BitVector reservedRegs_; LiveIntervals* li_; - LiveStacks* ls_; MachineLoopInfo *loopInfo; /// handled_ - Intervals are added to the handled_ set in the order of their @@ -183,6 +196,8 @@ namespace { virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); + AU.addRequired(); + AU.addPreserved(); AU.addRequired(); AU.addPreserved(); if (StrongPHIElim) @@ -193,12 +208,15 @@ namespace { AU.addRequired(); if (PreSplitIntervals) AU.addRequiredID(PreAllocSplittingID); - AU.addRequired(); - AU.addPreserved(); + AU.addRequiredID(LiveStacksID); + AU.addPreservedID(LiveStacksID); AU.addRequired(); AU.addPreserved(); AU.addRequired(); AU.addPreserved(); + AU.addRequired(); + AU.addPreserved(); + AU.addRequiredID(MachineDominatorsID); AU.addPreservedID(MachineDominatorsID); MachineFunctionPass::getAnalysisUsage(AU); } @@ -370,8 +388,19 @@ namespace { char RALinScan::ID = 0; } -INITIALIZE_PASS(RALinScan, "linearscan-regalloc", - "Linear Scan Register Allocator", false, false); +INITIALIZE_PASS_BEGIN(RALinScan, "linearscan-regalloc", + "Linear Scan Register Allocator", false, false) +INITIALIZE_PASS_DEPENDENCY(LiveIntervals) +INITIALIZE_PASS_DEPENDENCY(StrongPHIElimination) +INITIALIZE_PASS_DEPENDENCY(CalculateSpillWeights) +INITIALIZE_PASS_DEPENDENCY(PreAllocSplitting) +INITIALIZE_PASS_DEPENDENCY(LiveStacks) +INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo) +INITIALIZE_PASS_DEPENDENCY(VirtRegMap) +INITIALIZE_AG_DEPENDENCY(RegisterCoalescer) +INITIALIZE_AG_DEPENDENCY(AliasAnalysis) +INITIALIZE_PASS_END(RALinScan, "linearscan-regalloc", + "Linear Scan Register Allocator", false, false) void RALinScan::ComputeRelatedRegClasses() { // First pass, add all reg classes to the union, and determine at least one @@ -402,8 +431,12 @@ void RALinScan::ComputeRelatedRegClasses() { for (DenseMap::iterator I = OneClassForEachPhysReg.begin(), E = OneClassForEachPhysReg.end(); I != E; ++I) - for (const unsigned *AS = tri_->getAliasSet(I->first); *AS; ++AS) - RelatedRegClasses.unionSets(I->second, OneClassForEachPhysReg[*AS]); + for (const unsigned *AS = tri_->getAliasSet(I->first); *AS; ++AS) { + const TargetRegisterClass *AliasClass = + OneClassForEachPhysReg.lookup(*AS); + if (AliasClass) + RelatedRegClasses.unionSets(I->second, AliasClass); + } } /// attemptTrivialCoalescing - If a simple interval is defined by a copy, try @@ -431,8 +464,7 @@ unsigned RALinScan::attemptTrivialCoalescing(LiveInterval &cur, unsigned Reg) { unsigned CandReg; { MachineInstr *CopyMI; - if (vni->def != SlotIndex() && vni->isDefAccurate() && - (CopyMI = li_->getInstructionFromIndex(vni->def)) && CopyMI->isCopy()) + if ((CopyMI = li_->getInstructionFromIndex(vni->def)) && CopyMI->isCopy()) // Defined by a copy, try to extend SrcReg forward CandReg = CopyMI->getOperand(1).getReg(); else if (TrivCoalesceEnds && @@ -442,6 +474,10 @@ unsigned RALinScan::attemptTrivialCoalescing(LiveInterval &cur, unsigned Reg) { CandReg = CopyMI->getOperand(0).getReg(); else return Reg; + + // If the target of the copy is a sub-register then don't coalesce. + if(CopyMI->getOperand(0).getSubReg()) + return Reg; } if (TargetRegisterInfo::isVirtualRegister(CandReg)) { @@ -478,7 +514,6 @@ bool RALinScan::runOnMachineFunction(MachineFunction &fn) { allocatableRegs_ = tri_->getAllocatableSet(fn); reservedRegs_ = tri_->getReservedRegs(fn); li_ = &getAnalysis(); - ls_ = &getAnalysis(); loopInfo = &getAnalysis(); // We don't run the coalescer here because we have no reason to @@ -505,6 +540,9 @@ bool RALinScan::runOnMachineFunction(MachineFunction &fn) { // Rewrite spill code and update the PhysRegsUsed set. rewriter_->runOnMachineFunction(*mf_, *vrm_, li_); + // Write out new DBG_VALUE instructions. + getAnalysis().emitDebugValues(vrm_); + assert(unhandled_.empty() && "Unhandled live intervals remain!"); finalizeRegUses(); @@ -638,8 +676,6 @@ void RALinScan::linearScan() { // Look for physical registers that end up not being allocated even though // register allocator had to spill other registers in its register class. - if (ls_->getNumIntervals() == 0) - return; if (!vrm_->FindUnusedRegisters(li_)) return; } @@ -784,30 +820,6 @@ static void RevertVectorIteratorsTo(RALinScan::IntervalPtrs &V, } } -/// addStackInterval - Create a LiveInterval for stack if the specified live -/// interval has been spilled. -static void addStackInterval(LiveInterval *cur, LiveStacks *ls_, - LiveIntervals *li_, - MachineRegisterInfo* mri_, VirtRegMap &vrm_) { - int SS = vrm_.getStackSlot(cur->reg); - if (SS == VirtRegMap::NO_STACK_SLOT) - return; - - const TargetRegisterClass *RC = mri_->getRegClass(cur->reg); - LiveInterval &SI = ls_->getOrCreateInterval(SS, RC); - - VNInfo *VNI; - if (SI.hasAtLeastOneValue()) - VNI = SI.getValNumInfo(0); - else - VNI = SI.getNextValue(SlotIndex(), 0, false, - ls_->getVNInfoAllocator()); - - LiveInterval &RI = li_->getInterval(cur->reg); - // FIXME: This may be overly conservative. - SI.MergeRangesInAsValue(RI, VNI); -} - /// getConflictWeight - Return the number of conflicts between cur /// live interval and defs and uses of Reg weighted by loop depthes. static @@ -925,13 +937,9 @@ LiveInterval *RALinScan::hasNextReloadInterval(LiveInterval *cur) { } void RALinScan::DowngradeRegister(LiveInterval *li, unsigned Reg) { - bool isNew = DowngradedRegs.insert(Reg); - isNew = isNew; // Silence compiler warning. - assert(isNew && "Multiple reloads holding the same register?"); - DowngradeMap.insert(std::make_pair(li->reg, Reg)); - for (const unsigned *AS = tri_->getAliasSet(Reg); *AS; ++AS) { - isNew = DowngradedRegs.insert(*AS); - isNew = isNew; // Silence compiler warning. + for (const unsigned *AS = tri_->getOverlaps(Reg); *AS; ++AS) { + bool isNew = DowngradedRegs.insert(*AS); + (void)isNew; // Silence compiler warning. assert(isNew && "Multiple reloads holding the same register?"); DowngradeMap.insert(std::make_pair(li->reg, *AS)); } @@ -957,10 +965,11 @@ namespace { /// assignRegOrStackSlotAtInterval - assign a register if one is available, or /// spill. void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) { - DEBUG(dbgs() << "\tallocating current interval: "); + const TargetRegisterClass *RC = mri_->getRegClass(cur->reg); + DEBUG(dbgs() << "\tallocating current interval from " + << RC->getName() << ": "); // This is an implicitly defined live interval, just assign any register. - const TargetRegisterClass *RC = mri_->getRegClass(cur->reg); if (cur->empty()) { unsigned physReg = vrm_->getRegAllocPref(cur->reg); if (!physReg) @@ -984,8 +993,7 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) { // one, e.g. X86::mov32to32_. These move instructions are not coalescable. if (!vrm_->getRegAllocPref(cur->reg) && cur->hasAtLeastOneValue()) { VNInfo *vni = cur->begin()->valno; - if ((vni->def != SlotIndex()) && !vni->isUnused() && - vni->isDefAccurate()) { + if (!vni->isUnused()) { MachineInstr *CopyMI = li_->getInstructionFromIndex(vni->def); if (CopyMI && CopyMI->isCopy()) { unsigned DstSubReg = CopyMI->getOperand(0).getSubReg(); @@ -1225,7 +1233,6 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) { spiller_->spill(cur, added, spillIs); std::sort(added.begin(), added.end(), LISorter()); - addStackInterval(cur, ls_, li_, mri_, *vrm_); if (added.empty()) return; // Early exit if all spills were folded. @@ -1300,7 +1307,6 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) { if (sli->beginIndex() < earliestStart) earliestStart = sli->beginIndex(); spiller_->spill(sli, added, spillIs); - addStackInterval(sli, ls_, li_, mri_, *vrm_); spilled.insert(sli->reg); } @@ -1419,8 +1425,7 @@ unsigned RALinScan::getFreePhysReg(LiveInterval* cur, std::pair Hint = mri_->getRegAllocationHint(cur->reg); // Resolve second part of the hint (if possible) given the current allocation. unsigned physReg = Hint.second; - if (physReg && - TargetRegisterInfo::isVirtualRegister(physReg) && vrm_->hasPhys(physReg)) + if (TargetRegisterInfo::isVirtualRegister(physReg) && vrm_->hasPhys(physReg)) physReg = vrm_->getPhys(physReg); TargetRegisterClass::iterator I, E; diff --git a/lib/CodeGen/RegAllocPBQP.cpp b/lib/CodeGen/RegAllocPBQP.cpp index 61f337bab49c..ea0d1fe0233f 100644 --- a/lib/CodeGen/RegAllocPBQP.cpp +++ b/lib/CodeGen/RegAllocPBQP.cpp @@ -31,9 +31,6 @@ #define DEBUG_TYPE "regalloc" -#include "PBQP/HeuristicSolver.h" -#include "PBQP/Graph.h" -#include "PBQP/Heuristics/Briggs.h" #include "RenderMachineFunction.h" #include "Splitter.h" #include "VirtRegMap.h" @@ -41,9 +38,13 @@ #include "llvm/CodeGen/CalcSpillWeights.h" #include "llvm/CodeGen/LiveIntervalAnalysis.h" #include "llvm/CodeGen/LiveStackAnalysis.h" +#include "llvm/CodeGen/RegAllocPBQP.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineLoopInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/PBQP/HeuristicSolver.h" +#include "llvm/CodeGen/PBQP/Graph.h" +#include "llvm/CodeGen/PBQP/Heuristics/Briggs.h" #include "llvm/CodeGen/RegAllocRegistry.h" #include "llvm/CodeGen/RegisterCoalescer.h" #include "llvm/Support/Debug.h" @@ -51,7 +52,6 @@ #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" #include -#include #include #include #include @@ -60,7 +60,7 @@ using namespace llvm; static RegisterRegAlloc registerPBQPRepAlloc("pbqp", "PBQP register allocator", - llvm::createPBQPRegisterAllocator); + createDefaultPBQPRegisterAllocator); static cl::opt pbqpCoalescing("pbqp-coalescing", @@ -69,698 +69,471 @@ pbqpCoalescing("pbqp-coalescing", static cl::opt pbqpPreSplitting("pbqp-pre-splitting", - cl::desc("Pre-splite before PBQP register allocation."), + cl::desc("Pre-split before PBQP register allocation."), cl::init(false), cl::Hidden); namespace { - /// - /// PBQP based allocators solve the register allocation problem by mapping - /// register allocation problems to Partitioned Boolean Quadratic - /// Programming problems. - class PBQPRegAlloc : public MachineFunctionPass { - public: +/// +/// PBQP based allocators solve the register allocation problem by mapping +/// register allocation problems to Partitioned Boolean Quadratic +/// Programming problems. +class RegAllocPBQP : public MachineFunctionPass { +public: + + static char ID; + + /// Construct a PBQP register allocator. + RegAllocPBQP(std::auto_ptr b) + : MachineFunctionPass(ID), builder(b) { + initializeSlotIndexesPass(*PassRegistry::getPassRegistry()); + initializeLiveIntervalsPass(*PassRegistry::getPassRegistry()); + initializeRegisterCoalescerAnalysisGroup(*PassRegistry::getPassRegistry()); + initializeCalculateSpillWeightsPass(*PassRegistry::getPassRegistry()); + initializeLiveStacksPass(*PassRegistry::getPassRegistry()); + initializeMachineLoopInfoPass(*PassRegistry::getPassRegistry()); + initializeLoopSplitterPass(*PassRegistry::getPassRegistry()); + initializeVirtRegMapPass(*PassRegistry::getPassRegistry()); + initializeRenderMachineFunctionPass(*PassRegistry::getPassRegistry()); + } - static char ID; + /// Return the pass name. + virtual const char* getPassName() const { + return "PBQP Register Allocator"; + } - /// Construct a PBQP register allocator. - PBQPRegAlloc() : MachineFunctionPass(ID) {} + /// PBQP analysis usage. + virtual void getAnalysisUsage(AnalysisUsage &au) const; - /// Return the pass name. - virtual const char* getPassName() const { - return "PBQP Register Allocator"; - } + /// Perform register allocation + virtual bool runOnMachineFunction(MachineFunction &MF); - /// PBQP analysis usage. - virtual void getAnalysisUsage(AnalysisUsage &au) const { - au.addRequired(); - au.addPreserved(); - au.addRequired(); - //au.addRequiredID(SplitCriticalEdgesID); - au.addRequired(); - au.addRequired(); - au.addRequired(); - au.addPreserved(); - au.addRequired(); - au.addPreserved(); - if (pbqpPreSplitting) - au.addRequired(); - au.addRequired(); - au.addRequired(); - MachineFunctionPass::getAnalysisUsage(au); - } +private: - /// Perform register allocation - virtual bool runOnMachineFunction(MachineFunction &MF); + typedef std::map LI2NodeMap; + typedef std::vector Node2LIMap; + typedef std::vector AllowedSet; + typedef std::vector AllowedSetMap; + typedef std::pair RegPair; + typedef std::map CoalesceMap; + typedef std::vector NodeVector; + typedef std::set RegSet; - private: - class LIOrdering { - public: - bool operator()(const LiveInterval *li1, const LiveInterval *li2) const { - return li1->reg < li2->reg; - } - }; - - typedef std::map LI2NodeMap; - typedef std::vector Node2LIMap; - typedef std::vector AllowedSet; - typedef std::vector AllowedSetMap; - typedef std::set RegSet; - typedef std::pair RegPair; - typedef std::map CoalesceMap; - - typedef std::set LiveIntervalSet; - - typedef std::vector NodeVector; - - MachineFunction *mf; - const TargetMachine *tm; - const TargetRegisterInfo *tri; - const TargetInstrInfo *tii; - const MachineLoopInfo *loopInfo; - MachineRegisterInfo *mri; - RenderMachineFunction *rmf; - - LiveIntervals *lis; - LiveStacks *lss; - VirtRegMap *vrm; - - LI2NodeMap li2Node; - Node2LIMap node2LI; - AllowedSetMap allowedSets; - LiveIntervalSet vregIntervalsToAlloc, - emptyVRegIntervals; - NodeVector problemNodes; - - - /// Builds a PBQP cost vector. - template - PBQP::Vector buildCostVector(unsigned vReg, - const RegContainer &allowed, - const CoalesceMap &cealesces, - PBQP::PBQPNum spillCost) const; - - /// \brief Builds a PBQP interference matrix. - /// - /// @return Either a pointer to a non-zero PBQP matrix representing the - /// allocation option costs, or a null pointer for a zero matrix. - /// - /// Expects allowed sets for two interfering LiveIntervals. These allowed - /// sets should contain only allocable registers from the LiveInterval's - /// register class, with any interfering pre-colored registers removed. - template - PBQP::Matrix* buildInterferenceMatrix(const RegContainer &allowed1, - const RegContainer &allowed2) const; - - /// - /// Expects allowed sets for two potentially coalescable LiveIntervals, - /// and an estimated benefit due to coalescing. The allowed sets should - /// contain only allocable registers from the LiveInterval's register - /// classes, with any interfering pre-colored registers removed. - template - PBQP::Matrix* buildCoalescingMatrix(const RegContainer &allowed1, - const RegContainer &allowed2, - PBQP::PBQPNum cBenefit) const; - - /// \brief Finds coalescing opportunities and returns them as a map. - /// - /// Any entries in the map are guaranteed coalescable, even if their - /// corresponding live intervals overlap. - CoalesceMap findCoalesces(); - - /// \brief Finds the initial set of vreg intervals to allocate. - void findVRegIntervalsToAlloc(); - - /// \brief Constructs a PBQP problem representation of the register - /// allocation problem for this function. - /// - /// @return a PBQP solver object for the register allocation problem. - PBQP::Graph constructPBQPProblem(); - - /// \brief Adds a stack interval if the given live interval has been - /// spilled. Used to support stack slot coloring. - void addStackInterval(const LiveInterval *spilled,MachineRegisterInfo* mri); - - /// \brief Given a solved PBQP problem maps this solution back to a register - /// assignment. - bool mapPBQPToRegAlloc(const PBQP::Solution &solution); - - /// \brief Postprocessing before final spilling. Sets basic block "live in" - /// variables. - void finalizeAlloc() const; - - }; - - char PBQPRegAlloc::ID = 0; -} + std::auto_ptr builder; + MachineFunction *mf; + const TargetMachine *tm; + const TargetRegisterInfo *tri; + const TargetInstrInfo *tii; + const MachineLoopInfo *loopInfo; + MachineRegisterInfo *mri; + RenderMachineFunction *rmf; -template -PBQP::Vector PBQPRegAlloc::buildCostVector(unsigned vReg, - const RegContainer &allowed, - const CoalesceMap &coalesces, - PBQP::PBQPNum spillCost) const { + LiveIntervals *lis; + LiveStacks *lss; + VirtRegMap *vrm; - typedef typename RegContainer::const_iterator AllowedItr; + RegSet vregsToAlloc, emptyIntervalVRegs; - // Allocate vector. Additional element (0th) used for spill option - PBQP::Vector v(allowed.size() + 1, 0); + /// \brief Finds the initial set of vreg intervals to allocate. + void findVRegIntervalsToAlloc(); - v[0] = spillCost; + /// \brief Adds a stack interval if the given live interval has been + /// spilled. Used to support stack slot coloring. + void addStackInterval(const LiveInterval *spilled,MachineRegisterInfo* mri); - // Iterate over the allowed registers inserting coalesce benefits if there - // are any. - unsigned ai = 0; - for (AllowedItr itr = allowed.begin(), end = allowed.end(); - itr != end; ++itr, ++ai) { + /// \brief Given a solved PBQP problem maps this solution back to a register + /// assignment. + bool mapPBQPToRegAlloc(const PBQPRAProblem &problem, + const PBQP::Solution &solution); - unsigned pReg = *itr; + /// \brief Postprocessing before final spilling. Sets basic block "live in" + /// variables. + void finalizeAlloc() const; - CoalesceMap::const_iterator cmItr = - coalesces.find(RegPair(vReg, pReg)); +}; - // No coalesce - on to the next preg. - if (cmItr == coalesces.end()) - continue; +char RegAllocPBQP::ID = 0; - // We have a coalesce - insert the benefit. - v[ai + 1] = -cmItr->second; - } +} // End anonymous namespace. - return v; +unsigned PBQPRAProblem::getVRegForNode(PBQP::Graph::ConstNodeItr node) const { + Node2VReg::const_iterator vregItr = node2VReg.find(node); + assert(vregItr != node2VReg.end() && "No vreg for node."); + return vregItr->second; } -template -PBQP::Matrix* PBQPRegAlloc::buildInterferenceMatrix( - const RegContainer &allowed1, const RegContainer &allowed2) const { - - typedef typename RegContainer::const_iterator RegContainerIterator; - - // Construct a PBQP matrix representing the cost of allocation options. The - // rows and columns correspond to the allocation options for the two live - // intervals. Elements will be infinite where corresponding registers alias, - // since we cannot allocate aliasing registers to interfering live intervals. - // All other elements (non-aliasing combinations) will have zero cost. Note - // that the spill option (element 0,0) has zero cost, since we can allocate - // both intervals to memory safely (the cost for each individual allocation - // to memory is accounted for by the cost vectors for each live interval). - PBQP::Matrix *m = - new PBQP::Matrix(allowed1.size() + 1, allowed2.size() + 1, 0); - - // Assume this is a zero matrix until proven otherwise. Zero matrices occur - // between interfering live ranges with non-overlapping register sets (e.g. - // non-overlapping reg classes, or disjoint sets of allowed regs within the - // same class). The term "overlapping" is used advisedly: sets which do not - // intersect, but contain registers which alias, will have non-zero matrices. - // We optimize zero matrices away to improve solver speed. - bool isZeroMatrix = true; - - - // Row index. Starts at 1, since the 0th row is for the spill option, which - // is always zero. - unsigned ri = 1; - - // Iterate over allowed sets, insert infinities where required. - for (RegContainerIterator a1Itr = allowed1.begin(), a1End = allowed1.end(); - a1Itr != a1End; ++a1Itr) { - - // Column index, starts at 1 as for row index. - unsigned ci = 1; - unsigned reg1 = *a1Itr; - - for (RegContainerIterator a2Itr = allowed2.begin(), a2End = allowed2.end(); - a2Itr != a2End; ++a2Itr) { - - unsigned reg2 = *a2Itr; - - // If the row/column regs are identical or alias insert an infinity. - if (tri->regsOverlap(reg1, reg2)) { - (*m)[ri][ci] = std::numeric_limits::infinity(); - isZeroMatrix = false; - } - - ++ci; - } - - ++ri; - } - - // If this turns out to be a zero matrix... - if (isZeroMatrix) { - // free it and return null. - delete m; - return 0; - } - - // ...otherwise return the cost matrix. - return m; +PBQP::Graph::NodeItr PBQPRAProblem::getNodeForVReg(unsigned vreg) const { + VReg2Node::const_iterator nodeItr = vreg2Node.find(vreg); + assert(nodeItr != vreg2Node.end() && "No node for vreg."); + return nodeItr->second; + } -template -PBQP::Matrix* PBQPRegAlloc::buildCoalescingMatrix( - const RegContainer &allowed1, const RegContainer &allowed2, - PBQP::PBQPNum cBenefit) const { - - typedef typename RegContainer::const_iterator RegContainerIterator; - - // Construct a PBQP Matrix representing the benefits of coalescing. As with - // interference matrices the rows and columns represent allowed registers - // for the LiveIntervals which are (potentially) to be coalesced. The amount - // -cBenefit will be placed in any element representing the same register - // for both intervals. - PBQP::Matrix *m = - new PBQP::Matrix(allowed1.size() + 1, allowed2.size() + 1, 0); - - // Reset costs to zero. - m->reset(0); - - // Assume the matrix is zero till proven otherwise. Zero matrices will be - // optimized away as in the interference case. - bool isZeroMatrix = true; - - // Row index. Starts at 1, since the 0th row is for the spill option, which - // is always zero. - unsigned ri = 1; - - // Iterate over the allowed sets, insert coalescing benefits where - // appropriate. - for (RegContainerIterator a1Itr = allowed1.begin(), a1End = allowed1.end(); - a1Itr != a1End; ++a1Itr) { - - // Column index, starts at 1 as for row index. - unsigned ci = 1; - unsigned reg1 = *a1Itr; - - for (RegContainerIterator a2Itr = allowed2.begin(), a2End = allowed2.end(); - a2Itr != a2End; ++a2Itr) { - - // If the row and column represent the same register insert a beneficial - // cost to preference this allocation - it would allow us to eliminate a - // move instruction. - if (reg1 == *a2Itr) { - (*m)[ri][ci] = -cBenefit; - isZeroMatrix = false; - } - - ++ci; - } - - ++ri; - } - - // If this turns out to be a zero matrix... - if (isZeroMatrix) { - // ...free it and return null. - delete m; - return 0; - } - - return m; +const PBQPRAProblem::AllowedSet& + PBQPRAProblem::getAllowedSet(unsigned vreg) const { + AllowedSetMap::const_iterator allowedSetItr = allowedSets.find(vreg); + assert(allowedSetItr != allowedSets.end() && "No pregs for vreg."); + const AllowedSet &allowedSet = allowedSetItr->second; + return allowedSet; } -PBQPRegAlloc::CoalesceMap PBQPRegAlloc::findCoalesces() { - - typedef MachineFunction::const_iterator MFIterator; - typedef MachineBasicBlock::const_iterator MBBIterator; - typedef LiveInterval::const_vni_iterator VNIIterator; +unsigned PBQPRAProblem::getPRegForOption(unsigned vreg, unsigned option) const { + assert(isPRegOption(vreg, option) && "Not a preg option."); - CoalesceMap coalescesFound; + const AllowedSet& allowedSet = getAllowedSet(vreg); + assert(option <= allowedSet.size() && "Option outside allowed set."); + return allowedSet[option - 1]; +} - // To find coalesces we need to iterate over the function looking for - // copy instructions. - for (MFIterator bbItr = mf->begin(), bbEnd = mf->end(); - bbItr != bbEnd; ++bbItr) { +std::auto_ptr PBQPBuilder::build(MachineFunction *mf, + const LiveIntervals *lis, + const MachineLoopInfo *loopInfo, + const RegSet &vregs) { - const MachineBasicBlock *mbb = &*bbItr; + typedef std::vector LIVector; - for (MBBIterator iItr = mbb->begin(), iEnd = mbb->end(); - iItr != iEnd; ++iItr) { + MachineRegisterInfo *mri = &mf->getRegInfo(); + const TargetRegisterInfo *tri = mf->getTarget().getRegisterInfo(); - const MachineInstr *instr = &*iItr; + std::auto_ptr p(new PBQPRAProblem()); + PBQP::Graph &g = p->getGraph(); + RegSet pregs; - // If this isn't a copy then continue to the next instruction. - if (!instr->isCopy()) - continue; - - unsigned srcReg = instr->getOperand(1).getReg(); - unsigned dstReg = instr->getOperand(0).getReg(); + // Collect the set of preg intervals, record that they're used in the MF. + for (LiveIntervals::const_iterator itr = lis->begin(), end = lis->end(); + itr != end; ++itr) { + if (TargetRegisterInfo::isPhysicalRegister(itr->first)) { + pregs.insert(itr->first); + mri->setPhysRegUsed(itr->first); + } + } - // If the registers are already the same our job is nice and easy. - if (dstReg == srcReg) - continue; + BitVector reservedRegs = tri->getReservedRegs(*mf); + + // Iterate over vregs. + for (RegSet::const_iterator vregItr = vregs.begin(), vregEnd = vregs.end(); + vregItr != vregEnd; ++vregItr) { + unsigned vreg = *vregItr; + const TargetRegisterClass *trc = mri->getRegClass(vreg); + const LiveInterval *vregLI = &lis->getInterval(vreg); + + // Compute an initial allowed set for the current vreg. + typedef std::vector VRAllowed; + VRAllowed vrAllowed; + for (TargetRegisterClass::iterator aoItr = trc->allocation_order_begin(*mf), + aoEnd = trc->allocation_order_end(*mf); + aoItr != aoEnd; ++aoItr) { + unsigned preg = *aoItr; + if (!reservedRegs.test(preg)) { + vrAllowed.push_back(preg); + } + } - bool srcRegIsPhysical = TargetRegisterInfo::isPhysicalRegister(srcReg), - dstRegIsPhysical = TargetRegisterInfo::isPhysicalRegister(dstReg); + // Remove any physical registers which overlap. + for (RegSet::const_iterator pregItr = pregs.begin(), + pregEnd = pregs.end(); + pregItr != pregEnd; ++pregItr) { + unsigned preg = *pregItr; + const LiveInterval *pregLI = &lis->getInterval(preg); - // If both registers are physical then we can't coalesce. - if (srcRegIsPhysical && dstRegIsPhysical) + if (pregLI->empty()) { continue; + } - // If it's a copy that includes two virtual register but the source and - // destination classes differ then we can't coalesce. - if (!srcRegIsPhysical && !dstRegIsPhysical && - mri->getRegClass(srcReg) != mri->getRegClass(dstReg)) + if (!vregLI->overlaps(*pregLI)) { continue; - - // If one is physical and one is virtual, check that the physical is - // allocatable in the class of the virtual. - if (srcRegIsPhysical && !dstRegIsPhysical) { - const TargetRegisterClass *dstRegClass = mri->getRegClass(dstReg); - if (std::find(dstRegClass->allocation_order_begin(*mf), - dstRegClass->allocation_order_end(*mf), srcReg) == - dstRegClass->allocation_order_end(*mf)) - continue; } - if (!srcRegIsPhysical && dstRegIsPhysical) { - const TargetRegisterClass *srcRegClass = mri->getRegClass(srcReg); - if (std::find(srcRegClass->allocation_order_begin(*mf), - srcRegClass->allocation_order_end(*mf), dstReg) == - srcRegClass->allocation_order_end(*mf)) - continue; - } - - // If we've made it here we have a copy with compatible register classes. - // We can probably coalesce, but we need to consider overlap. - const LiveInterval *srcLI = &lis->getInterval(srcReg), - *dstLI = &lis->getInterval(dstReg); - if (srcLI->overlaps(*dstLI)) { - // Even in the case of an overlap we might still be able to coalesce, - // but we need to make sure that no definition of either range occurs - // while the other range is live. + // Remove the register from the allowed set. + VRAllowed::iterator eraseItr = + std::find(vrAllowed.begin(), vrAllowed.end(), preg); - // Otherwise start by assuming we're ok. - bool badDef = false; - - // Test all defs of the source range. - for (VNIIterator - vniItr = srcLI->vni_begin(), vniEnd = srcLI->vni_end(); - vniItr != vniEnd; ++vniItr) { + if (eraseItr != vrAllowed.end()) { + vrAllowed.erase(eraseItr); + } - // If we find a poorly defined def we err on the side of caution. - if (!(*vniItr)->def.isValid()) { - badDef = true; - break; - } + // Also remove any aliases. + const unsigned *aliasItr = tri->getAliasSet(preg); + if (aliasItr != 0) { + for (; *aliasItr != 0; ++aliasItr) { + VRAllowed::iterator eraseItr = + std::find(vrAllowed.begin(), vrAllowed.end(), *aliasItr); - // If we find a def that kills the coalescing opportunity then - // record it and break from the loop. - if (dstLI->liveAt((*vniItr)->def)) { - badDef = true; - break; + if (eraseItr != vrAllowed.end()) { + vrAllowed.erase(eraseItr); } } + } + } - // If we have a bad def give up, continue to the next instruction. - if (badDef) - continue; - - // Otherwise test definitions of the destination range. - for (VNIIterator - vniItr = dstLI->vni_begin(), vniEnd = dstLI->vni_end(); - vniItr != vniEnd; ++vniItr) { + // Construct the node. + PBQP::Graph::NodeItr node = + g.addNode(PBQP::Vector(vrAllowed.size() + 1, 0)); - // We want to make sure we skip the copy instruction itself. - if ((*vniItr)->getCopy() == instr) - continue; + // Record the mapping and allowed set in the problem. + p->recordVReg(vreg, node, vrAllowed.begin(), vrAllowed.end()); - if (!(*vniItr)->def.isValid()) { - badDef = true; - break; - } + PBQP::PBQPNum spillCost = (vregLI->weight != 0.0) ? + vregLI->weight : std::numeric_limits::min(); - if (srcLI->liveAt((*vniItr)->def)) { - badDef = true; - break; - } - } + addSpillCosts(g.getNodeCosts(node), spillCost); + } - // As before a bad def we give up and continue to the next instr. - if (badDef) - continue; + for (RegSet::const_iterator vr1Itr = vregs.begin(), vrEnd = vregs.end(); + vr1Itr != vrEnd; ++vr1Itr) { + unsigned vr1 = *vr1Itr; + const LiveInterval &l1 = lis->getInterval(vr1); + const PBQPRAProblem::AllowedSet &vr1Allowed = p->getAllowedSet(vr1); + + for (RegSet::const_iterator vr2Itr = llvm::next(vr1Itr); + vr2Itr != vrEnd; ++vr2Itr) { + unsigned vr2 = *vr2Itr; + const LiveInterval &l2 = lis->getInterval(vr2); + const PBQPRAProblem::AllowedSet &vr2Allowed = p->getAllowedSet(vr2); + + assert(!l2.empty() && "Empty interval in vreg set?"); + if (l1.overlaps(l2)) { + PBQP::Graph::EdgeItr edge = + g.addEdge(p->getNodeForVReg(vr1), p->getNodeForVReg(vr2), + PBQP::Matrix(vr1Allowed.size()+1, vr2Allowed.size()+1, 0)); + + addInterferenceCosts(g.getEdgeCosts(edge), vr1Allowed, vr2Allowed, tri); } - - // If we make it to here then either the ranges didn't overlap, or they - // did, but none of their definitions would prevent us from coalescing. - // We're good to go with the coalesce. - - float cBenefit = std::pow(10.0f, (float)loopInfo->getLoopDepth(mbb)) / 5.0; - - coalescesFound[RegPair(srcReg, dstReg)] = cBenefit; - coalescesFound[RegPair(dstReg, srcReg)] = cBenefit; } - } - return coalescesFound; + return p; } -void PBQPRegAlloc::findVRegIntervalsToAlloc() { - - // Iterate over all live ranges. - for (LiveIntervals::iterator itr = lis->begin(), end = lis->end(); - itr != end; ++itr) { - - // Ignore physical ones. - if (TargetRegisterInfo::isPhysicalRegister(itr->first)) - continue; - - LiveInterval *li = itr->second; - - // If this live interval is non-empty we will use pbqp to allocate it. - // Empty intervals we allocate in a simple post-processing stage in - // finalizeAlloc. - if (!li->empty()) { - vregIntervalsToAlloc.insert(li); - } - else { - emptyVRegIntervals.insert(li); - } - } +void PBQPBuilder::addSpillCosts(PBQP::Vector &costVec, + PBQP::PBQPNum spillCost) { + costVec[0] = spillCost; } -PBQP::Graph PBQPRegAlloc::constructPBQPProblem() { - - typedef std::vector LIVector; - typedef std::vector RegVector; +void PBQPBuilder::addInterferenceCosts( + PBQP::Matrix &costMat, + const PBQPRAProblem::AllowedSet &vr1Allowed, + const PBQPRAProblem::AllowedSet &vr2Allowed, + const TargetRegisterInfo *tri) { + assert(costMat.getRows() == vr1Allowed.size() + 1 && "Matrix height mismatch."); + assert(costMat.getCols() == vr2Allowed.size() + 1 && "Matrix width mismatch."); - // This will store the physical intervals for easy reference. - LIVector physIntervals; + for (unsigned i = 0; i != vr1Allowed.size(); ++i) { + unsigned preg1 = vr1Allowed[i]; - // Start by clearing the old node <-> live interval mappings & allowed sets - li2Node.clear(); - node2LI.clear(); - allowedSets.clear(); - - // Populate physIntervals, update preg use: - for (LiveIntervals::iterator itr = lis->begin(), end = lis->end(); - itr != end; ++itr) { + for (unsigned j = 0; j != vr2Allowed.size(); ++j) { + unsigned preg2 = vr2Allowed[j]; - if (TargetRegisterInfo::isPhysicalRegister(itr->first)) { - physIntervals.push_back(itr->second); - mri->setPhysRegUsed(itr->second->reg); + if (tri->regsOverlap(preg1, preg2)) { + costMat[i + 1][j + 1] = std::numeric_limits::infinity(); + } } } +} - // Iterate over vreg intervals, construct live interval <-> node number - // mappings. - for (LiveIntervalSet::const_iterator - itr = vregIntervalsToAlloc.begin(), end = vregIntervalsToAlloc.end(); - itr != end; ++itr) { - const LiveInterval *li = *itr; - - li2Node[li] = node2LI.size(); - node2LI.push_back(li); - } - - // Get the set of potential coalesces. - CoalesceMap coalesces; - - if (pbqpCoalescing) { - coalesces = findCoalesces(); - } - - // Construct a PBQP solver for this problem - PBQP::Graph problem; - problemNodes.resize(vregIntervalsToAlloc.size()); - - // Resize allowedSets container appropriately. - allowedSets.resize(vregIntervalsToAlloc.size()); - - BitVector ReservedRegs = tri->getReservedRegs(*mf); - - // Iterate over virtual register intervals to compute allowed sets... - for (unsigned node = 0; node < node2LI.size(); ++node) { - - // Grab pointers to the interval and its register class. - const LiveInterval *li = node2LI[node]; - const TargetRegisterClass *liRC = mri->getRegClass(li->reg); +std::auto_ptr PBQPBuilderWithCoalescing::build( + MachineFunction *mf, + const LiveIntervals *lis, + const MachineLoopInfo *loopInfo, + const RegSet &vregs) { - // Start by assuming all allocable registers in the class are allowed... - RegVector liAllowed; - TargetRegisterClass::iterator aob = liRC->allocation_order_begin(*mf); - TargetRegisterClass::iterator aoe = liRC->allocation_order_end(*mf); - for (TargetRegisterClass::iterator it = aob; it != aoe; ++it) - if (!ReservedRegs.test(*it)) - liAllowed.push_back(*it); + std::auto_ptr p = PBQPBuilder::build(mf, lis, loopInfo, vregs); + PBQP::Graph &g = p->getGraph(); - // Eliminate the physical registers which overlap with this range, along - // with all their aliases. - for (LIVector::iterator pItr = physIntervals.begin(), - pEnd = physIntervals.end(); pItr != pEnd; ++pItr) { + const TargetMachine &tm = mf->getTarget(); + CoalescerPair cp(*tm.getInstrInfo(), *tm.getRegisterInfo()); - if (!li->overlaps(**pItr)) - continue; + // Scan the machine function and add a coalescing cost whenever CoalescerPair + // gives the Ok. + for (MachineFunction::const_iterator mbbItr = mf->begin(), + mbbEnd = mf->end(); + mbbItr != mbbEnd; ++mbbItr) { + const MachineBasicBlock *mbb = &*mbbItr; - unsigned pReg = (*pItr)->reg; - - // If we get here then the live intervals overlap, but we're still ok - // if they're coalescable. - if (coalesces.find(RegPair(li->reg, pReg)) != coalesces.end()) - continue; + for (MachineBasicBlock::const_iterator miItr = mbb->begin(), + miEnd = mbb->end(); + miItr != miEnd; ++miItr) { + const MachineInstr *mi = &*miItr; - // If we get here then we have a genuine exclusion. + if (!cp.setRegisters(mi)) { + continue; // Not coalescable. + } - // Remove the overlapping reg... - RegVector::iterator eraseItr = - std::find(liAllowed.begin(), liAllowed.end(), pReg); + if (cp.getSrcReg() == cp.getDstReg()) { + continue; // Already coalesced. + } - if (eraseItr != liAllowed.end()) - liAllowed.erase(eraseItr); + unsigned dst = cp.getDstReg(), + src = cp.getSrcReg(); - const unsigned *aliasItr = tri->getAliasSet(pReg); + const float copyFactor = 0.5; // Cost of copy relative to load. Current + // value plucked randomly out of the air. + + PBQP::PBQPNum cBenefit = + copyFactor * LiveIntervals::getSpillWeight(false, true, + loopInfo->getLoopDepth(mbb)); - if (aliasItr != 0) { - // ...and its aliases. - for (; *aliasItr != 0; ++aliasItr) { - RegVector::iterator eraseItr = - std::find(liAllowed.begin(), liAllowed.end(), *aliasItr); + if (cp.isPhys()) { + if (!lis->isAllocatable(dst)) { + continue; + } - if (eraseItr != liAllowed.end()) { - liAllowed.erase(eraseItr); + const PBQPRAProblem::AllowedSet &allowed = p->getAllowedSet(src); + unsigned pregOpt = 0; + while (pregOpt < allowed.size() && allowed[pregOpt] != dst) { + ++pregOpt; + } + if (pregOpt < allowed.size()) { + ++pregOpt; // +1 to account for spill option. + PBQP::Graph::NodeItr node = p->getNodeForVReg(src); + addPhysRegCoalesce(g.getNodeCosts(node), pregOpt, cBenefit); + } + } else { + const PBQPRAProblem::AllowedSet *allowed1 = &p->getAllowedSet(dst); + const PBQPRAProblem::AllowedSet *allowed2 = &p->getAllowedSet(src); + PBQP::Graph::NodeItr node1 = p->getNodeForVReg(dst); + PBQP::Graph::NodeItr node2 = p->getNodeForVReg(src); + PBQP::Graph::EdgeItr edge = g.findEdge(node1, node2); + if (edge == g.edgesEnd()) { + edge = g.addEdge(node1, node2, PBQP::Matrix(allowed1->size() + 1, + allowed2->size() + 1, + 0)); + } else { + if (g.getEdgeNode1(edge) == node2) { + std::swap(node1, node2); + std::swap(allowed1, allowed2); } } + + addVirtRegCoalesce(g.getEdgeCosts(edge), *allowed1, *allowed2, + cBenefit); } } + } - // Copy the allowed set into a member vector for use when constructing cost - // vectors & matrices, and mapping PBQP solutions back to assignments. - allowedSets[node] = AllowedSet(liAllowed.begin(), liAllowed.end()); + return p; +} - // Set the spill cost to the interval weight, or epsilon if the - // interval weight is zero - PBQP::PBQPNum spillCost = (li->weight != 0.0) ? - li->weight : std::numeric_limits::min(); +void PBQPBuilderWithCoalescing::addPhysRegCoalesce(PBQP::Vector &costVec, + unsigned pregOption, + PBQP::PBQPNum benefit) { + costVec[pregOption] += -benefit; +} - // Build a cost vector for this interval. - problemNodes[node] = - problem.addNode( - buildCostVector(li->reg, allowedSets[node], coalesces, spillCost)); +void PBQPBuilderWithCoalescing::addVirtRegCoalesce( + PBQP::Matrix &costMat, + const PBQPRAProblem::AllowedSet &vr1Allowed, + const PBQPRAProblem::AllowedSet &vr2Allowed, + PBQP::PBQPNum benefit) { - } + assert(costMat.getRows() == vr1Allowed.size() + 1 && "Size mismatch."); + assert(costMat.getCols() == vr2Allowed.size() + 1 && "Size mismatch."); + for (unsigned i = 0; i != vr1Allowed.size(); ++i) { + unsigned preg1 = vr1Allowed[i]; + for (unsigned j = 0; j != vr2Allowed.size(); ++j) { + unsigned preg2 = vr2Allowed[j]; + + if (preg1 == preg2) { + costMat[i + 1][j + 1] += -benefit; + } + } + } +} - // Now add the cost matrices... - for (unsigned node1 = 0; node1 < node2LI.size(); ++node1) { - const LiveInterval *li = node2LI[node1]; - // Test for live range overlaps and insert interference matrices. - for (unsigned node2 = node1 + 1; node2 < node2LI.size(); ++node2) { - const LiveInterval *li2 = node2LI[node2]; +void RegAllocPBQP::getAnalysisUsage(AnalysisUsage &au) const { + au.addRequired(); + au.addPreserved(); + au.addRequired(); + //au.addRequiredID(SplitCriticalEdgesID); + au.addRequired(); + au.addRequired(); + au.addRequired(); + au.addPreserved(); + au.addRequired(); + au.addPreserved(); + if (pbqpPreSplitting) + au.addRequired(); + au.addRequired(); + au.addRequired(); + MachineFunctionPass::getAnalysisUsage(au); +} - CoalesceMap::const_iterator cmItr = - coalesces.find(RegPair(li->reg, li2->reg)); +void RegAllocPBQP::findVRegIntervalsToAlloc() { - PBQP::Matrix *m = 0; + // Iterate over all live ranges. + for (LiveIntervals::iterator itr = lis->begin(), end = lis->end(); + itr != end; ++itr) { - if (cmItr != coalesces.end()) { - m = buildCoalescingMatrix(allowedSets[node1], allowedSets[node2], - cmItr->second); - } - else if (li->overlaps(*li2)) { - m = buildInterferenceMatrix(allowedSets[node1], allowedSets[node2]); - } + // Ignore physical ones. + if (TargetRegisterInfo::isPhysicalRegister(itr->first)) + continue; - if (m != 0) { - problem.addEdge(problemNodes[node1], - problemNodes[node2], - *m); + LiveInterval *li = itr->second; - delete m; - } + // If this live interval is non-empty we will use pbqp to allocate it. + // Empty intervals we allocate in a simple post-processing stage in + // finalizeAlloc. + if (!li->empty()) { + vregsToAlloc.insert(li->reg); + } else { + emptyIntervalVRegs.insert(li->reg); } } - - assert(problem.getNumNodes() == allowedSets.size()); -/* - std::cerr << "Allocating for " << problem.getNumNodes() << " nodes, " - << problem.getNumEdges() << " edges.\n"; - - problem.printDot(std::cerr); -*/ - // We're done, PBQP problem constructed - return it. - return problem; } -void PBQPRegAlloc::addStackInterval(const LiveInterval *spilled, +void RegAllocPBQP::addStackInterval(const LiveInterval *spilled, MachineRegisterInfo* mri) { int stackSlot = vrm->getStackSlot(spilled->reg); - if (stackSlot == VirtRegMap::NO_STACK_SLOT) + if (stackSlot == VirtRegMap::NO_STACK_SLOT) { return; + } const TargetRegisterClass *RC = mri->getRegClass(spilled->reg); LiveInterval &stackInterval = lss->getOrCreateInterval(stackSlot, RC); VNInfo *vni; - if (stackInterval.getNumValNums() != 0) + if (stackInterval.getNumValNums() != 0) { vni = stackInterval.getValNumInfo(0); - else + } else { vni = stackInterval.getNextValue( - SlotIndex(), 0, false, lss->getVNInfoAllocator()); + SlotIndex(), 0, lss->getVNInfoAllocator()); + } LiveInterval &rhsInterval = lis->getInterval(spilled->reg); stackInterval.MergeRangesInAsValue(rhsInterval, vni); } -bool PBQPRegAlloc::mapPBQPToRegAlloc(const PBQP::Solution &solution) { - +bool RegAllocPBQP::mapPBQPToRegAlloc(const PBQPRAProblem &problem, + const PBQP::Solution &solution) { // Set to true if we have any spills bool anotherRoundNeeded = false; // Clear the existing allocation. vrm->clearAllVirt(); - // Iterate over the nodes mapping the PBQP solution to a register assignment. - for (unsigned node = 0; node < node2LI.size(); ++node) { - unsigned virtReg = node2LI[node]->reg, - allocSelection = solution.getSelection(problemNodes[node]); - - - // If the PBQP solution is non-zero it's a physical register... - if (allocSelection != 0) { - // Get the physical reg, subtracting 1 to account for the spill option. - unsigned physReg = allowedSets[node][allocSelection - 1]; - - DEBUG(dbgs() << "VREG " << virtReg << " -> " - << tri->getName(physReg) << "\n"); - - assert(physReg != 0); - - // Add to the virt reg map and update the used phys regs. - vrm->assignVirt2Phys(virtReg, physReg); - } - // ...Otherwise it's a spill. - else { - - // Make sure we ignore this virtual reg on the next round - // of allocation - vregIntervalsToAlloc.erase(&lis->getInterval(virtReg)); - - // Insert spill ranges for this live range - const LiveInterval *spillInterval = node2LI[node]; - double oldSpillWeight = spillInterval->weight; + const PBQP::Graph &g = problem.getGraph(); + // Iterate over the nodes mapping the PBQP solution to a register + // assignment. + for (PBQP::Graph::ConstNodeItr node = g.nodesBegin(), + nodeEnd = g.nodesEnd(); + node != nodeEnd; ++node) { + unsigned vreg = problem.getVRegForNode(node); + unsigned alloc = solution.getSelection(node); + + if (problem.isPRegOption(vreg, alloc)) { + unsigned preg = problem.getPRegForOption(vreg, alloc); + DEBUG(dbgs() << "VREG " << vreg << " -> " << tri->getName(preg) << "\n"); + assert(preg != 0 && "Invalid preg selected."); + vrm->assignVirt2Phys(vreg, preg); + } else if (problem.isSpillOption(vreg, alloc)) { + vregsToAlloc.erase(vreg); + const LiveInterval* spillInterval = &lis->getInterval(vreg); + double oldWeight = spillInterval->weight; SmallVector spillIs; rmf->rememberUseDefs(spillInterval); std::vector newSpills = @@ -768,42 +541,42 @@ bool PBQPRegAlloc::mapPBQPToRegAlloc(const PBQP::Solution &solution) { addStackInterval(spillInterval, mri); rmf->rememberSpills(spillInterval, newSpills); - (void) oldSpillWeight; - DEBUG(dbgs() << "VREG " << virtReg << " -> SPILLED (Cost: " - << oldSpillWeight << ", New vregs: "); + (void) oldWeight; + DEBUG(dbgs() << "VREG " << vreg << " -> SPILLED (Cost: " + << oldWeight << ", New vregs: "); // Copy any newly inserted live intervals into the list of regs to // allocate. for (std::vector::const_iterator itr = newSpills.begin(), end = newSpills.end(); itr != end; ++itr) { - assert(!(*itr)->empty() && "Empty spill range."); - DEBUG(dbgs() << (*itr)->reg << " "); - - vregIntervalsToAlloc.insert(*itr); + vregsToAlloc.insert((*itr)->reg); } DEBUG(dbgs() << ")\n"); // We need another round if spill intervals were added. anotherRoundNeeded |= !newSpills.empty(); + } else { + assert(false && "Unknown allocation option."); } } return !anotherRoundNeeded; } -void PBQPRegAlloc::finalizeAlloc() const { + +void RegAllocPBQP::finalizeAlloc() const { typedef LiveIntervals::iterator LIIterator; typedef LiveInterval::Ranges::const_iterator LRIterator; // First allocate registers for the empty intervals. - for (LiveIntervalSet::const_iterator - itr = emptyVRegIntervals.begin(), end = emptyVRegIntervals.end(); + for (RegSet::const_iterator + itr = emptyIntervalVRegs.begin(), end = emptyIntervalVRegs.end(); itr != end; ++itr) { - LiveInterval *li = *itr; + LiveInterval *li = &lis->getInterval(*itr); unsigned physReg = vrm->getRegAllocPref(li->reg); @@ -828,11 +601,9 @@ void PBQPRegAlloc::finalizeAlloc() const { // Get the physical register for this interval if (TargetRegisterInfo::isPhysicalRegister(li->reg)) { reg = li->reg; - } - else if (vrm->isAssignedReg(li->reg)) { + } else if (vrm->isAssignedReg(li->reg)) { reg = vrm->getPhys(li->reg); - } - else { + } else { // Ranges which are assigned a stack slot only are ignored. continue; } @@ -849,7 +620,7 @@ void PBQPRegAlloc::finalizeAlloc() const { // Find the set of basic blocks which this range is live into... if (lis->findLiveInMBBs(lrItr->start, lrItr->end, liveInMBBs)) { // And add the physreg for this interval to their live-in sets. - for (unsigned i = 0; i < liveInMBBs.size(); ++i) { + for (unsigned i = 0; i != liveInMBBs.size(); ++i) { if (liveInMBBs[i] != entryMBB) { if (!liveInMBBs[i]->isLiveIn(reg)) { liveInMBBs[i]->addLiveIn(reg); @@ -863,7 +634,7 @@ void PBQPRegAlloc::finalizeAlloc() const { } -bool PBQPRegAlloc::runOnMachineFunction(MachineFunction &MF) { +bool RegAllocPBQP::runOnMachineFunction(MachineFunction &MF) { mf = &MF; tm = &mf->getTarget(); @@ -894,7 +665,7 @@ bool PBQPRegAlloc::runOnMachineFunction(MachineFunction &MF) { findVRegIntervalsToAlloc(); // If there are non-empty intervals allocate them using pbqp. - if (!vregIntervalsToAlloc.empty()) { + if (!vregsToAlloc.empty()) { bool pbqpAllocComplete = false; unsigned round = 0; @@ -902,11 +673,13 @@ bool PBQPRegAlloc::runOnMachineFunction(MachineFunction &MF) { while (!pbqpAllocComplete) { DEBUG(dbgs() << " PBQP Regalloc round " << round << ":\n"); - PBQP::Graph problem = constructPBQPProblem(); + std::auto_ptr problem = + builder->build(mf, lis, loopInfo, vregsToAlloc); PBQP::Solution solution = - PBQP::HeuristicSolver::solve(problem); + PBQP::HeuristicSolver::solve( + problem->getGraph()); - pbqpAllocComplete = mapPBQPToRegAlloc(solution); + pbqpAllocComplete = mapPBQPToRegAlloc(*problem, solution); ++round; } @@ -917,12 +690,8 @@ bool PBQPRegAlloc::runOnMachineFunction(MachineFunction &MF) { rmf->renderMachineFunction("After PBQP register allocation.", vrm); - vregIntervalsToAlloc.clear(); - emptyVRegIntervals.clear(); - li2Node.clear(); - node2LI.clear(); - allowedSets.clear(); - problemNodes.clear(); + vregsToAlloc.clear(); + emptyIntervalVRegs.clear(); DEBUG(dbgs() << "Post alloc VirtRegMap:\n" << *vrm << "\n"); @@ -934,9 +703,18 @@ bool PBQPRegAlloc::runOnMachineFunction(MachineFunction &MF) { return true; } -FunctionPass* llvm::createPBQPRegisterAllocator() { - return new PBQPRegAlloc(); +FunctionPass* llvm::createPBQPRegisterAllocator( + std::auto_ptr builder) { + return new RegAllocPBQP(builder); } +FunctionPass* llvm::createDefaultPBQPRegisterAllocator() { + if (pbqpCoalescing) { + return createPBQPRegisterAllocator( + std::auto_ptr(new PBQPBuilderWithCoalescing())); + } // else + return createPBQPRegisterAllocator( + std::auto_ptr(new PBQPBuilder())); +} #undef DEBUG_TYPE diff --git a/lib/CodeGen/RegisterCoalescer.cpp b/lib/CodeGen/RegisterCoalescer.cpp index 02b5539f0f4f..407559a211a0 100644 --- a/lib/CodeGen/RegisterCoalescer.cpp +++ b/lib/CodeGen/RegisterCoalescer.cpp @@ -24,7 +24,8 @@ using namespace llvm; // Register the RegisterCoalescer interface, providing a nice name to refer to. -static RegisterAnalysisGroup Z("Register Coalescer"); +INITIALIZE_ANALYSIS_GROUP(RegisterCoalescer, "Register Coalescer", + SimpleRegisterCoalescing) char RegisterCoalescer::ID = 0; // RegisterCoalescer destructor: DO NOT move this to the header file diff --git a/lib/CodeGen/RenderMachineFunction.cpp b/lib/CodeGen/RenderMachineFunction.cpp index 93426eecbbc1..cbfd5a23d63d 100644 --- a/lib/CodeGen/RenderMachineFunction.cpp +++ b/lib/CodeGen/RenderMachineFunction.cpp @@ -30,9 +30,14 @@ using namespace llvm; char RenderMachineFunction::ID = 0; -INITIALIZE_PASS(RenderMachineFunction, "rendermf", +INITIALIZE_PASS_BEGIN(RenderMachineFunction, "rendermf", "Render machine functions (and related info) to HTML pages", - false, false); + false, false) +INITIALIZE_PASS_DEPENDENCY(SlotIndexes) +INITIALIZE_PASS_DEPENDENCY(LiveIntervals) +INITIALIZE_PASS_END(RenderMachineFunction, "rendermf", + "Render machine functions (and related info) to HTML pages", + false, false) static cl::opt outputFileSuffix("rmf-file-suffix", @@ -458,14 +463,9 @@ namespace llvm { liItr != liEnd; ++liItr) { LiveInterval *li = liItr->second; - const TargetRegisterClass *liTRC; - if (TargetRegisterInfo::isPhysicalRegister(li->reg)) continue; - liTRC = mri->getRegClass(li->reg); - - // For all ranges in the current interal. for (LiveInterval::iterator lrItr = li->begin(), lrEnd = li->end(); diff --git a/lib/CodeGen/RenderMachineFunction.h b/lib/CodeGen/RenderMachineFunction.h index 8d56a8292ac5..85719923c0c6 100644 --- a/lib/CodeGen/RenderMachineFunction.h +++ b/lib/CodeGen/RenderMachineFunction.h @@ -202,7 +202,9 @@ namespace llvm { public: static char ID; - RenderMachineFunction() : MachineFunctionPass(ID) {} + RenderMachineFunction() : MachineFunctionPass(ID) { + initializeRenderMachineFunctionPass(*PassRegistry::getPassRegistry()); + } virtual void getAnalysisUsage(AnalysisUsage &au) const; diff --git a/lib/CodeGen/ScheduleDAG.cpp b/lib/CodeGen/ScheduleDAG.cpp index 7d39dc496afe..3388889c9e91 100644 --- a/lib/CodeGen/ScheduleDAG.cpp +++ b/lib/CodeGen/ScheduleDAG.cpp @@ -15,6 +15,7 @@ #define DEBUG_TYPE "pre-RA-sched" #include "llvm/CodeGen/ScheduleDAG.h" #include "llvm/CodeGen/ScheduleHazardRecognizer.h" +#include "llvm/CodeGen/SelectionDAGNodes.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetRegisterInfo.h" @@ -33,6 +34,12 @@ ScheduleDAG::ScheduleDAG(MachineFunction &mf) ScheduleDAG::~ScheduleDAG() {} +/// getInstrDesc helper to handle SDNodes. +const TargetInstrDesc *ScheduleDAG::getNodeDesc(const SDNode *Node) const { + if (!Node || !Node->isMachineOpcode()) return NULL; + return &TII->get(Node->getMachineOpcode()); +} + /// dump - dump the schedule. void ScheduleDAG::dumpSchedule() const { for (unsigned i = 0, e = Sequence.size(); i != e; i++) { @@ -68,12 +75,12 @@ void ScheduleDAG::Run(MachineBasicBlock *bb, /// addPred - This adds the specified edge as a pred of the current node if /// not already. It also adds the current node as a successor of the /// specified node. -void SUnit::addPred(const SDep &D) { +bool SUnit::addPred(const SDep &D) { // If this node already has this depenence, don't add a redundant one. for (SmallVector::const_iterator I = Preds.begin(), E = Preds.end(); I != E; ++I) if (*I == D) - return; + return false; // Now add a corresponding succ to N. SDep P = D; P.setSUnit(this); @@ -99,6 +106,7 @@ void SUnit::addPred(const SDep &D) { this->setDepthDirty(); N->setHeightDirty(); } + return true; } /// removePred - This removes the specified edge as a pred of the current @@ -278,6 +286,7 @@ void SUnit::dumpAll(const ScheduleDAG *G) const { dbgs() << " # preds left : " << NumPredsLeft << "\n"; dbgs() << " # succs left : " << NumSuccsLeft << "\n"; + dbgs() << " # rdefs left : " << NumRegDefsLeft << "\n"; dbgs() << " Latency : " << Latency << "\n"; dbgs() << " Depth : " << Depth << "\n"; dbgs() << " Height : " << Height << "\n"; @@ -492,7 +501,7 @@ void ScheduleDAGTopologicalSort::RemovePred(SUnit *M, SUnit *N) { /// all nodes affected by the edge insertion. These nodes will later get new /// topological indexes by means of the Shift method. void ScheduleDAGTopologicalSort::DFS(const SUnit *SU, int UpperBound, - bool& HasLoop) { + bool &HasLoop) { std::vector WorkList; WorkList.reserve(SUnits.size()); diff --git a/lib/CodeGen/ScheduleDAGEmit.cpp b/lib/CodeGen/ScheduleDAGEmit.cpp index 0a2fb3796a42..6b7a8c6491bd 100644 --- a/lib/CodeGen/ScheduleDAGEmit.cpp +++ b/lib/CodeGen/ScheduleDAGEmit.cpp @@ -57,7 +57,7 @@ void ScheduleDAG::EmitPhysRegCopy(SUnit *SU, assert(I->getReg() && "Unknown physical register!"); unsigned VRBase = MRI.createVirtualRegister(SU->CopyDstRC); bool isNew = VRBaseMap.insert(std::make_pair(SU, VRBase)).second; - isNew = isNew; // Silence compiler warning. + (void)isNew; // Silence compiler warning. assert(isNew && "Node emitted out of order - early"); BuildMI(*BB, InsertPos, DebugLoc(), TII->get(TargetOpcode::COPY), VRBase) .addReg(I->getReg()); diff --git a/lib/CodeGen/ScheduleDAGInstrs.cpp b/lib/CodeGen/ScheduleDAGInstrs.cpp index ea93dd5c6663..f17023eabb72 100644 --- a/lib/CodeGen/ScheduleDAGInstrs.cpp +++ b/lib/CodeGen/ScheduleDAGInstrs.cpp @@ -16,6 +16,7 @@ #include "ScheduleDAGInstrs.h" #include "llvm/Operator.h" #include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" @@ -32,9 +33,9 @@ using namespace llvm; ScheduleDAGInstrs::ScheduleDAGInstrs(MachineFunction &mf, const MachineLoopInfo &mli, const MachineDominatorTree &mdt) - : ScheduleDAG(mf), MLI(mli), MDT(mdt), Defs(TRI->getNumRegs()), - Uses(TRI->getNumRegs()), LoopRegs(MLI, MDT) { - MFI = mf.getFrameInfo(); + : ScheduleDAG(mf), MLI(mli), MDT(mdt), MFI(mf.getFrameInfo()), + InstrItins(mf.getTarget().getInstrItineraryData()), + Defs(TRI->getNumRegs()), Uses(TRI->getNumRegs()), LoopRegs(MLI, MDT) { DbgValueVec.clear(); } @@ -78,12 +79,12 @@ static const Value *getUnderlyingObjectFromInt(const Value *V) { } while (1); } -/// getUnderlyingObject - This is a wrapper around Value::getUnderlyingObject +/// getUnderlyingObject - This is a wrapper around GetUnderlyingObject /// and adds support for basic ptrtoint+arithmetic+inttoptr sequences. static const Value *getUnderlyingObject(const Value *V) { // First just call Value::getUnderlyingObject to let it do what it does. do { - V = V->getUnderlyingObject(); + V = GetUnderlyingObject(V); // If it found an inttoptr, use special code to continue climing. if (Operator::getOpcode(V) != Instruction::IntToPtr) break; @@ -141,6 +142,46 @@ void ScheduleDAGInstrs::StartBlock(MachineBasicBlock *BB) { } } +/// AddSchedBarrierDeps - Add dependencies from instructions in the current +/// list of instructions being scheduled to scheduling barrier by adding +/// the exit SU to the register defs and use list. This is because we want to +/// make sure instructions which define registers that are either used by +/// the terminator or are live-out are properly scheduled. This is +/// especially important when the definition latency of the return value(s) +/// are too high to be hidden by the branch or when the liveout registers +/// used by instructions in the fallthrough block. +void ScheduleDAGInstrs::AddSchedBarrierDeps() { + MachineInstr *ExitMI = InsertPos != BB->end() ? &*InsertPos : 0; + ExitSU.setInstr(ExitMI); + bool AllDepKnown = ExitMI && + (ExitMI->getDesc().isCall() || ExitMI->getDesc().isBarrier()); + if (ExitMI && AllDepKnown) { + // If it's a call or a barrier, add dependencies on the defs and uses of + // instruction. + for (unsigned i = 0, e = ExitMI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = ExitMI->getOperand(i); + if (!MO.isReg() || MO.isDef()) continue; + unsigned Reg = MO.getReg(); + if (Reg == 0) continue; + + assert(TRI->isPhysicalRegister(Reg) && "Virtual register encountered!"); + Uses[Reg].push_back(&ExitSU); + } + } else { + // For others, e.g. fallthrough, conditional branch, assume the exit + // uses all the registers that are livein to the successor blocks. + SmallSet Seen; + for (MachineBasicBlock::succ_iterator SI = BB->succ_begin(), + SE = BB->succ_end(); SI != SE; ++SI) + for (MachineBasicBlock::livein_iterator I = (*SI)->livein_begin(), + E = (*SI)->livein_end(); I != E; ++I) { + unsigned Reg = *I; + if (Seen.insert(Reg)) + Uses[Reg].push_back(&ExitSU); + } + } +} + void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) { // We'll be allocating one SUnit for each instruction, plus one for // the region exit node. @@ -175,6 +216,10 @@ void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) { // without emitting the info from the previous call. DbgValueVec.clear(); + // Model data dependencies between instructions being scheduled and the + // ExitSU. + AddSchedBarrierDeps(); + // Walk the list of instructions, from bottom moving up. for (MachineBasicBlock::iterator MII = InsertPos, MIE = Begin; MII != MIE; --MII) { @@ -194,6 +239,8 @@ void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) { "Cannot schedule terminators or labels!"); // Create the SUnit for this MI. SUnit *SU = NewSUnit(MI); + SU->isCall = TID.isCall(); + SU->isCommutable = TID.isCommutable(); // Assign the Latency field of SU using target-provided information. if (UnitLatencies) @@ -228,6 +275,8 @@ void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) { unsigned AOLatency = (Kind == SDep::Anti) ? 0 : 1; for (unsigned i = 0, e = DefList.size(); i != e; ++i) { SUnit *DefSU = DefList[i]; + if (DefSU == &ExitSU) + continue; if (DefSU != SU && (Kind != SDep::Output || !MO.isDead() || !DefSU->getInstr()->registerDefIsDead(Reg))) @@ -237,6 +286,8 @@ void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) { std::vector &DefList = Defs[*Alias]; for (unsigned i = 0, e = DefList.size(); i != e; ++i) { SUnit *DefSU = DefList[i]; + if (DefSU == &ExitSU) + continue; if (DefSU != SU && (Kind != SDep::Output || !MO.isDead() || !DefSU->getInstr()->registerDefIsDead(*Alias))) @@ -258,12 +309,14 @@ void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) { // TODO: Perhaps we should get rid of // SpecialAddressLatency and just move this into // adjustSchedDependency for the targets that care about it. - if (SpecialAddressLatency != 0 && !UnitLatencies) { + if (SpecialAddressLatency != 0 && !UnitLatencies && + UseSU != &ExitSU) { MachineInstr *UseMI = UseSU->getInstr(); const TargetInstrDesc &UseTID = UseMI->getDesc(); int RegUseIndex = UseMI->findRegisterUseOperandIdx(Reg); assert(RegUseIndex >= 0 && "UseMI doesn's use register!"); - if ((UseTID.mayLoad() || UseTID.mayStore()) && + if (RegUseIndex >= 0 && + (UseTID.mayLoad() || UseTID.mayStore()) && (unsigned)RegUseIndex < UseTID.getNumOperands() && UseTID.OpInfo[RegUseIndex].isLookupPtrRegClass()) LDataLatency += SpecialAddressLatency; @@ -357,7 +410,7 @@ void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) { // produce more precise dependence information. #define STORE_LOAD_LATENCY 1 unsigned TrueMemOrderLatency = 0; - if (TID.isCall() || TID.hasUnmodeledSideEffects() || + if (TID.isCall() || MI->hasUnmodeledSideEffects() || (MI->hasVolatileMemoryRef() && (!TID.mayLoad() || !MI->isInvariantLoad(AA)))) { // Be conservative with these and add dependencies on all memory @@ -446,6 +499,14 @@ void ScheduleDAGInstrs::BuildSchedGraph(AliasAnalysis *AA) { // Treat all other stores conservatively. goto new_alias_chain; } + + if (!ExitSU.isPred(SU)) + // Push store's up a bit to avoid them getting in between cmp + // and branches. + ExitSU.addPred(SDep(SU, SDep::Order, 0, + /*Reg=*/0, /*isNormalMemory=*/false, + /*isMustAlias=*/false, + /*isArtificial=*/true)); } else if (TID.mayLoad()) { bool MayAlias = true; TrueMemOrderLatency = 0; @@ -498,23 +559,22 @@ void ScheduleDAGInstrs::FinishBlock() { } void ScheduleDAGInstrs::ComputeLatency(SUnit *SU) { - const InstrItineraryData &InstrItins = TM.getInstrItineraryData(); - // Compute the latency for the node. - SU->Latency = - InstrItins.getStageLatency(SU->getInstr()->getDesc().getSchedClass()); + if (!InstrItins || InstrItins->isEmpty()) { + SU->Latency = 1; - // Simplistic target-independent heuristic: assume that loads take - // extra time. - if (InstrItins.isEmpty()) + // Simplistic target-independent heuristic: assume that loads take + // extra time. if (SU->getInstr()->getDesc().mayLoad()) SU->Latency += 2; + } else { + SU->Latency = TII->getInstrLatency(InstrItins, SU->getInstr()); + } } void ScheduleDAGInstrs::ComputeOperandLatency(SUnit *Def, SUnit *Use, SDep& dep) const { - const InstrItineraryData &InstrItins = TM.getInstrItineraryData(); - if (InstrItins.isEmpty()) + if (!InstrItins || InstrItins->isEmpty()) return; // For a data dependency with a known register... @@ -528,14 +588,21 @@ void ScheduleDAGInstrs::ComputeOperandLatency(SUnit *Def, SUnit *Use, MachineInstr *DefMI = Def->getInstr(); int DefIdx = DefMI->findRegisterDefOperandIdx(Reg); if (DefIdx != -1) { - int DefCycle = InstrItins.getOperandCycle(DefMI->getDesc().getSchedClass(), - DefIdx); - if (DefCycle >= 0) { - MachineInstr *UseMI = Use->getInstr(); - const unsigned UseClass = UseMI->getDesc().getSchedClass(); - - // For all uses of the register, calculate the maxmimum latency - int Latency = -1; + const MachineOperand &MO = DefMI->getOperand(DefIdx); + if (MO.isReg() && MO.isImplicit() && + DefIdx >= (int)DefMI->getDesc().getNumOperands()) { + // This is an implicit def, getOperandLatency() won't return the correct + // latency. e.g. + // %D6, %D7 = VLD1q16 %R2, 0, ..., %Q3 + // %Q1 = VMULv8i16 %Q1, %Q3, ... + // What we want is to compute latency between def of %D6/%D7 and use of + // %Q3 instead. + DefIdx = DefMI->findRegisterDefOperandIdx(Reg, false, true, TRI); + } + MachineInstr *UseMI = Use->getInstr(); + // For all uses of the register, calculate the maxmimum latency + int Latency = -1; + if (UseMI) { for (unsigned i = 0, e = UseMI->getNumOperands(); i != e; ++i) { const MachineOperand &MO = UseMI->getOperand(i); if (!MO.isReg() || !MO.isUse()) @@ -544,15 +611,21 @@ void ScheduleDAGInstrs::ComputeOperandLatency(SUnit *Def, SUnit *Use, if (MOReg != Reg) continue; - int UseCycle = InstrItins.getOperandCycle(UseClass, i); - if (UseCycle >= 0) - Latency = std::max(Latency, DefCycle - UseCycle + 1); + int UseCycle = TII->getOperandLatency(InstrItins, DefMI, DefIdx, + UseMI, i); + Latency = std::max(Latency, UseCycle); } - - // If we found a latency, then replace the existing dependence latency. - if (Latency >= 0) - dep.setLatency(Latency); + } else { + // UseMI is null, then it must be a scheduling barrier. + if (!InstrItins || InstrItins->isEmpty()) + return; + unsigned DefClass = DefMI->getDesc().getSchedClass(); + Latency = InstrItins->getOperandCycle(DefClass, DefIdx); } + + // If we found a latency, then replace the existing dependence latency. + if (Latency >= 0) + dep.setLatency(Latency); } } diff --git a/lib/CodeGen/ScheduleDAGInstrs.h b/lib/CodeGen/ScheduleDAGInstrs.h index c8f543f7146d..c878287d9c8c 100644 --- a/lib/CodeGen/ScheduleDAGInstrs.h +++ b/lib/CodeGen/ScheduleDAGInstrs.h @@ -101,6 +101,7 @@ namespace llvm { const MachineLoopInfo &MLI; const MachineDominatorTree &MDT; const MachineFrameInfo *MFI; + const InstrItineraryData *InstrItins; /// Defs, Uses - Remember where defs and uses of each physical register /// are as we iterate upward through the instructions. This is allocated @@ -163,6 +164,15 @@ namespace llvm { /// input. virtual void BuildSchedGraph(AliasAnalysis *AA); + /// AddSchedBarrierDeps - Add dependencies from instructions in the current + /// list of instructions being scheduled to scheduling barrier. We want to + /// make sure instructions which define registers that are either used by + /// the terminator or are live-out are properly scheduled. This is + /// especially important when the definition latency of the return value(s) + /// are too high to be hidden by the branch or when the liveout registers + /// used by instructions in the fallthrough block. + void AddSchedBarrierDeps(); + /// ComputeLatency - Compute node latency. /// virtual void ComputeLatency(SUnit *SU); diff --git a/lib/CodeGen/ScoreboardHazardRecognizer.cpp b/lib/CodeGen/ScoreboardHazardRecognizer.cpp new file mode 100644 index 000000000000..e6d7ded8a784 --- /dev/null +++ b/lib/CodeGen/ScoreboardHazardRecognizer.cpp @@ -0,0 +1,243 @@ +//===----- ScoreboardHazardRecognizer.cpp - Scheduler Support -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the ScoreboardHazardRecognizer class, which +// encapsultes hazard-avoidance heuristics for scheduling, based on the +// scheduling itineraries specified for the target. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE ::llvm::ScoreboardHazardRecognizer::DebugType +#include "llvm/CodeGen/ScoreboardHazardRecognizer.h" +#include "llvm/CodeGen/ScheduleDAG.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetInstrItineraries.h" + +using namespace llvm; + +#ifndef NDEBUG +const char *ScoreboardHazardRecognizer::DebugType = ""; +#endif + +ScoreboardHazardRecognizer:: +ScoreboardHazardRecognizer(const InstrItineraryData *II, + const ScheduleDAG *SchedDAG, + const char *ParentDebugType) : + ScheduleHazardRecognizer(), ItinData(II), DAG(SchedDAG), IssueWidth(0), + IssueCount(0) { + +#ifndef NDEBUG + DebugType = ParentDebugType; +#endif + + // Determine the maximum depth of any itinerary. This determines the + // depth of the scoreboard. We always make the scoreboard at least 1 + // cycle deep to avoid dealing with the boundary condition. + unsigned ScoreboardDepth = 1; + if (ItinData && !ItinData->isEmpty()) { + IssueWidth = ItinData->IssueWidth; + + for (unsigned idx = 0; ; ++idx) { + if (ItinData->isEndMarker(idx)) + break; + + const InstrStage *IS = ItinData->beginStage(idx); + const InstrStage *E = ItinData->endStage(idx); + unsigned CurCycle = 0; + unsigned ItinDepth = 0; + for (; IS != E; ++IS) { + unsigned StageDepth = CurCycle + IS->getCycles(); + if (ItinDepth < StageDepth) ItinDepth = StageDepth; + CurCycle += IS->getNextCycles(); + } + + // Find the next power-of-2 >= ItinDepth + while (ItinDepth > ScoreboardDepth) { + ScoreboardDepth *= 2; + } + } + MaxLookAhead = ScoreboardDepth; + } + + ReservedScoreboard.reset(ScoreboardDepth); + RequiredScoreboard.reset(ScoreboardDepth); + + DEBUG(dbgs() << "Using scoreboard hazard recognizer: Depth = " + << ScoreboardDepth << '\n'); +} + +void ScoreboardHazardRecognizer::Reset() { + IssueCount = 0; + RequiredScoreboard.reset(); + ReservedScoreboard.reset(); +} + +void ScoreboardHazardRecognizer::Scoreboard::dump() const { + dbgs() << "Scoreboard:\n"; + + unsigned last = Depth - 1; + while ((last > 0) && ((*this)[last] == 0)) + last--; + + for (unsigned i = 0; i <= last; i++) { + unsigned FUs = (*this)[i]; + dbgs() << "\t"; + for (int j = 31; j >= 0; j--) + dbgs() << ((FUs & (1 << j)) ? '1' : '0'); + dbgs() << '\n'; + } +} + +bool ScoreboardHazardRecognizer::atIssueLimit() const { + if (IssueWidth == 0) + return false; + + return IssueCount == IssueWidth; +} + +ScheduleHazardRecognizer::HazardType +ScoreboardHazardRecognizer::getHazardType(SUnit *SU, int Stalls) { + if (!ItinData || ItinData->isEmpty()) + return NoHazard; + + // Note that stalls will be negative for bottom-up scheduling. + int cycle = Stalls; + + // Use the itinerary for the underlying instruction to check for + // free FU's in the scoreboard at the appropriate future cycles. + + const TargetInstrDesc *TID = DAG->getInstrDesc(SU); + if (TID == NULL) { + // Don't check hazards for non-machineinstr Nodes. + return NoHazard; + } + unsigned idx = TID->getSchedClass(); + for (const InstrStage *IS = ItinData->beginStage(idx), + *E = ItinData->endStage(idx); IS != E; ++IS) { + // We must find one of the stage's units free for every cycle the + // stage is occupied. FIXME it would be more accurate to find the + // same unit free in all the cycles. + for (unsigned int i = 0; i < IS->getCycles(); ++i) { + int StageCycle = cycle + (int)i; + if (StageCycle < 0) + continue; + + if (StageCycle >= (int)RequiredScoreboard.getDepth()) { + assert((StageCycle - Stalls) < (int)RequiredScoreboard.getDepth() && + "Scoreboard depth exceeded!"); + // This stage was stalled beyond pipeline depth, so cannot conflict. + break; + } + + unsigned freeUnits = IS->getUnits(); + switch (IS->getReservationKind()) { + default: + assert(0 && "Invalid FU reservation"); + case InstrStage::Required: + // Required FUs conflict with both reserved and required ones + freeUnits &= ~ReservedScoreboard[StageCycle]; + // FALLTHROUGH + case InstrStage::Reserved: + // Reserved FUs can conflict only with required ones. + freeUnits &= ~RequiredScoreboard[StageCycle]; + break; + } + + if (!freeUnits) { + DEBUG(dbgs() << "*** Hazard in cycle " << (cycle + i) << ", "); + DEBUG(dbgs() << "SU(" << SU->NodeNum << "): "); + DEBUG(DAG->dumpNode(SU)); + return Hazard; + } + } + + // Advance the cycle to the next stage. + cycle += IS->getNextCycles(); + } + + return NoHazard; +} + +void ScoreboardHazardRecognizer::EmitInstruction(SUnit *SU) { + if (!ItinData || ItinData->isEmpty()) + return; + + // Use the itinerary for the underlying instruction to reserve FU's + // in the scoreboard at the appropriate future cycles. + const TargetInstrDesc *TID = DAG->getInstrDesc(SU); + assert(TID && "The scheduler must filter non-machineinstrs"); + if (DAG->TII->isZeroCost(TID->Opcode)) + return; + + ++IssueCount; + + unsigned cycle = 0; + + unsigned idx = TID->getSchedClass(); + for (const InstrStage *IS = ItinData->beginStage(idx), + *E = ItinData->endStage(idx); IS != E; ++IS) { + // We must reserve one of the stage's units for every cycle the + // stage is occupied. FIXME it would be more accurate to reserve + // the same unit free in all the cycles. + for (unsigned int i = 0; i < IS->getCycles(); ++i) { + assert(((cycle + i) < RequiredScoreboard.getDepth()) && + "Scoreboard depth exceeded!"); + + unsigned freeUnits = IS->getUnits(); + switch (IS->getReservationKind()) { + default: + assert(0 && "Invalid FU reservation"); + case InstrStage::Required: + // Required FUs conflict with both reserved and required ones + freeUnits &= ~ReservedScoreboard[cycle + i]; + // FALLTHROUGH + case InstrStage::Reserved: + // Reserved FUs can conflict only with required ones. + freeUnits &= ~RequiredScoreboard[cycle + i]; + break; + } + + // reduce to a single unit + unsigned freeUnit = 0; + do { + freeUnit = freeUnits; + freeUnits = freeUnit & (freeUnit - 1); + } while (freeUnits); + + assert(freeUnit && "No function unit available!"); + if (IS->getReservationKind() == InstrStage::Required) + RequiredScoreboard[cycle + i] |= freeUnit; + else + ReservedScoreboard[cycle + i] |= freeUnit; + } + + // Advance the cycle to the next stage. + cycle += IS->getNextCycles(); + } + + DEBUG(ReservedScoreboard.dump()); + DEBUG(RequiredScoreboard.dump()); +} + +void ScoreboardHazardRecognizer::AdvanceCycle() { + IssueCount = 0; + ReservedScoreboard[0] = 0; ReservedScoreboard.advance(); + RequiredScoreboard[0] = 0; RequiredScoreboard.advance(); +} + +void ScoreboardHazardRecognizer::RecedeCycle() { + IssueCount = 0; + ReservedScoreboard[ReservedScoreboard.getDepth()-1] = 0; + ReservedScoreboard.recede(); + RequiredScoreboard[RequiredScoreboard.getDepth()-1] = 0; + RequiredScoreboard.recede(); +} diff --git a/lib/CodeGen/SelectionDAG/CMakeLists.txt b/lib/CodeGen/SelectionDAG/CMakeLists.txt index 799988a4c862..15932c03a190 100644 --- a/lib/CodeGen/SelectionDAG/CMakeLists.txt +++ b/lib/CodeGen/SelectionDAG/CMakeLists.txt @@ -21,5 +21,3 @@ add_llvm_library(LLVMSelectionDAG TargetLowering.cpp TargetSelectionDAGInfo.cpp ) - -target_link_libraries (LLVMSelectionDAG LLVMAnalysis LLVMAsmPrinter LLVMCodeGen) diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index c9c4d91e9736..90356021f602 100644 --- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -25,7 +25,6 @@ #include "llvm/CodeGen/PseudoSourceValue.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Target/TargetData.h" -#include "llvm/Target/TargetFrameInfo.h" #include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" @@ -43,6 +42,7 @@ STATISTIC(NodesCombined , "Number of dag nodes combined"); STATISTIC(PreIndexedNodes , "Number of pre-indexed nodes created"); STATISTIC(PostIndexedNodes, "Number of post-indexed nodes created"); STATISTIC(OpsNarrowed , "Number of load/op/store narrowed"); +STATISTIC(LdStFP2Int , "Number of fp load/store pairs transformed to int"); namespace { static cl::opt @@ -185,7 +185,7 @@ namespace { SDValue visitANY_EXTEND(SDNode *N); SDValue visitSIGN_EXTEND_INREG(SDNode *N); SDValue visitTRUNCATE(SDNode *N); - SDValue visitBIT_CONVERT(SDNode *N); + SDValue visitBITCAST(SDNode *N); SDValue visitBUILD_PAIR(SDNode *N); SDValue visitFADD(SDNode *N); SDValue visitFSUB(SDNode *N); @@ -229,12 +229,13 @@ namespace { SDValue SimplifyNodeWithTwoResults(SDNode *N, unsigned LoOp, unsigned HiOp); SDValue CombineConsecutiveLoads(SDNode *N, EVT VT); - SDValue ConstantFoldBIT_CONVERTofBUILD_VECTOR(SDNode *, EVT); + SDValue ConstantFoldBITCASTofBUILD_VECTOR(SDNode *, EVT); SDValue BuildSDIV(SDNode *N); SDValue BuildUDIV(SDNode *N); SDNode *MatchRotate(SDValue LHS, SDValue RHS, DebugLoc DL); SDValue ReduceLoadWidth(SDNode *N); SDValue ReduceLoadOpStoreWidth(SDNode *N); + SDValue TransformFPLoadStorePair(SDNode *N); SDValue GetDemandedBits(SDValue V, const APInt &Mask); @@ -248,16 +249,19 @@ namespace { bool isAlias(SDValue Ptr1, int64_t Size1, const Value *SrcValue1, int SrcValueOffset1, unsigned SrcValueAlign1, + const MDNode *TBAAInfo1, SDValue Ptr2, int64_t Size2, const Value *SrcValue2, int SrcValueOffset2, - unsigned SrcValueAlign2) const; + unsigned SrcValueAlign2, + const MDNode *TBAAInfo2) const; /// FindAliasInfo - Extracts the relevant alias information from the memory /// node. Returns true if the operand was a load. bool FindAliasInfo(SDNode *N, SDValue &Ptr, int64_t &Size, const Value *&SrcValue, int &SrcValueOffset, - unsigned &SrcValueAlignment) const; + unsigned &SrcValueAlignment, + const MDNode *&TBAAInfo) const; /// FindBetterChain - Walk up chain skipping non-aliasing memory nodes, /// looking for a better chain (aliasing node.) @@ -270,15 +274,15 @@ namespace { /// Run - runs the dag combiner on all nodes in the work list void Run(CombineLevel AtLevel); - + SelectionDAG &getDAG() const { return DAG; } - + /// getShiftAmountTy - Returns a type large enough to hold any valid /// shift amount - before type legalization these can be huge. EVT getShiftAmountTy() { return LegalTypes ? TLI.getShiftAmountTy() : TLI.getPointerTy(); } - + /// isTypeLegal - This method returns true if we are running before type /// legalization or if the specified VT is legal. bool isTypeLegal(const EVT &VT) { @@ -631,7 +635,7 @@ bool DAGCombiner::SimplifyDemandedBits(SDValue Op, const APInt &Demanded) { // Replace the old value with the new one. ++NodesCombined; - DEBUG(dbgs() << "\nReplacing.2 "; + DEBUG(dbgs() << "\nReplacing.2 "; TLO.Old.getNode()->dump(&DAG); dbgs() << "\nWith: "; TLO.New.getNode()->dump(&DAG); @@ -666,12 +670,13 @@ SDValue DAGCombiner::PromoteOperand(SDValue Op, EVT PVT, bool &Replace) { if (LoadSDNode *LD = dyn_cast(Op)) { EVT MemVT = LD->getMemoryVT(); ISD::LoadExtType ExtType = ISD::isNON_EXTLoad(LD) - ? (TLI.isLoadExtLegal(ISD::ZEXTLOAD, MemVT) ? ISD::ZEXTLOAD : ISD::EXTLOAD) + ? (TLI.isLoadExtLegal(ISD::ZEXTLOAD, MemVT) ? ISD::ZEXTLOAD + : ISD::EXTLOAD) : LD->getExtensionType(); Replace = true; - return DAG.getExtLoad(ExtType, PVT, dl, + return DAG.getExtLoad(ExtType, dl, PVT, LD->getChain(), LD->getBasePtr(), - LD->getSrcValue(), LD->getSrcValueOffset(), + LD->getPointerInfo(), MemVT, LD->isVolatile(), LD->isNonTemporal(), LD->getAlignment()); } @@ -691,7 +696,7 @@ SDValue DAGCombiner::PromoteOperand(SDValue Op, EVT PVT, bool &Replace) { unsigned ExtOpc = Op.getValueType().isByteSized() ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND; return DAG.getNode(ExtOpc, dl, PVT, Op); - } + } } if (!TLI.isOperationLegal(ISD::ANY_EXTEND, PVT)) @@ -889,11 +894,12 @@ bool DAGCombiner::PromoteLoad(SDValue Op) { LoadSDNode *LD = cast(N); EVT MemVT = LD->getMemoryVT(); ISD::LoadExtType ExtType = ISD::isNON_EXTLoad(LD) - ? (TLI.isLoadExtLegal(ISD::ZEXTLOAD, MemVT) ? ISD::ZEXTLOAD : ISD::EXTLOAD) + ? (TLI.isLoadExtLegal(ISD::ZEXTLOAD, MemVT) ? ISD::ZEXTLOAD + : ISD::EXTLOAD) : LD->getExtensionType(); - SDValue NewLD = DAG.getExtLoad(ExtType, PVT, dl, + SDValue NewLD = DAG.getExtLoad(ExtType, dl, PVT, LD->getChain(), LD->getBasePtr(), - LD->getSrcValue(), LD->getSrcValueOffset(), + LD->getPointerInfo(), MemVT, LD->isVolatile(), LD->isNonTemporal(), LD->getAlignment()); SDValue Result = DAG.getNode(ISD::TRUNCATE, dl, VT, NewLD); @@ -975,7 +981,7 @@ void DAGCombiner::Run(CombineLevel AtLevel) { RV.getNode()->getOpcode() != ISD::DELETED_NODE && "Node was deleted but visit returned new node!"); - DEBUG(dbgs() << "\nReplacing.3 "; + DEBUG(dbgs() << "\nReplacing.3 "; N->dump(&DAG); dbgs() << "\nWith: "; RV.getNode()->dump(&DAG); @@ -1054,7 +1060,7 @@ SDValue DAGCombiner::visit(SDNode *N) { case ISD::ANY_EXTEND: return visitANY_EXTEND(N); case ISD::SIGN_EXTEND_INREG: return visitSIGN_EXTEND_INREG(N); case ISD::TRUNCATE: return visitTRUNCATE(N); - case ISD::BIT_CONVERT: return visitBIT_CONVERT(N); + case ISD::BITCAST: return visitBITCAST(N); case ISD::BUILD_PAIR: return visitBUILD_PAIR(N); case ISD::FADD: return visitFADD(N); case ISD::FSUB: return visitFSUB(N); @@ -1225,7 +1231,7 @@ SDValue DAGCombiner::visitTokenFactor(SDNode *N) { } } } - + SDValue Result; // If we've change things around then replace token factor. @@ -1424,6 +1430,29 @@ SDValue DAGCombiner::visitADD(SDNode *N) { N0.getOperand(0).getOperand(1), N0.getOperand(1))); + if (N1.getOpcode() == ISD::AND) { + SDValue AndOp0 = N1.getOperand(0); + ConstantSDNode *AndOp1 = dyn_cast(N1->getOperand(1)); + unsigned NumSignBits = DAG.ComputeNumSignBits(AndOp0); + unsigned DestBits = VT.getScalarType().getSizeInBits(); + + // (add z, (and (sbbl x, x), 1)) -> (sub z, (sbbl x, x)) + // and similar xforms where the inner op is either ~0 or 0. + if (NumSignBits == DestBits && AndOp1 && AndOp1->isOne()) { + DebugLoc DL = N->getDebugLoc(); + return DAG.getNode(ISD::SUB, DL, VT, N->getOperand(0), AndOp0); + } + } + + // add (sext i1), X -> sub X, (zext i1) + if (N0.getOpcode() == ISD::SIGN_EXTEND && + N0.getOperand(0).getValueType() == MVT::i1 && + !TLI.isOperationLegal(ISD::SIGN_EXTEND, MVT::i1)) { + DebugLoc DL = N->getDebugLoc(); + SDValue ZExt = DAG.getNode(ISD::ZERO_EXTEND, DL, VT, N0.getOperand(0)); + return DAG.getNode(ISD::SUB, DL, VT, N1, ZExt); + } + return SDValue(); } @@ -1438,7 +1467,7 @@ SDValue DAGCombiner::visitADDC(SDNode *N) { if (N->hasNUsesOfValue(0, 1)) return CombineTo(N, DAG.getNode(ISD::ADD, N->getDebugLoc(), VT, N1, N0), DAG.getNode(ISD::CARRY_FALSE, - N->getDebugLoc(), MVT::Flag)); + N->getDebugLoc(), MVT::Glue)); // canonicalize constant to RHS. if (N0C && !N1C) @@ -1447,7 +1476,7 @@ SDValue DAGCombiner::visitADDC(SDNode *N) { // fold (addc x, 0) -> x + no carry out if (N1C && N1C->isNullValue()) return CombineTo(N, N0, DAG.getNode(ISD::CARRY_FALSE, - N->getDebugLoc(), MVT::Flag)); + N->getDebugLoc(), MVT::Glue)); // fold (addc a, b) -> (or a, b), CARRY_FALSE iff a and b share no bits. APInt LHSZero, LHSOne; @@ -1464,7 +1493,7 @@ SDValue DAGCombiner::visitADDC(SDNode *N) { (LHSZero & (~RHSZero & Mask)) == (~RHSZero & Mask)) return CombineTo(N, DAG.getNode(ISD::OR, N->getDebugLoc(), VT, N0, N1), DAG.getNode(ISD::CARRY_FALSE, - N->getDebugLoc(), MVT::Flag)); + N->getDebugLoc(), MVT::Glue)); } return SDValue(); @@ -1489,6 +1518,22 @@ SDValue DAGCombiner::visitADDE(SDNode *N) { return SDValue(); } +// Since it may not be valid to emit a fold to zero for vector initializers +// check if we can before folding. +static SDValue tryFoldToZero(DebugLoc DL, const TargetLowering &TLI, EVT VT, + SelectionDAG &DAG, bool LegalOperations) { + if (!VT.isVector()) { + return DAG.getConstant(0, VT); + } else if (!LegalOperations || TLI.isOperationLegal(ISD::BUILD_VECTOR, VT)) { + // Produce a vector of zeros. + SDValue El = DAG.getConstant(0, VT.getVectorElementType()); + std::vector Ops(VT.getVectorNumElements(), El); + return DAG.getNode(ISD::BUILD_VECTOR, DL, VT, + &Ops[0], Ops.size()); + } + return SDValue(); +} + SDValue DAGCombiner::visitSUB(SDNode *N) { SDValue N0 = N->getOperand(0); SDValue N1 = N->getOperand(1); @@ -1503,8 +1548,9 @@ SDValue DAGCombiner::visitSUB(SDNode *N) { } // fold (sub x, x) -> 0 + // FIXME: Refactor this and xor and other similar operations together. if (N0 == N1) - return DAG.getConstant(0, N->getValueType(0)); + return tryFoldToZero(N->getDebugLoc(), TLI, VT, DAG, LegalOperations); // fold (sub c1, c2) -> c1-c2 if (N0C && N1C) return DAG.FoldConstantArithmetic(ISD::SUB, VT, N0C, N1C); @@ -1515,6 +1561,9 @@ SDValue DAGCombiner::visitSUB(SDNode *N) { // Canonicalize (sub -1, x) -> ~x, i.e. (xor x, -1) if (N0C && N0C->isAllOnesValue()) return DAG.getNode(ISD::XOR, N->getDebugLoc(), VT, N1, N0); + // fold A-(A-B) -> B + if (N1.getOpcode() == ISD::SUB && N0 == N1.getOperand(0)) + return N1.getOperand(1); // fold (A+B)-A -> B if (N0.getOpcode() == ISD::ADD && N0.getOperand(0) == N1) return N0.getOperand(1); @@ -1897,6 +1946,7 @@ SDValue DAGCombiner::visitMULHS(SDNode *N) { SDValue N1 = N->getOperand(1); ConstantSDNode *N1C = dyn_cast(N1); EVT VT = N->getValueType(0); + DebugLoc DL = N->getDebugLoc(); // fold (mulhs x, 0) -> 0 if (N1C && N1C->isNullValue()) @@ -1910,6 +1960,22 @@ SDValue DAGCombiner::visitMULHS(SDNode *N) { if (N0.getOpcode() == ISD::UNDEF || N1.getOpcode() == ISD::UNDEF) return DAG.getConstant(0, VT); + // If the type twice as wide is legal, transform the mulhs to a wider multiply + // plus a shift. + if (VT.isSimple() && !VT.isVector()) { + MVT Simple = VT.getSimpleVT(); + unsigned SimpleSize = Simple.getSizeInBits(); + EVT NewVT = EVT::getIntegerVT(*DAG.getContext(), SimpleSize*2); + if (TLI.isOperationLegal(ISD::MUL, NewVT)) { + N0 = DAG.getNode(ISD::SIGN_EXTEND, DL, NewVT, N0); + N1 = DAG.getNode(ISD::SIGN_EXTEND, DL, NewVT, N1); + N1 = DAG.getNode(ISD::MUL, DL, NewVT, N0, N1); + N1 = DAG.getNode(ISD::SRL, DL, NewVT, N1, + DAG.getConstant(SimpleSize, getShiftAmountTy())); + return DAG.getNode(ISD::TRUNCATE, DL, VT, N1); + } + } + return SDValue(); } @@ -1918,6 +1984,7 @@ SDValue DAGCombiner::visitMULHU(SDNode *N) { SDValue N1 = N->getOperand(1); ConstantSDNode *N1C = dyn_cast(N1); EVT VT = N->getValueType(0); + DebugLoc DL = N->getDebugLoc(); // fold (mulhu x, 0) -> 0 if (N1C && N1C->isNullValue()) @@ -1929,6 +1996,22 @@ SDValue DAGCombiner::visitMULHU(SDNode *N) { if (N0.getOpcode() == ISD::UNDEF || N1.getOpcode() == ISD::UNDEF) return DAG.getConstant(0, VT); + // If the type twice as wide is legal, transform the mulhu to a wider multiply + // plus a shift. + if (VT.isSimple() && !VT.isVector()) { + MVT Simple = VT.getSimpleVT(); + unsigned SimpleSize = Simple.getSizeInBits(); + EVT NewVT = EVT::getIntegerVT(*DAG.getContext(), SimpleSize*2); + if (TLI.isOperationLegal(ISD::MUL, NewVT)) { + N0 = DAG.getNode(ISD::ZERO_EXTEND, DL, NewVT, N0); + N1 = DAG.getNode(ISD::ZERO_EXTEND, DL, NewVT, N1); + N1 = DAG.getNode(ISD::MUL, DL, NewVT, N0, N1); + N1 = DAG.getNode(ISD::SRL, DL, NewVT, N1, + DAG.getConstant(SimpleSize, getShiftAmountTy())); + return DAG.getNode(ISD::TRUNCATE, DL, VT, N1); + } + } + return SDValue(); } @@ -1992,6 +2075,29 @@ SDValue DAGCombiner::visitSMUL_LOHI(SDNode *N) { SDValue Res = SimplifyNodeWithTwoResults(N, ISD::MUL, ISD::MULHS); if (Res.getNode()) return Res; + EVT VT = N->getValueType(0); + DebugLoc DL = N->getDebugLoc(); + + // If the type twice as wide is legal, transform the mulhu to a wider multiply + // plus a shift. + if (VT.isSimple() && !VT.isVector()) { + MVT Simple = VT.getSimpleVT(); + unsigned SimpleSize = Simple.getSizeInBits(); + EVT NewVT = EVT::getIntegerVT(*DAG.getContext(), SimpleSize*2); + if (TLI.isOperationLegal(ISD::MUL, NewVT)) { + SDValue Lo = DAG.getNode(ISD::SIGN_EXTEND, DL, NewVT, N->getOperand(0)); + SDValue Hi = DAG.getNode(ISD::SIGN_EXTEND, DL, NewVT, N->getOperand(1)); + Lo = DAG.getNode(ISD::MUL, DL, NewVT, Lo, Hi); + // Compute the high part as N1. + Hi = DAG.getNode(ISD::SRL, DL, NewVT, Lo, + DAG.getConstant(SimpleSize, getShiftAmountTy())); + Hi = DAG.getNode(ISD::TRUNCATE, DL, VT, Hi); + // Compute the low part as N0. + Lo = DAG.getNode(ISD::TRUNCATE, DL, VT, Lo); + return CombineTo(N, Lo, Hi); + } + } + return SDValue(); } @@ -1999,6 +2105,29 @@ SDValue DAGCombiner::visitUMUL_LOHI(SDNode *N) { SDValue Res = SimplifyNodeWithTwoResults(N, ISD::MUL, ISD::MULHU); if (Res.getNode()) return Res; + EVT VT = N->getValueType(0); + DebugLoc DL = N->getDebugLoc(); + + // If the type twice as wide is legal, transform the mulhu to a wider multiply + // plus a shift. + if (VT.isSimple() && !VT.isVector()) { + MVT Simple = VT.getSimpleVT(); + unsigned SimpleSize = Simple.getSizeInBits(); + EVT NewVT = EVT::getIntegerVT(*DAG.getContext(), SimpleSize*2); + if (TLI.isOperationLegal(ISD::MUL, NewVT)) { + SDValue Lo = DAG.getNode(ISD::ZERO_EXTEND, DL, NewVT, N->getOperand(0)); + SDValue Hi = DAG.getNode(ISD::ZERO_EXTEND, DL, NewVT, N->getOperand(1)); + Lo = DAG.getNode(ISD::MUL, DL, NewVT, Lo, Hi); + // Compute the high part as N1. + Hi = DAG.getNode(ISD::SRL, DL, NewVT, Lo, + DAG.getConstant(SimpleSize, getShiftAmountTy())); + Hi = DAG.getNode(ISD::TRUNCATE, DL, VT, Hi); + // Compute the low part as N0. + Lo = DAG.getNode(ISD::TRUNCATE, DL, VT, Lo); + return CombineTo(N, Lo, Hi); + } + } + return SDValue(); } @@ -2116,7 +2245,7 @@ SDValue DAGCombiner::visitAND(SDNode *N) { if (N1C && N0.getOpcode() == ISD::ANY_EXTEND) { SDValue N0Op0 = N0.getOperand(0); APInt Mask = ~N1C->getAPIntValue(); - Mask.trunc(N0Op0.getValueSizeInBits()); + Mask = Mask.trunc(N0Op0.getValueSizeInBits()); if (DAG.MaskedValueIsZero(N0Op0, Mask)) { SDValue Zext = DAG.getNode(ISD::ZERO_EXTEND, N->getDebugLoc(), N0.getValueType(), N0Op0); @@ -2198,10 +2327,9 @@ SDValue DAGCombiner::visitAND(SDNode *N) { BitWidth - MemVT.getScalarType().getSizeInBits())) && ((!LegalOperations && !LN0->isVolatile()) || TLI.isLoadExtLegal(ISD::ZEXTLOAD, MemVT))) { - SDValue ExtLoad = DAG.getExtLoad(ISD::ZEXTLOAD, VT, N0.getDebugLoc(), + SDValue ExtLoad = DAG.getExtLoad(ISD::ZEXTLOAD, N0.getDebugLoc(), VT, LN0->getChain(), LN0->getBasePtr(), - LN0->getSrcValue(), - LN0->getSrcValueOffset(), MemVT, + LN0->getPointerInfo(), MemVT, LN0->isVolatile(), LN0->isNonTemporal(), LN0->getAlignment()); AddToWorkList(N); @@ -2221,10 +2349,10 @@ SDValue DAGCombiner::visitAND(SDNode *N) { BitWidth - MemVT.getScalarType().getSizeInBits())) && ((!LegalOperations && !LN0->isVolatile()) || TLI.isLoadExtLegal(ISD::ZEXTLOAD, MemVT))) { - SDValue ExtLoad = DAG.getExtLoad(ISD::ZEXTLOAD, VT, N0.getDebugLoc(), + SDValue ExtLoad = DAG.getExtLoad(ISD::ZEXTLOAD, N0.getDebugLoc(), VT, LN0->getChain(), - LN0->getBasePtr(), LN0->getSrcValue(), - LN0->getSrcValueOffset(), MemVT, + LN0->getBasePtr(), LN0->getPointerInfo(), + MemVT, LN0->isVolatile(), LN0->isNonTemporal(), LN0->getAlignment()); AddToWorkList(N); @@ -2253,18 +2381,18 @@ SDValue DAGCombiner::visitAND(SDNode *N) { if (ExtVT == LoadedVT && (!LegalOperations || TLI.isLoadExtLegal(ISD::ZEXTLOAD, ExtVT))) { EVT LoadResultTy = HasAnyExt ? LN0->getValueType(0) : VT; - - SDValue NewLoad = - DAG.getExtLoad(ISD::ZEXTLOAD, LoadResultTy, LN0->getDebugLoc(), + + SDValue NewLoad = + DAG.getExtLoad(ISD::ZEXTLOAD, LN0->getDebugLoc(), LoadResultTy, LN0->getChain(), LN0->getBasePtr(), - LN0->getSrcValue(), LN0->getSrcValueOffset(), + LN0->getPointerInfo(), ExtVT, LN0->isVolatile(), LN0->isNonTemporal(), LN0->getAlignment()); AddToWorkList(N); CombineTo(LN0, NewLoad, NewLoad.getValue(1)); return SDValue(N, 0); // Return N so it doesn't get rechecked! } - + // Do not change the width of a volatile load. // Do not generate loads of non-round integer types since these can // be expensive (and would be wrong if the type is not byte sized). @@ -2288,12 +2416,12 @@ SDValue DAGCombiner::visitAND(SDNode *N) { } AddToWorkList(NewPtr.getNode()); - + EVT LoadResultTy = HasAnyExt ? LN0->getValueType(0) : VT; SDValue Load = - DAG.getExtLoad(ISD::ZEXTLOAD, LoadResultTy, LN0->getDebugLoc(), + DAG.getExtLoad(ISD::ZEXTLOAD, LN0->getDebugLoc(), LoadResultTy, LN0->getChain(), NewPtr, - LN0->getSrcValue(), LN0->getSrcValueOffset(), + LN0->getPointerInfo(), ExtVT, LN0->isVolatile(), LN0->isNonTemporal(), Alignment); AddToWorkList(N); @@ -2722,17 +2850,8 @@ SDValue DAGCombiner::visitXOR(SDNode *N) { N01C->getAPIntValue(), VT)); } // fold (xor x, x) -> 0 - if (N0 == N1) { - if (!VT.isVector()) { - return DAG.getConstant(0, VT); - } else if (!LegalOperations || TLI.isOperationLegal(ISD::BUILD_VECTOR, VT)){ - // Produce a vector of zeros. - SDValue El = DAG.getConstant(0, VT.getVectorElementType()); - std::vector Ops(VT.getVectorNumElements(), El); - return DAG.getNode(ISD::BUILD_VECTOR, N->getDebugLoc(), VT, - &Ops[0], Ops.size()); - } - } + if (N0 == N1) + return tryFoldToZero(N->getDebugLoc(), TLI, VT, DAG, LegalOperations); // Simplify: xor (op x...), (op y...) -> (op (xor x, y)) if (N0.getOpcode() == N1.getOpcode()) { @@ -2810,7 +2929,8 @@ SDValue DAGCombiner::visitShiftByConstant(SDNode *N, unsigned Amt) { LHS->getOperand(1), N->getOperand(1)); // Create the new shift. - SDValue NewShift = DAG.getNode(N->getOpcode(), LHS->getOperand(0).getDebugLoc(), + SDValue NewShift = DAG.getNode(N->getOpcode(), + LHS->getOperand(0).getDebugLoc(), VT, LHS->getOperand(0), N->getOperand(1)); // Create the new binop. @@ -2850,7 +2970,7 @@ SDValue DAGCombiner::visitSHL(SDNode *N) { EVT TruncVT = N1.getValueType(); SDValue N100 = N1.getOperand(0).getOperand(0); APInt TruncC = N101C->getAPIntValue(); - TruncC.trunc(TruncVT.getSizeInBits()); + TruncC = TruncC.trunc(TruncVT.getSizeInBits()); return DAG.getNode(ISD::SHL, N->getDebugLoc(), VT, N0, DAG.getNode(ISD::AND, N->getDebugLoc(), TruncVT, DAG.getNode(ISD::TRUNCATE, @@ -2868,11 +2988,37 @@ SDValue DAGCombiner::visitSHL(SDNode *N) { N0.getOperand(1).getOpcode() == ISD::Constant) { uint64_t c1 = cast(N0.getOperand(1))->getZExtValue(); uint64_t c2 = N1C->getZExtValue(); - if (c1 + c2 > OpSizeInBits) + if (c1 + c2 >= OpSizeInBits) return DAG.getConstant(0, VT); return DAG.getNode(ISD::SHL, N->getDebugLoc(), VT, N0.getOperand(0), DAG.getConstant(c1 + c2, N1.getValueType())); } + + // fold (shl (ext (shl x, c1)), c2) -> (ext (shl x, (add c1, c2))) + // For this to be valid, the second form must not preserve any of the bits + // that are shifted out by the inner shift in the first form. This means + // the outer shift size must be >= the number of bits added by the ext. + // As a corollary, we don't care what kind of ext it is. + if (N1C && (N0.getOpcode() == ISD::ZERO_EXTEND || + N0.getOpcode() == ISD::ANY_EXTEND || + N0.getOpcode() == ISD::SIGN_EXTEND) && + N0.getOperand(0).getOpcode() == ISD::SHL && + isa(N0.getOperand(0)->getOperand(1))) { + uint64_t c1 = + cast(N0.getOperand(0)->getOperand(1))->getZExtValue(); + uint64_t c2 = N1C->getZExtValue(); + EVT InnerShiftVT = N0.getOperand(0).getValueType(); + uint64_t InnerShiftSize = InnerShiftVT.getScalarType().getSizeInBits(); + if (c2 >= OpSizeInBits - InnerShiftSize) { + if (c1 + c2 >= OpSizeInBits) + return DAG.getConstant(0, VT); + return DAG.getNode(ISD::SHL, N0->getDebugLoc(), VT, + DAG.getNode(N0.getOpcode(), N0->getDebugLoc(), VT, + N0.getOperand(0)->getOperand(0)), + DAG.getConstant(c1 + c2, N1.getValueType())); + } + } + // fold (shl (srl x, c1), c2) -> (shl (and x, (shl -1, c1)), (sub c2, c1)) or // (srl (and x, (shl -1, c1)), (sub c1, c2)) if (N1C && N0.getOpcode() == ISD::SRL && @@ -2973,7 +3119,8 @@ SDValue DAGCombiner::visitSRA(SDNode *N) { if (N01C && N1C) { // Determine what the truncate's result bitsize and type would be. EVT TruncVT = - EVT::getIntegerVT(*DAG.getContext(), OpSizeInBits - N1C->getZExtValue()); + EVT::getIntegerVT(*DAG.getContext(), + OpSizeInBits - N1C->getZExtValue()); // Determine the residual right-shift amount. signed ShiftAmt = N1C->getZExtValue() - N01C->getZExtValue(); @@ -3006,7 +3153,7 @@ SDValue DAGCombiner::visitSRA(SDNode *N) { EVT TruncVT = N1.getValueType(); SDValue N100 = N1.getOperand(0).getOperand(0); APInt TruncC = N101C->getAPIntValue(); - TruncC.trunc(TruncVT.getScalarType().getSizeInBits()); + TruncC = TruncC.trunc(TruncVT.getScalarType().getSizeInBits()); return DAG.getNode(ISD::SRA, N->getDebugLoc(), VT, N0, DAG.getNode(ISD::AND, N->getDebugLoc(), TruncVT, @@ -3017,6 +3164,29 @@ SDValue DAGCombiner::visitSRA(SDNode *N) { } } + // fold (sra (trunc (sr x, c1)), c2) -> (trunc (sra x, c1+c2)) + // if c1 is equal to the number of bits the trunc removes + if (N0.getOpcode() == ISD::TRUNCATE && + (N0.getOperand(0).getOpcode() == ISD::SRL || + N0.getOperand(0).getOpcode() == ISD::SRA) && + N0.getOperand(0).hasOneUse() && + N0.getOperand(0).getOperand(1).hasOneUse() && + N1C && isa(N0.getOperand(0).getOperand(1))) { + EVT LargeVT = N0.getOperand(0).getValueType(); + ConstantSDNode *LargeShiftAmt = + cast(N0.getOperand(0).getOperand(1)); + + if (LargeVT.getScalarType().getSizeInBits() - OpSizeInBits == + LargeShiftAmt->getZExtValue()) { + SDValue Amt = + DAG.getConstant(LargeShiftAmt->getZExtValue() + N1C->getZExtValue(), + getShiftAmountTy()); + SDValue SRA = DAG.getNode(ISD::SRA, N->getDebugLoc(), LargeVT, + N0.getOperand(0).getOperand(0), Amt); + return DAG.getNode(ISD::TRUNCATE, N->getDebugLoc(), VT, SRA); + } + } + // Simplify, based on bits shifted out of the LHS. if (N1C && SimplifyDemandedBits(SDValue(N, 0))) return SDValue(N, 0); @@ -3065,12 +3235,33 @@ SDValue DAGCombiner::visitSRL(SDNode *N) { N0.getOperand(1).getOpcode() == ISD::Constant) { uint64_t c1 = cast(N0.getOperand(1))->getZExtValue(); uint64_t c2 = N1C->getZExtValue(); - if (c1 + c2 > OpSizeInBits) + if (c1 + c2 >= OpSizeInBits) return DAG.getConstant(0, VT); return DAG.getNode(ISD::SRL, N->getDebugLoc(), VT, N0.getOperand(0), DAG.getConstant(c1 + c2, N1.getValueType())); } - + + // fold (srl (trunc (srl x, c1)), c2) -> 0 or (trunc (srl x, (add c1, c2))) + if (N1C && N0.getOpcode() == ISD::TRUNCATE && + N0.getOperand(0).getOpcode() == ISD::SRL && + isa(N0.getOperand(0)->getOperand(1))) { + uint64_t c1 = + cast(N0.getOperand(0)->getOperand(1))->getZExtValue(); + uint64_t c2 = N1C->getZExtValue(); + EVT InnerShiftVT = N0.getOperand(0).getValueType(); + EVT ShiftCountVT = N0.getOperand(0)->getOperand(1).getValueType(); + uint64_t InnerShiftSize = InnerShiftVT.getScalarType().getSizeInBits(); + // This is only valid if the OpSizeInBits + c1 = size of inner shift. + if (c1 + OpSizeInBits == InnerShiftSize) { + if (c1 + c2 >= InnerShiftSize) + return DAG.getConstant(0, VT); + return DAG.getNode(ISD::TRUNCATE, N0->getDebugLoc(), VT, + DAG.getNode(ISD::SRL, N0->getDebugLoc(), InnerShiftVT, + N0.getOperand(0)->getOperand(0), + DAG.getConstant(c1 + c2, ShiftCountVT))); + } + } + // fold (srl (shl x, c), c) -> (and x, cst2) if (N1C && N0.getOpcode() == ISD::SHL && N0.getOperand(1) == N1 && N0.getValueSizeInBits() <= 64) { @@ -3078,7 +3269,7 @@ SDValue DAGCombiner::visitSRL(SDNode *N) { return DAG.getNode(ISD::AND, N->getDebugLoc(), VT, N0.getOperand(0), DAG.getConstant(~0ULL >> ShAmt, VT)); } - + // fold (srl (anyextend x), c) -> (anyextend (srl x, c)) if (N1C && N0.getOpcode() == ISD::ANY_EXTEND) { @@ -3147,7 +3338,7 @@ SDValue DAGCombiner::visitSRL(SDNode *N) { EVT TruncVT = N1.getValueType(); SDValue N100 = N1.getOperand(0).getOperand(0); APInt TruncC = N101C->getAPIntValue(); - TruncC.trunc(TruncVT.getSizeInBits()); + TruncC = TruncC.trunc(TruncVT.getSizeInBits()); return DAG.getNode(ISD::SRL, N->getDebugLoc(), VT, N0, DAG.getNode(ISD::AND, N->getDebugLoc(), TruncVT, @@ -3182,7 +3373,7 @@ SDValue DAGCombiner::visitSRL(SDNode *N) { // brcond i32 %c ... // // into - // + // // %a = ... // %b = and %a, 2 // %c = setcc eq %b, 0 @@ -3422,7 +3613,7 @@ static bool ExtendUsesToFormExtLoad(SDNode *N, SDValue N0, } if (BothLiveOut) // Both unextended and extended values are live out. There had better be - // good a reason for the transformation. + // a good reason for the transformation. return ExtendNodes.size(); } return true; @@ -3503,10 +3694,9 @@ SDValue DAGCombiner::visitSIGN_EXTEND(SDNode *N) { DoXform = ExtendUsesToFormExtLoad(N, N0, ISD::SIGN_EXTEND, SetCCs, TLI); if (DoXform) { LoadSDNode *LN0 = cast(N0); - SDValue ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, VT, N->getDebugLoc(), + SDValue ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, N->getDebugLoc(), VT, LN0->getChain(), - LN0->getBasePtr(), LN0->getSrcValue(), - LN0->getSrcValueOffset(), + LN0->getBasePtr(), LN0->getPointerInfo(), N0.getValueType(), LN0->isVolatile(), LN0->isNonTemporal(), LN0->getAlignment()); @@ -3547,10 +3737,10 @@ SDValue DAGCombiner::visitSIGN_EXTEND(SDNode *N) { EVT MemVT = LN0->getMemoryVT(); if ((!LegalOperations && !LN0->isVolatile()) || TLI.isLoadExtLegal(ISD::SEXTLOAD, MemVT)) { - SDValue ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, VT, N->getDebugLoc(), + SDValue ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, N->getDebugLoc(), VT, LN0->getChain(), - LN0->getBasePtr(), LN0->getSrcValue(), - LN0->getSrcValueOffset(), MemVT, + LN0->getBasePtr(), LN0->getPointerInfo(), + MemVT, LN0->isVolatile(), LN0->isNonTemporal(), LN0->getAlignment()); CombineTo(N, ExtLoad); @@ -3611,7 +3801,7 @@ SDValue DAGCombiner::visitSIGN_EXTEND(SDNode *N) { N0.getOperand(0), N0.getOperand(1), cast(N0.getOperand(2))->get()), NegOne, DAG.getConstant(0, VT)); - } + } // fold (sext x) -> (zext x) if the sign bit is known zero. if ((!LegalOperations || TLI.isOperationLegal(ISD::ZERO_EXTEND, VT)) && @@ -3652,6 +3842,20 @@ SDValue DAGCombiner::visitZERO_EXTEND(SDNode *N) { // fold (zext (truncate x)) -> (and x, mask) if (N0.getOpcode() == ISD::TRUNCATE && (!LegalOperations || TLI.isOperationLegal(ISD::AND, VT))) { + + // fold (zext (truncate (load x))) -> (zext (smaller load x)) + // fold (zext (truncate (srl (load x), c))) -> (zext (smaller load (x+c/n))) + SDValue NarrowLoad = ReduceLoadWidth(N0.getNode()); + if (NarrowLoad.getNode()) { + SDNode* oye = N0.getNode()->getOperand(0).getNode(); + if (NarrowLoad.getNode() != N0.getNode()) { + CombineTo(N0.getNode(), NarrowLoad); + // CombineTo deleted the truncate, if needed, but not what's under it. + AddToWorkList(oye); + } + return SDValue(N, 0); // Return N so it doesn't get rechecked! + } + SDValue Op = N0.getOperand(0); if (Op.getValueType().bitsLT(VT)) { Op = DAG.getNode(ISD::ANY_EXTEND, N->getDebugLoc(), VT, Op); @@ -3677,7 +3881,7 @@ SDValue DAGCombiner::visitZERO_EXTEND(SDNode *N) { X = DAG.getNode(ISD::TRUNCATE, X.getDebugLoc(), VT, X); } APInt Mask = cast(N0.getOperand(1))->getAPIntValue(); - Mask.zext(VT.getSizeInBits()); + Mask = Mask.zext(VT.getSizeInBits()); return DAG.getNode(ISD::AND, N->getDebugLoc(), VT, X, DAG.getConstant(Mask, VT)); } @@ -3692,10 +3896,9 @@ SDValue DAGCombiner::visitZERO_EXTEND(SDNode *N) { DoXform = ExtendUsesToFormExtLoad(N, N0, ISD::ZERO_EXTEND, SetCCs, TLI); if (DoXform) { LoadSDNode *LN0 = cast(N0); - SDValue ExtLoad = DAG.getExtLoad(ISD::ZEXTLOAD, VT, N->getDebugLoc(), + SDValue ExtLoad = DAG.getExtLoad(ISD::ZEXTLOAD, N->getDebugLoc(), VT, LN0->getChain(), - LN0->getBasePtr(), LN0->getSrcValue(), - LN0->getSrcValueOffset(), + LN0->getBasePtr(), LN0->getPointerInfo(), N0.getValueType(), LN0->isVolatile(), LN0->isNonTemporal(), LN0->getAlignment()); @@ -3736,10 +3939,10 @@ SDValue DAGCombiner::visitZERO_EXTEND(SDNode *N) { EVT MemVT = LN0->getMemoryVT(); if ((!LegalOperations && !LN0->isVolatile()) || TLI.isLoadExtLegal(ISD::ZEXTLOAD, MemVT)) { - SDValue ExtLoad = DAG.getExtLoad(ISD::ZEXTLOAD, VT, N->getDebugLoc(), + SDValue ExtLoad = DAG.getExtLoad(ISD::ZEXTLOAD, N->getDebugLoc(), VT, LN0->getChain(), - LN0->getBasePtr(), LN0->getSrcValue(), - LN0->getSrcValueOffset(), MemVT, + LN0->getBasePtr(), LN0->getPointerInfo(), + MemVT, LN0->isVolatile(), LN0->isNonTemporal(), LN0->getAlignment()); CombineTo(N, ExtLoad); @@ -3805,21 +4008,27 @@ SDValue DAGCombiner::visitZERO_EXTEND(SDNode *N) { isa(N0.getOperand(1)) && N0.getOperand(0).getOpcode() == ISD::ZERO_EXTEND && N0.hasOneUse()) { + SDValue ShAmt = N0.getOperand(1); + unsigned ShAmtVal = cast(ShAmt)->getZExtValue(); if (N0.getOpcode() == ISD::SHL) { + SDValue InnerZExt = N0.getOperand(0); // If the original shl may be shifting out bits, do not perform this // transformation. - unsigned ShAmt = cast(N0.getOperand(1))->getZExtValue(); - unsigned KnownZeroBits = N0.getOperand(0).getValueType().getSizeInBits() - - N0.getOperand(0).getOperand(0).getValueType().getSizeInBits(); - if (ShAmt > KnownZeroBits) + unsigned KnownZeroBits = InnerZExt.getValueType().getSizeInBits() - + InnerZExt.getOperand(0).getValueType().getSizeInBits(); + if (ShAmtVal > KnownZeroBits) return SDValue(); } - DebugLoc dl = N->getDebugLoc(); - return DAG.getNode(N0.getOpcode(), dl, VT, - DAG.getNode(ISD::ZERO_EXTEND, dl, VT, N0.getOperand(0)), - DAG.getNode(ISD::ZERO_EXTEND, dl, - N0.getOperand(1).getValueType(), - N0.getOperand(1))); + + DebugLoc DL = N->getDebugLoc(); + + // Ensure that the shift amount is wide enough for the shifted value. + if (VT.getSizeInBits() >= 256) + ShAmt = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i32, ShAmt); + + return DAG.getNode(N0.getOpcode(), DL, VT, + DAG.getNode(ISD::ZERO_EXTEND, DL, VT, N0.getOperand(0)), + ShAmt); } return SDValue(); @@ -3879,7 +4088,7 @@ SDValue DAGCombiner::visitANY_EXTEND(SDNode *N) { X = DAG.getNode(ISD::TRUNCATE, N->getDebugLoc(), VT, X); } APInt Mask = cast(N0.getOperand(1))->getAPIntValue(); - Mask.zext(VT.getSizeInBits()); + Mask = Mask.zext(VT.getSizeInBits()); return DAG.getNode(ISD::AND, N->getDebugLoc(), VT, X, DAG.getConstant(Mask, VT)); } @@ -3894,10 +4103,9 @@ SDValue DAGCombiner::visitANY_EXTEND(SDNode *N) { DoXform = ExtendUsesToFormExtLoad(N, N0, ISD::ANY_EXTEND, SetCCs, TLI); if (DoXform) { LoadSDNode *LN0 = cast(N0); - SDValue ExtLoad = DAG.getExtLoad(ISD::EXTLOAD, VT, N->getDebugLoc(), + SDValue ExtLoad = DAG.getExtLoad(ISD::EXTLOAD, N->getDebugLoc(), VT, LN0->getChain(), - LN0->getBasePtr(), LN0->getSrcValue(), - LN0->getSrcValueOffset(), + LN0->getBasePtr(), LN0->getPointerInfo(), N0.getValueType(), LN0->isVolatile(), LN0->isNonTemporal(), LN0->getAlignment()); @@ -3938,11 +4146,9 @@ SDValue DAGCombiner::visitANY_EXTEND(SDNode *N) { N0.hasOneUse()) { LoadSDNode *LN0 = cast(N0); EVT MemVT = LN0->getMemoryVT(); - SDValue ExtLoad = DAG.getExtLoad(LN0->getExtensionType(), VT, - N->getDebugLoc(), - LN0->getChain(), LN0->getBasePtr(), - LN0->getSrcValue(), - LN0->getSrcValueOffset(), MemVT, + SDValue ExtLoad = DAG.getExtLoad(LN0->getExtensionType(), N->getDebugLoc(), + VT, LN0->getChain(), LN0->getBasePtr(), + LN0->getPointerInfo(), MemVT, LN0->isVolatile(), LN0->isNonTemporal(), LN0->getAlignment()); CombineTo(N, ExtLoad); @@ -4053,11 +4259,8 @@ SDValue DAGCombiner::ReduceLoadWidth(SDNode *N) { if (Opc == ISD::SIGN_EXTEND_INREG) { ExtType = ISD::SEXTLOAD; ExtVT = cast(N->getOperand(1))->getVT(); - if (LegalOperations && !TLI.isLoadExtLegal(ISD::SEXTLOAD, ExtVT)) - return SDValue(); } else if (Opc == ISD::SRL) { - // Annother special-case: SRL is basically zero-extending a narrower - // value. + // Another special-case: SRL is basically zero-extending a narrower value. ExtType = ISD::ZEXTLOAD; N0 = SDValue(N, 0); ConstantSDNode *N01 = dyn_cast(N0.getOperand(1)); @@ -4065,10 +4268,18 @@ SDValue DAGCombiner::ReduceLoadWidth(SDNode *N) { ExtVT = EVT::getIntegerVT(*DAG.getContext(), VT.getSizeInBits() - N01->getZExtValue()); } + if (LegalOperations && !TLI.isLoadExtLegal(ExtType, ExtVT)) + return SDValue(); unsigned EVTBits = ExtVT.getSizeInBits(); + + // Do not generate loads of non-round integer types since these can + // be expensive (and would be wrong if the type is not byte sized). + if (!ExtVT.isRound()) + return SDValue(); + unsigned ShAmt = 0; - if (N0.getOpcode() == ISD::SRL && N0.hasOneUse() && ExtVT.isRound()) { + if (N0.getOpcode() == ISD::SRL && N0.hasOneUse()) { if (ConstantSDNode *N01 = dyn_cast(N0.getOperand(1))) { ShAmt = N01->getZExtValue(); // Is the shift amount a multiple of size of VT? @@ -4078,52 +4289,88 @@ SDValue DAGCombiner::ReduceLoadWidth(SDNode *N) { if ((N0.getValueType().getSizeInBits() & (EVTBits-1)) != 0) return SDValue(); } + + // At this point, we must have a load or else we can't do the transform. + if (!isa(N0)) return SDValue(); + + // If the shift amount is larger than the input type then we're not + // accessing any of the loaded bytes. If the load was a zextload/extload + // then the result of the shift+trunc is zero/undef (handled elsewhere). + // If the load was a sextload then the result is a splat of the sign bit + // of the extended byte. This is not worth optimizing for. + if (ShAmt >= cast(N0)->getMemoryVT().getSizeInBits()) + return SDValue(); } } - // Do not generate loads of non-round integer types since these can - // be expensive (and would be wrong if the type is not byte sized). - if (isa(N0) && N0.hasOneUse() && ExtVT.isRound() && - cast(N0)->getMemoryVT().getSizeInBits() >= EVTBits && - // Do not change the width of a volatile load. - !cast(N0)->isVolatile()) { - LoadSDNode *LN0 = cast(N0); - EVT PtrType = N0.getOperand(1).getValueType(); - - // For big endian targets, we need to adjust the offset to the pointer to - // load the correct bytes. - if (TLI.isBigEndian()) { - unsigned LVTStoreBits = LN0->getMemoryVT().getStoreSizeInBits(); - unsigned EVTStoreBits = ExtVT.getStoreSizeInBits(); - ShAmt = LVTStoreBits - EVTStoreBits - ShAmt; - } - - uint64_t PtrOff = ShAmt / 8; - unsigned NewAlign = MinAlign(LN0->getAlignment(), PtrOff); - SDValue NewPtr = DAG.getNode(ISD::ADD, LN0->getDebugLoc(), - PtrType, LN0->getBasePtr(), - DAG.getConstant(PtrOff, PtrType)); - AddToWorkList(NewPtr.getNode()); - - SDValue Load = (ExtType == ISD::NON_EXTLOAD) - ? DAG.getLoad(VT, N0.getDebugLoc(), LN0->getChain(), NewPtr, - LN0->getSrcValue(), LN0->getSrcValueOffset() + PtrOff, - LN0->isVolatile(), LN0->isNonTemporal(), NewAlign) - : DAG.getExtLoad(ExtType, VT, N0.getDebugLoc(), LN0->getChain(), NewPtr, - LN0->getSrcValue(), LN0->getSrcValueOffset() + PtrOff, - ExtVT, LN0->isVolatile(), LN0->isNonTemporal(), - NewAlign); - - // Replace the old load's chain with the new load's chain. - WorkListRemover DeadNodes(*this); - DAG.ReplaceAllUsesOfValueWith(N0.getValue(1), Load.getValue(1), - &DeadNodes); + // If the load is shifted left (and the result isn't shifted back right), + // we can fold the truncate through the shift. + unsigned ShLeftAmt = 0; + if (ShAmt == 0 && N0.getOpcode() == ISD::SHL && N0.hasOneUse() && + ExtVT == VT && TLI.isNarrowingProfitable(N0.getValueType(), VT)) { + if (ConstantSDNode *N01 = dyn_cast(N0.getOperand(1))) { + ShLeftAmt = N01->getZExtValue(); + N0 = N0.getOperand(0); + } + } + + // If we haven't found a load, we can't narrow it. Don't transform one with + // multiple uses, this would require adding a new load. + if (!isa(N0) || !N0.hasOneUse() || + // Don't change the width of a volatile load. + cast(N0)->isVolatile()) + return SDValue(); + + // Verify that we are actually reducing a load width here. + if (cast(N0)->getMemoryVT().getSizeInBits() < EVTBits) + return SDValue(); + + LoadSDNode *LN0 = cast(N0); + EVT PtrType = N0.getOperand(1).getValueType(); + + // For big endian targets, we need to adjust the offset to the pointer to + // load the correct bytes. + if (TLI.isBigEndian()) { + unsigned LVTStoreBits = LN0->getMemoryVT().getStoreSizeInBits(); + unsigned EVTStoreBits = ExtVT.getStoreSizeInBits(); + ShAmt = LVTStoreBits - EVTStoreBits - ShAmt; + } + + uint64_t PtrOff = ShAmt / 8; + unsigned NewAlign = MinAlign(LN0->getAlignment(), PtrOff); + SDValue NewPtr = DAG.getNode(ISD::ADD, LN0->getDebugLoc(), + PtrType, LN0->getBasePtr(), + DAG.getConstant(PtrOff, PtrType)); + AddToWorkList(NewPtr.getNode()); + + SDValue Load; + if (ExtType == ISD::NON_EXTLOAD) + Load = DAG.getLoad(VT, N0.getDebugLoc(), LN0->getChain(), NewPtr, + LN0->getPointerInfo().getWithOffset(PtrOff), + LN0->isVolatile(), LN0->isNonTemporal(), NewAlign); + else + Load = DAG.getExtLoad(ExtType, N0.getDebugLoc(), VT, LN0->getChain(),NewPtr, + LN0->getPointerInfo().getWithOffset(PtrOff), + ExtVT, LN0->isVolatile(), LN0->isNonTemporal(), + NewAlign); + + // Replace the old load's chain with the new load's chain. + WorkListRemover DeadNodes(*this); + DAG.ReplaceAllUsesOfValueWith(N0.getValue(1), Load.getValue(1), + &DeadNodes); - // Return the new loaded value. - return Load; + // Shift the result left, if we've swallowed a left shift. + SDValue Result = Load; + if (ShLeftAmt != 0) { + EVT ShImmTy = getShiftAmountTy(); + if (!isUIntN(ShImmTy.getSizeInBits(), ShLeftAmt)) + ShImmTy = VT; + Result = DAG.getNode(ISD::SHL, N0.getDebugLoc(), VT, + Result, DAG.getConstant(ShLeftAmt, ShImmTy)); } - return SDValue(); + // Return the new loaded value. + return Result; } SDValue DAGCombiner::visitSIGN_EXTEND_INREG(SDNode *N) { @@ -4196,10 +4443,10 @@ SDValue DAGCombiner::visitSIGN_EXTEND_INREG(SDNode *N) { ((!LegalOperations && !cast(N0)->isVolatile()) || TLI.isLoadExtLegal(ISD::SEXTLOAD, EVT))) { LoadSDNode *LN0 = cast(N0); - SDValue ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, VT, N->getDebugLoc(), + SDValue ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, N->getDebugLoc(), VT, LN0->getChain(), - LN0->getBasePtr(), LN0->getSrcValue(), - LN0->getSrcValueOffset(), EVT, + LN0->getBasePtr(), LN0->getPointerInfo(), + EVT, LN0->isVolatile(), LN0->isNonTemporal(), LN0->getAlignment()); CombineTo(N, ExtLoad); @@ -4213,10 +4460,10 @@ SDValue DAGCombiner::visitSIGN_EXTEND_INREG(SDNode *N) { ((!LegalOperations && !cast(N0)->isVolatile()) || TLI.isLoadExtLegal(ISD::SEXTLOAD, EVT))) { LoadSDNode *LN0 = cast(N0); - SDValue ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, VT, N->getDebugLoc(), + SDValue ExtLoad = DAG.getExtLoad(ISD::SEXTLOAD, N->getDebugLoc(), VT, LN0->getChain(), - LN0->getBasePtr(), LN0->getSrcValue(), - LN0->getSrcValueOffset(), EVT, + LN0->getBasePtr(), LN0->getPointerInfo(), + EVT, LN0->isVolatile(), LN0->isNonTemporal(), LN0->getAlignment()); CombineTo(N, ExtLoad); @@ -4295,7 +4542,9 @@ SDValue DAGCombiner::CombineConsecutiveLoads(SDNode *N, EVT VT) { LoadSDNode *LD1 = dyn_cast(getBuildPairElt(N, 0)); LoadSDNode *LD2 = dyn_cast(getBuildPairElt(N, 1)); - if (!LD1 || !LD2 || !ISD::isNON_EXTLoad(LD1) || !LD1->hasOneUse()) + if (!LD1 || !LD2 || !ISD::isNON_EXTLoad(LD1) || !LD1->hasOneUse() || + LD1->getPointerInfo().getAddrSpace() != + LD2->getPointerInfo().getAddrSpace()) return SDValue(); EVT LD1VT = LD1->getValueType(0); @@ -4313,14 +4562,14 @@ SDValue DAGCombiner::CombineConsecutiveLoads(SDNode *N, EVT VT) { if (NewAlign <= Align && (!LegalOperations || TLI.isOperationLegal(ISD::LOAD, VT))) return DAG.getLoad(VT, N->getDebugLoc(), LD1->getChain(), - LD1->getBasePtr(), LD1->getSrcValue(), - LD1->getSrcValueOffset(), false, false, Align); + LD1->getBasePtr(), LD1->getPointerInfo(), + false, false, Align); } return SDValue(); } -SDValue DAGCombiner::visitBIT_CONVERT(SDNode *N) { +SDValue DAGCombiner::visitBITCAST(SDNode *N) { SDValue N0 = N->getOperand(0); EVT VT = N->getValueType(0); @@ -4344,12 +4593,12 @@ SDValue DAGCombiner::visitBIT_CONVERT(SDNode *N) { assert(!DestEltVT.isVector() && "Element type of vector ValueType must not be vector!"); if (isSimple) - return ConstantFoldBIT_CONVERTofBUILD_VECTOR(N0.getNode(), DestEltVT); + return ConstantFoldBITCASTofBUILD_VECTOR(N0.getNode(), DestEltVT); } // If the input is a constant, let getNode fold it. if (isa(N0) || isa(N0)) { - SDValue Res = DAG.getNode(ISD::BIT_CONVERT, N->getDebugLoc(), VT, N0); + SDValue Res = DAG.getNode(ISD::BITCAST, N->getDebugLoc(), VT, N0); if (Res.getNode() != N) { if (!LegalOperations || TLI.isOperationLegal(Res.getNode()->getOpcode(), VT)) @@ -4365,8 +4614,8 @@ SDValue DAGCombiner::visitBIT_CONVERT(SDNode *N) { } // (conv (conv x, t1), t2) -> (conv x, t2) - if (N0.getOpcode() == ISD::BIT_CONVERT) - return DAG.getNode(ISD::BIT_CONVERT, N->getDebugLoc(), VT, + if (N0.getOpcode() == ISD::BITCAST) + return DAG.getNode(ISD::BITCAST, N->getDebugLoc(), VT, N0.getOperand(0)); // fold (conv (load x)) -> (load (conv*)x) @@ -4382,13 +4631,12 @@ SDValue DAGCombiner::visitBIT_CONVERT(SDNode *N) { if (Align <= OrigAlign) { SDValue Load = DAG.getLoad(VT, N->getDebugLoc(), LN0->getChain(), - LN0->getBasePtr(), - LN0->getSrcValue(), LN0->getSrcValueOffset(), + LN0->getBasePtr(), LN0->getPointerInfo(), LN0->isVolatile(), LN0->isNonTemporal(), OrigAlign); AddToWorkList(N); CombineTo(N0.getNode(), - DAG.getNode(ISD::BIT_CONVERT, N0.getDebugLoc(), + DAG.getNode(ISD::BITCAST, N0.getDebugLoc(), N0.getValueType(), Load), Load.getValue(1)); return Load; @@ -4400,7 +4648,7 @@ SDValue DAGCombiner::visitBIT_CONVERT(SDNode *N) { // This often reduces constant pool loads. if ((N0.getOpcode() == ISD::FNEG || N0.getOpcode() == ISD::FABS) && N0.getNode()->hasOneUse() && VT.isInteger() && !VT.isVector()) { - SDValue NewConv = DAG.getNode(ISD::BIT_CONVERT, N0.getDebugLoc(), VT, + SDValue NewConv = DAG.getNode(ISD::BITCAST, N0.getDebugLoc(), VT, N0.getOperand(0)); AddToWorkList(NewConv.getNode()); @@ -4423,7 +4671,7 @@ SDValue DAGCombiner::visitBIT_CONVERT(SDNode *N) { unsigned OrigXWidth = N0.getOperand(1).getValueType().getSizeInBits(); EVT IntXVT = EVT::getIntegerVT(*DAG.getContext(), OrigXWidth); if (isTypeLegal(IntXVT)) { - SDValue X = DAG.getNode(ISD::BIT_CONVERT, N0.getDebugLoc(), + SDValue X = DAG.getNode(ISD::BITCAST, N0.getDebugLoc(), IntXVT, N0.getOperand(1)); AddToWorkList(X.getNode()); @@ -4448,7 +4696,7 @@ SDValue DAGCombiner::visitBIT_CONVERT(SDNode *N) { X, DAG.getConstant(SignBit, VT)); AddToWorkList(X.getNode()); - SDValue Cst = DAG.getNode(ISD::BIT_CONVERT, N0.getDebugLoc(), + SDValue Cst = DAG.getNode(ISD::BITCAST, N0.getDebugLoc(), VT, N0.getOperand(0)); Cst = DAG.getNode(ISD::AND, Cst.getDebugLoc(), VT, Cst, DAG.getConstant(~SignBit, VT)); @@ -4473,11 +4721,11 @@ SDValue DAGCombiner::visitBUILD_PAIR(SDNode *N) { return CombineConsecutiveLoads(N, VT); } -/// ConstantFoldBIT_CONVERTofBUILD_VECTOR - We know that BV is a build_vector +/// ConstantFoldBITCASTofBUILD_VECTOR - We know that BV is a build_vector /// node with Constant, ConstantFP or Undef operands. DstEltVT indicates the /// destination element value type. SDValue DAGCombiner:: -ConstantFoldBIT_CONVERTofBUILD_VECTOR(SDNode *BV, EVT DstEltVT) { +ConstantFoldBITCASTofBUILD_VECTOR(SDNode *BV, EVT DstEltVT) { EVT SrcEltVT = BV->getValueType(0).getVectorElementType(); // If this is already the right type, we're done. @@ -4495,10 +4743,10 @@ ConstantFoldBIT_CONVERTofBUILD_VECTOR(SDNode *BV, EVT DstEltVT) { // Due to the FP element handling below calling this routine recursively, // we can end up with a scalar-to-vector node here. if (BV->getOpcode() == ISD::SCALAR_TO_VECTOR) - return DAG.getNode(ISD::SCALAR_TO_VECTOR, BV->getDebugLoc(), VT, - DAG.getNode(ISD::BIT_CONVERT, BV->getDebugLoc(), + return DAG.getNode(ISD::SCALAR_TO_VECTOR, BV->getDebugLoc(), VT, + DAG.getNode(ISD::BITCAST, BV->getDebugLoc(), DstEltVT, BV->getOperand(0))); - + SmallVector Ops; for (unsigned i = 0, e = BV->getNumOperands(); i != e; ++i) { SDValue Op = BV->getOperand(i); @@ -4506,7 +4754,7 @@ ConstantFoldBIT_CONVERTofBUILD_VECTOR(SDNode *BV, EVT DstEltVT) { // are promoted and implicitly truncated. Make that explicit here. if (Op.getValueType() != SrcEltVT) Op = DAG.getNode(ISD::TRUNCATE, BV->getDebugLoc(), SrcEltVT, Op); - Ops.push_back(DAG.getNode(ISD::BIT_CONVERT, BV->getDebugLoc(), + Ops.push_back(DAG.getNode(ISD::BITCAST, BV->getDebugLoc(), DstEltVT, Op)); AddToWorkList(Ops.back().getNode()); } @@ -4522,7 +4770,7 @@ ConstantFoldBIT_CONVERTofBUILD_VECTOR(SDNode *BV, EVT DstEltVT) { // same sizes. assert((SrcEltVT == MVT::f32 || SrcEltVT == MVT::f64) && "Unknown FP VT!"); EVT IntVT = EVT::getIntegerVT(*DAG.getContext(), SrcEltVT.getSizeInBits()); - BV = ConstantFoldBIT_CONVERTofBUILD_VECTOR(BV, IntVT).getNode(); + BV = ConstantFoldBITCASTofBUILD_VECTOR(BV, IntVT).getNode(); SrcEltVT = IntVT; } @@ -4531,10 +4779,10 @@ ConstantFoldBIT_CONVERTofBUILD_VECTOR(SDNode *BV, EVT DstEltVT) { if (DstEltVT.isFloatingPoint()) { assert((DstEltVT == MVT::f32 || DstEltVT == MVT::f64) && "Unknown FP VT!"); EVT TmpVT = EVT::getIntegerVT(*DAG.getContext(), DstEltVT.getSizeInBits()); - SDNode *Tmp = ConstantFoldBIT_CONVERTofBUILD_VECTOR(BV, TmpVT).getNode(); + SDNode *Tmp = ConstantFoldBITCASTofBUILD_VECTOR(BV, TmpVT).getNode(); // Next, convert to FP elements of the same size. - return ConstantFoldBIT_CONVERTofBUILD_VECTOR(Tmp, DstEltVT); + return ConstantFoldBITCASTofBUILD_VECTOR(Tmp, DstEltVT); } // Okay, we know the src/dst types are both integers of differing types. @@ -4556,7 +4804,7 @@ ConstantFoldBIT_CONVERTofBUILD_VECTOR(SDNode *BV, EVT DstEltVT) { if (Op.getOpcode() == ISD::UNDEF) continue; EltIsUndef = false; - NewBits |= APInt(cast(Op)->getAPIntValue()). + NewBits |= cast(Op)->getAPIntValue(). zextOrTrunc(SrcBitSize).zext(DstBitSize); } @@ -4586,13 +4834,13 @@ ConstantFoldBIT_CONVERTofBUILD_VECTOR(SDNode *BV, EVT DstEltVT) { continue; } - APInt OpVal = APInt(cast(BV->getOperand(i))-> - getAPIntValue()).zextOrTrunc(SrcBitSize); + APInt OpVal = cast(BV->getOperand(i))-> + getAPIntValue().zextOrTrunc(SrcBitSize); for (unsigned j = 0; j != NumOutputsPerInput; ++j) { - APInt ThisVal = APInt(OpVal).trunc(DstBitSize); + APInt ThisVal = OpVal.trunc(DstBitSize); Ops.push_back(DAG.getConstant(ThisVal, DstEltVT)); - if (isS2V && i == 0 && j == 0 && APInt(ThisVal).zext(SrcBitSize) == OpVal) + if (isS2V && i == 0 && j == 0 && ThisVal.zext(SrcBitSize) == OpVal) // Simply turn this into a SCALAR_TO_VECTOR of the new type. return DAG.getNode(ISD::SCALAR_TO_VECTOR, BV->getDebugLoc(), VT, Ops[0]); @@ -4984,10 +5232,9 @@ SDValue DAGCombiner::visitFP_EXTEND(SDNode *N) { ((!LegalOperations && !cast(N0)->isVolatile()) || TLI.isLoadExtLegal(ISD::EXTLOAD, N0.getValueType()))) { LoadSDNode *LN0 = cast(N0); - SDValue ExtLoad = DAG.getExtLoad(ISD::EXTLOAD, VT, N->getDebugLoc(), + SDValue ExtLoad = DAG.getExtLoad(ISD::EXTLOAD, N->getDebugLoc(), VT, LN0->getChain(), - LN0->getBasePtr(), LN0->getSrcValue(), - LN0->getSrcValueOffset(), + LN0->getBasePtr(), LN0->getPointerInfo(), N0.getValueType(), LN0->isVolatile(), LN0->isNonTemporal(), LN0->getAlignment()); @@ -5011,7 +5258,7 @@ SDValue DAGCombiner::visitFNEG(SDNode *N) { // Transform fneg(bitconvert(x)) -> bitconvert(x^sign) to avoid loading // constant pool values. - if (N0.getOpcode() == ISD::BIT_CONVERT && + if (N0.getOpcode() == ISD::BITCAST && !VT.isVector() && N0.getNode()->hasOneUse() && N0.getOperand(0).getValueType().isInteger()) { @@ -5021,7 +5268,7 @@ SDValue DAGCombiner::visitFNEG(SDNode *N) { Int = DAG.getNode(ISD::XOR, N0.getDebugLoc(), IntVT, Int, DAG.getConstant(APInt::getSignBit(IntVT.getSizeInBits()), IntVT)); AddToWorkList(Int.getNode()); - return DAG.getNode(ISD::BIT_CONVERT, N->getDebugLoc(), + return DAG.getNode(ISD::BITCAST, N->getDebugLoc(), VT, Int); } } @@ -5047,7 +5294,7 @@ SDValue DAGCombiner::visitFABS(SDNode *N) { // Transform fabs(bitconvert(x)) -> bitconvert(x&~sign) to avoid loading // constant pool values. - if (N0.getOpcode() == ISD::BIT_CONVERT && N0.getNode()->hasOneUse() && + if (N0.getOpcode() == ISD::BITCAST && N0.getNode()->hasOneUse() && N0.getOperand(0).getValueType().isInteger() && !N0.getOperand(0).getValueType().isVector()) { SDValue Int = N0.getOperand(0); @@ -5056,7 +5303,7 @@ SDValue DAGCombiner::visitFABS(SDNode *N) { Int = DAG.getNode(ISD::AND, N0.getDebugLoc(), IntVT, Int, DAG.getConstant(~APInt::getSignBit(IntVT.getSizeInBits()), IntVT)); AddToWorkList(Int.getNode()); - return DAG.getNode(ISD::BIT_CONVERT, N->getDebugLoc(), + return DAG.getNode(ISD::BITCAST, N->getDebugLoc(), N->getValueType(0), Int); } } @@ -5084,14 +5331,17 @@ SDValue DAGCombiner::visitBRCOND(SDNode *N) { N1.getOperand(0), N1.getOperand(1), N2); } - SDNode *Trunc = 0; - if (N1.getOpcode() == ISD::TRUNCATE && N1.hasOneUse()) { - // Look past truncate. - Trunc = N1.getNode(); - N1 = N1.getOperand(0); - } + if ((N1.hasOneUse() && N1.getOpcode() == ISD::SRL) || + ((N1.getOpcode() == ISD::TRUNCATE && N1.hasOneUse()) && + (N1.getOperand(0).hasOneUse() && + N1.getOperand(0).getOpcode() == ISD::SRL))) { + SDNode *Trunc = 0; + if (N1.getOpcode() == ISD::TRUNCATE) { + // Look pass the truncate. + Trunc = N1.getNode(); + N1 = N1.getOperand(0); + } - if (N1.hasOneUse() && N1.getOpcode() == ISD::SRL) { // Match this pattern so that we can generate simpler code: // // %a = ... @@ -5100,7 +5350,7 @@ SDValue DAGCombiner::visitBRCOND(SDNode *N) { // brcond i32 %c ... // // into - // + // // %a = ... // %b = and i32 %a, 2 // %c = setcc eq %b, 0 @@ -5146,8 +5396,12 @@ SDValue DAGCombiner::visitBRCOND(SDNode *N) { } } } + + if (Trunc) + // Restore N1 if the above transformation doesn't match. + N1 = N->getOperand(1); } - + // Transform br(xor(x, y)) -> br(x != y) // Transform br(xor(xor(x,y), 1)) -> br (x == y) if (N1.hasOneUse() && N1.getOpcode() == ISD::XOR) { @@ -5181,9 +5435,7 @@ SDValue DAGCombiner::visitBRCOND(SDNode *N) { Equal = true; } - SDValue NodeToReplace = Trunc ? SDValue(Trunc, 0) : N1; - - EVT SetCCVT = NodeToReplace.getValueType(); + EVT SetCCVT = N1.getValueType(); if (LegalTypes) SetCCVT = TLI.getSetCCResultType(SetCCVT); SDValue SetCC = DAG.getSetCC(TheXor->getDebugLoc(), @@ -5192,9 +5444,9 @@ SDValue DAGCombiner::visitBRCOND(SDNode *N) { Equal ? ISD::SETEQ : ISD::SETNE); // Replace the uses of XOR with SETCC WorkListRemover DeadNodes(*this); - DAG.ReplaceAllUsesOfValueWith(NodeToReplace, SetCC, &DeadNodes); - removeFromWorkList(NodeToReplace.getNode()); - DAG.DeleteNode(NodeToReplace.getNode()); + DAG.ReplaceAllUsesOfValueWith(N1, SetCC, &DeadNodes); + removeFromWorkList(N1.getNode()); + DAG.DeleteNode(N1.getNode()); return DAG.getNode(ISD::BRCOND, N->getDebugLoc(), MVT::Other, Chain, SetCC, N2); } @@ -5568,10 +5820,10 @@ SDValue DAGCombiner::visitLOAD(SDNode *N) { if (OptLevel != CodeGenOpt::None && LD->isUnindexed()) { if (unsigned Align = DAG.InferPtrAlignment(Ptr)) { if (Align > LD->getAlignment()) - return DAG.getExtLoad(LD->getExtensionType(), LD->getValueType(0), - N->getDebugLoc(), - Chain, Ptr, LD->getSrcValue(), - LD->getSrcValueOffset(), LD->getMemoryVT(), + return DAG.getExtLoad(LD->getExtensionType(), N->getDebugLoc(), + LD->getValueType(0), + Chain, Ptr, LD->getPointerInfo(), + LD->getMemoryVT(), LD->isVolatile(), LD->isNonTemporal(), Align); } } @@ -5587,15 +5839,13 @@ SDValue DAGCombiner::visitLOAD(SDNode *N) { // Replace the chain to void dependency. if (LD->getExtensionType() == ISD::NON_EXTLOAD) { ReplLoad = DAG.getLoad(N->getValueType(0), LD->getDebugLoc(), - BetterChain, Ptr, - LD->getSrcValue(), LD->getSrcValueOffset(), + BetterChain, Ptr, LD->getPointerInfo(), LD->isVolatile(), LD->isNonTemporal(), LD->getAlignment()); } else { - ReplLoad = DAG.getExtLoad(LD->getExtensionType(), LD->getValueType(0), - LD->getDebugLoc(), - BetterChain, Ptr, LD->getSrcValue(), - LD->getSrcValueOffset(), + ReplLoad = DAG.getExtLoad(LD->getExtensionType(), LD->getDebugLoc(), + LD->getValueType(0), + BetterChain, Ptr, LD->getPointerInfo(), LD->getMemoryVT(), LD->isVolatile(), LD->isNonTemporal(), @@ -5605,10 +5855,10 @@ SDValue DAGCombiner::visitLOAD(SDNode *N) { // Create token factor to keep old chain connected. SDValue Token = DAG.getNode(ISD::TokenFactor, N->getDebugLoc(), MVT::Other, Chain, ReplLoad.getValue(1)); - + // Make sure the new and old chains are cleaned up. AddToWorkList(Token.getNode()); - + // Replace uses with load result and token factor. Don't add users // to work list. return CombineTo(N, ReplLoad.getValue(0), Token, false); @@ -5628,17 +5878,17 @@ SDValue DAGCombiner::visitLOAD(SDNode *N) { static std::pair CheckForMaskedLoad(SDValue V, SDValue Ptr, SDValue Chain) { std::pair Result(0, 0); - + // Check for the structure we're looking for. if (V->getOpcode() != ISD::AND || !isa(V->getOperand(1)) || !ISD::isNormalLoad(V->getOperand(0).getNode())) return Result; - + // Check the chain and pointer. LoadSDNode *LD = cast(V->getOperand(0)); if (LD->getBasePtr() != Ptr) return Result; // Not from same pointer. - + // The store should be chained directly to the load or be an operand of a // tokenfactor. if (LD == Chain.getNode()) @@ -5654,7 +5904,7 @@ CheckForMaskedLoad(SDValue V, SDValue Ptr, SDValue Chain) { } if (!isOk) return Result; } - + // This only handles simple types. if (V.getValueType() != MVT::i16 && V.getValueType() != MVT::i32 && @@ -5670,7 +5920,7 @@ CheckForMaskedLoad(SDValue V, SDValue Ptr, SDValue Chain) { unsigned NotMaskTZ = CountTrailingZeros_64(NotMask); if (NotMaskTZ & 7) return Result; // Must be multiple of a byte. if (NotMaskLZ == 64) return Result; // All zero mask. - + // See if we have a continuous run of bits. If so, we have 0*1+0* if (CountTrailingOnes_64(NotMask >> NotMaskTZ)+NotMaskTZ+NotMaskLZ != 64) return Result; @@ -5678,19 +5928,19 @@ CheckForMaskedLoad(SDValue V, SDValue Ptr, SDValue Chain) { // Adjust NotMaskLZ down to be from the actual size of the int instead of i64. if (V.getValueType() != MVT::i64 && NotMaskLZ) NotMaskLZ -= 64-V.getValueSizeInBits(); - + unsigned MaskedBytes = (V.getValueSizeInBits()-NotMaskLZ-NotMaskTZ)/8; switch (MaskedBytes) { - case 1: - case 2: + case 1: + case 2: case 4: break; default: return Result; // All one mask, or 5-byte mask. } - + // Verify that the first bit starts at a multiple of mask so that the access // is aligned the same as the access width. if (NotMaskTZ && NotMaskTZ/8 % MaskedBytes) return Result; - + Result.first = MaskedBytes; Result.second = NotMaskTZ/8; return Result; @@ -5707,20 +5957,20 @@ ShrinkLoadReplaceStoreWithStore(const std::pair &MaskInfo, unsigned NumBytes = MaskInfo.first; unsigned ByteShift = MaskInfo.second; SelectionDAG &DAG = DC->getDAG(); - + // Check to see if IVal is all zeros in the part being masked in by the 'or' // that uses this. If not, this is not a replacement. APInt Mask = ~APInt::getBitsSet(IVal.getValueSizeInBits(), ByteShift*8, (ByteShift+NumBytes)*8); if (!DAG.MaskedValueIsZero(IVal, Mask)) return 0; - + // Check that it is legal on the target to do this. It is legal if the new // VT we're shrinking to (i8/i16/i32) is legal or we're still before type // legalization. MVT VT = MVT::getIntegerVT(NumBytes*8); if (!DC->isTypeLegal(VT)) return 0; - + // Okay, we can do this! Replace the 'St' store with a store of IVal that is // shifted by ByteShift and truncated down to NumBytes. if (ByteShift) @@ -5735,20 +5985,20 @@ ShrinkLoadReplaceStoreWithStore(const std::pair &MaskInfo, StOffset = ByteShift; else StOffset = IVal.getValueType().getStoreSize() - ByteShift - NumBytes; - + SDValue Ptr = St->getBasePtr(); if (StOffset) { Ptr = DAG.getNode(ISD::ADD, IVal->getDebugLoc(), Ptr.getValueType(), Ptr, DAG.getConstant(StOffset, Ptr.getValueType())); NewAlign = MinAlign(NewAlign, StOffset); } - + // Truncate down to the new size. IVal = DAG.getNode(ISD::TRUNCATE, IVal->getDebugLoc(), VT, IVal); - + ++OpsNarrowed; - return DAG.getStore(St->getChain(), St->getDebugLoc(), IVal, Ptr, - St->getSrcValue(), St->getSrcValueOffset()+StOffset, + return DAG.getStore(St->getChain(), St->getDebugLoc(), IVal, Ptr, + St->getPointerInfo().getWithOffset(StOffset), false, false, NewAlign).getNode(); } @@ -5771,7 +6021,7 @@ SDValue DAGCombiner::ReduceLoadOpStoreWidth(SDNode *N) { return SDValue(); unsigned Opc = Value.getOpcode(); - + // If this is "store (or X, Y), P" and X is "(and (load P), cst)", where cst // is a byte mask indicating a consecutive number of bytes, check to see if // Y is known to provide just those bytes. If so, we try to replace the @@ -5784,7 +6034,7 @@ SDValue DAGCombiner::ReduceLoadOpStoreWidth(SDNode *N) { if (SDNode *NewST = ShrinkLoadReplaceStoreWithStore(MaskedLoad, Value.getOperand(1), ST,this)) return SDValue(NewST, 0); - + // Or is commutative, so try swapping X and Y. MaskedLoad = CheckForMaskedLoad(Value.getOperand(1), Ptr, Chain); if (MaskedLoad.first) @@ -5792,7 +6042,7 @@ SDValue DAGCombiner::ReduceLoadOpStoreWidth(SDNode *N) { Value.getOperand(0), ST,this)) return SDValue(NewST, 0); } - + if ((Opc != ISD::OR && Opc != ISD::XOR && Opc != ISD::AND) || Value.getOperand(1).getOpcode() != ISD::Constant) return SDValue(); @@ -5801,7 +6051,9 @@ SDValue DAGCombiner::ReduceLoadOpStoreWidth(SDNode *N) { if (ISD::isNormalLoad(N0.getNode()) && N0.hasOneUse() && Chain == SDValue(N0.getNode(), 1)) { LoadSDNode *LD = cast(N0); - if (LD->getBasePtr() != Ptr) + if (LD->getBasePtr() != Ptr || + LD->getPointerInfo().getAddrSpace() != + ST->getPointerInfo().getAddrSpace()) return SDValue(); // Find the type to narrow it the load / op / store to. @@ -5850,14 +6102,14 @@ SDValue DAGCombiner::ReduceLoadOpStoreWidth(SDNode *N) { DAG.getConstant(PtrOff, Ptr.getValueType())); SDValue NewLD = DAG.getLoad(NewVT, N0.getDebugLoc(), LD->getChain(), NewPtr, - LD->getSrcValue(), LD->getSrcValueOffset(), + LD->getPointerInfo().getWithOffset(PtrOff), LD->isVolatile(), LD->isNonTemporal(), NewAlign); SDValue NewVal = DAG.getNode(Opc, Value.getDebugLoc(), NewVT, NewLD, DAG.getConstant(NewImm, NewVT)); SDValue NewST = DAG.getStore(Chain, N->getDebugLoc(), NewVal, NewPtr, - ST->getSrcValue(), ST->getSrcValueOffset(), + ST->getPointerInfo().getWithOffset(PtrOff), false, false, NewAlign); AddToWorkList(NewPtr.getNode()); @@ -5874,6 +6126,63 @@ SDValue DAGCombiner::ReduceLoadOpStoreWidth(SDNode *N) { return SDValue(); } +/// TransformFPLoadStorePair - For a given floating point load / store pair, +/// if the load value isn't used by any other operations, then consider +/// transforming the pair to integer load / store operations if the target +/// deems the transformation profitable. +SDValue DAGCombiner::TransformFPLoadStorePair(SDNode *N) { + StoreSDNode *ST = cast(N); + SDValue Chain = ST->getChain(); + SDValue Value = ST->getValue(); + if (ISD::isNormalStore(ST) && ISD::isNormalLoad(Value.getNode()) && + Value.hasOneUse() && + Chain == SDValue(Value.getNode(), 1)) { + LoadSDNode *LD = cast(Value); + EVT VT = LD->getMemoryVT(); + if (!VT.isFloatingPoint() || + VT != ST->getMemoryVT() || + LD->isNonTemporal() || + ST->isNonTemporal() || + LD->getPointerInfo().getAddrSpace() != 0 || + ST->getPointerInfo().getAddrSpace() != 0) + return SDValue(); + + EVT IntVT = EVT::getIntegerVT(*DAG.getContext(), VT.getSizeInBits()); + if (!TLI.isOperationLegal(ISD::LOAD, IntVT) || + !TLI.isOperationLegal(ISD::STORE, IntVT) || + !TLI.isDesirableToTransformToIntegerOp(ISD::LOAD, VT) || + !TLI.isDesirableToTransformToIntegerOp(ISD::STORE, VT)) + return SDValue(); + + unsigned LDAlign = LD->getAlignment(); + unsigned STAlign = ST->getAlignment(); + const Type *IntVTTy = IntVT.getTypeForEVT(*DAG.getContext()); + unsigned ABIAlign = TLI.getTargetData()->getABITypeAlignment(IntVTTy); + if (LDAlign < ABIAlign || STAlign < ABIAlign) + return SDValue(); + + SDValue NewLD = DAG.getLoad(IntVT, Value.getDebugLoc(), + LD->getChain(), LD->getBasePtr(), + LD->getPointerInfo(), + false, false, LDAlign); + + SDValue NewST = DAG.getStore(NewLD.getValue(1), N->getDebugLoc(), + NewLD, ST->getBasePtr(), + ST->getPointerInfo(), + false, false, STAlign); + + AddToWorkList(NewLD.getNode()); + AddToWorkList(NewST.getNode()); + WorkListRemover DeadNodes(*this); + DAG.ReplaceAllUsesOfValueWith(Value.getValue(1), NewLD.getValue(1), + &DeadNodes); + ++LdStFP2Int; + return NewST; + } + + return SDValue(); +} + SDValue DAGCombiner::visitSTORE(SDNode *N) { StoreSDNode *ST = cast(N); SDValue Chain = ST->getChain(); @@ -5882,7 +6191,7 @@ SDValue DAGCombiner::visitSTORE(SDNode *N) { // If this is a store of a bit convert, store the input value if the // resultant store does not need a higher alignment than the original. - if (Value.getOpcode() == ISD::BIT_CONVERT && !ST->isTruncatingStore() && + if (Value.getOpcode() == ISD::BITCAST && !ST->isTruncatingStore() && ST->isUnindexed()) { unsigned OrigAlign = ST->getAlignment(); EVT SVT = Value.getOperand(0).getValueType(); @@ -5892,8 +6201,7 @@ SDValue DAGCombiner::visitSTORE(SDNode *N) { ((!LegalOperations && !ST->isVolatile()) || TLI.isOperationLegalOrCustom(ISD::STORE, SVT))) return DAG.getStore(Chain, N->getDebugLoc(), Value.getOperand(0), - Ptr, ST->getSrcValue(), - ST->getSrcValueOffset(), ST->isVolatile(), + Ptr, ST->getPointerInfo(), ST->isVolatile(), ST->isNonTemporal(), OrigAlign); } @@ -5917,8 +6225,7 @@ SDValue DAGCombiner::visitSTORE(SDNode *N) { Tmp = DAG.getConstant((uint32_t)CFP->getValueAPF(). bitcastToAPInt().getZExtValue(), MVT::i32); return DAG.getStore(Chain, N->getDebugLoc(), Tmp, - Ptr, ST->getSrcValue(), - ST->getSrcValueOffset(), ST->isVolatile(), + Ptr, ST->getPointerInfo(), ST->isVolatile(), ST->isNonTemporal(), ST->getAlignment()); } break; @@ -5929,8 +6236,7 @@ SDValue DAGCombiner::visitSTORE(SDNode *N) { Tmp = DAG.getConstant(CFP->getValueAPF().bitcastToAPInt(). getZExtValue(), MVT::i64); return DAG.getStore(Chain, N->getDebugLoc(), Tmp, - Ptr, ST->getSrcValue(), - ST->getSrcValueOffset(), ST->isVolatile(), + Ptr, ST->getPointerInfo(), ST->isVolatile(), ST->isNonTemporal(), ST->getAlignment()); } else if (!ST->isVolatile() && TLI.isOperationLegalOrCustom(ISD::STORE, MVT::i32)) { @@ -5942,23 +6248,20 @@ SDValue DAGCombiner::visitSTORE(SDNode *N) { SDValue Hi = DAG.getConstant(Val >> 32, MVT::i32); if (TLI.isBigEndian()) std::swap(Lo, Hi); - int SVOffset = ST->getSrcValueOffset(); unsigned Alignment = ST->getAlignment(); bool isVolatile = ST->isVolatile(); bool isNonTemporal = ST->isNonTemporal(); SDValue St0 = DAG.getStore(Chain, ST->getDebugLoc(), Lo, - Ptr, ST->getSrcValue(), - ST->getSrcValueOffset(), + Ptr, ST->getPointerInfo(), isVolatile, isNonTemporal, ST->getAlignment()); Ptr = DAG.getNode(ISD::ADD, N->getDebugLoc(), Ptr.getValueType(), Ptr, DAG.getConstant(4, Ptr.getValueType())); - SVOffset += 4; Alignment = MinAlign(Alignment, 4U); SDValue St1 = DAG.getStore(Chain, ST->getDebugLoc(), Hi, - Ptr, ST->getSrcValue(), - SVOffset, isVolatile, isNonTemporal, + Ptr, ST->getPointerInfo().getWithOffset(4), + isVolatile, isNonTemporal, Alignment); return DAG.getNode(ISD::TokenFactor, N->getDebugLoc(), MVT::Other, St0, St1); @@ -5974,12 +6277,17 @@ SDValue DAGCombiner::visitSTORE(SDNode *N) { if (unsigned Align = DAG.InferPtrAlignment(Ptr)) { if (Align > ST->getAlignment()) return DAG.getTruncStore(Chain, N->getDebugLoc(), Value, - Ptr, ST->getSrcValue(), - ST->getSrcValueOffset(), ST->getMemoryVT(), + Ptr, ST->getPointerInfo(), ST->getMemoryVT(), ST->isVolatile(), ST->isNonTemporal(), Align); } } + // Try transforming a pair floating point load / store ops to integer + // load / store ops. + SDValue NewST = TransformFPLoadStorePair(N); + if (NewST.getNode()) + return NewST; + if (CombinerAA) { // Walk up chain skipping non-aliasing memory nodes. SDValue BetterChain = FindBetterChain(N, Chain); @@ -5991,12 +6299,12 @@ SDValue DAGCombiner::visitSTORE(SDNode *N) { // Replace the chain to avoid dependency. if (ST->isTruncatingStore()) { ReplStore = DAG.getTruncStore(BetterChain, N->getDebugLoc(), Value, Ptr, - ST->getSrcValue(),ST->getSrcValueOffset(), + ST->getPointerInfo(), ST->getMemoryVT(), ST->isVolatile(), ST->isNonTemporal(), ST->getAlignment()); } else { ReplStore = DAG.getStore(BetterChain, N->getDebugLoc(), Value, Ptr, - ST->getSrcValue(), ST->getSrcValueOffset(), + ST->getPointerInfo(), ST->isVolatile(), ST->isNonTemporal(), ST->getAlignment()); } @@ -6030,17 +6338,16 @@ SDValue DAGCombiner::visitSTORE(SDNode *N) { AddToWorkList(Value.getNode()); if (Shorter.getNode()) return DAG.getTruncStore(Chain, N->getDebugLoc(), Shorter, - Ptr, ST->getSrcValue(), - ST->getSrcValueOffset(), ST->getMemoryVT(), + Ptr, ST->getPointerInfo(), ST->getMemoryVT(), ST->isVolatile(), ST->isNonTemporal(), ST->getAlignment()); // Otherwise, see if we can simplify the operation with // SimplifyDemandedBits, which only works if the value has a single use. if (SimplifyDemandedBits(Value, - APInt::getLowBitsSet( - Value.getValueType().getScalarType().getSizeInBits(), - ST->getMemoryVT().getScalarType().getSizeInBits()))) + APInt::getLowBitsSet( + Value.getValueType().getScalarType().getSizeInBits(), + ST->getMemoryVT().getScalarType().getSizeInBits()))) return SDValue(N, 0); } @@ -6064,8 +6371,7 @@ SDValue DAGCombiner::visitSTORE(SDNode *N) { TLI.isTruncStoreLegal(Value.getOperand(0).getValueType(), ST->getMemoryVT())) { return DAG.getTruncStore(Chain, N->getDebugLoc(), Value.getOperand(0), - Ptr, ST->getSrcValue(), - ST->getSrcValueOffset(), ST->getMemoryVT(), + Ptr, ST->getPointerInfo(), ST->getMemoryVT(), ST->isVolatile(), ST->isNonTemporal(), ST->getAlignment()); } @@ -6082,6 +6388,12 @@ SDValue DAGCombiner::visitINSERT_VECTOR_ELT(SDNode *N) { if (InVal.getOpcode() == ISD::UNDEF) return InVec; + EVT VT = InVec.getValueType(); + + // If we can't generate a legal BUILD_VECTOR, exit + if (LegalOperations && !TLI.isOperationLegal(ISD::BUILD_VECTOR, VT)) + return SDValue(); + // If the invec is a BUILD_VECTOR and if EltNo is a constant, build a new // vector with the inserted element. if (InVec.getOpcode() == ISD::BUILD_VECTOR && isa(EltNo)) { @@ -6091,13 +6403,12 @@ SDValue DAGCombiner::visitINSERT_VECTOR_ELT(SDNode *N) { if (Elt < Ops.size()) Ops[Elt] = InVal; return DAG.getNode(ISD::BUILD_VECTOR, N->getDebugLoc(), - InVec.getValueType(), &Ops[0], Ops.size()); + VT, &Ops[0], Ops.size()); } - // If the invec is an UNDEF and if EltNo is a constant, create a new + // If the invec is an UNDEF and if EltNo is a constant, create a new // BUILD_VECTOR with undef elements and the inserted element. - if (!LegalOperations && InVec.getOpcode() == ISD::UNDEF && + if (InVec.getOpcode() == ISD::UNDEF && isa(EltNo)) { - EVT VT = InVec.getValueType(); EVT EltVT = VT.getVectorElementType(); unsigned NElts = VT.getVectorNumElements(); SmallVector Ops(NElts, DAG.getUNDEF(EltVT)); @@ -6106,7 +6417,7 @@ SDValue DAGCombiner::visitINSERT_VECTOR_ELT(SDNode *N) { if (Elt < Ops.size()) Ops[Elt] = InVal; return DAG.getNode(ISD::BUILD_VECTOR, N->getDebugLoc(), - InVec.getValueType(), &Ops[0], Ops.size()); + VT, &Ops[0], Ops.size()); } return SDValue(); } @@ -6138,14 +6449,14 @@ SDValue DAGCombiner::visitEXTRACT_VECTOR_ELT(SDNode *N) { SDValue EltNo = N->getOperand(1); if (isa(EltNo)) { - unsigned Elt = cast(EltNo)->getZExtValue(); + int Elt = cast(EltNo)->getZExtValue(); bool NewLoad = false; bool BCNumEltsChanged = false; EVT VT = InVec.getValueType(); EVT ExtVT = VT.getVectorElementType(); EVT LVT = ExtVT; - if (InVec.getOpcode() == ISD::BIT_CONVERT) { + if (InVec.getOpcode() == ISD::BITCAST) { EVT BCVT = InVec.getOperand(0).getValueType(); if (!BCVT.isVector() || ExtVT.bitsGT(BCVT.getVectorElementType())) return SDValue(); @@ -6176,10 +6487,10 @@ SDValue DAGCombiner::visitEXTRACT_VECTOR_ELT(SDNode *N) { // Select the input vector, guarding against out of range extract vector. unsigned NumElems = VT.getVectorNumElements(); - int Idx = (Elt > NumElems) ? -1 : SVN->getMaskElt(Elt); + int Idx = (Elt > (int)NumElems) ? -1 : SVN->getMaskElt(Elt); InVec = (Idx < (int)NumElems) ? InVec.getOperand(0) : InVec.getOperand(1); - if (InVec.getOpcode() == ISD::BIT_CONVERT) + if (InVec.getOpcode() == ISD::BITCAST) InVec = InVec.getOperand(0); if (ISD::isNormalLoad(InVec.getNode())) { LN0 = cast(InVec); @@ -6190,12 +6501,17 @@ SDValue DAGCombiner::visitEXTRACT_VECTOR_ELT(SDNode *N) { if (!LN0 || !LN0->hasOneUse() || LN0->isVolatile()) return SDValue(); + // If Idx was -1 above, Elt is going to be -1, so just return undef. + if (Elt == -1) + return DAG.getUNDEF(LN0->getBasePtr().getValueType()); + unsigned Align = LN0->getAlignment(); if (NewLoad) { // Check the resultant load doesn't need a higher alignment than the // original load. unsigned NewAlign = - TLI.getTargetData()->getABITypeAlignment(LVT.getTypeForEVT(*DAG.getContext())); + TLI.getTargetData() + ->getABITypeAlignment(LVT.getTypeForEVT(*DAG.getContext())); if (NewAlign > Align || !TLI.isOperationLegalOrCustom(ISD::LOAD, LVT)) return SDValue(); @@ -6204,8 +6520,10 @@ SDValue DAGCombiner::visitEXTRACT_VECTOR_ELT(SDNode *N) { } SDValue NewPtr = LN0->getBasePtr(); + unsigned PtrOff = 0; + if (Elt) { - unsigned PtrOff = LVT.getSizeInBits() * Elt / 8; + PtrOff = LVT.getSizeInBits() * Elt / 8; EVT PtrType = NewPtr.getValueType(); if (TLI.isBigEndian()) PtrOff = VT.getSizeInBits() / 8 - PtrOff; @@ -6214,7 +6532,7 @@ SDValue DAGCombiner::visitEXTRACT_VECTOR_ELT(SDNode *N) { } return DAG.getLoad(LVT, N->getDebugLoc(), LN0->getChain(), NewPtr, - LN0->getSrcValue(), LN0->getSrcValueOffset(), + LN0->getPointerInfo().getWithOffset(PtrOff), LN0->isVolatile(), LN0->isNonTemporal(), Align); } @@ -6280,7 +6598,7 @@ SDValue DAGCombiner::visitBUILD_VECTOR(SDNode *N) { unsigned ExtIndex = cast(ExtVal)->getZExtValue(); if (ExtIndex > VT.getVectorNumElements()) return SDValue(); - + Mask.push_back(ExtIndex); continue; } @@ -6328,15 +6646,16 @@ SDValue DAGCombiner::visitVECTOR_SHUFFLE(SDNode *N) { // FIXME: implement canonicalizations from DAG.getVectorShuffle() - // If it is a splat, check if the argument vector is a build_vector with - // all scalar elements the same. - if (cast(N)->isSplat()) { + // If it is a splat, check if the argument vector is another splat or a + // build_vector with all scalar elements the same. + ShuffleVectorSDNode *SVN = cast(N); + if (SVN->isSplat() && SVN->getSplatIndex() < (int)NumElts) { SDNode *V = N0.getNode(); // If this is a bit convert that changes the element type of the vector but // not the number of vector elements, look through it. Be careful not to // look though conversions that change things like v4f32 to v2f64. - if (V->getOpcode() == ISD::BIT_CONVERT) { + if (V->getOpcode() == ISD::BITCAST) { SDValue ConvInput = V->getOperand(0); if (ConvInput.getValueType().isVector() && ConvInput.getValueType().getVectorNumElements() == NumElts) @@ -6344,30 +6663,28 @@ SDValue DAGCombiner::visitVECTOR_SHUFFLE(SDNode *N) { } if (V->getOpcode() == ISD::BUILD_VECTOR) { - unsigned NumElems = V->getNumOperands(); - unsigned BaseIdx = cast(N)->getSplatIndex(); - if (NumElems > BaseIdx) { - SDValue Base; - bool AllSame = true; - for (unsigned i = 0; i != NumElems; ++i) { - if (V->getOperand(i).getOpcode() != ISD::UNDEF) { - Base = V->getOperand(i); - break; - } + assert(V->getNumOperands() == NumElts && + "BUILD_VECTOR has wrong number of operands"); + SDValue Base; + bool AllSame = true; + for (unsigned i = 0; i != NumElts; ++i) { + if (V->getOperand(i).getOpcode() != ISD::UNDEF) { + Base = V->getOperand(i); + break; } - // Splat of , return - if (!Base.getNode()) - return N0; - for (unsigned i = 0; i != NumElems; ++i) { - if (V->getOperand(i) != Base) { - AllSame = false; - break; - } + } + // Splat of , return + if (!Base.getNode()) + return N0; + for (unsigned i = 0; i != NumElts; ++i) { + if (V->getOperand(i) != Base) { + AllSame = false; + break; } - // Splat of , return - if (AllSame) - return N0; } + // Splat of , return + if (AllSame) + return N0; } } return SDValue(); @@ -6436,7 +6753,7 @@ SDValue DAGCombiner::XformToShuffleWithZero(SDNode *N) { SDValue LHS = N->getOperand(0); SDValue RHS = N->getOperand(1); if (N->getOpcode() == ISD::AND) { - if (RHS.getOpcode() == ISD::BIT_CONVERT) + if (RHS.getOpcode() == ISD::BITCAST) RHS = RHS.getOperand(0); if (RHS.getOpcode() == ISD::BUILD_VECTOR) { SmallVector Indices; @@ -6464,9 +6781,9 @@ SDValue DAGCombiner::XformToShuffleWithZero(SDNode *N) { DAG.getConstant(0, EltVT)); SDValue Zero = DAG.getNode(ISD::BUILD_VECTOR, N->getDebugLoc(), RVT, &ZeroOps[0], ZeroOps.size()); - LHS = DAG.getNode(ISD::BIT_CONVERT, dl, RVT, LHS); + LHS = DAG.getNode(ISD::BITCAST, dl, RVT, LHS); SDValue Shuf = DAG.getVectorShuffle(RVT, dl, LHS, Zero, &Indices[0]); - return DAG.getNode(ISD::BIT_CONVERT, dl, VT, Shuf); + return DAG.getNode(ISD::BITCAST, dl, VT, Shuf); } } @@ -6480,10 +6797,9 @@ SDValue DAGCombiner::SimplifyVBinOp(SDNode *N) { // things. Simplifying them may result in a loss of legality. if (LegalOperations) return SDValue(); - EVT VT = N->getValueType(0); - assert(VT.isVector() && "SimplifyVBinOp only works on vectors!"); + assert(N->getValueType(0).isVector() && + "SimplifyVBinOp only works on vectors!"); - EVT EltType = VT.getVectorElementType(); SDValue LHS = N->getOperand(0); SDValue RHS = N->getOperand(1); SDValue Shuffle = XformToShuffleWithZero(N); @@ -6516,14 +6832,10 @@ SDValue DAGCombiner::SimplifyVBinOp(SDNode *N) { break; } - // If the vector element type is not legal, the BUILD_VECTOR operands - // are promoted and implicitly truncated. Make that explicit here. - if (LHSOp.getValueType() != EltType) - LHSOp = DAG.getNode(ISD::TRUNCATE, LHS.getDebugLoc(), EltType, LHSOp); - if (RHSOp.getValueType() != EltType) - RHSOp = DAG.getNode(ISD::TRUNCATE, RHS.getDebugLoc(), EltType, RHSOp); - - SDValue FoldOp = DAG.getNode(N->getOpcode(), LHS.getDebugLoc(), EltType, + EVT VT = LHSOp.getValueType(); + assert(RHSOp.getValueType() == VT && + "SimplifyVBinOp with different BUILD_VECTOR element types"); + SDValue FoldOp = DAG.getNode(N->getOpcode(), LHS.getDebugLoc(), VT, LHSOp, RHSOp); if (FoldOp.getOpcode() != ISD::UNDEF && FoldOp.getOpcode() != ISD::Constant && @@ -6533,11 +6845,9 @@ SDValue DAGCombiner::SimplifyVBinOp(SDNode *N) { AddToWorkList(FoldOp.getNode()); } - if (Ops.size() == LHS.getNumOperands()) { - EVT VT = LHS.getValueType(); - return DAG.getNode(ISD::BUILD_VECTOR, N->getDebugLoc(), VT, - &Ops[0], Ops.size()); - } + if (Ops.size() == LHS.getNumOperands()) + return DAG.getNode(ISD::BUILD_VECTOR, N->getDebugLoc(), + LHS.getValueType(), &Ops[0], Ops.size()); } return SDValue(); @@ -6580,103 +6890,101 @@ SDValue DAGCombiner::SimplifySelect(DebugLoc DL, SDValue N0, bool DAGCombiner::SimplifySelectOps(SDNode *TheSelect, SDValue LHS, SDValue RHS) { + // Cannot simplify select with vector condition + if (TheSelect->getOperand(0).getValueType().isVector()) return false; + // If this is a select from two identical things, try to pull the operation // through the select. - if (LHS.getOpcode() == RHS.getOpcode() && LHS.hasOneUse() && RHS.hasOneUse()){ - // If this is a load and the token chain is identical, replace the select - // of two loads with a load through a select of the address to load from. - // This triggers in things like "select bool X, 10.0, 123.0" after the FP - // constants have been dropped into the constant pool. - if (LHS.getOpcode() == ISD::LOAD && + if (LHS.getOpcode() != RHS.getOpcode() || + !LHS.hasOneUse() || !RHS.hasOneUse()) + return false; + + // If this is a load and the token chain is identical, replace the select + // of two loads with a load through a select of the address to load from. + // This triggers in things like "select bool X, 10.0, 123.0" after the FP + // constants have been dropped into the constant pool. + if (LHS.getOpcode() == ISD::LOAD) { + LoadSDNode *LLD = cast(LHS); + LoadSDNode *RLD = cast(RHS); + + // Token chains must be identical. + if (LHS.getOperand(0) != RHS.getOperand(0) || // Do not let this transformation reduce the number of volatile loads. - !cast(LHS)->isVolatile() && - !cast(RHS)->isVolatile() && - // Token chains must be identical. - LHS.getOperand(0) == RHS.getOperand(0)) { - LoadSDNode *LLD = cast(LHS); - LoadSDNode *RLD = cast(RHS); - - // If this is an EXTLOAD, the VT's must match. - if (LLD->getMemoryVT() == RLD->getMemoryVT()) { + LLD->isVolatile() || RLD->isVolatile() || + // If this is an EXTLOAD, the VT's must match. + LLD->getMemoryVT() != RLD->getMemoryVT() || + // If this is an EXTLOAD, the kind of extension must match. + (LLD->getExtensionType() != RLD->getExtensionType() && + // The only exception is if one of the extensions is anyext. + LLD->getExtensionType() != ISD::EXTLOAD && + RLD->getExtensionType() != ISD::EXTLOAD) || // FIXME: this discards src value information. This is // over-conservative. It would be beneficial to be able to remember // both potential memory locations. Since we are discarding // src value info, don't do the transformation if the memory // locations are not in the default address space. - unsigned LLDAddrSpace = 0, RLDAddrSpace = 0; - if (const Value *LLDVal = LLD->getMemOperand()->getValue()) { - if (const PointerType *PT = dyn_cast(LLDVal->getType())) - LLDAddrSpace = PT->getAddressSpace(); - } - if (const Value *RLDVal = RLD->getMemOperand()->getValue()) { - if (const PointerType *PT = dyn_cast(RLDVal->getType())) - RLDAddrSpace = PT->getAddressSpace(); - } - SDValue Addr; - if (LLDAddrSpace == 0 && RLDAddrSpace == 0) { - if (TheSelect->getOpcode() == ISD::SELECT) { - // Check that the condition doesn't reach either load. If so, folding - // this will induce a cycle into the DAG. - if ((!LLD->hasAnyUseOfValue(1) || - !LLD->isPredecessorOf(TheSelect->getOperand(0).getNode())) && - (!RLD->hasAnyUseOfValue(1) || - !RLD->isPredecessorOf(TheSelect->getOperand(0).getNode()))) { - Addr = DAG.getNode(ISD::SELECT, TheSelect->getDebugLoc(), - LLD->getBasePtr().getValueType(), - TheSelect->getOperand(0), LLD->getBasePtr(), - RLD->getBasePtr()); - } - } else { - // Check that the condition doesn't reach either load. If so, folding - // this will induce a cycle into the DAG. - if ((!LLD->hasAnyUseOfValue(1) || - (!LLD->isPredecessorOf(TheSelect->getOperand(0).getNode()) && - !LLD->isPredecessorOf(TheSelect->getOperand(1).getNode()))) && - (!RLD->hasAnyUseOfValue(1) || - (!RLD->isPredecessorOf(TheSelect->getOperand(0).getNode()) && - !RLD->isPredecessorOf(TheSelect->getOperand(1).getNode())))) { - Addr = DAG.getNode(ISD::SELECT_CC, TheSelect->getDebugLoc(), - LLD->getBasePtr().getValueType(), - TheSelect->getOperand(0), - TheSelect->getOperand(1), - LLD->getBasePtr(), RLD->getBasePtr(), - TheSelect->getOperand(4)); - } - } - } - - if (Addr.getNode()) { - SDValue Load; - if (LLD->getExtensionType() == ISD::NON_EXTLOAD) { - Load = DAG.getLoad(TheSelect->getValueType(0), - TheSelect->getDebugLoc(), - LLD->getChain(), - Addr, 0, 0, - LLD->isVolatile(), - LLD->isNonTemporal(), - LLD->getAlignment()); - } else { - Load = DAG.getExtLoad(LLD->getExtensionType(), - TheSelect->getValueType(0), - TheSelect->getDebugLoc(), - LLD->getChain(), Addr, 0, 0, - LLD->getMemoryVT(), - LLD->isVolatile(), - LLD->isNonTemporal(), - LLD->getAlignment()); - } + LLD->getPointerInfo().getAddrSpace() != 0 || + RLD->getPointerInfo().getAddrSpace() != 0) + return false; - // Users of the select now use the result of the load. - CombineTo(TheSelect, Load); + // Check that the select condition doesn't reach either load. If so, + // folding this will induce a cycle into the DAG. If not, this is safe to + // xform, so create a select of the addresses. + SDValue Addr; + if (TheSelect->getOpcode() == ISD::SELECT) { + SDNode *CondNode = TheSelect->getOperand(0).getNode(); + if ((LLD->hasAnyUseOfValue(1) && LLD->isPredecessorOf(CondNode)) || + (RLD->hasAnyUseOfValue(1) && RLD->isPredecessorOf(CondNode))) + return false; + Addr = DAG.getNode(ISD::SELECT, TheSelect->getDebugLoc(), + LLD->getBasePtr().getValueType(), + TheSelect->getOperand(0), LLD->getBasePtr(), + RLD->getBasePtr()); + } else { // Otherwise SELECT_CC + SDNode *CondLHS = TheSelect->getOperand(0).getNode(); + SDNode *CondRHS = TheSelect->getOperand(1).getNode(); + + if ((LLD->hasAnyUseOfValue(1) && + (LLD->isPredecessorOf(CondLHS) || LLD->isPredecessorOf(CondRHS))) || + (LLD->hasAnyUseOfValue(1) && + (LLD->isPredecessorOf(CondLHS) || LLD->isPredecessorOf(CondRHS)))) + return false; - // Users of the old loads now use the new load's chain. We know the - // old-load value is dead now. - CombineTo(LHS.getNode(), Load.getValue(0), Load.getValue(1)); - CombineTo(RHS.getNode(), Load.getValue(0), Load.getValue(1)); - return true; - } - } - } + Addr = DAG.getNode(ISD::SELECT_CC, TheSelect->getDebugLoc(), + LLD->getBasePtr().getValueType(), + TheSelect->getOperand(0), + TheSelect->getOperand(1), + LLD->getBasePtr(), RLD->getBasePtr(), + TheSelect->getOperand(4)); + } + + SDValue Load; + if (LLD->getExtensionType() == ISD::NON_EXTLOAD) { + Load = DAG.getLoad(TheSelect->getValueType(0), + TheSelect->getDebugLoc(), + // FIXME: Discards pointer info. + LLD->getChain(), Addr, MachinePointerInfo(), + LLD->isVolatile(), LLD->isNonTemporal(), + LLD->getAlignment()); + } else { + Load = DAG.getExtLoad(LLD->getExtensionType() == ISD::EXTLOAD ? + RLD->getExtensionType() : LLD->getExtensionType(), + TheSelect->getDebugLoc(), + TheSelect->getValueType(0), + // FIXME: Discards pointer info. + LLD->getChain(), Addr, MachinePointerInfo(), + LLD->getMemoryVT(), LLD->isVolatile(), + LLD->isNonTemporal(), LLD->getAlignment()); + } + + // Users of the select now use the result of the load. + CombineTo(TheSelect, Load); + + // Users of the old loads now use the new load's chain. We know the + // old-load value is dead now. + CombineTo(LHS.getNode(), Load.getValue(0), Load.getValue(1)); + CombineTo(RHS.getNode(), Load.getValue(0), Load.getValue(1)); + return true; } return false; @@ -6689,7 +6997,7 @@ SDValue DAGCombiner::SimplifySelectCC(DebugLoc DL, SDValue N0, SDValue N1, ISD::CondCode CC, bool NotExtCompare) { // (x ? y : y) -> y. if (N2 == N3) return N2; - + EVT VT = N2.getValueType(); ConstantSDNode *N1C = dyn_cast(N1.getNode()); ConstantSDNode *N2C = dyn_cast(N2.getNode()); @@ -6725,7 +7033,7 @@ SDValue DAGCombiner::SimplifySelectCC(DebugLoc DL, SDValue N0, SDValue N1, return DAG.getNode(ISD::FABS, DL, VT, N3); } } - + // Turn "(a cond b) ? 1.0f : 2.0f" into "load (tmp + ((a cond b) ? 0 : 4)" // where "tmp" is a constant pool entry containing an array with 1.0 and 2.0 // in it. This is a win when the constant is not otherwise available because @@ -6748,7 +7056,7 @@ SDValue DAGCombiner::SimplifySelectCC(DebugLoc DL, SDValue N0, SDValue N1, }; const Type *FPTy = Elts[0]->getType(); const TargetData &TD = *TLI.getTargetData(); - + // Create a ConstantArray of the two constants. Constant *CA = ConstantArray::get(ArrayType::get(FPTy, 2), Elts, 2); SDValue CPIdx = DAG.getConstantPool(CA, TLI.getPointerTy(), @@ -6760,7 +7068,7 @@ SDValue DAGCombiner::SimplifySelectCC(DebugLoc DL, SDValue N0, SDValue N1, SDValue Zero = DAG.getIntPtrConstant(0); unsigned EltSize = (unsigned)TD.getTypeAllocSize(Elts[0]->getType()); SDValue One = DAG.getIntPtrConstant(EltSize); - + SDValue Cond = DAG.getSetCC(DL, TLI.getSetCCResultType(N0.getValueType()), N0, N1, CC); @@ -6769,11 +7077,11 @@ SDValue DAGCombiner::SimplifySelectCC(DebugLoc DL, SDValue N0, SDValue N1, CPIdx = DAG.getNode(ISD::ADD, DL, TLI.getPointerTy(), CPIdx, CstOffset); return DAG.getLoad(TV->getValueType(0), DL, DAG.getEntryNode(), CPIdx, - PseudoSourceValue::getConstantPool(), 0, false, + MachinePointerInfo::getConstantPool(), false, false, Alignment); } - } + } // Check to see if we can perform the "gzip trick", transforming // (select_cc setlt X, 0, A, 0) -> (and (sra X, (sub size(X), 1), A) @@ -6818,6 +7126,35 @@ SDValue DAGCombiner::SimplifySelectCC(DebugLoc DL, SDValue N0, SDValue N1, } } + // fold (select_cc seteq (and x, y), 0, 0, A) -> (and (shr (shl x)) A) + // where y is has a single bit set. + // A plaintext description would be, we can turn the SELECT_CC into an AND + // when the condition can be materialized as an all-ones register. Any + // single bit-test can be materialized as an all-ones register with + // shift-left and shift-right-arith. + if (CC == ISD::SETEQ && N0->getOpcode() == ISD::AND && + N0->getValueType(0) == VT && + N1C && N1C->isNullValue() && + N2C && N2C->isNullValue()) { + SDValue AndLHS = N0->getOperand(0); + ConstantSDNode *ConstAndRHS = dyn_cast(N0->getOperand(1)); + if (ConstAndRHS && ConstAndRHS->getAPIntValue().countPopulation() == 1) { + // Shift the tested bit over the sign bit. + APInt AndMask = ConstAndRHS->getAPIntValue(); + SDValue ShlAmt = + DAG.getConstant(AndMask.countLeadingZeros(), getShiftAmountTy()); + SDValue Shl = DAG.getNode(ISD::SHL, N0.getDebugLoc(), VT, AndLHS, ShlAmt); + + // Now arithmetic right shift it all the way over, so the result is either + // all-ones, or zero. + SDValue ShrAmt = + DAG.getConstant(AndMask.getBitWidth()-1, getShiftAmountTy()); + SDValue Shr = DAG.getNode(ISD::SRA, N0.getDebugLoc(), VT, Shl, ShrAmt); + + return DAG.getNode(ISD::AND, DL, VT, Shr, N3); + } + } + // fold select C, 16, 0 -> shl C, 4 if (N2C && N3C && N3C->isNullValue() && N2C->getAPIntValue().isPowerOf2() && TLI.getBooleanContents() == TargetLowering::ZeroOrOneBooleanContent) { @@ -6971,7 +7308,8 @@ SDValue DAGCombiner::BuildUDIV(SDNode *N) { } /// FindBaseOffset - Return true if base is a frame index, which is known not -// to alias with anything but itself. Provides base object and offset as results. +// to alias with anything but itself. Provides base object and offset as +// results. static bool FindBaseOffset(SDValue Ptr, SDValue &Base, int64_t &Offset, const GlobalValue *&GV, void *&CV) { // Assume it is a primitive operation. @@ -6984,7 +7322,7 @@ static bool FindBaseOffset(SDValue Ptr, SDValue &Base, int64_t &Offset, Offset += C->getZExtValue(); } } - + // Return the underlying GlobalValue, and update the Offset. Return false // for GlobalAddressSDNode since the same GlobalAddress may be represented // by multiple nodes with different offsets. @@ -7012,9 +7350,11 @@ static bool FindBaseOffset(SDValue Ptr, SDValue &Base, int64_t &Offset, bool DAGCombiner::isAlias(SDValue Ptr1, int64_t Size1, const Value *SrcValue1, int SrcValueOffset1, unsigned SrcValueAlign1, + const MDNode *TBAAInfo1, SDValue Ptr2, int64_t Size2, const Value *SrcValue2, int SrcValueOffset2, - unsigned SrcValueAlign2) const { + unsigned SrcValueAlign2, + const MDNode *TBAAInfo2) const { // If they are the same then they must be aliases. if (Ptr1 == Ptr2) return true; @@ -7030,8 +7370,19 @@ bool DAGCombiner::isAlias(SDValue Ptr1, int64_t Size1, if (Base1 == Base2 || (GV1 && (GV1 == GV2)) || (CV1 && (CV1 == CV2))) return !((Offset1 + Size1) <= Offset2 || (Offset2 + Size2) <= Offset1); - // If we know what the bases are, and they aren't identical, then we know they - // cannot alias. + // It is possible for different frame indices to alias each other, mostly + // when tail call optimization reuses return address slots for arguments. + // To catch this case, look up the actual index of frame indices to compute + // the real alias relationship. + if (isFrameIndex1 && isFrameIndex2) { + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + Offset1 += MFI->getObjectOffset(cast(Base1)->getIndex()); + Offset2 += MFI->getObjectOffset(cast(Base2)->getIndex()); + return !((Offset1 + Size1) <= Offset2 || (Offset2 + Size2) <= Offset1); + } + + // Otherwise, if we know what the bases are, and they aren't identical, then + // we know they cannot alias. if ((isFrameIndex1 || CV1 || GV1) && (isFrameIndex2 || CV2 || GV2)) return false; @@ -7044,20 +7395,21 @@ bool DAGCombiner::isAlias(SDValue Ptr1, int64_t Size1, (Size1 == Size2) && (SrcValueAlign1 > Size1)) { int64_t OffAlign1 = SrcValueOffset1 % SrcValueAlign1; int64_t OffAlign2 = SrcValueOffset2 % SrcValueAlign1; - + // There is no overlap between these relatively aligned accesses of similar // size, return no alias. if ((OffAlign1 + Size1) <= OffAlign2 || (OffAlign2 + Size2) <= OffAlign1) return false; } - + if (CombinerGlobalAA) { // Use alias analysis information. int64_t MinOffset = std::min(SrcValueOffset1, SrcValueOffset2); int64_t Overlap1 = Size1 + SrcValueOffset1 - MinOffset; int64_t Overlap2 = Size2 + SrcValueOffset2 - MinOffset; AliasAnalysis::AliasResult AAResult = - AA.alias(SrcValue1, Overlap1, SrcValue2, Overlap2); + AA.alias(AliasAnalysis::Location(SrcValue1, Overlap1, TBAAInfo1), + AliasAnalysis::Location(SrcValue2, Overlap2, TBAAInfo2)); if (AAResult == AliasAnalysis::NoAlias) return false; } @@ -7070,15 +7422,17 @@ bool DAGCombiner::isAlias(SDValue Ptr1, int64_t Size1, /// node. Returns true if the operand was a load. bool DAGCombiner::FindAliasInfo(SDNode *N, SDValue &Ptr, int64_t &Size, - const Value *&SrcValue, + const Value *&SrcValue, int &SrcValueOffset, - unsigned &SrcValueAlign) const { + unsigned &SrcValueAlign, + const MDNode *&TBAAInfo) const { if (LoadSDNode *LD = dyn_cast(N)) { Ptr = LD->getBasePtr(); Size = LD->getMemoryVT().getSizeInBits() >> 3; SrcValue = LD->getSrcValue(); SrcValueOffset = LD->getSrcValueOffset(); SrcValueAlign = LD->getOriginalAlignment(); + TBAAInfo = LD->getTBAAInfo(); return true; } else if (StoreSDNode *ST = dyn_cast(N)) { Ptr = ST->getBasePtr(); @@ -7086,6 +7440,7 @@ bool DAGCombiner::FindAliasInfo(SDNode *N, SrcValue = ST->getSrcValue(); SrcValueOffset = ST->getSrcValueOffset(); SrcValueAlign = ST->getOriginalAlignment(); + TBAAInfo = ST->getTBAAInfo(); } else { llvm_unreachable("FindAliasInfo expected a memory operand"); } @@ -7106,26 +7461,27 @@ void DAGCombiner::GatherAllAliases(SDNode *N, SDValue OriginalChain, const Value *SrcValue; int SrcValueOffset; unsigned SrcValueAlign; - bool IsLoad = FindAliasInfo(N, Ptr, Size, SrcValue, SrcValueOffset, - SrcValueAlign); + const MDNode *SrcTBAAInfo; + bool IsLoad = FindAliasInfo(N, Ptr, Size, SrcValue, SrcValueOffset, + SrcValueAlign, SrcTBAAInfo); // Starting off. Chains.push_back(OriginalChain); unsigned Depth = 0; - + // Look at each chain and determine if it is an alias. If so, add it to the // aliases list. If not, then continue up the chain looking for the next // candidate. while (!Chains.empty()) { SDValue Chain = Chains.back(); Chains.pop_back(); - - // For TokenFactor nodes, look at each operand and only continue up the - // chain until we find two aliases. If we've seen two aliases, assume we'll + + // For TokenFactor nodes, look at each operand and only continue up the + // chain until we find two aliases. If we've seen two aliases, assume we'll // find more and revert to original chain since the xform is unlikely to be // profitable. - // - // FIXME: The depth check could be made to return the last non-aliasing + // + // FIXME: The depth check could be made to return the last non-aliasing // chain we found before we hit a tokenfactor rather than the original // chain. if (Depth > 6 || Aliases.size() == 2) { @@ -7151,15 +7507,18 @@ void DAGCombiner::GatherAllAliases(SDNode *N, SDValue OriginalChain, const Value *OpSrcValue; int OpSrcValueOffset; unsigned OpSrcValueAlign; + const MDNode *OpSrcTBAAInfo; bool IsOpLoad = FindAliasInfo(Chain.getNode(), OpPtr, OpSize, OpSrcValue, OpSrcValueOffset, - OpSrcValueAlign); + OpSrcValueAlign, + OpSrcTBAAInfo); // If chain is alias then stop here. if (!(IsLoad && IsOpLoad) && isAlias(Ptr, Size, SrcValue, SrcValueOffset, SrcValueAlign, + SrcTBAAInfo, OpPtr, OpSize, OpSrcValue, OpSrcValueOffset, - OpSrcValueAlign)) { + OpSrcValueAlign, OpSrcTBAAInfo)) { Aliases.push_back(Chain); } else { // Look further up the chain. @@ -7206,9 +7565,9 @@ SDValue DAGCombiner::FindBetterChain(SDNode *N, SDValue OldChain) { // If a single operand then chain to it. We don't need to revisit it. return Aliases[0]; } - + // Construct a custom tailored token factor. - return DAG.getNode(ISD::TokenFactor, N->getDebugLoc(), MVT::Other, + return DAG.getNode(ISD::TokenFactor, N->getDebugLoc(), MVT::Other, &Aliases[0], Aliases.size()); } diff --git a/lib/CodeGen/SelectionDAG/FastISel.cpp b/lib/CodeGen/SelectionDAG/FastISel.cpp index a4eed71e65c0..490b857b0e9c 100644 --- a/lib/CodeGen/SelectionDAG/FastISel.cpp +++ b/lib/CodeGen/SelectionDAG/FastISel.cpp @@ -55,6 +55,7 @@ #include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Debug.h" using namespace llvm; /// startNewBlock - Set the current block to which generated machine @@ -197,12 +198,12 @@ unsigned FastISel::materializeRegForValue(const Value *V, MVT VT) { BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::IMPLICIT_DEF), Reg); } - + // If target-independent code couldn't handle the value, give target-specific // code a try. if (!Reg && isa(V)) Reg = TargetMaterializeConstant(cast(V)); - + // Don't cache constant materializations in the general ValueMap. // To do so would require tracking what uses they dominate. if (Reg != 0) { @@ -234,7 +235,7 @@ unsigned FastISel::UpdateValueMap(const Value *I, unsigned Reg) { LocalValueMap[I] = Reg; return Reg; } - + unsigned &AssignedReg = FuncInfo.ValueMap[I]; if (AssignedReg == 0) // Use the new register. @@ -414,7 +415,7 @@ bool FastISel::SelectGetElementPtr(const User *I) { // If this is a constant subscript, handle it quickly. if (const ConstantInt *CI = dyn_cast(Idx)) { if (CI->isZero()) continue; - uint64_t Offs = + uint64_t Offs = TD.getTypeAllocSize(Ty)*cast(CI)->getSExtValue(); N = FastEmit_ri_(VT, ISD::ADD, N, NIsKill, Offs, VT); if (N == 0) @@ -423,7 +424,7 @@ bool FastISel::SelectGetElementPtr(const User *I) { NIsKill = true; continue; } - + // N = N + Idx * ElementSize; uint64_t ElementSize = TD.getTypeAllocSize(Ty); std::pair Pair = getRegForGEPIndex(Idx); @@ -467,16 +468,28 @@ bool FastISel::SelectCall(const User *I) { return true; const Value *Address = DI->getAddress(); - if (!Address) + if (!Address || isa(Address) || isa(Address)) return true; - if (isa(Address)) - return true; - const AllocaInst *AI = dyn_cast(Address); - // Don't handle byval struct arguments or VLAs, for example. - if (!AI) - // Building the map above is target independent. Generating DBG_VALUE - // inline is target dependent; do this now. - (void)TargetSelectInstruction(cast(I)); + + unsigned Reg = 0; + unsigned Offset = 0; + if (const Argument *Arg = dyn_cast(Address)) { + if (Arg->hasByValAttr()) { + // Byval arguments' frame index is recorded during argument lowering. + // Use this info directly. + Offset = FuncInfo.getByValArgumentFrameIndex(Arg); + if (Offset) + Reg = TRI.getFrameRegister(*FuncInfo.MF); + } + } + if (!Reg) + Reg = getRegForValue(Address); + + if (Reg) + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(TargetOpcode::DBG_VALUE)) + .addReg(Reg, RegState::Debug).addImm(Offset) + .addMetadata(DI->getVariable()); return true; } case Intrinsic::dbg_value: { @@ -505,11 +518,8 @@ bool FastISel::SelectCall(const User *I) { } else { // We can't yet handle anything else here because it would require // generating code, thus altering codegen because of debug info. - // Insert an undef so we can see what we dropped. - BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II) - .addReg(0U).addImm(DI->getOffset()) - .addMetadata(DI->getVariable()); - } + DEBUG(dbgs() << "Dropping debug info for " << DI); + } return true; } case Intrinsic::eh_exception: { @@ -582,12 +592,12 @@ bool FastISel::SelectCall(const User *I) { bool FastISel::SelectCast(const User *I, unsigned Opcode) { EVT SrcVT = TLI.getValueType(I->getOperand(0)->getType()); EVT DstVT = TLI.getValueType(I->getType()); - + if (SrcVT == MVT::Other || !SrcVT.isSimple() || DstVT == MVT::Other || !DstVT.isSimple()) // Unhandled type. Halt "fast" selection and bail. return false; - + // Check if the destination type is legal. Or as a special case, // it may be i1 if we're doing a truncate because that's // easy and somewhat common. @@ -629,7 +639,7 @@ bool FastISel::SelectCast(const User *I, unsigned Opcode) { InputReg, InputRegIsKill); if (!ResultReg) return false; - + UpdateValueMap(I, ResultReg); return true; } @@ -644,23 +654,23 @@ bool FastISel::SelectBitCast(const User *I) { return true; } - // Bitcasts of other values become reg-reg copies or BIT_CONVERT operators. + // Bitcasts of other values become reg-reg copies or BITCAST operators. EVT SrcVT = TLI.getValueType(I->getOperand(0)->getType()); EVT DstVT = TLI.getValueType(I->getType()); - + if (SrcVT == MVT::Other || !SrcVT.isSimple() || DstVT == MVT::Other || !DstVT.isSimple() || !TLI.isTypeLegal(SrcVT) || !TLI.isTypeLegal(DstVT)) // Unhandled type. Halt "fast" selection and bail. return false; - + unsigned Op0 = getRegForValue(I->getOperand(0)); if (Op0 == 0) // Unhandled operand. Halt "fast" selection and bail. return false; bool Op0IsKill = hasTrivialKill(I->getOperand(0)); - + // First, try to perform the bitcast by inserting a reg-reg copy. unsigned ResultReg = 0; if (SrcVT.getSimpleVT() == DstVT.getSimpleVT()) { @@ -673,15 +683,15 @@ bool FastISel::SelectBitCast(const User *I) { ResultReg).addReg(Op0); } } - - // If the reg-reg copy failed, select a BIT_CONVERT opcode. + + // If the reg-reg copy failed, select a BITCAST opcode. if (!ResultReg) ResultReg = FastEmit_r(SrcVT.getSimpleVT(), DstVT.getSimpleVT(), - ISD::BIT_CONVERT, Op0, Op0IsKill); - + ISD::BITCAST, Op0, Op0IsKill); + if (!ResultReg) return false; - + UpdateValueMap(I, ResultReg); return true; } @@ -753,7 +763,7 @@ FastISel::SelectFNeg(const User *I) { return false; unsigned IntReg = FastEmit_r(VT.getSimpleVT(), IntVT.getSimpleVT(), - ISD::BIT_CONVERT, OpReg, OpRegIsKill); + ISD::BITCAST, OpReg, OpRegIsKill); if (IntReg == 0) return false; @@ -765,7 +775,7 @@ FastISel::SelectFNeg(const User *I) { return false; ResultReg = FastEmit_r(IntVT.getSimpleVT(), VT.getSimpleVT(), - ISD::BIT_CONVERT, IntResultReg, /*Kill=*/true); + ISD::BITCAST, IntResultReg, /*Kill=*/true); if (ResultReg == 0) return false; @@ -845,10 +855,10 @@ FastISel::SelectOperator(const User *I, unsigned Opcode) { // Dynamic-sized alloca is not handled yet. return false; - + case Instruction::Call: return SelectCall(I); - + case Instruction::BitCast: return SelectBitCast(I); @@ -911,7 +921,7 @@ unsigned FastISel::FastEmit_r(MVT, MVT, return 0; } -unsigned FastISel::FastEmit_rr(MVT, MVT, +unsigned FastISel::FastEmit_rr(MVT, MVT, unsigned, unsigned /*Op0*/, bool /*Op0IsKill*/, unsigned /*Op1*/, bool /*Op1IsKill*/) { @@ -1139,7 +1149,7 @@ unsigned FastISel::FastEmitInst_i(unsigned MachineInstOpcode, uint64_t Imm) { unsigned ResultReg = createResultReg(RC); const TargetInstrDesc &II = TII.get(MachineInstOpcode); - + if (II.getNumDefs() >= 1) BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, ResultReg).addImm(Imm); else { diff --git a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp index 5ef6404ee5d6..98582ba99f14 100644 --- a/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ b/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -29,7 +29,6 @@ #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetData.h" -#include "llvm/Target/TargetFrameInfo.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetOptions.h" diff --git a/lib/CodeGen/SelectionDAG/InstrEmitter.cpp b/lib/CodeGen/SelectionDAG/InstrEmitter.cpp index 61c2a90e7edc..e309defba20f 100644 --- a/lib/CodeGen/SelectionDAG/InstrEmitter.cpp +++ b/lib/CodeGen/SelectionDAG/InstrEmitter.cpp @@ -31,11 +31,11 @@ using namespace llvm; /// CountResults - The results of target nodes have register or immediate -/// operands first, then an optional chain, and optional flag operands (which do +/// operands first, then an optional chain, and optional glue operands (which do /// not go into the resulting MachineInstr). unsigned InstrEmitter::CountResults(SDNode *Node) { unsigned N = Node->getNumValues(); - while (N && Node->getValueType(N - 1) == MVT::Flag) + while (N && Node->getValueType(N - 1) == MVT::Glue) --N; if (N && Node->getValueType(N - 1) == MVT::Other) --N; // Skip over chain result. @@ -43,12 +43,12 @@ unsigned InstrEmitter::CountResults(SDNode *Node) { } /// CountOperands - The inputs to target nodes have any actual inputs first, -/// followed by an optional chain operand, then an optional flag operand. +/// followed by an optional chain operand, then an optional glue operand. /// Compute the number of actual operands that will go into the resulting /// MachineInstr. unsigned InstrEmitter::CountOperands(SDNode *Node) { unsigned N = Node->getNumOperands(); - while (N && Node->getOperand(N - 1).getValueType() == MVT::Flag) + while (N && Node->getOperand(N - 1).getValueType() == MVT::Glue) --N; if (N && Node->getOperand(N - 1).getValueType() == MVT::Other) --N; // Ignore chain if it exists. @@ -67,7 +67,7 @@ EmitCopyFromReg(SDNode *Node, unsigned ResNo, bool IsClone, bool IsCloned, if (IsClone) VRBaseMap.erase(Op); bool isNew = VRBaseMap.insert(std::make_pair(Op, SrcReg)).second; - isNew = isNew; // Silence compiler warning. + (void)isNew; // Silence compiler warning. assert(isNew && "Node emitted out of order - early"); return; } @@ -96,7 +96,7 @@ EmitCopyFromReg(SDNode *Node, unsigned ResNo, bool IsClone, bool IsCloned, if (Op.getNode() != Node || Op.getResNo() != ResNo) continue; EVT VT = Node->getValueType(Op.getResNo()); - if (VT == MVT::Other || VT == MVT::Flag) + if (VT == MVT::Other || VT == MVT::Glue) continue; Match = false; if (User->isMachineOpcode()) { @@ -150,7 +150,7 @@ EmitCopyFromReg(SDNode *Node, unsigned ResNo, bool IsClone, bool IsCloned, if (IsClone) VRBaseMap.erase(Op); bool isNew = VRBaseMap.insert(std::make_pair(Op, VRBase)).second; - isNew = isNew; // Silence compiler warning. + (void)isNew; // Silence compiler warning. assert(isNew && "Node emitted out of order - early"); } @@ -224,7 +224,7 @@ void InstrEmitter::CreateVirtualRegisters(SDNode *Node, MachineInstr *MI, if (IsClone) VRBaseMap.erase(Op); bool isNew = VRBaseMap.insert(std::make_pair(Op, VRBase)).second; - isNew = isNew; // Silence compiler warning. + (void)isNew; // Silence compiler warning. assert(isNew && "Node emitted out of order - early"); } } @@ -264,8 +264,8 @@ InstrEmitter::AddRegisterOperand(MachineInstr *MI, SDValue Op, DenseMap &VRBaseMap, bool IsDebug, bool IsClone, bool IsCloned) { assert(Op.getValueType() != MVT::Other && - Op.getValueType() != MVT::Flag && - "Chain and flag operands should occur at end of operand list!"); + Op.getValueType() != MVT::Glue && + "Chain and glue operands should occur at end of operand list!"); // Get/emit the operand. unsigned VReg = getVR(Op, VRBaseMap); assert(TargetRegisterInfo::isVirtualRegister(VReg) && "Not a vreg?"); @@ -377,8 +377,8 @@ void InstrEmitter::AddOperand(MachineInstr *MI, SDValue Op, BA->getTargetFlags())); } else { assert(Op.getValueType() != MVT::Other && - Op.getValueType() != MVT::Flag && - "Chain and flag operands should occur at end of operand list!"); + Op.getValueType() != MVT::Glue && + "Chain and glue operands should occur at end of operand list!"); AddRegisterOperand(MI, Op, IIOpNum, II, VRBaseMap, IsDebug, IsClone, IsCloned); } @@ -428,31 +428,47 @@ void InstrEmitter::EmitSubregNode(SDNode *Node, // Figure out the register class to create for the destreg. unsigned VReg = getVR(Node->getOperand(0), VRBaseMap); - const TargetRegisterClass *TRC = MRI->getRegClass(VReg); - const TargetRegisterClass *SRC = TRC->getSubRegisterRegClass(SubIdx); - assert(SRC && "Invalid subregister index in EXTRACT_SUBREG"); - - // Figure out the register class to create for the destreg. - // Note that if we're going to directly use an existing register, - // it must be precisely the required class, and not a subclass - // thereof. - if (VRBase == 0 || SRC != MRI->getRegClass(VRBase)) { - // Create the reg - assert(SRC && "Couldn't find source register class"); - VRBase = MRI->createVirtualRegister(SRC); - } + MachineInstr *DefMI = MRI->getVRegDef(VReg); + unsigned SrcReg, DstReg, DefSubIdx; + if (DefMI && + TII->isCoalescableExtInstr(*DefMI, SrcReg, DstReg, DefSubIdx) && + SubIdx == DefSubIdx) { + // Optimize these: + // r1025 = s/zext r1024, 4 + // r1026 = extract_subreg r1025, 4 + // to a copy + // r1026 = copy r1024 + const TargetRegisterClass *TRC = MRI->getRegClass(SrcReg); + VRBase = MRI->createVirtualRegister(TRC); + BuildMI(*MBB, InsertPos, Node->getDebugLoc(), + TII->get(TargetOpcode::COPY), VRBase).addReg(SrcReg); + } else { + const TargetRegisterClass *TRC = MRI->getRegClass(VReg); + const TargetRegisterClass *SRC = TRC->getSubRegisterRegClass(SubIdx); + assert(SRC && "Invalid subregister index in EXTRACT_SUBREG"); + + // Figure out the register class to create for the destreg. + // Note that if we're going to directly use an existing register, + // it must be precisely the required class, and not a subclass + // thereof. + if (VRBase == 0 || SRC != MRI->getRegClass(VRBase)) { + // Create the reg + assert(SRC && "Couldn't find source register class"); + VRBase = MRI->createVirtualRegister(SRC); + } - // Create the extract_subreg machine instruction. - MachineInstr *MI = BuildMI(*MF, Node->getDebugLoc(), - TII->get(TargetOpcode::COPY), VRBase); + // Create the extract_subreg machine instruction. + MachineInstr *MI = BuildMI(*MF, Node->getDebugLoc(), + TII->get(TargetOpcode::COPY), VRBase); - // Add source, and subreg index - AddOperand(MI, Node->getOperand(0), 0, 0, VRBaseMap, /*IsDebug=*/false, - IsClone, IsCloned); - assert(TargetRegisterInfo::isVirtualRegister(MI->getOperand(1).getReg()) && - "Cannot yet extract from physregs"); - MI->getOperand(1).setSubReg(SubIdx); - MBB->insert(InsertPos, MI); + // Add source, and subreg index + AddOperand(MI, Node->getOperand(0), 0, 0, VRBaseMap, /*IsDebug=*/false, + IsClone, IsCloned); + assert(TargetRegisterInfo::isVirtualRegister(MI->getOperand(1).getReg())&& + "Cannot yet extract from physregs"); + MI->getOperand(1).setSubReg(SubIdx); + MBB->insert(InsertPos, MI); + } } else if (Opc == TargetOpcode::INSERT_SUBREG || Opc == TargetOpcode::SUBREG_TO_REG) { SDValue N0 = Node->getOperand(0); @@ -496,7 +512,7 @@ void InstrEmitter::EmitSubregNode(SDNode *Node, SDValue Op(Node, 0); bool isNew = VRBaseMap.insert(std::make_pair(Op, VRBase)).second; - isNew = isNew; // Silence compiler warning. + (void)isNew; // Silence compiler warning. assert(isNew && "Node emitted out of order - early"); } @@ -518,7 +534,7 @@ InstrEmitter::EmitCopyToRegClassNode(SDNode *Node, SDValue Op(Node, 0); bool isNew = VRBaseMap.insert(std::make_pair(Op, NewVReg)).second; - isNew = isNew; // Silence compiler warning. + (void)isNew; // Silence compiler warning. assert(isNew && "Node emitted out of order - early"); } @@ -543,9 +559,7 @@ void InstrEmitter::EmitRegSequence(SDNode *Node, const TargetRegisterClass *TRC = MRI->getRegClass(SubReg); const TargetRegisterClass *SRC = TRI->getMatchingSuperRegClass(RC, TRC, SubIdx); - if (!SRC) - llvm_unreachable("Invalid subregister index in REG_SEQUENCE"); - if (SRC != RC) { + if (SRC && SRC != RC) { MRI->setRegClass(NewVReg, SRC); RC = SRC; } @@ -557,7 +571,7 @@ void InstrEmitter::EmitRegSequence(SDNode *Node, MBB->insert(InsertPos, MI); SDValue Op(Node, 0); bool isNew = VRBaseMap.insert(std::make_pair(Op, NewVReg)).second; - isNew = isNew; // Silence compiler warning. + (void)isNew; // Silence compiler warning. assert(isNew && "Node emitted out of order - early"); } @@ -673,10 +687,10 @@ EmitMachineNode(SDNode *Node, bool IsClone, bool IsCloned, // The MachineInstr constructor adds implicit-def operands. Scan through // these to determine which are dead. if (MI->getNumOperands() != 0 && - Node->getValueType(Node->getNumValues()-1) == MVT::Flag) { + Node->getValueType(Node->getNumValues()-1) == MVT::Glue) { // First, collect all used registers. SmallVector UsedRegs; - for (SDNode *F = Node->getFlaggedUser(); F; F = F->getFlaggedUser()) + for (SDNode *F = Node->getGluedUser(); F; F = F->getGluedUser()) if (F->getOpcode() == ISD::CopyFromReg) UsedRegs.push_back(cast(F->getOperand(1))->getReg()); else { @@ -689,7 +703,7 @@ EmitMachineNode(SDNode *Node, bool IsClone, bool IsCloned, for (unsigned i = 0, e = F->getNumOperands(); i != e; ++i) if (RegisterSDNode *R = dyn_cast(F->getOperand(i))) { unsigned Reg = R->getReg(); - if (Reg != 0 && TargetRegisterInfo::isPhysicalRegister(Reg)) + if (TargetRegisterInfo::isPhysicalRegister(Reg)) UsedRegs.push_back(Reg); } } @@ -721,20 +735,7 @@ EmitMachineNode(SDNode *Node, bool IsClone, bool IsCloned, // hook knows where in the block to insert the replacement code. MBB->insert(InsertPos, MI); - if (II.usesCustomInsertionHook()) { - // Insert this instruction into the basic block using a target - // specific inserter which may returns a new basic block. - bool AtEnd = InsertPos == MBB->end(); - MachineBasicBlock *NewMBB = TLI->EmitInstrWithCustomInserter(MI, MBB); - if (NewMBB != MBB) { - if (AtEnd) - InsertPos = NewMBB->end(); - MBB = NewMBB; - } - return; - } - - // Additional results must be an physical register def. + // Additional results must be physical register defs. if (HasPhysRegOuts) { for (unsigned i = II.getNumDefs(); i < NumResults; ++i) { unsigned Reg = II.getImplicitDefs()[i - II.getNumDefs()]; @@ -742,17 +743,17 @@ EmitMachineNode(SDNode *Node, bool IsClone, bool IsCloned, EmitCopyFromReg(Node, i, IsClone, IsCloned, Reg, VRBaseMap); // If there are no uses, mark the register as dead now, so that // MachineLICM/Sink can see that it's dead. Don't do this if the - // node has a Flag value, for the benefit of targets still using - // Flag for values in physregs. - else if (Node->getValueType(Node->getNumValues()-1) != MVT::Flag) + // node has a Glue value, for the benefit of targets still using + // Glue for values in physregs. + else if (Node->getValueType(Node->getNumValues()-1) != MVT::Glue) MI->addRegisterDead(Reg, TRI); } } // If the instruction has implicit defs and the node doesn't, mark the - // implicit def as dead. If the node has any flag outputs, we don't do this - // because we don't know what implicit defs are being used by flagged nodes. - if (Node->getValueType(Node->getNumValues()-1) != MVT::Flag) + // implicit def as dead. If the node has any glue outputs, we don't do this + // because we don't know what implicit defs are being used by glued nodes. + if (Node->getValueType(Node->getNumValues()-1) != MVT::Glue) if (const unsigned *IDList = II.getImplicitDefs()) { for (unsigned i = NumResults, e = II.getNumDefs()+II.getNumImplicitDefs(); i != e; ++i) @@ -808,8 +809,8 @@ EmitSpecialNode(SDNode *Node, bool IsClone, bool IsCloned, case ISD::INLINEASM: { unsigned NumOps = Node->getNumOperands(); - if (Node->getOperand(NumOps-1).getValueType() == MVT::Flag) - --NumOps; // Ignore the flag operand. + if (Node->getOperand(NumOps-1).getValueType() == MVT::Glue) + --NumOps; // Ignore the glue operand. // Create the inline asm machine instruction. MachineInstr *MI = BuildMI(*MF, Node->getDebugLoc(), @@ -820,11 +821,11 @@ EmitSpecialNode(SDNode *Node, bool IsClone, bool IsCloned, const char *AsmStr = cast(AsmStrV)->getSymbol(); MI->addOperand(MachineOperand::CreateES(AsmStr)); - // Add the isAlignStack bit. - int64_t isAlignStack = - cast(Node->getOperand(InlineAsm::Op_IsAlignStack))-> + // Add the HasSideEffect and isAlignStack bits. + int64_t ExtraInfo = + cast(Node->getOperand(InlineAsm::Op_ExtraInfo))-> getZExtValue(); - MI->addOperand(MachineOperand::CreateImm(isAlignStack)); + MI->addOperand(MachineOperand::CreateImm(ExtraInfo)); // Add all of the operand registers to the instruction. for (unsigned i = InlineAsm::Op_FirstOperand; i != NumOps;) { diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index 2981cd3f1cab..49c862ce3e0b 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -11,14 +11,15 @@ // //===----------------------------------------------------------------------===// -#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/Analysis/DebugInfo.h" +#include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineModuleInfo.h" -#include "llvm/Analysis/DebugInfo.h" #include "llvm/CodeGen/PseudoSourceValue.h" -#include "llvm/Target/TargetFrameInfo.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetMachine.h" @@ -65,11 +66,6 @@ class SelectionDAGLegalize { /// against each other, including inserted libcalls. SDValue LastCALLSEQ_END; - /// IsLegalizingCall - This member is used *only* for purposes of providing - /// helpful assertions that a libcall isn't created while another call is - /// being legalized (which could lead to non-serialized call sequences). - bool IsLegalizingCall; - enum LegalizeAction { Legal, // The target natively supports this operation. Promote, // This operation should be executed in a larger type. @@ -91,6 +87,9 @@ class SelectionDAGLegalize { // If someone requests legalization of the new node, return itself. if (From != To) LegalizedNodes.insert(std::make_pair(To, To)); + + // Transfer SDDbgValues. + DAG.TransferDbgValues(From, To); } public: @@ -172,6 +171,7 @@ private: SDValue ExpandBitCount(unsigned Opc, SDValue Op, DebugLoc dl); SDValue ExpandExtractFromVectorThroughStack(SDValue Op); + SDValue ExpandInsertToVectorThroughStack(SDValue Op); SDValue ExpandVectorBuildThroughStack(SDNode* Node); std::pair ExpandAtomic(SDNode *Node); @@ -224,7 +224,6 @@ SelectionDAGLegalize::SelectionDAGLegalize(SelectionDAG &dag, void SelectionDAGLegalize::LegalizeDAG() { LastCALLSEQ_END = DAG.getEntryNode(); - IsLegalizingCall = false; // The legalize process is inherently a bottom-up recursive process (users // legalize their uses before themselves). Given infinite stack space, we @@ -251,9 +250,16 @@ void SelectionDAGLegalize::LegalizeDAG() { /// FindCallEndFromCallStart - Given a chained node that is part of a call /// sequence, find the CALLSEQ_END node that terminates the call sequence. -static SDNode *FindCallEndFromCallStart(SDNode *Node) { - if (Node->getOpcode() == ISD::CALLSEQ_END) - return Node; +static SDNode *FindCallEndFromCallStart(SDNode *Node, int depth = 0) { + // Nested CALLSEQ_START/END constructs aren't yet legal, + // but we can DTRT and handle them correctly here. + if (Node->getOpcode() == ISD::CALLSEQ_START) + depth++; + else if (Node->getOpcode() == ISD::CALLSEQ_END) { + depth--; + if (depth == 0) + return Node; + } if (Node->use_empty()) return 0; // No CallSeqEnd @@ -283,7 +289,7 @@ static SDNode *FindCallEndFromCallStart(SDNode *Node) { SDNode *User = *UI; for (unsigned i = 0, e = User->getNumOperands(); i != e; ++i) if (User->getOperand(i) == TheChain) - if (SDNode *Result = FindCallEndFromCallStart(User)) + if (SDNode *Result = FindCallEndFromCallStart(User, depth)) return Result; } return 0; @@ -292,12 +298,26 @@ static SDNode *FindCallEndFromCallStart(SDNode *Node) { /// FindCallStartFromCallEnd - Given a chained node that is part of a call /// sequence, find the CALLSEQ_START node that initiates the call sequence. static SDNode *FindCallStartFromCallEnd(SDNode *Node) { + int nested = 0; assert(Node && "Didn't find callseq_start for a call??"); - if (Node->getOpcode() == ISD::CALLSEQ_START) return Node; - - assert(Node->getOperand(0).getValueType() == MVT::Other && - "Node doesn't have a token chain argument!"); - return FindCallStartFromCallEnd(Node->getOperand(0).getNode()); + while (Node->getOpcode() != ISD::CALLSEQ_START || nested) { + Node = Node->getOperand(0).getNode(); + assert(Node->getOperand(0).getValueType() == MVT::Other && + "Node doesn't have a token chain argument!"); + switch (Node->getOpcode()) { + default: + break; + case ISD::CALLSEQ_START: + if (!nested) + return Node; + nested--; + break; + case ISD::CALLSEQ_END: + nested++; + break; + } + } + return 0; } /// LegalizeAllNodesNotLeadingTo - Recursively walk the uses of N, looking to @@ -377,12 +397,12 @@ static SDValue ExpandConstantFP(ConstantFPSDNode *CFP, bool UseCP, SDValue CPIdx = DAG.getConstantPool(LLVMC, TLI.getPointerTy()); unsigned Alignment = cast(CPIdx)->getAlignment(); if (Extend) - return DAG.getExtLoad(ISD::EXTLOAD, OrigVT, dl, + return DAG.getExtLoad(ISD::EXTLOAD, dl, OrigVT, DAG.getEntryNode(), - CPIdx, PseudoSourceValue::getConstantPool(), - 0, VT, false, false, Alignment); + CPIdx, MachinePointerInfo::getConstantPool(), + VT, false, false, Alignment); return DAG.getLoad(OrigVT, dl, DAG.getEntryNode(), CPIdx, - PseudoSourceValue::getConstantPool(), 0, false, false, + MachinePointerInfo::getConstantPool(), false, false, Alignment); } @@ -395,7 +415,6 @@ SDValue ExpandUnalignedStore(StoreSDNode *ST, SelectionDAG &DAG, SDValue Val = ST->getValue(); EVT VT = Val.getValueType(); int Alignment = ST->getAlignment(); - int SVOffset = ST->getSrcValueOffset(); DebugLoc dl = ST->getDebugLoc(); if (ST->getMemoryVT().isFloatingPoint() || ST->getMemoryVT().isVector()) { @@ -404,10 +423,9 @@ SDValue ExpandUnalignedStore(StoreSDNode *ST, SelectionDAG &DAG, // Expand to a bitconvert of the value to the integer type of the // same size, then a (misaligned) int store. // FIXME: Does not handle truncating floating point stores! - SDValue Result = DAG.getNode(ISD::BIT_CONVERT, dl, intVT, Val); - return DAG.getStore(Chain, dl, Result, Ptr, ST->getSrcValue(), - SVOffset, ST->isVolatile(), ST->isNonTemporal(), - Alignment); + SDValue Result = DAG.getNode(ISD::BITCAST, dl, intVT, Val); + return DAG.getStore(Chain, dl, Result, Ptr, ST->getPointerInfo(), + ST->isVolatile(), ST->isNonTemporal(), Alignment); } else { // Do a (aligned) store to a stack slot, then copy from the stack slot // to the final destination using (unaligned) integer loads and stores. @@ -425,8 +443,8 @@ SDValue ExpandUnalignedStore(StoreSDNode *ST, SelectionDAG &DAG, // Perform the original store, only redirected to the stack slot. SDValue Store = DAG.getTruncStore(Chain, dl, - Val, StackPtr, NULL, 0, StoredVT, - false, false, 0); + Val, StackPtr, MachinePointerInfo(), + StoredVT, false, false, 0); SDValue Increment = DAG.getConstant(RegBytes, TLI.getPointerTy()); SmallVector Stores; unsigned Offset = 0; @@ -434,11 +452,12 @@ SDValue ExpandUnalignedStore(StoreSDNode *ST, SelectionDAG &DAG, // Do all but one copies using the full register width. for (unsigned i = 1; i < NumRegs; i++) { // Load one integer register's worth from the stack slot. - SDValue Load = DAG.getLoad(RegVT, dl, Store, StackPtr, NULL, 0, + SDValue Load = DAG.getLoad(RegVT, dl, Store, StackPtr, + MachinePointerInfo(), false, false, 0); // Store it to the final location. Remember the store. Stores.push_back(DAG.getStore(Load.getValue(1), dl, Load, Ptr, - ST->getSrcValue(), SVOffset + Offset, + ST->getPointerInfo().getWithOffset(Offset), ST->isVolatile(), ST->isNonTemporal(), MinAlign(ST->getAlignment(), Offset))); // Increment the pointers. @@ -455,11 +474,13 @@ SDValue ExpandUnalignedStore(StoreSDNode *ST, SelectionDAG &DAG, 8 * (StoredBytes - Offset)); // Load from the stack slot. - SDValue Load = DAG.getExtLoad(ISD::EXTLOAD, RegVT, dl, Store, StackPtr, - NULL, 0, MemVT, false, false, 0); + SDValue Load = DAG.getExtLoad(ISD::EXTLOAD, dl, RegVT, Store, StackPtr, + MachinePointerInfo(), + MemVT, false, false, 0); Stores.push_back(DAG.getTruncStore(Load.getValue(1), dl, Load, Ptr, - ST->getSrcValue(), SVOffset + Offset, + ST->getPointerInfo() + .getWithOffset(Offset), MemVT, ST->isVolatile(), ST->isNonTemporal(), MinAlign(ST->getAlignment(), Offset))); @@ -484,13 +505,13 @@ SDValue ExpandUnalignedStore(StoreSDNode *ST, SelectionDAG &DAG, // Store the two parts SDValue Store1, Store2; Store1 = DAG.getTruncStore(Chain, dl, TLI.isLittleEndian()?Lo:Hi, Ptr, - ST->getSrcValue(), SVOffset, NewStoredVT, + ST->getPointerInfo(), NewStoredVT, ST->isVolatile(), ST->isNonTemporal(), Alignment); Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, DAG.getConstant(IncrementSize, TLI.getPointerTy())); Alignment = MinAlign(Alignment, IncrementSize); Store2 = DAG.getTruncStore(Chain, dl, TLI.isLittleEndian()?Hi:Lo, Ptr, - ST->getSrcValue(), SVOffset + IncrementSize, + ST->getPointerInfo().getWithOffset(IncrementSize), NewStoredVT, ST->isVolatile(), ST->isNonTemporal(), Alignment); @@ -501,7 +522,6 @@ SDValue ExpandUnalignedStore(StoreSDNode *ST, SelectionDAG &DAG, static SDValue ExpandUnalignedLoad(LoadSDNode *LD, SelectionDAG &DAG, const TargetLowering &TLI) { - int SVOffset = LD->getSrcValueOffset(); SDValue Chain = LD->getChain(); SDValue Ptr = LD->getBasePtr(); EVT VT = LD->getValueType(0); @@ -512,74 +532,75 @@ SDValue ExpandUnalignedLoad(LoadSDNode *LD, SelectionDAG &DAG, if (TLI.isTypeLegal(intVT)) { // Expand to a (misaligned) integer load of the same size, // then bitconvert to floating point or vector. - SDValue newLoad = DAG.getLoad(intVT, dl, Chain, Ptr, LD->getSrcValue(), - SVOffset, LD->isVolatile(), + SDValue newLoad = DAG.getLoad(intVT, dl, Chain, Ptr, LD->getPointerInfo(), + LD->isVolatile(), LD->isNonTemporal(), LD->getAlignment()); - SDValue Result = DAG.getNode(ISD::BIT_CONVERT, dl, LoadedVT, newLoad); + SDValue Result = DAG.getNode(ISD::BITCAST, dl, LoadedVT, newLoad); if (VT.isFloatingPoint() && LoadedVT != VT) Result = DAG.getNode(ISD::FP_EXTEND, dl, VT, Result); SDValue Ops[] = { Result, Chain }; return DAG.getMergeValues(Ops, 2, dl); - } else { - // Copy the value to a (aligned) stack slot using (unaligned) integer - // loads and stores, then do a (aligned) load from the stack slot. - EVT RegVT = TLI.getRegisterType(*DAG.getContext(), intVT); - unsigned LoadedBytes = LoadedVT.getSizeInBits() / 8; - unsigned RegBytes = RegVT.getSizeInBits() / 8; - unsigned NumRegs = (LoadedBytes + RegBytes - 1) / RegBytes; - - // Make sure the stack slot is also aligned for the register type. - SDValue StackBase = DAG.CreateStackTemporary(LoadedVT, RegVT); - - SDValue Increment = DAG.getConstant(RegBytes, TLI.getPointerTy()); - SmallVector Stores; - SDValue StackPtr = StackBase; - unsigned Offset = 0; - - // Do all but one copies using the full register width. - for (unsigned i = 1; i < NumRegs; i++) { - // Load one integer register's worth from the original location. - SDValue Load = DAG.getLoad(RegVT, dl, Chain, Ptr, LD->getSrcValue(), - SVOffset + Offset, LD->isVolatile(), - LD->isNonTemporal(), - MinAlign(LD->getAlignment(), Offset)); - // Follow the load with a store to the stack slot. Remember the store. - Stores.push_back(DAG.getStore(Load.getValue(1), dl, Load, StackPtr, - NULL, 0, false, false, 0)); - // Increment the pointers. - Offset += RegBytes; - Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, Increment); - StackPtr = DAG.getNode(ISD::ADD, dl, StackPtr.getValueType(), StackPtr, - Increment); - } + } - // The last copy may be partial. Do an extending load. - EVT MemVT = EVT::getIntegerVT(*DAG.getContext(), - 8 * (LoadedBytes - Offset)); - SDValue Load = DAG.getExtLoad(ISD::EXTLOAD, RegVT, dl, Chain, Ptr, - LD->getSrcValue(), SVOffset + Offset, - MemVT, LD->isVolatile(), - LD->isNonTemporal(), - MinAlign(LD->getAlignment(), Offset)); + // Copy the value to a (aligned) stack slot using (unaligned) integer + // loads and stores, then do a (aligned) load from the stack slot. + EVT RegVT = TLI.getRegisterType(*DAG.getContext(), intVT); + unsigned LoadedBytes = LoadedVT.getSizeInBits() / 8; + unsigned RegBytes = RegVT.getSizeInBits() / 8; + unsigned NumRegs = (LoadedBytes + RegBytes - 1) / RegBytes; + + // Make sure the stack slot is also aligned for the register type. + SDValue StackBase = DAG.CreateStackTemporary(LoadedVT, RegVT); + + SDValue Increment = DAG.getConstant(RegBytes, TLI.getPointerTy()); + SmallVector Stores; + SDValue StackPtr = StackBase; + unsigned Offset = 0; + + // Do all but one copies using the full register width. + for (unsigned i = 1; i < NumRegs; i++) { + // Load one integer register's worth from the original location. + SDValue Load = DAG.getLoad(RegVT, dl, Chain, Ptr, + LD->getPointerInfo().getWithOffset(Offset), + LD->isVolatile(), LD->isNonTemporal(), + MinAlign(LD->getAlignment(), Offset)); // Follow the load with a store to the stack slot. Remember the store. - // On big-endian machines this requires a truncating store to ensure - // that the bits end up in the right place. - Stores.push_back(DAG.getTruncStore(Load.getValue(1), dl, Load, StackPtr, - NULL, 0, MemVT, false, false, 0)); - - // The order of the stores doesn't matter - say it with a TokenFactor. - SDValue TF = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &Stores[0], - Stores.size()); - - // Finally, perform the original load only redirected to the stack slot. - Load = DAG.getExtLoad(LD->getExtensionType(), VT, dl, TF, StackBase, - NULL, 0, LoadedVT, false, false, 0); - - // Callers expect a MERGE_VALUES node. - SDValue Ops[] = { Load, TF }; - return DAG.getMergeValues(Ops, 2, dl); + Stores.push_back(DAG.getStore(Load.getValue(1), dl, Load, StackPtr, + MachinePointerInfo(), false, false, 0)); + // Increment the pointers. + Offset += RegBytes; + Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, Increment); + StackPtr = DAG.getNode(ISD::ADD, dl, StackPtr.getValueType(), StackPtr, + Increment); } + + // The last copy may be partial. Do an extending load. + EVT MemVT = EVT::getIntegerVT(*DAG.getContext(), + 8 * (LoadedBytes - Offset)); + SDValue Load = DAG.getExtLoad(ISD::EXTLOAD, dl, RegVT, Chain, Ptr, + LD->getPointerInfo().getWithOffset(Offset), + MemVT, LD->isVolatile(), + LD->isNonTemporal(), + MinAlign(LD->getAlignment(), Offset)); + // Follow the load with a store to the stack slot. Remember the store. + // On big-endian machines this requires a truncating store to ensure + // that the bits end up in the right place. + Stores.push_back(DAG.getTruncStore(Load.getValue(1), dl, Load, StackPtr, + MachinePointerInfo(), MemVT, + false, false, 0)); + + // The order of the stores doesn't matter - say it with a TokenFactor. + SDValue TF = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &Stores[0], + Stores.size()); + + // Finally, perform the original load only redirected to the stack slot. + Load = DAG.getExtLoad(LD->getExtensionType(), dl, VT, TF, StackBase, + MachinePointerInfo(), LoadedVT, false, false, 0); + + // Callers expect a MERGE_VALUES node. + SDValue Ops[] = { Load, TF }; + return DAG.getMergeValues(Ops, 2, dl); } assert(LoadedVT.isInteger() && !LoadedVT.isVector() && "Unaligned load of unsupported type."); @@ -602,22 +623,24 @@ SDValue ExpandUnalignedLoad(LoadSDNode *LD, SelectionDAG &DAG, // Load the value in two parts SDValue Lo, Hi; if (TLI.isLittleEndian()) { - Lo = DAG.getExtLoad(ISD::ZEXTLOAD, VT, dl, Chain, Ptr, LD->getSrcValue(), - SVOffset, NewLoadedVT, LD->isVolatile(), + Lo = DAG.getExtLoad(ISD::ZEXTLOAD, dl, VT, Chain, Ptr, LD->getPointerInfo(), + NewLoadedVT, LD->isVolatile(), LD->isNonTemporal(), Alignment); Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, DAG.getConstant(IncrementSize, TLI.getPointerTy())); - Hi = DAG.getExtLoad(HiExtType, VT, dl, Chain, Ptr, LD->getSrcValue(), - SVOffset + IncrementSize, NewLoadedVT, LD->isVolatile(), + Hi = DAG.getExtLoad(HiExtType, dl, VT, Chain, Ptr, + LD->getPointerInfo().getWithOffset(IncrementSize), + NewLoadedVT, LD->isVolatile(), LD->isNonTemporal(), MinAlign(Alignment,IncrementSize)); } else { - Hi = DAG.getExtLoad(HiExtType, VT, dl, Chain, Ptr, LD->getSrcValue(), - SVOffset, NewLoadedVT, LD->isVolatile(), + Hi = DAG.getExtLoad(HiExtType, dl, VT, Chain, Ptr, LD->getPointerInfo(), + NewLoadedVT, LD->isVolatile(), LD->isNonTemporal(), Alignment); Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, DAG.getConstant(IncrementSize, TLI.getPointerTy())); - Lo = DAG.getExtLoad(ISD::ZEXTLOAD, VT, dl, Chain, Ptr, LD->getSrcValue(), - SVOffset + IncrementSize, NewLoadedVT, LD->isVolatile(), + Lo = DAG.getExtLoad(ISD::ZEXTLOAD, dl, VT, Chain, Ptr, + LD->getPointerInfo().getWithOffset(IncrementSize), + NewLoadedVT, LD->isVolatile(), LD->isNonTemporal(), MinAlign(Alignment,IncrementSize)); } @@ -660,7 +683,7 @@ PerformInsertVectorEltInMemory(SDValue Vec, SDValue Val, SDValue Idx, // Store the vector. SDValue Ch = DAG.getStore(DAG.getEntryNode(), dl, Tmp1, StackPtr, - PseudoSourceValue::getFixedStack(SPFI), 0, + MachinePointerInfo::getFixedStack(SPFI), false, false, 0); // Truncate or zero extend offset to target pointer type. @@ -671,13 +694,11 @@ PerformInsertVectorEltInMemory(SDValue Vec, SDValue Val, SDValue Idx, Tmp3 = DAG.getNode(ISD::MUL, dl, IdxVT, Tmp3,DAG.getConstant(EltSize, IdxVT)); SDValue StackPtr2 = DAG.getNode(ISD::ADD, dl, IdxVT, Tmp3, StackPtr); // Store the scalar value. - Ch = DAG.getTruncStore(Ch, dl, Tmp2, StackPtr2, - PseudoSourceValue::getFixedStack(SPFI), 0, EltVT, + Ch = DAG.getTruncStore(Ch, dl, Tmp2, StackPtr2, MachinePointerInfo(), EltVT, false, false, 0); // Load the updated vector. return DAG.getLoad(VT, dl, Ch, StackPtr, - PseudoSourceValue::getFixedStack(SPFI), 0, - false, false, 0); + MachinePointerInfo::getFixedStack(SPFI), false, false, 0); } @@ -719,7 +740,6 @@ SDValue SelectionDAGLegalize::OptimizeFloatStore(StoreSDNode* ST) { SDValue Tmp1 = ST->getChain(); SDValue Tmp2 = ST->getBasePtr(); SDValue Tmp3; - int SVOffset = ST->getSrcValueOffset(); unsigned Alignment = ST->getAlignment(); bool isVolatile = ST->isVolatile(); bool isNonTemporal = ST->isNonTemporal(); @@ -730,29 +750,34 @@ SDValue SelectionDAGLegalize::OptimizeFloatStore(StoreSDNode* ST) { Tmp3 = DAG.getConstant(CFP->getValueAPF(). bitcastToAPInt().zextOrTrunc(32), MVT::i32); - return DAG.getStore(Tmp1, dl, Tmp3, Tmp2, ST->getSrcValue(), - SVOffset, isVolatile, isNonTemporal, Alignment); - } else if (CFP->getValueType(0) == MVT::f64) { + return DAG.getStore(Tmp1, dl, Tmp3, Tmp2, ST->getPointerInfo(), + isVolatile, isNonTemporal, Alignment); + } + + if (CFP->getValueType(0) == MVT::f64) { // If this target supports 64-bit registers, do a single 64-bit store. if (getTypeAction(MVT::i64) == Legal) { Tmp3 = DAG.getConstant(CFP->getValueAPF().bitcastToAPInt(). zextOrTrunc(64), MVT::i64); - return DAG.getStore(Tmp1, dl, Tmp3, Tmp2, ST->getSrcValue(), - SVOffset, isVolatile, isNonTemporal, Alignment); - } else if (getTypeAction(MVT::i32) == Legal && !ST->isVolatile()) { + return DAG.getStore(Tmp1, dl, Tmp3, Tmp2, ST->getPointerInfo(), + isVolatile, isNonTemporal, Alignment); + } + + if (getTypeAction(MVT::i32) == Legal && !ST->isVolatile()) { // Otherwise, if the target supports 32-bit registers, use 2 32-bit // stores. If the target supports neither 32- nor 64-bits, this // xform is certainly not worth it. const APInt &IntVal =CFP->getValueAPF().bitcastToAPInt(); - SDValue Lo = DAG.getConstant(APInt(IntVal).trunc(32), MVT::i32); + SDValue Lo = DAG.getConstant(IntVal.trunc(32), MVT::i32); SDValue Hi = DAG.getConstant(IntVal.lshr(32).trunc(32), MVT::i32); if (TLI.isBigEndian()) std::swap(Lo, Hi); - Lo = DAG.getStore(Tmp1, dl, Lo, Tmp2, ST->getSrcValue(), - SVOffset, isVolatile, isNonTemporal, Alignment); + Lo = DAG.getStore(Tmp1, dl, Lo, Tmp2, ST->getPointerInfo(), isVolatile, + isNonTemporal, Alignment); Tmp2 = DAG.getNode(ISD::ADD, dl, Tmp2.getValueType(), Tmp2, DAG.getIntPtrConstant(4)); - Hi = DAG.getStore(Tmp1, dl, Hi, Tmp2, ST->getSrcValue(), SVOffset+4, + Hi = DAG.getStore(Tmp1, dl, Hi, Tmp2, + ST->getPointerInfo().getWithOffset(4), isVolatile, isNonTemporal, MinAlign(Alignment, 4U)); return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo, Hi); @@ -792,7 +817,7 @@ SDValue SelectionDAGLegalize::LegalizeOp(SDValue Op) { bool isCustom = false; // Figure out the correct action; the way to query this varies by opcode - TargetLowering::LegalizeAction Action; + TargetLowering::LegalizeAction Action = TargetLowering::Legal; bool SimpleFinishLegalizing = true; switch (Node->getOpcode()) { case ISD::INTRINSIC_W_CHAIN: @@ -860,6 +885,7 @@ SDValue SelectionDAGLegalize::LegalizeOp(SDValue Op) { case ISD::FRAME_TO_ARGS_OFFSET: case ISD::EH_SJLJ_SETJMP: case ISD::EH_SJLJ_LONGJMP: + case ISD::EH_SJLJ_DISPATCHSETUP: // These operations lie about being legal: when they claim to be legal, // they should actually be expanded. Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0)); @@ -996,6 +1022,7 @@ SDValue SelectionDAGLegalize::LegalizeOp(SDValue Op) { } break; case ISD::CALLSEQ_START: { + static int depth = 0; SDNode *CallEnd = FindCallEndFromCallStart(Node); // Recursively Legalize all of the inputs of the call end that do not lead @@ -1013,7 +1040,7 @@ SDValue SelectionDAGLegalize::LegalizeOp(SDValue Op) { // Merge in the last call to ensure that this call starts after the last // call ended. - if (LastCALLSEQ_END.getOpcode() != ISD::EntryToken) { + if (LastCALLSEQ_END.getOpcode() != ISD::EntryToken && depth == 0) { Tmp1 = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Tmp1, LastCALLSEQ_END); Tmp1 = LegalizeOp(Tmp1); @@ -1036,14 +1063,18 @@ SDValue SelectionDAGLegalize::LegalizeOp(SDValue Op) { // sequence have been legalized, legalize the call itself. During this // process, no libcalls can/will be inserted, guaranteeing that no calls // can overlap. - assert(!IsLegalizingCall && "Inconsistent sequentialization of calls!"); + + SDValue Saved_LastCALLSEQ_END = LastCALLSEQ_END ; // Note that we are selecting this call! LastCALLSEQ_END = SDValue(CallEnd, 0); - IsLegalizingCall = true; + depth++; // Legalize the call, starting from the CALLSEQ_END. LegalizeOp(LastCALLSEQ_END); - assert(!IsLegalizingCall && "CALLSEQ_END should have cleared this!"); + depth--; + assert(depth >= 0 && "Un-matched CALLSEQ_START?"); + if (depth > 0) + LastCALLSEQ_END = Saved_LastCALLSEQ_END; return Result; } case ISD::CALLSEQ_END: @@ -1062,7 +1093,7 @@ SDValue SelectionDAGLegalize::LegalizeOp(SDValue Op) { Tmp1 = LegalizeOp(Node->getOperand(0)); // Legalize the chain. // Do not try to legalize the target-specific arguments (#1+), except for // an optional flag input. - if (Node->getOperand(Node->getNumOperands()-1).getValueType() != MVT::Flag){ + if (Node->getOperand(Node->getNumOperands()-1).getValueType() != MVT::Glue){ if (Tmp1 != Node->getOperand(0)) { SmallVector Ops(Node->op_begin(), Node->op_end()); Ops[0] = Tmp1; @@ -1082,10 +1113,7 @@ SDValue SelectionDAGLegalize::LegalizeOp(SDValue Op) { Result.getResNo()); } } - assert(IsLegalizingCall && "Call sequence imbalance between start/end?"); // This finishes up call legalization. - IsLegalizingCall = false; - // If the CALLSEQ_END node has a flag, remember that we legalized it. AddLegalizedOperand(SDValue(Node, 0), Result.getValue(0)); if (Node->getNumValues() == 2) @@ -1136,11 +1164,10 @@ SDValue SelectionDAGLegalize::LegalizeOp(SDValue Op) { // Change base type to a different vector type. EVT NVT = TLI.getTypeToPromoteTo(Node->getOpcode(), VT); - Tmp1 = DAG.getLoad(NVT, dl, Tmp1, Tmp2, LD->getSrcValue(), - LD->getSrcValueOffset(), + Tmp1 = DAG.getLoad(NVT, dl, Tmp1, Tmp2, LD->getPointerInfo(), LD->isVolatile(), LD->isNonTemporal(), LD->getAlignment()); - Tmp3 = LegalizeOp(DAG.getNode(ISD::BIT_CONVERT, dl, VT, Tmp1)); + Tmp3 = LegalizeOp(DAG.getNode(ISD::BITCAST, dl, VT, Tmp1)); Tmp4 = LegalizeOp(Tmp1.getValue(1)); break; } @@ -1150,227 +1177,224 @@ SDValue SelectionDAGLegalize::LegalizeOp(SDValue Op) { AddLegalizedOperand(SDValue(Node, 0), Tmp3); AddLegalizedOperand(SDValue(Node, 1), Tmp4); return Op.getResNo() ? Tmp4 : Tmp3; - } else { - EVT SrcVT = LD->getMemoryVT(); - unsigned SrcWidth = SrcVT.getSizeInBits(); - int SVOffset = LD->getSrcValueOffset(); - unsigned Alignment = LD->getAlignment(); - bool isVolatile = LD->isVolatile(); - bool isNonTemporal = LD->isNonTemporal(); - - if (SrcWidth != SrcVT.getStoreSizeInBits() && - // Some targets pretend to have an i1 loading operation, and actually - // load an i8. This trick is correct for ZEXTLOAD because the top 7 - // bits are guaranteed to be zero; it helps the optimizers understand - // that these bits are zero. It is also useful for EXTLOAD, since it - // tells the optimizers that those bits are undefined. It would be - // nice to have an effective generic way of getting these benefits... - // Until such a way is found, don't insist on promoting i1 here. - (SrcVT != MVT::i1 || - TLI.getLoadExtAction(ExtType, MVT::i1) == TargetLowering::Promote)) { - // Promote to a byte-sized load if not loading an integral number of - // bytes. For example, promote EXTLOAD:i20 -> EXTLOAD:i24. - unsigned NewWidth = SrcVT.getStoreSizeInBits(); - EVT NVT = EVT::getIntegerVT(*DAG.getContext(), NewWidth); - SDValue Ch; - - // The extra bits are guaranteed to be zero, since we stored them that - // way. A zext load from NVT thus automatically gives zext from SrcVT. - - ISD::LoadExtType NewExtType = - ExtType == ISD::ZEXTLOAD ? ISD::ZEXTLOAD : ISD::EXTLOAD; - - Result = DAG.getExtLoad(NewExtType, Node->getValueType(0), dl, - Tmp1, Tmp2, LD->getSrcValue(), SVOffset, - NVT, isVolatile, isNonTemporal, Alignment); - - Ch = Result.getValue(1); // The chain. - - if (ExtType == ISD::SEXTLOAD) - // Having the top bits zero doesn't help when sign extending. - Result = DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, - Result.getValueType(), - Result, DAG.getValueType(SrcVT)); - else if (ExtType == ISD::ZEXTLOAD || NVT == Result.getValueType()) - // All the top bits are guaranteed to be zero - inform the optimizers. - Result = DAG.getNode(ISD::AssertZext, dl, - Result.getValueType(), Result, - DAG.getValueType(SrcVT)); - - Tmp1 = LegalizeOp(Result); - Tmp2 = LegalizeOp(Ch); - } else if (SrcWidth & (SrcWidth - 1)) { - // If not loading a power-of-2 number of bits, expand as two loads. - assert(!SrcVT.isVector() && "Unsupported extload!"); - unsigned RoundWidth = 1 << Log2_32(SrcWidth); - assert(RoundWidth < SrcWidth); - unsigned ExtraWidth = SrcWidth - RoundWidth; - assert(ExtraWidth < RoundWidth); - assert(!(RoundWidth % 8) && !(ExtraWidth % 8) && - "Load size not an integral number of bytes!"); - EVT RoundVT = EVT::getIntegerVT(*DAG.getContext(), RoundWidth); - EVT ExtraVT = EVT::getIntegerVT(*DAG.getContext(), ExtraWidth); - SDValue Lo, Hi, Ch; - unsigned IncrementSize; + } - if (TLI.isLittleEndian()) { - // EXTLOAD:i24 -> ZEXTLOAD:i16 | (shl EXTLOAD@+2:i8, 16) - // Load the bottom RoundWidth bits. - Lo = DAG.getExtLoad(ISD::ZEXTLOAD, Node->getValueType(0), dl, - Tmp1, Tmp2, - LD->getSrcValue(), SVOffset, RoundVT, isVolatile, - isNonTemporal, Alignment); - - // Load the remaining ExtraWidth bits. - IncrementSize = RoundWidth / 8; - Tmp2 = DAG.getNode(ISD::ADD, dl, Tmp2.getValueType(), Tmp2, - DAG.getIntPtrConstant(IncrementSize)); - Hi = DAG.getExtLoad(ExtType, Node->getValueType(0), dl, Tmp1, Tmp2, - LD->getSrcValue(), SVOffset + IncrementSize, - ExtraVT, isVolatile, isNonTemporal, - MinAlign(Alignment, IncrementSize)); - - // Build a factor node to remember that this load is independent of - // the other one. - Ch = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo.getValue(1), - Hi.getValue(1)); - - // Move the top bits to the right place. - Hi = DAG.getNode(ISD::SHL, dl, Hi.getValueType(), Hi, - DAG.getConstant(RoundWidth, TLI.getShiftAmountTy())); + EVT SrcVT = LD->getMemoryVT(); + unsigned SrcWidth = SrcVT.getSizeInBits(); + unsigned Alignment = LD->getAlignment(); + bool isVolatile = LD->isVolatile(); + bool isNonTemporal = LD->isNonTemporal(); + + if (SrcWidth != SrcVT.getStoreSizeInBits() && + // Some targets pretend to have an i1 loading operation, and actually + // load an i8. This trick is correct for ZEXTLOAD because the top 7 + // bits are guaranteed to be zero; it helps the optimizers understand + // that these bits are zero. It is also useful for EXTLOAD, since it + // tells the optimizers that those bits are undefined. It would be + // nice to have an effective generic way of getting these benefits... + // Until such a way is found, don't insist on promoting i1 here. + (SrcVT != MVT::i1 || + TLI.getLoadExtAction(ExtType, MVT::i1) == TargetLowering::Promote)) { + // Promote to a byte-sized load if not loading an integral number of + // bytes. For example, promote EXTLOAD:i20 -> EXTLOAD:i24. + unsigned NewWidth = SrcVT.getStoreSizeInBits(); + EVT NVT = EVT::getIntegerVT(*DAG.getContext(), NewWidth); + SDValue Ch; + + // The extra bits are guaranteed to be zero, since we stored them that + // way. A zext load from NVT thus automatically gives zext from SrcVT. + + ISD::LoadExtType NewExtType = + ExtType == ISD::ZEXTLOAD ? ISD::ZEXTLOAD : ISD::EXTLOAD; + + Result = DAG.getExtLoad(NewExtType, dl, Node->getValueType(0), + Tmp1, Tmp2, LD->getPointerInfo(), + NVT, isVolatile, isNonTemporal, Alignment); + + Ch = Result.getValue(1); // The chain. + + if (ExtType == ISD::SEXTLOAD) + // Having the top bits zero doesn't help when sign extending. + Result = DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, + Result.getValueType(), + Result, DAG.getValueType(SrcVT)); + else if (ExtType == ISD::ZEXTLOAD || NVT == Result.getValueType()) + // All the top bits are guaranteed to be zero - inform the optimizers. + Result = DAG.getNode(ISD::AssertZext, dl, + Result.getValueType(), Result, + DAG.getValueType(SrcVT)); + + Tmp1 = LegalizeOp(Result); + Tmp2 = LegalizeOp(Ch); + } else if (SrcWidth & (SrcWidth - 1)) { + // If not loading a power-of-2 number of bits, expand as two loads. + assert(!SrcVT.isVector() && "Unsupported extload!"); + unsigned RoundWidth = 1 << Log2_32(SrcWidth); + assert(RoundWidth < SrcWidth); + unsigned ExtraWidth = SrcWidth - RoundWidth; + assert(ExtraWidth < RoundWidth); + assert(!(RoundWidth % 8) && !(ExtraWidth % 8) && + "Load size not an integral number of bytes!"); + EVT RoundVT = EVT::getIntegerVT(*DAG.getContext(), RoundWidth); + EVT ExtraVT = EVT::getIntegerVT(*DAG.getContext(), ExtraWidth); + SDValue Lo, Hi, Ch; + unsigned IncrementSize; + + if (TLI.isLittleEndian()) { + // EXTLOAD:i24 -> ZEXTLOAD:i16 | (shl EXTLOAD@+2:i8, 16) + // Load the bottom RoundWidth bits. + Lo = DAG.getExtLoad(ISD::ZEXTLOAD, dl, Node->getValueType(0), + Tmp1, Tmp2, + LD->getPointerInfo(), RoundVT, isVolatile, + isNonTemporal, Alignment); + + // Load the remaining ExtraWidth bits. + IncrementSize = RoundWidth / 8; + Tmp2 = DAG.getNode(ISD::ADD, dl, Tmp2.getValueType(), Tmp2, + DAG.getIntPtrConstant(IncrementSize)); + Hi = DAG.getExtLoad(ExtType, dl, Node->getValueType(0), Tmp1, Tmp2, + LD->getPointerInfo().getWithOffset(IncrementSize), + ExtraVT, isVolatile, isNonTemporal, + MinAlign(Alignment, IncrementSize)); + + // Build a factor node to remember that this load is independent of + // the other one. + Ch = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo.getValue(1), + Hi.getValue(1)); + + // Move the top bits to the right place. + Hi = DAG.getNode(ISD::SHL, dl, Hi.getValueType(), Hi, + DAG.getConstant(RoundWidth, TLI.getShiftAmountTy())); + + // Join the hi and lo parts. + Result = DAG.getNode(ISD::OR, dl, Node->getValueType(0), Lo, Hi); + } else { + // Big endian - avoid unaligned loads. + // EXTLOAD:i24 -> (shl EXTLOAD:i16, 8) | ZEXTLOAD@+2:i8 + // Load the top RoundWidth bits. + Hi = DAG.getExtLoad(ExtType, dl, Node->getValueType(0), Tmp1, Tmp2, + LD->getPointerInfo(), RoundVT, isVolatile, + isNonTemporal, Alignment); + + // Load the remaining ExtraWidth bits. + IncrementSize = RoundWidth / 8; + Tmp2 = DAG.getNode(ISD::ADD, dl, Tmp2.getValueType(), Tmp2, + DAG.getIntPtrConstant(IncrementSize)); + Lo = DAG.getExtLoad(ISD::ZEXTLOAD, + dl, Node->getValueType(0), Tmp1, Tmp2, + LD->getPointerInfo().getWithOffset(IncrementSize), + ExtraVT, isVolatile, isNonTemporal, + MinAlign(Alignment, IncrementSize)); + + // Build a factor node to remember that this load is independent of + // the other one. + Ch = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo.getValue(1), + Hi.getValue(1)); + + // Move the top bits to the right place. + Hi = DAG.getNode(ISD::SHL, dl, Hi.getValueType(), Hi, + DAG.getConstant(ExtraWidth, TLI.getShiftAmountTy())); + + // Join the hi and lo parts. + Result = DAG.getNode(ISD::OR, dl, Node->getValueType(0), Lo, Hi); + } - // Join the hi and lo parts. - Result = DAG.getNode(ISD::OR, dl, Node->getValueType(0), Lo, Hi); + Tmp1 = LegalizeOp(Result); + Tmp2 = LegalizeOp(Ch); + } else { + switch (TLI.getLoadExtAction(ExtType, SrcVT)) { + default: assert(0 && "This action is not supported yet!"); + case TargetLowering::Custom: + isCustom = true; + // FALLTHROUGH + case TargetLowering::Legal: + Result = SDValue(DAG.UpdateNodeOperands(Result.getNode(), + Tmp1, Tmp2, LD->getOffset()), + Result.getResNo()); + Tmp1 = Result.getValue(0); + Tmp2 = Result.getValue(1); + + if (isCustom) { + Tmp3 = TLI.LowerOperation(Result, DAG); + if (Tmp3.getNode()) { + Tmp1 = LegalizeOp(Tmp3); + Tmp2 = LegalizeOp(Tmp3.getValue(1)); + } } else { - // Big endian - avoid unaligned loads. - // EXTLOAD:i24 -> (shl EXTLOAD:i16, 8) | ZEXTLOAD@+2:i8 - // Load the top RoundWidth bits. - Hi = DAG.getExtLoad(ExtType, Node->getValueType(0), dl, Tmp1, Tmp2, - LD->getSrcValue(), SVOffset, RoundVT, isVolatile, - isNonTemporal, Alignment); - - // Load the remaining ExtraWidth bits. - IncrementSize = RoundWidth / 8; - Tmp2 = DAG.getNode(ISD::ADD, dl, Tmp2.getValueType(), Tmp2, - DAG.getIntPtrConstant(IncrementSize)); - Lo = DAG.getExtLoad(ISD::ZEXTLOAD, - Node->getValueType(0), dl, Tmp1, Tmp2, - LD->getSrcValue(), SVOffset + IncrementSize, - ExtraVT, isVolatile, isNonTemporal, - MinAlign(Alignment, IncrementSize)); - - // Build a factor node to remember that this load is independent of - // the other one. - Ch = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo.getValue(1), - Hi.getValue(1)); - - // Move the top bits to the right place. - Hi = DAG.getNode(ISD::SHL, dl, Hi.getValueType(), Hi, - DAG.getConstant(ExtraWidth, TLI.getShiftAmountTy())); - - // Join the hi and lo parts. - Result = DAG.getNode(ISD::OR, dl, Node->getValueType(0), Lo, Hi); - } - - Tmp1 = LegalizeOp(Result); - Tmp2 = LegalizeOp(Ch); - } else { - switch (TLI.getLoadExtAction(ExtType, SrcVT)) { - default: assert(0 && "This action is not supported yet!"); - case TargetLowering::Custom: - isCustom = true; - // FALLTHROUGH - case TargetLowering::Legal: - Result = SDValue(DAG.UpdateNodeOperands(Result.getNode(), - Tmp1, Tmp2, LD->getOffset()), - Result.getResNo()); - Tmp1 = Result.getValue(0); - Tmp2 = Result.getValue(1); - - if (isCustom) { - Tmp3 = TLI.LowerOperation(Result, DAG); - if (Tmp3.getNode()) { - Tmp1 = LegalizeOp(Tmp3); - Tmp2 = LegalizeOp(Tmp3.getValue(1)); - } - } else { - // If this is an unaligned load and the target doesn't support it, - // expand it. - if (!TLI.allowsUnalignedMemoryAccesses(LD->getMemoryVT())) { - const Type *Ty = - LD->getMemoryVT().getTypeForEVT(*DAG.getContext()); - unsigned ABIAlignment = - TLI.getTargetData()->getABITypeAlignment(Ty); - if (LD->getAlignment() < ABIAlignment){ - Result = ExpandUnalignedLoad(cast(Result.getNode()), - DAG, TLI); - Tmp1 = Result.getOperand(0); - Tmp2 = Result.getOperand(1); - Tmp1 = LegalizeOp(Tmp1); - Tmp2 = LegalizeOp(Tmp2); - } + // If this is an unaligned load and the target doesn't support it, + // expand it. + if (!TLI.allowsUnalignedMemoryAccesses(LD->getMemoryVT())) { + const Type *Ty = + LD->getMemoryVT().getTypeForEVT(*DAG.getContext()); + unsigned ABIAlignment = + TLI.getTargetData()->getABITypeAlignment(Ty); + if (LD->getAlignment() < ABIAlignment){ + Result = ExpandUnalignedLoad(cast(Result.getNode()), + DAG, TLI); + Tmp1 = Result.getOperand(0); + Tmp2 = Result.getOperand(1); + Tmp1 = LegalizeOp(Tmp1); + Tmp2 = LegalizeOp(Tmp2); } } - break; - case TargetLowering::Expand: - if (!TLI.isLoadExtLegal(ISD::EXTLOAD, SrcVT) && isTypeLegal(SrcVT)) { - SDValue Load = DAG.getLoad(SrcVT, dl, Tmp1, Tmp2, LD->getSrcValue(), - LD->getSrcValueOffset(), - LD->isVolatile(), LD->isNonTemporal(), - LD->getAlignment()); - unsigned ExtendOp; - switch (ExtType) { - case ISD::EXTLOAD: - ExtendOp = (SrcVT.isFloatingPoint() ? - ISD::FP_EXTEND : ISD::ANY_EXTEND); - break; - case ISD::SEXTLOAD: ExtendOp = ISD::SIGN_EXTEND; break; - case ISD::ZEXTLOAD: ExtendOp = ISD::ZERO_EXTEND; break; - default: llvm_unreachable("Unexpected extend load type!"); - } - Result = DAG.getNode(ExtendOp, dl, Node->getValueType(0), Load); - Tmp1 = LegalizeOp(Result); // Relegalize new nodes. - Tmp2 = LegalizeOp(Load.getValue(1)); + } + break; + case TargetLowering::Expand: + if (!TLI.isLoadExtLegal(ISD::EXTLOAD, SrcVT) && isTypeLegal(SrcVT)) { + SDValue Load = DAG.getLoad(SrcVT, dl, Tmp1, Tmp2, + LD->getPointerInfo(), + LD->isVolatile(), LD->isNonTemporal(), + LD->getAlignment()); + unsigned ExtendOp; + switch (ExtType) { + case ISD::EXTLOAD: + ExtendOp = (SrcVT.isFloatingPoint() ? + ISD::FP_EXTEND : ISD::ANY_EXTEND); break; + case ISD::SEXTLOAD: ExtendOp = ISD::SIGN_EXTEND; break; + case ISD::ZEXTLOAD: ExtendOp = ISD::ZERO_EXTEND; break; + default: llvm_unreachable("Unexpected extend load type!"); } - // FIXME: This does not work for vectors on most targets. Sign- and - // zero-extend operations are currently folded into extending loads, - // whether they are legal or not, and then we end up here without any - // support for legalizing them. - assert(ExtType != ISD::EXTLOAD && - "EXTLOAD should always be supported!"); - // Turn the unsupported load into an EXTLOAD followed by an explicit - // zero/sign extend inreg. - Result = DAG.getExtLoad(ISD::EXTLOAD, Node->getValueType(0), dl, - Tmp1, Tmp2, LD->getSrcValue(), - LD->getSrcValueOffset(), SrcVT, - LD->isVolatile(), LD->isNonTemporal(), - LD->getAlignment()); - SDValue ValRes; - if (ExtType == ISD::SEXTLOAD) - ValRes = DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, - Result.getValueType(), - Result, DAG.getValueType(SrcVT)); - else - ValRes = DAG.getZeroExtendInReg(Result, dl, SrcVT); - Tmp1 = LegalizeOp(ValRes); // Relegalize new nodes. - Tmp2 = LegalizeOp(Result.getValue(1)); // Relegalize new nodes. + Result = DAG.getNode(ExtendOp, dl, Node->getValueType(0), Load); + Tmp1 = LegalizeOp(Result); // Relegalize new nodes. + Tmp2 = LegalizeOp(Load.getValue(1)); break; } + // FIXME: This does not work for vectors on most targets. Sign- and + // zero-extend operations are currently folded into extending loads, + // whether they are legal or not, and then we end up here without any + // support for legalizing them. + assert(ExtType != ISD::EXTLOAD && + "EXTLOAD should always be supported!"); + // Turn the unsupported load into an EXTLOAD followed by an explicit + // zero/sign extend inreg. + Result = DAG.getExtLoad(ISD::EXTLOAD, dl, Node->getValueType(0), + Tmp1, Tmp2, LD->getPointerInfo(), SrcVT, + LD->isVolatile(), LD->isNonTemporal(), + LD->getAlignment()); + SDValue ValRes; + if (ExtType == ISD::SEXTLOAD) + ValRes = DAG.getNode(ISD::SIGN_EXTEND_INREG, dl, + Result.getValueType(), + Result, DAG.getValueType(SrcVT)); + else + ValRes = DAG.getZeroExtendInReg(Result, dl, SrcVT.getScalarType()); + Tmp1 = LegalizeOp(ValRes); // Relegalize new nodes. + Tmp2 = LegalizeOp(Result.getValue(1)); // Relegalize new nodes. + break; } - - // Since loads produce two values, make sure to remember that we legalized - // both of them. - AddLegalizedOperand(SDValue(Node, 0), Tmp1); - AddLegalizedOperand(SDValue(Node, 1), Tmp2); - return Op.getResNo() ? Tmp2 : Tmp1; } + + // Since loads produce two values, make sure to remember that we legalized + // both of them. + AddLegalizedOperand(SDValue(Node, 0), Tmp1); + AddLegalizedOperand(SDValue(Node, 1), Tmp2); + return Op.getResNo() ? Tmp2 : Tmp1; } case ISD::STORE: { StoreSDNode *ST = cast(Node); Tmp1 = LegalizeOp(ST->getChain()); // Legalize the chain. Tmp2 = LegalizeOp(ST->getBasePtr()); // Legalize the pointer. - int SVOffset = ST->getSrcValueOffset(); unsigned Alignment = ST->getAlignment(); bool isVolatile = ST->isVolatile(); bool isNonTemporal = ST->isNonTemporal(); @@ -1408,10 +1432,10 @@ SDValue SelectionDAGLegalize::LegalizeOp(SDValue Op) { break; case TargetLowering::Promote: assert(VT.isVector() && "Unknown legal promote case!"); - Tmp3 = DAG.getNode(ISD::BIT_CONVERT, dl, + Tmp3 = DAG.getNode(ISD::BITCAST, dl, TLI.getTypeToPromoteTo(ISD::STORE, VT), Tmp3); Result = DAG.getStore(Tmp1, dl, Tmp3, Tmp2, - ST->getSrcValue(), SVOffset, isVolatile, + ST->getPointerInfo(), isVolatile, isNonTemporal, Alignment); break; } @@ -1430,9 +1454,8 @@ SDValue SelectionDAGLegalize::LegalizeOp(SDValue Op) { EVT NVT = EVT::getIntegerVT(*DAG.getContext(), StVT.getStoreSizeInBits()); Tmp3 = DAG.getZeroExtendInReg(Tmp3, dl, StVT); - Result = DAG.getTruncStore(Tmp1, dl, Tmp3, Tmp2, ST->getSrcValue(), - SVOffset, NVT, isVolatile, isNonTemporal, - Alignment); + Result = DAG.getTruncStore(Tmp1, dl, Tmp3, Tmp2, ST->getPointerInfo(), + NVT, isVolatile, isNonTemporal, Alignment); } else if (StWidth & (StWidth - 1)) { // If not storing a power-of-2 number of bits, expand as two stores. assert(!StVT.isVector() && "Unsupported truncstore!"); @@ -1450,8 +1473,8 @@ SDValue SelectionDAGLegalize::LegalizeOp(SDValue Op) { if (TLI.isLittleEndian()) { // TRUNCSTORE:i24 X -> TRUNCSTORE:i16 X, TRUNCSTORE@+2:i8 (srl X, 16) // Store the bottom RoundWidth bits. - Lo = DAG.getTruncStore(Tmp1, dl, Tmp3, Tmp2, ST->getSrcValue(), - SVOffset, RoundVT, + Lo = DAG.getTruncStore(Tmp1, dl, Tmp3, Tmp2, ST->getPointerInfo(), + RoundVT, isVolatile, isNonTemporal, Alignment); // Store the remaining ExtraWidth bits. @@ -1460,9 +1483,9 @@ SDValue SelectionDAGLegalize::LegalizeOp(SDValue Op) { DAG.getIntPtrConstant(IncrementSize)); Hi = DAG.getNode(ISD::SRL, dl, Tmp3.getValueType(), Tmp3, DAG.getConstant(RoundWidth, TLI.getShiftAmountTy())); - Hi = DAG.getTruncStore(Tmp1, dl, Hi, Tmp2, ST->getSrcValue(), - SVOffset + IncrementSize, ExtraVT, isVolatile, - isNonTemporal, + Hi = DAG.getTruncStore(Tmp1, dl, Hi, Tmp2, + ST->getPointerInfo().getWithOffset(IncrementSize), + ExtraVT, isVolatile, isNonTemporal, MinAlign(Alignment, IncrementSize)); } else { // Big endian - avoid unaligned stores. @@ -1470,17 +1493,16 @@ SDValue SelectionDAGLegalize::LegalizeOp(SDValue Op) { // Store the top RoundWidth bits. Hi = DAG.getNode(ISD::SRL, dl, Tmp3.getValueType(), Tmp3, DAG.getConstant(ExtraWidth, TLI.getShiftAmountTy())); - Hi = DAG.getTruncStore(Tmp1, dl, Hi, Tmp2, ST->getSrcValue(), - SVOffset, RoundVT, isVolatile, isNonTemporal, - Alignment); + Hi = DAG.getTruncStore(Tmp1, dl, Hi, Tmp2, ST->getPointerInfo(), + RoundVT, isVolatile, isNonTemporal, Alignment); // Store the remaining ExtraWidth bits. IncrementSize = RoundWidth / 8; Tmp2 = DAG.getNode(ISD::ADD, dl, Tmp2.getValueType(), Tmp2, DAG.getIntPtrConstant(IncrementSize)); - Lo = DAG.getTruncStore(Tmp1, dl, Tmp3, Tmp2, ST->getSrcValue(), - SVOffset + IncrementSize, ExtraVT, isVolatile, - isNonTemporal, + Lo = DAG.getTruncStore(Tmp1, dl, Tmp3, Tmp2, + ST->getPointerInfo().getWithOffset(IncrementSize), + ExtraVT, isVolatile, isNonTemporal, MinAlign(Alignment, IncrementSize)); } @@ -1514,9 +1536,8 @@ SDValue SelectionDAGLegalize::LegalizeOp(SDValue Op) { // TRUNCSTORE:i16 i32 -> STORE i16 assert(isTypeLegal(StVT) && "Do not know how to expand this store!"); Tmp3 = DAG.getNode(ISD::TRUNCATE, dl, StVT, Tmp3); - Result = DAG.getStore(Tmp1, dl, Tmp3, Tmp2, ST->getSrcValue(), - SVOffset, isVolatile, isNonTemporal, - Alignment); + Result = DAG.getStore(Tmp1, dl, Tmp3, Tmp2, ST->getPointerInfo(), + isVolatile, isNonTemporal, Alignment); break; } } @@ -1543,8 +1564,8 @@ SDValue SelectionDAGLegalize::ExpandExtractFromVectorThroughStack(SDValue Op) { DebugLoc dl = Op.getDebugLoc(); // Store the value to a temporary stack slot, then LOAD the returned part. SDValue StackPtr = DAG.CreateStackTemporary(Vec.getValueType()); - SDValue Ch = DAG.getStore(DAG.getEntryNode(), dl, Vec, StackPtr, NULL, 0, - false, false, 0); + SDValue Ch = DAG.getStore(DAG.getEntryNode(), dl, Vec, StackPtr, + MachinePointerInfo(), false, false, 0); // Add the offset to the index. unsigned EltSize = @@ -1560,12 +1581,56 @@ SDValue SelectionDAGLegalize::ExpandExtractFromVectorThroughStack(SDValue Op) { StackPtr = DAG.getNode(ISD::ADD, dl, Idx.getValueType(), Idx, StackPtr); if (Op.getValueType().isVector()) - return DAG.getLoad(Op.getValueType(), dl, Ch, StackPtr, NULL, 0, + return DAG.getLoad(Op.getValueType(), dl, Ch, StackPtr,MachinePointerInfo(), false, false, 0); + return DAG.getExtLoad(ISD::EXTLOAD, dl, Op.getValueType(), Ch, StackPtr, + MachinePointerInfo(), + Vec.getValueType().getVectorElementType(), + false, false, 0); +} + +SDValue SelectionDAGLegalize::ExpandInsertToVectorThroughStack(SDValue Op) { + assert(Op.getValueType().isVector() && "Non-vector insert subvector!"); + + SDValue Vec = Op.getOperand(0); + SDValue Part = Op.getOperand(1); + SDValue Idx = Op.getOperand(2); + DebugLoc dl = Op.getDebugLoc(); + + // Store the value to a temporary stack slot, then LOAD the returned part. + + SDValue StackPtr = DAG.CreateStackTemporary(Vec.getValueType()); + int FI = cast(StackPtr.getNode())->getIndex(); + MachinePointerInfo PtrInfo = MachinePointerInfo::getFixedStack(FI); + + // First store the whole vector. + SDValue Ch = DAG.getStore(DAG.getEntryNode(), dl, Vec, StackPtr, PtrInfo, + false, false, 0); + + // Then store the inserted part. + + // Add the offset to the index. + unsigned EltSize = + Vec.getValueType().getVectorElementType().getSizeInBits()/8; + + Idx = DAG.getNode(ISD::MUL, dl, Idx.getValueType(), Idx, + DAG.getConstant(EltSize, Idx.getValueType())); + + if (Idx.getValueType().bitsGT(TLI.getPointerTy())) + Idx = DAG.getNode(ISD::TRUNCATE, dl, TLI.getPointerTy(), Idx); else - return DAG.getExtLoad(ISD::EXTLOAD, Op.getValueType(), dl, Ch, StackPtr, - NULL, 0, Vec.getValueType().getVectorElementType(), - false, false, 0); + Idx = DAG.getNode(ISD::ZERO_EXTEND, dl, TLI.getPointerTy(), Idx); + + SDValue SubStackPtr = DAG.getNode(ISD::ADD, dl, Idx.getValueType(), Idx, + StackPtr); + + // Store the subvector. + Ch = DAG.getStore(DAG.getEntryNode(), dl, Part, SubStackPtr, + MachinePointerInfo(), false, false, 0); + + // Finally, load the updated vector. + return DAG.getLoad(Op.getValueType(), dl, Ch, StackPtr, PtrInfo, + false, false, 0); } SDValue SelectionDAGLegalize::ExpandVectorBuildThroughStack(SDNode* Node) { @@ -1578,7 +1643,7 @@ SDValue SelectionDAGLegalize::ExpandVectorBuildThroughStack(SDNode* Node) { DebugLoc dl = Node->getDebugLoc(); SDValue FIPtr = DAG.CreateStackTemporary(VT); int FI = cast(FIPtr.getNode())->getIndex(); - const Value *SV = PseudoSourceValue::getFixedStack(FI); + MachinePointerInfo PtrInfo = MachinePointerInfo::getFixedStack(FI); // Emit a store of each element to the stack slot. SmallVector Stores; @@ -1597,11 +1662,13 @@ SDValue SelectionDAGLegalize::ExpandVectorBuildThroughStack(SDNode* Node) { // element type, only store the bits necessary. if (EltVT.bitsLT(Node->getOperand(i).getValueType().getScalarType())) { Stores.push_back(DAG.getTruncStore(DAG.getEntryNode(), dl, - Node->getOperand(i), Idx, SV, Offset, + Node->getOperand(i), Idx, + PtrInfo.getWithOffset(Offset), EltVT, false, false, 0)); } else Stores.push_back(DAG.getStore(DAG.getEntryNode(), dl, - Node->getOperand(i), Idx, SV, Offset, + Node->getOperand(i), Idx, + PtrInfo.getWithOffset(Offset), false, false, 0)); } @@ -1613,7 +1680,7 @@ SDValue SelectionDAGLegalize::ExpandVectorBuildThroughStack(SDNode* Node) { StoreChain = DAG.getEntryNode(); // Result is a load from the stack slot. - return DAG.getLoad(VT, dl, StoreChain, FIPtr, SV, 0, false, false, 0); + return DAG.getLoad(VT, dl, StoreChain, FIPtr, PtrInfo, false, false, 0); } SDValue SelectionDAGLegalize::ExpandFCOPYSIGN(SDNode* Node) { @@ -1628,7 +1695,7 @@ SDValue SelectionDAGLegalize::ExpandFCOPYSIGN(SDNode* Node) { EVT IVT = EVT::getIntegerVT(*DAG.getContext(), FloatVT.getSizeInBits()); if (isTypeLegal(IVT)) { // Convert to an integer with the same sign bit. - SignBit = DAG.getNode(ISD::BIT_CONVERT, dl, IVT, Tmp2); + SignBit = DAG.getNode(ISD::BITCAST, dl, IVT, Tmp2); } else { // Store the float to memory, then load the sign part out as an integer. MVT LoadTy = TLI.getPointerTy(); @@ -1636,12 +1703,13 @@ SDValue SelectionDAGLegalize::ExpandFCOPYSIGN(SDNode* Node) { SDValue StackPtr = DAG.CreateStackTemporary(FloatVT, LoadTy); // Then store the float to it. SDValue Ch = - DAG.getStore(DAG.getEntryNode(), dl, Tmp2, StackPtr, NULL, 0, + DAG.getStore(DAG.getEntryNode(), dl, Tmp2, StackPtr, MachinePointerInfo(), false, false, 0); if (TLI.isBigEndian()) { assert(FloatVT.isByteSized() && "Unsupported floating point type!"); // Load out a legal integer with the same sign bit as the float. - SignBit = DAG.getLoad(LoadTy, dl, Ch, StackPtr, NULL, 0, false, false, 0); + SignBit = DAG.getLoad(LoadTy, dl, Ch, StackPtr, MachinePointerInfo(), + false, false, 0); } else { // Little endian SDValue LoadPtr = StackPtr; // The float may be wider than the integer we are going to load. Advance @@ -1651,7 +1719,8 @@ SDValue SelectionDAGLegalize::ExpandFCOPYSIGN(SDNode* Node) { LoadPtr = DAG.getNode(ISD::ADD, dl, LoadPtr.getValueType(), LoadPtr, DAG.getIntPtrConstant(ByteOffset)); // Load a legal integer containing the sign bit. - SignBit = DAG.getLoad(LoadTy, dl, Ch, LoadPtr, NULL, 0, false, false, 0); + SignBit = DAG.getLoad(LoadTy, dl, Ch, LoadPtr, MachinePointerInfo(), + false, false, 0); // Move the sign bit to the top bit of the loaded integer. unsigned BitShift = LoadTy.getSizeInBits() - (FloatVT.getSizeInBits() - 8 * ByteOffset); @@ -1694,7 +1763,7 @@ void SelectionDAGLegalize::ExpandDYNAMIC_STACKALLOC(SDNode* Node, SDValue SP = DAG.getCopyFromReg(Chain, dl, SPReg, VT); Chain = SP.getValue(1); unsigned Align = cast(Tmp3)->getZExtValue(); - unsigned StackAlign = TM.getFrameInfo()->getStackAlignment(); + unsigned StackAlign = TM.getFrameLowering()->getStackAlignment(); if (Align > StackAlign) SP = DAG.getNode(ISD::AND, dl, VT, SP, DAG.getConstant(-(uint64_t)Align, VT)); @@ -1768,7 +1837,7 @@ SDValue SelectionDAGLegalize::EmitStackConvert(SDValue SrcOp, FrameIndexSDNode *StackPtrFI = cast(FIPtr); int SPFI = StackPtrFI->getIndex(); - const Value *SV = PseudoSourceValue::getFixedStack(SPFI); + MachinePointerInfo PtrInfo = MachinePointerInfo::getFixedStack(SPFI); unsigned SrcSize = SrcOp.getValueType().getSizeInBits(); unsigned SlotSize = SlotVT.getSizeInBits(); @@ -1782,21 +1851,21 @@ SDValue SelectionDAGLegalize::EmitStackConvert(SDValue SrcOp, if (SrcSize > SlotSize) Store = DAG.getTruncStore(DAG.getEntryNode(), dl, SrcOp, FIPtr, - SV, 0, SlotVT, false, false, SrcAlign); + PtrInfo, SlotVT, false, false, SrcAlign); else { assert(SrcSize == SlotSize && "Invalid store"); Store = DAG.getStore(DAG.getEntryNode(), dl, SrcOp, FIPtr, - SV, 0, false, false, SrcAlign); + PtrInfo, false, false, SrcAlign); } // Result is a load from the stack slot. if (SlotSize == DestSize) - return DAG.getLoad(DestVT, dl, Store, FIPtr, SV, 0, false, false, - DestAlign); + return DAG.getLoad(DestVT, dl, Store, FIPtr, PtrInfo, + false, false, DestAlign); assert(SlotSize < DestSize && "Unknown extension!"); - return DAG.getExtLoad(ISD::EXTLOAD, DestVT, dl, Store, FIPtr, SV, 0, SlotVT, - false, false, DestAlign); + return DAG.getExtLoad(ISD::EXTLOAD, dl, DestVT, Store, FIPtr, + PtrInfo, SlotVT, false, false, DestAlign); } SDValue SelectionDAGLegalize::ExpandSCALAR_TO_VECTOR(SDNode *Node) { @@ -1810,11 +1879,11 @@ SDValue SelectionDAGLegalize::ExpandSCALAR_TO_VECTOR(SDNode *Node) { SDValue Ch = DAG.getTruncStore(DAG.getEntryNode(), dl, Node->getOperand(0), StackPtr, - PseudoSourceValue::getFixedStack(SPFI), 0, + MachinePointerInfo::getFixedStack(SPFI), Node->getValueType(0).getVectorElementType(), false, false, 0); return DAG.getLoad(Node->getValueType(0), dl, Ch, StackPtr, - PseudoSourceValue::getFixedStack(SPFI), 0, + MachinePointerInfo::getFixedStack(SPFI), false, false, 0); } @@ -1888,7 +1957,7 @@ SDValue SelectionDAGLegalize::ExpandBUILD_VECTOR(SDNode *Node) { SDValue CPIdx = DAG.getConstantPool(CP, TLI.getPointerTy()); unsigned Alignment = cast(CPIdx)->getAlignment(); return DAG.getLoad(VT, dl, DAG.getEntryNode(), CPIdx, - PseudoSourceValue::getConstantPool(), 0, + MachinePointerInfo::getConstantPool(), false, false, Alignment); } @@ -1924,7 +1993,6 @@ SDValue SelectionDAGLegalize::ExpandBUILD_VECTOR(SDNode *Node) { // and leave the Hi part unset. SDValue SelectionDAGLegalize::ExpandLibCall(RTLIB::Libcall LC, SDNode *Node, bool isSigned) { - assert(!IsLegalizingCall && "Cannot overlap legalization of calls!"); // The input chain to this libcall is the entry node of the function. // Legalizing the call will automatically add the previous call to the // dependence. @@ -1945,12 +2013,20 @@ SDValue SelectionDAGLegalize::ExpandLibCall(RTLIB::Libcall LC, SDNode *Node, // Splice the libcall in wherever FindInputOutputChains tells us to. const Type *RetTy = Node->getValueType(0).getTypeForEVT(*DAG.getContext()); + + // isTailCall may be true since the callee does not reference caller stack + // frame. Check if it's in the right position. + bool isTailCall = isInTailCallPosition(DAG, Node, TLI); std::pair CallInfo = TLI.LowerCallTo(InChain, RetTy, isSigned, !isSigned, false, false, - 0, TLI.getLibcallCallingConv(LC), false, + 0, TLI.getLibcallCallingConv(LC), isTailCall, /*isReturnValueUsed=*/true, Callee, Args, DAG, Node->getDebugLoc()); + if (!CallInfo.second.getNode()) + // It's a tailcall, return the chain (which is the DAG root). + return DAG.getRoot(); + // Legalize the call sequence, starting with the chain. This will advance // the LastCALLSEQ_END to the legalized version of the CALLSEQ_END node that // was added by LowerCallTo (guaranteeing proper serialization of calls). @@ -1964,7 +2040,6 @@ std::pair SelectionDAGLegalize::ExpandChainLibCall(RTLIB::Libcall LC, SDNode *Node, bool isSigned) { - assert(!IsLegalizingCall && "Cannot overlap legalization of calls!"); SDValue InChain = Node->getOperand(0); TargetLowering::ArgListTy Args; @@ -1985,7 +2060,7 @@ SelectionDAGLegalize::ExpandChainLibCall(RTLIB::Libcall LC, const Type *RetTy = Node->getValueType(0).getTypeForEVT(*DAG.getContext()); std::pair CallInfo = TLI.LowerCallTo(InChain, RetTy, isSigned, !isSigned, false, false, - 0, TLI.getLibcallCallingConv(LC), false, + 0, TLI.getLibcallCallingConv(LC), /*isTailCall=*/false, /*isReturnValueUsed=*/true, Callee, Args, DAG, Node->getDebugLoc()); @@ -2064,16 +2139,17 @@ SDValue SelectionDAGLegalize::ExpandLegalINT_TO_FP(bool isSigned, } // store the lo of the constructed double - based on integer input SDValue Store1 = DAG.getStore(DAG.getEntryNode(), dl, - Op0Mapped, Lo, NULL, 0, + Op0Mapped, Lo, MachinePointerInfo(), false, false, 0); // initial hi portion of constructed double SDValue InitialHi = DAG.getConstant(0x43300000u, MVT::i32); // store the hi of the constructed double - biased exponent - SDValue Store2=DAG.getStore(Store1, dl, InitialHi, Hi, NULL, 0, - false, false, 0); + SDValue Store2 = DAG.getStore(Store1, dl, InitialHi, Hi, + MachinePointerInfo(), + false, false, 0); // load the constructed double - SDValue Load = DAG.getLoad(MVT::f64, dl, Store2, StackSlot, NULL, 0, - false, false, 0); + SDValue Load = DAG.getLoad(MVT::f64, dl, Store2, StackSlot, + MachinePointerInfo(), false, false, 0); // FP constant to bias correct the final result SDValue Bias = DAG.getConstantFP(isSigned ? BitsToDouble(0x4330000080000000ULL) : @@ -2116,17 +2192,40 @@ SDValue SelectionDAGLegalize::ExpandLegalINT_TO_FP(bool isSigned, DAG.getConstant(32, MVT::i64)); SDValue LoOr = DAG.getNode(ISD::OR, dl, MVT::i64, Lo, TwoP52); SDValue HiOr = DAG.getNode(ISD::OR, dl, MVT::i64, Hi, TwoP84); - SDValue LoFlt = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::f64, LoOr); - SDValue HiFlt = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::f64, HiOr); + SDValue LoFlt = DAG.getNode(ISD::BITCAST, dl, MVT::f64, LoOr); + SDValue HiFlt = DAG.getNode(ISD::BITCAST, dl, MVT::f64, HiOr); SDValue HiSub = DAG.getNode(ISD::FSUB, dl, MVT::f64, HiFlt, TwoP84PlusTwoP52); return DAG.getNode(ISD::FADD, dl, MVT::f64, LoFlt, HiSub); } - // Implementation of unsigned i64 to f32. This implementation has the - // advantage of performing rounding correctly. + // Implementation of unsigned i64 to f32. // TODO: Generalize this for use with other types. if (Op0.getValueType() == MVT::i64 && DestVT == MVT::f32) { + // For unsigned conversions, convert them to signed conversions using the + // algorithm from the x86_64 __floatundidf in compiler_rt. + if (!isSigned) { + SDValue Fast = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::f32, Op0); + + SDValue ShiftConst = DAG.getConstant(1, TLI.getShiftAmountTy()); + SDValue Shr = DAG.getNode(ISD::SRL, dl, MVT::i64, Op0, ShiftConst); + SDValue AndConst = DAG.getConstant(1, MVT::i64); + SDValue And = DAG.getNode(ISD::AND, dl, MVT::i64, Op0, AndConst); + SDValue Or = DAG.getNode(ISD::OR, dl, MVT::i64, And, Shr); + + SDValue SignCvt = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::f32, Or); + SDValue Slow = DAG.getNode(ISD::FADD, dl, MVT::f32, SignCvt, SignCvt); + + // TODO: This really should be implemented using a branch rather than a + // select. We happen to get lucky and machinesink does the right + // thing most of the time. This would be a good candidate for a + //pseudo-op, or, even better, for whole-function isel. + SDValue SignBitTest = DAG.getSetCC(dl, TLI.getSetCCResultType(MVT::i64), + Op0, DAG.getConstant(0, MVT::i64), ISD::SETLT); + return DAG.getNode(ISD::SELECT, dl, MVT::f32, SignBitTest, Slow, Fast); + } + + // Otherwise, implement the fully general conversion. EVT SHVT = TLI.getShiftAmountTy(); SDValue And = DAG.getNode(ISD::AND, dl, MVT::i64, Op0, @@ -2140,7 +2239,7 @@ SDValue SelectionDAGLegalize::ExpandLegalINT_TO_FP(bool isSigned, SDValue Sel = DAG.getNode(ISD::SELECT, dl, MVT::i64, Ne, Or, Op0); SDValue Ge = DAG.getSetCC(dl, TLI.getSetCCResultType(MVT::i64), Op0, DAG.getConstant(UINT64_C(0x0020000000000000), MVT::i64), - ISD::SETUGE); + ISD::SETUGE); SDValue Sel2 = DAG.getNode(ISD::SELECT, dl, MVT::i64, Ge, Sel, Op0); SDValue Sh = DAG.getNode(ISD::SRL, dl, MVT::i64, Sel2, @@ -2155,7 +2254,6 @@ SDValue SelectionDAGLegalize::ExpandLegalINT_TO_FP(bool isSigned, SDValue Fadd = DAG.getNode(ISD::FADD, dl, MVT::f64, Fmul, Fcvt2); return DAG.getNode(ISD::FP_ROUND, dl, MVT::f32, Fadd, DAG.getIntPtrConstant(0)); - } SDValue Tmp1 = DAG.getNode(ISD::SINT_TO_FP, dl, DestVT, Op0); @@ -2189,13 +2287,13 @@ SDValue SelectionDAGLegalize::ExpandLegalINT_TO_FP(bool isSigned, SDValue FudgeInReg; if (DestVT == MVT::f32) FudgeInReg = DAG.getLoad(MVT::f32, dl, DAG.getEntryNode(), CPIdx, - PseudoSourceValue::getConstantPool(), 0, + MachinePointerInfo::getConstantPool(), false, false, Alignment); else { FudgeInReg = - LegalizeOp(DAG.getExtLoad(ISD::EXTLOAD, DestVT, dl, + LegalizeOp(DAG.getExtLoad(ISD::EXTLOAD, dl, DestVT, DAG.getEntryNode(), CPIdx, - PseudoSourceValue::getConstantPool(), 0, + MachinePointerInfo::getConstantPool(), MVT::f32, false, false, Alignment)); } @@ -2332,6 +2430,18 @@ SDValue SelectionDAGLegalize::ExpandBSWAP(SDValue Op, DebugLoc dl) { } } +/// SplatByte - Distribute ByteVal over NumBits bits. +// FIXME: Move this helper to a common place. +static APInt SplatByte(unsigned NumBits, uint8_t ByteVal) { + APInt Val = APInt(NumBits, ByteVal); + unsigned Shift = 8; + for (unsigned i = NumBits; i > 8; i >>= 1) { + Val = (Val << Shift) | Val; + Shift <<= 1; + } + return Val; +} + /// ExpandBitCount - Expand the specified bitcount instruction into operations. /// SDValue SelectionDAGLegalize::ExpandBitCount(unsigned Opc, SDValue Op, @@ -2339,26 +2449,45 @@ SDValue SelectionDAGLegalize::ExpandBitCount(unsigned Opc, SDValue Op, switch (Opc) { default: assert(0 && "Cannot expand this yet!"); case ISD::CTPOP: { - static const uint64_t mask[6] = { - 0x5555555555555555ULL, 0x3333333333333333ULL, - 0x0F0F0F0F0F0F0F0FULL, 0x00FF00FF00FF00FFULL, - 0x0000FFFF0000FFFFULL, 0x00000000FFFFFFFFULL - }; EVT VT = Op.getValueType(); EVT ShVT = TLI.getShiftAmountTy(); - unsigned len = VT.getSizeInBits(); - for (unsigned i = 0; (1U << i) <= (len / 2); ++i) { - //x = (x & mask[i][len/8]) + (x >> (1 << i) & mask[i][len/8]) - unsigned EltSize = VT.isVector() ? - VT.getVectorElementType().getSizeInBits() : len; - SDValue Tmp2 = DAG.getConstant(APInt(EltSize, mask[i]), VT); - SDValue Tmp3 = DAG.getConstant(1ULL << i, ShVT); - Op = DAG.getNode(ISD::ADD, dl, VT, - DAG.getNode(ISD::AND, dl, VT, Op, Tmp2), - DAG.getNode(ISD::AND, dl, VT, - DAG.getNode(ISD::SRL, dl, VT, Op, Tmp3), - Tmp2)); - } + unsigned Len = VT.getSizeInBits(); + + assert(VT.isInteger() && Len <= 128 && Len % 8 == 0 && + "CTPOP not implemented for this type."); + + // This is the "best" algorithm from + // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel + + SDValue Mask55 = DAG.getConstant(SplatByte(Len, 0x55), VT); + SDValue Mask33 = DAG.getConstant(SplatByte(Len, 0x33), VT); + SDValue Mask0F = DAG.getConstant(SplatByte(Len, 0x0F), VT); + SDValue Mask01 = DAG.getConstant(SplatByte(Len, 0x01), VT); + + // v = v - ((v >> 1) & 0x55555555...) + Op = DAG.getNode(ISD::SUB, dl, VT, Op, + DAG.getNode(ISD::AND, dl, VT, + DAG.getNode(ISD::SRL, dl, VT, Op, + DAG.getConstant(1, ShVT)), + Mask55)); + // v = (v & 0x33333333...) + ((v >> 2) & 0x33333333...) + Op = DAG.getNode(ISD::ADD, dl, VT, + DAG.getNode(ISD::AND, dl, VT, Op, Mask33), + DAG.getNode(ISD::AND, dl, VT, + DAG.getNode(ISD::SRL, dl, VT, Op, + DAG.getConstant(2, ShVT)), + Mask33)); + // v = (v + (v >> 4)) & 0x0F0F0F0F... + Op = DAG.getNode(ISD::AND, dl, VT, + DAG.getNode(ISD::ADD, dl, VT, Op, + DAG.getNode(ISD::SRL, dl, VT, Op, + DAG.getConstant(4, ShVT))), + Mask0F); + // v = (v * 0x01010101...) >> (Len - 8) + Op = DAG.getNode(ISD::SRL, dl, VT, + DAG.getNode(ISD::MUL, dl, VT, Op, Mask01), + DAG.getConstant(Len - 8, ShVT)); + return Op; } case ISD::CTLZ: { @@ -2516,9 +2645,14 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node, case ISD::PREFETCH: case ISD::VAEND: case ISD::EH_SJLJ_LONGJMP: + case ISD::EH_SJLJ_DISPATCHSETUP: + // If the target didn't expand these, there's nothing to do, so just + // preserve the chain and be done. Results.push_back(Node->getOperand(0)); break; case ISD::EH_SJLJ_SETJMP: + // If the target didn't expand this, just return 'zero' and preserve the + // chain. Results.push_back(DAG.getConstant(0, MVT::i32)); Results.push_back(Node->getOperand(0)); break; @@ -2527,7 +2661,8 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node, TargetLowering::ArgListTy Args; std::pair CallResult = TLI.LowerCallTo(Node->getOperand(0), Type::getVoidTy(*DAG.getContext()), - false, false, false, false, 0, CallingConv::C, false, + false, false, false, false, 0, CallingConv::C, + /*isTailCall=*/false, /*isReturnValueUsed=*/true, DAG.getExternalSymbol("__sync_synchronize", TLI.getPointerTy()), @@ -2538,7 +2673,6 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node, // By default, atomic intrinsics are marked Legal and lowered. Targets // which don't support them directly, however, may want libcalls, in which // case they mark them Expand, and we get here. - // FIXME: Unimplemented for now. Add libcalls. case ISD::ATOMIC_SWAP: case ISD::ATOMIC_LOAD_ADD: case ISD::ATOMIC_LOAD_SUB: @@ -2578,7 +2712,8 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node, TargetLowering::ArgListTy Args; std::pair CallResult = TLI.LowerCallTo(Node->getOperand(0), Type::getVoidTy(*DAG.getContext()), - false, false, false, false, 0, CallingConv::C, false, + false, false, false, false, 0, CallingConv::C, + /*isTailCall=*/false, /*isReturnValueUsed=*/true, DAG.getExternalSymbol("abort", TLI.getPointerTy()), Args, DAG, dl); @@ -2586,7 +2721,7 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node, break; } case ISD::FP_ROUND: - case ISD::BIT_CONVERT: + case ISD::BITCAST: Tmp1 = EmitStackConvert(Node->getOperand(0), Node->getValueType(0), Node->getValueType(0), dl); Results.push_back(Tmp1); @@ -2637,8 +2772,7 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node, SDValue True, False; EVT VT = Node->getOperand(0).getValueType(); EVT NVT = Node->getValueType(0); - const uint64_t zero[] = {0, 0}; - APFloat apf = APFloat(APInt(VT.getSizeInBits(), 2, zero)); + APFloat apf(APInt::getNullValue(VT.getSizeInBits())); APInt x = APInt::getSignBit(NVT.getSizeInBits()); (void)apf.convertFromAPInt(x, false, APFloat::rmNearestTiesToEven); Tmp1 = DAG.getConstantFP(apf, VT); @@ -2662,8 +2796,8 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node, Tmp2 = Node->getOperand(1); unsigned Align = Node->getConstantOperandVal(3); - SDValue VAListLoad = DAG.getLoad(TLI.getPointerTy(), dl, Tmp1, Tmp2, V, 0, - false, false, 0); + SDValue VAListLoad = DAG.getLoad(TLI.getPointerTy(), dl, Tmp1, Tmp2, + MachinePointerInfo(V), false, false, 0); SDValue VAList = VAListLoad; if (Align > TLI.getMinStackArgumentAlignment()) { @@ -2674,7 +2808,7 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node, TLI.getPointerTy())); VAList = DAG.getNode(ISD::AND, dl, TLI.getPointerTy(), VAList, - DAG.getConstant(-Align, + DAG.getConstant(-(int64_t)Align, TLI.getPointerTy())); } @@ -2684,10 +2818,10 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node, getTypeAllocSize(VT.getTypeForEVT(*DAG.getContext())), TLI.getPointerTy())); // Store the incremented VAList to the legalized pointer - Tmp3 = DAG.getStore(VAListLoad.getValue(1), dl, Tmp3, Tmp2, V, 0, - false, false, 0); + Tmp3 = DAG.getStore(VAListLoad.getValue(1), dl, Tmp3, Tmp2, + MachinePointerInfo(V), false, false, 0); // Load the actual argument out of the pointer VAList - Results.push_back(DAG.getLoad(VT, dl, Tmp3, VAList, NULL, 0, + Results.push_back(DAG.getLoad(VT, dl, Tmp3, VAList, MachinePointerInfo(), false, false, 0)); Results.push_back(Results[0].getValue(1)); break; @@ -2698,16 +2832,17 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node, const Value *VD = cast(Node->getOperand(3))->getValue(); const Value *VS = cast(Node->getOperand(4))->getValue(); Tmp1 = DAG.getLoad(TLI.getPointerTy(), dl, Node->getOperand(0), - Node->getOperand(2), VS, 0, false, false, 0); - Tmp1 = DAG.getStore(Tmp1.getValue(1), dl, Tmp1, Node->getOperand(1), VD, 0, - false, false, 0); + Node->getOperand(2), MachinePointerInfo(VS), + false, false, 0); + Tmp1 = DAG.getStore(Tmp1.getValue(1), dl, Tmp1, Node->getOperand(1), + MachinePointerInfo(VD), false, false, 0); Results.push_back(Tmp1); break; } case ISD::EXTRACT_VECTOR_ELT: if (Node->getOperand(0).getValueType().getVectorNumElements() == 1) // This must be an access of the only element. Return it. - Tmp1 = DAG.getNode(ISD::BIT_CONVERT, dl, Node->getValueType(0), + Tmp1 = DAG.getNode(ISD::BITCAST, dl, Node->getValueType(0), Node->getOperand(0)); else Tmp1 = ExpandExtractFromVectorThroughStack(SDValue(Node, 0)); @@ -2716,6 +2851,9 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node, case ISD::EXTRACT_SUBVECTOR: Results.push_back(ExpandExtractFromVectorThroughStack(SDValue(Node, 0))); break; + case ISD::INSERT_SUBVECTOR: + Results.push_back(ExpandInsertToVectorThroughStack(SDValue(Node, 0))); + break; case ISD::CONCAT_VECTORS: { Results.push_back(ExpandVectorBuildThroughStack(Node)); break; @@ -3094,14 +3232,8 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node, BottomHalf = DAG.getNode(Ops[isSigned][1], dl, DAG.getVTList(VT, VT), LHS, RHS); TopHalf = BottomHalf.getValue(1); - } else { - // FIXME: We should be able to fall back to a libcall with an illegal - // type in some cases. - // Also, we can fall back to a division in some cases, but that's a big - // performance hit in the general case. - assert(TLI.isTypeLegal(EVT::getIntegerVT(*DAG.getContext(), - VT.getSizeInBits() * 2)) && - "Don't know how to expand this operation yet!"); + } else if (TLI.isTypeLegal(EVT::getIntegerVT(*DAG.getContext(), + VT.getSizeInBits() * 2))) { EVT WideVT = EVT::getIntegerVT(*DAG.getContext(), VT.getSizeInBits() * 2); LHS = DAG.getNode(Ops[isSigned][2], dl, WideVT, LHS); RHS = DAG.getNode(Ops[isSigned][2], dl, WideVT, RHS); @@ -3110,6 +3242,30 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node, DAG.getIntPtrConstant(0)); TopHalf = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, VT, Tmp1, DAG.getIntPtrConstant(1)); + } else { + // We can fall back to a libcall with an illegal type for the MUL if we + // have a libcall big enough. + // Also, we can fall back to a division in some cases, but that's a big + // performance hit in the general case. + EVT WideVT = EVT::getIntegerVT(*DAG.getContext(), VT.getSizeInBits() * 2); + RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; + if (WideVT == MVT::i16) + LC = RTLIB::MUL_I16; + else if (WideVT == MVT::i32) + LC = RTLIB::MUL_I32; + else if (WideVT == MVT::i64) + LC = RTLIB::MUL_I64; + else if (WideVT == MVT::i128) + LC = RTLIB::MUL_I128; + assert(LC != RTLIB::UNKNOWN_LIBCALL && "Cannot expand this operation!"); + LHS = DAG.getNode(Ops[isSigned][2], dl, WideVT, LHS); + RHS = DAG.getNode(Ops[isSigned][2], dl, WideVT, RHS); + + SDValue Ret = ExpandLibCall(LC, Node, isSigned); + BottomHalf = DAG.getNode(ISD::TRUNCATE, dl, VT, Ret); + TopHalf = DAG.getNode(ISD::SRL, dl, Ret.getValueType(), Ret, + DAG.getConstant(VT.getSizeInBits(), TLI.getPointerTy())); + TopHalf = DAG.getNode(ISD::TRUNCATE, dl, VT, TopHalf); } if (isSigned) { Tmp1 = DAG.getConstant(VT.getSizeInBits() - 1, TLI.getShiftAmountTy()); @@ -3165,8 +3321,8 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node, SDValue Addr = DAG.getNode(ISD::ADD, dl, PTy, Index, Table); EVT MemVT = EVT::getIntegerVT(*DAG.getContext(), EntrySize * 8); - SDValue LD = DAG.getExtLoad(ISD::SEXTLOAD, PTy, dl, Chain, Addr, - PseudoSourceValue::getJumpTable(), 0, MemVT, + SDValue LD = DAG.getExtLoad(ISD::SEXTLOAD, dl, PTy, Chain, Addr, + MachinePointerInfo::getJumpTable(), MemVT, false, false, 0); Addr = LD; if (TM.getRelocationModel() == Reloc::PIC_) { @@ -3329,8 +3485,8 @@ void SelectionDAGLegalize::PromoteNode(SDNode *Node, case ISD::XOR: { unsigned ExtOp, TruncOp; if (OVT.isVector()) { - ExtOp = ISD::BIT_CONVERT; - TruncOp = ISD::BIT_CONVERT; + ExtOp = ISD::BITCAST; + TruncOp = ISD::BITCAST; } else { assert(OVT.isInteger() && "Cannot promote logic operation"); ExtOp = ISD::ANY_EXTEND; @@ -3347,8 +3503,8 @@ void SelectionDAGLegalize::PromoteNode(SDNode *Node, case ISD::SELECT: { unsigned ExtOp, TruncOp; if (Node->getValueType(0).isVector()) { - ExtOp = ISD::BIT_CONVERT; - TruncOp = ISD::BIT_CONVERT; + ExtOp = ISD::BITCAST; + TruncOp = ISD::BITCAST; } else if (Node->getValueType(0).isInteger()) { ExtOp = ISD::ANY_EXTEND; TruncOp = ISD::TRUNCATE; @@ -3375,12 +3531,12 @@ void SelectionDAGLegalize::PromoteNode(SDNode *Node, cast(Node)->getMask(Mask); // Cast the two input vectors. - Tmp1 = DAG.getNode(ISD::BIT_CONVERT, dl, NVT, Node->getOperand(0)); - Tmp2 = DAG.getNode(ISD::BIT_CONVERT, dl, NVT, Node->getOperand(1)); + Tmp1 = DAG.getNode(ISD::BITCAST, dl, NVT, Node->getOperand(0)); + Tmp2 = DAG.getNode(ISD::BITCAST, dl, NVT, Node->getOperand(1)); // Convert the shuffle mask to the right # elements. Tmp1 = ShuffleWithNarrowerEltType(NVT, OVT, dl, Tmp1, Tmp2, Mask); - Tmp1 = DAG.getNode(ISD::BIT_CONVERT, dl, OVT, Tmp1); + Tmp1 = DAG.getNode(ISD::BITCAST, dl, OVT, Tmp1); Results.push_back(Tmp1); break; } diff --git a/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp index 650ee5a0721c..27752123aac4 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp @@ -55,7 +55,7 @@ void DAGTypeLegalizer::SoftenFloatResult(SDNode *N, unsigned ResNo) { #endif llvm_unreachable("Do not know how to soften the result of this operator!"); - case ISD::BIT_CONVERT: R = SoftenFloatRes_BIT_CONVERT(N); break; + case ISD::BITCAST: R = SoftenFloatRes_BITCAST(N); break; case ISD::BUILD_PAIR: R = SoftenFloatRes_BUILD_PAIR(N); break; case ISD::ConstantFP: R = SoftenFloatRes_ConstantFP(cast(N)); @@ -102,7 +102,7 @@ void DAGTypeLegalizer::SoftenFloatResult(SDNode *N, unsigned ResNo) { SetSoftenedFloat(SDValue(N, ResNo), R); } -SDValue DAGTypeLegalizer::SoftenFloatRes_BIT_CONVERT(SDNode *N) { +SDValue DAGTypeLegalizer::SoftenFloatRes_BITCAST(SDNode *N) { return BitConvertToInteger(N->getOperand(0)); } @@ -133,8 +133,9 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_FABS(SDNode *N) { unsigned Size = NVT.getSizeInBits(); // Mask = ~(1 << (Size-1)) - SDValue Mask = DAG.getConstant(APInt::getAllOnesValue(Size).clear(Size-1), - NVT); + APInt API = APInt::getAllOnesValue(Size); + API.clearBit(Size-1); + SDValue Mask = DAG.getConstant(API, NVT); SDValue Op = GetSoftenedFloat(N->getOperand(0)); return DAG.getNode(ISD::AND, N->getDebugLoc(), NVT, Op, Mask); } @@ -455,7 +456,7 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_LOAD(SDNode *N) { if (L->getExtensionType() == ISD::NON_EXTLOAD) { NewL = DAG.getLoad(L->getAddressingMode(), L->getExtensionType(), NVT, dl, L->getChain(), L->getBasePtr(), L->getOffset(), - L->getSrcValue(), L->getSrcValueOffset(), NVT, + L->getPointerInfo(), NVT, L->isVolatile(), L->isNonTemporal(), L->getAlignment()); // Legalized the chain result - switch anything that used the old chain to // use the new one. @@ -466,8 +467,7 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_LOAD(SDNode *N) { // Do a non-extending load followed by FP_EXTEND. NewL = DAG.getLoad(L->getAddressingMode(), ISD::NON_EXTLOAD, L->getMemoryVT(), dl, L->getChain(), - L->getBasePtr(), L->getOffset(), - L->getSrcValue(), L->getSrcValueOffset(), + L->getBasePtr(), L->getOffset(), L->getPointerInfo(), L->getMemoryVT(), L->isVolatile(), L->isNonTemporal(), L->getAlignment()); // Legalized the chain result - switch anything that used the old chain to @@ -558,7 +558,7 @@ bool DAGTypeLegalizer::SoftenFloatOperand(SDNode *N, unsigned OpNo) { #endif llvm_unreachable("Do not know how to soften this operator's operand!"); - case ISD::BIT_CONVERT: Res = SoftenFloatOp_BIT_CONVERT(N); break; + case ISD::BITCAST: Res = SoftenFloatOp_BITCAST(N); break; case ISD::BR_CC: Res = SoftenFloatOp_BR_CC(N); break; case ISD::FP_ROUND: Res = SoftenFloatOp_FP_ROUND(N); break; case ISD::FP_TO_SINT: Res = SoftenFloatOp_FP_TO_SINT(N); break; @@ -670,8 +670,8 @@ void DAGTypeLegalizer::SoftenSetCCOperands(SDValue &NewLHS, SDValue &NewRHS, } } -SDValue DAGTypeLegalizer::SoftenFloatOp_BIT_CONVERT(SDNode *N) { - return DAG.getNode(ISD::BIT_CONVERT, N->getDebugLoc(), N->getValueType(0), +SDValue DAGTypeLegalizer::SoftenFloatOp_BITCAST(SDNode *N) { + return DAG.getNode(ISD::BITCAST, N->getDebugLoc(), N->getValueType(0), GetSoftenedFloat(N->getOperand(0))); } @@ -780,7 +780,7 @@ SDValue DAGTypeLegalizer::SoftenFloatOp_STORE(SDNode *N, unsigned OpNo) { Val = GetSoftenedFloat(Val); return DAG.getStore(ST->getChain(), dl, Val, ST->getBasePtr(), - ST->getSrcValue(), ST->getSrcValueOffset(), + ST->getPointerInfo(), ST->isVolatile(), ST->isNonTemporal(), ST->getAlignment()); } @@ -816,7 +816,7 @@ void DAGTypeLegalizer::ExpandFloatResult(SDNode *N, unsigned ResNo) { case ISD::SELECT: SplitRes_SELECT(N, Lo, Hi); break; case ISD::SELECT_CC: SplitRes_SELECT_CC(N, Lo, Hi); break; - case ISD::BIT_CONVERT: ExpandRes_BIT_CONVERT(N, Lo, Hi); break; + case ISD::BITCAST: ExpandRes_BITCAST(N, Lo, Hi); break; case ISD::BUILD_PAIR: ExpandRes_BUILD_PAIR(N, Lo, Hi); break; case ISD::EXTRACT_ELEMENT: ExpandRes_EXTRACT_ELEMENT(N, Lo, Hi); break; case ISD::EXTRACT_VECTOR_ELT: ExpandRes_EXTRACT_VECTOR_ELT(N, Lo, Hi); break; @@ -1110,9 +1110,8 @@ void DAGTypeLegalizer::ExpandFloatRes_LOAD(SDNode *N, SDValue &Lo, assert(NVT.isByteSized() && "Expanded type not byte sized!"); assert(LD->getMemoryVT().bitsLE(NVT) && "Float type not round?"); - Hi = DAG.getExtLoad(LD->getExtensionType(), NVT, dl, Chain, Ptr, - LD->getSrcValue(), LD->getSrcValueOffset(), - LD->getMemoryVT(), LD->isVolatile(), + Hi = DAG.getExtLoad(LD->getExtensionType(), dl, NVT, Chain, Ptr, + LD->getPointerInfo(), LD->getMemoryVT(), LD->isVolatile(), LD->isNonTemporal(), LD->getAlignment()); // Remember the chain. @@ -1222,7 +1221,7 @@ bool DAGTypeLegalizer::ExpandFloatOperand(SDNode *N, unsigned OpNo) { #endif llvm_unreachable("Do not know how to expand this operator's operand!"); - case ISD::BIT_CONVERT: Res = ExpandOp_BIT_CONVERT(N); break; + case ISD::BITCAST: Res = ExpandOp_BITCAST(N); break; case ISD::BUILD_VECTOR: Res = ExpandOp_BUILD_VECTOR(N); break; case ISD::EXTRACT_ELEMENT: Res = ExpandOp_EXTRACT_ELEMENT(N); break; @@ -1421,7 +1420,7 @@ SDValue DAGTypeLegalizer::ExpandFloatOp_STORE(SDNode *N, unsigned OpNo) { GetExpandedOp(ST->getValue(), Lo, Hi); return DAG.getTruncStore(Chain, N->getDebugLoc(), Hi, Ptr, - ST->getSrcValue(), ST->getSrcValueOffset(), + ST->getPointerInfo(), ST->getMemoryVT(), ST->isVolatile(), ST->isNonTemporal(), ST->getAlignment()); } diff --git a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp index f8c589071921..f0752df80f12 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -49,7 +49,7 @@ void DAGTypeLegalizer::PromoteIntegerResult(SDNode *N, unsigned ResNo) { llvm_unreachable("Do not know how to promote this operator!"); case ISD::AssertSext: Res = PromoteIntRes_AssertSext(N); break; case ISD::AssertZext: Res = PromoteIntRes_AssertZext(N); break; - case ISD::BIT_CONVERT: Res = PromoteIntRes_BIT_CONVERT(N); break; + case ISD::BITCAST: Res = PromoteIntRes_BITCAST(N); break; case ISD::BSWAP: Res = PromoteIntRes_BSWAP(N); break; case ISD::BUILD_PAIR: Res = PromoteIntRes_BUILD_PAIR(N); break; case ISD::Constant: Res = PromoteIntRes_Constant(N); break; @@ -143,7 +143,7 @@ SDValue DAGTypeLegalizer::PromoteIntRes_Atomic1(AtomicSDNode *N) { SDValue Res = DAG.getAtomic(N->getOpcode(), N->getDebugLoc(), N->getMemoryVT(), N->getChain(), N->getBasePtr(), - Op2, N->getSrcValue(), N->getAlignment()); + Op2, N->getMemOperand()); // Legalized the chain result - switch anything that used the old chain to // use the new one. ReplaceValueWith(SDValue(N, 1), Res.getValue(1)); @@ -155,14 +155,14 @@ SDValue DAGTypeLegalizer::PromoteIntRes_Atomic2(AtomicSDNode *N) { SDValue Op3 = GetPromotedInteger(N->getOperand(3)); SDValue Res = DAG.getAtomic(N->getOpcode(), N->getDebugLoc(), N->getMemoryVT(), N->getChain(), N->getBasePtr(), - Op2, Op3, N->getSrcValue(), N->getAlignment()); + Op2, Op3, N->getMemOperand()); // Legalized the chain result - switch anything that used the old chain to // use the new one. ReplaceValueWith(SDValue(N, 1), Res.getValue(1)); return Res; } -SDValue DAGTypeLegalizer::PromoteIntRes_BIT_CONVERT(SDNode *N) { +SDValue DAGTypeLegalizer::PromoteIntRes_BITCAST(SDNode *N) { SDValue InOp = N->getOperand(0); EVT InVT = InOp.getValueType(); EVT NInVT = TLI.getTypeToTransformTo(*DAG.getContext(), InVT); @@ -179,8 +179,7 @@ SDValue DAGTypeLegalizer::PromoteIntRes_BIT_CONVERT(SDNode *N) { case PromoteInteger: if (NOutVT.bitsEq(NInVT)) // The input promotes to the same size. Convert the promoted value. - return DAG.getNode(ISD::BIT_CONVERT, dl, - NOutVT, GetPromotedInteger(InOp)); + return DAG.getNode(ISD::BITCAST, dl, NOutVT, GetPromotedInteger(InOp)); break; case SoftenFloat: // Promote the integer operand by hand. @@ -193,7 +192,7 @@ SDValue DAGTypeLegalizer::PromoteIntRes_BIT_CONVERT(SDNode *N) { return DAG.getNode(ISD::ANY_EXTEND, dl, NOutVT, BitConvertToInteger(GetScalarizedVector(InOp))); case SplitVector: { - // For example, i32 = BIT_CONVERT v2i16 on alpha. Convert the split + // For example, i32 = BITCAST v2i16 on alpha. Convert the split // pieces of the input into integers and reassemble in the final type. SDValue Lo, Hi; GetSplitVector(N->getOperand(0), Lo, Hi); @@ -207,12 +206,12 @@ SDValue DAGTypeLegalizer::PromoteIntRes_BIT_CONVERT(SDNode *N) { EVT::getIntegerVT(*DAG.getContext(), NOutVT.getSizeInBits()), JoinIntegers(Lo, Hi)); - return DAG.getNode(ISD::BIT_CONVERT, dl, NOutVT, InOp); + return DAG.getNode(ISD::BITCAST, dl, NOutVT, InOp); } case WidenVector: if (OutVT.bitsEq(NInVT)) // The input is widened to the same size. Convert to the widened value. - return DAG.getNode(ISD::BIT_CONVERT, dl, OutVT, GetWidenedVector(InOp)); + return DAG.getNode(ISD::BITCAST, dl, OutVT, GetWidenedVector(InOp)); } return DAG.getNode(ISD::ANY_EXTEND, dl, NOutVT, @@ -293,7 +292,7 @@ SDValue DAGTypeLegalizer::PromoteIntRes_CTTZ(SDNode *N) { // value was zero. This can be handled by setting the bit just off // the top of the original type. APInt TopBit(NVT.getSizeInBits(), 0); - TopBit.set(OVT.getSizeInBits()); + TopBit.setBit(OVT.getSizeInBits()); Op = DAG.getNode(ISD::OR, dl, NVT, Op, DAG.getConstant(TopBit, NVT)); return DAG.getNode(ISD::CTTZ, dl, NVT, Op); } @@ -371,8 +370,8 @@ SDValue DAGTypeLegalizer::PromoteIntRes_LOAD(LoadSDNode *N) { ISD::LoadExtType ExtType = ISD::isNON_EXTLoad(N) ? ISD::EXTLOAD : N->getExtensionType(); DebugLoc dl = N->getDebugLoc(); - SDValue Res = DAG.getExtLoad(ExtType, NVT, dl, N->getChain(), N->getBasePtr(), - N->getSrcValue(), N->getSrcValueOffset(), + SDValue Res = DAG.getExtLoad(ExtType, dl, NVT, N->getChain(), N->getBasePtr(), + N->getPointerInfo(), N->getMemoryVT(), N->isVolatile(), N->isNonTemporal(), N->getAlignment()); @@ -549,6 +548,48 @@ SDValue DAGTypeLegalizer::PromoteIntRes_UADDSUBO(SDNode *N, unsigned ResNo) { return Res; } +SDValue DAGTypeLegalizer::PromoteIntRes_XMULO(SDNode *N, unsigned ResNo) { + // Promote the overflow bit trivially. + if (ResNo == 1) + return PromoteIntRes_Overflow(N); + + SDValue LHS = N->getOperand(0), RHS = N->getOperand(1); + DebugLoc DL = N->getDebugLoc(); + EVT SmallVT = LHS.getValueType(); + + // To determine if the result overflowed in a larger type, we extend the input + // to the larger type, do the multiply, then check the high bits of the result + // to see if the overflow happened. + if (N->getOpcode() == ISD::SMULO) { + LHS = SExtPromotedInteger(LHS); + RHS = SExtPromotedInteger(RHS); + } else { + LHS = ZExtPromotedInteger(LHS); + RHS = ZExtPromotedInteger(RHS); + } + SDValue Mul = DAG.getNode(ISD::MUL, DL, LHS.getValueType(), LHS, RHS); + + // Overflow occurred iff the high part of the result does not zero/sign-extend + // the low part. + SDValue Overflow; + if (N->getOpcode() == ISD::UMULO) { + // Unsigned overflow occurred iff the high part is non-zero. + SDValue Hi = DAG.getNode(ISD::SRL, DL, Mul.getValueType(), Mul, + DAG.getIntPtrConstant(SmallVT.getSizeInBits())); + Overflow = DAG.getSetCC(DL, N->getValueType(1), Hi, + DAG.getConstant(0, Hi.getValueType()), ISD::SETNE); + } else { + // Signed overflow occurred iff the high part does not sign extend the low. + SDValue SExt = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, Mul.getValueType(), + Mul, DAG.getValueType(SmallVT)); + Overflow = DAG.getSetCC(DL, N->getValueType(1), SExt, Mul, ISD::SETNE); + } + + // Use the calculated overflow everywhere. + ReplaceValueWith(SDValue(N, 1), Overflow); + return Mul; +} + SDValue DAGTypeLegalizer::PromoteIntRes_UDIV(SDNode *N) { // Zero extend the input. SDValue LHS = ZExtPromotedInteger(N->getOperand(0)); @@ -602,11 +643,6 @@ SDValue DAGTypeLegalizer::PromoteIntRes_VAARG(SDNode *N) { return Res; } -SDValue DAGTypeLegalizer::PromoteIntRes_XMULO(SDNode *N, unsigned ResNo) { - assert(ResNo == 1 && "Only boolean result promotion currently supported!"); - return PromoteIntRes_Overflow(N); -} - //===----------------------------------------------------------------------===// // Integer Operand Promotion //===----------------------------------------------------------------------===// @@ -631,7 +667,7 @@ bool DAGTypeLegalizer::PromoteIntegerOperand(SDNode *N, unsigned OpNo) { llvm_unreachable("Do not know how to promote this operator's operand!"); case ISD::ANY_EXTEND: Res = PromoteIntOp_ANY_EXTEND(N); break; - case ISD::BIT_CONVERT: Res = PromoteIntOp_BIT_CONVERT(N); break; + case ISD::BITCAST: Res = PromoteIntOp_BITCAST(N); break; case ISD::BR_CC: Res = PromoteIntOp_BR_CC(N, OpNo); break; case ISD::BRCOND: Res = PromoteIntOp_BRCOND(N, OpNo); break; case ISD::BUILD_PAIR: Res = PromoteIntOp_BUILD_PAIR(N); break; @@ -713,7 +749,7 @@ SDValue DAGTypeLegalizer::PromoteIntOp_ANY_EXTEND(SDNode *N) { return DAG.getNode(ISD::ANY_EXTEND, N->getDebugLoc(), N->getValueType(0), Op); } -SDValue DAGTypeLegalizer::PromoteIntOp_BIT_CONVERT(SDNode *N) { +SDValue DAGTypeLegalizer::PromoteIntOp_BITCAST(SDNode *N) { // This should only occur in unusual situations like bitcasting to an // x86_fp80, so just turn it into a store+load return CreateStackStoreLoad(N->getOperand(0), N->getValueType(0)); @@ -889,7 +925,6 @@ SDValue DAGTypeLegalizer::PromoteIntOp_SINT_TO_FP(SDNode *N) { SDValue DAGTypeLegalizer::PromoteIntOp_STORE(StoreSDNode *N, unsigned OpNo){ assert(ISD::isUNINDEXEDStore(N) && "Indexed store during type legalization!"); SDValue Ch = N->getChain(), Ptr = N->getBasePtr(); - int SVOffset = N->getSrcValueOffset(); unsigned Alignment = N->getAlignment(); bool isVolatile = N->isVolatile(); bool isNonTemporal = N->isNonTemporal(); @@ -898,8 +933,8 @@ SDValue DAGTypeLegalizer::PromoteIntOp_STORE(StoreSDNode *N, unsigned OpNo){ SDValue Val = GetPromotedInteger(N->getValue()); // Get promoted value. // Truncate the value and store the result. - return DAG.getTruncStore(Ch, dl, Val, Ptr, N->getSrcValue(), - SVOffset, N->getMemoryVT(), + return DAG.getTruncStore(Ch, dl, Val, Ptr, N->getPointerInfo(), + N->getMemoryVT(), isVolatile, isNonTemporal, Alignment); } @@ -951,7 +986,7 @@ void DAGTypeLegalizer::ExpandIntegerResult(SDNode *N, unsigned ResNo) { case ISD::SELECT_CC: SplitRes_SELECT_CC(N, Lo, Hi); break; case ISD::UNDEF: SplitRes_UNDEF(N, Lo, Hi); break; - case ISD::BIT_CONVERT: ExpandRes_BIT_CONVERT(N, Lo, Hi); break; + case ISD::BITCAST: ExpandRes_BITCAST(N, Lo, Hi); break; case ISD::BUILD_PAIR: ExpandRes_BUILD_PAIR(N, Lo, Hi); break; case ISD::EXTRACT_ELEMENT: ExpandRes_EXTRACT_ELEMENT(N, Lo, Hi); break; case ISD::EXTRACT_VECTOR_ELT: ExpandRes_EXTRACT_VECTOR_ELT(N, Lo, Hi); break; @@ -978,6 +1013,23 @@ void DAGTypeLegalizer::ExpandIntegerResult(SDNode *N, unsigned ResNo) { case ISD::UREM: ExpandIntRes_UREM(N, Lo, Hi); break; case ISD::ZERO_EXTEND: ExpandIntRes_ZERO_EXTEND(N, Lo, Hi); break; + case ISD::ATOMIC_LOAD_ADD: + case ISD::ATOMIC_LOAD_SUB: + case ISD::ATOMIC_LOAD_AND: + case ISD::ATOMIC_LOAD_OR: + case ISD::ATOMIC_LOAD_XOR: + case ISD::ATOMIC_LOAD_NAND: + case ISD::ATOMIC_LOAD_MIN: + case ISD::ATOMIC_LOAD_MAX: + case ISD::ATOMIC_LOAD_UMIN: + case ISD::ATOMIC_LOAD_UMAX: + case ISD::ATOMIC_SWAP: { + std::pair Tmp = ExpandAtomic(N); + SplitInteger(Tmp.first, Lo, Hi); + ReplaceValueWith(SDValue(N, 1), Tmp.second); + break; + } + case ISD::AND: case ISD::OR: case ISD::XOR: ExpandIntRes_Logical(N, Lo, Hi); break; @@ -999,6 +1051,8 @@ void DAGTypeLegalizer::ExpandIntegerResult(SDNode *N, unsigned ResNo) { case ISD::SSUBO: ExpandIntRes_SADDSUBO(N, Lo, Hi); break; case ISD::UADDO: case ISD::USUBO: ExpandIntRes_UADDSUBO(N, Lo, Hi); break; + case ISD::UMULO: + case ISD::SMULO: ExpandIntRes_UMULSMULO(N, Lo, Hi); break; } // If Lo/Hi is null, the sub-method took care of registering results etc. @@ -1006,11 +1060,98 @@ void DAGTypeLegalizer::ExpandIntegerResult(SDNode *N, unsigned ResNo) { SetExpandedInteger(SDValue(N, ResNo), Lo, Hi); } +/// Lower an atomic node to the appropriate builtin call. +std::pair DAGTypeLegalizer::ExpandAtomic(SDNode *Node) { + unsigned Opc = Node->getOpcode(); + MVT VT = cast(Node)->getMemoryVT().getSimpleVT(); + RTLIB::Libcall LC; + + switch (Opc) { + default: + llvm_unreachable("Unhandled atomic intrinsic Expand!"); + break; + case ISD::ATOMIC_SWAP: + switch (VT.SimpleTy) { + default: llvm_unreachable("Unexpected value type for atomic!"); + case MVT::i8: LC = RTLIB::SYNC_LOCK_TEST_AND_SET_1; break; + case MVT::i16: LC = RTLIB::SYNC_LOCK_TEST_AND_SET_2; break; + case MVT::i32: LC = RTLIB::SYNC_LOCK_TEST_AND_SET_4; break; + case MVT::i64: LC = RTLIB::SYNC_LOCK_TEST_AND_SET_8; break; + } + break; + case ISD::ATOMIC_CMP_SWAP: + switch (VT.SimpleTy) { + default: llvm_unreachable("Unexpected value type for atomic!"); + case MVT::i8: LC = RTLIB::SYNC_VAL_COMPARE_AND_SWAP_1; break; + case MVT::i16: LC = RTLIB::SYNC_VAL_COMPARE_AND_SWAP_2; break; + case MVT::i32: LC = RTLIB::SYNC_VAL_COMPARE_AND_SWAP_4; break; + case MVT::i64: LC = RTLIB::SYNC_VAL_COMPARE_AND_SWAP_8; break; + } + break; + case ISD::ATOMIC_LOAD_ADD: + switch (VT.SimpleTy) { + default: llvm_unreachable("Unexpected value type for atomic!"); + case MVT::i8: LC = RTLIB::SYNC_FETCH_AND_ADD_1; break; + case MVT::i16: LC = RTLIB::SYNC_FETCH_AND_ADD_2; break; + case MVT::i32: LC = RTLIB::SYNC_FETCH_AND_ADD_4; break; + case MVT::i64: LC = RTLIB::SYNC_FETCH_AND_ADD_8; break; + } + break; + case ISD::ATOMIC_LOAD_SUB: + switch (VT.SimpleTy) { + default: llvm_unreachable("Unexpected value type for atomic!"); + case MVT::i8: LC = RTLIB::SYNC_FETCH_AND_SUB_1; break; + case MVT::i16: LC = RTLIB::SYNC_FETCH_AND_SUB_2; break; + case MVT::i32: LC = RTLIB::SYNC_FETCH_AND_SUB_4; break; + case MVT::i64: LC = RTLIB::SYNC_FETCH_AND_SUB_8; break; + } + break; + case ISD::ATOMIC_LOAD_AND: + switch (VT.SimpleTy) { + default: llvm_unreachable("Unexpected value type for atomic!"); + case MVT::i8: LC = RTLIB::SYNC_FETCH_AND_AND_1; break; + case MVT::i16: LC = RTLIB::SYNC_FETCH_AND_AND_2; break; + case MVT::i32: LC = RTLIB::SYNC_FETCH_AND_AND_4; break; + case MVT::i64: LC = RTLIB::SYNC_FETCH_AND_AND_8; break; + } + break; + case ISD::ATOMIC_LOAD_OR: + switch (VT.SimpleTy) { + default: llvm_unreachable("Unexpected value type for atomic!"); + case MVT::i8: LC = RTLIB::SYNC_FETCH_AND_OR_1; break; + case MVT::i16: LC = RTLIB::SYNC_FETCH_AND_OR_2; break; + case MVT::i32: LC = RTLIB::SYNC_FETCH_AND_OR_4; break; + case MVT::i64: LC = RTLIB::SYNC_FETCH_AND_OR_8; break; + } + break; + case ISD::ATOMIC_LOAD_XOR: + switch (VT.SimpleTy) { + default: llvm_unreachable("Unexpected value type for atomic!"); + case MVT::i8: LC = RTLIB::SYNC_FETCH_AND_XOR_1; break; + case MVT::i16: LC = RTLIB::SYNC_FETCH_AND_XOR_2; break; + case MVT::i32: LC = RTLIB::SYNC_FETCH_AND_XOR_4; break; + case MVT::i64: LC = RTLIB::SYNC_FETCH_AND_XOR_8; break; + } + break; + case ISD::ATOMIC_LOAD_NAND: + switch (VT.SimpleTy) { + default: llvm_unreachable("Unexpected value type for atomic!"); + case MVT::i8: LC = RTLIB::SYNC_FETCH_AND_NAND_1; break; + case MVT::i16: LC = RTLIB::SYNC_FETCH_AND_NAND_2; break; + case MVT::i32: LC = RTLIB::SYNC_FETCH_AND_NAND_4; break; + case MVT::i64: LC = RTLIB::SYNC_FETCH_AND_NAND_8; break; + } + break; + } + + return ExpandChainLibCall(LC, Node, false); +} + /// ExpandShiftByConstant - N is a shift by a value that needs to be expanded, /// and the shift amount is a constant 'Amt'. Expand the operation. void DAGTypeLegalizer::ExpandShiftByConstant(SDNode *N, unsigned Amt, SDValue &Lo, SDValue &Hi) { - DebugLoc dl = N->getDebugLoc(); + DebugLoc DL = N->getDebugLoc(); // Expand the incoming operand to be shifted, so that we have its parts SDValue InL, InH; GetExpandedInteger(N->getOperand(0), InL, InH); @@ -1025,8 +1166,8 @@ void DAGTypeLegalizer::ExpandShiftByConstant(SDNode *N, unsigned Amt, Lo = Hi = DAG.getConstant(0, NVT); } else if (Amt > NVTBits) { Lo = DAG.getConstant(0, NVT); - Hi = DAG.getNode(ISD::SHL, dl, - NVT, InL, DAG.getConstant(Amt-NVTBits,ShTy)); + Hi = DAG.getNode(ISD::SHL, DL, + NVT, InL, DAG.getConstant(Amt-NVTBits, ShTy)); } else if (Amt == NVTBits) { Lo = DAG.getConstant(0, NVT); Hi = InL; @@ -1034,17 +1175,17 @@ void DAGTypeLegalizer::ExpandShiftByConstant(SDNode *N, unsigned Amt, TLI.isOperationLegalOrCustom(ISD::ADDC, TLI.getTypeToExpandTo(*DAG.getContext(), NVT))) { // Emit this X << 1 as X+X. - SDVTList VTList = DAG.getVTList(NVT, MVT::Flag); + SDVTList VTList = DAG.getVTList(NVT, MVT::Glue); SDValue LoOps[2] = { InL, InL }; - Lo = DAG.getNode(ISD::ADDC, dl, VTList, LoOps, 2); + Lo = DAG.getNode(ISD::ADDC, DL, VTList, LoOps, 2); SDValue HiOps[3] = { InH, InH, Lo.getValue(1) }; - Hi = DAG.getNode(ISD::ADDE, dl, VTList, HiOps, 3); + Hi = DAG.getNode(ISD::ADDE, DL, VTList, HiOps, 3); } else { - Lo = DAG.getNode(ISD::SHL, dl, NVT, InL, DAG.getConstant(Amt, ShTy)); - Hi = DAG.getNode(ISD::OR, dl, NVT, - DAG.getNode(ISD::SHL, dl, NVT, InH, + Lo = DAG.getNode(ISD::SHL, DL, NVT, InL, DAG.getConstant(Amt, ShTy)); + Hi = DAG.getNode(ISD::OR, DL, NVT, + DAG.getNode(ISD::SHL, DL, NVT, InH, DAG.getConstant(Amt, ShTy)), - DAG.getNode(ISD::SRL, dl, NVT, InL, + DAG.getNode(ISD::SRL, DL, NVT, InL, DAG.getConstant(NVTBits-Amt, ShTy))); } return; @@ -1055,43 +1196,43 @@ void DAGTypeLegalizer::ExpandShiftByConstant(SDNode *N, unsigned Amt, Lo = DAG.getConstant(0, NVT); Hi = DAG.getConstant(0, NVT); } else if (Amt > NVTBits) { - Lo = DAG.getNode(ISD::SRL, dl, + Lo = DAG.getNode(ISD::SRL, DL, NVT, InH, DAG.getConstant(Amt-NVTBits,ShTy)); Hi = DAG.getConstant(0, NVT); } else if (Amt == NVTBits) { Lo = InH; Hi = DAG.getConstant(0, NVT); } else { - Lo = DAG.getNode(ISD::OR, dl, NVT, - DAG.getNode(ISD::SRL, dl, NVT, InL, + Lo = DAG.getNode(ISD::OR, DL, NVT, + DAG.getNode(ISD::SRL, DL, NVT, InL, DAG.getConstant(Amt, ShTy)), - DAG.getNode(ISD::SHL, dl, NVT, InH, + DAG.getNode(ISD::SHL, DL, NVT, InH, DAG.getConstant(NVTBits-Amt, ShTy))); - Hi = DAG.getNode(ISD::SRL, dl, NVT, InH, DAG.getConstant(Amt, ShTy)); + Hi = DAG.getNode(ISD::SRL, DL, NVT, InH, DAG.getConstant(Amt, ShTy)); } return; } assert(N->getOpcode() == ISD::SRA && "Unknown shift!"); if (Amt > VTBits) { - Hi = Lo = DAG.getNode(ISD::SRA, dl, NVT, InH, + Hi = Lo = DAG.getNode(ISD::SRA, DL, NVT, InH, DAG.getConstant(NVTBits-1, ShTy)); } else if (Amt > NVTBits) { - Lo = DAG.getNode(ISD::SRA, dl, NVT, InH, + Lo = DAG.getNode(ISD::SRA, DL, NVT, InH, DAG.getConstant(Amt-NVTBits, ShTy)); - Hi = DAG.getNode(ISD::SRA, dl, NVT, InH, + Hi = DAG.getNode(ISD::SRA, DL, NVT, InH, DAG.getConstant(NVTBits-1, ShTy)); } else if (Amt == NVTBits) { Lo = InH; - Hi = DAG.getNode(ISD::SRA, dl, NVT, InH, + Hi = DAG.getNode(ISD::SRA, DL, NVT, InH, DAG.getConstant(NVTBits-1, ShTy)); } else { - Lo = DAG.getNode(ISD::OR, dl, NVT, - DAG.getNode(ISD::SRL, dl, NVT, InL, + Lo = DAG.getNode(ISD::OR, DL, NVT, + DAG.getNode(ISD::SRL, DL, NVT, InL, DAG.getConstant(Amt, ShTy)), - DAG.getNode(ISD::SHL, dl, NVT, InH, + DAG.getNode(ISD::SHL, DL, NVT, InH, DAG.getConstant(NVTBits-Amt, ShTy))); - Hi = DAG.getNode(ISD::SRA, dl, NVT, InH, DAG.getConstant(Amt, ShTy)); + Hi = DAG.getNode(ISD::SRA, DL, NVT, InH, DAG.getConstant(Amt, ShTy)); } } @@ -1269,7 +1410,7 @@ void DAGTypeLegalizer::ExpandIntRes_ADDSUB(SDNode *N, // Do not generate ADDC/ADDE or SUBC/SUBE if the target does not support // them. TODO: Teach operation legalization how to expand unsupported // ADDC/ADDE/SUBC/SUBE. The problem is that these operations generate - // a carry of type MVT::Flag, but there doesn't seem to be any way to + // a carry of type MVT::Glue, but there doesn't seem to be any way to // generate a value of this type in the expanded code sequence. bool hasCarry = TLI.isOperationLegalOrCustom(N->getOpcode() == ISD::ADD ? @@ -1277,7 +1418,7 @@ void DAGTypeLegalizer::ExpandIntRes_ADDSUB(SDNode *N, TLI.getTypeToExpandTo(*DAG.getContext(), NVT)); if (hasCarry) { - SDVTList VTList = DAG.getVTList(NVT, MVT::Flag); + SDVTList VTList = DAG.getVTList(NVT, MVT::Glue); if (N->getOpcode() == ISD::ADD) { Lo = DAG.getNode(ISD::ADDC, dl, VTList, LoOps, 2); HiOps[2] = Lo.getValue(1); @@ -1287,31 +1428,32 @@ void DAGTypeLegalizer::ExpandIntRes_ADDSUB(SDNode *N, HiOps[2] = Lo.getValue(1); Hi = DAG.getNode(ISD::SUBE, dl, VTList, HiOps, 3); } + return; + } + + if (N->getOpcode() == ISD::ADD) { + Lo = DAG.getNode(ISD::ADD, dl, NVT, LoOps, 2); + Hi = DAG.getNode(ISD::ADD, dl, NVT, HiOps, 2); + SDValue Cmp1 = DAG.getSetCC(dl, TLI.getSetCCResultType(NVT), Lo, LoOps[0], + ISD::SETULT); + SDValue Carry1 = DAG.getNode(ISD::SELECT, dl, NVT, Cmp1, + DAG.getConstant(1, NVT), + DAG.getConstant(0, NVT)); + SDValue Cmp2 = DAG.getSetCC(dl, TLI.getSetCCResultType(NVT), Lo, LoOps[1], + ISD::SETULT); + SDValue Carry2 = DAG.getNode(ISD::SELECT, dl, NVT, Cmp2, + DAG.getConstant(1, NVT), Carry1); + Hi = DAG.getNode(ISD::ADD, dl, NVT, Hi, Carry2); } else { - if (N->getOpcode() == ISD::ADD) { - Lo = DAG.getNode(ISD::ADD, dl, NVT, LoOps, 2); - Hi = DAG.getNode(ISD::ADD, dl, NVT, HiOps, 2); - SDValue Cmp1 = DAG.getSetCC(dl, TLI.getSetCCResultType(NVT), Lo, LoOps[0], - ISD::SETULT); - SDValue Carry1 = DAG.getNode(ISD::SELECT, dl, NVT, Cmp1, - DAG.getConstant(1, NVT), - DAG.getConstant(0, NVT)); - SDValue Cmp2 = DAG.getSetCC(dl, TLI.getSetCCResultType(NVT), Lo, LoOps[1], - ISD::SETULT); - SDValue Carry2 = DAG.getNode(ISD::SELECT, dl, NVT, Cmp2, - DAG.getConstant(1, NVT), Carry1); - Hi = DAG.getNode(ISD::ADD, dl, NVT, Hi, Carry2); - } else { - Lo = DAG.getNode(ISD::SUB, dl, NVT, LoOps, 2); - Hi = DAG.getNode(ISD::SUB, dl, NVT, HiOps, 2); - SDValue Cmp = - DAG.getSetCC(dl, TLI.getSetCCResultType(LoOps[0].getValueType()), - LoOps[0], LoOps[1], ISD::SETULT); - SDValue Borrow = DAG.getNode(ISD::SELECT, dl, NVT, Cmp, - DAG.getConstant(1, NVT), - DAG.getConstant(0, NVT)); - Hi = DAG.getNode(ISD::SUB, dl, NVT, Hi, Borrow); - } + Lo = DAG.getNode(ISD::SUB, dl, NVT, LoOps, 2); + Hi = DAG.getNode(ISD::SUB, dl, NVT, HiOps, 2); + SDValue Cmp = + DAG.getSetCC(dl, TLI.getSetCCResultType(LoOps[0].getValueType()), + LoOps[0], LoOps[1], ISD::SETULT); + SDValue Borrow = DAG.getNode(ISD::SELECT, dl, NVT, Cmp, + DAG.getConstant(1, NVT), + DAG.getConstant(0, NVT)); + Hi = DAG.getNode(ISD::SUB, dl, NVT, Hi, Borrow); } } @@ -1322,7 +1464,7 @@ void DAGTypeLegalizer::ExpandIntRes_ADDSUBC(SDNode *N, DebugLoc dl = N->getDebugLoc(); GetExpandedInteger(N->getOperand(0), LHSL, LHSH); GetExpandedInteger(N->getOperand(1), RHSL, RHSH); - SDVTList VTList = DAG.getVTList(LHSL.getValueType(), MVT::Flag); + SDVTList VTList = DAG.getVTList(LHSL.getValueType(), MVT::Glue); SDValue LoOps[2] = { LHSL, RHSL }; SDValue HiOps[3] = { LHSH, RHSH }; @@ -1348,7 +1490,7 @@ void DAGTypeLegalizer::ExpandIntRes_ADDSUBE(SDNode *N, DebugLoc dl = N->getDebugLoc(); GetExpandedInteger(N->getOperand(0), LHSL, LHSH); GetExpandedInteger(N->getOperand(1), RHSL, RHSH); - SDVTList VTList = DAG.getVTList(LHSL.getValueType(), MVT::Flag); + SDVTList VTList = DAG.getVTList(LHSL.getValueType(), MVT::Glue); SDValue LoOps[3] = { LHSL, RHSL, N->getOperand(2) }; SDValue HiOps[3] = { LHSH, RHSH }; @@ -1437,7 +1579,7 @@ void DAGTypeLegalizer::ExpandIntRes_Constant(SDNode *N, EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); unsigned NBitWidth = NVT.getSizeInBits(); const APInt &Cst = cast(N)->getAPIntValue(); - Lo = DAG.getConstant(APInt(Cst).trunc(NBitWidth), NVT); + Lo = DAG.getConstant(Cst.trunc(NBitWidth), NVT); Hi = DAG.getConstant(Cst.lshr(NBitWidth).trunc(NBitWidth), NVT); } @@ -1524,7 +1666,6 @@ void DAGTypeLegalizer::ExpandIntRes_LOAD(LoadSDNode *N, SDValue Ch = N->getChain(); SDValue Ptr = N->getBasePtr(); ISD::LoadExtType ExtType = N->getExtensionType(); - int SVOffset = N->getSrcValueOffset(); unsigned Alignment = N->getAlignment(); bool isVolatile = N->isVolatile(); bool isNonTemporal = N->isNonTemporal(); @@ -1535,7 +1676,7 @@ void DAGTypeLegalizer::ExpandIntRes_LOAD(LoadSDNode *N, if (N->getMemoryVT().bitsLE(NVT)) { EVT MemVT = N->getMemoryVT(); - Lo = DAG.getExtLoad(ExtType, NVT, dl, Ch, Ptr, N->getSrcValue(), SVOffset, + Lo = DAG.getExtLoad(ExtType, dl, NVT, Ch, Ptr, N->getPointerInfo(), MemVT, isVolatile, isNonTemporal, Alignment); // Remember the chain. @@ -1557,7 +1698,7 @@ void DAGTypeLegalizer::ExpandIntRes_LOAD(LoadSDNode *N, } } else if (TLI.isLittleEndian()) { // Little-endian - low bits are at low addresses. - Lo = DAG.getLoad(NVT, dl, Ch, Ptr, N->getSrcValue(), SVOffset, + Lo = DAG.getLoad(NVT, dl, Ch, Ptr, N->getPointerInfo(), isVolatile, isNonTemporal, Alignment); unsigned ExcessBits = @@ -1568,8 +1709,8 @@ void DAGTypeLegalizer::ExpandIntRes_LOAD(LoadSDNode *N, unsigned IncrementSize = NVT.getSizeInBits()/8; Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, DAG.getIntPtrConstant(IncrementSize)); - Hi = DAG.getExtLoad(ExtType, NVT, dl, Ch, Ptr, N->getSrcValue(), - SVOffset+IncrementSize, NEVT, + Hi = DAG.getExtLoad(ExtType, dl, NVT, Ch, Ptr, + N->getPointerInfo().getWithOffset(IncrementSize), NEVT, isVolatile, isNonTemporal, MinAlign(Alignment, IncrementSize)); @@ -1586,7 +1727,7 @@ void DAGTypeLegalizer::ExpandIntRes_LOAD(LoadSDNode *N, unsigned ExcessBits = (EBytes - IncrementSize)*8; // Load both the high bits and maybe some of the low bits. - Hi = DAG.getExtLoad(ExtType, NVT, dl, Ch, Ptr, N->getSrcValue(), SVOffset, + Hi = DAG.getExtLoad(ExtType, dl, NVT, Ch, Ptr, N->getPointerInfo(), EVT::getIntegerVT(*DAG.getContext(), MemVT.getSizeInBits() - ExcessBits), isVolatile, isNonTemporal, Alignment); @@ -1595,8 +1736,8 @@ void DAGTypeLegalizer::ExpandIntRes_LOAD(LoadSDNode *N, Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, DAG.getIntPtrConstant(IncrementSize)); // Load the rest of the low bits. - Lo = DAG.getExtLoad(ISD::ZEXTLOAD, NVT, dl, Ch, Ptr, N->getSrcValue(), - SVOffset+IncrementSize, + Lo = DAG.getExtLoad(ISD::ZEXTLOAD, dl, NVT, Ch, Ptr, + N->getPointerInfo().getWithOffset(IncrementSize), EVT::getIntegerVT(*DAG.getContext(), ExcessBits), isVolatile, isNonTemporal, MinAlign(Alignment, IncrementSize)); @@ -1987,6 +2128,31 @@ void DAGTypeLegalizer::ExpandIntRes_UADDSUBO(SDNode *N, ReplaceValueWith(SDValue(N, 1), Ofl); } +void DAGTypeLegalizer::ExpandIntRes_UMULSMULO(SDNode *N, + SDValue &Lo, SDValue &Hi) { + SDValue LHS = N->getOperand(0); + SDValue RHS = N->getOperand(1); + DebugLoc dl = N->getDebugLoc(); + EVT VT = N->getValueType(0); + EVT HalfVT = EVT::getIntegerVT(*DAG.getContext(), VT.getSizeInBits() / 2); + // Expand the result by simply replacing it with the equivalent + // non-overflow-checking operation. + SDValue Ret = DAG.getNode(ISD::MUL, dl, LHS.getValueType(), LHS, RHS); + SplitInteger(Ret, Lo, Hi); + + // Now calculate overflow. + SDValue Ofl; + if (N->getOpcode() == ISD::UMULO) + Ofl = DAG.getSetCC(dl, N->getValueType(1), Hi, + DAG.getConstant(0, VT), ISD::SETNE); + else { + SDValue Tmp = DAG.getConstant(VT.getSizeInBits() - 1, HalfVT); + Tmp = DAG.getNode(ISD::SRA, dl, HalfVT, Lo, Tmp); + Ofl = DAG.getSetCC(dl, N->getValueType(1), Hi, Tmp, ISD::SETNE); + } + ReplaceValueWith(SDValue(N, 1), Ofl); +} + void DAGTypeLegalizer::ExpandIntRes_UDIV(SDNode *N, SDValue &Lo, SDValue &Hi) { EVT VT = N->getValueType(0); @@ -2078,7 +2244,7 @@ bool DAGTypeLegalizer::ExpandIntegerOperand(SDNode *N, unsigned OpNo) { #endif llvm_unreachable("Do not know how to expand this operator's operand!"); - case ISD::BIT_CONVERT: Res = ExpandOp_BIT_CONVERT(N); break; + case ISD::BITCAST: Res = ExpandOp_BITCAST(N); break; case ISD::BR_CC: Res = ExpandIntOp_BR_CC(N); break; case ISD::BUILD_VECTOR: Res = ExpandOp_BUILD_VECTOR(N); break; case ISD::EXTRACT_ELEMENT: Res = ExpandOp_EXTRACT_ELEMENT(N); break; @@ -2308,7 +2474,6 @@ SDValue DAGTypeLegalizer::ExpandIntOp_STORE(StoreSDNode *N, unsigned OpNo) { EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT); SDValue Ch = N->getChain(); SDValue Ptr = N->getBasePtr(); - int SVOffset = N->getSrcValueOffset(); unsigned Alignment = N->getAlignment(); bool isVolatile = N->isVolatile(); bool isNonTemporal = N->isNonTemporal(); @@ -2319,14 +2484,16 @@ SDValue DAGTypeLegalizer::ExpandIntOp_STORE(StoreSDNode *N, unsigned OpNo) { if (N->getMemoryVT().bitsLE(NVT)) { GetExpandedInteger(N->getValue(), Lo, Hi); - return DAG.getTruncStore(Ch, dl, Lo, Ptr, N->getSrcValue(), SVOffset, + return DAG.getTruncStore(Ch, dl, Lo, Ptr, N->getPointerInfo(), N->getMemoryVT(), isVolatile, isNonTemporal, Alignment); - } else if (TLI.isLittleEndian()) { + } + + if (TLI.isLittleEndian()) { // Little-endian - low bits are at low addresses. GetExpandedInteger(N->getValue(), Lo, Hi); - Lo = DAG.getStore(Ch, dl, Lo, Ptr, N->getSrcValue(), SVOffset, + Lo = DAG.getStore(Ch, dl, Lo, Ptr, N->getPointerInfo(), isVolatile, isNonTemporal, Alignment); unsigned ExcessBits = @@ -2337,50 +2504,49 @@ SDValue DAGTypeLegalizer::ExpandIntOp_STORE(StoreSDNode *N, unsigned OpNo) { unsigned IncrementSize = NVT.getSizeInBits()/8; Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, DAG.getIntPtrConstant(IncrementSize)); - Hi = DAG.getTruncStore(Ch, dl, Hi, Ptr, N->getSrcValue(), - SVOffset+IncrementSize, NEVT, - isVolatile, isNonTemporal, + Hi = DAG.getTruncStore(Ch, dl, Hi, Ptr, + N->getPointerInfo().getWithOffset(IncrementSize), + NEVT, isVolatile, isNonTemporal, MinAlign(Alignment, IncrementSize)); return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo, Hi); - } else { - // Big-endian - high bits are at low addresses. Favor aligned stores at - // the cost of some bit-fiddling. - GetExpandedInteger(N->getValue(), Lo, Hi); - - EVT ExtVT = N->getMemoryVT(); - unsigned EBytes = ExtVT.getStoreSize(); - unsigned IncrementSize = NVT.getSizeInBits()/8; - unsigned ExcessBits = (EBytes - IncrementSize)*8; - EVT HiVT = EVT::getIntegerVT(*DAG.getContext(), - ExtVT.getSizeInBits() - ExcessBits); + } - if (ExcessBits < NVT.getSizeInBits()) { - // Transfer high bits from the top of Lo to the bottom of Hi. - Hi = DAG.getNode(ISD::SHL, dl, NVT, Hi, - DAG.getConstant(NVT.getSizeInBits() - ExcessBits, - TLI.getPointerTy())); - Hi = DAG.getNode(ISD::OR, dl, NVT, Hi, - DAG.getNode(ISD::SRL, dl, NVT, Lo, - DAG.getConstant(ExcessBits, - TLI.getPointerTy()))); - } + // Big-endian - high bits are at low addresses. Favor aligned stores at + // the cost of some bit-fiddling. + GetExpandedInteger(N->getValue(), Lo, Hi); + + EVT ExtVT = N->getMemoryVT(); + unsigned EBytes = ExtVT.getStoreSize(); + unsigned IncrementSize = NVT.getSizeInBits()/8; + unsigned ExcessBits = (EBytes - IncrementSize)*8; + EVT HiVT = EVT::getIntegerVT(*DAG.getContext(), + ExtVT.getSizeInBits() - ExcessBits); + + if (ExcessBits < NVT.getSizeInBits()) { + // Transfer high bits from the top of Lo to the bottom of Hi. + Hi = DAG.getNode(ISD::SHL, dl, NVT, Hi, + DAG.getConstant(NVT.getSizeInBits() - ExcessBits, + TLI.getPointerTy())); + Hi = DAG.getNode(ISD::OR, dl, NVT, Hi, + DAG.getNode(ISD::SRL, dl, NVT, Lo, + DAG.getConstant(ExcessBits, + TLI.getPointerTy()))); + } - // Store both the high bits and maybe some of the low bits. - Hi = DAG.getTruncStore(Ch, dl, Hi, Ptr, N->getSrcValue(), - SVOffset, HiVT, isVolatile, isNonTemporal, - Alignment); + // Store both the high bits and maybe some of the low bits. + Hi = DAG.getTruncStore(Ch, dl, Hi, Ptr, N->getPointerInfo(), + HiVT, isVolatile, isNonTemporal, Alignment); - // Increment the pointer to the other half. - Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, - DAG.getIntPtrConstant(IncrementSize)); - // Store the lowest ExcessBits bits in the second half. - Lo = DAG.getTruncStore(Ch, dl, Lo, Ptr, N->getSrcValue(), - SVOffset+IncrementSize, - EVT::getIntegerVT(*DAG.getContext(), ExcessBits), - isVolatile, isNonTemporal, - MinAlign(Alignment, IncrementSize)); - return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo, Hi); - } + // Increment the pointer to the other half. + Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, + DAG.getIntPtrConstant(IncrementSize)); + // Store the lowest ExcessBits bits in the second half. + Lo = DAG.getTruncStore(Ch, dl, Lo, Ptr, + N->getPointerInfo().getWithOffset(IncrementSize), + EVT::getIntegerVT(*DAG.getContext(), ExcessBits), + isVolatile, isNonTemporal, + MinAlign(Alignment, IncrementSize)); + return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo, Hi); } SDValue DAGTypeLegalizer::ExpandIntOp_TRUNCATE(SDNode *N) { @@ -2460,8 +2626,10 @@ SDValue DAGTypeLegalizer::ExpandIntOp_UINT_TO_FP(SDNode *N) { // Load the value out, extending it from f32 to the destination float type. // FIXME: Avoid the extend by constructing the right constant pool? - SDValue Fudge = DAG.getExtLoad(ISD::EXTLOAD, DstVT, dl, DAG.getEntryNode(), - FudgePtr, NULL, 0, MVT::f32, + SDValue Fudge = DAG.getExtLoad(ISD::EXTLOAD, dl, DstVT, DAG.getEntryNode(), + FudgePtr, + MachinePointerInfo::getConstantPool(), + MVT::f32, false, false, Alignment); return DAG.getNode(ISD::FADD, dl, DstVT, SignedConv, Fudge); } diff --git a/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp index 6e56c98e9b56..cedda7e7075a 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp @@ -714,6 +714,11 @@ void DAGTypeLegalizer::ReplaceValueWith(SDValue From, SDValue To) { if (M->getNodeId() == Processed) RemapValue(NewVal); DAG.ReplaceAllUsesOfValueWith(OldVal, NewVal, &NUL); + // OldVal may be a target of the ReplacedValues map which was marked + // NewNode to force reanalysis because it was updated. Ensure that + // anything that ReplacedValues mapped to OldVal will now be mapped + // all the way to NewVal. + ReplacedValues[OldVal] = NewVal; } // The original node continues to exist in the DAG, marked NewNode. } @@ -858,7 +863,7 @@ void DAGTypeLegalizer::SetWidenedVector(SDValue Op, SDValue Result) { /// BitConvertToInteger - Convert to an integer of the same size. SDValue DAGTypeLegalizer::BitConvertToInteger(SDValue Op) { unsigned BitWidth = Op.getValueType().getSizeInBits(); - return DAG.getNode(ISD::BIT_CONVERT, Op.getDebugLoc(), + return DAG.getNode(ISD::BITCAST, Op.getDebugLoc(), EVT::getIntegerVT(*DAG.getContext(), BitWidth), Op); } @@ -869,7 +874,7 @@ SDValue DAGTypeLegalizer::BitConvertVectorToIntegerVector(SDValue Op) { unsigned EltWidth = Op.getValueType().getVectorElementType().getSizeInBits(); EVT EltNVT = EVT::getIntegerVT(*DAG.getContext(), EltWidth); unsigned NumElts = Op.getValueType().getVectorNumElements(); - return DAG.getNode(ISD::BIT_CONVERT, Op.getDebugLoc(), + return DAG.getNode(ISD::BITCAST, Op.getDebugLoc(), EVT::getVectorVT(*DAG.getContext(), EltNVT, NumElts), Op); } @@ -880,10 +885,11 @@ SDValue DAGTypeLegalizer::CreateStackStoreLoad(SDValue Op, // the source and destination types. SDValue StackPtr = DAG.CreateStackTemporary(Op.getValueType(), DestVT); // Emit a store to the stack slot. - SDValue Store = DAG.getStore(DAG.getEntryNode(), dl, Op, StackPtr, NULL, 0, - false, false, 0); + SDValue Store = DAG.getStore(DAG.getEntryNode(), dl, Op, StackPtr, + MachinePointerInfo(), false, false, 0); // Result is a load from the stack slot. - return DAG.getLoad(DestVT, dl, Store, StackPtr, NULL, 0, false, false, 0); + return DAG.getLoad(DestVT, dl, Store, StackPtr, MachinePointerInfo(), + false, false, 0); } /// CustomLowerNode - Replace the node's results with custom code provided @@ -1049,6 +1055,39 @@ SDValue DAGTypeLegalizer::MakeLibCall(RTLIB::Libcall LC, EVT RetVT, return CallInfo.first; } +// ExpandChainLibCall - Expand a node into a call to a libcall. Similar to +// ExpandLibCall except that the first operand is the in-chain. +std::pair +DAGTypeLegalizer::ExpandChainLibCall(RTLIB::Libcall LC, + SDNode *Node, + bool isSigned) { + SDValue InChain = Node->getOperand(0); + + TargetLowering::ArgListTy Args; + TargetLowering::ArgListEntry Entry; + for (unsigned i = 1, e = Node->getNumOperands(); i != e; ++i) { + EVT ArgVT = Node->getOperand(i).getValueType(); + const Type *ArgTy = ArgVT.getTypeForEVT(*DAG.getContext()); + Entry.Node = Node->getOperand(i); + Entry.Ty = ArgTy; + Entry.isSExt = isSigned; + Entry.isZExt = !isSigned; + Args.push_back(Entry); + } + SDValue Callee = DAG.getExternalSymbol(TLI.getLibcallName(LC), + TLI.getPointerTy()); + + // Splice the libcall in wherever FindInputOutputChains tells us to. + const Type *RetTy = Node->getValueType(0).getTypeForEVT(*DAG.getContext()); + std::pair CallInfo = + TLI.LowerCallTo(InChain, RetTy, isSigned, !isSigned, false, false, + 0, TLI.getLibcallCallingConv(LC), /*isTailCall=*/false, + /*isReturnValueUsed=*/true, + Callee, Args, DAG, Node->getDebugLoc()); + + return CallInfo; +} + /// PromoteTargetBoolean - Promote the given target boolean to a target boolean /// of the given type. A target boolean is an integer value, not necessarily of /// type i1, the bits of which conform to getBooleanContents. diff --git a/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/lib/CodeGen/SelectionDAG/LegalizeTypes.h index d56029208e61..3f81bbbe4061 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ b/lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -99,7 +99,7 @@ private: return SoftenFloat; return ExpandFloat; } - + if (VT.getVectorNumElements() == 1) return ScalarizeVector; return SplitVector; @@ -192,6 +192,10 @@ private: SDValue MakeLibCall(RTLIB::Libcall LC, EVT RetVT, const SDValue *Ops, unsigned NumOps, bool isSigned, DebugLoc dl); + std::pair ExpandChainLibCall(RTLIB::Libcall LC, + SDNode *Node, bool isSigned); + std::pair ExpandAtomic(SDNode *Node); + SDValue PromoteTargetBoolean(SDValue Bool, EVT VT); void ReplaceValueWith(SDValue From, SDValue To); void SplitInteger(SDValue Op, SDValue &Lo, SDValue &Hi); @@ -244,7 +248,7 @@ private: SDValue PromoteIntRes_AssertZext(SDNode *N); SDValue PromoteIntRes_Atomic1(AtomicSDNode *N); SDValue PromoteIntRes_Atomic2(AtomicSDNode *N); - SDValue PromoteIntRes_BIT_CONVERT(SDNode *N); + SDValue PromoteIntRes_BITCAST(SDNode *N); SDValue PromoteIntRes_BSWAP(SDNode *N); SDValue PromoteIntRes_BUILD_PAIR(SDNode *N); SDValue PromoteIntRes_Constant(SDNode *N); @@ -278,7 +282,7 @@ private: // Integer Operand Promotion. bool PromoteIntegerOperand(SDNode *N, unsigned OperandNo); SDValue PromoteIntOp_ANY_EXTEND(SDNode *N); - SDValue PromoteIntOp_BIT_CONVERT(SDNode *N); + SDValue PromoteIntOp_BITCAST(SDNode *N); SDValue PromoteIntOp_BUILD_PAIR(SDNode *N); SDValue PromoteIntOp_BR_CC(SDNode *N, unsigned OpNo); SDValue PromoteIntOp_BRCOND(SDNode *N, unsigned OpNo); @@ -344,6 +348,7 @@ private: void ExpandIntRes_SADDSUBO (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandIntRes_UADDSUBO (SDNode *N, SDValue &Lo, SDValue &Hi); + void ExpandIntRes_UMULSMULO (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandShiftByConstant(SDNode *N, unsigned Amt, SDValue &Lo, SDValue &Hi); @@ -352,7 +357,7 @@ private: // Integer Operand Expansion. bool ExpandIntegerOperand(SDNode *N, unsigned OperandNo); - SDValue ExpandIntOp_BIT_CONVERT(SDNode *N); + SDValue ExpandIntOp_BITCAST(SDNode *N); SDValue ExpandIntOp_BR_CC(SDNode *N); SDValue ExpandIntOp_BUILD_VECTOR(SDNode *N); SDValue ExpandIntOp_EXTRACT_ELEMENT(SDNode *N); @@ -387,7 +392,7 @@ private: // Result Float to Integer Conversion. void SoftenFloatResult(SDNode *N, unsigned OpNo); - SDValue SoftenFloatRes_BIT_CONVERT(SDNode *N); + SDValue SoftenFloatRes_BITCAST(SDNode *N); SDValue SoftenFloatRes_BUILD_PAIR(SDNode *N); SDValue SoftenFloatRes_ConstantFP(ConstantFPSDNode *N); SDValue SoftenFloatRes_EXTRACT_VECTOR_ELT(SDNode *N); @@ -426,7 +431,7 @@ private: // Operand Float to Integer Conversion. bool SoftenFloatOperand(SDNode *N, unsigned OpNo); - SDValue SoftenFloatOp_BIT_CONVERT(SDNode *N); + SDValue SoftenFloatOp_BITCAST(SDNode *N); SDValue SoftenFloatOp_BR_CC(SDNode *N); SDValue SoftenFloatOp_FP_ROUND(SDNode *N); SDValue SoftenFloatOp_FP_TO_SINT(SDNode *N); @@ -515,7 +520,7 @@ private: SDValue ScalarizeVecRes_UnaryOp(SDNode *N); SDValue ScalarizeVecRes_InregOp(SDNode *N); - SDValue ScalarizeVecRes_BIT_CONVERT(SDNode *N); + SDValue ScalarizeVecRes_BITCAST(SDNode *N); SDValue ScalarizeVecRes_CONVERT_RNDSAT(SDNode *N); SDValue ScalarizeVecRes_EXTRACT_SUBVECTOR(SDNode *N); SDValue ScalarizeVecRes_FPOWI(SDNode *N); @@ -532,7 +537,7 @@ private: // Vector Operand Scalarization: <1 x ty> -> ty. bool ScalarizeVectorOperand(SDNode *N, unsigned OpNo); - SDValue ScalarizeVecOp_BIT_CONVERT(SDNode *N); + SDValue ScalarizeVecOp_BITCAST(SDNode *N); SDValue ScalarizeVecOp_CONCAT_VECTORS(SDNode *N); SDValue ScalarizeVecOp_EXTRACT_VECTOR_ELT(SDNode *N); SDValue ScalarizeVecOp_STORE(StoreSDNode *N, unsigned OpNo); @@ -557,7 +562,7 @@ private: void SplitVecRes_UnaryOp(SDNode *N, SDValue &Lo, SDValue &Hi); void SplitVecRes_InregOp(SDNode *N, SDValue &Lo, SDValue &Hi); - void SplitVecRes_BIT_CONVERT(SDNode *N, SDValue &Lo, SDValue &Hi); + void SplitVecRes_BITCAST(SDNode *N, SDValue &Lo, SDValue &Hi); void SplitVecRes_BUILD_PAIR(SDNode *N, SDValue &Lo, SDValue &Hi); void SplitVecRes_BUILD_VECTOR(SDNode *N, SDValue &Lo, SDValue &Hi); void SplitVecRes_CONCAT_VECTORS(SDNode *N, SDValue &Lo, SDValue &Hi); @@ -577,11 +582,12 @@ private: bool SplitVectorOperand(SDNode *N, unsigned OpNo); SDValue SplitVecOp_UnaryOp(SDNode *N); - SDValue SplitVecOp_BIT_CONVERT(SDNode *N); + SDValue SplitVecOp_BITCAST(SDNode *N); SDValue SplitVecOp_EXTRACT_SUBVECTOR(SDNode *N); SDValue SplitVecOp_EXTRACT_VECTOR_ELT(SDNode *N); SDValue SplitVecOp_STORE(StoreSDNode *N, unsigned OpNo); SDValue SplitVecOp_CONCAT_VECTORS(SDNode *N); + SDValue SplitVecOp_FP_ROUND(SDNode *N); //===--------------------------------------------------------------------===// // Vector Widening Support: LegalizeVectorTypes.cpp @@ -603,7 +609,7 @@ private: // Widen Vector Result Promotion. void WidenVectorResult(SDNode *N, unsigned ResNo); - SDValue WidenVecRes_BIT_CONVERT(SDNode* N); + SDValue WidenVecRes_BITCAST(SDNode* N); SDValue WidenVecRes_BUILD_VECTOR(SDNode* N); SDValue WidenVecRes_CONCAT_VECTORS(SDNode* N); SDValue WidenVecRes_CONVERT_RNDSAT(SDNode* N); @@ -628,7 +634,7 @@ private: // Widen Vector Operand. bool WidenVectorOperand(SDNode *N, unsigned ResNo); - SDValue WidenVecOp_BIT_CONVERT(SDNode *N); + SDValue WidenVecOp_BITCAST(SDNode *N); SDValue WidenVecOp_CONCAT_VECTORS(SDNode *N); SDValue WidenVecOp_EXTRACT_VECTOR_ELT(SDNode *N); SDValue WidenVecOp_EXTRACT_SUBVECTOR(SDNode *N); @@ -721,7 +727,7 @@ private: } // Generic Result Expansion. - void ExpandRes_BIT_CONVERT (SDNode *N, SDValue &Lo, SDValue &Hi); + void ExpandRes_BITCAST (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandRes_BUILD_PAIR (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandRes_EXTRACT_ELEMENT (SDNode *N, SDValue &Lo, SDValue &Hi); void ExpandRes_EXTRACT_VECTOR_ELT(SDNode *N, SDValue &Lo, SDValue &Hi); @@ -729,7 +735,7 @@ private: void ExpandRes_VAARG (SDNode *N, SDValue &Lo, SDValue &Hi); // Generic Operand Expansion. - SDValue ExpandOp_BIT_CONVERT (SDNode *N); + SDValue ExpandOp_BITCAST (SDNode *N); SDValue ExpandOp_BUILD_VECTOR (SDNode *N); SDValue ExpandOp_EXTRACT_ELEMENT (SDNode *N); SDValue ExpandOp_INSERT_VECTOR_ELT(SDNode *N); diff --git a/lib/CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp b/lib/CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp index 9c2b1d9ed73d..a75ae87f3cbe 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp @@ -32,8 +32,7 @@ using namespace llvm; // little/big-endian machines, followed by the Hi/Lo part. This means that // they cannot be used as is on vectors, for which Lo is always stored first. -void DAGTypeLegalizer::ExpandRes_BIT_CONVERT(SDNode *N, SDValue &Lo, - SDValue &Hi) { +void DAGTypeLegalizer::ExpandRes_BITCAST(SDNode *N, SDValue &Lo, SDValue &Hi) { EVT OutVT = N->getValueType(0); EVT NOutVT = TLI.getTypeToTransformTo(*DAG.getContext(), OutVT); SDValue InOp = N->getOperand(0); @@ -50,31 +49,31 @@ void DAGTypeLegalizer::ExpandRes_BIT_CONVERT(SDNode *N, SDValue &Lo, case SoftenFloat: // Convert the integer operand instead. SplitInteger(GetSoftenedFloat(InOp), Lo, Hi); - Lo = DAG.getNode(ISD::BIT_CONVERT, dl, NOutVT, Lo); - Hi = DAG.getNode(ISD::BIT_CONVERT, dl, NOutVT, Hi); + Lo = DAG.getNode(ISD::BITCAST, dl, NOutVT, Lo); + Hi = DAG.getNode(ISD::BITCAST, dl, NOutVT, Hi); return; case ExpandInteger: case ExpandFloat: // Convert the expanded pieces of the input. GetExpandedOp(InOp, Lo, Hi); - Lo = DAG.getNode(ISD::BIT_CONVERT, dl, NOutVT, Lo); - Hi = DAG.getNode(ISD::BIT_CONVERT, dl, NOutVT, Hi); + Lo = DAG.getNode(ISD::BITCAST, dl, NOutVT, Lo); + Hi = DAG.getNode(ISD::BITCAST, dl, NOutVT, Hi); return; case SplitVector: GetSplitVector(InOp, Lo, Hi); if (TLI.isBigEndian()) std::swap(Lo, Hi); - Lo = DAG.getNode(ISD::BIT_CONVERT, dl, NOutVT, Lo); - Hi = DAG.getNode(ISD::BIT_CONVERT, dl, NOutVT, Hi); + Lo = DAG.getNode(ISD::BITCAST, dl, NOutVT, Lo); + Hi = DAG.getNode(ISD::BITCAST, dl, NOutVT, Hi); return; case ScalarizeVector: // Convert the element instead. SplitInteger(BitConvertToInteger(GetScalarizedVector(InOp)), Lo, Hi); - Lo = DAG.getNode(ISD::BIT_CONVERT, dl, NOutVT, Lo); - Hi = DAG.getNode(ISD::BIT_CONVERT, dl, NOutVT, Hi); + Lo = DAG.getNode(ISD::BITCAST, dl, NOutVT, Lo); + Hi = DAG.getNode(ISD::BITCAST, dl, NOutVT, Hi); return; case WidenVector: { - assert(!(InVT.getVectorNumElements() & 1) && "Unsupported BIT_CONVERT"); + assert(!(InVT.getVectorNumElements() & 1) && "Unsupported BITCAST"); InOp = GetWidenedVector(InOp); EVT InNVT = EVT::getVectorVT(*DAG.getContext(), InVT.getVectorElementType(), InVT.getVectorNumElements()/2); @@ -84,19 +83,19 @@ void DAGTypeLegalizer::ExpandRes_BIT_CONVERT(SDNode *N, SDValue &Lo, DAG.getIntPtrConstant(InNVT.getVectorNumElements())); if (TLI.isBigEndian()) std::swap(Lo, Hi); - Lo = DAG.getNode(ISD::BIT_CONVERT, dl, NOutVT, Lo); - Hi = DAG.getNode(ISD::BIT_CONVERT, dl, NOutVT, Hi); + Lo = DAG.getNode(ISD::BITCAST, dl, NOutVT, Lo); + Hi = DAG.getNode(ISD::BITCAST, dl, NOutVT, Hi); return; } } if (InVT.isVector() && OutVT.isInteger()) { - // Handle cases like i64 = BIT_CONVERT v1i64 on x86, where the operand + // Handle cases like i64 = BITCAST v1i64 on x86, where the operand // is legal but the result is not. EVT NVT = EVT::getVectorVT(*DAG.getContext(), NOutVT, 2); if (isTypeLegal(NVT)) { - SDValue CastInOp = DAG.getNode(ISD::BIT_CONVERT, dl, NVT, InOp); + SDValue CastInOp = DAG.getNode(ISD::BITCAST, dl, NVT, InOp); Lo = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, NOutVT, CastInOp, DAG.getIntPtrConstant(0)); Hi = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, NOutVT, CastInOp, @@ -119,14 +118,14 @@ void DAGTypeLegalizer::ExpandRes_BIT_CONVERT(SDNode *N, SDValue &Lo, getTypeForEVT(*DAG.getContext())); SDValue StackPtr = DAG.CreateStackTemporary(InVT, Alignment); int SPFI = cast(StackPtr.getNode())->getIndex(); - const Value *SV = PseudoSourceValue::getFixedStack(SPFI); + MachinePointerInfo PtrInfo = MachinePointerInfo::getFixedStack(SPFI); // Emit a store to the stack slot. - SDValue Store = DAG.getStore(DAG.getEntryNode(), dl, InOp, StackPtr, SV, 0, + SDValue Store = DAG.getStore(DAG.getEntryNode(), dl, InOp, StackPtr, PtrInfo, false, false, 0); // Load the first half from the stack slot. - Lo = DAG.getLoad(NOutVT, dl, Store, StackPtr, SV, 0, false, false, 0); + Lo = DAG.getLoad(NOutVT, dl, Store, StackPtr, PtrInfo, false, false, 0); // Increment the pointer to the other half. unsigned IncrementSize = NOutVT.getSizeInBits() / 8; @@ -134,7 +133,8 @@ void DAGTypeLegalizer::ExpandRes_BIT_CONVERT(SDNode *N, SDValue &Lo, DAG.getIntPtrConstant(IncrementSize)); // Load the second half from the stack slot. - Hi = DAG.getLoad(NOutVT, dl, Store, StackPtr, SV, IncrementSize, false, + Hi = DAG.getLoad(NOutVT, dl, Store, StackPtr, + PtrInfo.getWithOffset(IncrementSize), false, false, MinAlign(Alignment, IncrementSize)); // Handle endianness of the load. @@ -172,7 +172,7 @@ void DAGTypeLegalizer::ExpandRes_EXTRACT_VECTOR_ELT(SDNode *N, SDValue &Lo, EVT OldVT = N->getValueType(0); EVT NewVT = TLI.getTypeToTransformTo(*DAG.getContext(), OldVT); - SDValue NewVec = DAG.getNode(ISD::BIT_CONVERT, dl, + SDValue NewVec = DAG.getNode(ISD::BITCAST, dl, EVT::getVectorVT(*DAG.getContext(), NewVT, 2*OldElts), OldVec); @@ -204,22 +204,21 @@ void DAGTypeLegalizer::ExpandRes_NormalLoad(SDNode *N, SDValue &Lo, EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), LD->getValueType(0)); SDValue Chain = LD->getChain(); SDValue Ptr = LD->getBasePtr(); - int SVOffset = LD->getSrcValueOffset(); unsigned Alignment = LD->getAlignment(); bool isVolatile = LD->isVolatile(); bool isNonTemporal = LD->isNonTemporal(); assert(NVT.isByteSized() && "Expanded type not byte sized!"); - Lo = DAG.getLoad(NVT, dl, Chain, Ptr, LD->getSrcValue(), SVOffset, + Lo = DAG.getLoad(NVT, dl, Chain, Ptr, LD->getPointerInfo(), isVolatile, isNonTemporal, Alignment); // Increment the pointer to the other half. unsigned IncrementSize = NVT.getSizeInBits() / 8; Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, DAG.getIntPtrConstant(IncrementSize)); - Hi = DAG.getLoad(NVT, dl, Chain, Ptr, LD->getSrcValue(), - SVOffset+IncrementSize, + Hi = DAG.getLoad(NVT, dl, Chain, Ptr, + LD->getPointerInfo().getWithOffset(IncrementSize), isVolatile, isNonTemporal, MinAlign(Alignment, IncrementSize)); @@ -262,14 +261,14 @@ void DAGTypeLegalizer::ExpandRes_VAARG(SDNode *N, SDValue &Lo, SDValue &Hi) { // Generic Operand Expansion. //===--------------------------------------------------------------------===// -SDValue DAGTypeLegalizer::ExpandOp_BIT_CONVERT(SDNode *N) { +SDValue DAGTypeLegalizer::ExpandOp_BITCAST(SDNode *N) { DebugLoc dl = N->getDebugLoc(); if (N->getValueType(0).isVector()) { // An illegal expanding type is being converted to a legal vector type. // Make a two element vector out of the expanded parts and convert that // instead, but only if the new vector type is legal (otherwise there // is no point, and it might create expansion loops). For example, on - // x86 this turns v1i64 = BIT_CONVERT i64 into v1i64 = BIT_CONVERT v2i32. + // x86 this turns v1i64 = BITCAST i64 into v1i64 = BITCAST v2i32. EVT OVT = N->getOperand(0).getValueType(); EVT NVT = EVT::getVectorVT(*DAG.getContext(), TLI.getTypeToTransformTo(*DAG.getContext(), OVT), @@ -283,7 +282,7 @@ SDValue DAGTypeLegalizer::ExpandOp_BIT_CONVERT(SDNode *N) { std::swap(Parts[0], Parts[1]); SDValue Vec = DAG.getNode(ISD::BUILD_VECTOR, dl, NVT, Parts, 2); - return DAG.getNode(ISD::BIT_CONVERT, dl, N->getValueType(0), Vec); + return DAG.getNode(ISD::BITCAST, dl, N->getValueType(0), Vec); } } @@ -322,7 +321,7 @@ SDValue DAGTypeLegalizer::ExpandOp_BUILD_VECTOR(SDNode *N) { &NewElts[0], NewElts.size()); // Convert the new vector to the old vector type. - return DAG.getNode(ISD::BIT_CONVERT, dl, VecVT, NewVec); + return DAG.getNode(ISD::BITCAST, dl, VecVT, NewVec); } SDValue DAGTypeLegalizer::ExpandOp_EXTRACT_ELEMENT(SDNode *N) { @@ -347,7 +346,7 @@ SDValue DAGTypeLegalizer::ExpandOp_INSERT_VECTOR_ELT(SDNode *N) { // Bitconvert to a vector of twice the length with elements of the expanded // type, insert the expanded vector elements, and then convert back. EVT NewVecVT = EVT::getVectorVT(*DAG.getContext(), NewEVT, NumElts*2); - SDValue NewVec = DAG.getNode(ISD::BIT_CONVERT, dl, + SDValue NewVec = DAG.getNode(ISD::BITCAST, dl, NewVecVT, N->getOperand(0)); SDValue Lo, Hi; @@ -363,7 +362,7 @@ SDValue DAGTypeLegalizer::ExpandOp_INSERT_VECTOR_ELT(SDNode *N) { NewVec = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, NewVecVT, NewVec, Hi, Idx); // Convert the new vector to the old vector type. - return DAG.getNode(ISD::BIT_CONVERT, dl, VecVT, NewVec); + return DAG.getNode(ISD::BITCAST, dl, VecVT, NewVec); } SDValue DAGTypeLegalizer::ExpandOp_SCALAR_TO_VECTOR(SDNode *N) { @@ -390,7 +389,6 @@ SDValue DAGTypeLegalizer::ExpandOp_NormalStore(SDNode *N, unsigned OpNo) { St->getValue().getValueType()); SDValue Chain = St->getChain(); SDValue Ptr = St->getBasePtr(); - int SVOffset = St->getSrcValueOffset(); unsigned Alignment = St->getAlignment(); bool isVolatile = St->isVolatile(); bool isNonTemporal = St->isNonTemporal(); @@ -404,14 +402,14 @@ SDValue DAGTypeLegalizer::ExpandOp_NormalStore(SDNode *N, unsigned OpNo) { if (TLI.isBigEndian()) std::swap(Lo, Hi); - Lo = DAG.getStore(Chain, dl, Lo, Ptr, St->getSrcValue(), SVOffset, + Lo = DAG.getStore(Chain, dl, Lo, Ptr, St->getPointerInfo(), isVolatile, isNonTemporal, Alignment); Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, DAG.getIntPtrConstant(IncrementSize)); assert(isTypeLegal(Ptr.getValueType()) && "Pointers must be legal!"); - Hi = DAG.getStore(Chain, dl, Hi, Ptr, St->getSrcValue(), - SVOffset + IncrementSize, + Hi = DAG.getStore(Chain, dl, Hi, Ptr, + St->getPointerInfo().getWithOffset(IncrementSize), isVolatile, isNonTemporal, MinAlign(Alignment, IncrementSize)); diff --git a/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp b/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp index 621c08724210..167dbe0377b3 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp @@ -241,14 +241,14 @@ SDValue VectorLegalizer::PromoteVectorOp(SDValue Op) { for (unsigned j = 0; j != Op.getNumOperands(); ++j) { if (Op.getOperand(j).getValueType().isVector()) - Operands[j] = DAG.getNode(ISD::BIT_CONVERT, dl, NVT, Op.getOperand(j)); + Operands[j] = DAG.getNode(ISD::BITCAST, dl, NVT, Op.getOperand(j)); else Operands[j] = Op.getOperand(j); } Op = DAG.getNode(Op.getOpcode(), dl, NVT, &Operands[0], Operands.size()); - return DAG.getNode(ISD::BIT_CONVERT, dl, VT, Op); + return DAG.getNode(ISD::BITCAST, dl, VT, Op); } SDValue VectorLegalizer::ExpandFNEG(SDValue Op) { diff --git a/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp index 93bc2d04928e..182f8fcbfbf3 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp @@ -46,7 +46,7 @@ void DAGTypeLegalizer::ScalarizeVectorResult(SDNode *N, unsigned ResNo) { #endif llvm_unreachable("Do not know how to scalarize the result of this operator!"); - case ISD::BIT_CONVERT: R = ScalarizeVecRes_BIT_CONVERT(N); break; + case ISD::BITCAST: R = ScalarizeVecRes_BITCAST(N); break; case ISD::BUILD_VECTOR: R = N->getOperand(0); break; case ISD::CONVERT_RNDSAT: R = ScalarizeVecRes_CONVERT_RNDSAT(N); break; case ISD::EXTRACT_SUBVECTOR: R = ScalarizeVecRes_EXTRACT_SUBVECTOR(N); break; @@ -122,9 +122,9 @@ SDValue DAGTypeLegalizer::ScalarizeVecRes_BinOp(SDNode *N) { LHS.getValueType(), LHS, RHS); } -SDValue DAGTypeLegalizer::ScalarizeVecRes_BIT_CONVERT(SDNode *N) { +SDValue DAGTypeLegalizer::ScalarizeVecRes_BITCAST(SDNode *N) { EVT NewVT = N->getValueType(0).getVectorElementType(); - return DAG.getNode(ISD::BIT_CONVERT, N->getDebugLoc(), + return DAG.getNode(ISD::BITCAST, N->getDebugLoc(), NewVT, N->getOperand(0)); } @@ -171,7 +171,7 @@ SDValue DAGTypeLegalizer::ScalarizeVecRes_LOAD(LoadSDNode *N) { N->getDebugLoc(), N->getChain(), N->getBasePtr(), DAG.getUNDEF(N->getBasePtr().getValueType()), - N->getSrcValue(), N->getSrcValueOffset(), + N->getPointerInfo(), N->getMemoryVT().getVectorElementType(), N->isVolatile(), N->isNonTemporal(), N->getOriginalAlignment()); @@ -296,8 +296,8 @@ bool DAGTypeLegalizer::ScalarizeVectorOperand(SDNode *N, unsigned OpNo) { dbgs() << "\n"; #endif llvm_unreachable("Do not know how to scalarize this operator's operand!"); - case ISD::BIT_CONVERT: - Res = ScalarizeVecOp_BIT_CONVERT(N); + case ISD::BITCAST: + Res = ScalarizeVecOp_BITCAST(N); break; case ISD::CONCAT_VECTORS: Res = ScalarizeVecOp_CONCAT_VECTORS(N); @@ -326,11 +326,11 @@ bool DAGTypeLegalizer::ScalarizeVectorOperand(SDNode *N, unsigned OpNo) { return false; } -/// ScalarizeVecOp_BIT_CONVERT - If the value to convert is a vector that needs +/// ScalarizeVecOp_BITCAST - If the value to convert is a vector that needs /// to be scalarized, it must be <1 x ty>. Convert the element instead. -SDValue DAGTypeLegalizer::ScalarizeVecOp_BIT_CONVERT(SDNode *N) { +SDValue DAGTypeLegalizer::ScalarizeVecOp_BITCAST(SDNode *N) { SDValue Elt = GetScalarizedVector(N->getOperand(0)); - return DAG.getNode(ISD::BIT_CONVERT, N->getDebugLoc(), + return DAG.getNode(ISD::BITCAST, N->getDebugLoc(), N->getValueType(0), Elt); } @@ -365,14 +365,13 @@ SDValue DAGTypeLegalizer::ScalarizeVecOp_STORE(StoreSDNode *N, unsigned OpNo){ if (N->isTruncatingStore()) return DAG.getTruncStore(N->getChain(), dl, GetScalarizedVector(N->getOperand(1)), - N->getBasePtr(), - N->getSrcValue(), N->getSrcValueOffset(), + N->getBasePtr(), N->getPointerInfo(), N->getMemoryVT().getVectorElementType(), N->isVolatile(), N->isNonTemporal(), N->getAlignment()); return DAG.getStore(N->getChain(), dl, GetScalarizedVector(N->getOperand(1)), - N->getBasePtr(), N->getSrcValue(), N->getSrcValueOffset(), + N->getBasePtr(), N->getPointerInfo(), N->isVolatile(), N->isNonTemporal(), N->getOriginalAlignment()); } @@ -407,7 +406,7 @@ void DAGTypeLegalizer::SplitVectorResult(SDNode *N, unsigned ResNo) { case ISD::SELECT_CC: SplitRes_SELECT_CC(N, Lo, Hi); break; case ISD::UNDEF: SplitRes_UNDEF(N, Lo, Hi); break; - case ISD::BIT_CONVERT: SplitVecRes_BIT_CONVERT(N, Lo, Hi); break; + case ISD::BITCAST: SplitVecRes_BITCAST(N, Lo, Hi); break; case ISD::BUILD_VECTOR: SplitVecRes_BUILD_VECTOR(N, Lo, Hi); break; case ISD::CONCAT_VECTORS: SplitVecRes_CONCAT_VECTORS(N, Lo, Hi); break; case ISD::CONVERT_RNDSAT: SplitVecRes_CONVERT_RNDSAT(N, Lo, Hi); break; @@ -497,8 +496,8 @@ void DAGTypeLegalizer::SplitVecRes_BinOp(SDNode *N, SDValue &Lo, Hi = DAG.getNode(N->getOpcode(), dl, LHSHi.getValueType(), LHSHi, RHSHi); } -void DAGTypeLegalizer::SplitVecRes_BIT_CONVERT(SDNode *N, SDValue &Lo, - SDValue &Hi) { +void DAGTypeLegalizer::SplitVecRes_BITCAST(SDNode *N, SDValue &Lo, + SDValue &Hi) { // We know the result is a vector. The input may be either a vector or a // scalar value. EVT LoVT, HiVT; @@ -526,8 +525,8 @@ void DAGTypeLegalizer::SplitVecRes_BIT_CONVERT(SDNode *N, SDValue &Lo, GetExpandedOp(InOp, Lo, Hi); if (TLI.isBigEndian()) std::swap(Lo, Hi); - Lo = DAG.getNode(ISD::BIT_CONVERT, dl, LoVT, Lo); - Hi = DAG.getNode(ISD::BIT_CONVERT, dl, HiVT, Hi); + Lo = DAG.getNode(ISD::BITCAST, dl, LoVT, Lo); + Hi = DAG.getNode(ISD::BITCAST, dl, HiVT, Hi); return; } break; @@ -535,8 +534,8 @@ void DAGTypeLegalizer::SplitVecRes_BIT_CONVERT(SDNode *N, SDValue &Lo, // If the input is a vector that needs to be split, convert each split // piece of the input now. GetSplitVector(InOp, Lo, Hi); - Lo = DAG.getNode(ISD::BIT_CONVERT, dl, LoVT, Lo); - Hi = DAG.getNode(ISD::BIT_CONVERT, dl, HiVT, Hi); + Lo = DAG.getNode(ISD::BITCAST, dl, LoVT, Lo); + Hi = DAG.getNode(ISD::BITCAST, dl, HiVT, Hi); return; } @@ -550,8 +549,8 @@ void DAGTypeLegalizer::SplitVecRes_BIT_CONVERT(SDNode *N, SDValue &Lo, if (TLI.isBigEndian()) std::swap(Lo, Hi); - Lo = DAG.getNode(ISD::BIT_CONVERT, dl, LoVT, Lo); - Hi = DAG.getNode(ISD::BIT_CONVERT, dl, HiVT, Hi); + Lo = DAG.getNode(ISD::BITCAST, dl, LoVT, Lo); + Hi = DAG.getNode(ISD::BITCAST, dl, HiVT, Hi); } void DAGTypeLegalizer::SplitVecRes_BUILD_VECTOR(SDNode *N, SDValue &Lo, @@ -626,9 +625,9 @@ void DAGTypeLegalizer::SplitVecRes_CONVERT_RNDSAT(SDNode *N, SDValue &Lo, EVT InNVT = EVT::getVectorVT(*DAG.getContext(), InVT.getVectorElementType(), LoVT.getVectorNumElements()); VLo = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, InNVT, InOp, - DAG.getIntPtrConstant(0)); + DAG.getIntPtrConstant(0)); VHi = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, InNVT, InOp, - DAG.getIntPtrConstant(InNVT.getVectorNumElements())); + DAG.getIntPtrConstant(InNVT.getVectorNumElements())); break; } } @@ -646,16 +645,15 @@ void DAGTypeLegalizer::SplitVecRes_EXTRACT_SUBVECTOR(SDNode *N, SDValue &Lo, SDValue &Hi) { SDValue Vec = N->getOperand(0); SDValue Idx = N->getOperand(1); - EVT IdxVT = Idx.getValueType(); DebugLoc dl = N->getDebugLoc(); EVT LoVT, HiVT; GetSplitDestVTs(N->getValueType(0), LoVT, HiVT); Lo = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, LoVT, Vec, Idx); - Idx = DAG.getNode(ISD::ADD, dl, IdxVT, Idx, - DAG.getConstant(LoVT.getVectorNumElements(), IdxVT)); - Hi = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, HiVT, Vec, Idx); + uint64_t IdxVal = cast(Idx)->getZExtValue(); + Hi = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, HiVT, Vec, + DAG.getIntPtrConstant(IdxVal + LoVT.getVectorNumElements())); } void DAGTypeLegalizer::SplitVecRes_FPOWI(SDNode *N, SDValue &Lo, @@ -705,8 +703,8 @@ void DAGTypeLegalizer::SplitVecRes_INSERT_VECTOR_ELT(SDNode *N, SDValue &Lo, EVT VecVT = Vec.getValueType(); EVT EltVT = VecVT.getVectorElementType(); SDValue StackPtr = DAG.CreateStackTemporary(VecVT); - SDValue Store = DAG.getStore(DAG.getEntryNode(), dl, Vec, StackPtr, NULL, 0, - false, false, 0); + SDValue Store = DAG.getStore(DAG.getEntryNode(), dl, Vec, StackPtr, + MachinePointerInfo(), false, false, 0); // Store the new element. This may be larger than the vector element type, // so use a truncating store. @@ -714,11 +712,11 @@ void DAGTypeLegalizer::SplitVecRes_INSERT_VECTOR_ELT(SDNode *N, SDValue &Lo, const Type *VecType = VecVT.getTypeForEVT(*DAG.getContext()); unsigned Alignment = TLI.getTargetData()->getPrefTypeAlignment(VecType); - Store = DAG.getTruncStore(Store, dl, Elt, EltPtr, NULL, 0, EltVT, + Store = DAG.getTruncStore(Store, dl, Elt, EltPtr, MachinePointerInfo(), EltVT, false, false, 0); // Load the Lo part from the stack slot. - Lo = DAG.getLoad(Lo.getValueType(), dl, Store, StackPtr, NULL, 0, + Lo = DAG.getLoad(Lo.getValueType(), dl, Store, StackPtr, MachinePointerInfo(), false, false, 0); // Increment the pointer to the other part. @@ -727,8 +725,8 @@ void DAGTypeLegalizer::SplitVecRes_INSERT_VECTOR_ELT(SDNode *N, SDValue &Lo, DAG.getIntPtrConstant(IncrementSize)); // Load the Hi part from the stack slot. - Hi = DAG.getLoad(Hi.getValueType(), dl, Store, StackPtr, NULL, 0, false, - false, MinAlign(Alignment, IncrementSize)); + Hi = DAG.getLoad(Hi.getValueType(), dl, Store, StackPtr, MachinePointerInfo(), + false, false, MinAlign(Alignment, IncrementSize)); } void DAGTypeLegalizer::SplitVecRes_SCALAR_TO_VECTOR(SDNode *N, SDValue &Lo, @@ -751,8 +749,6 @@ void DAGTypeLegalizer::SplitVecRes_LOAD(LoadSDNode *LD, SDValue &Lo, SDValue Ch = LD->getChain(); SDValue Ptr = LD->getBasePtr(); SDValue Offset = DAG.getUNDEF(Ptr.getValueType()); - const Value *SV = LD->getSrcValue(); - int SVOffset = LD->getSrcValueOffset(); EVT MemoryVT = LD->getMemoryVT(); unsigned Alignment = LD->getOriginalAlignment(); bool isVolatile = LD->isVolatile(); @@ -762,14 +758,15 @@ void DAGTypeLegalizer::SplitVecRes_LOAD(LoadSDNode *LD, SDValue &Lo, GetSplitDestVTs(MemoryVT, LoMemVT, HiMemVT); Lo = DAG.getLoad(ISD::UNINDEXED, ExtType, LoVT, dl, Ch, Ptr, Offset, - SV, SVOffset, LoMemVT, isVolatile, isNonTemporal, Alignment); + LD->getPointerInfo(), LoMemVT, isVolatile, isNonTemporal, + Alignment); unsigned IncrementSize = LoMemVT.getSizeInBits()/8; Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, DAG.getIntPtrConstant(IncrementSize)); - SVOffset += IncrementSize; Hi = DAG.getLoad(ISD::UNINDEXED, ExtType, HiVT, dl, Ch, Ptr, Offset, - SV, SVOffset, HiMemVT, isVolatile, isNonTemporal, Alignment); + LD->getPointerInfo().getWithOffset(IncrementSize), + HiMemVT, isVolatile, isNonTemporal, Alignment); // Build a factor node to remember that this load is independent of the // other one. @@ -980,10 +977,11 @@ bool DAGTypeLegalizer::SplitVectorOperand(SDNode *N, unsigned OpNo) { #endif llvm_unreachable("Do not know how to split this operator's operand!"); - case ISD::BIT_CONVERT: Res = SplitVecOp_BIT_CONVERT(N); break; + case ISD::BITCAST: Res = SplitVecOp_BITCAST(N); break; case ISD::EXTRACT_SUBVECTOR: Res = SplitVecOp_EXTRACT_SUBVECTOR(N); break; case ISD::EXTRACT_VECTOR_ELT:Res = SplitVecOp_EXTRACT_VECTOR_ELT(N); break; case ISD::CONCAT_VECTORS: Res = SplitVecOp_CONCAT_VECTORS(N); break; + case ISD::FP_ROUND: Res = SplitVecOp_FP_ROUND(N); break; case ISD::STORE: Res = SplitVecOp_STORE(cast(N), OpNo); break; @@ -995,6 +993,8 @@ bool DAGTypeLegalizer::SplitVectorOperand(SDNode *N, unsigned OpNo) { case ISD::FP_TO_UINT: case ISD::SINT_TO_FP: case ISD::UINT_TO_FP: + case ISD::FP_EXTEND: + case ISD::FTRUNC: case ISD::TRUNCATE: case ISD::SIGN_EXTEND: case ISD::ZERO_EXTEND: @@ -1036,8 +1036,8 @@ SDValue DAGTypeLegalizer::SplitVecOp_UnaryOp(SDNode *N) { return DAG.getNode(ISD::CONCAT_VECTORS, dl, ResVT, Lo, Hi); } -SDValue DAGTypeLegalizer::SplitVecOp_BIT_CONVERT(SDNode *N) { - // For example, i64 = BIT_CONVERT v4i16 on alpha. Typically the vector will +SDValue DAGTypeLegalizer::SplitVecOp_BITCAST(SDNode *N) { + // For example, i64 = BITCAST v4i16 on alpha. Typically the vector will // end up being split all the way down to individual components. Convert the // split pieces into integers and reassemble. SDValue Lo, Hi; @@ -1048,13 +1048,12 @@ SDValue DAGTypeLegalizer::SplitVecOp_BIT_CONVERT(SDNode *N) { if (TLI.isBigEndian()) std::swap(Lo, Hi); - return DAG.getNode(ISD::BIT_CONVERT, N->getDebugLoc(), N->getValueType(0), + return DAG.getNode(ISD::BITCAST, N->getDebugLoc(), N->getValueType(0), JoinIntegers(Lo, Hi)); } SDValue DAGTypeLegalizer::SplitVecOp_EXTRACT_SUBVECTOR(SDNode *N) { - // We know that the extracted result type is legal. For now, assume the index - // is a constant. + // We know that the extracted result type is legal. EVT SubVT = N->getValueType(0); SDValue Idx = N->getOperand(1); DebugLoc dl = N->getDebugLoc(); @@ -1099,15 +1098,13 @@ SDValue DAGTypeLegalizer::SplitVecOp_EXTRACT_VECTOR_ELT(SDNode *N) { EVT EltVT = VecVT.getVectorElementType(); DebugLoc dl = N->getDebugLoc(); SDValue StackPtr = DAG.CreateStackTemporary(VecVT); - int SPFI = cast(StackPtr.getNode())->getIndex(); - const Value *SV = PseudoSourceValue::getFixedStack(SPFI); - SDValue Store = DAG.getStore(DAG.getEntryNode(), dl, Vec, StackPtr, SV, 0, - false, false, 0); + SDValue Store = DAG.getStore(DAG.getEntryNode(), dl, Vec, StackPtr, + MachinePointerInfo(), false, false, 0); // Load back the required element. StackPtr = GetVectorElementPointer(StackPtr, EltVT, Idx); - return DAG.getExtLoad(ISD::EXTLOAD, N->getValueType(0), dl, Store, StackPtr, - SV, 0, EltVT, false, false, 0); + return DAG.getExtLoad(ISD::EXTLOAD, dl, N->getValueType(0), Store, StackPtr, + MachinePointerInfo(), EltVT, false, false, 0); } SDValue DAGTypeLegalizer::SplitVecOp_STORE(StoreSDNode *N, unsigned OpNo) { @@ -1118,7 +1115,6 @@ SDValue DAGTypeLegalizer::SplitVecOp_STORE(StoreSDNode *N, unsigned OpNo) { bool isTruncating = N->isTruncatingStore(); SDValue Ch = N->getChain(); SDValue Ptr = N->getBasePtr(); - int SVOffset = N->getSrcValueOffset(); EVT MemoryVT = N->getMemoryVT(); unsigned Alignment = N->getOriginalAlignment(); bool isVol = N->isVolatile(); @@ -1132,22 +1128,23 @@ SDValue DAGTypeLegalizer::SplitVecOp_STORE(StoreSDNode *N, unsigned OpNo) { unsigned IncrementSize = LoMemVT.getSizeInBits()/8; if (isTruncating) - Lo = DAG.getTruncStore(Ch, DL, Lo, Ptr, N->getSrcValue(), SVOffset, + Lo = DAG.getTruncStore(Ch, DL, Lo, Ptr, N->getPointerInfo(), LoMemVT, isVol, isNT, Alignment); else - Lo = DAG.getStore(Ch, DL, Lo, Ptr, N->getSrcValue(), SVOffset, + Lo = DAG.getStore(Ch, DL, Lo, Ptr, N->getPointerInfo(), isVol, isNT, Alignment); // Increment the pointer to the other half. Ptr = DAG.getNode(ISD::ADD, DL, Ptr.getValueType(), Ptr, DAG.getIntPtrConstant(IncrementSize)); - SVOffset += IncrementSize; if (isTruncating) - Hi = DAG.getTruncStore(Ch, DL, Hi, Ptr, N->getSrcValue(), SVOffset, + Hi = DAG.getTruncStore(Ch, DL, Hi, Ptr, + N->getPointerInfo().getWithOffset(IncrementSize), HiMemVT, isVol, isNT, Alignment); else - Hi = DAG.getStore(Ch, DL, Hi, Ptr, N->getSrcValue(), SVOffset, + Hi = DAG.getStore(Ch, DL, Hi, Ptr, + N->getPointerInfo().getWithOffset(IncrementSize), isVol, isNT, Alignment); return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, Lo, Hi); @@ -1155,7 +1152,7 @@ SDValue DAGTypeLegalizer::SplitVecOp_STORE(StoreSDNode *N, unsigned OpNo) { SDValue DAGTypeLegalizer::SplitVecOp_CONCAT_VECTORS(SDNode *N) { DebugLoc DL = N->getDebugLoc(); - + // The input operands all must have the same type, and we know the result the // result type is valid. Convert this to a buildvector which extracts all the // input elements. @@ -1172,11 +1169,29 @@ SDValue DAGTypeLegalizer::SplitVecOp_CONCAT_VECTORS(SDNode *N) { } } - + return DAG.getNode(ISD::BUILD_VECTOR, DL, N->getValueType(0), &Elts[0], Elts.size()); } +SDValue DAGTypeLegalizer::SplitVecOp_FP_ROUND(SDNode *N) { + // The result has a legal vector type, but the input needs splitting. + EVT ResVT = N->getValueType(0); + SDValue Lo, Hi; + DebugLoc DL = N->getDebugLoc(); + GetSplitVector(N->getOperand(0), Lo, Hi); + EVT InVT = Lo.getValueType(); + + EVT OutVT = EVT::getVectorVT(*DAG.getContext(), ResVT.getVectorElementType(), + InVT.getVectorNumElements()); + + Lo = DAG.getNode(ISD::FP_ROUND, DL, OutVT, Lo, N->getOperand(1)); + Hi = DAG.getNode(ISD::FP_ROUND, DL, OutVT, Hi, N->getOperand(1)); + + return DAG.getNode(ISD::CONCAT_VECTORS, DL, ResVT, Lo, Hi); +} + + //===----------------------------------------------------------------------===// // Result Vector Widening @@ -1201,7 +1216,7 @@ void DAGTypeLegalizer::WidenVectorResult(SDNode *N, unsigned ResNo) { #endif llvm_unreachable("Do not know how to widen the result of this operator!"); - case ISD::BIT_CONVERT: Res = WidenVecRes_BIT_CONVERT(N); break; + case ISD::BITCAST: Res = WidenVecRes_BITCAST(N); break; case ISD::BUILD_VECTOR: Res = WidenVecRes_BUILD_VECTOR(N); break; case ISD::CONCAT_VECTORS: Res = WidenVecRes_CONCAT_VECTORS(N); break; case ISD::CONVERT_RNDSAT: Res = WidenVecRes_CONVERT_RNDSAT(N); break; @@ -1297,7 +1312,7 @@ SDValue DAGTypeLegalizer::WidenVecRes_Binary(SDNode *N) { EVT WidenEltVT = WidenVT.getVectorElementType(); EVT VT = WidenVT; unsigned NumElts = VT.getVectorNumElements(); - while (!TLI.isTypeSynthesizable(VT) && NumElts != 1) { + while (!TLI.isTypeLegal(VT) && NumElts != 1) { NumElts = NumElts / 2; VT = EVT::getVectorVT(*DAG.getContext(), WidenEltVT, NumElts); } @@ -1308,11 +1323,11 @@ SDValue DAGTypeLegalizer::WidenVecRes_Binary(SDNode *N) { SDValue InOp2 = GetWidenedVector(N->getOperand(1)); return DAG.getNode(N->getOpcode(), dl, WidenVT, InOp1, InOp2); } - + // No legal vector version so unroll the vector operation and then widen. if (NumElts == 1) return DAG.UnrollVectorOp(N, WidenVT.getVectorNumElements()); - + // Since the operation can trap, apply operation on the original vector. EVT MaxVT = VT; SDValue InOp1 = GetWidenedVector(N->getOperand(0)); @@ -1323,7 +1338,7 @@ SDValue DAGTypeLegalizer::WidenVecRes_Binary(SDNode *N) { unsigned ConcatEnd = 0; // Current ConcatOps index. int Idx = 0; // Current Idx into input vectors. - // NumElts := greatest synthesizable vector size (at most WidenVT) + // NumElts := greatest legal vector size (at most WidenVT) // while (orig. vector has unhandled elements) { // take munches of size NumElts from the beginning and add to ConcatOps // NumElts := next smaller supported vector size or 1 @@ -1341,13 +1356,13 @@ SDValue DAGTypeLegalizer::WidenVecRes_Binary(SDNode *N) { do { NumElts = NumElts / 2; VT = EVT::getVectorVT(*DAG.getContext(), WidenEltVT, NumElts); - } while (!TLI.isTypeSynthesizable(VT) && NumElts != 1); + } while (!TLI.isTypeLegal(VT) && NumElts != 1); if (NumElts == 1) { for (unsigned i = 0; i != CurNumElts; ++i, ++Idx) { - SDValue EOp1 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, WidenEltVT, + SDValue EOp1 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, WidenEltVT, InOp1, DAG.getIntPtrConstant(Idx)); - SDValue EOp2 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, WidenEltVT, + SDValue EOp2 = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, WidenEltVT, InOp2, DAG.getIntPtrConstant(Idx)); ConcatOps[ConcatEnd++] = DAG.getNode(Opcode, dl, WidenEltVT, EOp1, EOp2); @@ -1378,7 +1393,7 @@ SDValue DAGTypeLegalizer::WidenVecRes_Binary(SDNode *N) { do { NextSize *= 2; NextVT = EVT::getVectorVT(*DAG.getContext(), WidenEltVT, NextSize); - } while (!TLI.isTypeSynthesizable(NextVT)); + } while (!TLI.isTypeLegal(NextVT)); if (!VT.isVector()) { // Scalar type, create an INSERT_VECTOR_ELEMENT of type NextVT @@ -1415,7 +1430,7 @@ SDValue DAGTypeLegalizer::WidenVecRes_Binary(SDNode *N) { if (VT == WidenVT) return ConcatOps[0]; } - + // add undefs of size MaxVT until ConcatOps grows to length of WidenVT unsigned NumOps = WidenVT.getVectorNumElements()/MaxVT.getVectorNumElements(); if (NumOps != ConcatEnd ) { @@ -1428,7 +1443,7 @@ SDValue DAGTypeLegalizer::WidenVecRes_Binary(SDNode *N) { SDValue DAGTypeLegalizer::WidenVecRes_Convert(SDNode *N) { SDValue InOp = N->getOperand(0); - DebugLoc dl = N->getDebugLoc(); + DebugLoc DL = N->getDebugLoc(); EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); unsigned WidenNumElts = WidenVT.getVectorNumElements(); @@ -1444,11 +1459,14 @@ SDValue DAGTypeLegalizer::WidenVecRes_Convert(SDNode *N) { InOp = GetWidenedVector(N->getOperand(0)); InVT = InOp.getValueType(); InVTNumElts = InVT.getVectorNumElements(); - if (InVTNumElts == WidenNumElts) - return DAG.getNode(Opcode, dl, WidenVT, InOp); + if (InVTNumElts == WidenNumElts) { + if (N->getNumOperands() == 1) + return DAG.getNode(Opcode, DL, WidenVT, InOp); + return DAG.getNode(Opcode, DL, WidenVT, InOp, N->getOperand(1)); + } } - if (TLI.isTypeSynthesizable(InWidenVT)) { + if (TLI.isTypeLegal(InWidenVT)) { // Because the result and the input are different vector types, widening // the result could create a legal type but widening the input might make // it an illegal type that might lead to repeatedly splitting the input @@ -1462,16 +1480,20 @@ SDValue DAGTypeLegalizer::WidenVecRes_Convert(SDNode *N) { SDValue UndefVal = DAG.getUNDEF(InVT); for (unsigned i = 1; i != NumConcat; ++i) Ops[i] = UndefVal; - return DAG.getNode(Opcode, dl, WidenVT, - DAG.getNode(ISD::CONCAT_VECTORS, dl, InWidenVT, - &Ops[0], NumConcat)); + SDValue InVec = DAG.getNode(ISD::CONCAT_VECTORS, DL, InWidenVT, + &Ops[0], NumConcat); + if (N->getNumOperands() == 1) + return DAG.getNode(Opcode, DL, WidenVT, InVec); + return DAG.getNode(Opcode, DL, WidenVT, InVec, N->getOperand(1)); } if (InVTNumElts % WidenNumElts == 0) { + SDValue InVal = DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, InWidenVT, + InOp, DAG.getIntPtrConstant(0)); // Extract the input and convert the shorten input vector. - return DAG.getNode(Opcode, dl, WidenVT, - DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, InWidenVT, - InOp, DAG.getIntPtrConstant(0))); + if (N->getNumOperands() == 1) + return DAG.getNode(Opcode, DL, WidenVT, InVal); + return DAG.getNode(Opcode, DL, WidenVT, InVal, N->getOperand(1)); } } @@ -1480,16 +1502,20 @@ SDValue DAGTypeLegalizer::WidenVecRes_Convert(SDNode *N) { EVT EltVT = WidenVT.getVectorElementType(); unsigned MinElts = std::min(InVTNumElts, WidenNumElts); unsigned i; - for (i=0; i < MinElts; ++i) - Ops[i] = DAG.getNode(Opcode, dl, EltVT, - DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, InEltVT, InOp, - DAG.getIntPtrConstant(i))); + for (i=0; i < MinElts; ++i) { + SDValue Val = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, InEltVT, InOp, + DAG.getIntPtrConstant(i)); + if (N->getNumOperands() == 1) + Ops[i] = DAG.getNode(Opcode, DL, EltVT, Val); + else + Ops[i] = DAG.getNode(Opcode, DL, EltVT, Val, N->getOperand(1)); + } SDValue UndefVal = DAG.getUNDEF(EltVT); for (; i < WidenNumElts; ++i) Ops[i] = UndefVal; - return DAG.getNode(ISD::BUILD_VECTOR, dl, WidenVT, &Ops[0], WidenNumElts); + return DAG.getNode(ISD::BUILD_VECTOR, DL, WidenVT, &Ops[0], WidenNumElts); } SDValue DAGTypeLegalizer::WidenVecRes_POWI(SDNode *N) { @@ -1536,7 +1562,7 @@ SDValue DAGTypeLegalizer::WidenVecRes_InregOp(SDNode *N) { WidenVT, WidenLHS, DAG.getValueType(ExtVT)); } -SDValue DAGTypeLegalizer::WidenVecRes_BIT_CONVERT(SDNode *N) { +SDValue DAGTypeLegalizer::WidenVecRes_BITCAST(SDNode *N) { SDValue InOp = N->getOperand(0); EVT InVT = InOp.getValueType(); EVT VT = N->getValueType(0); @@ -1555,7 +1581,7 @@ SDValue DAGTypeLegalizer::WidenVecRes_BIT_CONVERT(SDNode *N) { InOp = GetPromotedInteger(InOp); InVT = InOp.getValueType(); if (WidenVT.bitsEq(InVT)) - return DAG.getNode(ISD::BIT_CONVERT, dl, WidenVT, InOp); + return DAG.getNode(ISD::BITCAST, dl, WidenVT, InOp); break; case SoftenFloat: case ExpandInteger: @@ -1570,13 +1596,14 @@ SDValue DAGTypeLegalizer::WidenVecRes_BIT_CONVERT(SDNode *N) { InVT = InOp.getValueType(); if (WidenVT.bitsEq(InVT)) // The input widens to the same size. Convert to the widen value. - return DAG.getNode(ISD::BIT_CONVERT, dl, WidenVT, InOp); + return DAG.getNode(ISD::BITCAST, dl, WidenVT, InOp); break; } unsigned WidenSize = WidenVT.getSizeInBits(); unsigned InSize = InVT.getSizeInBits(); - if (WidenSize % InSize == 0) { + // x86mmx is not an acceptable vector element type, so don't try. + if (WidenSize % InSize == 0 && InVT != MVT::x86mmx) { // Determine new input vector type. The new input vector type will use // the same element type (if its a vector) or use the input type as a // vector. It is the same size as the type to widen to. @@ -1590,7 +1617,7 @@ SDValue DAGTypeLegalizer::WidenVecRes_BIT_CONVERT(SDNode *N) { NewInVT = EVT::getVectorVT(*DAG.getContext(), InVT, NewNumElts); } - if (TLI.isTypeSynthesizable(NewInVT)) { + if (TLI.isTypeLegal(NewInVT)) { // Because the result and the input are different vector types, widening // the result could create a legal type but widening the input might make // it an illegal type that might lead to repeatedly splitting the input @@ -1609,7 +1636,7 @@ SDValue DAGTypeLegalizer::WidenVecRes_BIT_CONVERT(SDNode *N) { else NewVec = DAG.getNode(ISD::BUILD_VECTOR, dl, NewInVT, &Ops[0], NewNumElts); - return DAG.getNode(ISD::BIT_CONVERT, dl, WidenVT, NewVec); + return DAG.getNode(ISD::BITCAST, dl, WidenVT, NewVec); } } @@ -1730,7 +1757,7 @@ SDValue DAGTypeLegalizer::WidenVecRes_CONVERT_RNDSAT(SDNode *N) { SatOp, CvtCode); } - if (TLI.isTypeSynthesizable(InWidenVT)) { + if (TLI.isTypeLegal(InWidenVT)) { // Because the result and the input are different vector types, widening // the result could create a legal type but widening the input might make // it an illegal type that might lead to repeatedly splitting the input @@ -1794,39 +1821,25 @@ SDValue DAGTypeLegalizer::WidenVecRes_EXTRACT_SUBVECTOR(SDNode *N) { EVT InVT = InOp.getValueType(); - ConstantSDNode *CIdx = dyn_cast(Idx); - if (CIdx) { - unsigned IdxVal = CIdx->getZExtValue(); - // Check if we can just return the input vector after widening. - if (IdxVal == 0 && InVT == WidenVT) - return InOp; - - // Check if we can extract from the vector. - unsigned InNumElts = InVT.getVectorNumElements(); - if (IdxVal % WidenNumElts == 0 && IdxVal + WidenNumElts < InNumElts) - return DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, WidenVT, InOp, Idx); - } + // Check if we can just return the input vector after widening. + uint64_t IdxVal = cast(Idx)->getZExtValue(); + if (IdxVal == 0 && InVT == WidenVT) + return InOp; + + // Check if we can extract from the vector. + unsigned InNumElts = InVT.getVectorNumElements(); + if (IdxVal % WidenNumElts == 0 && IdxVal + WidenNumElts < InNumElts) + return DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, WidenVT, InOp, Idx); // We could try widening the input to the right length but for now, extract // the original elements, fill the rest with undefs and build a vector. SmallVector Ops(WidenNumElts); EVT EltVT = VT.getVectorElementType(); - EVT IdxVT = Idx.getValueType(); unsigned NumElts = VT.getVectorNumElements(); unsigned i; - if (CIdx) { - unsigned IdxVal = CIdx->getZExtValue(); - for (i=0; i < NumElts; ++i) - Ops[i] = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, EltVT, InOp, - DAG.getConstant(IdxVal+i, IdxVT)); - } else { - Ops[0] = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, EltVT, InOp, Idx); - for (i=1; i < NumElts; ++i) { - SDValue NewIdx = DAG.getNode(ISD::ADD, dl, Idx.getValueType(), Idx, - DAG.getConstant(i, IdxVT)); - Ops[i] = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, EltVT, InOp, NewIdx); - } - } + for (i=0; i < NumElts; ++i) + Ops[i] = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, EltVT, InOp, + DAG.getIntPtrConstant(IdxVal+i)); SDValue UndefVal = DAG.getUNDEF(EltVT); for (; i < WidenNumElts; ++i) @@ -1985,7 +1998,7 @@ bool DAGTypeLegalizer::WidenVectorOperand(SDNode *N, unsigned ResNo) { #endif llvm_unreachable("Do not know how to widen this operator's operand!"); - case ISD::BIT_CONVERT: Res = WidenVecOp_BIT_CONVERT(N); break; + case ISD::BITCAST: Res = WidenVecOp_BITCAST(N); break; case ISD::CONCAT_VECTORS: Res = WidenVecOp_CONCAT_VECTORS(N); break; case ISD::EXTRACT_SUBVECTOR: Res = WidenVecOp_EXTRACT_SUBVECTOR(N); break; case ISD::EXTRACT_VECTOR_ELT: Res = WidenVecOp_EXTRACT_VECTOR_ELT(N); break; @@ -2044,7 +2057,7 @@ SDValue DAGTypeLegalizer::WidenVecOp_Convert(SDNode *N) { return DAG.getNode(ISD::BUILD_VECTOR, dl, VT, &Ops[0], NumElts); } -SDValue DAGTypeLegalizer::WidenVecOp_BIT_CONVERT(SDNode *N) { +SDValue DAGTypeLegalizer::WidenVecOp_BITCAST(SDNode *N) { EVT VT = N->getValueType(0); SDValue InOp = GetWidenedVector(N->getOperand(0)); EVT InWidenVT = InOp.getValueType(); @@ -2053,11 +2066,12 @@ SDValue DAGTypeLegalizer::WidenVecOp_BIT_CONVERT(SDNode *N) { // Check if we can convert between two legal vector types and extract. unsigned InWidenSize = InWidenVT.getSizeInBits(); unsigned Size = VT.getSizeInBits(); - if (InWidenSize % Size == 0 && !VT.isVector()) { + // x86mmx is not an acceptable vector element type, so don't try. + if (InWidenSize % Size == 0 && !VT.isVector() && VT != MVT::x86mmx) { unsigned NewNumElts = InWidenSize / Size; EVT NewVT = EVT::getVectorVT(*DAG.getContext(), VT, NewNumElts); - if (TLI.isTypeSynthesizable(NewVT)) { - SDValue BitOp = DAG.getNode(ISD::BIT_CONVERT, dl, NewVT, InOp); + if (TLI.isTypeLegal(NewVT)) { + SDValue BitOp = DAG.getNode(ISD::BITCAST, dl, NewVT, InOp); return DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, VT, BitOp, DAG.getIntPtrConstant(0)); } @@ -2146,7 +2160,7 @@ static EVT FindMemType(SelectionDAG& DAG, const TargetLowering &TLI, if (Width == WidenEltWidth) return RetVT; - // See if there is larger legal integer than the element type to load/store + // See if there is larger legal integer than the element type to load/store unsigned VT; for (VT = (unsigned)MVT::LAST_INTEGER_VALUETYPE; VT >= (unsigned)MVT::FIRST_INTEGER_VALUETYPE; --VT) { @@ -2154,7 +2168,7 @@ static EVT FindMemType(SelectionDAG& DAG, const TargetLowering &TLI, unsigned MemVTWidth = MemVT.getSizeInBits(); if (MemVT.getSizeInBits() <= WidenEltWidth) break; - if (TLI.isTypeSynthesizable(MemVT) && (WidenWidth % MemVTWidth) == 0 && + if (TLI.isTypeLegal(MemVT) && (WidenWidth % MemVTWidth) == 0 && (MemVTWidth <= Width || (Align!=0 && MemVTWidth<=AlignInBits && MemVTWidth<=Width+WidenEx))) { RetVT = MemVT; @@ -2168,7 +2182,7 @@ static EVT FindMemType(SelectionDAG& DAG, const TargetLowering &TLI, VT >= (unsigned)MVT::FIRST_VECTOR_VALUETYPE; --VT) { EVT MemVT = (MVT::SimpleValueType) VT; unsigned MemVTWidth = MemVT.getSizeInBits(); - if (TLI.isTypeSynthesizable(MemVT) && WidenEltVT == MemVT.getVectorElementType() && + if (TLI.isTypeLegal(MemVT) && WidenEltVT == MemVT.getVectorElementType() && (WidenWidth % MemVTWidth) == 0 && (MemVTWidth <= Width || (Align!=0 && MemVTWidth<=AlignInBits && MemVTWidth<=Width+WidenEx))) { @@ -2201,7 +2215,7 @@ static SDValue BuildVectorFromScalar(SelectionDAG& DAG, EVT VecTy, if (NewLdTy != LdTy) { NumElts = Width / NewLdTy.getSizeInBits(); NewVecVT = EVT::getVectorVT(*DAG.getContext(), NewLdTy, NumElts); - VecOp = DAG.getNode(ISD::BIT_CONVERT, dl, NewVecVT, VecOp); + VecOp = DAG.getNode(ISD::BITCAST, dl, NewVecVT, VecOp); // Readjust position and vector position based on new load type Idx = Idx * LdTy.getSizeInBits() / NewLdTy.getSizeInBits(); LdTy = NewLdTy; @@ -2209,11 +2223,11 @@ static SDValue BuildVectorFromScalar(SelectionDAG& DAG, EVT VecTy, VecOp = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, NewVecVT, VecOp, LdOps[i], DAG.getIntPtrConstant(Idx++)); } - return DAG.getNode(ISD::BIT_CONVERT, dl, VecTy, VecOp); + return DAG.getNode(ISD::BITCAST, dl, VecTy, VecOp); } -SDValue DAGTypeLegalizer::GenWidenVectorLoads(SmallVector& LdChain, - LoadSDNode * LD) { +SDValue DAGTypeLegalizer::GenWidenVectorLoads(SmallVector &LdChain, + LoadSDNode *LD) { // The strategy assumes that we can efficiently load powers of two widths. // The routines chops the vector into the largest vector loads with the same // element type or scalar loads and then recombines it to the widen vector @@ -2228,11 +2242,9 @@ SDValue DAGTypeLegalizer::GenWidenVectorLoads(SmallVector& LdChain, // Load information SDValue Chain = LD->getChain(); SDValue BasePtr = LD->getBasePtr(); - int SVOffset = LD->getSrcValueOffset(); unsigned Align = LD->getAlignment(); bool isVolatile = LD->isVolatile(); bool isNonTemporal = LD->isNonTemporal(); - const Value *SV = LD->getSrcValue(); int LdWidth = LdVT.getSizeInBits(); int WidthDiff = WidenWidth - LdWidth; // Difference @@ -2241,7 +2253,7 @@ SDValue DAGTypeLegalizer::GenWidenVectorLoads(SmallVector& LdChain, // Find the vector type that can load from. EVT NewVT = FindMemType(DAG, TLI, LdWidth, WidenVT, LdAlign, WidthDiff); int NewVTWidth = NewVT.getSizeInBits(); - SDValue LdOp = DAG.getLoad(NewVT, dl, Chain, BasePtr, SV, SVOffset, + SDValue LdOp = DAG.getLoad(NewVT, dl, Chain, BasePtr, LD->getPointerInfo(), isVolatile, isNonTemporal, Align); LdChain.push_back(LdOp.getValue(1)); @@ -2251,7 +2263,7 @@ SDValue DAGTypeLegalizer::GenWidenVectorLoads(SmallVector& LdChain, unsigned NumElts = WidenWidth / NewVTWidth; EVT NewVecVT = EVT::getVectorVT(*DAG.getContext(), NewVT, NumElts); SDValue VecOp = DAG.getNode(ISD::SCALAR_TO_VECTOR, dl, NewVecVT, LdOp); - return DAG.getNode(ISD::BIT_CONVERT, dl, WidenVT, VecOp); + return DAG.getNode(ISD::BITCAST, dl, WidenVT, VecOp); } if (NewVT == WidenVT) return LdOp; @@ -2286,8 +2298,9 @@ SDValue DAGTypeLegalizer::GenWidenVectorLoads(SmallVector& LdChain, NewVTWidth = NewVT.getSizeInBits(); } - SDValue LdOp = DAG.getLoad(NewVT, dl, Chain, BasePtr, SV, - SVOffset+Offset, isVolatile, + SDValue LdOp = DAG.getLoad(NewVT, dl, Chain, BasePtr, + LD->getPointerInfo().getWithOffset(Offset), + isVolatile, isNonTemporal, MinAlign(Align, Increment)); LdChain.push_back(LdOp.getValue(1)); LdOps.push_back(LdOp); @@ -2300,7 +2313,7 @@ SDValue DAGTypeLegalizer::GenWidenVectorLoads(SmallVector& LdChain, if (!LdOps[0].getValueType().isVector()) // All the loads are scalar loads. return BuildVectorFromScalar(DAG, WidenVT, LdOps, 0, End); - + // If the load contains vectors, build the vector using concat vector. // All of the vectors used to loads are power of 2 and the scalars load // can be combined to make a power of 2 vector. @@ -2362,11 +2375,9 @@ DAGTypeLegalizer::GenWidenVectorExtLoads(SmallVector& LdChain, // Load information SDValue Chain = LD->getChain(); SDValue BasePtr = LD->getBasePtr(); - int SVOffset = LD->getSrcValueOffset(); unsigned Align = LD->getAlignment(); bool isVolatile = LD->isVolatile(); bool isNonTemporal = LD->isNonTemporal(); - const Value *SV = LD->getSrcValue(); EVT EltVT = WidenVT.getVectorElementType(); EVT LdEltVT = LdVT.getVectorElementType(); @@ -2376,16 +2387,17 @@ DAGTypeLegalizer::GenWidenVectorExtLoads(SmallVector& LdChain, unsigned WidenNumElts = WidenVT.getVectorNumElements(); SmallVector Ops(WidenNumElts); unsigned Increment = LdEltVT.getSizeInBits() / 8; - Ops[0] = DAG.getExtLoad(ExtType, EltVT, dl, Chain, BasePtr, SV, SVOffset, + Ops[0] = DAG.getExtLoad(ExtType, dl, EltVT, Chain, BasePtr, + LD->getPointerInfo(), LdEltVT, isVolatile, isNonTemporal, Align); LdChain.push_back(Ops[0].getValue(1)); unsigned i = 0, Offset = Increment; for (i=1; i < NumElts; ++i, Offset += Increment) { SDValue NewBasePtr = DAG.getNode(ISD::ADD, dl, BasePtr.getValueType(), BasePtr, DAG.getIntPtrConstant(Offset)); - Ops[i] = DAG.getExtLoad(ExtType, EltVT, dl, Chain, NewBasePtr, SV, - SVOffset + Offset, LdEltVT, isVolatile, - isNonTemporal, Align); + Ops[i] = DAG.getExtLoad(ExtType, dl, EltVT, Chain, NewBasePtr, + LD->getPointerInfo().getWithOffset(Offset), LdEltVT, + isVolatile, isNonTemporal, Align); LdChain.push_back(Ops[i].getValue(1)); } @@ -2405,8 +2417,6 @@ void DAGTypeLegalizer::GenWidenVectorStores(SmallVector& StChain, // element type or scalar stores. SDValue Chain = ST->getChain(); SDValue BasePtr = ST->getBasePtr(); - const Value *SV = ST->getSrcValue(); - int SVOffset = ST->getSrcValueOffset(); unsigned Align = ST->getAlignment(); bool isVolatile = ST->isVolatile(); bool isNonTemporal = ST->isNonTemporal(); @@ -2433,9 +2443,9 @@ void DAGTypeLegalizer::GenWidenVectorStores(SmallVector& StChain, do { SDValue EOp = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, NewVT, ValOp, DAG.getIntPtrConstant(Idx)); - StChain.push_back(DAG.getStore(Chain, dl, EOp, BasePtr, SV, - SVOffset + Offset, isVolatile, - isNonTemporal, + StChain.push_back(DAG.getStore(Chain, dl, EOp, BasePtr, + ST->getPointerInfo().getWithOffset(Offset), + isVolatile, isNonTemporal, MinAlign(Align, Offset))); StWidth -= NewVTWidth; Offset += Increment; @@ -2447,15 +2457,16 @@ void DAGTypeLegalizer::GenWidenVectorStores(SmallVector& StChain, // Cast the vector to the scalar type we can store unsigned NumElts = ValWidth / NewVTWidth; EVT NewVecVT = EVT::getVectorVT(*DAG.getContext(), NewVT, NumElts); - SDValue VecOp = DAG.getNode(ISD::BIT_CONVERT, dl, NewVecVT, ValOp); + SDValue VecOp = DAG.getNode(ISD::BITCAST, dl, NewVecVT, ValOp); // Readjust index position based on new vector type Idx = Idx * ValEltWidth / NewVTWidth; do { SDValue EOp = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, NewVT, VecOp, DAG.getIntPtrConstant(Idx++)); - StChain.push_back(DAG.getStore(Chain, dl, EOp, BasePtr, SV, - SVOffset + Offset, isVolatile, - isNonTemporal, MinAlign(Align, Offset))); + StChain.push_back(DAG.getStore(Chain, dl, EOp, BasePtr, + ST->getPointerInfo().getWithOffset(Offset), + isVolatile, isNonTemporal, + MinAlign(Align, Offset))); StWidth -= NewVTWidth; Offset += Increment; BasePtr = DAG.getNode(ISD::ADD, dl, BasePtr.getValueType(), BasePtr, @@ -2474,14 +2485,12 @@ DAGTypeLegalizer::GenWidenVectorTruncStores(SmallVector& StChain, // and then store it. Instead, we extract each element and then store it. SDValue Chain = ST->getChain(); SDValue BasePtr = ST->getBasePtr(); - const Value *SV = ST->getSrcValue(); - int SVOffset = ST->getSrcValueOffset(); unsigned Align = ST->getAlignment(); bool isVolatile = ST->isVolatile(); bool isNonTemporal = ST->isNonTemporal(); SDValue ValOp = GetWidenedVector(ST->getValue()); DebugLoc dl = ST->getDebugLoc(); - + EVT StVT = ST->getMemoryVT(); EVT ValVT = ValOp.getValueType(); @@ -2499,8 +2508,8 @@ DAGTypeLegalizer::GenWidenVectorTruncStores(SmallVector& StChain, unsigned NumElts = StVT.getVectorNumElements(); SDValue EOp = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, ValEltVT, ValOp, DAG.getIntPtrConstant(0)); - StChain.push_back(DAG.getTruncStore(Chain, dl, EOp, BasePtr, SV, - SVOffset, StEltVT, + StChain.push_back(DAG.getTruncStore(Chain, dl, EOp, BasePtr, + ST->getPointerInfo(), StEltVT, isVolatile, isNonTemporal, Align)); unsigned Offset = Increment; for (unsigned i=1; i < NumElts; ++i, Offset += Increment) { @@ -2508,9 +2517,9 @@ DAGTypeLegalizer::GenWidenVectorTruncStores(SmallVector& StChain, BasePtr, DAG.getIntPtrConstant(Offset)); SDValue EOp = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, ValEltVT, ValOp, DAG.getIntPtrConstant(0)); - StChain.push_back(DAG.getTruncStore(Chain, dl, EOp, NewBasePtr, SV, - SVOffset + Offset, StEltVT, - isVolatile, isNonTemporal, + StChain.push_back(DAG.getTruncStore(Chain, dl, EOp, NewBasePtr, + ST->getPointerInfo().getWithOffset(Offset), + StEltVT, isVolatile, isNonTemporal, MinAlign(Align, Offset))); } } diff --git a/lib/CodeGen/SelectionDAG/SDNodeDbgValue.h b/lib/CodeGen/SelectionDAG/SDNodeDbgValue.h index ac2d33884b26..2dcb22957325 100644 --- a/lib/CodeGen/SelectionDAG/SDNodeDbgValue.h +++ b/lib/CodeGen/SelectionDAG/SDNodeDbgValue.h @@ -16,7 +16,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/Support/DebugLoc.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { diff --git a/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp b/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp index fae27294e364..e3da2084529a 100644 --- a/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp +++ b/lib/CodeGen/SelectionDAG/ScheduleDAGFast.cpp @@ -205,7 +205,7 @@ void ScheduleDAGFast::ScheduleNodeBottomUp(SUnit *SU, unsigned CurCycle) { /// CopyAndMoveSuccessors - Clone the specified node and move its scheduled /// successors to the newly created node. SUnit *ScheduleDAGFast::CopyAndMoveSuccessors(SUnit *SU) { - if (SU->getNode()->getFlaggedNode()) + if (SU->getNode()->getGluedNode()) return NULL; SDNode *N = SU->getNode(); @@ -216,7 +216,7 @@ SUnit *ScheduleDAGFast::CopyAndMoveSuccessors(SUnit *SU) { bool TryUnfold = false; for (unsigned i = 0, e = N->getNumValues(); i != e; ++i) { EVT VT = N->getValueType(i); - if (VT == MVT::Flag) + if (VT == MVT::Glue) return NULL; else if (VT == MVT::Other) TryUnfold = true; @@ -224,7 +224,7 @@ SUnit *ScheduleDAGFast::CopyAndMoveSuccessors(SUnit *SU) { for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) { const SDValue &Op = N->getOperand(i); EVT VT = Op.getNode()->getValueType(Op.getResNo()); - if (VT == MVT::Flag) + if (VT == MVT::Glue) return NULL; } @@ -476,12 +476,12 @@ bool ScheduleDAGFast::DelayForLiveRegsBottomUp(SUnit *SU, } } - for (SDNode *Node = SU->getNode(); Node; Node = Node->getFlaggedNode()) { + for (SDNode *Node = SU->getNode(); Node; Node = Node->getGluedNode()) { if (Node->getOpcode() == ISD::INLINEASM) { // Inline asm can clobber physical defs. unsigned NumOps = Node->getNumOperands(); - if (Node->getOperand(NumOps-1).getValueType() == MVT::Flag) - --NumOps; // Ignore the flag operand. + if (Node->getOperand(NumOps-1).getValueType() == MVT::Glue) + --NumOps; // Ignore the glue operand. for (unsigned i = InlineAsm::Op_FirstOperand; i != NumOps;) { unsigned Flags = diff --git a/lib/CodeGen/SelectionDAG/ScheduleDAGList.cpp b/lib/CodeGen/SelectionDAG/ScheduleDAGList.cpp index 56f5ded50083..430283d5eff9 100644 --- a/lib/CodeGen/SelectionDAG/ScheduleDAGList.cpp +++ b/lib/CodeGen/SelectionDAG/ScheduleDAGList.cpp @@ -40,7 +40,7 @@ STATISTIC(NumStalls, "Number of pipeline stalls"); static RegisterScheduler tdListDAGScheduler("list-td", "Top-down list scheduler", createTDListDAGScheduler); - + namespace { //===----------------------------------------------------------------------===// /// ScheduleDAGList - The actual list scheduler implementation. This supports @@ -51,7 +51,7 @@ private: /// AvailableQueue - The priority queue to use for the available SUnits. /// SchedulingPriorityQueue *AvailableQueue; - + /// PendingQueue - This contains all of the instructions whose operands have /// been issued, but their results are not ready yet (due to the latency of /// the operation). Once the operands become available, the instruction is @@ -63,11 +63,12 @@ private: public: ScheduleDAGList(MachineFunction &mf, - SchedulingPriorityQueue *availqueue, - ScheduleHazardRecognizer *HR) - : ScheduleDAGSDNodes(mf), - AvailableQueue(availqueue), HazardRec(HR) { - } + SchedulingPriorityQueue *availqueue) + : ScheduleDAGSDNodes(mf), AvailableQueue(availqueue) { + + const TargetMachine &tm = mf.getTarget(); + HazardRec = tm.getInstrInfo()->CreateTargetHazardRecognizer(&tm, this); + } ~ScheduleDAGList() { delete HazardRec; @@ -87,14 +88,14 @@ private: /// Schedule - Schedule the DAG using list scheduling. void ScheduleDAGList::Schedule() { DEBUG(dbgs() << "********** List Scheduling **********\n"); - + // Build the scheduling graph. BuildSchedGraph(NULL); AvailableQueue->initNodes(SUnits); - + ListScheduleTopDown(); - + AvailableQueue->releaseState(); } @@ -118,7 +119,7 @@ void ScheduleDAGList::ReleaseSucc(SUnit *SU, const SDep &D) { --SuccSU->NumPredsLeft; SuccSU->setDepthToAtLeast(SU->getDepth() + D.getLatency()); - + // If all the node's predecessors are scheduled, this node is ready // to be scheduled. Ignore the special ExitSU node. if (SuccSU->NumPredsLeft == 0 && SuccSU != &ExitSU) @@ -142,7 +143,7 @@ void ScheduleDAGList::ReleaseSuccessors(SUnit *SU) { void ScheduleDAGList::ScheduleNodeTopDown(SUnit *SU, unsigned CurCycle) { DEBUG(dbgs() << "*** Scheduling [" << CurCycle << "]: "); DEBUG(SU->dump(this)); - + Sequence.push_back(SU); assert(CurCycle >= SU->getDepth() && "Node scheduled above its depth!"); SU->setDepthToAtLeast(CurCycle); @@ -168,7 +169,7 @@ void ScheduleDAGList::ListScheduleTopDown() { SUnits[i].isAvailable = true; } } - + // While Available queue is not empty, grab the node with the highest // priority. If it is not ready put it back. Schedule the node. std::vector NotReady; @@ -187,7 +188,7 @@ void ScheduleDAGList::ListScheduleTopDown() { assert(PendingQueue[i]->getDepth() > CurCycle && "Negative latency?"); } } - + // If there are no instructions available, don't try to issue anything, and // don't advance the hazard recognizer. if (AvailableQueue->empty()) { @@ -196,24 +197,24 @@ void ScheduleDAGList::ListScheduleTopDown() { } SUnit *FoundSUnit = 0; - + bool HasNoopHazards = false; while (!AvailableQueue->empty()) { SUnit *CurSUnit = AvailableQueue->pop(); - + ScheduleHazardRecognizer::HazardType HT = - HazardRec->getHazardType(CurSUnit); + HazardRec->getHazardType(CurSUnit, 0/*no stalls*/); if (HT == ScheduleHazardRecognizer::NoHazard) { FoundSUnit = CurSUnit; break; } - + // Remember if this is a noop hazard. HasNoopHazards |= HT == ScheduleHazardRecognizer::NoopHazard; - + NotReady.push_back(CurSUnit); } - + // Add the nodes that aren't ready back onto the available list. if (!NotReady.empty()) { AvailableQueue->push_all(NotReady); @@ -228,7 +229,7 @@ void ScheduleDAGList::ListScheduleTopDown() { // If this is a pseudo-op node, we don't want to increment the current // cycle. if (FoundSUnit->Latency) // Don't increment CurCycle for pseudo-ops! - ++CurCycle; + ++CurCycle; } else if (!HasNoopHazards) { // Otherwise, we have a pipeline stall, but no other problem, just advance // the current cycle and try again. @@ -257,12 +258,8 @@ void ScheduleDAGList::ListScheduleTopDown() { // Public Constructor Functions //===----------------------------------------------------------------------===// -/// createTDListDAGScheduler - This creates a top-down list scheduler with a -/// new hazard recognizer. This scheduler takes ownership of the hazard -/// recognizer and deletes it when done. +/// createTDListDAGScheduler - This creates a top-down list scheduler. ScheduleDAGSDNodes * llvm::createTDListDAGScheduler(SelectionDAGISel *IS, CodeGenOpt::Level) { - return new ScheduleDAGList(*IS->MF, - new LatencyPriorityQueue(), - IS->CreateTargetHazardRecognizer()); + return new ScheduleDAGList(*IS->MF, new LatencyPriorityQueue()); } diff --git a/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp b/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp index 4c3e4e3b0768..0b548b277f4c 100644 --- a/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp +++ b/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp @@ -20,6 +20,7 @@ #include "llvm/InlineAsm.h" #include "llvm/CodeGen/SchedulerRegistry.h" #include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/CodeGen/ScheduleHazardRecognizer.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetMachine.h" @@ -65,6 +66,10 @@ static RegisterScheduler "which tries to balance ILP and register pressure", createILPListDAGScheduler); +static cl::opt DisableSchedCycles( + "disable-sched-cycles", cl::Hidden, cl::init(false), + cl::desc("Disable cycle-level precision during preRA scheduling")); + namespace { //===----------------------------------------------------------------------===// /// ScheduleDAGRRList - The actual register reduction list scheduler @@ -83,31 +88,56 @@ private: /// AvailableQueue - The priority queue to use for the available SUnits. SchedulingPriorityQueue *AvailableQueue; + /// PendingQueue - This contains all of the instructions whose operands have + /// been issued, but their results are not ready yet (due to the latency of + /// the operation). Once the operands becomes available, the instruction is + /// added to the AvailableQueue. + std::vector PendingQueue; + + /// HazardRec - The hazard recognizer to use. + ScheduleHazardRecognizer *HazardRec; + + /// CurCycle - The current scheduler state corresponds to this cycle. + unsigned CurCycle; + + /// MinAvailableCycle - Cycle of the soonest available instruction. + unsigned MinAvailableCycle; + /// LiveRegDefs - A set of physical registers and their definition /// that are "live". These nodes must be scheduled before any other nodes that /// modifies the registers can be scheduled. unsigned NumLiveRegs; std::vector LiveRegDefs; - std::vector LiveRegCycles; + std::vector LiveRegGens; /// Topo - A topological ordering for SUnits which permits fast IsReachable /// and similar queries. ScheduleDAGTopologicalSort Topo; public: - ScheduleDAGRRList(MachineFunction &mf, - bool isbottomup, bool needlatency, - SchedulingPriorityQueue *availqueue) - : ScheduleDAGSDNodes(mf), isBottomUp(isbottomup), NeedLatency(needlatency), - AvailableQueue(availqueue), Topo(SUnits) { - } + ScheduleDAGRRList(MachineFunction &mf, bool needlatency, + SchedulingPriorityQueue *availqueue, + CodeGenOpt::Level OptLevel) + : ScheduleDAGSDNodes(mf), isBottomUp(availqueue->isBottomUp()), + NeedLatency(needlatency), AvailableQueue(availqueue), CurCycle(0), + Topo(SUnits) { + + const TargetMachine &tm = mf.getTarget(); + if (DisableSchedCycles || !NeedLatency) + HazardRec = new ScheduleHazardRecognizer(); + else + HazardRec = tm.getInstrInfo()->CreateTargetHazardRecognizer(&tm, this); + } ~ScheduleDAGRRList() { + delete HazardRec; delete AvailableQueue; } void Schedule(); + ScheduleHazardRecognizer *getHazardRec() { return HazardRec; } + /// IsReachable - Checks if SU is reachable from TargetSU. bool IsReachable(const SUnit *SU, const SUnit *TargetSU) { return Topo.IsReachable(SU, TargetSU); @@ -136,24 +166,37 @@ public: } private: + bool isReady(SUnit *SU) { + return DisableSchedCycles || !AvailableQueue->hasReadyFilter() || + AvailableQueue->isReady(SU); + } + void ReleasePred(SUnit *SU, const SDep *PredEdge); - void ReleasePredecessors(SUnit *SU, unsigned CurCycle); + void ReleasePredecessors(SUnit *SU); void ReleaseSucc(SUnit *SU, const SDep *SuccEdge); void ReleaseSuccessors(SUnit *SU); + void ReleasePending(); + void AdvanceToCycle(unsigned NextCycle); + void AdvancePastStalls(SUnit *SU); + void EmitNode(SUnit *SU); + void ScheduleNodeBottomUp(SUnit*); void CapturePred(SDep *PredEdge); - void ScheduleNodeBottomUp(SUnit*, unsigned); - void ScheduleNodeTopDown(SUnit*, unsigned); void UnscheduleNodeBottomUp(SUnit*); - void BacktrackBottomUp(SUnit*, unsigned, unsigned&); + void RestoreHazardCheckerBottomUp(); + void BacktrackBottomUp(SUnit*, SUnit*); SUnit *CopyAndMoveSuccessors(SUnit*); void InsertCopiesAndMoveSuccs(SUnit*, unsigned, const TargetRegisterClass*, const TargetRegisterClass*, SmallVector&); bool DelayForLiveRegsBottomUp(SUnit*, SmallVector&); - void ListScheduleTopDown(); + + SUnit *PickNodeToScheduleBottomUp(); void ListScheduleBottomUp(); + void ScheduleNodeTopDown(SUnit*); + void ListScheduleTopDown(); + /// CreateNewSUnit - Creates a new SUnit and returns a pointer to it. /// Updates the topological ordering if required. @@ -190,11 +233,13 @@ private: void ScheduleDAGRRList::Schedule() { DEBUG(dbgs() << "********** List Scheduling BB#" << BB->getNumber() - << " **********\n"); + << " '" << BB->getName() << "' **********\n"); + CurCycle = 0; + MinAvailableCycle = DisableSchedCycles ? 0 : UINT_MAX; NumLiveRegs = 0; - LiveRegDefs.resize(TRI->getNumRegs(), NULL); - LiveRegCycles.resize(TRI->getNumRegs(), 0); + LiveRegDefs.resize(TRI->getNumRegs(), NULL); + LiveRegGens.resize(TRI->getNumRegs(), NULL); // Build the scheduling graph. BuildSchedGraph(NULL); @@ -204,13 +249,15 @@ void ScheduleDAGRRList::Schedule() { Topo.InitDAGTopologicalSorting(); AvailableQueue->initNodes(SUnits); - + + HazardRec->Reset(); + // Execute the actual scheduling loop Top-Down or Bottom-Up as appropriate. if (isBottomUp) ListScheduleBottomUp(); else ListScheduleTopDown(); - + AvailableQueue->releaseState(); } @@ -243,33 +290,197 @@ void ScheduleDAGRRList::ReleasePred(SUnit *SU, const SDep *PredEdge) { // to be scheduled. Ignore the special EntrySU node. if (PredSU->NumSuccsLeft == 0 && PredSU != &EntrySU) { PredSU->isAvailable = true; - AvailableQueue->push(PredSU); + + unsigned Height = PredSU->getHeight(); + if (Height < MinAvailableCycle) + MinAvailableCycle = Height; + + if (isReady(SU)) { + AvailableQueue->push(PredSU); + } + // CapturePred and others may have left the node in the pending queue, avoid + // adding it twice. + else if (!PredSU->isPending) { + PredSU->isPending = true; + PendingQueue.push_back(PredSU); + } } } -void ScheduleDAGRRList::ReleasePredecessors(SUnit *SU, unsigned CurCycle) { +/// Call ReleasePred for each predecessor, then update register live def/gen. +/// Always update LiveRegDefs for a register dependence even if the current SU +/// also defines the register. This effectively create one large live range +/// across a sequence of two-address node. This is important because the +/// entire chain must be scheduled together. Example: +/// +/// flags = (3) add +/// flags = (2) addc flags +/// flags = (1) addc flags +/// +/// results in +/// +/// LiveRegDefs[flags] = 3 +/// LiveRegGens[flags] = 1 +/// +/// If (2) addc is unscheduled, then (1) addc must also be unscheduled to avoid +/// interference on flags. +void ScheduleDAGRRList::ReleasePredecessors(SUnit *SU) { // Bottom up: release predecessors for (SUnit::pred_iterator I = SU->Preds.begin(), E = SU->Preds.end(); I != E; ++I) { ReleasePred(SU, &*I); if (I->isAssignedRegDep()) { // This is a physical register dependency and it's impossible or - // expensive to copy the register. Make sure nothing that can + // expensive to copy the register. Make sure nothing that can // clobber the register is scheduled between the predecessor and // this node. - if (!LiveRegDefs[I->getReg()]) { + SUnit *RegDef = LiveRegDefs[I->getReg()]; (void)RegDef; + assert((!RegDef || RegDef == SU || RegDef == I->getSUnit()) && + "interference on register dependence"); + LiveRegDefs[I->getReg()] = I->getSUnit(); + if (!LiveRegGens[I->getReg()]) { ++NumLiveRegs; - LiveRegDefs[I->getReg()] = I->getSUnit(); - LiveRegCycles[I->getReg()] = CurCycle; + LiveRegGens[I->getReg()] = SU; } } } } +/// Check to see if any of the pending instructions are ready to issue. If +/// so, add them to the available queue. +void ScheduleDAGRRList::ReleasePending() { + if (DisableSchedCycles) { + assert(PendingQueue.empty() && "pending instrs not allowed in this mode"); + return; + } + + // If the available queue is empty, it is safe to reset MinAvailableCycle. + if (AvailableQueue->empty()) + MinAvailableCycle = UINT_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 = PendingQueue.size(); i != e; ++i) { + unsigned ReadyCycle = + isBottomUp ? PendingQueue[i]->getHeight() : PendingQueue[i]->getDepth(); + if (ReadyCycle < MinAvailableCycle) + MinAvailableCycle = ReadyCycle; + + if (PendingQueue[i]->isAvailable) { + if (!isReady(PendingQueue[i])) + continue; + AvailableQueue->push(PendingQueue[i]); + } + PendingQueue[i]->isPending = false; + PendingQueue[i] = PendingQueue.back(); + PendingQueue.pop_back(); + --i; --e; + } +} + +/// Move the scheduler state forward by the specified number of Cycles. +void ScheduleDAGRRList::AdvanceToCycle(unsigned NextCycle) { + if (NextCycle <= CurCycle) + return; + + AvailableQueue->setCurCycle(NextCycle); + if (!HazardRec->isEnabled()) { + // Bypass lots of virtual calls in case of long latency. + CurCycle = NextCycle; + } + else { + for (; CurCycle != NextCycle; ++CurCycle) { + if (isBottomUp) + HazardRec->RecedeCycle(); + else + HazardRec->AdvanceCycle(); + } + } + // FIXME: Instead of visiting the pending Q each time, set a dirty flag on the + // available Q to release pending nodes at least once before popping. + ReleasePending(); +} + +/// Move the scheduler state forward until the specified node's dependents are +/// ready and can be scheduled with no resource conflicts. +void ScheduleDAGRRList::AdvancePastStalls(SUnit *SU) { + if (DisableSchedCycles) + return; + + unsigned ReadyCycle = isBottomUp ? SU->getHeight() : SU->getDepth(); + + // Bump CurCycle to account for latency. We assume the latency of other + // available instructions may be hidden by the stall (not a full pipe stall). + // This updates the hazard recognizer's cycle before reserving resources for + // this instruction. + AdvanceToCycle(ReadyCycle); + + // Calls are scheduled in their preceding cycle, so don't conflict with + // hazards from instructions after the call. EmitNode will reset the + // scoreboard state before emitting the call. + if (isBottomUp && SU->isCall) + return; + + // FIXME: For resource conflicts in very long non-pipelined stages, we + // should probably skip ahead here to avoid useless scoreboard checks. + int Stalls = 0; + while (true) { + ScheduleHazardRecognizer::HazardType HT = + HazardRec->getHazardType(SU, isBottomUp ? -Stalls : Stalls); + + if (HT == ScheduleHazardRecognizer::NoHazard) + break; + + ++Stalls; + } + AdvanceToCycle(CurCycle + Stalls); +} + +/// Record this SUnit in the HazardRecognizer. +/// Does not update CurCycle. +void ScheduleDAGRRList::EmitNode(SUnit *SU) { + if (!HazardRec->isEnabled()) + return; + + // Check for phys reg copy. + if (!SU->getNode()) + return; + + switch (SU->getNode()->getOpcode()) { + default: + assert(SU->getNode()->isMachineOpcode() && + "This target-independent node should not be scheduled."); + break; + case ISD::MERGE_VALUES: + case ISD::TokenFactor: + case ISD::CopyToReg: + case ISD::CopyFromReg: + case ISD::EH_LABEL: + // Noops don't affect the scoreboard state. Copies are likely to be + // removed. + return; + case ISD::INLINEASM: + // For inline asm, clear the pipeline state. + HazardRec->Reset(); + return; + } + if (isBottomUp && SU->isCall) { + // Calls are scheduled with their preceding instructions. For bottom-up + // scheduling, clear the pipeline state before emitting. + HazardRec->Reset(); + } + + HazardRec->EmitInstruction(SU); + + if (!isBottomUp && SU->isCall) { + HazardRec->Reset(); + } +} + /// ScheduleNodeBottomUp - Add the node to the schedule. Decrement the pending /// count of its predecessors. If a predecessor pending count is zero, add it to /// the Available queue. -void ScheduleDAGRRList::ScheduleNodeBottomUp(SUnit *SU, unsigned CurCycle) { +void ScheduleDAGRRList::ScheduleNodeBottomUp(SUnit *SU) { DEBUG(dbgs() << "\n*** Scheduling [" << CurCycle << "]: "); DEBUG(SU->dump(this)); @@ -278,36 +489,51 @@ void ScheduleDAGRRList::ScheduleNodeBottomUp(SUnit *SU, unsigned CurCycle) { DEBUG(dbgs() << " Height [" << SU->getHeight() << "] pipeline stall!\n"); #endif - // FIXME: Handle noop hazard. + // FIXME: Do not modify node height. It may interfere with + // backtracking. Instead add a "ready cycle" to SUnit. Before scheduling the + // node it's ready cycle can aid heuristics, and after scheduling it can + // indicate the scheduled cycle. SU->setHeightToAtLeast(CurCycle); + + // Reserve resources for the scheduled intruction. + EmitNode(SU); + Sequence.push_back(SU); AvailableQueue->ScheduledNode(SU); - ReleasePredecessors(SU, CurCycle); + // Update liveness of predecessors before successors to avoid treating a + // two-address node as a live range def. + ReleasePredecessors(SU); // Release all the implicit physical register defs that are live. for (SUnit::succ_iterator I = SU->Succs.begin(), E = SU->Succs.end(); I != E; ++I) { - if (I->isAssignedRegDep()) { - if (LiveRegCycles[I->getReg()] == I->getSUnit()->getHeight()) { - assert(NumLiveRegs > 0 && "NumLiveRegs is already zero!"); - assert(LiveRegDefs[I->getReg()] == SU && - "Physical register dependency violated?"); - --NumLiveRegs; - LiveRegDefs[I->getReg()] = NULL; - LiveRegCycles[I->getReg()] = 0; - } + // LiveRegDegs[I->getReg()] != SU when SU is a two-address node. + if (I->isAssignedRegDep() && LiveRegDefs[I->getReg()] == SU) { + assert(NumLiveRegs > 0 && "NumLiveRegs is already zero!"); + --NumLiveRegs; + LiveRegDefs[I->getReg()] = NULL; + LiveRegGens[I->getReg()] = NULL; } } SU->isScheduled = true; + + // Conditions under which the scheduler should eagerly advance the cycle: + // (1) No available instructions + // (2) All pipelines full, so available instructions must have hazards. + // + // If HazardRec is disabled, count each inst as one cycle. + if (!HazardRec->isEnabled() || HazardRec->atIssueLimit() + || AvailableQueue->empty()) + AdvanceToCycle(CurCycle + 1); } /// CapturePred - This does the opposite of ReleasePred. Since SU is being /// unscheduled, incrcease the succ left count of its predecessors. Remove /// them from AvailableQueue if necessary. -void ScheduleDAGRRList::CapturePred(SDep *PredEdge) { +void ScheduleDAGRRList::CapturePred(SDep *PredEdge) { SUnit *PredSU = PredEdge->getSUnit(); if (PredSU->isAvailable) { PredSU->isAvailable = false; @@ -328,59 +554,98 @@ void ScheduleDAGRRList::UnscheduleNodeBottomUp(SUnit *SU) { for (SUnit::pred_iterator I = SU->Preds.begin(), E = SU->Preds.end(); I != E; ++I) { CapturePred(&*I); - if (I->isAssignedRegDep() && SU->getHeight() == LiveRegCycles[I->getReg()]){ + if (I->isAssignedRegDep() && SU == LiveRegGens[I->getReg()]){ assert(NumLiveRegs > 0 && "NumLiveRegs is already zero!"); assert(LiveRegDefs[I->getReg()] == I->getSUnit() && "Physical register dependency violated?"); --NumLiveRegs; LiveRegDefs[I->getReg()] = NULL; - LiveRegCycles[I->getReg()] = 0; + LiveRegGens[I->getReg()] = NULL; } } for (SUnit::succ_iterator I = SU->Succs.begin(), E = SU->Succs.end(); I != E; ++I) { if (I->isAssignedRegDep()) { + // This becomes the nearest def. Note that an earlier def may still be + // pending if this is a two-address node. + LiveRegDefs[I->getReg()] = SU; if (!LiveRegDefs[I->getReg()]) { - LiveRegDefs[I->getReg()] = SU; ++NumLiveRegs; } - if (I->getSUnit()->getHeight() < LiveRegCycles[I->getReg()]) - LiveRegCycles[I->getReg()] = I->getSUnit()->getHeight(); + if (LiveRegGens[I->getReg()] == NULL || + I->getSUnit()->getHeight() < LiveRegGens[I->getReg()]->getHeight()) + LiveRegGens[I->getReg()] = I->getSUnit(); } } + if (SU->getHeight() < MinAvailableCycle) + MinAvailableCycle = SU->getHeight(); SU->setHeightDirty(); SU->isScheduled = false; SU->isAvailable = true; - AvailableQueue->push(SU); + if (!DisableSchedCycles && AvailableQueue->hasReadyFilter()) { + // Don't make available until backtracking is complete. + SU->isPending = true; + PendingQueue.push_back(SU); + } + else { + AvailableQueue->push(SU); + } AvailableQueue->UnscheduledNode(SU); } +/// After backtracking, the hazard checker needs to be restored to a state +/// corresponding the the current cycle. +void ScheduleDAGRRList::RestoreHazardCheckerBottomUp() { + HazardRec->Reset(); + + unsigned LookAhead = std::min((unsigned)Sequence.size(), + HazardRec->getMaxLookAhead()); + if (LookAhead == 0) + return; + + std::vector::const_iterator I = (Sequence.end() - LookAhead); + unsigned HazardCycle = (*I)->getHeight(); + for (std::vector::const_iterator E = Sequence.end(); I != E; ++I) { + SUnit *SU = *I; + for (; SU->getHeight() > HazardCycle; ++HazardCycle) { + HazardRec->RecedeCycle(); + } + EmitNode(SU); + } +} + /// BacktrackBottomUp - Backtrack scheduling to a previous cycle specified in /// BTCycle in order to schedule a specific node. -void ScheduleDAGRRList::BacktrackBottomUp(SUnit *SU, unsigned BtCycle, - unsigned &CurCycle) { - SUnit *OldSU = NULL; - while (CurCycle > BtCycle) { - OldSU = Sequence.back(); +void ScheduleDAGRRList::BacktrackBottomUp(SUnit *SU, SUnit *BtSU) { + SUnit *OldSU = Sequence.back(); + while (true) { Sequence.pop_back(); if (SU->isSucc(OldSU)) // Don't try to remove SU from AvailableQueue. SU->isAvailable = false; + // FIXME: use ready cycle instead of height + CurCycle = OldSU->getHeight(); UnscheduleNodeBottomUp(OldSU); - --CurCycle; AvailableQueue->setCurCycle(CurCycle); + if (OldSU == BtSU) + break; + OldSU = Sequence.back(); } assert(!SU->isSucc(OldSU) && "Something is wrong!"); + RestoreHazardCheckerBottomUp(); + + ReleasePending(); + ++NumBacktracks; } static bool isOperandOf(const SUnit *SU, SDNode *N) { for (const SDNode *SUNode = SU->getNode(); SUNode; - SUNode = SUNode->getFlaggedNode()) { + SUNode = SUNode->getGluedNode()) { if (SUNode->isOperandOf(N)) return true; } @@ -390,18 +655,18 @@ static bool isOperandOf(const SUnit *SU, SDNode *N) { /// CopyAndMoveSuccessors - Clone the specified node and move its scheduled /// successors to the newly created node. SUnit *ScheduleDAGRRList::CopyAndMoveSuccessors(SUnit *SU) { - if (SU->getNode()->getFlaggedNode()) - return NULL; - SDNode *N = SU->getNode(); if (!N) return NULL; + if (SU->getNode()->getGluedNode()) + return NULL; + SUnit *NewSU; bool TryUnfold = false; for (unsigned i = 0, e = N->getNumValues(); i != e; ++i) { EVT VT = N->getValueType(i); - if (VT == MVT::Flag) + if (VT == MVT::Glue) return NULL; else if (VT == MVT::Other) TryUnfold = true; @@ -409,7 +674,7 @@ SUnit *ScheduleDAGRRList::CopyAndMoveSuccessors(SUnit *SU) { for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) { const SDValue &Op = N->getOperand(i); EVT VT = Op.getNode()->getValueType(Op.getResNo()); - if (VT == MVT::Flag) + if (VT == MVT::Glue) return NULL; } @@ -441,13 +706,15 @@ SUnit *ScheduleDAGRRList::CopyAndMoveSuccessors(SUnit *SU) { } else { LoadSU = CreateNewSUnit(LoadNode); LoadNode->setNodeId(LoadSU->NodeNum); + + InitNumRegDefsLeft(LoadSU); ComputeLatency(LoadSU); } SUnit *NewSU = CreateNewSUnit(N); assert(N->getNodeId() == -1 && "Node already inserted!"); N->setNodeId(NewSU->NodeNum); - + const TargetInstrDesc &TID = TII->get(N->getMachineOpcode()); for (unsigned i = 0; i != TID.getNumOperands(); ++i) { if (TID.getOperandConstraint(i, TOI::TIED_TO) != -1) { @@ -457,6 +724,8 @@ SUnit *ScheduleDAGRRList::CopyAndMoveSuccessors(SUnit *SU) { } if (TID.isCommutable()) NewSU->isCommutable = true; + + InitNumRegDefsLeft(NewSU); ComputeLatency(NewSU); // Record all the edges to and from the old SU, by category. @@ -507,6 +776,10 @@ SUnit *ScheduleDAGRRList::CopyAndMoveSuccessors(SUnit *SU) { RemovePred(SuccDep, D); D.setSUnit(NewSU); AddPred(SuccDep, D); + // Balance register pressure. + if (AvailableQueue->tracksRegPressure() && SuccDep->isScheduled + && !D.isCtrl() && NewSU->NumRegDefsLeft > 0) + --NewSU->NumRegDefsLeft; } for (unsigned i = 0, e = ChainSuccs.size(); i != e; ++i) { SDep D = ChainSuccs[i]; @@ -517,7 +790,7 @@ SUnit *ScheduleDAGRRList::CopyAndMoveSuccessors(SUnit *SU) { D.setSUnit(LoadSU); AddPred(SuccDep, D); } - } + } // Add a data dependency to reflect that NewSU reads the value defined // by LoadSU. @@ -633,52 +906,52 @@ static EVT getPhysicalRegisterVT(SDNode *N, unsigned Reg, /// CheckForLiveRegDef - Return true and update live register vector if the /// specified register def of the specified SUnit clobbers any "live" registers. -static bool CheckForLiveRegDef(SUnit *SU, unsigned Reg, +static void CheckForLiveRegDef(SUnit *SU, unsigned Reg, std::vector &LiveRegDefs, SmallSet &RegAdded, SmallVector &LRegs, const TargetRegisterInfo *TRI) { - bool Added = false; - if (LiveRegDefs[Reg] && LiveRegDefs[Reg] != SU) { - if (RegAdded.insert(Reg)) { + for (const unsigned *AliasI = TRI->getOverlaps(Reg); *AliasI; ++AliasI) { + + // Check if Ref is live. + if (!LiveRegDefs[Reg]) continue; + + // Allow multiple uses of the same def. + if (LiveRegDefs[Reg] == SU) continue; + + // Add Reg to the set of interfering live regs. + if (RegAdded.insert(Reg)) LRegs.push_back(Reg); - Added = true; - } } - for (const unsigned *Alias = TRI->getAliasSet(Reg); *Alias; ++Alias) - if (LiveRegDefs[*Alias] && LiveRegDefs[*Alias] != SU) { - if (RegAdded.insert(*Alias)) { - LRegs.push_back(*Alias); - Added = true; - } - } - return Added; } /// DelayForLiveRegsBottomUp - Returns true if it is necessary to delay /// scheduling of the given node to satisfy live physical register dependencies. /// If the specific node is the last one that's available to schedule, do /// whatever is necessary (i.e. backtracking or cloning) to make it possible. -bool ScheduleDAGRRList::DelayForLiveRegsBottomUp(SUnit *SU, - SmallVector &LRegs){ +bool ScheduleDAGRRList:: +DelayForLiveRegsBottomUp(SUnit *SU, SmallVector &LRegs) { if (NumLiveRegs == 0) return false; SmallSet RegAdded; // If this node would clobber any "live" register, then it's not ready. + // + // If SU is the currently live definition of the same register that it uses, + // then we are free to schedule it. for (SUnit::pred_iterator I = SU->Preds.begin(), E = SU->Preds.end(); I != E; ++I) { - if (I->isAssignedRegDep()) + if (I->isAssignedRegDep() && LiveRegDefs[I->getReg()] != SU) CheckForLiveRegDef(I->getSUnit(), I->getReg(), LiveRegDefs, RegAdded, LRegs, TRI); } - for (SDNode *Node = SU->getNode(); Node; Node = Node->getFlaggedNode()) { + for (SDNode *Node = SU->getNode(); Node; Node = Node->getGluedNode()) { if (Node->getOpcode() == ISD::INLINEASM) { // Inline asm can clobber physical defs. unsigned NumOps = Node->getNumOperands(); - if (Node->getOperand(NumOps-1).getValueType() == MVT::Flag) - --NumOps; // Ignore the flag operand. + if (Node->getOperand(NumOps-1).getValueType() == MVT::Glue) + --NumOps; // Ignore the glue operand. for (unsigned i = InlineAsm::Op_FirstOperand; i != NumOps;) { unsigned Flags = @@ -708,17 +981,151 @@ bool ScheduleDAGRRList::DelayForLiveRegsBottomUp(SUnit *SU, for (const unsigned *Reg = TID.ImplicitDefs; *Reg; ++Reg) CheckForLiveRegDef(SU, *Reg, LiveRegDefs, RegAdded, LRegs, TRI); } + return !LRegs.empty(); } +/// Return a node that can be scheduled in this cycle. Requirements: +/// (1) Ready: latency has been satisfied +/// (2) No Hazards: resources are available +/// (3) No Interferences: may unschedule to break register interferences. +SUnit *ScheduleDAGRRList::PickNodeToScheduleBottomUp() { + SmallVector Interferences; + DenseMap > LRegsMap; + + SUnit *CurSU = AvailableQueue->pop(); + while (CurSU) { + SmallVector LRegs; + if (!DelayForLiveRegsBottomUp(CurSU, LRegs)) + break; + LRegsMap.insert(std::make_pair(CurSU, LRegs)); + + CurSU->isPending = true; // This SU is not in AvailableQueue right now. + Interferences.push_back(CurSU); + CurSU = AvailableQueue->pop(); + } + if (CurSU) { + // Add the nodes that aren't ready back onto the available list. + for (unsigned i = 0, e = Interferences.size(); i != e; ++i) { + Interferences[i]->isPending = false; + assert(Interferences[i]->isAvailable && "must still be available"); + AvailableQueue->push(Interferences[i]); + } + return CurSU; + } + + // All candidates are delayed due to live physical reg dependencies. + // Try backtracking, code duplication, or inserting cross class copies + // to resolve it. + for (unsigned i = 0, e = Interferences.size(); i != e; ++i) { + SUnit *TrySU = Interferences[i]; + SmallVector &LRegs = LRegsMap[TrySU]; + + // Try unscheduling up to the point where it's safe to schedule + // this node. + SUnit *BtSU = NULL; + unsigned LiveCycle = UINT_MAX; + for (unsigned j = 0, ee = LRegs.size(); j != ee; ++j) { + unsigned Reg = LRegs[j]; + if (LiveRegGens[Reg]->getHeight() < LiveCycle) { + BtSU = LiveRegGens[Reg]; + LiveCycle = BtSU->getHeight(); + } + } + if (!WillCreateCycle(TrySU, BtSU)) { + BacktrackBottomUp(TrySU, BtSU); + + // Force the current node to be scheduled before the node that + // requires the physical reg dep. + if (BtSU->isAvailable) { + BtSU->isAvailable = false; + if (!BtSU->isPending) + AvailableQueue->remove(BtSU); + } + AddPred(TrySU, SDep(BtSU, SDep::Order, /*Latency=*/1, + /*Reg=*/0, /*isNormalMemory=*/false, + /*isMustAlias=*/false, /*isArtificial=*/true)); + + // If one or more successors has been unscheduled, then the current + // node is no longer avaialable. Schedule a successor that's now + // available instead. + if (!TrySU->isAvailable) { + CurSU = AvailableQueue->pop(); + } + else { + CurSU = TrySU; + TrySU->isPending = false; + Interferences.erase(Interferences.begin()+i); + } + break; + } + } + + if (!CurSU) { + // Can't backtrack. If it's too expensive to copy the value, then try + // duplicate the nodes that produces these "too expensive to copy" + // values to break the dependency. In case even that doesn't work, + // insert cross class copies. + // If it's not too expensive, i.e. cost != -1, issue copies. + SUnit *TrySU = Interferences[0]; + SmallVector &LRegs = LRegsMap[TrySU]; + assert(LRegs.size() == 1 && "Can't handle this yet!"); + unsigned Reg = LRegs[0]; + SUnit *LRDef = LiveRegDefs[Reg]; + EVT VT = getPhysicalRegisterVT(LRDef->getNode(), Reg, TII); + const TargetRegisterClass *RC = + TRI->getMinimalPhysRegClass(Reg, VT); + const TargetRegisterClass *DestRC = TRI->getCrossCopyRegClass(RC); + + // If cross copy register class is null, then it must be possible copy + // the value directly. Do not try duplicate the def. + SUnit *NewDef = 0; + if (DestRC) + NewDef = CopyAndMoveSuccessors(LRDef); + else + DestRC = RC; + if (!NewDef) { + // Issue copies, these can be expensive cross register class copies. + SmallVector Copies; + InsertCopiesAndMoveSuccs(LRDef, Reg, DestRC, RC, Copies); + DEBUG(dbgs() << " Adding an edge from SU #" << TrySU->NodeNum + << " to SU #" << Copies.front()->NodeNum << "\n"); + AddPred(TrySU, SDep(Copies.front(), SDep::Order, /*Latency=*/1, + /*Reg=*/0, /*isNormalMemory=*/false, + /*isMustAlias=*/false, + /*isArtificial=*/true)); + NewDef = Copies.back(); + } + + DEBUG(dbgs() << " Adding an edge from SU #" << NewDef->NodeNum + << " to SU #" << TrySU->NodeNum << "\n"); + LiveRegDefs[Reg] = NewDef; + AddPred(NewDef, SDep(TrySU, SDep::Order, /*Latency=*/1, + /*Reg=*/0, /*isNormalMemory=*/false, + /*isMustAlias=*/false, + /*isArtificial=*/true)); + TrySU->isAvailable = false; + CurSU = NewDef; + } + + assert(CurSU && "Unable to resolve live physical register dependencies!"); + + // Add the nodes that aren't ready back onto the available list. + for (unsigned i = 0, e = Interferences.size(); i != e; ++i) { + Interferences[i]->isPending = false; + // May no longer be available due to backtracking. + if (Interferences[i]->isAvailable) { + AvailableQueue->push(Interferences[i]); + } + } + return CurSU; +} /// ListScheduleBottomUp - The main loop of list scheduling for bottom-up /// schedulers. void ScheduleDAGRRList::ListScheduleBottomUp() { - unsigned CurCycle = 0; - // Release any predecessors of the special Exit node. - ReleasePredecessors(&ExitSU, CurCycle); + ReleasePredecessors(&ExitSU); // Add root to Available queue. if (!SUnits.empty()) { @@ -730,135 +1137,29 @@ void ScheduleDAGRRList::ListScheduleBottomUp() { // While Available queue is not empty, grab the node with the highest // priority. If it is not ready put it back. Schedule the node. - SmallVector NotReady; - DenseMap > LRegsMap; Sequence.reserve(SUnits.size()); while (!AvailableQueue->empty()) { - bool Delayed = false; - LRegsMap.clear(); - SUnit *CurSU = AvailableQueue->pop(); - while (CurSU) { - SmallVector LRegs; - if (!DelayForLiveRegsBottomUp(CurSU, LRegs)) - break; - Delayed = true; - LRegsMap.insert(std::make_pair(CurSU, LRegs)); + DEBUG(dbgs() << "\n*** Examining Available\n"; + AvailableQueue->dump(this)); - CurSU->isPending = true; // This SU is not in AvailableQueue right now. - NotReady.push_back(CurSU); - CurSU = AvailableQueue->pop(); - } + // Pick the best node to schedule taking all constraints into + // consideration. + SUnit *SU = PickNodeToScheduleBottomUp(); - // All candidates are delayed due to live physical reg dependencies. - // Try backtracking, code duplication, or inserting cross class copies - // to resolve it. - if (Delayed && !CurSU) { - for (unsigned i = 0, e = NotReady.size(); i != e; ++i) { - SUnit *TrySU = NotReady[i]; - SmallVector &LRegs = LRegsMap[TrySU]; - - // Try unscheduling up to the point where it's safe to schedule - // this node. - unsigned LiveCycle = CurCycle; - for (unsigned j = 0, ee = LRegs.size(); j != ee; ++j) { - unsigned Reg = LRegs[j]; - unsigned LCycle = LiveRegCycles[Reg]; - LiveCycle = std::min(LiveCycle, LCycle); - } - SUnit *OldSU = Sequence[LiveCycle]; - if (!WillCreateCycle(TrySU, OldSU)) { - BacktrackBottomUp(TrySU, LiveCycle, CurCycle); - // Force the current node to be scheduled before the node that - // requires the physical reg dep. - if (OldSU->isAvailable) { - OldSU->isAvailable = false; - AvailableQueue->remove(OldSU); - } - AddPred(TrySU, SDep(OldSU, SDep::Order, /*Latency=*/1, - /*Reg=*/0, /*isNormalMemory=*/false, - /*isMustAlias=*/false, /*isArtificial=*/true)); - // If one or more successors has been unscheduled, then the current - // node is no longer avaialable. Schedule a successor that's now - // available instead. - if (!TrySU->isAvailable) - CurSU = AvailableQueue->pop(); - else { - CurSU = TrySU; - TrySU->isPending = false; - NotReady.erase(NotReady.begin()+i); - } - break; - } - } + AdvancePastStalls(SU); - if (!CurSU) { - // Can't backtrack. If it's too expensive to copy the value, then try - // duplicate the nodes that produces these "too expensive to copy" - // values to break the dependency. In case even that doesn't work, - // insert cross class copies. - // If it's not too expensive, i.e. cost != -1, issue copies. - SUnit *TrySU = NotReady[0]; - SmallVector &LRegs = LRegsMap[TrySU]; - assert(LRegs.size() == 1 && "Can't handle this yet!"); - unsigned Reg = LRegs[0]; - SUnit *LRDef = LiveRegDefs[Reg]; - EVT VT = getPhysicalRegisterVT(LRDef->getNode(), Reg, TII); - const TargetRegisterClass *RC = - TRI->getMinimalPhysRegClass(Reg, VT); - const TargetRegisterClass *DestRC = TRI->getCrossCopyRegClass(RC); - - // If cross copy register class is null, then it must be possible copy - // the value directly. Do not try duplicate the def. - SUnit *NewDef = 0; - if (DestRC) - NewDef = CopyAndMoveSuccessors(LRDef); - else - DestRC = RC; - if (!NewDef) { - // Issue copies, these can be expensive cross register class copies. - SmallVector Copies; - InsertCopiesAndMoveSuccs(LRDef, Reg, DestRC, RC, Copies); - DEBUG(dbgs() << " Adding an edge from SU #" << TrySU->NodeNum - << " to SU #" << Copies.front()->NodeNum << "\n"); - AddPred(TrySU, SDep(Copies.front(), SDep::Order, /*Latency=*/1, - /*Reg=*/0, /*isNormalMemory=*/false, - /*isMustAlias=*/false, - /*isArtificial=*/true)); - NewDef = Copies.back(); - } + ScheduleNodeBottomUp(SU); - DEBUG(dbgs() << " Adding an edge from SU #" << NewDef->NodeNum - << " to SU #" << TrySU->NodeNum << "\n"); - LiveRegDefs[Reg] = NewDef; - AddPred(NewDef, SDep(TrySU, SDep::Order, /*Latency=*/1, - /*Reg=*/0, /*isNormalMemory=*/false, - /*isMustAlias=*/false, - /*isArtificial=*/true)); - TrySU->isAvailable = false; - CurSU = NewDef; - } - - assert(CurSU && "Unable to resolve live physical register dependencies!"); - } - - // Add the nodes that aren't ready back onto the available list. - for (unsigned i = 0, e = NotReady.size(); i != e; ++i) { - NotReady[i]->isPending = false; - // May no longer be available due to backtracking. - if (NotReady[i]->isAvailable) - AvailableQueue->push(NotReady[i]); + while (AvailableQueue->empty() && !PendingQueue.empty()) { + // Advance the cycle to free resources. Skip ahead to the next ready SU. + assert(MinAvailableCycle < UINT_MAX && "MinAvailableCycle uninitialized"); + AdvanceToCycle(std::max(CurCycle + 1, MinAvailableCycle)); } - NotReady.clear(); - - if (CurSU) - ScheduleNodeBottomUp(CurSU, CurCycle); - ++CurCycle; - AvailableQueue->setCurCycle(CurCycle); } // Reverse the order if it is bottom up. std::reverse(Sequence.begin(), Sequence.end()); - + #ifndef NDEBUG VerifySchedule(isBottomUp); #endif @@ -905,7 +1206,7 @@ void ScheduleDAGRRList::ReleaseSuccessors(SUnit *SU) { /// ScheduleNodeTopDown - Add the node to the schedule. Decrement the pending /// count of its successors. If a successor pending count is zero, add it to /// the Available queue. -void ScheduleDAGRRList::ScheduleNodeTopDown(SUnit *SU, unsigned CurCycle) { +void ScheduleDAGRRList::ScheduleNodeTopDown(SUnit *SU) { DEBUG(dbgs() << "*** Scheduling [" << CurCycle << "]: "); DEBUG(SU->dump(this)); @@ -921,7 +1222,6 @@ void ScheduleDAGRRList::ScheduleNodeTopDown(SUnit *SU, unsigned CurCycle) { /// ListScheduleTopDown - The main loop of list scheduling for top-down /// schedulers. void ScheduleDAGRRList::ListScheduleTopDown() { - unsigned CurCycle = 0; AvailableQueue->setCurCycle(CurCycle); // Release any successors of the special Entry node. @@ -935,19 +1235,19 @@ void ScheduleDAGRRList::ListScheduleTopDown() { SUnits[i].isAvailable = true; } } - + // While Available queue is not empty, grab the node with the highest // priority. If it is not ready put it back. Schedule the node. Sequence.reserve(SUnits.size()); while (!AvailableQueue->empty()) { SUnit *CurSU = AvailableQueue->pop(); - + if (CurSU) - ScheduleNodeTopDown(CurSU, CurCycle); + ScheduleNodeTopDown(CurSU); ++CurCycle; AvailableQueue->setCurCycle(CurCycle); } - + #ifndef NDEBUG VerifySchedule(isBottomUp); #endif @@ -955,70 +1255,288 @@ void ScheduleDAGRRList::ListScheduleTopDown() { //===----------------------------------------------------------------------===// -// RegReductionPriorityQueue Implementation +// RegReductionPriorityQueue Definition //===----------------------------------------------------------------------===// // // This is a SchedulingPriorityQueue that schedules using Sethi Ullman numbers // to reduce register pressure. -// +// namespace { - template - class RegReductionPriorityQueue; - - /// bu_ls_rr_sort - Priority function for bottom up register pressure - // reduction scheduler. - struct bu_ls_rr_sort : public std::binary_function { - RegReductionPriorityQueue *SPQ; - bu_ls_rr_sort(RegReductionPriorityQueue *spq) : SPQ(spq) {} - bu_ls_rr_sort(const bu_ls_rr_sort &RHS) : SPQ(RHS.SPQ) {} - - bool operator()(const SUnit* left, const SUnit* right) const; +class RegReductionPQBase; + +struct queue_sort : public std::binary_function { + bool isReady(SUnit* SU, unsigned CurCycle) const { return true; } +}; + +/// bu_ls_rr_sort - Priority function for bottom up register pressure +// reduction scheduler. +struct bu_ls_rr_sort : public queue_sort { + enum { + IsBottomUp = true, + HasReadyFilter = false }; - // td_ls_rr_sort - Priority function for top down register pressure reduction - // scheduler. - struct td_ls_rr_sort : public std::binary_function { - RegReductionPriorityQueue *SPQ; - td_ls_rr_sort(RegReductionPriorityQueue *spq) : SPQ(spq) {} - td_ls_rr_sort(const td_ls_rr_sort &RHS) : SPQ(RHS.SPQ) {} - - bool operator()(const SUnit* left, const SUnit* right) const; + RegReductionPQBase *SPQ; + bu_ls_rr_sort(RegReductionPQBase *spq) : SPQ(spq) {} + bu_ls_rr_sort(const bu_ls_rr_sort &RHS) : SPQ(RHS.SPQ) {} + + bool operator()(SUnit* left, SUnit* right) const; +}; + +// td_ls_rr_sort - Priority function for top down register pressure reduction +// scheduler. +struct td_ls_rr_sort : public queue_sort { + enum { + IsBottomUp = false, + HasReadyFilter = false }; - // src_ls_rr_sort - Priority function for source order scheduler. - struct src_ls_rr_sort : public std::binary_function { - RegReductionPriorityQueue *SPQ; - src_ls_rr_sort(RegReductionPriorityQueue *spq) - : SPQ(spq) {} - src_ls_rr_sort(const src_ls_rr_sort &RHS) - : SPQ(RHS.SPQ) {} - - bool operator()(const SUnit* left, const SUnit* right) const; + RegReductionPQBase *SPQ; + td_ls_rr_sort(RegReductionPQBase *spq) : SPQ(spq) {} + td_ls_rr_sort(const td_ls_rr_sort &RHS) : SPQ(RHS.SPQ) {} + + bool operator()(const SUnit* left, const SUnit* right) const; +}; + +// src_ls_rr_sort - Priority function for source order scheduler. +struct src_ls_rr_sort : public queue_sort { + enum { + IsBottomUp = true, + HasReadyFilter = false }; - // hybrid_ls_rr_sort - Priority function for hybrid scheduler. - struct hybrid_ls_rr_sort : public std::binary_function { - RegReductionPriorityQueue *SPQ; - hybrid_ls_rr_sort(RegReductionPriorityQueue *spq) - : SPQ(spq) {} - hybrid_ls_rr_sort(const hybrid_ls_rr_sort &RHS) - : SPQ(RHS.SPQ) {} + RegReductionPQBase *SPQ; + src_ls_rr_sort(RegReductionPQBase *spq) + : SPQ(spq) {} + src_ls_rr_sort(const src_ls_rr_sort &RHS) + : SPQ(RHS.SPQ) {} + + bool operator()(SUnit* left, SUnit* right) const; +}; - bool operator()(const SUnit* left, const SUnit* right) const; +// hybrid_ls_rr_sort - Priority function for hybrid scheduler. +struct hybrid_ls_rr_sort : public queue_sort { + enum { + IsBottomUp = true, + HasReadyFilter = true }; - // ilp_ls_rr_sort - Priority function for ILP (instruction level parallelism) - // scheduler. - struct ilp_ls_rr_sort : public std::binary_function { - RegReductionPriorityQueue *SPQ; - ilp_ls_rr_sort(RegReductionPriorityQueue *spq) - : SPQ(spq) {} - ilp_ls_rr_sort(const ilp_ls_rr_sort &RHS) - : SPQ(RHS.SPQ) {} + RegReductionPQBase *SPQ; + hybrid_ls_rr_sort(RegReductionPQBase *spq) + : SPQ(spq) {} + hybrid_ls_rr_sort(const hybrid_ls_rr_sort &RHS) + : SPQ(RHS.SPQ) {} + + bool isReady(SUnit *SU, unsigned CurCycle) const; - bool operator()(const SUnit* left, const SUnit* right) const; + bool operator()(SUnit* left, SUnit* right) const; +}; + +// ilp_ls_rr_sort - Priority function for ILP (instruction level parallelism) +// scheduler. +struct ilp_ls_rr_sort : public queue_sort { + enum { + IsBottomUp = true, + HasReadyFilter = true }; -} // end anonymous namespace + + RegReductionPQBase *SPQ; + ilp_ls_rr_sort(RegReductionPQBase *spq) + : SPQ(spq) {} + ilp_ls_rr_sort(const ilp_ls_rr_sort &RHS) + : SPQ(RHS.SPQ) {} + + bool isReady(SUnit *SU, unsigned CurCycle) const; + + bool operator()(SUnit* left, SUnit* right) const; +}; + +class RegReductionPQBase : public SchedulingPriorityQueue { +protected: + std::vector Queue; + unsigned CurQueueId; + bool TracksRegPressure; + + // SUnits - The SUnits for the current graph. + std::vector *SUnits; + + MachineFunction &MF; + const TargetInstrInfo *TII; + const TargetRegisterInfo *TRI; + const TargetLowering *TLI; + ScheduleDAGRRList *scheduleDAG; + + // SethiUllmanNumbers - The SethiUllman number for each node. + std::vector SethiUllmanNumbers; + + /// RegPressure - Tracking current reg pressure per register class. + /// + std::vector RegPressure; + + /// RegLimit - Tracking the number of allocatable registers per register + /// class. + std::vector RegLimit; + +public: + RegReductionPQBase(MachineFunction &mf, + bool hasReadyFilter, + bool tracksrp, + const TargetInstrInfo *tii, + const TargetRegisterInfo *tri, + const TargetLowering *tli) + : SchedulingPriorityQueue(hasReadyFilter), + CurQueueId(0), TracksRegPressure(tracksrp), + MF(mf), TII(tii), TRI(tri), TLI(tli), scheduleDAG(NULL) { + if (TracksRegPressure) { + unsigned NumRC = TRI->getNumRegClasses(); + RegLimit.resize(NumRC); + RegPressure.resize(NumRC); + std::fill(RegLimit.begin(), RegLimit.end(), 0); + std::fill(RegPressure.begin(), RegPressure.end(), 0); + for (TargetRegisterInfo::regclass_iterator I = TRI->regclass_begin(), + E = TRI->regclass_end(); I != E; ++I) + RegLimit[(*I)->getID()] = tli->getRegPressureLimit(*I, MF); + } + } + + void setScheduleDAG(ScheduleDAGRRList *scheduleDag) { + scheduleDAG = scheduleDag; + } + + ScheduleHazardRecognizer* getHazardRec() { + return scheduleDAG->getHazardRec(); + } + + void initNodes(std::vector &sunits); + + void addNode(const SUnit *SU); + + void updateNode(const SUnit *SU); + + void releaseState() { + SUnits = 0; + SethiUllmanNumbers.clear(); + std::fill(RegPressure.begin(), RegPressure.end(), 0); + } + + unsigned getNodePriority(const SUnit *SU) const; + + unsigned getNodeOrdering(const SUnit *SU) const { + return scheduleDAG->DAG->GetOrdering(SU->getNode()); + } + + bool empty() const { return Queue.empty(); } + + void push(SUnit *U) { + assert(!U->NodeQueueId && "Node in the queue already"); + U->NodeQueueId = ++CurQueueId; + Queue.push_back(U); + } + + void remove(SUnit *SU) { + assert(!Queue.empty() && "Queue is empty!"); + assert(SU->NodeQueueId != 0 && "Not in queue!"); + std::vector::iterator I = std::find(Queue.begin(), Queue.end(), + SU); + if (I != prior(Queue.end())) + std::swap(*I, Queue.back()); + Queue.pop_back(); + SU->NodeQueueId = 0; + } + + bool tracksRegPressure() const { return TracksRegPressure; } + + void dumpRegPressure() const; + + bool HighRegPressure(const SUnit *SU) const; + + bool MayReduceRegPressure(SUnit *SU); + + void ScheduledNode(SUnit *SU); + + void UnscheduledNode(SUnit *SU); + +protected: + bool canClobber(const SUnit *SU, const SUnit *Op); + void AddPseudoTwoAddrDeps(); + void PrescheduleNodesWithMultipleUses(); + void CalculateSethiUllmanNumbers(); +}; + +template +class RegReductionPriorityQueue : public RegReductionPQBase { + static SUnit *popFromQueue(std::vector &Q, SF &Picker) { + std::vector::iterator Best = Q.begin(); + for (std::vector::iterator I = llvm::next(Q.begin()), + E = Q.end(); I != E; ++I) + if (Picker(*Best, *I)) + Best = I; + SUnit *V = *Best; + if (Best != prior(Q.end())) + std::swap(*Best, Q.back()); + Q.pop_back(); + return V; + } + + SF Picker; + +public: + RegReductionPriorityQueue(MachineFunction &mf, + bool tracksrp, + const TargetInstrInfo *tii, + const TargetRegisterInfo *tri, + const TargetLowering *tli) + : RegReductionPQBase(mf, SF::HasReadyFilter, tracksrp, tii, tri, tli), + Picker(this) {} + + bool isBottomUp() const { return SF::IsBottomUp; } + + bool isReady(SUnit *U) const { + return Picker.HasReadyFilter && Picker.isReady(U, getCurCycle()); + } + + SUnit *pop() { + if (Queue.empty()) return NULL; + + SUnit *V = popFromQueue(Queue, Picker); + V->NodeQueueId = 0; + return V; + } + + void dump(ScheduleDAG *DAG) const { + // Emulate pop() without clobbering NodeQueueIds. + std::vector DumpQueue = Queue; + SF DumpPicker = Picker; + while (!DumpQueue.empty()) { + SUnit *SU = popFromQueue(DumpQueue, DumpPicker); + if (isBottomUp()) + dbgs() << "Height " << SU->getHeight() << ": "; + else + dbgs() << "Depth " << SU->getDepth() << ": "; + SU->dump(DAG); + } + } +}; + +typedef RegReductionPriorityQueue +BURegReductionPriorityQueue; + +typedef RegReductionPriorityQueue +TDRegReductionPriorityQueue; + +typedef RegReductionPriorityQueue +SrcRegReductionPriorityQueue; + +typedef RegReductionPriorityQueue +HybridBURRPriorityQueue; + +typedef RegReductionPriorityQueue +ILPBURRPriorityQueue; +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// Static Node Priority for Register Pressure Reduction +//===----------------------------------------------------------------------===// /// CalcNodeSethiUllmanNumber - Compute Sethi Ullman number. /// Smaller number is the higher priority. @@ -1045,413 +1563,283 @@ CalcNodeSethiUllmanNumber(const SUnit *SU, std::vector &SUNumbers) { if (SethiUllmanNumber == 0) SethiUllmanNumber = 1; - + return SethiUllmanNumber; } -namespace { - template - class RegReductionPriorityQueue : public SchedulingPriorityQueue { - std::vector Queue; - SF Picker; - unsigned CurQueueId; - bool TracksRegPressure; - - protected: - // SUnits - The SUnits for the current graph. - std::vector *SUnits; - - MachineFunction &MF; - const TargetInstrInfo *TII; - const TargetRegisterInfo *TRI; - const TargetLowering *TLI; - ScheduleDAGRRList *scheduleDAG; - - // SethiUllmanNumbers - The SethiUllman number for each node. - std::vector SethiUllmanNumbers; - - /// RegPressure - Tracking current reg pressure per register class. - /// - std::vector RegPressure; - - /// RegLimit - Tracking the number of allocatable registers per register - /// class. - std::vector RegLimit; - - public: - RegReductionPriorityQueue(MachineFunction &mf, - bool tracksrp, - const TargetInstrInfo *tii, - const TargetRegisterInfo *tri, - const TargetLowering *tli) - : Picker(this), CurQueueId(0), TracksRegPressure(tracksrp), - MF(mf), TII(tii), TRI(tri), TLI(tli), scheduleDAG(NULL) { - if (TracksRegPressure) { - unsigned NumRC = TRI->getNumRegClasses(); - RegLimit.resize(NumRC); - RegPressure.resize(NumRC); - std::fill(RegLimit.begin(), RegLimit.end(), 0); - std::fill(RegPressure.begin(), RegPressure.end(), 0); - for (TargetRegisterInfo::regclass_iterator I = TRI->regclass_begin(), - E = TRI->regclass_end(); I != E; ++I) - RegLimit[(*I)->getID()] = tli->getRegPressureLimit(*I, MF); - } - } - - void initNodes(std::vector &sunits) { - SUnits = &sunits; - // Add pseudo dependency edges for two-address nodes. - AddPseudoTwoAddrDeps(); - // Reroute edges to nodes with multiple uses. - PrescheduleNodesWithMultipleUses(); - // Calculate node priorities. - CalculateSethiUllmanNumbers(); - } - - void addNode(const SUnit *SU) { - unsigned SUSize = SethiUllmanNumbers.size(); - if (SUnits->size() > SUSize) - SethiUllmanNumbers.resize(SUSize*2, 0); - CalcNodeSethiUllmanNumber(SU, SethiUllmanNumbers); - } - - void updateNode(const SUnit *SU) { - SethiUllmanNumbers[SU->NodeNum] = 0; - CalcNodeSethiUllmanNumber(SU, SethiUllmanNumbers); - } +/// CalculateSethiUllmanNumbers - Calculate Sethi-Ullman numbers of all +/// scheduling units. +void RegReductionPQBase::CalculateSethiUllmanNumbers() { + SethiUllmanNumbers.assign(SUnits->size(), 0); - void releaseState() { - SUnits = 0; - SethiUllmanNumbers.clear(); - std::fill(RegPressure.begin(), RegPressure.end(), 0); - } + for (unsigned i = 0, e = SUnits->size(); i != e; ++i) + CalcNodeSethiUllmanNumber(&(*SUnits)[i], SethiUllmanNumbers); +} - unsigned getNodePriority(const SUnit *SU) const { - assert(SU->NodeNum < SethiUllmanNumbers.size()); - unsigned Opc = SU->getNode() ? SU->getNode()->getOpcode() : 0; - if (Opc == ISD::TokenFactor || Opc == ISD::CopyToReg) - // CopyToReg should be close to its uses to facilitate coalescing and - // avoid spilling. - return 0; - if (Opc == TargetOpcode::EXTRACT_SUBREG || - Opc == TargetOpcode::SUBREG_TO_REG || - Opc == TargetOpcode::INSERT_SUBREG) - // EXTRACT_SUBREG, INSERT_SUBREG, and SUBREG_TO_REG nodes should be - // close to their uses to facilitate coalescing. - return 0; - if (SU->NumSuccs == 0 && SU->NumPreds != 0) - // If SU does not have a register use, i.e. it doesn't produce a value - // that would be consumed (e.g. store), then it terminates a chain of - // computation. Give it a large SethiUllman number so it will be - // scheduled right before its predecessors that it doesn't lengthen - // their live ranges. - return 0xffff; - if (SU->NumPreds == 0 && SU->NumSuccs != 0) - // If SU does not have a register def, schedule it close to its uses - // because it does not lengthen any live ranges. - return 0; - return SethiUllmanNumbers[SU->NodeNum]; - } +void RegReductionPQBase::initNodes(std::vector &sunits) { + SUnits = &sunits; + // Add pseudo dependency edges for two-address nodes. + AddPseudoTwoAddrDeps(); + // Reroute edges to nodes with multiple uses. + if (!TracksRegPressure) + PrescheduleNodesWithMultipleUses(); + // Calculate node priorities. + CalculateSethiUllmanNumbers(); +} - unsigned getNodeOrdering(const SUnit *SU) const { - return scheduleDAG->DAG->GetOrdering(SU->getNode()); - } +void RegReductionPQBase::addNode(const SUnit *SU) { + unsigned SUSize = SethiUllmanNumbers.size(); + if (SUnits->size() > SUSize) + SethiUllmanNumbers.resize(SUSize*2, 0); + CalcNodeSethiUllmanNumber(SU, SethiUllmanNumbers); +} - bool empty() const { return Queue.empty(); } - - void push(SUnit *U) { - assert(!U->NodeQueueId && "Node in the queue already"); - U->NodeQueueId = ++CurQueueId; - Queue.push_back(U); - } +void RegReductionPQBase::updateNode(const SUnit *SU) { + SethiUllmanNumbers[SU->NodeNum] = 0; + CalcNodeSethiUllmanNumber(SU, SethiUllmanNumbers); +} - SUnit *pop() { - if (empty()) return NULL; - std::vector::iterator Best = Queue.begin(); - for (std::vector::iterator I = llvm::next(Queue.begin()), - E = Queue.end(); I != E; ++I) - if (Picker(*Best, *I)) - Best = I; - SUnit *V = *Best; - if (Best != prior(Queue.end())) - std::swap(*Best, Queue.back()); - Queue.pop_back(); - V->NodeQueueId = 0; - return V; - } +// Lower priority means schedule further down. For bottom-up scheduling, lower +// priority SUs are scheduled before higher priority SUs. +unsigned RegReductionPQBase::getNodePriority(const SUnit *SU) const { + assert(SU->NodeNum < SethiUllmanNumbers.size()); + unsigned Opc = SU->getNode() ? SU->getNode()->getOpcode() : 0; + if (Opc == ISD::TokenFactor || Opc == ISD::CopyToReg) + // CopyToReg should be close to its uses to facilitate coalescing and + // avoid spilling. + return 0; + if (Opc == TargetOpcode::EXTRACT_SUBREG || + Opc == TargetOpcode::SUBREG_TO_REG || + Opc == TargetOpcode::INSERT_SUBREG) + // EXTRACT_SUBREG, INSERT_SUBREG, and SUBREG_TO_REG nodes should be + // close to their uses to facilitate coalescing. + return 0; + if (SU->NumSuccs == 0 && SU->NumPreds != 0) + // If SU does not have a register use, i.e. it doesn't produce a value + // that would be consumed (e.g. store), then it terminates a chain of + // computation. Give it a large SethiUllman number so it will be + // scheduled right before its predecessors that it doesn't lengthen + // their live ranges. + return 0xffff; + if (SU->NumPreds == 0 && SU->NumSuccs != 0) + // If SU does not have a register def, schedule it close to its uses + // because it does not lengthen any live ranges. + return 0; + return SethiUllmanNumbers[SU->NodeNum]; +} - void remove(SUnit *SU) { - assert(!Queue.empty() && "Queue is empty!"); - assert(SU->NodeQueueId != 0 && "Not in queue!"); - std::vector::iterator I = std::find(Queue.begin(), Queue.end(), - SU); - if (I != prior(Queue.end())) - std::swap(*I, Queue.back()); - Queue.pop_back(); - SU->NodeQueueId = 0; - } +//===----------------------------------------------------------------------===// +// Register Pressure Tracking +//===----------------------------------------------------------------------===// - bool HighRegPressure(const SUnit *SU) const { - if (!TLI) - return false; +void RegReductionPQBase::dumpRegPressure() const { + for (TargetRegisterInfo::regclass_iterator I = TRI->regclass_begin(), + E = TRI->regclass_end(); I != E; ++I) { + const TargetRegisterClass *RC = *I; + unsigned Id = RC->getID(); + unsigned RP = RegPressure[Id]; + if (!RP) continue; + DEBUG(dbgs() << RC->getName() << ": " << RP << " / " << RegLimit[Id] + << '\n'); + } +} - for (SUnit::const_pred_iterator I = SU->Preds.begin(),E = SU->Preds.end(); - I != E; ++I) { - if (I->isCtrl()) - continue; - SUnit *PredSU = I->getSUnit(); - const SDNode *PN = PredSU->getNode(); - if (!PN->isMachineOpcode()) { - if (PN->getOpcode() == ISD::CopyFromReg) { - EVT VT = PN->getValueType(0); - unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); - unsigned Cost = TLI->getRepRegClassCostFor(VT); - if ((RegPressure[RCId] + Cost) >= RegLimit[RCId]) - return true; - } - continue; - } - unsigned POpc = PN->getMachineOpcode(); - if (POpc == TargetOpcode::IMPLICIT_DEF) - continue; - if (POpc == TargetOpcode::EXTRACT_SUBREG) { - EVT VT = PN->getOperand(0).getValueType(); - unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); - unsigned Cost = TLI->getRepRegClassCostFor(VT); - // Check if this increases register pressure of the specific register - // class to the point where it would cause spills. - if ((RegPressure[RCId] + Cost) >= RegLimit[RCId]) - return true; - continue; - } else if (POpc == TargetOpcode::INSERT_SUBREG || - POpc == TargetOpcode::SUBREG_TO_REG) { - EVT VT = PN->getValueType(0); - unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); - unsigned Cost = TLI->getRepRegClassCostFor(VT); - // Check if this increases register pressure of the specific register - // class to the point where it would cause spills. - if ((RegPressure[RCId] + Cost) >= RegLimit[RCId]) - return true; - continue; - } - unsigned NumDefs = TII->get(PN->getMachineOpcode()).getNumDefs(); - for (unsigned i = 0; i != NumDefs; ++i) { - EVT VT = PN->getValueType(i); - unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); - if (RegPressure[RCId] >= RegLimit[RCId]) - return true; // Reg pressure already high. - unsigned Cost = TLI->getRepRegClassCostFor(VT); - if (!PN->hasAnyUseOfValue(i)) - continue; - // Check if this increases register pressure of the specific register - // class to the point where it would cause spills. - if ((RegPressure[RCId] + Cost) >= RegLimit[RCId]) - return true; - } - } +bool RegReductionPQBase::HighRegPressure(const SUnit *SU) const { + if (!TLI) + return false; - return false; + for (SUnit::const_pred_iterator I = SU->Preds.begin(),E = SU->Preds.end(); + I != E; ++I) { + if (I->isCtrl()) + continue; + SUnit *PredSU = I->getSUnit(); + // NumRegDefsLeft is zero when enough uses of this node have been scheduled + // to cover the number of registers defined (they are all live). + if (PredSU->NumRegDefsLeft == 0) { + continue; + } + for (ScheduleDAGSDNodes::RegDefIter RegDefPos(PredSU, scheduleDAG); + RegDefPos.IsValid(); RegDefPos.Advance()) { + EVT VT = RegDefPos.GetValue(); + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + unsigned Cost = TLI->getRepRegClassCostFor(VT); + if ((RegPressure[RCId] + Cost) >= RegLimit[RCId]) + return true; } + } + return false; +} - void ScheduledNode(SUnit *SU) { - if (!TracksRegPressure) - return; - - const SDNode *N = SU->getNode(); - if (!N->isMachineOpcode()) { - if (N->getOpcode() != ISD::CopyToReg) - return; - } else { - unsigned Opc = N->getMachineOpcode(); - if (Opc == TargetOpcode::EXTRACT_SUBREG || - Opc == TargetOpcode::INSERT_SUBREG || - Opc == TargetOpcode::SUBREG_TO_REG || - Opc == TargetOpcode::REG_SEQUENCE || - Opc == TargetOpcode::IMPLICIT_DEF) - return; - } +bool RegReductionPQBase::MayReduceRegPressure(SUnit *SU) { + const SDNode *N = SU->getNode(); - for (SUnit::pred_iterator I = SU->Preds.begin(), E = SU->Preds.end(); - I != E; ++I) { - if (I->isCtrl()) - continue; - SUnit *PredSU = I->getSUnit(); - if (PredSU->NumSuccsLeft != PredSU->NumSuccs) - continue; - const SDNode *PN = PredSU->getNode(); - if (!PN->isMachineOpcode()) { - if (PN->getOpcode() == ISD::CopyFromReg) { - EVT VT = PN->getValueType(0); - unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); - RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); - } - continue; - } - unsigned POpc = PN->getMachineOpcode(); - if (POpc == TargetOpcode::IMPLICIT_DEF) - continue; - if (POpc == TargetOpcode::EXTRACT_SUBREG) { - EVT VT = PN->getOperand(0).getValueType(); - unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); - RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); - continue; - } else if (POpc == TargetOpcode::INSERT_SUBREG || - POpc == TargetOpcode::SUBREG_TO_REG) { - EVT VT = PN->getValueType(0); - unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); - RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); - continue; - } - unsigned NumDefs = TII->get(PN->getMachineOpcode()).getNumDefs(); - for (unsigned i = 0; i != NumDefs; ++i) { - EVT VT = PN->getValueType(i); - if (!PN->hasAnyUseOfValue(i)) - continue; - unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); - RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); - } - } + if (!N->isMachineOpcode() || !SU->NumSuccs) + return false; - // Check for isMachineOpcode() as PrescheduleNodesWithMultipleUses() - // may transfer data dependencies to CopyToReg. - if (SU->NumSuccs && N->isMachineOpcode()) { - unsigned NumDefs = TII->get(N->getMachineOpcode()).getNumDefs(); - for (unsigned i = 0; i != NumDefs; ++i) { - EVT VT = N->getValueType(i); - if (!N->hasAnyUseOfValue(i)) - continue; - unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); - if (RegPressure[RCId] < TLI->getRepRegClassCostFor(VT)) - // Register pressure tracking is imprecise. This can happen. - RegPressure[RCId] = 0; - else - RegPressure[RCId] -= TLI->getRepRegClassCostFor(VT); - } - } + unsigned NumDefs = TII->get(N->getMachineOpcode()).getNumDefs(); + for (unsigned i = 0; i != NumDefs; ++i) { + EVT VT = N->getValueType(i); + if (!N->hasAnyUseOfValue(i)) + continue; + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + if (RegPressure[RCId] >= RegLimit[RCId]) + return true; + } + return false; +} + +void RegReductionPQBase::ScheduledNode(SUnit *SU) { + if (!TracksRegPressure) + return; - dumpRegPressure(); + for (SUnit::pred_iterator I = SU->Preds.begin(), E = SU->Preds.end(); + I != E; ++I) { + if (I->isCtrl()) + continue; + SUnit *PredSU = I->getSUnit(); + // NumRegDefsLeft is zero when enough uses of this node have been scheduled + // to cover the number of registers defined (they are all live). + if (PredSU->NumRegDefsLeft == 0) { + continue; + } + // FIXME: The ScheduleDAG currently loses information about which of a + // node's values is consumed by each dependence. Consequently, if the node + // defines multiple register classes, we don't know which to pressurize + // here. Instead the following loop consumes the register defs in an + // arbitrary order. At least it handles the common case of clustered loads + // to the same class. For precise liveness, each SDep needs to indicate the + // result number. But that tightly couples the ScheduleDAG with the + // SelectionDAG making updates tricky. A simpler hack would be to attach a + // value type or register class to SDep. + // + // The most important aspect of register tracking is balancing the increase + // here with the reduction further below. Note that this SU may use multiple + // defs in PredSU. The can't be determined here, but we've already + // compensated by reducing NumRegDefsLeft in PredSU during + // ScheduleDAGSDNodes::AddSchedEdges. + --PredSU->NumRegDefsLeft; + unsigned SkipRegDefs = PredSU->NumRegDefsLeft; + for (ScheduleDAGSDNodes::RegDefIter RegDefPos(PredSU, scheduleDAG); + RegDefPos.IsValid(); RegDefPos.Advance(), --SkipRegDefs) { + if (SkipRegDefs) + continue; + EVT VT = RegDefPos.GetValue(); + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); + break; } + } - void UnscheduledNode(SUnit *SU) { - if (!TracksRegPressure) - return; - - const SDNode *N = SU->getNode(); - if (!N->isMachineOpcode()) { - if (N->getOpcode() != ISD::CopyToReg) - return; - } else { - unsigned Opc = N->getMachineOpcode(); - if (Opc == TargetOpcode::EXTRACT_SUBREG || - Opc == TargetOpcode::INSERT_SUBREG || - Opc == TargetOpcode::SUBREG_TO_REG || - Opc == TargetOpcode::REG_SEQUENCE || - Opc == TargetOpcode::IMPLICIT_DEF) - return; - } + // We should have this assert, but there may be dead SDNodes that never + // materialize as SUnits, so they don't appear to generate liveness. + //assert(SU->NumRegDefsLeft == 0 && "not all regdefs have scheduled uses"); + int SkipRegDefs = (int)SU->NumRegDefsLeft; + for (ScheduleDAGSDNodes::RegDefIter RegDefPos(SU, scheduleDAG); + RegDefPos.IsValid(); RegDefPos.Advance(), --SkipRegDefs) { + if (SkipRegDefs > 0) + continue; + EVT VT = RegDefPos.GetValue(); + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + if (RegPressure[RCId] < TLI->getRepRegClassCostFor(VT)) { + // Register pressure tracking is imprecise. This can happen. But we try + // hard not to let it happen because it likely results in poor scheduling. + DEBUG(dbgs() << " SU(" << SU->NodeNum << ") has too many regdefs\n"); + RegPressure[RCId] = 0; + } + else { + RegPressure[RCId] -= TLI->getRepRegClassCostFor(VT); + } + } + dumpRegPressure(); +} - for (SUnit::pred_iterator I = SU->Preds.begin(), E = SU->Preds.end(); - I != E; ++I) { - if (I->isCtrl()) - continue; - SUnit *PredSU = I->getSUnit(); - if (PredSU->NumSuccsLeft != PredSU->NumSuccs) - continue; - const SDNode *PN = PredSU->getNode(); - if (!PN->isMachineOpcode()) { - if (PN->getOpcode() == ISD::CopyFromReg) { - EVT VT = PN->getValueType(0); - unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); - RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); - } - continue; - } - unsigned POpc = PN->getMachineOpcode(); - if (POpc == TargetOpcode::IMPLICIT_DEF) - continue; - if (POpc == TargetOpcode::EXTRACT_SUBREG) { - EVT VT = PN->getOperand(0).getValueType(); - unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); - RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); - continue; - } else if (POpc == TargetOpcode::INSERT_SUBREG || - POpc == TargetOpcode::SUBREG_TO_REG) { - EVT VT = PN->getValueType(0); - unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); - RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); - continue; - } - unsigned NumDefs = TII->get(PN->getMachineOpcode()).getNumDefs(); - for (unsigned i = 0; i != NumDefs; ++i) { - EVT VT = PN->getValueType(i); - if (!PN->hasAnyUseOfValue(i)) - continue; - unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); - if (RegPressure[RCId] < TLI->getRepRegClassCostFor(VT)) - // Register pressure tracking is imprecise. This can happen. - RegPressure[RCId] = 0; - else - RegPressure[RCId] -= TLI->getRepRegClassCostFor(VT); - } - } +void RegReductionPQBase::UnscheduledNode(SUnit *SU) { + if (!TracksRegPressure) + return; + + const SDNode *N = SU->getNode(); + if (!N->isMachineOpcode()) { + if (N->getOpcode() != ISD::CopyToReg) + return; + } else { + unsigned Opc = N->getMachineOpcode(); + if (Opc == TargetOpcode::EXTRACT_SUBREG || + Opc == TargetOpcode::INSERT_SUBREG || + Opc == TargetOpcode::SUBREG_TO_REG || + Opc == TargetOpcode::REG_SEQUENCE || + Opc == TargetOpcode::IMPLICIT_DEF) + return; + } - // Check for isMachineOpcode() as PrescheduleNodesWithMultipleUses() - // may transfer data dependencies to CopyToReg. - if (SU->NumSuccs && N->isMachineOpcode()) { - unsigned NumDefs = TII->get(N->getMachineOpcode()).getNumDefs(); - for (unsigned i = NumDefs, e = N->getNumValues(); i != e; ++i) { - EVT VT = N->getValueType(i); - if (VT == MVT::Flag || VT == MVT::Other) - continue; - if (!N->hasAnyUseOfValue(i)) - continue; - unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); - RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); - } + for (SUnit::pred_iterator I = SU->Preds.begin(), E = SU->Preds.end(); + I != E; ++I) { + if (I->isCtrl()) + continue; + SUnit *PredSU = I->getSUnit(); + // NumSuccsLeft counts all deps. Don't compare it with NumSuccs which only + // counts data deps. + if (PredSU->NumSuccsLeft != PredSU->Succs.size()) + continue; + const SDNode *PN = PredSU->getNode(); + if (!PN->isMachineOpcode()) { + if (PN->getOpcode() == ISD::CopyFromReg) { + EVT VT = PN->getValueType(0); + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); } - - dumpRegPressure(); + continue; } - - void setScheduleDAG(ScheduleDAGRRList *scheduleDag) { - scheduleDAG = scheduleDag; + unsigned POpc = PN->getMachineOpcode(); + if (POpc == TargetOpcode::IMPLICIT_DEF) + continue; + if (POpc == TargetOpcode::EXTRACT_SUBREG) { + EVT VT = PN->getOperand(0).getValueType(); + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); + continue; + } else if (POpc == TargetOpcode::INSERT_SUBREG || + POpc == TargetOpcode::SUBREG_TO_REG) { + EVT VT = PN->getValueType(0); + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); + continue; } - - void dumpRegPressure() const { - for (TargetRegisterInfo::regclass_iterator I = TRI->regclass_begin(), - E = TRI->regclass_end(); I != E; ++I) { - const TargetRegisterClass *RC = *I; - unsigned Id = RC->getID(); - unsigned RP = RegPressure[Id]; - if (!RP) continue; - DEBUG(dbgs() << RC->getName() << ": " << RP << " / " << RegLimit[Id] - << '\n'); - } + unsigned NumDefs = TII->get(PN->getMachineOpcode()).getNumDefs(); + for (unsigned i = 0; i != NumDefs; ++i) { + EVT VT = PN->getValueType(i); + if (!PN->hasAnyUseOfValue(i)) + continue; + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + if (RegPressure[RCId] < TLI->getRepRegClassCostFor(VT)) + // Register pressure tracking is imprecise. This can happen. + RegPressure[RCId] = 0; + else + RegPressure[RCId] -= TLI->getRepRegClassCostFor(VT); } + } - protected: - bool canClobber(const SUnit *SU, const SUnit *Op); - void AddPseudoTwoAddrDeps(); - void PrescheduleNodesWithMultipleUses(); - void CalculateSethiUllmanNumbers(); - }; - - typedef RegReductionPriorityQueue - BURegReductionPriorityQueue; - - typedef RegReductionPriorityQueue - TDRegReductionPriorityQueue; - - typedef RegReductionPriorityQueue - SrcRegReductionPriorityQueue; - - typedef RegReductionPriorityQueue - HybridBURRPriorityQueue; + // Check for isMachineOpcode() as PrescheduleNodesWithMultipleUses() + // may transfer data dependencies to CopyToReg. + if (SU->NumSuccs && N->isMachineOpcode()) { + unsigned NumDefs = TII->get(N->getMachineOpcode()).getNumDefs(); + for (unsigned i = NumDefs, e = N->getNumValues(); i != e; ++i) { + EVT VT = N->getValueType(i); + if (VT == MVT::Glue || VT == MVT::Other) + continue; + if (!N->hasAnyUseOfValue(i)) + continue; + unsigned RCId = TLI->getRepRegClassFor(VT)->getID(); + RegPressure[RCId] += TLI->getRepRegClassCostFor(VT); + } + } - typedef RegReductionPriorityQueue - ILPBURRPriorityQueue; + dumpRegPressure(); } +//===----------------------------------------------------------------------===// +// Dynamic Node Priority for Register Pressure Reduction +//===----------------------------------------------------------------------===// + /// closestSucc - Returns the scheduled cycle of the successor which is /// closest to the current cycle. static unsigned closestSucc(const SUnit *SU) { @@ -1483,9 +1871,123 @@ static unsigned calcMaxScratches(const SUnit *SU) { return Scratches; } -template -static bool BURRSort(const SUnit *left, const SUnit *right, - const RegReductionPriorityQueue *SPQ) { +/// hasOnlyLiveOutUse - Return true if SU has a single value successor that is a +/// CopyToReg to a virtual register. This SU def is probably a liveout and +/// it has no other use. It should be scheduled closer to the terminator. +static bool hasOnlyLiveOutUses(const SUnit *SU) { + bool RetVal = false; + for (SUnit::const_succ_iterator I = SU->Succs.begin(), E = SU->Succs.end(); + I != E; ++I) { + if (I->isCtrl()) continue; + const SUnit *SuccSU = I->getSUnit(); + if (SuccSU->getNode() && SuccSU->getNode()->getOpcode() == ISD::CopyToReg) { + unsigned Reg = + cast(SuccSU->getNode()->getOperand(1))->getReg(); + if (TargetRegisterInfo::isVirtualRegister(Reg)) { + RetVal = true; + continue; + } + } + return false; + } + return RetVal; +} + +/// UnitsSharePred - Return true if the two scheduling units share a common +/// data predecessor. +static bool UnitsSharePred(const SUnit *left, const SUnit *right) { + SmallSet Preds; + for (SUnit::const_pred_iterator I = left->Preds.begin(),E = left->Preds.end(); + I != E; ++I) { + if (I->isCtrl()) continue; // ignore chain preds + Preds.insert(I->getSUnit()); + } + for (SUnit::const_pred_iterator I = right->Preds.begin(),E = right->Preds.end(); + I != E; ++I) { + if (I->isCtrl()) continue; // ignore chain preds + if (Preds.count(I->getSUnit())) + return true; + } + return false; +} + +// Check for either a dependence (latency) or resource (hazard) stall. +// +// Note: The ScheduleHazardRecognizer interface requires a non-const SU. +static bool BUHasStall(SUnit *SU, int Height, RegReductionPQBase *SPQ) { + if ((int)SPQ->getCurCycle() < Height) return true; + if (SPQ->getHazardRec()->getHazardType(SU, 0) + != ScheduleHazardRecognizer::NoHazard) + return true; + return false; +} + +// Return -1 if left has higher priority, 1 if right has higher priority. +// Return 0 if latency-based priority is equivalent. +static int BUCompareLatency(SUnit *left, SUnit *right, bool checkPref, + RegReductionPQBase *SPQ) { + // If the two nodes share an operand and one of them has a single + // use that is a live out copy, favor the one that is live out. Otherwise + // it will be difficult to eliminate the copy if the instruction is a + // loop induction variable update. e.g. + // BB: + // sub r1, r3, #1 + // str r0, [r2, r3] + // mov r3, r1 + // cmp + // bne BB + bool SharePred = UnitsSharePred(left, right); + // FIXME: Only adjust if BB is a loop back edge. + // FIXME: What's the cost of a copy? + int LBonus = (SharePred && hasOnlyLiveOutUses(left)) ? 1 : 0; + int RBonus = (SharePred && hasOnlyLiveOutUses(right)) ? 1 : 0; + int LHeight = (int)left->getHeight() - LBonus; + int RHeight = (int)right->getHeight() - RBonus; + + bool LStall = (!checkPref || left->SchedulingPref == Sched::Latency) && + BUHasStall(left, LHeight, SPQ); + bool RStall = (!checkPref || right->SchedulingPref == Sched::Latency) && + BUHasStall(right, RHeight, SPQ); + + // If scheduling one of the node will cause a pipeline stall, delay it. + // If scheduling either one of the node will cause a pipeline stall, sort + // them according to their height. + if (LStall) { + if (!RStall) + return 1; + if (LHeight != RHeight) + return LHeight > RHeight ? 1 : -1; + } else if (RStall) + return -1; + + // If either node is scheduling for latency, sort them by height/depth + // and latency. + if (!checkPref || (left->SchedulingPref == Sched::Latency || + right->SchedulingPref == Sched::Latency)) { + if (DisableSchedCycles) { + if (LHeight != RHeight) + return LHeight > RHeight ? 1 : -1; + } + else { + // If neither instruction stalls (!LStall && !RStall) then + // it's height is already covered so only its depth matters. We also reach + // this if both stall but have the same height. + unsigned LDepth = left->getDepth(); + unsigned RDepth = right->getDepth(); + if (LDepth != RDepth) { + DEBUG(dbgs() << " Comparing latency of SU (" << left->NodeNum + << ") depth " << LDepth << " vs SU (" << right->NodeNum + << ") depth " << RDepth << "\n"); + return LDepth < RDepth ? 1 : -1; + } + } + if (left->Latency != right->Latency) + return left->Latency > right->Latency ? 1 : -1; + } + return 0; +} + +static bool BURRSort(SUnit *left, SUnit *right, RegReductionPQBase *SPQ) { unsigned LPriority = SPQ->getNodePriority(left); unsigned RPriority = SPQ->getNodePriority(right); if (LPriority != RPriority) @@ -1519,24 +2021,31 @@ static bool BURRSort(const SUnit *left, const SUnit *right, if (LScratch != RScratch) return LScratch > RScratch; - if (left->getHeight() != right->getHeight()) - return left->getHeight() > right->getHeight(); - - if (left->getDepth() != right->getDepth()) - return left->getDepth() < right->getDepth(); + if (!DisableSchedCycles) { + int result = BUCompareLatency(left, right, false /*checkPref*/, SPQ); + if (result != 0) + return result > 0; + } + else { + if (left->getHeight() != right->getHeight()) + return left->getHeight() > right->getHeight(); - assert(left->NodeQueueId && right->NodeQueueId && + if (left->getDepth() != right->getDepth()) + return left->getDepth() < right->getDepth(); + } + + assert(left->NodeQueueId && right->NodeQueueId && "NodeQueueId cannot be zero"); return (left->NodeQueueId > right->NodeQueueId); } // Bottom up -bool bu_ls_rr_sort::operator()(const SUnit *left, const SUnit *right) const { +bool bu_ls_rr_sort::operator()(SUnit *left, SUnit *right) const { return BURRSort(left, right, SPQ); } // Source order, otherwise bottom up. -bool src_ls_rr_sort::operator()(const SUnit *left, const SUnit *right) const { +bool src_ls_rr_sort::operator()(SUnit *left, SUnit *right) const { unsigned LOrder = SPQ->getNodeOrdering(left); unsigned ROrder = SPQ->getNodeOrdering(right); @@ -1548,49 +2057,69 @@ bool src_ls_rr_sort::operator()(const SUnit *left, const SUnit *right) const { return BURRSort(left, right, SPQ); } -bool hybrid_ls_rr_sort::operator()(const SUnit *left, const SUnit *right) const{ +// If the time between now and when the instruction will be ready can cover +// the spill code, then avoid adding it to the ready queue. This gives long +// stalls highest priority and allows hoisting across calls. It should also +// speed up processing the available queue. +bool hybrid_ls_rr_sort::isReady(SUnit *SU, unsigned CurCycle) const { + static const unsigned ReadyDelay = 3; + + if (SPQ->MayReduceRegPressure(SU)) return true; + + if (SU->getHeight() > (CurCycle + ReadyDelay)) return false; + + if (SPQ->getHazardRec()->getHazardType(SU, -ReadyDelay) + != ScheduleHazardRecognizer::NoHazard) + return false; + + return true; +} + +// Return true if right should be scheduled with higher priority than left. +bool hybrid_ls_rr_sort::operator()(SUnit *left, SUnit *right) const { + if (left->isCall || right->isCall) + // No way to compute latency of calls. + return BURRSort(left, right, SPQ); + bool LHigh = SPQ->HighRegPressure(left); bool RHigh = SPQ->HighRegPressure(right); // Avoid causing spills. If register pressure is high, schedule for // register pressure reduction. - if (LHigh && !RHigh) + if (LHigh && !RHigh) { + DEBUG(dbgs() << " pressure SU(" << left->NodeNum << ") > SU(" + << right->NodeNum << ")\n"); return true; - else if (!LHigh && RHigh) + } + else if (!LHigh && RHigh) { + DEBUG(dbgs() << " pressure SU(" << right->NodeNum << ") > SU(" + << left->NodeNum << ")\n"); return false; + } else if (!LHigh && !RHigh) { - // Low register pressure situation, schedule for latency if possible. - bool LStall = left->SchedulingPref == Sched::Latency && - SPQ->getCurCycle() < left->getHeight(); - bool RStall = right->SchedulingPref == Sched::Latency && - SPQ->getCurCycle() < right->getHeight(); - // If scheduling one of the node will cause a pipeline stall, delay it. - // If scheduling either one of the node will cause a pipeline stall, sort - // them according to their height. - // If neither will cause a pipeline stall, try to reduce register pressure. - if (LStall) { - if (!RStall) - return true; - if (left->getHeight() != right->getHeight()) - return left->getHeight() > right->getHeight(); - } else if (RStall) - return false; - - // If either node is scheduling for latency, sort them by height and latency - // first. - if (left->SchedulingPref == Sched::Latency || - right->SchedulingPref == Sched::Latency) { - if (left->getHeight() != right->getHeight()) - return left->getHeight() > right->getHeight(); - if (left->Latency != right->Latency) - return left->Latency > right->Latency; - } + int result = BUCompareLatency(left, right, true /*checkPref*/, SPQ); + if (result != 0) + return result > 0; } - return BURRSort(left, right, SPQ); } -bool ilp_ls_rr_sort::operator()(const SUnit *left, - const SUnit *right) const { +// Schedule as many instructions in each cycle as possible. So don't make an +// instruction available unless it is ready in the current cycle. +bool ilp_ls_rr_sort::isReady(SUnit *SU, unsigned CurCycle) const { + if (SU->getHeight() > CurCycle) return false; + + if (SPQ->getHazardRec()->getHazardType(SU, 0) + != ScheduleHazardRecognizer::NoHazard) + return false; + + return SU->getHeight() <= CurCycle; +} + +bool ilp_ls_rr_sort::operator()(SUnit *left, SUnit *right) const { + if (left->isCall || right->isCall) + // No way to compute latency of calls. + return BURRSort(left, right, SPQ); + bool LHigh = SPQ->HighRegPressure(left); bool RHigh = SPQ->HighRegPressure(right); // Avoid causing spills. If register pressure is high, schedule for @@ -1611,9 +2140,11 @@ bool ilp_ls_rr_sort::operator()(const SUnit *left, return BURRSort(left, right, SPQ); } -template -bool -RegReductionPriorityQueue::canClobber(const SUnit *SU, const SUnit *Op) { +//===----------------------------------------------------------------------===// +// Preschedule for Register Pressure +//===----------------------------------------------------------------------===// + +bool RegReductionPQBase::canClobber(const SUnit *SU, const SUnit *Op) { if (SU->isTwoAddress) { unsigned Opc = SU->getNode()->getMachineOpcode(); const TargetInstrDesc &TID = TII->get(Opc); @@ -1631,19 +2162,6 @@ RegReductionPriorityQueue::canClobber(const SUnit *SU, const SUnit *Op) { return false; } -/// hasCopyToRegUse - Return true if SU has a value successor that is a -/// CopyToReg node. -static bool hasCopyToRegUse(const SUnit *SU) { - for (SUnit::const_succ_iterator I = SU->Succs.begin(), E = SU->Succs.end(); - I != E; ++I) { - if (I->isCtrl()) continue; - const SUnit *SuccSU = I->getSUnit(); - if (SuccSU->getNode() && SuccSU->getNode()->getOpcode() == ISD::CopyToReg) - return true; - } - return false; -} - /// canClobberPhysRegDefs - True if SU would clobber one of SuccSU's /// physical register defs. static bool canClobberPhysRegDefs(const SUnit *SuccSU, const SUnit *SU, @@ -1654,7 +2172,7 @@ static bool canClobberPhysRegDefs(const SUnit *SuccSU, const SUnit *SU, const unsigned *ImpDefs = TII->get(N->getMachineOpcode()).getImplicitDefs(); assert(ImpDefs && "Caller should check hasPhysRegDefs"); for (const SDNode *SUNode = SU->getNode(); SUNode; - SUNode = SUNode->getFlaggedNode()) { + SUNode = SUNode->getGluedNode()) { if (!SUNode->isMachineOpcode()) continue; const unsigned *SUImpDefs = @@ -1663,7 +2181,7 @@ static bool canClobberPhysRegDefs(const SUnit *SuccSU, const SUnit *SU, return false; for (unsigned i = NumDefs, e = N->getNumValues(); i != e; ++i) { EVT VT = N->getValueType(i); - if (VT == MVT::Flag || VT == MVT::Other) + if (VT == MVT::Glue || VT == MVT::Other) continue; if (!N->hasAnyUseOfValue(i)) continue; @@ -1709,8 +2227,7 @@ static bool canClobberPhysRegDefs(const SUnit *SuccSU, const SUnit *SU, /// after N, which shortens the U->N live range, reducing /// register pressure. /// -template -void RegReductionPriorityQueue::PrescheduleNodesWithMultipleUses() { +void RegReductionPQBase::PrescheduleNodesWithMultipleUses() { // Visit all the nodes in topological order, working top-down. for (unsigned i = 0, e = SUnits->size(); i != e; ++i) { SUnit *SU = &(*SUnits)[i]; @@ -1748,7 +2265,7 @@ void RegReductionPriorityQueue::PrescheduleNodesWithMultipleUses() { if (PredSU->NumSuccs == 1) continue; // Avoid prescheduling to copies from virtual registers, which don't behave - // like other nodes from the perspective of scheduling // heuristics. + // like other nodes from the perspective of scheduling heuristics. if (SDNode *N = SU->getNode()) if (N->getOpcode() == ISD::CopyFromReg && TargetRegisterInfo::isVirtualRegister @@ -1802,17 +2319,17 @@ void RegReductionPriorityQueue::PrescheduleNodesWithMultipleUses() { /// one that has a CopyToReg use (more likely to be a loop induction update). /// If both are two-address, but one is commutable while the other is not /// commutable, favor the one that's not commutable. -template -void RegReductionPriorityQueue::AddPseudoTwoAddrDeps() { +void RegReductionPQBase::AddPseudoTwoAddrDeps() { for (unsigned i = 0, e = SUnits->size(); i != e; ++i) { SUnit *SU = &(*SUnits)[i]; if (!SU->isTwoAddress) continue; SDNode *Node = SU->getNode(); - if (!Node || !Node->isMachineOpcode() || SU->getNode()->getFlaggedNode()) + if (!Node || !Node->isMachineOpcode() || SU->getNode()->getGluedNode()) continue; + bool isLiveOut = hasOnlyLiveOutUses(SU); unsigned Opc = Node->getMachineOpcode(); const TargetInstrDesc &TID = TII->get(Opc); unsigned NumRes = TID.getNumDefs(); @@ -1862,7 +2379,7 @@ void RegReductionPriorityQueue::AddPseudoTwoAddrDeps() { SuccOpc == TargetOpcode::SUBREG_TO_REG) continue; if ((!canClobber(SuccSU, DUSU) || - (hasCopyToRegUse(SU) && !hasCopyToRegUse(SuccSU)) || + (isLiveOut && !hasOnlyLiveOutUses(SuccSU)) || (!SU->isCommutable && SuccSU->isCommutable)) && !scheduleDAG->IsReachable(SuccSU, SU)) { DEBUG(dbgs() << " Adding a pseudo-two-addr edge from SU #" @@ -1877,20 +2394,10 @@ void RegReductionPriorityQueue::AddPseudoTwoAddrDeps() { } } -/// CalculateSethiUllmanNumbers - Calculate Sethi-Ullman numbers of all -/// scheduling units. -template -void RegReductionPriorityQueue::CalculateSethiUllmanNumbers() { - SethiUllmanNumbers.assign(SUnits->size(), 0); - - for (unsigned i = 0, e = SUnits->size(); i != e; ++i) - CalcNodeSethiUllmanNumber(&(*SUnits)[i], SethiUllmanNumbers); -} - /// LimitedSumOfUnscheduledPredsOfSuccs - Compute the sum of the unscheduled /// predecessors of the successors of the SUnit SU. Stop when the provided /// limit is exceeded. -static unsigned LimitedSumOfUnscheduledPredsOfSuccs(const SUnit *SU, +static unsigned LimitedSumOfUnscheduledPredsOfSuccs(const SUnit *SU, unsigned Limit) { unsigned Sum = 0; for (SUnit::const_succ_iterator I = SU->Succs.begin(), E = SU->Succs.end(); @@ -1942,7 +2449,7 @@ bool td_ls_rr_sort::operator()(const SUnit *left, const SUnit *right) const { if (left->NumSuccsLeft != right->NumSuccsLeft) return left->NumSuccsLeft > right->NumSuccsLeft; - assert(left->NodeQueueId && right->NodeQueueId && + assert(left->NodeQueueId && right->NodeQueueId && "NodeQueueId cannot be zero"); return (left->NodeQueueId > right->NodeQueueId); } @@ -1952,68 +2459,74 @@ bool td_ls_rr_sort::operator()(const SUnit *left, const SUnit *right) const { //===----------------------------------------------------------------------===// llvm::ScheduleDAGSDNodes * -llvm::createBURRListDAGScheduler(SelectionDAGISel *IS, CodeGenOpt::Level) { +llvm::createBURRListDAGScheduler(SelectionDAGISel *IS, + CodeGenOpt::Level OptLevel) { const TargetMachine &TM = IS->TM; const TargetInstrInfo *TII = TM.getInstrInfo(); const TargetRegisterInfo *TRI = TM.getRegisterInfo(); - + BURegReductionPriorityQueue *PQ = new BURegReductionPriorityQueue(*IS->MF, false, TII, TRI, 0); - ScheduleDAGRRList *SD = new ScheduleDAGRRList(*IS->MF, true, false, PQ); + ScheduleDAGRRList *SD = new ScheduleDAGRRList(*IS->MF, false, PQ, OptLevel); PQ->setScheduleDAG(SD); - return SD; + return SD; } llvm::ScheduleDAGSDNodes * -llvm::createTDRRListDAGScheduler(SelectionDAGISel *IS, CodeGenOpt::Level) { +llvm::createTDRRListDAGScheduler(SelectionDAGISel *IS, + CodeGenOpt::Level OptLevel) { const TargetMachine &TM = IS->TM; const TargetInstrInfo *TII = TM.getInstrInfo(); const TargetRegisterInfo *TRI = TM.getRegisterInfo(); - + TDRegReductionPriorityQueue *PQ = new TDRegReductionPriorityQueue(*IS->MF, false, TII, TRI, 0); - ScheduleDAGRRList *SD = new ScheduleDAGRRList(*IS->MF, false, false, PQ); + ScheduleDAGRRList *SD = new ScheduleDAGRRList(*IS->MF, false, PQ, OptLevel); PQ->setScheduleDAG(SD); return SD; } llvm::ScheduleDAGSDNodes * -llvm::createSourceListDAGScheduler(SelectionDAGISel *IS, CodeGenOpt::Level) { +llvm::createSourceListDAGScheduler(SelectionDAGISel *IS, + CodeGenOpt::Level OptLevel) { const TargetMachine &TM = IS->TM; const TargetInstrInfo *TII = TM.getInstrInfo(); const TargetRegisterInfo *TRI = TM.getRegisterInfo(); - + SrcRegReductionPriorityQueue *PQ = new SrcRegReductionPriorityQueue(*IS->MF, false, TII, TRI, 0); - ScheduleDAGRRList *SD = new ScheduleDAGRRList(*IS->MF, true, false, PQ); + ScheduleDAGRRList *SD = new ScheduleDAGRRList(*IS->MF, false, PQ, OptLevel); PQ->setScheduleDAG(SD); - return SD; + return SD; } llvm::ScheduleDAGSDNodes * -llvm::createHybridListDAGScheduler(SelectionDAGISel *IS, CodeGenOpt::Level) { +llvm::createHybridListDAGScheduler(SelectionDAGISel *IS, + CodeGenOpt::Level OptLevel) { const TargetMachine &TM = IS->TM; const TargetInstrInfo *TII = TM.getInstrInfo(); const TargetRegisterInfo *TRI = TM.getRegisterInfo(); const TargetLowering *TLI = &IS->getTargetLowering(); - + HybridBURRPriorityQueue *PQ = new HybridBURRPriorityQueue(*IS->MF, true, TII, TRI, TLI); - ScheduleDAGRRList *SD = new ScheduleDAGRRList(*IS->MF, true, true, PQ); + + ScheduleDAGRRList *SD = new ScheduleDAGRRList(*IS->MF, true, PQ, OptLevel); PQ->setScheduleDAG(SD); - return SD; + return SD; } llvm::ScheduleDAGSDNodes * -llvm::createILPListDAGScheduler(SelectionDAGISel *IS, CodeGenOpt::Level) { +llvm::createILPListDAGScheduler(SelectionDAGISel *IS, + CodeGenOpt::Level OptLevel) { const TargetMachine &TM = IS->TM; const TargetInstrInfo *TII = TM.getInstrInfo(); const TargetRegisterInfo *TRI = TM.getRegisterInfo(); const TargetLowering *TLI = &IS->getTargetLowering(); - + ILPBURRPriorityQueue *PQ = new ILPBURRPriorityQueue(*IS->MF, true, TII, TRI, TLI); - ScheduleDAGRRList *SD = new ScheduleDAGRRList(*IS->MF, true, true, PQ); + ScheduleDAGRRList *SD = new ScheduleDAGRRList(*IS->MF, true, PQ, OptLevel); PQ->setScheduleDAG(SD); - return SD; + return SD; } diff --git a/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp b/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp index f1bf82ab145a..477c1ffe65d3 100644 --- a/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp +++ b/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp @@ -34,8 +34,8 @@ using namespace llvm; STATISTIC(LoadsClustered, "Number of loads clustered together"); ScheduleDAGSDNodes::ScheduleDAGSDNodes(MachineFunction &mf) - : ScheduleDAG(mf) { -} + : ScheduleDAG(mf), + InstrItins(mf.getTarget().getInstrItineraryData()) {} /// Run - perform scheduling. /// @@ -72,6 +72,7 @@ SUnit *ScheduleDAGSDNodes::Clone(SUnit *Old) { SUnit *SU = NewSUnit(Old->getNode()); SU->OrigNode = Old->OrigNode; SU->Latency = Old->Latency; + SU->isCall = Old->isCall; SU->isTwoAddress = Old->isTwoAddress; SU->isCommutable = Old->isCommutable; SU->hasPhysRegDefs = Old->hasPhysRegDefs; @@ -85,7 +86,7 @@ SUnit *ScheduleDAGSDNodes::Clone(SUnit *Old) { /// a specified operand is a physical register dependency. If so, returns the /// register and the cost of copying the register. static void CheckForPhysRegDependency(SDNode *Def, SDNode *User, unsigned Op, - const TargetRegisterInfo *TRI, + const TargetRegisterInfo *TRI, const TargetInstrInfo *TII, unsigned &PhysReg, int &Cost) { if (Op != 2 || User->getOpcode() != ISD::CopyToReg) @@ -108,29 +109,28 @@ static void CheckForPhysRegDependency(SDNode *Def, SDNode *User, unsigned Op, } } -static void AddFlags(SDNode *N, SDValue Flag, bool AddFlag, - SelectionDAG *DAG) { +static void AddGlue(SDNode *N, SDValue Glue, bool AddGlue, SelectionDAG *DAG) { SmallVector VTs; - SDNode *FlagDestNode = Flag.getNode(); + SDNode *GlueDestNode = Glue.getNode(); - // Don't add a flag from a node to itself. - if (FlagDestNode == N) return; + // Don't add glue from a node to itself. + if (GlueDestNode == N) return; - // Don't add a flag to something which already has a flag. - if (N->getValueType(N->getNumValues() - 1) == MVT::Flag) return; + // Don't add glue to something which already has glue. + if (N->getValueType(N->getNumValues() - 1) == MVT::Glue) return; for (unsigned I = 0, E = N->getNumValues(); I != E; ++I) VTs.push_back(N->getValueType(I)); - if (AddFlag) - VTs.push_back(MVT::Flag); + if (AddGlue) + VTs.push_back(MVT::Glue); SmallVector Ops; for (unsigned I = 0, E = N->getNumOperands(); I != E; ++I) Ops.push_back(N->getOperand(I)); - if (FlagDestNode) - Ops.push_back(Flag); + if (GlueDestNode) + Ops.push_back(Glue); SDVTList VTList = DAG->getVTList(&VTs[0], VTs.size()); MachineSDNode::mmo_iterator Begin = 0, End = 0; @@ -149,9 +149,9 @@ static void AddFlags(SDNode *N, SDValue Flag, bool AddFlag, MN->setMemRefs(Begin, End); } -/// ClusterNeighboringLoads - Force nearby loads together by "flagging" them. +/// ClusterNeighboringLoads - Force nearby loads together by "gluing" them. /// This function finds loads of the same base and different offsets. If the -/// offsets are not far apart (target specific), it add MVT::Flag inputs and +/// offsets are not far apart (target specific), it add MVT::Glue inputs and /// outputs to ensure they are scheduled together and in order. This /// optimization may benefit some targets by improving cache locality. void ScheduleDAGSDNodes::ClusterNeighboringLoads(SDNode *Node) { @@ -213,20 +213,20 @@ void ScheduleDAGSDNodes::ClusterNeighboringLoads(SDNode *Node) { if (NumLoads == 0) return; - // Cluster loads by adding MVT::Flag outputs and inputs. This also + // Cluster loads by adding MVT::Glue outputs and inputs. This also // ensure they are scheduled in order of increasing addresses. SDNode *Lead = Loads[0]; - AddFlags(Lead, SDValue(0, 0), true, DAG); + AddGlue(Lead, SDValue(0, 0), true, DAG); - SDValue InFlag = SDValue(Lead, Lead->getNumValues() - 1); + SDValue InGlue = SDValue(Lead, Lead->getNumValues() - 1); for (unsigned I = 1, E = Loads.size(); I != E; ++I) { - bool OutFlag = I < E - 1; + bool OutGlue = I < E - 1; SDNode *Load = Loads[I]; - AddFlags(Load, InFlag, OutFlag, DAG); + AddGlue(Load, InGlue, OutGlue, DAG); - if (OutFlag) - InFlag = SDValue(Load, Load->getNumValues() - 1); + if (OutGlue) + InGlue = SDValue(Load, Load->getNumValues() - 1); ++LoadsClustered; } @@ -266,68 +266,75 @@ void ScheduleDAGSDNodes::BuildSchedUnits() { // FIXME: Multiply by 2 because we may clone nodes during scheduling. // This is a temporary workaround. SUnits.reserve(NumNodes * 2); - + // Add all nodes in depth first order. SmallVector Worklist; SmallPtrSet Visited; Worklist.push_back(DAG->getRoot().getNode()); Visited.insert(DAG->getRoot().getNode()); - + while (!Worklist.empty()) { SDNode *NI = Worklist.pop_back_val(); - + // Add all operands to the worklist unless they've already been added. for (unsigned i = 0, e = NI->getNumOperands(); i != e; ++i) if (Visited.insert(NI->getOperand(i).getNode())) Worklist.push_back(NI->getOperand(i).getNode()); - + if (isPassiveNode(NI)) // Leaf node, e.g. a TargetImmediate. continue; - + // If this node has already been processed, stop now. if (NI->getNodeId() != -1) continue; - + SUnit *NodeSUnit = NewSUnit(NI); - - // See if anything is flagged to this node, if so, add them to flagged - // nodes. Nodes can have at most one flag input and one flag output. Flags - // are required to be the last operand and result of a node. - - // Scan up to find flagged preds. + + // See if anything is glued to this node, if so, add them to glued + // nodes. Nodes can have at most one glue input and one glue output. Glue + // is required to be the last operand and result of a node. + + // Scan up to find glued preds. SDNode *N = NI; while (N->getNumOperands() && - N->getOperand(N->getNumOperands()-1).getValueType() == MVT::Flag) { + N->getOperand(N->getNumOperands()-1).getValueType() == MVT::Glue) { N = N->getOperand(N->getNumOperands()-1).getNode(); assert(N->getNodeId() == -1 && "Node already inserted!"); N->setNodeId(NodeSUnit->NodeNum); + if (N->isMachineOpcode() && TII->get(N->getMachineOpcode()).isCall()) + NodeSUnit->isCall = true; } - - // Scan down to find any flagged succs. + + // Scan down to find any glued succs. N = NI; - while (N->getValueType(N->getNumValues()-1) == MVT::Flag) { - SDValue FlagVal(N, N->getNumValues()-1); - - // There are either zero or one users of the Flag result. - bool HasFlagUse = false; - for (SDNode::use_iterator UI = N->use_begin(), E = N->use_end(); + while (N->getValueType(N->getNumValues()-1) == MVT::Glue) { + SDValue GlueVal(N, N->getNumValues()-1); + + // There are either zero or one users of the Glue result. + bool HasGlueUse = false; + for (SDNode::use_iterator UI = N->use_begin(), E = N->use_end(); UI != E; ++UI) - if (FlagVal.isOperandOf(*UI)) { - HasFlagUse = true; + if (GlueVal.isOperandOf(*UI)) { + HasGlueUse = true; assert(N->getNodeId() == -1 && "Node already inserted!"); N->setNodeId(NodeSUnit->NodeNum); N = *UI; + if (N->isMachineOpcode() && TII->get(N->getMachineOpcode()).isCall()) + NodeSUnit->isCall = true; break; } - if (!HasFlagUse) break; + if (!HasGlueUse) break; } - - // If there are flag operands involved, N is now the bottom-most node - // of the sequence of nodes that are flagged together. + + // If there are glue operands involved, N is now the bottom-most node + // of the sequence of nodes that are glued together. // Update the SUnit. NodeSUnit->setNode(N); assert(N->getNodeId() == -1 && "Node already inserted!"); N->setNodeId(NodeSUnit->NodeNum); + // Compute NumRegDefsLeft. This must be done before AddSchedEdges. + InitNumRegDefsLeft(NodeSUnit); + // Assign the Latency field of NodeSUnit using target-provided information. ComputeLatency(NodeSUnit); } @@ -343,7 +350,7 @@ void ScheduleDAGSDNodes::AddSchedEdges() { for (unsigned su = 0, e = SUnits.size(); su != e; ++su) { SUnit *SU = &SUnits[su]; SDNode *MainNode = SU->getNode(); - + if (MainNode->isMachineOpcode()) { unsigned Opc = MainNode->getMachineOpcode(); const TargetInstrDesc &TID = TII->get(Opc); @@ -356,9 +363,9 @@ void ScheduleDAGSDNodes::AddSchedEdges() { if (TID.isCommutable()) SU->isCommutable = true; } - + // Find all predecessors and successors of the group. - for (SDNode *N = SU->getNode(); N; N = N->getFlaggedNode()) { + for (SDNode *N = SU->getNode(); N; N = N->getGluedNode()) { if (N->isMachineOpcode() && TII->get(N->getMachineOpcode()).getImplicitDefs()) { SU->hasPhysRegClobbers = true; @@ -368,7 +375,7 @@ void ScheduleDAGSDNodes::AddSchedEdges() { if (NumUsed > TII->get(N->getMachineOpcode()).getNumDefs()) SU->hasPhysRegDefs = true; } - + for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) { SDNode *OpN = N->getOperand(i).getNode(); if (isPassiveNode(OpN)) continue; // Not scheduled. @@ -377,7 +384,7 @@ void ScheduleDAGSDNodes::AddSchedEdges() { if (OpSU == SU) continue; // In the same group. EVT OpVT = N->getOperand(i).getValueType(); - assert(OpVT != MVT::Flag && "Flagged nodes should be in same sunit!"); + assert(OpVT != MVT::Glue && "Glued nodes should be in same sunit!"); bool isChain = OpVT == MVT::Other; unsigned PhysReg = 0; @@ -403,7 +410,13 @@ void ScheduleDAGSDNodes::AddSchedEdges() { ST.adjustSchedDependency(OpSU, SU, const_cast(dep)); } - SU->addPred(dep); + if (!SU->addPred(dep) && !dep.isCtrl() && OpSU->NumRegDefsLeft > 0) { + // 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 + // a single use, so to keep pressure balanced we reduce the defs. + --OpSU->NumRegDefsLeft; + } } } } @@ -412,7 +425,7 @@ void ScheduleDAGSDNodes::AddSchedEdges() { /// BuildSchedGraph - Build the SUnit graph from the selection dag that we /// are input. This SUnit graph is similar to the SelectionDAG, but /// excludes nodes that aren't interesting to scheduling, and represents -/// flagged together nodes with a single SUnit. +/// glued together nodes with a single SUnit. void ScheduleDAGSDNodes::BuildSchedGraph(AliasAnalysis *AA) { // Cluster certain nodes which should be scheduled together. ClusterNodes(); @@ -422,6 +435,69 @@ void ScheduleDAGSDNodes::BuildSchedGraph(AliasAnalysis *AA) { AddSchedEdges(); } +// Initialize NumNodeDefs for the current Node's opcode. +void ScheduleDAGSDNodes::RegDefIter::InitNodeNumDefs() { + if (!Node->isMachineOpcode()) { + if (Node->getOpcode() == ISD::CopyFromReg) + NodeNumDefs = 1; + else + NodeNumDefs = 0; + return; + } + unsigned POpc = Node->getMachineOpcode(); + if (POpc == TargetOpcode::IMPLICIT_DEF) { + // No register need be allocated for this. + NodeNumDefs = 0; + return; + } + unsigned NRegDefs = SchedDAG->TII->get(Node->getMachineOpcode()).getNumDefs(); + // Some instructions define regs that are not represented in the selection DAG + // (e.g. unused flags). See tMOVi8. Make sure we don't access past NumValues. + NodeNumDefs = std::min(Node->getNumValues(), NRegDefs); + DefIdx = 0; +} + +// Construct a RegDefIter for this SUnit and find the first valid value. +ScheduleDAGSDNodes::RegDefIter::RegDefIter(const SUnit *SU, + const ScheduleDAGSDNodes *SD) + : SchedDAG(SD), Node(SU->getNode()), DefIdx(0), NodeNumDefs(0) { + InitNodeNumDefs(); + Advance(); +} + +// Advance to the next valid value defined by the SUnit. +void ScheduleDAGSDNodes::RegDefIter::Advance() { + for (;Node;) { // Visit all glued nodes. + for (;DefIdx < NodeNumDefs; ++DefIdx) { + if (!Node->hasAnyUseOfValue(DefIdx)) + continue; + if (Node->isMachineOpcode() && + Node->getMachineOpcode() == TargetOpcode::EXTRACT_SUBREG) { + // Propagate the incoming (full-register) type. I doubt it's needed. + ValueType = Node->getOperand(0).getValueType(); + } + else { + ValueType = Node->getValueType(DefIdx); + } + ++DefIdx; + return; // Found a normal regdef. + } + Node = Node->getGluedNode(); + if (Node == NULL) { + return; // No values left to visit. + } + InitNodeNumDefs(); + } +} + +void ScheduleDAGSDNodes::InitNumRegDefsLeft(SUnit *SU) { + assert(SU->NumRegDefsLeft == 0 && "expect a new node"); + for (RegDefIter I(SU, this); I.IsValid(); I.Advance()) { + assert(SU->NumRegDefsLeft < USHRT_MAX && "overflow is ok but unexpected"); + ++SU->NumRegDefsLeft; + } +} + void ScheduleDAGSDNodes::ComputeLatency(SUnit *SU) { // Check to see if the scheduler cares about latencies. if (ForceUnitLatencies()) { @@ -429,20 +505,17 @@ void ScheduleDAGSDNodes::ComputeLatency(SUnit *SU) { return; } - const InstrItineraryData &InstrItins = TM.getInstrItineraryData(); - if (InstrItins.isEmpty()) { + if (!InstrItins || InstrItins->isEmpty()) { SU->Latency = 1; return; } - + // Compute the latency for the node. We use the sum of the latencies for - // all nodes flagged together into this SUnit. + // all nodes glued together into this SUnit. SU->Latency = 0; - for (SDNode *N = SU->getNode(); N; N = N->getFlaggedNode()) - if (N->isMachineOpcode()) { - SU->Latency += InstrItins. - getStageLatency(TII->get(N->getMachineOpcode()).getSchedClass()); - } + for (SDNode *N = SU->getNode(); N; N = N->getGluedNode()) + if (N->isMachineOpcode()) + SU->Latency += TII->getInstrLatency(InstrItins, N); } void ScheduleDAGSDNodes::ComputeOperandLatency(SDNode *Def, SDNode *Use, @@ -451,32 +524,25 @@ void ScheduleDAGSDNodes::ComputeOperandLatency(SDNode *Def, SDNode *Use, if (ForceUnitLatencies()) return; - const InstrItineraryData &InstrItins = TM.getInstrItineraryData(); - if (InstrItins.isEmpty()) - return; - if (dep.getKind() != SDep::Data) return; unsigned DefIdx = Use->getOperand(OpIdx).getResNo(); - if (Def->isMachineOpcode()) { - const TargetInstrDesc &II = TII->get(Def->getMachineOpcode()); - if (DefIdx >= II.getNumDefs()) - return; - int DefCycle = InstrItins.getOperandCycle(II.getSchedClass(), DefIdx); - if (DefCycle < 0) - return; - int UseCycle = 1; - if (Use->isMachineOpcode()) { - const unsigned UseClass = TII->get(Use->getMachineOpcode()).getSchedClass(); - UseCycle = InstrItins.getOperandCycle(UseClass, OpIdx); - } - if (UseCycle >= 0) { - int Latency = DefCycle - UseCycle + 1; - if (Latency >= 0) - dep.setLatency(Latency); - } + if (Use->isMachineOpcode()) + // Adjust the use operand index by num of defs. + OpIdx += TII->get(Use->getMachineOpcode()).getNumDefs(); + int Latency = TII->getOperandLatency(InstrItins, Def, DefIdx, Use, OpIdx); + if (Latency > 1 && Use->getOpcode() == ISD::CopyToReg && + !BB->succ_empty()) { + unsigned Reg = cast(Use->getOperand(1))->getReg(); + if (TargetRegisterInfo::isVirtualRegister(Reg)) + // This copy is a liveout value. It is likely coalesced, so reduce the + // latency so not to penalize the def. + // FIXME: need target specific adjustment here? + Latency = (Latency > 1) ? Latency - 1 : 1; } + if (Latency >= 0) + dep.setLatency(Latency); } void ScheduleDAGSDNodes::dumpNode(const SUnit *SU) const { @@ -487,14 +553,14 @@ void ScheduleDAGSDNodes::dumpNode(const SUnit *SU) const { SU->getNode()->dump(DAG); dbgs() << "\n"; - SmallVector FlaggedNodes; - for (SDNode *N = SU->getNode()->getFlaggedNode(); N; N = N->getFlaggedNode()) - FlaggedNodes.push_back(N); - while (!FlaggedNodes.empty()) { + SmallVector GluedNodes; + for (SDNode *N = SU->getNode()->getGluedNode(); N; N = N->getGluedNode()) + GluedNodes.push_back(N); + while (!GluedNodes.empty()) { dbgs() << " "; - FlaggedNodes.back()->dump(DAG); + GluedNodes.back()->dump(DAG); dbgs() << "\n"; - FlaggedNodes.pop_back(); + GluedNodes.pop_back(); } } @@ -507,37 +573,25 @@ namespace { }; } -// ProcessSourceNode - Process nodes with source order numbers. These are added -// to a vector which EmitSchedule uses to determine how to insert dbg_value -// instructions in the right order. -static void ProcessSourceNode(SDNode *N, SelectionDAG *DAG, - InstrEmitter &Emitter, - DenseMap &VRBaseMap, +/// ProcessSDDbgValues - Process SDDbgValues assoicated with this node. +static void ProcessSDDbgValues(SDNode *N, SelectionDAG *DAG, + InstrEmitter &Emitter, SmallVector, 32> &Orders, - SmallSet &Seen) { - unsigned Order = DAG->GetOrdering(N); - if (!Order || !Seen.insert(Order)) - return; - - MachineBasicBlock *BB = Emitter.getBlock(); - if (Emitter.getInsertPos() == BB->begin() || BB->back().isPHI()) { - // Did not insert any instruction. - Orders.push_back(std::make_pair(Order, (MachineInstr*)0)); - return; - } - - Orders.push_back(std::make_pair(Order, prior(Emitter.getInsertPos()))); + DenseMap &VRBaseMap, + unsigned Order) { if (!N->getHasDebugValue()) return; + // Opportunistically insert immediate dbg_value uses, i.e. those with source // order number right after the N. + MachineBasicBlock *BB = Emitter.getBlock(); MachineBasicBlock::iterator InsertPos = Emitter.getInsertPos(); SmallVector &DVs = DAG->GetDbgValues(N); for (unsigned i = 0, e = DVs.size(); i != e; ++i) { if (DVs[i]->isInvalidated()) continue; unsigned DVOrder = DVs[i]->getOrder(); - if (DVOrder == ++Order) { + if (!Order || DVOrder == ++Order) { MachineInstr *DbgMI = Emitter.EmitDbgValue(DVs[i], VRBaseMap); if (DbgMI) { Orders.push_back(std::make_pair(DVOrder, DbgMI)); @@ -548,6 +602,33 @@ static void ProcessSourceNode(SDNode *N, SelectionDAG *DAG, } } +// ProcessSourceNode - Process nodes with source order numbers. These are added +// to a vector which EmitSchedule uses to determine how to insert dbg_value +// instructions in the right order. +static void ProcessSourceNode(SDNode *N, SelectionDAG *DAG, + InstrEmitter &Emitter, + DenseMap &VRBaseMap, + SmallVector, 32> &Orders, + SmallSet &Seen) { + unsigned Order = DAG->GetOrdering(N); + if (!Order || !Seen.insert(Order)) { + // Process any valid SDDbgValues even if node does not have any order + // assigned. + ProcessSDDbgValues(N, DAG, Emitter, Orders, VRBaseMap, 0); + return; + } + + MachineBasicBlock *BB = Emitter.getBlock(); + if (Emitter.getInsertPos() == BB->begin() || BB->back().isPHI()) { + // Did not insert any instruction. + Orders.push_back(std::make_pair(Order, (MachineInstr*)0)); + return; + } + + Orders.push_back(std::make_pair(Order, prior(Emitter.getInsertPos()))); + ProcessSDDbgValues(N, DAG, Emitter, Orders, VRBaseMap, Order); +} + /// EmitSchedule - Emit the machine code in scheduled order. MachineBasicBlock *ScheduleDAGSDNodes::EmitSchedule() { @@ -578,25 +659,25 @@ MachineBasicBlock *ScheduleDAGSDNodes::EmitSchedule() { } // For pre-regalloc scheduling, create instructions corresponding to the - // SDNode and any flagged SDNodes and append them to the block. + // SDNode and any glued SDNodes and append them to the block. if (!SU->getNode()) { // Emit a copy. EmitPhysRegCopy(SU, CopyVRBaseMap); continue; } - SmallVector FlaggedNodes; - for (SDNode *N = SU->getNode()->getFlaggedNode(); N; - N = N->getFlaggedNode()) - FlaggedNodes.push_back(N); - while (!FlaggedNodes.empty()) { - SDNode *N = FlaggedNodes.back(); - Emitter.EmitNode(FlaggedNodes.back(), SU->OrigNode != SU, SU->isCloned, + SmallVector GluedNodes; + for (SDNode *N = SU->getNode()->getGluedNode(); N; + N = N->getGluedNode()) + GluedNodes.push_back(N); + while (!GluedNodes.empty()) { + SDNode *N = GluedNodes.back(); + Emitter.EmitNode(GluedNodes.back(), SU->OrigNode != SU, SU->isCloned, VRBaseMap); // Remember the source order of the inserted instruction. if (HasDbg) ProcessSourceNode(N, DAG, Emitter, VRBaseMap, Orders, Seen); - FlaggedNodes.pop_back(); + GluedNodes.pop_back(); } Emitter.EmitNode(SU->getNode(), SU->OrigNode != SU, SU->isCloned, VRBaseMap); @@ -625,16 +706,8 @@ MachineBasicBlock *ScheduleDAGSDNodes::EmitSchedule() { // Insert all SDDbgValue's whose order(s) are before "Order". if (!MI) continue; -#ifndef NDEBUG - unsigned LastDIOrder = 0; -#endif for (; DI != DE && (*DI)->getOrder() >= LastOrder && (*DI)->getOrder() < Order; ++DI) { -#ifndef NDEBUG - assert((*DI)->getOrder() >= LastDIOrder && - "SDDbgValue nodes must be in source order!"); - LastDIOrder = (*DI)->getOrder(); -#endif if ((*DI)->isInvalidated()) continue; MachineInstr *DbgMI = Emitter.EmitDbgValue(*DI, VRBaseMap); diff --git a/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.h b/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.h index 842fc8c72703..cc7310e4ca42 100644 --- a/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.h +++ b/lib/CodeGen/SelectionDAG/ScheduleDAGSDNodes.h @@ -20,13 +20,13 @@ namespace llvm { /// ScheduleDAGSDNodes - A ScheduleDAG for scheduling SDNode-based DAGs. - /// + /// /// Edges between SUnits are initially based on edges in the SelectionDAG, /// and additional edges can be added by the schedulers as heuristics. /// SDNodes such as Constants, Registers, and a few others that are not /// interesting to schedulers are not allocated SUnits. /// - /// SDNodes with MVT::Flag operands are grouped along with the flagged + /// SDNodes with MVT::Glue operands are grouped along with the flagged /// nodes into a single SUnit so that they are scheduled together. /// /// SDNode-based scheduling graphs do not use SDep::Anti or SDep::Output @@ -36,6 +36,7 @@ namespace llvm { class ScheduleDAGSDNodes : public ScheduleDAG { public: SelectionDAG *DAG; // DAG of the current basic block + const InstrItineraryData *InstrItins; explicit ScheduleDAGSDNodes(MachineFunction &mf); @@ -72,13 +73,17 @@ namespace llvm { /// predecessors / successors info nor the temporary scheduling states. /// SUnit *Clone(SUnit *N); - + /// BuildSchedGraph - Build the SUnit graph from the selection dag that we /// are input. This SUnit graph is similar to the SelectionDAG, but /// excludes nodes that aren't interesting to scheduling, and represents /// flagged together nodes with a single SUnit. virtual void BuildSchedGraph(AliasAnalysis *AA); + /// InitNumRegDefsLeft - Determine the # of regs defined by this node. + /// + void InitNumRegDefsLeft(SUnit *SU); + /// ComputeLatency - Compute node latency. /// virtual void ComputeLatency(SUnit *SU); @@ -105,6 +110,30 @@ namespace llvm { virtual void getCustomGraphFeatures(GraphWriter &GW) const; + /// RegDefIter - In place iteration over the values defined by an + /// SUnit. This does not need copies of the iterator or any other STLisms. + /// The iterator creates itself, rather than being provided by the SchedDAG. + class RegDefIter { + const ScheduleDAGSDNodes *SchedDAG; + const SDNode *Node; + unsigned DefIdx; + unsigned NodeNumDefs; + EVT ValueType; + public: + RegDefIter(const SUnit *SU, const ScheduleDAGSDNodes *SD); + + bool IsValid() const { return Node != NULL; } + + EVT GetValue() const { + assert(IsValid() && "bad iterator"); + return ValueType; + } + + void Advance(); + private: + void InitNodeNumDefs(); + }; + private: /// ClusterNeighboringLoads - Cluster loads from "near" addresses into /// combined SUnits. diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index ad06ebda5b00..2fb2f2d8aa1e 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -31,7 +31,6 @@ #include "llvm/CodeGen/PseudoSourceValue.h" #include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetData.h" -#include "llvm/Target/TargetFrameInfo.h" #include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetSelectionDAGInfo.h" #include "llvm/Target/TargetOptions.h" @@ -44,7 +43,7 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Mutex.h" +#include "llvm/Support/Mutex.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" @@ -111,7 +110,7 @@ bool ConstantFPSDNode::isValueValidForType(EVT VT, /// BUILD_VECTOR where all of the elements are ~0 or undef. bool ISD::isBuildVectorAllOnes(const SDNode *N) { // Look through a bit convert. - if (N->getOpcode() == ISD::BIT_CONVERT) + if (N->getOpcode() == ISD::BITCAST) N = N->getOperand(0).getNode(); if (N->getOpcode() != ISD::BUILD_VECTOR) return false; @@ -152,7 +151,7 @@ bool ISD::isBuildVectorAllOnes(const SDNode *N) { /// BUILD_VECTOR where all of the elements are 0 or undef. bool ISD::isBuildVectorAllZeros(const SDNode *N) { // Look through a bit convert. - if (N->getOpcode() == ISD::BIT_CONVERT) + if (N->getOpcode() == ISD::BITCAST) N = N->getOperand(0).getNode(); if (N->getOpcode() != ISD::BUILD_VECTOR) return false; @@ -199,6 +198,8 @@ bool ISD::isScalarToVector(const SDNode *N) { if (N->getOperand(0).getOpcode() == ISD::UNDEF) return false; unsigned NumElems = N->getNumOperands(); + if (NumElems == 1) + return false; for (unsigned i = 1; i < NumElems; ++i) { SDValue V = N->getOperand(i); if (V.getOpcode() != ISD::UNDEF) @@ -489,7 +490,7 @@ encodeMemSDNodeFlags(int ConvType, ISD::MemIndexedMode AM, bool isVolatile, /// doNotCSE - Return true if CSE should not be performed for this node. static bool doNotCSE(SDNode *N) { - if (N->getValueType(0) == MVT::Flag) + if (N->getValueType(0) == MVT::Glue) return true; // Never CSE anything that produces a flag. switch (N->getOpcode()) { @@ -501,7 +502,7 @@ static bool doNotCSE(SDNode *N) { // Check that remaining values produced are not flags. for (unsigned i = 1, e = N->getNumValues(); i != e; ++i) - if (N->getValueType(i) == MVT::Flag) + if (N->getValueType(i) == MVT::Glue) return true; // Never CSE anything that produces a flag. return false; @@ -609,9 +610,6 @@ void SelectionDAG::DeallocateNode(SDNode *N) { bool SelectionDAG::RemoveNodeFromCSEMaps(SDNode *N) { bool Erased = false; switch (N->getOpcode()) { - case ISD::EntryToken: - llvm_unreachable("EntryToken should not be in CSEMaps!"); - return false; case ISD::HANDLENODE: return false; // noop. case ISD::CONDCODE: assert(CondCodeNodes[cast(N)->get()] && @@ -641,6 +639,8 @@ bool SelectionDAG::RemoveNodeFromCSEMaps(SDNode *N) { } default: // Remove it from the CSE Map. + assert(N->getOpcode() != ISD::DELETED_NODE && "DELETED_NODE in CSEMap!"); + assert(N->getOpcode() != ISD::EntryToken && "EntryToken in CSEMap!"); Erased = CSEMap.RemoveNode(N); break; } @@ -648,7 +648,7 @@ bool SelectionDAG::RemoveNodeFromCSEMaps(SDNode *N) { // Verify that the node was actually in one of the CSE maps, unless it has a // flag result (which cannot be CSE'd) or is one of the special cases that are // not subject to CSE. - if (!Erased && N->getValueType(N->getNumValues()-1) != MVT::Flag && + if (!Erased && N->getValueType(N->getNumValues()-1) != MVT::Glue && !N->isMachineOpcode() && !doNotCSE(N)) { N->dump(this); dbgs() << "\n"; @@ -743,8 +743,9 @@ SDNode *SelectionDAG::FindModifiedNodeSlot(SDNode *N, return Node; } -/// VerifyNode - Sanity check the given node. Aborts if it is invalid. -void SelectionDAG::VerifyNode(SDNode *N) { +#ifndef NDEBUG +/// VerifyNodeCommon - Sanity check the given node. Aborts if it is invalid. +static void VerifyNodeCommon(SDNode *N) { switch (N->getOpcode()) { default: break; @@ -778,6 +779,44 @@ void SelectionDAG::VerifyNode(SDNode *N) { } } +/// VerifySDNode - Sanity check the given SDNode. Aborts if it is invalid. +static void VerifySDNode(SDNode *N) { + // The SDNode allocators cannot be used to allocate nodes with fields that are + // not present in an SDNode! + assert(!isa(N) && "Bad MemSDNode!"); + assert(!isa(N) && "Bad ShuffleVectorSDNode!"); + assert(!isa(N) && "Bad ConstantSDNode!"); + assert(!isa(N) && "Bad ConstantFPSDNode!"); + assert(!isa(N) && "Bad GlobalAddressSDNode!"); + assert(!isa(N) && "Bad FrameIndexSDNode!"); + assert(!isa(N) && "Bad JumpTableSDNode!"); + assert(!isa(N) && "Bad ConstantPoolSDNode!"); + assert(!isa(N) && "Bad BasicBlockSDNode!"); + assert(!isa(N) && "Bad SrcValueSDNode!"); + assert(!isa(N) && "Bad MDNodeSDNode!"); + assert(!isa(N) && "Bad RegisterSDNode!"); + assert(!isa(N) && "Bad BlockAddressSDNode!"); + assert(!isa(N) && "Bad EHLabelSDNode!"); + assert(!isa(N) && "Bad ExternalSymbolSDNode!"); + assert(!isa(N) && "Bad CondCodeSDNode!"); + assert(!isa(N) && "Bad CvtRndSatSDNode!"); + assert(!isa(N) && "Bad VTSDNode!"); + assert(!isa(N) && "Bad MachineSDNode!"); + + VerifyNodeCommon(N); +} + +/// VerifyMachineNode - Sanity check the given MachineNode. Aborts if it is +/// invalid. +static void VerifyMachineNode(SDNode *N) { + // The MachineNode allocators cannot be used to allocate nodes with fields + // that are not present in a MachineNode! + // Currently there are no such nodes. + + VerifyNodeCommon(N); +} +#endif // NDEBUG + /// getEVTAlignment - Compute the default alignment value for the /// given type. /// @@ -1315,7 +1354,7 @@ SDValue SelectionDAG::getEHLabel(DebugLoc dl, SDValue Root, MCSymbol *Label) { void *IP = 0; if (SDNode *E = CSEMap.FindNodeOrInsertPos(ID, IP)) return SDValue(E, 0); - + SDNode *N = new (NodeAllocator) EHLabelSDNode(dl, Root, Label); CSEMap.InsertNode(N, IP); AllNodes.push_back(N); @@ -1365,11 +1404,11 @@ SDValue SelectionDAG::getMDNode(const MDNode *MD) { FoldingSetNodeID ID; AddNodeIDNode(ID, ISD::MDNODE_SDNODE, getVTList(MVT::Other), 0, 0); ID.AddPointer(MD); - + void *IP = 0; if (SDNode *E = CSEMap.FindNodeOrInsertPos(ID, IP)) return SDValue(E, 0); - + SDNode *N = new (NodeAllocator) MDNodeSDNode(MD); CSEMap.InsertNode(N, IP); AllNodes.push_back(N); @@ -1613,7 +1652,7 @@ void SelectionDAG::ComputeMaskedBits(SDValue Op, const APInt &Mask, // Also compute a conserative estimate for high known-0 bits. // More trickiness is possible, but this is sufficient for the // interesting case of alignment computation. - KnownOne.clear(); + KnownOne.clearAllBits(); unsigned TrailZ = KnownZero.countTrailingOnes() + KnownZero2.countTrailingOnes(); unsigned LeadZ = std::max(KnownZero.countLeadingOnes() + @@ -1636,8 +1675,8 @@ void SelectionDAG::ComputeMaskedBits(SDValue Op, const APInt &Mask, AllOnes, KnownZero2, KnownOne2, Depth+1); unsigned LeadZ = KnownZero2.countLeadingOnes(); - KnownOne2.clear(); - KnownZero2.clear(); + KnownOne2.clearAllBits(); + KnownZero2.clearAllBits(); ComputeMaskedBits(Op.getOperand(1), AllOnes, KnownZero2, KnownOne2, Depth+1); unsigned RHSUnknownLeadingOnes = KnownOne2.countLeadingZeros(); @@ -1765,7 +1804,7 @@ void SelectionDAG::ComputeMaskedBits(SDValue Op, const APInt &Mask, // If the sign extended bits are demanded, we know that the sign // bit is demanded. - InSignBit.zext(BitWidth); + InSignBit = InSignBit.zext(BitWidth); if (NewBits.getBoolValue()) InputDemandedBits |= InSignBit; @@ -1792,7 +1831,7 @@ void SelectionDAG::ComputeMaskedBits(SDValue Op, const APInt &Mask, case ISD::CTPOP: { unsigned LowBits = Log2_32(BitWidth)+1; KnownZero = APInt::getHighBitsSet(BitWidth, BitWidth - LowBits); - KnownOne.clear(); + KnownOne.clearAllBits(); return; } case ISD::LOAD: { @@ -1808,13 +1847,12 @@ void SelectionDAG::ComputeMaskedBits(SDValue Op, const APInt &Mask, EVT InVT = Op.getOperand(0).getValueType(); unsigned InBits = InVT.getScalarType().getSizeInBits(); APInt NewBits = APInt::getHighBitsSet(BitWidth, BitWidth - InBits) & Mask; - APInt InMask = Mask; - InMask.trunc(InBits); - KnownZero.trunc(InBits); - KnownOne.trunc(InBits); + APInt InMask = Mask.trunc(InBits); + KnownZero = KnownZero.trunc(InBits); + KnownOne = KnownOne.trunc(InBits); ComputeMaskedBits(Op.getOperand(0), InMask, KnownZero, KnownOne, Depth+1); - KnownZero.zext(BitWidth); - KnownOne.zext(BitWidth); + KnownZero = KnownZero.zext(BitWidth); + KnownOne = KnownOne.zext(BitWidth); KnownZero |= NewBits; return; } @@ -1823,16 +1861,15 @@ void SelectionDAG::ComputeMaskedBits(SDValue Op, const APInt &Mask, unsigned InBits = InVT.getScalarType().getSizeInBits(); APInt InSignBit = APInt::getSignBit(InBits); APInt NewBits = APInt::getHighBitsSet(BitWidth, BitWidth - InBits) & Mask; - APInt InMask = Mask; - InMask.trunc(InBits); + APInt InMask = Mask.trunc(InBits); // If any of the sign extended bits are demanded, we know that the sign // bit is demanded. Temporarily set this bit in the mask for our callee. if (NewBits.getBoolValue()) InMask |= InSignBit; - KnownZero.trunc(InBits); - KnownOne.trunc(InBits); + KnownZero = KnownZero.trunc(InBits); + KnownOne = KnownOne.trunc(InBits); ComputeMaskedBits(Op.getOperand(0), InMask, KnownZero, KnownOne, Depth+1); // Note if the sign bit is known to be zero or one. @@ -1844,13 +1881,12 @@ void SelectionDAG::ComputeMaskedBits(SDValue Op, const APInt &Mask, // If the sign bit wasn't actually demanded by our caller, we don't // want it set in the KnownZero and KnownOne result values. Reset the // mask and reapply it to the result values. - InMask = Mask; - InMask.trunc(InBits); + InMask = Mask.trunc(InBits); KnownZero &= InMask; KnownOne &= InMask; - KnownZero.zext(BitWidth); - KnownOne.zext(BitWidth); + KnownZero = KnownZero.zext(BitWidth); + KnownOne = KnownOne.zext(BitWidth); // If the sign bit is known zero or one, the top bits match. if (SignBitKnownZero) @@ -1862,26 +1898,24 @@ void SelectionDAG::ComputeMaskedBits(SDValue Op, const APInt &Mask, case ISD::ANY_EXTEND: { EVT InVT = Op.getOperand(0).getValueType(); unsigned InBits = InVT.getScalarType().getSizeInBits(); - APInt InMask = Mask; - InMask.trunc(InBits); - KnownZero.trunc(InBits); - KnownOne.trunc(InBits); + APInt InMask = Mask.trunc(InBits); + KnownZero = KnownZero.trunc(InBits); + KnownOne = KnownOne.trunc(InBits); ComputeMaskedBits(Op.getOperand(0), InMask, KnownZero, KnownOne, Depth+1); - KnownZero.zext(BitWidth); - KnownOne.zext(BitWidth); + KnownZero = KnownZero.zext(BitWidth); + KnownOne = KnownOne.zext(BitWidth); return; } case ISD::TRUNCATE: { EVT InVT = Op.getOperand(0).getValueType(); unsigned InBits = InVT.getScalarType().getSizeInBits(); - APInt InMask = Mask; - InMask.zext(InBits); - KnownZero.zext(InBits); - KnownOne.zext(InBits); + APInt InMask = Mask.zext(InBits); + KnownZero = KnownZero.zext(InBits); + KnownOne = KnownOne.zext(InBits); ComputeMaskedBits(Op.getOperand(0), InMask, KnownZero, KnownOne, Depth+1); assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); - KnownZero.trunc(BitWidth); - KnownOne.trunc(BitWidth); + KnownZero = KnownZero.trunc(BitWidth); + KnownOne = KnownOne.trunc(BitWidth); break; } case ISD::AssertZext: { @@ -1921,7 +1955,8 @@ void SelectionDAG::ComputeMaskedBits(SDValue Op, const APInt &Mask, } } // fall through - case ISD::ADD: { + case ISD::ADD: + case ISD::ADDE: { // Output known-0 bits are known if clear or set in both the low clear bits // common to both LHS & RHS. For example, 8+(X<<3) is known to have the // low 3 bits clear. @@ -1936,7 +1971,17 @@ void SelectionDAG::ComputeMaskedBits(SDValue Op, const APInt &Mask, KnownZeroOut = std::min(KnownZeroOut, KnownZero2.countTrailingOnes()); - KnownZero |= APInt::getLowBitsSet(BitWidth, KnownZeroOut); + if (Op.getOpcode() == ISD::ADD) { + KnownZero |= APInt::getLowBitsSet(BitWidth, KnownZeroOut); + return; + } + + // With ADDE, a carry bit may be added in, so we can only use this + // information if we know (at least) that the low two bits are clear. We + // then return to the caller that the low bit is unknown but that other bits + // are known zero. + if (KnownZeroOut >= 2) // ADDE + KnownZero |= APInt::getBitsSet(BitWidth, 1, KnownZeroOut); return; } case ISD::SREM: @@ -1991,10 +2036,19 @@ void SelectionDAG::ComputeMaskedBits(SDValue Op, const APInt &Mask, uint32_t Leaders = std::max(KnownZero.countLeadingOnes(), KnownZero2.countLeadingOnes()); - KnownOne.clear(); + KnownOne.clearAllBits(); KnownZero = APInt::getHighBitsSet(BitWidth, Leaders) & Mask; return; } + case ISD::FrameIndex: + case ISD::TargetFrameIndex: + if (unsigned Align = InferPtrAlignment(Op)) { + // The low bits are known zero if the pointer is aligned. + KnownZero = APInt::getLowBitsSet(BitWidth, Log2_32(Align)); + return; + } + break; + default: // Allow the target to implement this method for its nodes. if (Op.getOpcode() >= ISD::BUILTIN_OP_END) { @@ -2234,6 +2288,25 @@ unsigned SelectionDAG::ComputeNumSignBits(SDValue Op, unsigned Depth) const{ return std::max(FirstAnswer, std::min(VTBits, Mask.countLeadingZeros())); } +/// isBaseWithConstantOffset - Return true if the specified operand is an +/// ISD::ADD with a ConstantSDNode on the right-hand side, or if it is an +/// ISD::OR with a ConstantSDNode that is guaranteed to have the same +/// semantics as an ADD. This handles the equivalence: +/// X|Cst == X+Cst iff X&Cst = 0. +bool SelectionDAG::isBaseWithConstantOffset(SDValue Op) const { + if ((Op.getOpcode() != ISD::ADD && Op.getOpcode() != ISD::OR) || + !isa(Op.getOperand(1))) + return false; + + if (Op.getOpcode() == ISD::OR && + !MaskedValueIsZero(Op.getOperand(0), + cast(Op.getOperand(1))->getAPIntValue())) + return false; + + return true; +} + + bool SelectionDAG::isKnownNeverNaN(SDValue Op) const { // If we're told that NaNs won't happen, assume they won't. if (NoNaNsFPMath) @@ -2295,7 +2368,7 @@ SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL, EVT VT) { AllNodes.push_back(N); #ifndef NDEBUG - VerifyNode(N); + VerifySDNode(N); #endif return SDValue(N, 0); } @@ -2308,23 +2381,22 @@ SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL, switch (Opcode) { default: break; case ISD::SIGN_EXTEND: - return getConstant(APInt(Val).sextOrTrunc(VT.getSizeInBits()), VT); + return getConstant(Val.sextOrTrunc(VT.getSizeInBits()), VT); case ISD::ANY_EXTEND: case ISD::ZERO_EXTEND: case ISD::TRUNCATE: - return getConstant(APInt(Val).zextOrTrunc(VT.getSizeInBits()), VT); + return getConstant(Val.zextOrTrunc(VT.getSizeInBits()), VT); case ISD::UINT_TO_FP: case ISD::SINT_TO_FP: { - const uint64_t zero[] = {0, 0}; // No compile time operations on ppcf128. if (VT == MVT::ppcf128) break; - APFloat apf = APFloat(APInt(VT.getSizeInBits(), 2, zero)); + APFloat apf(APInt::getNullValue(VT.getSizeInBits())); (void)apf.convertFromAPInt(Val, Opcode==ISD::SINT_TO_FP, APFloat::rmNearestTiesToEven); return getConstantFP(apf, VT); } - case ISD::BIT_CONVERT: + case ISD::BITCAST: if (VT == MVT::f32 && C->getValueType(0) == MVT::i32) return getConstantFP(Val.bitsToFloat(), VT); else if (VT == MVT::f64 && C->getValueType(0) == MVT::i64) @@ -2375,7 +2447,7 @@ SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL, APInt api(VT.getSizeInBits(), 2, x); return getConstant(api, VT); } - case ISD::BIT_CONVERT: + case ISD::BITCAST: if (VT == MVT::i32 && C->getValueType(0) == MVT::f32) return getConstant((uint32_t)V.bitcastToAPInt().getZExtValue(), VT); else if (VT == MVT::i64 && C->getValueType(0) == MVT::f64) @@ -2477,13 +2549,13 @@ SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL, return Operand.getNode()->getOperand(0); } break; - case ISD::BIT_CONVERT: + case ISD::BITCAST: // Basic sanity checking. assert(VT.getSizeInBits() == Operand.getValueType().getSizeInBits() - && "Cannot BIT_CONVERT between types of different sizes!"); + && "Cannot BITCAST between types of different sizes!"); if (VT == Operand.getValueType()) return Operand; // noop conversion. - if (OpOpcode == ISD::BIT_CONVERT) // bitconv(bitconv(x)) -> bitconv(x) - return getNode(ISD::BIT_CONVERT, DL, VT, Operand.getOperand(0)); + if (OpOpcode == ISD::BITCAST) // bitconv(bitconv(x)) -> bitconv(x) + return getNode(ISD::BITCAST, DL, VT, Operand.getOperand(0)); if (OpOpcode == ISD::UNDEF) return getUNDEF(VT); break; @@ -2519,7 +2591,7 @@ SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL, SDNode *N; SDVTList VTs = getVTList(VT); - if (VT != MVT::Flag) { // Don't CSE flag producing nodes + if (VT != MVT::Glue) { // Don't CSE flag producing nodes FoldingSetNodeID ID; SDValue Ops[1] = { Operand }; AddNodeIDNode(ID, Opcode, VTs, Ops, 1); @@ -2535,7 +2607,7 @@ SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL, AllNodes.push_back(N); #ifndef NDEBUG - VerifyNode(N); + VerifySDNode(N); #endif return SDValue(N, 0); } @@ -2676,6 +2748,13 @@ SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL, EVT VT, "Shift operators return type must be the same as their first arg"); assert(VT.isInteger() && N2.getValueType().isInteger() && "Shifts only work on integers"); + // Verify that the shift amount VT is bit enough to hold valid shift + // amounts. This catches things like trying to shift an i1024 value by an + // i8, which is easy to fall into in generic code that uses + // TLI.getShiftAmount(). + assert(N2.getValueType().getSizeInBits() >= + Log2_32_Ceil(N1.getValueType().getSizeInBits()) && + "Invalid use of small shift amount with oversized value!"); // Always fold shifts of i1 values so the code generator doesn't need to // handle them. Since we know the size of the shift has to be less than the @@ -2820,11 +2899,30 @@ SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL, EVT VT, return getConstant(ShiftedVal.trunc(ElementSize), VT); } break; - case ISD::EXTRACT_SUBVECTOR: - if (N1.getValueType() == VT) // Trivial extraction. - return N1; + case ISD::EXTRACT_SUBVECTOR: { + SDValue Index = N2; + if (VT.isSimple() && N1.getValueType().isSimple()) { + assert(VT.isVector() && N1.getValueType().isVector() && + "Extract subvector VTs must be a vectors!"); + assert(VT.getVectorElementType() == N1.getValueType().getVectorElementType() && + "Extract subvector VTs must have the same element type!"); + assert(VT.getSimpleVT() <= N1.getValueType().getSimpleVT() && + "Extract subvector must be from larger vector to smaller vector!"); + + if (isa(Index.getNode())) { + assert((VT.getVectorNumElements() + + cast(Index.getNode())->getZExtValue() + <= N1.getValueType().getVectorNumElements()) + && "Extract subvector overflow!"); + } + + // Trivial extraction. + if (VT.getSimpleVT() == N1.getValueType().getSimpleVT()) + return N1; + } break; } + } if (N1C) { if (N2C) { @@ -2961,7 +3059,7 @@ SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL, EVT VT, // Memoize this node if possible. SDNode *N; SDVTList VTs = getVTList(VT); - if (VT != MVT::Flag) { + if (VT != MVT::Glue) { SDValue Ops[] = { N1, N2 }; FoldingSetNodeID ID; AddNodeIDNode(ID, Opcode, VTs, Ops, 2); @@ -2977,7 +3075,7 @@ SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL, EVT VT, AllNodes.push_back(N); #ifndef NDEBUG - VerifyNode(N); + VerifySDNode(N); #endif return SDValue(N, 0); } @@ -3019,7 +3117,31 @@ SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL, EVT VT, case ISD::VECTOR_SHUFFLE: llvm_unreachable("should use getVectorShuffle constructor!"); break; - case ISD::BIT_CONVERT: + case ISD::INSERT_SUBVECTOR: { + SDValue Index = N3; + if (VT.isSimple() && N1.getValueType().isSimple() + && N2.getValueType().isSimple()) { + assert(VT.isVector() && N1.getValueType().isVector() && + N2.getValueType().isVector() && + "Insert subvector VTs must be a vectors"); + assert(VT == N1.getValueType() && + "Dest and insert subvector source types must match!"); + assert(N2.getValueType().getSimpleVT() <= N1.getValueType().getSimpleVT() && + "Insert subvector must be from smaller vector to larger vector!"); + if (isa(Index.getNode())) { + assert((N2.getValueType().getVectorNumElements() + + cast(Index.getNode())->getZExtValue() + <= VT.getVectorNumElements()) + && "Insert subvector overflow!"); + } + + // Trivial insertion. + if (VT.getSimpleVT() == N2.getValueType().getSimpleVT()) + return N2; + } + break; + } + case ISD::BITCAST: // Fold bit_convert nodes from a type to themselves. if (N1.getValueType() == VT) return N1; @@ -3029,7 +3151,7 @@ SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL, EVT VT, // Memoize node if it doesn't produce a flag. SDNode *N; SDVTList VTs = getVTList(VT); - if (VT != MVT::Flag) { + if (VT != MVT::Glue) { SDValue Ops[] = { N1, N2, N3 }; FoldingSetNodeID ID; AddNodeIDNode(ID, Opcode, VTs, Ops, 3); @@ -3045,7 +3167,7 @@ SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL, EVT VT, AllNodes.push_back(N); #ifndef NDEBUG - VerifyNode(N); + VerifySDNode(N); #endif return SDValue(N, 0); } @@ -3087,6 +3209,17 @@ SDValue SelectionDAG::getStackArgumentTokenFactor(SDValue Chain) { &ArgChains[0], ArgChains.size()); } +/// SplatByte - Distribute ByteVal over NumBits bits. +static APInt SplatByte(unsigned NumBits, uint8_t ByteVal) { + APInt Val = APInt(NumBits, ByteVal); + unsigned Shift = 8; + for (unsigned i = NumBits; i > 8; i >>= 1) { + Val = (Val << Shift) | Val; + Shift <<= 1; + } + return Val; +} + /// getMemsetValue - Vectorized representation of the memset value /// operand. static SDValue getMemsetValue(SDValue Value, EVT VT, SelectionDAG &DAG, @@ -3095,27 +3228,18 @@ static SDValue getMemsetValue(SDValue Value, EVT VT, SelectionDAG &DAG, unsigned NumBits = VT.getScalarType().getSizeInBits(); if (ConstantSDNode *C = dyn_cast(Value)) { - APInt Val = APInt(NumBits, C->getZExtValue() & 255); - unsigned Shift = 8; - for (unsigned i = NumBits; i > 8; i >>= 1) { - Val = (Val << Shift) | Val; - Shift <<= 1; - } + APInt Val = SplatByte(NumBits, C->getZExtValue() & 255); if (VT.isInteger()) return DAG.getConstant(Val, VT); return DAG.getConstantFP(APFloat(Val), VT); } - const TargetLowering &TLI = DAG.getTargetLoweringInfo(); Value = DAG.getNode(ISD::ZERO_EXTEND, dl, VT, Value); - unsigned Shift = 8; - for (unsigned i = NumBits; i > 8; i >>= 1) { - Value = DAG.getNode(ISD::OR, dl, VT, - DAG.getNode(ISD::SHL, dl, VT, Value, - DAG.getConstant(Shift, - TLI.getShiftAmountTy())), - Value); - Shift <<= 1; + if (NumBits > 8) { + // Use a multiplication with 0x010101... to extend the input to the + // required length. + APInt Magic = SplatByte(NumBits, 0x01); + Value = DAG.getNode(ISD::MUL, dl, VT, Value, DAG.getConstant(Magic, VT)); } return Value; @@ -3131,13 +3255,12 @@ static SDValue getMemsetStringVal(EVT VT, DebugLoc dl, SelectionDAG &DAG, if (Str.empty()) { if (VT.isInteger()) return DAG.getConstant(0, VT); - else if (VT.getSimpleVT().SimpleTy == MVT::f32 || - VT.getSimpleVT().SimpleTy == MVT::f64) + else if (VT == MVT::f32 || VT == MVT::f64) return DAG.getConstantFP(0.0, VT); else if (VT.isVector()) { unsigned NumElts = VT.getVectorNumElements(); MVT EltVT = (VT.getVectorElementType() == MVT::f32) ? MVT::i32 : MVT::i64; - return DAG.getNode(ISD::BIT_CONVERT, dl, VT, + return DAG.getNode(ISD::BITCAST, dl, VT, DAG.getConstant(0, EVT::getVectorVT(*DAG.getContext(), EltVT, NumElts))); } else @@ -3234,15 +3357,6 @@ static bool FindOptimalMemOpLowering(std::vector &MemOps, if (VT.bitsGT(LVT)) VT = LVT; } - - // If we're optimizing for size, and there is a limit, bump the maximum number - // of operations inserted down to 4. This is a wild guess that approximates - // the size of a call to memcpy or memset (3 arguments + call). - if (Limit != ~0U) { - const Function *F = DAG.getMachineFunction().getFunction(); - if (F->hasFnAttr(Attribute::OptimizeForSize)) - Limit = 4; - } unsigned NumMemOps = 0; while (Size != 0) { @@ -3276,18 +3390,22 @@ static SDValue getMemcpyLoadsAndStores(SelectionDAG &DAG, DebugLoc dl, SDValue Src, uint64_t Size, unsigned Align, bool isVol, bool AlwaysInline, - const Value *DstSV, uint64_t DstSVOff, - const Value *SrcSV, uint64_t SrcSVOff) { + MachinePointerInfo DstPtrInfo, + MachinePointerInfo SrcPtrInfo) { // Turn a memcpy of undef to nop. if (Src.getOpcode() == ISD::UNDEF) return Chain; // Expand memcpy to a series of load and store ops if the size operand falls // below a certain threshold. + // TODO: In the AlwaysInline case, if the size is big then generate a loop + // rather than maybe a humongous number of loads and stores. const TargetLowering &TLI = DAG.getTargetLoweringInfo(); std::vector MemOps; bool DstAlignCanChange = false; - MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + bool OptSize = MF.getFunction()->hasFnAttr(Attribute::OptimizeForSize); FrameIndexSDNode *FI = dyn_cast(Dst); if (FI && !MFI->isFixedObjectIndex(FI->getIndex())) DstAlignCanChange = true; @@ -3297,8 +3415,8 @@ static SDValue getMemcpyLoadsAndStores(SelectionDAG &DAG, DebugLoc dl, std::string Str; bool CopyFromStr = isMemSrcFromString(Src, Str); bool isZeroStr = CopyFromStr && Str.empty(); - unsigned Limit = AlwaysInline ? ~0U : TLI.getMaxStoresPerMemcpy(); - + unsigned Limit = AlwaysInline ? ~0U : TLI.getMaxStoresPerMemcpy(OptSize); + if (!FindOptimalMemOpLowering(MemOps, Limit, Size, (DstAlignCanChange ? 0 : Align), (isZeroStr ? 0 : SrcAlign), @@ -3334,7 +3452,8 @@ static SDValue getMemcpyLoadsAndStores(SelectionDAG &DAG, DebugLoc dl, Value = getMemsetStringVal(VT, dl, DAG, TLI, Str, SrcOff); Store = DAG.getStore(Chain, dl, Value, getMemBasePlusOffset(Dst, DstOff, DAG), - DstSV, DstSVOff + DstOff, isVol, false, Align); + DstPtrInfo.getWithOffset(DstOff), isVol, + false, Align); } else { // The type might not be legal for the target. This should only happen // if the type is smaller than a legal type, as on PPC, so the right @@ -3343,14 +3462,14 @@ static SDValue getMemcpyLoadsAndStores(SelectionDAG &DAG, DebugLoc dl, // FIXME does the case above also need this? EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT); assert(NVT.bitsGE(VT)); - Value = DAG.getExtLoad(ISD::EXTLOAD, NVT, dl, Chain, + Value = DAG.getExtLoad(ISD::EXTLOAD, dl, NVT, Chain, getMemBasePlusOffset(Src, SrcOff, DAG), - SrcSV, SrcSVOff + SrcOff, VT, isVol, false, + SrcPtrInfo.getWithOffset(SrcOff), VT, isVol, false, MinAlign(SrcAlign, SrcOff)); Store = DAG.getTruncStore(Chain, dl, Value, getMemBasePlusOffset(Dst, DstOff, DAG), - DstSV, DstSVOff + DstOff, VT, isVol, false, - Align); + DstPtrInfo.getWithOffset(DstOff), VT, isVol, + false, Align); } OutChains.push_back(Store); SrcOff += VTSize; @@ -3366,8 +3485,8 @@ static SDValue getMemmoveLoadsAndStores(SelectionDAG &DAG, DebugLoc dl, SDValue Src, uint64_t Size, unsigned Align, bool isVol, bool AlwaysInline, - const Value *DstSV, uint64_t DstSVOff, - const Value *SrcSV, uint64_t SrcSVOff) { + MachinePointerInfo DstPtrInfo, + MachinePointerInfo SrcPtrInfo) { // Turn a memmove of undef to nop. if (Src.getOpcode() == ISD::UNDEF) return Chain; @@ -3377,14 +3496,16 @@ static SDValue getMemmoveLoadsAndStores(SelectionDAG &DAG, DebugLoc dl, const TargetLowering &TLI = DAG.getTargetLoweringInfo(); std::vector MemOps; bool DstAlignCanChange = false; - MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + bool OptSize = MF.getFunction()->hasFnAttr(Attribute::OptimizeForSize); FrameIndexSDNode *FI = dyn_cast(Dst); if (FI && !MFI->isFixedObjectIndex(FI->getIndex())) DstAlignCanChange = true; unsigned SrcAlign = DAG.InferPtrAlignment(Src); if (Align > SrcAlign) SrcAlign = Align; - unsigned Limit = AlwaysInline ? ~0U : TLI.getMaxStoresPerMemmove(); + unsigned Limit = AlwaysInline ? ~0U : TLI.getMaxStoresPerMemmove(OptSize); if (!FindOptimalMemOpLowering(MemOps, Limit, Size, (DstAlignCanChange ? 0 : Align), @@ -3414,7 +3535,8 @@ static SDValue getMemmoveLoadsAndStores(SelectionDAG &DAG, DebugLoc dl, Value = DAG.getLoad(VT, dl, Chain, getMemBasePlusOffset(Src, SrcOff, DAG), - SrcSV, SrcSVOff + SrcOff, isVol, false, SrcAlign); + SrcPtrInfo.getWithOffset(SrcOff), isVol, + false, SrcAlign); LoadValues.push_back(Value); LoadChains.push_back(Value.getValue(1)); SrcOff += VTSize; @@ -3429,7 +3551,7 @@ static SDValue getMemmoveLoadsAndStores(SelectionDAG &DAG, DebugLoc dl, Store = DAG.getStore(Chain, dl, LoadValues[i], getMemBasePlusOffset(Dst, DstOff, DAG), - DstSV, DstSVOff + DstOff, isVol, false, Align); + DstPtrInfo.getWithOffset(DstOff), isVol, false, Align); OutChains.push_back(Store); DstOff += VTSize; } @@ -3442,7 +3564,7 @@ static SDValue getMemsetStores(SelectionDAG &DAG, DebugLoc dl, SDValue Chain, SDValue Dst, SDValue Src, uint64_t Size, unsigned Align, bool isVol, - const Value *DstSV, uint64_t DstSVOff) { + MachinePointerInfo DstPtrInfo) { // Turn a memset of undef to nop. if (Src.getOpcode() == ISD::UNDEF) return Chain; @@ -3452,13 +3574,15 @@ static SDValue getMemsetStores(SelectionDAG &DAG, DebugLoc dl, const TargetLowering &TLI = DAG.getTargetLoweringInfo(); std::vector MemOps; bool DstAlignCanChange = false; - MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + bool OptSize = MF.getFunction()->hasFnAttr(Attribute::OptimizeForSize); FrameIndexSDNode *FI = dyn_cast(Dst); if (FI && !MFI->isFixedObjectIndex(FI->getIndex())) DstAlignCanChange = true; bool NonScalarIntSafe = isa(Src) && cast(Src)->isNullValue(); - if (!FindOptimalMemOpLowering(MemOps, TLI.getMaxStoresPerMemset(), + if (!FindOptimalMemOpLowering(MemOps, TLI.getMaxStoresPerMemset(OptSize), Size, (DstAlignCanChange ? 0 : Align), 0, NonScalarIntSafe, false, DAG, TLI)) return SDValue(); @@ -3477,15 +3601,34 @@ static SDValue getMemsetStores(SelectionDAG &DAG, DebugLoc dl, SmallVector OutChains; uint64_t DstOff = 0; unsigned NumMemOps = MemOps.size(); + + // Find the largest store and generate the bit pattern for it. + EVT LargestVT = MemOps[0]; + for (unsigned i = 1; i < NumMemOps; i++) + if (MemOps[i].bitsGT(LargestVT)) + LargestVT = MemOps[i]; + SDValue MemSetValue = getMemsetValue(Src, LargestVT, DAG, dl); + for (unsigned i = 0; i < NumMemOps; i++) { EVT VT = MemOps[i]; - unsigned VTSize = VT.getSizeInBits() / 8; - SDValue Value = getMemsetValue(Src, VT, DAG, dl); + + // If this store is smaller than the largest store see whether we can get + // the smaller value for free with a truncate. + SDValue Value = MemSetValue; + if (VT.bitsLT(LargestVT)) { + if (!LargestVT.isVector() && !VT.isVector() && + TLI.isTruncateFree(LargestVT, VT)) + Value = DAG.getNode(ISD::TRUNCATE, dl, VT, MemSetValue); + else + Value = getMemsetValue(Src, VT, DAG, dl); + } + assert(Value.getValueType() == VT && "Value with wrong type."); SDValue Store = DAG.getStore(Chain, dl, Value, getMemBasePlusOffset(Dst, DstOff, DAG), - DstSV, DstSVOff + DstOff, isVol, false, 0); + DstPtrInfo.getWithOffset(DstOff), + isVol, false, Align); OutChains.push_back(Store); - DstOff += VTSize; + DstOff += VT.getSizeInBits() / 8; } return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, @@ -3495,8 +3638,8 @@ static SDValue getMemsetStores(SelectionDAG &DAG, DebugLoc dl, SDValue SelectionDAG::getMemcpy(SDValue Chain, DebugLoc dl, SDValue Dst, SDValue Src, SDValue Size, unsigned Align, bool isVol, bool AlwaysInline, - const Value *DstSV, uint64_t DstSVOff, - const Value *SrcSV, uint64_t SrcSVOff) { + MachinePointerInfo DstPtrInfo, + MachinePointerInfo SrcPtrInfo) { // Check to see if we should lower the memcpy to loads and stores first. // For cases within the target-specified limits, this is the best choice. @@ -3508,7 +3651,7 @@ SDValue SelectionDAG::getMemcpy(SDValue Chain, DebugLoc dl, SDValue Dst, SDValue Result = getMemcpyLoadsAndStores(*this, dl, Chain, Dst, Src, ConstantSize->getZExtValue(),Align, - isVol, false, DstSV, DstSVOff, SrcSV, SrcSVOff); + isVol, false, DstPtrInfo, SrcPtrInfo); if (Result.getNode()) return Result; } @@ -3518,7 +3661,7 @@ SDValue SelectionDAG::getMemcpy(SDValue Chain, DebugLoc dl, SDValue Dst, SDValue Result = TSI.EmitTargetCodeForMemcpy(*this, dl, Chain, Dst, Src, Size, Align, isVol, AlwaysInline, - DstSV, DstSVOff, SrcSV, SrcSVOff); + DstPtrInfo, SrcPtrInfo); if (Result.getNode()) return Result; @@ -3528,7 +3671,7 @@ SDValue SelectionDAG::getMemcpy(SDValue Chain, DebugLoc dl, SDValue Dst, assert(ConstantSize && "AlwaysInline requires a constant size!"); return getMemcpyLoadsAndStores(*this, dl, Chain, Dst, Src, ConstantSize->getZExtValue(), Align, isVol, - true, DstSV, DstSVOff, SrcSV, SrcSVOff); + true, DstPtrInfo, SrcPtrInfo); } // FIXME: If the memcpy is volatile (isVol), lowering it to a plain libc @@ -3559,8 +3702,8 @@ SDValue SelectionDAG::getMemcpy(SDValue Chain, DebugLoc dl, SDValue Dst, SDValue SelectionDAG::getMemmove(SDValue Chain, DebugLoc dl, SDValue Dst, SDValue Src, SDValue Size, unsigned Align, bool isVol, - const Value *DstSV, uint64_t DstSVOff, - const Value *SrcSV, uint64_t SrcSVOff) { + MachinePointerInfo DstPtrInfo, + MachinePointerInfo SrcPtrInfo) { // Check to see if we should lower the memmove to loads and stores first. // For cases within the target-specified limits, this is the best choice. @@ -3573,7 +3716,7 @@ SDValue SelectionDAG::getMemmove(SDValue Chain, DebugLoc dl, SDValue Dst, SDValue Result = getMemmoveLoadsAndStores(*this, dl, Chain, Dst, Src, ConstantSize->getZExtValue(), Align, isVol, - false, DstSV, DstSVOff, SrcSV, SrcSVOff); + false, DstPtrInfo, SrcPtrInfo); if (Result.getNode()) return Result; } @@ -3582,7 +3725,7 @@ SDValue SelectionDAG::getMemmove(SDValue Chain, DebugLoc dl, SDValue Dst, // code. If the target chooses to do this, this is the next best. SDValue Result = TSI.EmitTargetCodeForMemmove(*this, dl, Chain, Dst, Src, Size, Align, isVol, - DstSV, DstSVOff, SrcSV, SrcSVOff); + DstPtrInfo, SrcPtrInfo); if (Result.getNode()) return Result; @@ -3611,7 +3754,7 @@ SDValue SelectionDAG::getMemmove(SDValue Chain, DebugLoc dl, SDValue Dst, SDValue SelectionDAG::getMemset(SDValue Chain, DebugLoc dl, SDValue Dst, SDValue Src, SDValue Size, unsigned Align, bool isVol, - const Value *DstSV, uint64_t DstSVOff) { + MachinePointerInfo DstPtrInfo) { // Check to see if we should lower the memset to stores first. // For cases within the target-specified limits, this is the best choice. @@ -3623,7 +3766,7 @@ SDValue SelectionDAG::getMemset(SDValue Chain, DebugLoc dl, SDValue Dst, SDValue Result = getMemsetStores(*this, dl, Chain, Dst, Src, ConstantSize->getZExtValue(), - Align, isVol, DstSV, DstSVOff); + Align, isVol, DstPtrInfo); if (Result.getNode()) return Result; @@ -3633,11 +3776,11 @@ SDValue SelectionDAG::getMemset(SDValue Chain, DebugLoc dl, SDValue Dst, // code. If the target chooses to do this, this is the next best. SDValue Result = TSI.EmitTargetCodeForMemset(*this, dl, Chain, Dst, Src, Size, Align, isVol, - DstSV, DstSVOff); + DstPtrInfo); if (Result.getNode()) return Result; - // Emit a library call. + // Emit a library call. const Type *IntPtrTy = TLI.getTargetData()->getIntPtrType(*getContext()); TargetLowering::ArgListTy Args; TargetLowering::ArgListEntry Entry; @@ -3669,19 +3812,12 @@ SDValue SelectionDAG::getMemset(SDValue Chain, DebugLoc dl, SDValue Dst, } SDValue SelectionDAG::getAtomic(unsigned Opcode, DebugLoc dl, EVT MemVT, - SDValue Chain, - SDValue Ptr, SDValue Cmp, - SDValue Swp, const Value* PtrVal, + SDValue Chain, SDValue Ptr, SDValue Cmp, + SDValue Swp, MachinePointerInfo PtrInfo, unsigned Alignment) { if (Alignment == 0) // Ensure that codegen never sees alignment 0 Alignment = getEVTAlignment(MemVT); - // Check if the memory reference references a frame index - if (!PtrVal) - if (const FrameIndexSDNode *FI = - dyn_cast(Ptr.getNode())) - PtrVal = PseudoSourceValue::getFixedStack(FI->getIndex()); - MachineFunction &MF = getMachineFunction(); unsigned Flags = MachineMemOperand::MOLoad | MachineMemOperand::MOStore; @@ -3689,8 +3825,7 @@ SDValue SelectionDAG::getAtomic(unsigned Opcode, DebugLoc dl, EVT MemVT, Flags |= MachineMemOperand::MOVolatile; MachineMemOperand *MMO = - MF.getMachineMemOperand(PtrVal, Flags, 0, - MemVT.getStoreSize(), Alignment); + MF.getMachineMemOperand(PtrInfo, Flags, MemVT.getStoreSize(), Alignment); return getAtomic(Opcode, dl, MemVT, Chain, Ptr, Cmp, Swp, MMO); } @@ -3729,12 +3864,6 @@ SDValue SelectionDAG::getAtomic(unsigned Opcode, DebugLoc dl, EVT MemVT, if (Alignment == 0) // Ensure that codegen never sees alignment 0 Alignment = getEVTAlignment(MemVT); - // Check if the memory reference references a frame index - if (!PtrVal) - if (const FrameIndexSDNode *FI = - dyn_cast(Ptr.getNode())) - PtrVal = PseudoSourceValue::getFixedStack(FI->getIndex()); - MachineFunction &MF = getMachineFunction(); unsigned Flags = MachineMemOperand::MOLoad | MachineMemOperand::MOStore; @@ -3742,7 +3871,7 @@ SDValue SelectionDAG::getAtomic(unsigned Opcode, DebugLoc dl, EVT MemVT, Flags |= MachineMemOperand::MOVolatile; MachineMemOperand *MMO = - MF.getMachineMemOperand(PtrVal, Flags, 0, + MF.getMachineMemOperand(MachinePointerInfo(PtrVal), Flags, MemVT.getStoreSize(), Alignment); return getAtomic(Opcode, dl, MemVT, Chain, Ptr, Val, MMO); @@ -3785,7 +3914,6 @@ SDValue SelectionDAG::getAtomic(unsigned Opcode, DebugLoc dl, EVT MemVT, } /// getMergeValues - Create a MERGE_VALUES node from the given operands. -/// Allowed to return something different (and simpler) if Simplify is true. SDValue SelectionDAG::getMergeValues(const SDValue *Ops, unsigned NumOps, DebugLoc dl) { if (NumOps == 1) @@ -3803,18 +3931,18 @@ SDValue SelectionDAG::getMemIntrinsicNode(unsigned Opcode, DebugLoc dl, const EVT *VTs, unsigned NumVTs, const SDValue *Ops, unsigned NumOps, - EVT MemVT, const Value *srcValue, int SVOff, + EVT MemVT, MachinePointerInfo PtrInfo, unsigned Align, bool Vol, bool ReadMem, bool WriteMem) { return getMemIntrinsicNode(Opcode, dl, makeVTList(VTs, NumVTs), Ops, NumOps, - MemVT, srcValue, SVOff, Align, Vol, + MemVT, PtrInfo, Align, Vol, ReadMem, WriteMem); } SDValue SelectionDAG::getMemIntrinsicNode(unsigned Opcode, DebugLoc dl, SDVTList VTList, const SDValue *Ops, unsigned NumOps, - EVT MemVT, const Value *srcValue, int SVOff, + EVT MemVT, MachinePointerInfo PtrInfo, unsigned Align, bool Vol, bool ReadMem, bool WriteMem) { if (Align == 0) // Ensure that codegen never sees alignment 0 @@ -3829,8 +3957,7 @@ SelectionDAG::getMemIntrinsicNode(unsigned Opcode, DebugLoc dl, SDVTList VTList, if (Vol) Flags |= MachineMemOperand::MOVolatile; MachineMemOperand *MMO = - MF.getMachineMemOperand(srcValue, Flags, SVOff, - MemVT.getStoreSize(), Align); + MF.getMachineMemOperand(PtrInfo, Flags, MemVT.getStoreSize(), Align); return getMemIntrinsicNode(Opcode, dl, VTList, Ops, NumOps, MemVT, MMO); } @@ -3841,13 +3968,14 @@ SelectionDAG::getMemIntrinsicNode(unsigned Opcode, DebugLoc dl, SDVTList VTList, EVT MemVT, MachineMemOperand *MMO) { assert((Opcode == ISD::INTRINSIC_VOID || Opcode == ISD::INTRINSIC_W_CHAIN || + Opcode == ISD::PREFETCH || (Opcode <= INT_MAX && (int)Opcode >= ISD::FIRST_TARGET_MEMORY_OPCODE)) && "Opcode is not a memory-accessing opcode!"); // Memoize the node unless it returns a flag. MemIntrinsicSDNode *N; - if (VTList.VTs[VTList.NumVTs-1] != MVT::Flag) { + if (VTList.VTs[VTList.NumVTs-1] != MVT::Glue) { FoldingSetNodeID ID; AddNodeIDNode(ID, Opcode, VTList, Ops, NumOps); void *IP = 0; @@ -3867,36 +3995,70 @@ SelectionDAG::getMemIntrinsicNode(unsigned Opcode, DebugLoc dl, SDVTList VTList, return SDValue(N, 0); } +/// InferPointerInfo - If the specified ptr/offset is a frame index, infer a +/// MachinePointerInfo record from it. This is particularly useful because the +/// code generator has many cases where it doesn't bother passing in a +/// MachinePointerInfo to getLoad or getStore when it has "FI+Cst". +static MachinePointerInfo InferPointerInfo(SDValue Ptr, int64_t Offset = 0) { + // If this is FI+Offset, we can model it. + if (const FrameIndexSDNode *FI = dyn_cast(Ptr)) + return MachinePointerInfo::getFixedStack(FI->getIndex(), Offset); + + // If this is (FI+Offset1)+Offset2, we can model it. + if (Ptr.getOpcode() != ISD::ADD || + !isa(Ptr.getOperand(1)) || + !isa(Ptr.getOperand(0))) + return MachinePointerInfo(); + + int FI = cast(Ptr.getOperand(0))->getIndex(); + return MachinePointerInfo::getFixedStack(FI, Offset+ + cast(Ptr.getOperand(1))->getSExtValue()); +} + +/// InferPointerInfo - If the specified ptr/offset is a frame index, infer a +/// MachinePointerInfo record from it. This is particularly useful because the +/// code generator has many cases where it doesn't bother passing in a +/// MachinePointerInfo to getLoad or getStore when it has "FI+Cst". +static MachinePointerInfo InferPointerInfo(SDValue Ptr, SDValue OffsetOp) { + // If the 'Offset' value isn't a constant, we can't handle this. + if (ConstantSDNode *OffsetNode = dyn_cast(OffsetOp)) + return InferPointerInfo(Ptr, OffsetNode->getSExtValue()); + if (OffsetOp.getOpcode() == ISD::UNDEF) + return InferPointerInfo(Ptr); + return MachinePointerInfo(); +} + + SDValue SelectionDAG::getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, EVT VT, DebugLoc dl, SDValue Chain, SDValue Ptr, SDValue Offset, - const Value *SV, int SVOffset, EVT MemVT, + MachinePointerInfo PtrInfo, EVT MemVT, bool isVolatile, bool isNonTemporal, - unsigned Alignment) { + unsigned Alignment, const MDNode *TBAAInfo) { if (Alignment == 0) // Ensure that codegen never sees alignment 0 Alignment = getEVTAlignment(VT); - // Check if the memory reference references a frame index - if (!SV) - if (const FrameIndexSDNode *FI = - dyn_cast(Ptr.getNode())) - SV = PseudoSourceValue::getFixedStack(FI->getIndex()); - - MachineFunction &MF = getMachineFunction(); unsigned Flags = MachineMemOperand::MOLoad; if (isVolatile) Flags |= MachineMemOperand::MOVolatile; if (isNonTemporal) Flags |= MachineMemOperand::MONonTemporal; + + // If we don't have a PtrInfo, infer the trivial frame index case to simplify + // clients. + if (PtrInfo.V == 0) + PtrInfo = InferPointerInfo(Ptr, Offset); + + MachineFunction &MF = getMachineFunction(); MachineMemOperand *MMO = - MF.getMachineMemOperand(SV, Flags, SVOffset, - MemVT.getStoreSize(), Alignment); + MF.getMachineMemOperand(PtrInfo, Flags, MemVT.getStoreSize(), Alignment, + TBAAInfo); return getLoad(AM, ExtType, VT, dl, Chain, Ptr, Offset, MemVT, MMO); } SDValue -SelectionDAG::getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, +SelectionDAG::getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, EVT VT, DebugLoc dl, SDValue Chain, SDValue Ptr, SDValue Offset, EVT MemVT, MachineMemOperand *MMO) { @@ -3943,25 +4105,26 @@ SelectionDAG::getLoad(ISD::MemIndexedMode AM, ISD::LoadExtType ExtType, SDValue SelectionDAG::getLoad(EVT VT, DebugLoc dl, SDValue Chain, SDValue Ptr, - const Value *SV, int SVOffset, + MachinePointerInfo PtrInfo, bool isVolatile, bool isNonTemporal, - unsigned Alignment) { + unsigned Alignment, const MDNode *TBAAInfo) { SDValue Undef = getUNDEF(Ptr.getValueType()); return getLoad(ISD::UNINDEXED, ISD::NON_EXTLOAD, VT, dl, Chain, Ptr, Undef, - SV, SVOffset, VT, isVolatile, isNonTemporal, Alignment); + PtrInfo, VT, isVolatile, isNonTemporal, Alignment, TBAAInfo); } -SDValue SelectionDAG::getExtLoad(ISD::LoadExtType ExtType, EVT VT, DebugLoc dl, +SDValue SelectionDAG::getExtLoad(ISD::LoadExtType ExtType, DebugLoc dl, EVT VT, SDValue Chain, SDValue Ptr, - const Value *SV, - int SVOffset, EVT MemVT, + MachinePointerInfo PtrInfo, EVT MemVT, bool isVolatile, bool isNonTemporal, - unsigned Alignment) { + unsigned Alignment, const MDNode *TBAAInfo) { SDValue Undef = getUNDEF(Ptr.getValueType()); return getLoad(ISD::UNINDEXED, ExtType, VT, dl, Chain, Ptr, Undef, - SV, SVOffset, MemVT, isVolatile, isNonTemporal, Alignment); + PtrInfo, MemVT, isVolatile, isNonTemporal, Alignment, + TBAAInfo); } + SDValue SelectionDAG::getIndexedLoad(SDValue OrigLoad, DebugLoc dl, SDValue Base, SDValue Offset, ISD::MemIndexedMode AM) { @@ -3969,33 +4132,32 @@ SelectionDAG::getIndexedLoad(SDValue OrigLoad, DebugLoc dl, SDValue Base, assert(LD->getOffset().getOpcode() == ISD::UNDEF && "Load is already a indexed load!"); return getLoad(AM, LD->getExtensionType(), OrigLoad.getValueType(), dl, - LD->getChain(), Base, Offset, LD->getSrcValue(), - LD->getSrcValueOffset(), LD->getMemoryVT(), + LD->getChain(), Base, Offset, LD->getPointerInfo(), + LD->getMemoryVT(), LD->isVolatile(), LD->isNonTemporal(), LD->getAlignment()); } SDValue SelectionDAG::getStore(SDValue Chain, DebugLoc dl, SDValue Val, - SDValue Ptr, const Value *SV, int SVOffset, + SDValue Ptr, MachinePointerInfo PtrInfo, bool isVolatile, bool isNonTemporal, - unsigned Alignment) { + unsigned Alignment, const MDNode *TBAAInfo) { if (Alignment == 0) // Ensure that codegen never sees alignment 0 Alignment = getEVTAlignment(Val.getValueType()); - // Check if the memory reference references a frame index - if (!SV) - if (const FrameIndexSDNode *FI = - dyn_cast(Ptr.getNode())) - SV = PseudoSourceValue::getFixedStack(FI->getIndex()); - - MachineFunction &MF = getMachineFunction(); unsigned Flags = MachineMemOperand::MOStore; if (isVolatile) Flags |= MachineMemOperand::MOVolatile; if (isNonTemporal) Flags |= MachineMemOperand::MONonTemporal; + + if (PtrInfo.V == 0) + PtrInfo = InferPointerInfo(Ptr); + + MachineFunction &MF = getMachineFunction(); MachineMemOperand *MMO = - MF.getMachineMemOperand(SV, Flags, SVOffset, - Val.getValueType().getStoreSize(), Alignment); + MF.getMachineMemOperand(PtrInfo, Flags, + Val.getValueType().getStoreSize(), Alignment, + TBAAInfo); return getStore(Chain, dl, Val, Ptr, MMO); } @@ -4024,27 +4186,26 @@ SDValue SelectionDAG::getStore(SDValue Chain, DebugLoc dl, SDValue Val, } SDValue SelectionDAG::getTruncStore(SDValue Chain, DebugLoc dl, SDValue Val, - SDValue Ptr, const Value *SV, - int SVOffset, EVT SVT, - bool isVolatile, bool isNonTemporal, - unsigned Alignment) { + SDValue Ptr, MachinePointerInfo PtrInfo, + EVT SVT,bool isVolatile, bool isNonTemporal, + unsigned Alignment, + const MDNode *TBAAInfo) { if (Alignment == 0) // Ensure that codegen never sees alignment 0 Alignment = getEVTAlignment(SVT); - // Check if the memory reference references a frame index - if (!SV) - if (const FrameIndexSDNode *FI = - dyn_cast(Ptr.getNode())) - SV = PseudoSourceValue::getFixedStack(FI->getIndex()); - - MachineFunction &MF = getMachineFunction(); unsigned Flags = MachineMemOperand::MOStore; if (isVolatile) Flags |= MachineMemOperand::MOVolatile; if (isNonTemporal) Flags |= MachineMemOperand::MONonTemporal; + + if (PtrInfo.V == 0) + PtrInfo = InferPointerInfo(Ptr); + + MachineFunction &MF = getMachineFunction(); MachineMemOperand *MMO = - MF.getMachineMemOperand(SV, Flags, SVOffset, SVT.getStoreSize(), Alignment); + MF.getMachineMemOperand(PtrInfo, Flags, SVT.getStoreSize(), Alignment, + TBAAInfo); return getTruncStore(Chain, dl, Val, Ptr, SVT, MMO); } @@ -4170,7 +4331,7 @@ SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL, EVT VT, SDNode *N; SDVTList VTs = getVTList(VT); - if (VT != MVT::Flag) { + if (VT != MVT::Glue) { FoldingSetNodeID ID; AddNodeIDNode(ID, Opcode, VTs, Ops, NumOps); void *IP = 0; @@ -4186,7 +4347,7 @@ SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL, EVT VT, AllNodes.push_back(N); #ifndef NDEBUG - VerifyNode(N); + VerifySDNode(N); #endif return SDValue(N, 0); } @@ -4236,7 +4397,7 @@ SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL, SDVTList VTList, // Memoize the node unless it returns a flag. SDNode *N; - if (VTList.VTs[VTList.NumVTs-1] != MVT::Flag) { + if (VTList.VTs[VTList.NumVTs-1] != MVT::Glue) { FoldingSetNodeID ID; AddNodeIDNode(ID, Opcode, VTList, Ops, NumOps); void *IP = 0; @@ -4268,7 +4429,7 @@ SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL, SDVTList VTList, } AllNodes.push_back(N); #ifndef NDEBUG - VerifyNode(N); + VerifySDNode(N); #endif return SDValue(N, 0); } @@ -4645,7 +4806,7 @@ SDNode *SelectionDAG::MorphNodeTo(SDNode *N, unsigned Opc, unsigned NumOps) { // If an identical node already exists, use it. void *IP = 0; - if (VTs.VTs[VTs.NumVTs-1] != MVT::Flag) { + if (VTs.VTs[VTs.NumVTs-1] != MVT::Glue) { FoldingSetNodeID ID; AddNodeIDNode(ID, Opc, VTs, Ops, NumOps); if (SDNode *ON = CSEMap.FindNodeOrInsertPos(ID, IP)) @@ -4845,9 +5006,9 @@ SelectionDAG::getMachineNode(unsigned Opcode, DebugLoc dl, MachineSDNode * SelectionDAG::getMachineNode(unsigned Opcode, DebugLoc DL, SDVTList VTs, const SDValue *Ops, unsigned NumOps) { - bool DoCSE = VTs.VTs[VTs.NumVTs-1] != MVT::Flag; + bool DoCSE = VTs.VTs[VTs.NumVTs-1] != MVT::Glue; MachineSDNode *N; - void *IP; + void *IP = 0; if (DoCSE) { FoldingSetNodeID ID; @@ -4876,7 +5037,7 @@ SelectionDAG::getMachineNode(unsigned Opcode, DebugLoc DL, SDVTList VTs, AllNodes.push_back(N); #ifndef NDEBUG - VerifyNode(N); + VerifyMachineNode(N); #endif return N; } @@ -4907,7 +5068,7 @@ SelectionDAG::getTargetInsertSubreg(int SRIdx, DebugLoc DL, EVT VT, /// else return NULL. SDNode *SelectionDAG::getNodeIfExists(unsigned Opcode, SDVTList VTList, const SDValue *Ops, unsigned NumOps) { - if (VTList.VTs[VTList.NumVTs-1] != MVT::Flag) { + if (VTList.VTs[VTList.NumVTs-1] != MVT::Glue) { FoldingSetNodeID ID; AddNodeIDNode(ID, Opcode, VTList, Ops, NumOps); void *IP = 0; @@ -5340,6 +5501,29 @@ void SelectionDAG::AddDbgValue(SDDbgValue *DB, SDNode *SD, bool isParameter) { SD->setHasDebugValue(true); } +/// TransferDbgValues - Transfer SDDbgValues. +void SelectionDAG::TransferDbgValues(SDValue From, SDValue To) { + if (From == To || !From.getNode()->getHasDebugValue()) + return; + SDNode *FromNode = From.getNode(); + SDNode *ToNode = To.getNode(); + SmallVector &DVs = GetDbgValues(FromNode); + SmallVector ClonedDVs; + for (SmallVector::iterator I = DVs.begin(), E = DVs.end(); + I != E; ++I) { + SDDbgValue *Dbg = *I; + if (Dbg->getKind() == SDDbgValue::SDNODE) { + SDDbgValue *Clone = getDbgValue(Dbg->getMDPtr(), ToNode, To.getResNo(), + Dbg->getOffset(), Dbg->getDebugLoc(), + Dbg->getOrder()); + ClonedDVs.push_back(Clone); + } + } + for (SmallVector::iterator I = ClonedDVs.begin(), + E = ClonedDVs.end(); I != E; ++I) + AddDbgValue(*I, ToNode, false); +} + //===----------------------------------------------------------------------===// // SDNode Class //===----------------------------------------------------------------------===// @@ -5367,7 +5551,7 @@ MemSDNode::MemSDNode(unsigned Opc, DebugLoc dl, SDVTList VTs, EVT memvt, } MemSDNode::MemSDNode(unsigned Opc, DebugLoc dl, SDVTList VTs, - const SDValue *Ops, unsigned NumOps, EVT memvt, + const SDValue *Ops, unsigned NumOps, EVT memvt, MachineMemOperand *mmo) : SDNode(Opc, dl, VTs, Ops, NumOps), MemoryVT(memvt), MMO(mmo) { @@ -5386,7 +5570,7 @@ void SDNode::Profile(FoldingSetNodeID &ID) const { namespace { struct EVTArray { std::vector VTs; - + EVTArray() { VTs.reserve(MVT::LAST_VALUETYPE); for (unsigned i = 0; i < MVT::LAST_VALUETYPE; ++i) @@ -5406,7 +5590,7 @@ const EVT *SDNode::getValueTypeList(EVT VT) { sys::SmartScopedLock Lock(*VTMutex); return &(*EVTs->insert(VT).first); } else { - assert(VT.getSimpleVT().SimpleTy < MVT::LAST_VALUETYPE && + assert(VT.getSimpleVT() < MVT::LAST_VALUETYPE && "Value type out of range!"); return &SimpleVTArray->VTs[VT.getSimpleVT().SimpleTy]; } @@ -5478,9 +5662,9 @@ bool SDNode::isOperandOf(SDNode *N) const { /// reachesChainWithoutSideEffects - Return true if this operand (which must /// be a chain) reaches the specified operand without crossing any -/// side-effecting instructions. In practice, this looks through token -/// factors and non-volatile loads. In order to remain efficient, this only -/// looks a couple of nodes in, it does not do an exhaustive search. +/// side-effecting instructions on any chain path. In practice, this looks +/// through token factors and non-volatile loads. In order to remain efficient, +/// this only looks a couple of nodes in, it does not do an exhaustive search. bool SDValue::reachesChainWithoutSideEffects(SDValue Dest, unsigned Depth) const { if (*this == Dest) return true; @@ -5490,12 +5674,12 @@ bool SDValue::reachesChainWithoutSideEffects(SDValue Dest, if (Depth == 0) return false; // If this is a token factor, all inputs to the TF happen in parallel. If any - // of the operands of the TF reach dest, then we can do the xform. + // of the operands of the TF does not reach dest, then we cannot do the xform. if (getOpcode() == ISD::TokenFactor) { for (unsigned i = 0, e = getNumOperands(); i != e; ++i) - if (getOperand(i).reachesChainWithoutSideEffects(Dest, Depth-1)) - return true; - return false; + if (!getOperand(i).reachesChainWithoutSideEffects(Dest, Depth-1)) + return false; + return true; } // Loads don't have side effects, look through them. @@ -5600,6 +5784,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const { case ISD::EH_RETURN: return "EH_RETURN"; case ISD::EH_SJLJ_SETJMP: return "EH_SJLJ_SETJMP"; case ISD::EH_SJLJ_LONGJMP: return "EH_SJLJ_LONGJMP"; + case ISD::EH_SJLJ_DISPATCHSETUP: return "EH_SJLJ_DISPATCHSETUP"; case ISD::ConstantPool: return "ConstantPool"; case ISD::ExternalSymbol: return "ExternalSymbol"; case ISD::BlockAddress: return "BlockAddress"; @@ -5690,6 +5875,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const { case ISD::INSERT_VECTOR_ELT: return "insert_vector_elt"; case ISD::EXTRACT_VECTOR_ELT: return "extract_vector_elt"; case ISD::CONCAT_VECTORS: return "concat_vectors"; + case ISD::INSERT_SUBVECTOR: return "insert_subvector"; case ISD::EXTRACT_SUBVECTOR: return "extract_subvector"; case ISD::SCALAR_TO_VECTOR: return "scalar_to_vector"; case ISD::VECTOR_SHUFFLE: return "vector_shuffle"; @@ -5723,7 +5909,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const { case ISD::UINT_TO_FP: return "uint_to_fp"; case ISD::FP_TO_SINT: return "fp_to_sint"; case ISD::FP_TO_UINT: return "fp_to_uint"; - case ISD::BIT_CONVERT: return "bit_convert"; + case ISD::BITCAST: return "bit_convert"; case ISD::FP16_TO_FP32: return "fp16_to_fp32"; case ISD::FP32_TO_FP16: return "fp32_to_fp16"; @@ -5935,12 +6121,7 @@ void SDNode::print_details(raw_ostream &OS, const SelectionDAG *G) const { OS << LBB->getName() << " "; OS << (const void*)BBDN->getBasicBlock() << ">"; } else if (const RegisterSDNode *R = dyn_cast(this)) { - if (G && R->getReg() && - TargetRegisterInfo::isPhysicalRegister(R->getReg())) { - OS << " %" << G->getTarget().getRegisterInfo()->getName(R->getReg()); - } else { - OS << " %reg" << R->getReg(); - } + OS << ' ' << PrintReg(R->getReg(), G ? G->getTarget().getRegisterInfo() :0); } else if (const ExternalSymbolSDNode *ES = dyn_cast(this)) { OS << "'" << ES->getSymbol() << "'"; @@ -5986,7 +6167,7 @@ void SDNode::print_details(raw_ostream &OS, const SelectionDAG *G) const { const char *AM = getIndexedModeName(ST->getAddressingMode()); if (*AM) OS << ", " << AM; - + OS << ">"; } else if (const MemSDNode* M = dyn_cast(this)) { OS << "<" << *M->getMemOperand() << ">"; @@ -6037,7 +6218,7 @@ void SDNode::print(raw_ostream &OS, const SelectionDAG *G) const { static void printrWithDepthHelper(raw_ostream &OS, const SDNode *N, const SelectionDAG *G, unsigned depth, - unsigned indent) + unsigned indent) { if (depth == 0) return; @@ -6058,7 +6239,7 @@ static void printrWithDepthHelper(raw_ostream &OS, const SDNode *N, void SDNode::printrWithDepth(raw_ostream &OS, const SelectionDAG *G, unsigned depth) const { printrWithDepthHelper(OS, this, G, depth, 0); -} +} void SDNode::printrFull(raw_ostream &OS, const SelectionDAG *G) const { // Don't print impossibly deep things. @@ -6072,7 +6253,7 @@ void SDNode::dumprWithDepth(const SelectionDAG *G, unsigned depth) const { void SDNode::dumprFull(const SelectionDAG *G) const { // Don't print impossibly deep things. dumprWithDepth(G, 100); -} +} static void DumpNodes(const SDNode *N, unsigned indent, const SelectionDAG *G) { for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) @@ -6156,10 +6337,10 @@ SDValue SelectionDAG::UnrollVectorOp(SDNode *N, unsigned ResNE) { } -/// isConsecutiveLoad - Return true if LD is loading 'Bytes' bytes from a -/// location that is 'Dist' units away from the location that the 'Base' load +/// isConsecutiveLoad - Return true if LD is loading 'Bytes' bytes from a +/// location that is 'Dist' units away from the location that the 'Base' load /// is loading from. -bool SelectionDAG::isConsecutiveLoad(LoadSDNode *LD, LoadSDNode *Base, +bool SelectionDAG::isConsecutiveLoad(LoadSDNode *LD, LoadSDNode *Base, unsigned Bytes, int Dist) const { if (LD->getChain() != Base->getChain()) return false; @@ -6180,11 +6361,11 @@ bool SelectionDAG::isConsecutiveLoad(LoadSDNode *LD, LoadSDNode *Base, if (FS != BFS || FS != (int)Bytes) return false; return MFI->getObjectOffset(FI) == (MFI->getObjectOffset(BFI) + Dist*Bytes); } - if (Loc.getOpcode() == ISD::ADD && Loc.getOperand(0) == BaseLoc) { - ConstantSDNode *V = dyn_cast(Loc.getOperand(1)); - if (V && (V->getSExtValue() == Dist*Bytes)) - return true; - } + + // Handle X+C + if (isBaseWithConstantOffset(Loc) && Loc.getOperand(0) == BaseLoc && + cast(Loc.getOperand(1))->getSExtValue() == Dist*Bytes) + return true; const GlobalValue *GV1 = NULL; const GlobalValue *GV2 = NULL; @@ -6225,15 +6406,14 @@ unsigned SelectionDAG::InferPtrAlignment(SDValue Ptr) const { int64_t FrameOffset = 0; if (FrameIndexSDNode *FI = dyn_cast(Ptr)) { FrameIdx = FI->getIndex(); - } else if (Ptr.getOpcode() == ISD::ADD && - isa(Ptr.getOperand(1)) && + } else if (isBaseWithConstantOffset(Ptr) && isa(Ptr.getOperand(0))) { + // Handle FI+Cst FrameIdx = cast(Ptr.getOperand(0))->getIndex(); FrameOffset = Ptr.getConstantOperandVal(1); } if (FrameIdx != (1 << 31)) { - // FIXME: Handle FI+CST. const MachineFrameInfo &MFI = *getMachineFunction().getFrameInfo(); unsigned FIInfoAlign = MinAlign(MFI.getObjectAlignment(FrameIdx), FrameOffset); @@ -6354,7 +6534,7 @@ bool BuildVectorSDNode::isConstantSplat(APInt &SplatValue, if (OpVal.getOpcode() == ISD::UNDEF) SplatUndef |= APInt::getBitsSet(sz, BitPos, BitPos + EltBitSize); else if (ConstantSDNode *CN = dyn_cast(OpVal)) - SplatValue |= APInt(CN->getAPIntValue()).zextOrTrunc(EltBitSize). + SplatValue |= CN->getAPIntValue().zextOrTrunc(EltBitSize). zextOrTrunc(sz) << BitPos; else if (ConstantFPSDNode *CN = dyn_cast(OpVal)) SplatValue |= CN->getValueAPF().bitcastToAPInt().zextOrTrunc(sz) < 8) { unsigned HalfSize = sz / 2; - APInt HighValue = APInt(SplatValue).lshr(HalfSize).trunc(HalfSize); - APInt LowValue = APInt(SplatValue).trunc(HalfSize); - APInt HighUndef = APInt(SplatUndef).lshr(HalfSize).trunc(HalfSize); - APInt LowUndef = APInt(SplatUndef).trunc(HalfSize); + APInt HighValue = SplatValue.lshr(HalfSize).trunc(HalfSize); + APInt LowValue = SplatValue.trunc(HalfSize); + APInt HighUndef = SplatUndef.lshr(HalfSize).trunc(HalfSize); + APInt LowUndef = SplatUndef.trunc(HalfSize); // If the two halves do not match (ignoring undef bits), stop here. if ((HighValue & ~LowUndef) != (LowValue & ~HighUndef) || @@ -6412,7 +6592,7 @@ static void checkForCyclesHelper(const SDNode *N, // If this node has already been checked, don't check it again. if (Checked.count(N)) return; - + // If a node has already been visited on this depth-first walk, reject it as // a cycle. if (!Visited.insert(N)) { @@ -6421,10 +6601,10 @@ static void checkForCyclesHelper(const SDNode *N, errs() << "Detected cycle in SelectionDAG\n"; abort(); } - + for(unsigned i = 0, e = N->getNumOperands(); i != e; ++i) checkForCyclesHelper(N->getOperand(i).getNode(), Visited, Checked); - + Checked.insert(N); Visited.erase(N); } diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index e65744592c8b..452f5614b7bf 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -15,6 +15,7 @@ #include "SDNodeDbgValue.h" #include "SelectionDAGBuilder.h" #include "llvm/ADT/BitVector.h" +#include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/SmallSet.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/ConstantFolding.h" @@ -43,9 +44,8 @@ #include "llvm/CodeGen/PseudoSourceValue.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/Analysis/DebugInfo.h" -#include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Target/TargetData.h" -#include "llvm/Target/TargetFrameInfo.h" +#include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetIntrinsicInfo.h" #include "llvm/Target/TargetLowering.h" @@ -70,10 +70,28 @@ LimitFPPrecision("limit-float-precision", cl::location(LimitFloatPrecision), cl::init(0)); +// Limit the width of DAG chains. This is important in general to prevent +// prevent DAG-based analysis from blowing up. For example, alias analysis and +// load clustering may not complete in reasonable time. It is difficult to +// recognize and avoid this situation within each individual analysis, and +// future analyses are likely to have the same behavior. Limiting DAG width is +// the safe approach, and will be especially important with global DAGs. +// +// MaxParallelChains default is arbitrarily high to avoid affecting +// optimization, but could be lowered to improve compile time. Any ld-ld-st-st +// sequence over this should have been converted to llvm.memcpy by the +// frontend. It easy to induce this behavior with .ll code such as: +// %buffer = alloca [4096 x i8] +// %data = load [4096 x i8]* %argPtr +// store [4096 x i8] %data, [4096 x i8]* %buffer +static cl::opt +MaxParallelChains("dag-chain-limit", cl::desc("Max parallel isel dag chains"), + cl::init(64), cl::Hidden); + static SDValue getCopyFromPartsVector(SelectionDAG &DAG, DebugLoc DL, const SDValue *Parts, unsigned NumParts, EVT PartVT, EVT ValueVT); - + /// getCopyFromParts - Create a value that contains the specified legal parts /// combined into the value they represent. If the parts combine to a type /// larger then ValueVT then AssertOp can be used to specify whether the extra @@ -85,7 +103,7 @@ static SDValue getCopyFromParts(SelectionDAG &DAG, DebugLoc DL, ISD::NodeType AssertOp = ISD::DELETED_NODE) { if (ValueVT.isVector()) return getCopyFromPartsVector(DAG, DL, Parts, NumParts, PartVT, ValueVT); - + assert(NumParts > 0 && "No parts to assemble!"); const TargetLowering &TLI = DAG.getTargetLoweringInfo(); SDValue Val = Parts[0]; @@ -112,8 +130,8 @@ static SDValue getCopyFromParts(SelectionDAG &DAG, DebugLoc DL, Hi = getCopyFromParts(DAG, DL, Parts + RoundParts / 2, RoundParts / 2, PartVT, HalfVT); } else { - Lo = DAG.getNode(ISD::BIT_CONVERT, DL, HalfVT, Parts[0]); - Hi = DAG.getNode(ISD::BIT_CONVERT, DL, HalfVT, Parts[1]); + Lo = DAG.getNode(ISD::BITCAST, DL, HalfVT, Parts[0]); + Hi = DAG.getNode(ISD::BITCAST, DL, HalfVT, Parts[1]); } if (TLI.isBigEndian()) @@ -145,8 +163,8 @@ static SDValue getCopyFromParts(SelectionDAG &DAG, DebugLoc DL, assert(ValueVT == EVT(MVT::ppcf128) && PartVT == EVT(MVT::f64) && "Unexpected split"); SDValue Lo, Hi; - Lo = DAG.getNode(ISD::BIT_CONVERT, DL, EVT(MVT::f64), Parts[0]); - Hi = DAG.getNode(ISD::BIT_CONVERT, DL, EVT(MVT::f64), Parts[1]); + Lo = DAG.getNode(ISD::BITCAST, DL, EVT(MVT::f64), Parts[0]); + Hi = DAG.getNode(ISD::BITCAST, DL, EVT(MVT::f64), Parts[1]); if (TLI.isBigEndian()) std::swap(Lo, Hi); Val = DAG.getNode(ISD::BUILD_PAIR, DL, ValueVT, Lo, Hi); @@ -188,7 +206,7 @@ static SDValue getCopyFromParts(SelectionDAG &DAG, DebugLoc DL, } if (PartVT.getSizeInBits() == ValueVT.getSizeInBits()) - return DAG.getNode(ISD::BIT_CONVERT, DL, ValueVT, Val); + return DAG.getNode(ISD::BITCAST, DL, ValueVT, Val); llvm_unreachable("Unknown mismatch!"); return SDValue(); @@ -206,7 +224,7 @@ static SDValue getCopyFromPartsVector(SelectionDAG &DAG, DebugLoc DL, assert(NumParts > 0 && "No parts to assemble!"); const TargetLowering &TLI = DAG.getTargetLoweringInfo(); SDValue Val = Parts[0]; - + // Handle a multi-element vector. if (NumParts > 1) { EVT IntermediateVT, RegisterVT; @@ -219,7 +237,7 @@ static SDValue getCopyFromPartsVector(SelectionDAG &DAG, DebugLoc DL, assert(RegisterVT == PartVT && "Part type doesn't match vector breakdown!"); assert(RegisterVT == Parts[0].getValueType() && "Part type doesn't match part!"); - + // Assemble the parts into intermediate operands. SmallVector Ops(NumIntermediates); if (NumIntermediates == NumParts) { @@ -238,20 +256,20 @@ static SDValue getCopyFromPartsVector(SelectionDAG &DAG, DebugLoc DL, Ops[i] = getCopyFromParts(DAG, DL, &Parts[i * Factor], Factor, PartVT, IntermediateVT); } - + // Build a vector with BUILD_VECTOR or CONCAT_VECTORS from the // intermediate operands. Val = DAG.getNode(IntermediateVT.isVector() ? ISD::CONCAT_VECTORS : ISD::BUILD_VECTOR, DL, ValueVT, &Ops[0], NumIntermediates); } - + // There is now one part, held in Val. Correct it to match ValueVT. PartVT = Val.getValueType(); - + if (PartVT == ValueVT) return Val; - + if (PartVT.isVector()) { // If the element type of the source/dest vectors are the same, but the // parts vector has more elements than the value vector, then we have a @@ -262,12 +280,12 @@ static SDValue getCopyFromPartsVector(SelectionDAG &DAG, DebugLoc DL, "Cannot narrow, it would be a lossy transformation"); return DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, ValueVT, Val, DAG.getIntPtrConstant(0)); - } - + } + // Vector/Vector bitcast. - return DAG.getNode(ISD::BIT_CONVERT, DL, ValueVT, Val); + return DAG.getNode(ISD::BITCAST, DL, ValueVT, Val); } - + assert(ValueVT.getVectorElementType() == PartVT && ValueVT.getVectorNumElements() == 1 && "Only trivial scalar-to-vector conversions should get here!"); @@ -280,7 +298,7 @@ static SDValue getCopyFromPartsVector(SelectionDAG &DAG, DebugLoc DL, static void getCopyToPartsVector(SelectionDAG &DAG, DebugLoc dl, SDValue Val, SDValue *Parts, unsigned NumParts, EVT PartVT); - + /// getCopyToParts - Create a series of nodes that contain the specified value /// split into legal parts. If the parts contain more bits than Val, then, for /// integers, ExtendKind can be used to specify how to generate the extra bits. @@ -289,11 +307,11 @@ static void getCopyToParts(SelectionDAG &DAG, DebugLoc DL, EVT PartVT, ISD::NodeType ExtendKind = ISD::ANY_EXTEND) { EVT ValueVT = Val.getValueType(); - + // Handle the vector case separately. if (ValueVT.isVector()) return getCopyToPartsVector(DAG, DL, Val, Parts, NumParts, PartVT); - + const TargetLowering &TLI = DAG.getTargetLoweringInfo(); unsigned PartBits = PartVT.getSizeInBits(); unsigned OrigNumParts = NumParts; @@ -316,14 +334,14 @@ static void getCopyToParts(SelectionDAG &DAG, DebugLoc DL, Val = DAG.getNode(ISD::FP_EXTEND, DL, PartVT, Val); } else { assert(PartVT.isInteger() && ValueVT.isInteger() && - "Unknown mismatch!"); + "Unknown mismatch!"); ValueVT = EVT::getIntegerVT(*DAG.getContext(), NumParts * PartBits); Val = DAG.getNode(ExtendKind, DL, ValueVT, Val); } } else if (PartBits == ValueVT.getSizeInBits()) { // Different types of the same size. assert(NumParts == 1 && PartVT != ValueVT); - Val = DAG.getNode(ISD::BIT_CONVERT, DL, PartVT, Val); + Val = DAG.getNode(ISD::BITCAST, DL, PartVT, Val); } else if (NumParts * PartBits < ValueVT.getSizeInBits()) { // If the parts cover less bits than value has, truncate the value. assert(PartVT.isInteger() && ValueVT.isInteger() && @@ -366,7 +384,7 @@ static void getCopyToParts(SelectionDAG &DAG, DebugLoc DL, // The number of parts is a power of 2. Repeatedly bisect the value using // EXTRACT_ELEMENT. - Parts[0] = DAG.getNode(ISD::BIT_CONVERT, DL, + Parts[0] = DAG.getNode(ISD::BITCAST, DL, EVT::getIntegerVT(*DAG.getContext(), ValueVT.getSizeInBits()), Val); @@ -384,8 +402,8 @@ static void getCopyToParts(SelectionDAG &DAG, DebugLoc DL, ThisVT, Part0, DAG.getIntPtrConstant(0)); if (ThisBits == PartBits && ThisVT != PartVT) { - Part0 = DAG.getNode(ISD::BIT_CONVERT, DL, PartVT, Part0); - Part1 = DAG.getNode(ISD::BIT_CONVERT, DL, PartVT, Part1); + Part0 = DAG.getNode(ISD::BITCAST, DL, PartVT, Part0); + Part1 = DAG.getNode(ISD::BITCAST, DL, PartVT, Part1); } } } @@ -403,13 +421,13 @@ static void getCopyToPartsVector(SelectionDAG &DAG, DebugLoc DL, EVT ValueVT = Val.getValueType(); assert(ValueVT.isVector() && "Not a vector"); const TargetLowering &TLI = DAG.getTargetLoweringInfo(); - + if (NumParts == 1) { if (PartVT == ValueVT) { // Nothing to do. } else if (PartVT.getSizeInBits() == ValueVT.getSizeInBits()) { // Bitconvert vector->vector case. - Val = DAG.getNode(ISD::BIT_CONVERT, DL, PartVT, Val); + Val = DAG.getNode(ISD::BITCAST, DL, PartVT, Val); } else if (PartVT.isVector() && PartVT.getVectorElementType() == ValueVT.getVectorElementType()&& PartVT.getVectorNumElements() > ValueVT.getVectorNumElements()) { @@ -420,7 +438,7 @@ static void getCopyToPartsVector(SelectionDAG &DAG, DebugLoc DL, for (unsigned i = 0, e = ValueVT.getVectorNumElements(); i != e; ++i) Ops.push_back(DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, ElementVT, Val, DAG.getIntPtrConstant(i))); - + for (unsigned i = ValueVT.getVectorNumElements(), e = PartVT.getVectorNumElements(); i != e; ++i) Ops.push_back(DAG.getUNDEF(ElementVT)); @@ -428,7 +446,7 @@ static void getCopyToPartsVector(SelectionDAG &DAG, DebugLoc DL, Val = DAG.getNode(ISD::BUILD_VECTOR, DL, PartVT, &Ops[0], Ops.size()); // FIXME: Use CONCAT for 2x -> 4x. - + //SDValue UndefElts = DAG.getUNDEF(VectorTy); //Val = DAG.getNode(ISD::CONCAT_VECTORS, DL, PartVT, Val, UndefElts); } else { @@ -439,11 +457,11 @@ static void getCopyToPartsVector(SelectionDAG &DAG, DebugLoc DL, Val = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, PartVT, Val, DAG.getIntPtrConstant(0)); } - + Parts[0] = Val; return; } - + // Handle a multi-element vector. EVT IntermediateVT, RegisterVT; unsigned NumIntermediates; @@ -451,11 +469,11 @@ static void getCopyToPartsVector(SelectionDAG &DAG, DebugLoc DL, IntermediateVT, NumIntermediates, RegisterVT); unsigned NumElements = ValueVT.getVectorNumElements(); - + assert(NumRegs == NumParts && "Part count doesn't match vector breakdown!"); NumParts = NumRegs; // Silence a compiler warning. assert(RegisterVT == PartVT && "Part type doesn't match vector breakdown!"); - + // Split the vector into intermediate operands. SmallVector Ops(NumIntermediates); for (unsigned i = 0; i != NumIntermediates; ++i) { @@ -467,7 +485,7 @@ static void getCopyToPartsVector(SelectionDAG &DAG, DebugLoc DL, Ops[i] = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, IntermediateVT, Val, DAG.getIntPtrConstant(i)); } - + // Split the intermediate operands into legal parts. if (NumParts == NumIntermediates) { // If the register was not expanded, promote or copy the value, @@ -618,48 +636,49 @@ SDValue RegsForValue::getCopyFromRegs(SelectionDAG &DAG, } Chain = P.getValue(1); + Parts[i] = P; // If the source register was virtual and if we know something about it, // add an assert node. - if (TargetRegisterInfo::isVirtualRegister(Regs[Part+i]) && - RegisterVT.isInteger() && !RegisterVT.isVector()) { - unsigned SlotNo = Regs[Part+i]-TargetRegisterInfo::FirstVirtualRegister; - if (FuncInfo.LiveOutRegInfo.size() > SlotNo) { - const FunctionLoweringInfo::LiveOutInfo &LOI = - FuncInfo.LiveOutRegInfo[SlotNo]; - - unsigned RegSize = RegisterVT.getSizeInBits(); - unsigned NumSignBits = LOI.NumSignBits; - unsigned NumZeroBits = LOI.KnownZero.countLeadingOnes(); - - // FIXME: We capture more information than the dag can represent. For - // now, just use the tightest assertzext/assertsext possible. - bool isSExt = true; - EVT FromVT(MVT::Other); - if (NumSignBits == RegSize) - isSExt = true, FromVT = MVT::i1; // ASSERT SEXT 1 - else if (NumZeroBits >= RegSize-1) - isSExt = false, FromVT = MVT::i1; // ASSERT ZEXT 1 - else if (NumSignBits > RegSize-8) - isSExt = true, FromVT = MVT::i8; // ASSERT SEXT 8 - else if (NumZeroBits >= RegSize-8) - isSExt = false, FromVT = MVT::i8; // ASSERT ZEXT 8 - else if (NumSignBits > RegSize-16) - isSExt = true, FromVT = MVT::i16; // ASSERT SEXT 16 - else if (NumZeroBits >= RegSize-16) - isSExt = false, FromVT = MVT::i16; // ASSERT ZEXT 16 - else if (NumSignBits > RegSize-32) - isSExt = true, FromVT = MVT::i32; // ASSERT SEXT 32 - else if (NumZeroBits >= RegSize-32) - isSExt = false, FromVT = MVT::i32; // ASSERT ZEXT 32 - - if (FromVT != MVT::Other) - P = DAG.getNode(isSExt ? ISD::AssertSext : ISD::AssertZext, dl, - RegisterVT, P, DAG.getValueType(FromVT)); - } - } + if (!TargetRegisterInfo::isVirtualRegister(Regs[Part+i]) || + !RegisterVT.isInteger() || RegisterVT.isVector() || + !FuncInfo.LiveOutRegInfo.inBounds(Regs[Part+i])) + continue; + + const FunctionLoweringInfo::LiveOutInfo &LOI = + FuncInfo.LiveOutRegInfo[Regs[Part+i]]; + + unsigned RegSize = RegisterVT.getSizeInBits(); + unsigned NumSignBits = LOI.NumSignBits; + unsigned NumZeroBits = LOI.KnownZero.countLeadingOnes(); + + // FIXME: We capture more information than the dag can represent. For + // now, just use the tightest assertzext/assertsext possible. + bool isSExt = true; + EVT FromVT(MVT::Other); + if (NumSignBits == RegSize) + isSExt = true, FromVT = MVT::i1; // ASSERT SEXT 1 + else if (NumZeroBits >= RegSize-1) + isSExt = false, FromVT = MVT::i1; // ASSERT ZEXT 1 + else if (NumSignBits > RegSize-8) + isSExt = true, FromVT = MVT::i8; // ASSERT SEXT 8 + else if (NumZeroBits >= RegSize-8) + isSExt = false, FromVT = MVT::i8; // ASSERT ZEXT 8 + else if (NumSignBits > RegSize-16) + isSExt = true, FromVT = MVT::i16; // ASSERT SEXT 16 + else if (NumZeroBits >= RegSize-16) + isSExt = false, FromVT = MVT::i16; // ASSERT ZEXT 16 + else if (NumSignBits > RegSize-32) + isSExt = true, FromVT = MVT::i32; // ASSERT SEXT 32 + else if (NumZeroBits >= RegSize-32) + isSExt = false, FromVT = MVT::i32; // ASSERT ZEXT 32 + else + continue; - Parts[i] = P; + // Add an assertion node. + assert(FromVT != MVT::Other); + Parts[i] = DAG.getNode(isSExt ? ISD::AssertSext : ISD::AssertZext, dl, + RegisterVT, P, DAG.getValueType(FromVT)); } Values[Value] = getCopyFromParts(DAG, dl, Parts.begin(), @@ -889,11 +908,8 @@ void SelectionDAGBuilder::resolveDanglingDebugInfo(const Value *V, Val.getResNo(), Offset, dl, DbgSDNodeOrder); DAG.AddDbgValue(SDV, Val.getNode(), false); } - } else { - SDV = DAG.getDbgValue(Variable, UndefValue::get(V->getType()), - Offset, dl, SDNodeOrder); - DAG.AddDbgValue(SDV, 0, false); - } + } else + DEBUG(dbgs() << "Dropping debug info for " << DI); DanglingDebugInfoMap[V] = DanglingDebugInfo(); } } @@ -913,7 +929,9 @@ SDValue SelectionDAGBuilder::getValue(const Value *V) { unsigned InReg = It->second; RegsForValue RFV(*DAG.getContext(), TLI, InReg, V->getType()); SDValue Chain = DAG.getEntryNode(); - return N = RFV.getCopyFromRegs(DAG, FuncInfo, getCurDebugLoc(), Chain,NULL); + N = RFV.getCopyFromRegs(DAG, FuncInfo, getCurDebugLoc(), Chain,NULL); + resolveDanglingDebugInfo(V, N); + return N; } // Otherwise create a new SDValue and remember it. @@ -1088,7 +1106,8 @@ void SelectionDAGBuilder::visitRet(const ReturnInst &I) { Chains[i] = DAG.getStore(Chain, getCurDebugLoc(), SDValue(RetOp.getNode(), RetOp.getResNo() + i), - Add, NULL, Offsets[i], false, false, 0); + // FIXME: better loc info would be nice. + Add, MachinePointerInfo(), false, false, 0); } Chain = DAG.getNode(ISD::TokenFactor, getCurDebugLoc(), @@ -1347,7 +1366,7 @@ SelectionDAGBuilder::ShouldEmitAsBranches(const std::vector &Cases){ if (Cases[0].CC == ISD::SETNE && Cases[0].FalseBB == Cases[1].ThisBB) return false; } - + return true; } @@ -1383,6 +1402,7 @@ void SelectionDAGBuilder::visitBr(const BranchInst &I) { // If this is a series of conditions that are or'd or and'd together, emit // this as a sequence of branches instead of setcc's with and/or operations. + // As long as jumps are not expensive, this should improve performance. // For example, instead of something like: // cmp A, B // C = seteq @@ -1397,7 +1417,8 @@ void SelectionDAGBuilder::visitBr(const BranchInst &I) { // jle foo // if (const BinaryOperator *BOp = dyn_cast(CondVal)) { - if (BOp->hasOneUse() && + if (!TLI.isJumpExpensive() && + BOp->hasOneUse() && (BOp->getOpcode() == Instruction::And || BOp->getOpcode() == Instruction::Or)) { FindMergedConditions(BOp, Succ0MBB, Succ1MBB, BrMBB, BrMBB, @@ -1502,10 +1523,11 @@ void SelectionDAGBuilder::visitSwitchCase(CaseBlock &CB, MVT::Other, getControlRoot(), Cond, DAG.getBasicBlock(CB.TrueBB)); - // Insert the false branch. - if (CB.FalseBB != NextBlock) - BrCond = DAG.getNode(ISD::BR, dl, MVT::Other, BrCond, - DAG.getBasicBlock(CB.FalseBB)); + // Insert the false branch. Do this even if it's a fall through branch, + // this makes it easier to do DAG optimizations which require inverting + // the branch condition. + BrCond = DAG.getNode(ISD::BR, dl, MVT::Other, BrCond, + DAG.getBasicBlock(CB.FalseBB)); DAG.setRoot(BrCond); } @@ -1592,12 +1614,28 @@ void SelectionDAGBuilder::visitBitTestHeader(BitTestBlock &B, Sub, DAG.getConstant(B.Range, VT), ISD::SETUGT); - SDValue ShiftOp = DAG.getZExtOrTrunc(Sub, getCurDebugLoc(), - TLI.getPointerTy()); + // Determine the type of the test operands. + bool UsePtrType = false; + if (!TLI.isTypeLegal(VT)) + UsePtrType = true; + else { + for (unsigned i = 0, e = B.Cases.size(); i != e; ++i) + if ((uint64_t)((int64_t)B.Cases[i].Mask >> VT.getSizeInBits()) + 1 >= 2) { + // Switch table case range are encoded into series of masks. + // Just use pointer type, it's guaranteed to fit. + UsePtrType = true; + break; + } + } + if (UsePtrType) { + VT = TLI.getPointerTy(); + Sub = DAG.getZExtOrTrunc(Sub, getCurDebugLoc(), VT); + } - B.Reg = FuncInfo.CreateReg(TLI.getPointerTy()); + B.RegVT = VT; + B.Reg = FuncInfo.CreateReg(VT); SDValue CopyTo = DAG.getCopyToReg(getControlRoot(), getCurDebugLoc(), - B.Reg, ShiftOp); + B.Reg, Sub); // Set NextBlock to be the MBB immediately after the current one, if any. // This is used to avoid emitting unnecessary branches to the next block. @@ -1623,36 +1661,34 @@ void SelectionDAGBuilder::visitBitTestHeader(BitTestBlock &B, } /// visitBitTestCase - this function produces one "bit test" -void SelectionDAGBuilder::visitBitTestCase(MachineBasicBlock* NextMBB, +void SelectionDAGBuilder::visitBitTestCase(BitTestBlock &BB, + MachineBasicBlock* NextMBB, unsigned Reg, BitTestCase &B, MachineBasicBlock *SwitchBB) { - SDValue ShiftOp = DAG.getCopyFromReg(getControlRoot(), getCurDebugLoc(), Reg, - TLI.getPointerTy()); + EVT VT = BB.RegVT; + SDValue ShiftOp = DAG.getCopyFromReg(getControlRoot(), getCurDebugLoc(), + Reg, VT); SDValue Cmp; if (CountPopulation_64(B.Mask) == 1) { // Testing for a single bit; just compare the shift count with what it // would need to be to shift a 1 bit in that position. Cmp = DAG.getSetCC(getCurDebugLoc(), - TLI.getSetCCResultType(ShiftOp.getValueType()), + TLI.getSetCCResultType(VT), ShiftOp, - DAG.getConstant(CountTrailingZeros_64(B.Mask), - TLI.getPointerTy()), + DAG.getConstant(CountTrailingZeros_64(B.Mask), VT), ISD::SETEQ); } else { // Make desired shift - SDValue SwitchVal = DAG.getNode(ISD::SHL, getCurDebugLoc(), - TLI.getPointerTy(), - DAG.getConstant(1, TLI.getPointerTy()), - ShiftOp); + SDValue SwitchVal = DAG.getNode(ISD::SHL, getCurDebugLoc(), VT, + DAG.getConstant(1, VT), ShiftOp); // Emit bit tests and jumps SDValue AndOp = DAG.getNode(ISD::AND, getCurDebugLoc(), - TLI.getPointerTy(), SwitchVal, - DAG.getConstant(B.Mask, TLI.getPointerTy())); + VT, SwitchVal, DAG.getConstant(B.Mask, VT)); Cmp = DAG.getSetCC(getCurDebugLoc(), - TLI.getSetCCResultType(AndOp.getValueType()), - AndOp, DAG.getConstant(0, TLI.getPointerTy()), + TLI.getSetCCResultType(VT), + AndOp, DAG.getConstant(0, VT), ISD::SETNE); } @@ -1732,10 +1768,56 @@ bool SelectionDAGBuilder::handleSmallSwitchRange(CaseRec& CR, if (++BBI != FuncInfo.MF->end()) NextBlock = BBI; - // TODO: If any two of the cases has the same destination, and if one value + // If any two of the cases has the same destination, and if one value // is the same as the other, but has one bit unset that the other has set, // use bit manipulation to do two compares at once. For example: // "if (X == 6 || X == 4)" -> "if ((X|2) == 6)" + // TODO: This could be extended to merge any 2 cases in switches with 3 cases. + // TODO: Handle cases where CR.CaseBB != SwitchBB. + if (Size == 2 && CR.CaseBB == SwitchBB) { + Case &Small = *CR.Range.first; + Case &Big = *(CR.Range.second-1); + + if (Small.Low == Small.High && Big.Low == Big.High && Small.BB == Big.BB) { + const APInt& SmallValue = cast(Small.Low)->getValue(); + const APInt& BigValue = cast(Big.Low)->getValue(); + + // Check that there is only one bit different. + if (BigValue.countPopulation() == SmallValue.countPopulation() + 1 && + (SmallValue | BigValue) == BigValue) { + // Isolate the common bit. + APInt CommonBit = BigValue & ~SmallValue; + assert((SmallValue | CommonBit) == BigValue && + CommonBit.countPopulation() == 1 && "Not a common bit?"); + + SDValue CondLHS = getValue(SV); + EVT VT = CondLHS.getValueType(); + DebugLoc DL = getCurDebugLoc(); + + SDValue Or = DAG.getNode(ISD::OR, DL, VT, CondLHS, + DAG.getConstant(CommonBit, VT)); + SDValue Cond = DAG.getSetCC(DL, MVT::i1, + Or, DAG.getConstant(BigValue, VT), + ISD::SETEQ); + + // Update successor info. + SwitchBB->addSuccessor(Small.BB); + SwitchBB->addSuccessor(Default); + + // Insert the true branch. + SDValue BrCond = DAG.getNode(ISD::BRCOND, DL, MVT::Other, + getControlRoot(), Cond, + DAG.getBasicBlock(Small.BB)); + + // Insert the false branch. + BrCond = DAG.getNode(ISD::BR, DL, MVT::Other, BrCond, + DAG.getBasicBlock(Default)); + + DAG.setRoot(BrCond); + return true; + } + } + } // Rearrange the case blocks so that the last one falls through if possible. if (NextBlock && Default != NextBlock && BackCase.BB != NextBlock) { @@ -1800,9 +1882,8 @@ static inline bool areJTsAllowed(const TargetLowering &TLI) { } static APInt ComputeRange(const APInt &First, const APInt &Last) { - APInt LastExt(Last), FirstExt(First); uint32_t BitWidth = std::max(Last.getBitWidth(), First.getBitWidth()) + 1; - LastExt.sext(BitWidth); FirstExt.sext(BitWidth); + APInt LastExt = Last.sext(BitWidth), FirstExt = First.sext(BitWidth); return (LastExt - FirstExt + 1ULL); } @@ -2151,7 +2232,7 @@ bool SelectionDAGBuilder::handleBitTestsSwitchCase(CaseRec& CR, } BitTestBlock BTB(lowBound, cmpRange, SV, - -1U, (CR.CaseBB == SwitchBB), + -1U, MVT::Other, (CR.CaseBB == SwitchBB), CR.CaseBB, Default, BTC); if (CR.CaseBB == SwitchBB) @@ -2180,7 +2261,8 @@ size_t SelectionDAGBuilder::Clusterify(CaseVector& Cases, if (Cases.size() >= 2) // Must recompute end() each iteration because it may be // invalidated by erase if we hold on to it - for (CaseItr I = Cases.begin(), J = ++(Cases.begin()); J != Cases.end(); ) { + for (CaseItr I = Cases.begin(), J = llvm::next(Cases.begin()); + J != Cases.end(); ) { const APInt& nextValue = cast(J->Low)->getValue(); const APInt& currentValue = cast(I->High)->getValue(); MachineBasicBlock* nextBB = J->BB; @@ -2205,6 +2287,19 @@ size_t SelectionDAGBuilder::Clusterify(CaseVector& Cases, return numCmps; } +void SelectionDAGBuilder::UpdateSplitBlock(MachineBasicBlock *First, + MachineBasicBlock *Last) { + // Update JTCases. + for (unsigned i = 0, e = JTCases.size(); i != e; ++i) + if (JTCases[i].first.HeaderBB == First) + JTCases[i].first.HeaderBB = Last; + + // Update BitTestCases. + for (unsigned i = 0, e = BitTestCases.size(); i != e; ++i) + if (BitTestCases[i].Parent == First) + BitTestCases[i].Parent = Last; +} + void SelectionDAGBuilder::visitSwitch(const SwitchInst &SI) { MachineBasicBlock *SwitchMBB = FuncInfo.MBB; @@ -2292,30 +2387,14 @@ void SelectionDAGBuilder::visitIndirectBr(const IndirectBrInst &I) { void SelectionDAGBuilder::visitFSub(const User &I) { // -0.0 - X --> fneg const Type *Ty = I.getType(); - if (Ty->isVectorTy()) { - if (ConstantVector *CV = dyn_cast(I.getOperand(0))) { - const VectorType *DestTy = cast(I.getType()); - const Type *ElTy = DestTy->getElementType(); - unsigned VL = DestTy->getNumElements(); - std::vector NZ(VL, ConstantFP::getNegativeZero(ElTy)); - Constant *CNZ = ConstantVector::get(&NZ[0], NZ.size()); - if (CV == CNZ) { - SDValue Op2 = getValue(I.getOperand(1)); - setValue(&I, DAG.getNode(ISD::FNEG, getCurDebugLoc(), - Op2.getValueType(), Op2)); - return; - } - } + if (isa(I.getOperand(0)) && + I.getOperand(0) == ConstantFP::getZeroValueForNegation(Ty)) { + SDValue Op2 = getValue(I.getOperand(1)); + setValue(&I, DAG.getNode(ISD::FNEG, getCurDebugLoc(), + Op2.getValueType(), Op2)); + return; } - if (ConstantFP *CFP = dyn_cast(I.getOperand(0))) - if (CFP->isExactlyValue(ConstantFP::getNegativeZero(Ty)->getValueAPF())) { - SDValue Op2 = getValue(I.getOperand(1)); - setValue(&I, DAG.getNode(ISD::FNEG, getCurDebugLoc(), - Op2.getValueType(), Op2)); - return; - } - visitBinary(I, ISD::FSUB); } @@ -2329,31 +2408,29 @@ void SelectionDAGBuilder::visitBinary(const User &I, unsigned OpCode) { void SelectionDAGBuilder::visitShift(const User &I, unsigned Opcode) { SDValue Op1 = getValue(I.getOperand(0)); SDValue Op2 = getValue(I.getOperand(1)); - if (!I.getType()->isVectorTy() && - Op2.getValueType() != TLI.getShiftAmountTy()) { + + MVT ShiftTy = TLI.getShiftAmountTy(); + + // Coerce the shift amount to the right type if we can. + if (!I.getType()->isVectorTy() && Op2.getValueType() != ShiftTy) { + unsigned ShiftSize = ShiftTy.getSizeInBits(); + unsigned Op2Size = Op2.getValueType().getSizeInBits(); + DebugLoc DL = getCurDebugLoc(); + // If the operand is smaller than the shift count type, promote it. - EVT PTy = TLI.getPointerTy(); - EVT STy = TLI.getShiftAmountTy(); - if (STy.bitsGT(Op2.getValueType())) - Op2 = DAG.getNode(ISD::ANY_EXTEND, getCurDebugLoc(), - TLI.getShiftAmountTy(), Op2); + if (ShiftSize > Op2Size) + Op2 = DAG.getNode(ISD::ZERO_EXTEND, DL, ShiftTy, Op2); + // If the operand is larger than the shift count type but the shift // count type has enough bits to represent any shift value, truncate // it now. This is a common case and it exposes the truncate to // optimization early. - else if (STy.getSizeInBits() >= - Log2_32_Ceil(Op2.getValueType().getSizeInBits())) - Op2 = DAG.getNode(ISD::TRUNCATE, getCurDebugLoc(), - TLI.getShiftAmountTy(), Op2); - // Otherwise we'll need to temporarily settle for some other - // convenient type; type legalization will make adjustments as - // needed. - else if (PTy.bitsLT(Op2.getValueType())) - Op2 = DAG.getNode(ISD::TRUNCATE, getCurDebugLoc(), - TLI.getPointerTy(), Op2); - else if (PTy.bitsGT(Op2.getValueType())) - Op2 = DAG.getNode(ISD::ANY_EXTEND, getCurDebugLoc(), - TLI.getPointerTy(), Op2); + else if (ShiftSize >= Log2_32_Ceil(Op2.getValueType().getSizeInBits())) + Op2 = DAG.getNode(ISD::TRUNCATE, DL, ShiftTy, Op2); + // Otherwise we'll need to temporarily settle for some other convenient + // type. Type legalization will make adjustments once the shiftee is split. + else + Op2 = DAG.getZExtOrTrunc(Op2, DL, MVT::i32); } setValue(&I, DAG.getNode(Opcode, getCurDebugLoc(), @@ -2499,9 +2576,9 @@ void SelectionDAGBuilder::visitBitCast(const User &I) { EVT DestVT = TLI.getValueType(I.getType()); // BitCast assures us that source and destination are the same size so this is - // either a BIT_CONVERT or a no-op. + // either a BITCAST or a no-op. if (DestVT != N.getValueType()) - setValue(&I, DAG.getNode(ISD::BIT_CONVERT, getCurDebugLoc(), + setValue(&I, DAG.getNode(ISD::BITCAST, getCurDebugLoc(), DestVT, N)); // convert types. else setValue(&I, N); // noop cast. @@ -2650,7 +2727,7 @@ void SelectionDAGBuilder::visitShuffleVector(const User &I) { } else { StartIdx[Input] = (MinRange[Input]/MaskNumElts)*MaskNumElts; if (MaxRange[Input] - StartIdx[Input] < (int)MaskNumElts && - StartIdx[Input] + MaskNumElts < SrcNumElts) + StartIdx[Input] + MaskNumElts <= SrcNumElts) RangeUse[Input] = 1; // Extract from a multiple of the mask length. } } @@ -2726,8 +2803,7 @@ void SelectionDAGBuilder::visitInsertValue(const InsertValueInst &I) { bool IntoUndef = isa(Op0); bool FromUndef = isa(Op1); - unsigned LinearIndex = ComputeLinearIndex(TLI, AggTy, - I.idx_begin(), I.idx_end()); + unsigned LinearIndex = ComputeLinearIndex(AggTy, I.idx_begin(), I.idx_end()); SmallVector AggValueVTs; ComputeValueVTs(TLI, AggTy, AggValueVTs); @@ -2765,8 +2841,7 @@ void SelectionDAGBuilder::visitExtractValue(const ExtractValueInst &I) { const Type *ValTy = I.getType(); bool OutOfUndef = isa(Op0); - unsigned LinearIndex = ComputeLinearIndex(TLI, AggTy, - I.idx_begin(), I.idx_end()); + unsigned LinearIndex = ComputeLinearIndex(AggTy, I.idx_begin(), I.idx_end()); SmallVector ValValueVTs; ComputeValueVTs(TLI, ValTy, ValValueVTs); @@ -2884,7 +2959,7 @@ void SelectionDAGBuilder::visitAlloca(const AllocaInst &I) { // Handle alignment. If the requested alignment is less than or equal to // the stack alignment, ignore it. If the size is greater than or equal to // the stack alignment, we note this in the DYNAMIC_STACKALLOC node. - unsigned StackAlign = TM.getFrameInfo()->getStackAlignment(); + unsigned StackAlign = TM.getFrameLowering()->getStackAlignment(); if (Align <= StackAlign) Align = 0; @@ -2920,6 +2995,7 @@ void SelectionDAGBuilder::visitLoad(const LoadInst &I) { bool isVolatile = I.isVolatile(); bool isNonTemporal = I.getMetadata("nontemporal") != 0; unsigned Alignment = I.getAlignment(); + const MDNode *TBAAInfo = I.getMetadata(LLVMContext::MD_tbaa); SmallVector ValueVTs; SmallVector Offsets; @@ -2930,10 +3006,11 @@ void SelectionDAGBuilder::visitLoad(const LoadInst &I) { SDValue Root; bool ConstantMemory = false; - if (I.isVolatile()) + if (I.isVolatile() || NumValues > MaxParallelChains) // Serialize volatile loads with other side effects. Root = getRoot(); - else if (AA->pointsToConstantMemory(SV)) { + else if (AA->pointsToConstantMemory( + AliasAnalysis::Location(SV, AA->getTypeStoreSize(Ty), TBAAInfo))) { // Do not serialize (non-volatile) loads of constant memory with anything. Root = DAG.getEntryNode(); ConstantMemory = true; @@ -2943,23 +3020,38 @@ void SelectionDAGBuilder::visitLoad(const LoadInst &I) { } SmallVector Values(NumValues); - SmallVector Chains(NumValues); + SmallVector Chains(std::min(unsigned(MaxParallelChains), + NumValues)); EVT PtrVT = Ptr.getValueType(); - for (unsigned i = 0; i != NumValues; ++i) { + unsigned ChainI = 0; + for (unsigned i = 0; i != NumValues; ++i, ++ChainI) { + // Serializing loads here may result in excessive register pressure, and + // TokenFactor places arbitrary choke points on the scheduler. SD scheduling + // could recover a bit by hoisting nodes upward in the chain by recognizing + // they are side-effect free or do not alias. The optimizer should really + // avoid this case by converting large object/array copies to llvm.memcpy + // (MaxParallelChains should always remain as failsafe). + if (ChainI == MaxParallelChains) { + assert(PendingLoads.empty() && "PendingLoads must be serialized first"); + SDValue Chain = DAG.getNode(ISD::TokenFactor, getCurDebugLoc(), + MVT::Other, &Chains[0], ChainI); + Root = Chain; + ChainI = 0; + } SDValue A = DAG.getNode(ISD::ADD, getCurDebugLoc(), PtrVT, Ptr, DAG.getConstant(Offsets[i], PtrVT)); SDValue L = DAG.getLoad(ValueVTs[i], getCurDebugLoc(), Root, - A, SV, Offsets[i], isVolatile, - isNonTemporal, Alignment); + A, MachinePointerInfo(SV, Offsets[i]), isVolatile, + isNonTemporal, Alignment, TBAAInfo); Values[i] = L; - Chains[i] = L.getValue(1); + Chains[ChainI] = L.getValue(1); } if (!ConstantMemory) { SDValue Chain = DAG.getNode(ISD::TokenFactor, getCurDebugLoc(), - MVT::Other, &Chains[0], NumValues); + MVT::Other, &Chains[0], ChainI); if (isVolatile) DAG.setRoot(Chain); else @@ -2989,23 +3081,37 @@ void SelectionDAGBuilder::visitStore(const StoreInst &I) { SDValue Ptr = getValue(PtrV); SDValue Root = getRoot(); - SmallVector Chains(NumValues); + SmallVector Chains(std::min(unsigned(MaxParallelChains), + NumValues)); EVT PtrVT = Ptr.getValueType(); bool isVolatile = I.isVolatile(); bool isNonTemporal = I.getMetadata("nontemporal") != 0; unsigned Alignment = I.getAlignment(); - - for (unsigned i = 0; i != NumValues; ++i) { + const MDNode *TBAAInfo = I.getMetadata(LLVMContext::MD_tbaa); + + unsigned ChainI = 0; + for (unsigned i = 0; i != NumValues; ++i, ++ChainI) { + // See visitLoad comments. + if (ChainI == MaxParallelChains) { + SDValue Chain = DAG.getNode(ISD::TokenFactor, getCurDebugLoc(), + MVT::Other, &Chains[0], ChainI); + Root = Chain; + ChainI = 0; + } SDValue Add = DAG.getNode(ISD::ADD, getCurDebugLoc(), PtrVT, Ptr, DAG.getConstant(Offsets[i], PtrVT)); - Chains[i] = DAG.getStore(Root, getCurDebugLoc(), - SDValue(Src.getNode(), Src.getResNo() + i), - Add, PtrV, Offsets[i], isVolatile, - isNonTemporal, Alignment); - } - - DAG.setRoot(DAG.getNode(ISD::TokenFactor, getCurDebugLoc(), - MVT::Other, &Chains[0], NumValues)); + SDValue St = DAG.getStore(Root, getCurDebugLoc(), + SDValue(Src.getNode(), Src.getResNo() + i), + Add, MachinePointerInfo(PtrV, Offsets[i]), + isVolatile, isNonTemporal, Alignment, TBAAInfo); + Chains[ChainI] = St; + } + + SDValue StoreNode = DAG.getNode(ISD::TokenFactor, getCurDebugLoc(), + MVT::Other, &Chains[0], ChainI); + ++SDNodeOrder; + AssignOrderingToNode(StoreNode.getNode()); + DAG.setRoot(StoreNode); } /// visitTargetIntrinsic - Lower a call of a target intrinsic to an INTRINSIC @@ -3031,7 +3137,8 @@ void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I, bool IsTgtIntrinsic = TLI.getTgtMemIntrinsic(Info, I, Intrinsic); // Add the intrinsic ID as an integer operand if it's not a target intrinsic. - if (!IsTgtIntrinsic) + if (!IsTgtIntrinsic || Info.opc == ISD::INTRINSIC_VOID || + Info.opc == ISD::INTRINSIC_W_CHAIN) Ops.push_back(DAG.getConstant(Intrinsic, TLI.getPointerTy())); // Add all operands of the call to the operand list. @@ -3062,7 +3169,8 @@ void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I, // This is target intrinsic that touches memory Result = DAG.getMemIntrinsicNode(Info.opc, getCurDebugLoc(), VTs, &Ops[0], Ops.size(), - Info.memVT, Info.ptrVal, Info.offset, + Info.memVT, + MachinePointerInfo(Info.ptrVal, Info.offset), Info.align, Info.vol, Info.readMem, Info.writeMem); } else if (!HasChain) { @@ -3087,7 +3195,7 @@ void SelectionDAGBuilder::visitTargetIntrinsic(const CallInst &I, if (!I.getType()->isVoidTy()) { if (const VectorType *PTy = dyn_cast(I.getType())) { EVT VT = TLI.getValueType(PTy); - Result = DAG.getNode(ISD::BIT_CONVERT, getCurDebugLoc(), VT, Result); + Result = DAG.getNode(ISD::BITCAST, getCurDebugLoc(), VT, Result); } setValue(&I, Result); @@ -3106,7 +3214,7 @@ GetSignificand(SelectionDAG &DAG, SDValue Op, DebugLoc dl) { DAG.getConstant(0x007fffff, MVT::i32)); SDValue t2 = DAG.getNode(ISD::OR, dl, MVT::i32, t1, DAG.getConstant(0x3f800000, MVT::i32)); - return DAG.getNode(ISD::BIT_CONVERT, dl, MVT::f32, t2); + return DAG.getNode(ISD::BITCAST, dl, MVT::f32, t2); } /// GetExponent - Get the exponent: @@ -3205,13 +3313,13 @@ SelectionDAGBuilder::visitExp(const CallInst &I) { SDValue t4 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t3, X); SDValue t5 = DAG.getNode(ISD::FADD, dl, MVT::f32, t4, getF32Constant(DAG, 0x3f7f5e7e)); - SDValue TwoToFracPartOfX = DAG.getNode(ISD::BIT_CONVERT, dl,MVT::i32, t5); + SDValue TwoToFracPartOfX = DAG.getNode(ISD::BITCAST, dl,MVT::i32, t5); // Add the exponent into the result in integer domain. SDValue t6 = DAG.getNode(ISD::ADD, dl, MVT::i32, TwoToFracPartOfX, IntegerPartOfX); - result = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::f32, t6); + result = DAG.getNode(ISD::BITCAST, dl, MVT::f32, t6); } else if (LimitFloatPrecision > 6 && LimitFloatPrecision <= 12) { // For floating-point precision of 12: // @@ -3231,13 +3339,13 @@ SelectionDAGBuilder::visitExp(const CallInst &I) { SDValue t6 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t5, X); SDValue t7 = DAG.getNode(ISD::FADD, dl, MVT::f32, t6, getF32Constant(DAG, 0x3f7ff8fd)); - SDValue TwoToFracPartOfX = DAG.getNode(ISD::BIT_CONVERT, dl,MVT::i32, t7); + SDValue TwoToFracPartOfX = DAG.getNode(ISD::BITCAST, dl,MVT::i32, t7); // Add the exponent into the result in integer domain. SDValue t8 = DAG.getNode(ISD::ADD, dl, MVT::i32, TwoToFracPartOfX, IntegerPartOfX); - result = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::f32, t8); + result = DAG.getNode(ISD::BITCAST, dl, MVT::f32, t8); } else { // LimitFloatPrecision > 12 && LimitFloatPrecision <= 18 // For floating-point precision of 18: // @@ -3269,14 +3377,14 @@ SelectionDAGBuilder::visitExp(const CallInst &I) { SDValue t12 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t11, X); SDValue t13 = DAG.getNode(ISD::FADD, dl, MVT::f32, t12, getF32Constant(DAG, 0x3f800000)); - SDValue TwoToFracPartOfX = DAG.getNode(ISD::BIT_CONVERT, dl, + SDValue TwoToFracPartOfX = DAG.getNode(ISD::BITCAST, dl, MVT::i32, t13); // Add the exponent into the result in integer domain. SDValue t14 = DAG.getNode(ISD::ADD, dl, MVT::i32, TwoToFracPartOfX, IntegerPartOfX); - result = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::f32, t14); + result = DAG.getNode(ISD::BITCAST, dl, MVT::f32, t14); } } else { // No special expansion. @@ -3298,7 +3406,7 @@ SelectionDAGBuilder::visitLog(const CallInst &I) { if (getValue(I.getArgOperand(0)).getValueType() == MVT::f32 && LimitFloatPrecision > 0 && LimitFloatPrecision <= 18) { SDValue Op = getValue(I.getArgOperand(0)); - SDValue Op1 = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::i32, Op); + SDValue Op1 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Op); // Scale the exponent by log(2) [0.69314718f]. SDValue Exp = GetExponent(DAG, Op1, TLI, dl); @@ -3408,7 +3516,7 @@ SelectionDAGBuilder::visitLog2(const CallInst &I) { if (getValue(I.getArgOperand(0)).getValueType() == MVT::f32 && LimitFloatPrecision > 0 && LimitFloatPrecision <= 18) { SDValue Op = getValue(I.getArgOperand(0)); - SDValue Op1 = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::i32, Op); + SDValue Op1 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Op); // Get the exponent. SDValue LogOfExponent = GetExponent(DAG, Op1, TLI, dl); @@ -3517,7 +3625,7 @@ SelectionDAGBuilder::visitLog10(const CallInst &I) { if (getValue(I.getArgOperand(0)).getValueType() == MVT::f32 && LimitFloatPrecision > 0 && LimitFloatPrecision <= 18) { SDValue Op = getValue(I.getArgOperand(0)); - SDValue Op1 = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::i32, Op); + SDValue Op1 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Op); // Scale the exponent by log10(2) [0.30102999f]. SDValue Exp = GetExponent(DAG, Op1, TLI, dl); @@ -3645,11 +3753,11 @@ SelectionDAGBuilder::visitExp2(const CallInst &I) { SDValue t4 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t3, X); SDValue t5 = DAG.getNode(ISD::FADD, dl, MVT::f32, t4, getF32Constant(DAG, 0x3f7f5e7e)); - SDValue t6 = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::i32, t5); + SDValue t6 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, t5); SDValue TwoToFractionalPartOfX = DAG.getNode(ISD::ADD, dl, MVT::i32, t6, IntegerPartOfX); - result = DAG.getNode(ISD::BIT_CONVERT, dl, + result = DAG.getNode(ISD::BITCAST, dl, MVT::f32, TwoToFractionalPartOfX); } else if (LimitFloatPrecision > 6 && LimitFloatPrecision <= 12) { // For floating-point precision of 12: @@ -3670,11 +3778,11 @@ SelectionDAGBuilder::visitExp2(const CallInst &I) { SDValue t6 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t5, X); SDValue t7 = DAG.getNode(ISD::FADD, dl, MVT::f32, t6, getF32Constant(DAG, 0x3f7ff8fd)); - SDValue t8 = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::i32, t7); + SDValue t8 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, t7); SDValue TwoToFractionalPartOfX = DAG.getNode(ISD::ADD, dl, MVT::i32, t8, IntegerPartOfX); - result = DAG.getNode(ISD::BIT_CONVERT, dl, + result = DAG.getNode(ISD::BITCAST, dl, MVT::f32, TwoToFractionalPartOfX); } else { // LimitFloatPrecision > 12 && LimitFloatPrecision <= 18 // For floating-point precision of 18: @@ -3706,11 +3814,11 @@ SelectionDAGBuilder::visitExp2(const CallInst &I) { SDValue t12 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t11, X); SDValue t13 = DAG.getNode(ISD::FADD, dl, MVT::f32, t12, getF32Constant(DAG, 0x3f800000)); - SDValue t14 = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::i32, t13); + SDValue t14 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, t13); SDValue TwoToFractionalPartOfX = DAG.getNode(ISD::ADD, dl, MVT::i32, t14, IntegerPartOfX); - result = DAG.getNode(ISD::BIT_CONVERT, dl, + result = DAG.getNode(ISD::BITCAST, dl, MVT::f32, TwoToFractionalPartOfX); } } else { @@ -3778,11 +3886,11 @@ SelectionDAGBuilder::visitPow(const CallInst &I) { SDValue t4 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t3, X); SDValue t5 = DAG.getNode(ISD::FADD, dl, MVT::f32, t4, getF32Constant(DAG, 0x3f7f5e7e)); - SDValue t6 = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::i32, t5); + SDValue t6 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, t5); SDValue TwoToFractionalPartOfX = DAG.getNode(ISD::ADD, dl, MVT::i32, t6, IntegerPartOfX); - result = DAG.getNode(ISD::BIT_CONVERT, dl, + result = DAG.getNode(ISD::BITCAST, dl, MVT::f32, TwoToFractionalPartOfX); } else if (LimitFloatPrecision > 6 && LimitFloatPrecision <= 12) { // For floating-point precision of 12: @@ -3803,11 +3911,11 @@ SelectionDAGBuilder::visitPow(const CallInst &I) { SDValue t6 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t5, X); SDValue t7 = DAG.getNode(ISD::FADD, dl, MVT::f32, t6, getF32Constant(DAG, 0x3f7ff8fd)); - SDValue t8 = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::i32, t7); + SDValue t8 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, t7); SDValue TwoToFractionalPartOfX = DAG.getNode(ISD::ADD, dl, MVT::i32, t8, IntegerPartOfX); - result = DAG.getNode(ISD::BIT_CONVERT, dl, + result = DAG.getNode(ISD::BITCAST, dl, MVT::f32, TwoToFractionalPartOfX); } else { // LimitFloatPrecision > 12 && LimitFloatPrecision <= 18 // For floating-point precision of 18: @@ -3839,11 +3947,11 @@ SelectionDAGBuilder::visitPow(const CallInst &I) { SDValue t12 = DAG.getNode(ISD::FMUL, dl, MVT::f32, t11, X); SDValue t13 = DAG.getNode(ISD::FADD, dl, MVT::f32, t12, getF32Constant(DAG, 0x3f800000)); - SDValue t14 = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::i32, t13); + SDValue t14 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, t13); SDValue TwoToFractionalPartOfX = DAG.getNode(ISD::ADD, dl, MVT::i32, t14, IntegerPartOfX); - result = DAG.getNode(ISD::BIT_CONVERT, dl, + result = DAG.getNode(ISD::BITCAST, dl, MVT::f32, TwoToFractionalPartOfX); } } else { @@ -3915,13 +4023,16 @@ static SDValue ExpandPowI(DebugLoc DL, SDValue LHS, SDValue RHS, /// At the end of instruction selection, they will be inserted to the entry BB. bool SelectionDAGBuilder::EmitFuncArgumentDbgValue(const Value *V, MDNode *Variable, - int64_t Offset, + int64_t Offset, const SDValue &N) { const Argument *Arg = dyn_cast(V); if (!Arg) return false; MachineFunction &MF = DAG.getMachineFunction(); + const TargetInstrInfo *TII = DAG.getTarget().getInstrInfo(); + const TargetRegisterInfo *TRI = DAG.getTarget().getRegisterInfo(); + // Ignore inlined function arguments here. DIVariable DV(Variable); if (DV.isInlinedFnArgument(MF.getFunction())) @@ -3935,14 +4046,16 @@ SelectionDAGBuilder::EmitFuncArgumentDbgValue(const Value *V, MDNode *Variable, if (Arg->hasByValAttr()) { // Byval arguments' frame index is recorded during argument lowering. // Use this info directly. - const TargetRegisterInfo *TRI = DAG.getTarget().getRegisterInfo(); Reg = TRI->getFrameRegister(MF); Offset = FuncInfo.getByValArgumentFrameIndex(Arg); + // If byval argument ofset is not recorded then ignore this. + if (!Offset) + Reg = 0; } if (N.getNode() && N.getOpcode() == ISD::CopyFromReg) { Reg = cast(N.getOperand(1))->getReg(); - if (Reg && TargetRegisterInfo::isVirtualRegister(Reg)) { + if (TargetRegisterInfo::isVirtualRegister(Reg)) { MachineRegisterInfo &RegInfo = MF.getRegInfo(); unsigned PR = RegInfo.getLiveInPhysReg(Reg); if (PR) @@ -3951,13 +4064,25 @@ SelectionDAGBuilder::EmitFuncArgumentDbgValue(const Value *V, MDNode *Variable, } if (!Reg) { + // Check if ValueMap has reg number. DenseMap::iterator VMI = FuncInfo.ValueMap.find(V); - if (VMI == FuncInfo.ValueMap.end()) - return false; - Reg = VMI->second; + if (VMI != FuncInfo.ValueMap.end()) + Reg = VMI->second; } - const TargetInstrInfo *TII = DAG.getTarget().getInstrInfo(); + if (!Reg && N.getNode()) { + // Check if frame index is available. + if (LoadSDNode *LNode = dyn_cast(N.getNode())) + if (FrameIndexSDNode *FINode = + dyn_cast(LNode->getBasePtr().getNode())) { + Reg = TRI->getFrameRegister(MF); + Offset = FINode->getIndex(); + } + } + + if (!Reg) + return false; + MachineInstrBuilder MIB = BuildMI(MF, getCurDebugLoc(), TII->get(TargetOpcode::DBG_VALUE)) .addReg(Reg, RegState::Debug).addImm(Offset).addMetadata(Variable); @@ -3966,9 +4091,11 @@ SelectionDAGBuilder::EmitFuncArgumentDbgValue(const Value *V, MDNode *Variable, } // VisualStudio defines setjmp as _setjmp -#if defined(_MSC_VER) && defined(setjmp) -#define setjmp_undefined_for_visual_studio -#undef setjmp +#if defined(_MSC_VER) && defined(setjmp) && \ + !defined(setjmp_undefined_for_msvc) +# pragma push_macro("setjmp") +# undef setjmp +# define setjmp_undefined_for_msvc #endif /// visitIntrinsicCall - Lower the call to the specified intrinsic function. If @@ -4013,7 +4140,8 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { unsigned Align = cast(I.getArgOperand(3))->getZExtValue(); bool isVol = cast(I.getArgOperand(4))->getZExtValue(); DAG.setRoot(DAG.getMemcpy(getRoot(), dl, Op1, Op2, Op3, Align, isVol, false, - I.getArgOperand(0), 0, I.getArgOperand(1), 0)); + MachinePointerInfo(I.getArgOperand(0)), + MachinePointerInfo(I.getArgOperand(1)))); return 0; } case Intrinsic::memset: { @@ -4028,7 +4156,7 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { unsigned Align = cast(I.getArgOperand(3))->getZExtValue(); bool isVol = cast(I.getArgOperand(4))->getZExtValue(); DAG.setRoot(DAG.getMemset(getRoot(), dl, Op1, Op2, Op3, Align, isVol, - I.getArgOperand(0), 0)); + MachinePointerInfo(I.getArgOperand(0)))); return 0; } case Intrinsic::memmove: { @@ -4044,22 +4172,9 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { SDValue Op3 = getValue(I.getArgOperand(2)); unsigned Align = cast(I.getArgOperand(3))->getZExtValue(); bool isVol = cast(I.getArgOperand(4))->getZExtValue(); - - // If the source and destination are known to not be aliases, we can - // lower memmove as memcpy. - uint64_t Size = -1ULL; - if (ConstantSDNode *C = dyn_cast(Op3)) - Size = C->getZExtValue(); - if (AA->alias(I.getArgOperand(0), Size, I.getArgOperand(1), Size) == - AliasAnalysis::NoAlias) { - DAG.setRoot(DAG.getMemcpy(getRoot(), dl, Op1, Op2, Op3, Align, isVol, - false, I.getArgOperand(0), 0, - I.getArgOperand(1), 0)); - return 0; - } - DAG.setRoot(DAG.getMemmove(getRoot(), dl, Op1, Op2, Op3, Align, isVol, - I.getArgOperand(0), 0, I.getArgOperand(1), 0)); + MachinePointerInfo(I.getArgOperand(0)), + MachinePointerInfo(I.getArgOperand(1)))); return 0; } case Intrinsic::dbg_declare: { @@ -4078,10 +4193,7 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { // Check if address has undef value. if (isa(Address) || (Address->use_empty() && !isa(Address))) { - SDDbgValue*SDV = - DAG.getDbgValue(Variable, UndefValue::get(Address->getType()), - 0, dl, SDNodeOrder); - DAG.AddDbgValue(SDV, 0, false); + DEBUG(dbgs() << "Dropping debug info for " << DI); return 0; } @@ -4092,7 +4204,7 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { SDDbgValue *SDV; if (N.getNode()) { // Parameters are handled specially. - bool isParameter = + bool isParameter = DIVariable(Variable).getTag() == dwarf::DW_TAG_arg_variable; if (const BitCastInst *BCI = dyn_cast(Address)) Address = BCI->getOperand(0); @@ -4104,25 +4216,40 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { // Byval parameter. We have a frame index at this point. SDV = DAG.getDbgValue(Variable, FINode->getIndex(), 0, dl, SDNodeOrder); - else + else { // Can't do anything with other non-AI cases yet. This might be a // parameter of a callee function that got inlined, for example. + DEBUG(dbgs() << "Dropping debug info for " << DI); return 0; + } } else if (AI) SDV = DAG.getDbgValue(Variable, N.getNode(), N.getResNo(), 0, dl, SDNodeOrder); - else + else { // Can't do anything with other non-AI cases yet. + DEBUG(dbgs() << "Dropping debug info for " << DI); return 0; + } DAG.AddDbgValue(SDV, N.getNode(), isParameter); } else { - // If Address is an arugment then try to emits its dbg value using - // virtual register info from the FuncInfo.ValueMap. Otherwise add undef - // to help track missing debug info. + // If Address is an argument then try to emit its dbg value using + // virtual register info from the FuncInfo.ValueMap. if (!EmitFuncArgumentDbgValue(Address, Variable, 0, N)) { - SDV = DAG.getDbgValue(Variable, UndefValue::get(Address->getType()), - 0, dl, SDNodeOrder); - DAG.AddDbgValue(SDV, 0, false); + // If variable is pinned by a alloca in dominating bb then + // use StaticAllocaMap. + if (const AllocaInst *AI = dyn_cast(Address)) { + if (AI->getParent() != DI.getParent()) { + DenseMap::iterator SI = + FuncInfo.StaticAllocaMap.find(AI); + if (SI != FuncInfo.StaticAllocaMap.end()) { + SDV = DAG.getDbgValue(Variable, SI->second, + 0, dl, SDNodeOrder); + DAG.AddDbgValue(SDV, 0, false); + return 0; + } + } + } + DEBUG(dbgs() << "Dropping debug info for " << DI); } } return 0; @@ -4160,17 +4287,15 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { N.getResNo(), Offset, dl, SDNodeOrder); DAG.AddDbgValue(SDV, N.getNode(), false); } - } else if (isa(V) && !V->use_empty() ) { + } else if (!V->use_empty() ) { // Do not call getValue(V) yet, as we don't want to generate code. // Remember it for later. DanglingDebugInfo DDI(&DI, dl, SDNodeOrder); DanglingDebugInfoMap[V] = DDI; } else { // We may expand this to cover more cases. One case where we have no - // data available is an unreferenced parameter; we need this fallback. - SDV = DAG.getDbgValue(Variable, UndefValue::get(V->getType()), - Offset, dl, SDNodeOrder); - DAG.AddDbgValue(SDV, 0, false); + // data available is an unreferenced parameter. + DEBUG(dbgs() << "Dropping debug info for " << DI); } } @@ -4186,7 +4311,7 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { if (SI == FuncInfo.StaticAllocaMap.end()) return 0; // VLAs. int FI = SI->second; - + MachineModuleInfo &MMI = DAG.getMachineFunction().getMMI(); if (!DI.getDebugLoc().isUnknown() && MMI.hasDebugInfo()) MMI.setVariableDbgInfo(Variable, FI, DI.getDebugLoc()); @@ -4282,11 +4407,75 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { } case Intrinsic::eh_sjlj_longjmp: { DAG.setRoot(DAG.getNode(ISD::EH_SJLJ_LONGJMP, dl, MVT::Other, - getRoot(), - getValue(I.getArgOperand(0)))); + getRoot(), getValue(I.getArgOperand(0)))); + return 0; + } + case Intrinsic::eh_sjlj_dispatch_setup: { + DAG.setRoot(DAG.getNode(ISD::EH_SJLJ_DISPATCHSETUP, dl, MVT::Other, + getRoot(), getValue(I.getArgOperand(0)))); return 0; } + case Intrinsic::x86_mmx_pslli_w: + case Intrinsic::x86_mmx_pslli_d: + case Intrinsic::x86_mmx_pslli_q: + case Intrinsic::x86_mmx_psrli_w: + case Intrinsic::x86_mmx_psrli_d: + case Intrinsic::x86_mmx_psrli_q: + case Intrinsic::x86_mmx_psrai_w: + case Intrinsic::x86_mmx_psrai_d: { + SDValue ShAmt = getValue(I.getArgOperand(1)); + if (isa(ShAmt)) { + visitTargetIntrinsic(I, Intrinsic); + return 0; + } + unsigned NewIntrinsic = 0; + EVT ShAmtVT = MVT::v2i32; + switch (Intrinsic) { + case Intrinsic::x86_mmx_pslli_w: + NewIntrinsic = Intrinsic::x86_mmx_psll_w; + break; + case Intrinsic::x86_mmx_pslli_d: + NewIntrinsic = Intrinsic::x86_mmx_psll_d; + break; + case Intrinsic::x86_mmx_pslli_q: + NewIntrinsic = Intrinsic::x86_mmx_psll_q; + break; + case Intrinsic::x86_mmx_psrli_w: + NewIntrinsic = Intrinsic::x86_mmx_psrl_w; + break; + case Intrinsic::x86_mmx_psrli_d: + NewIntrinsic = Intrinsic::x86_mmx_psrl_d; + break; + case Intrinsic::x86_mmx_psrli_q: + NewIntrinsic = Intrinsic::x86_mmx_psrl_q; + break; + case Intrinsic::x86_mmx_psrai_w: + NewIntrinsic = Intrinsic::x86_mmx_psra_w; + break; + case Intrinsic::x86_mmx_psrai_d: + NewIntrinsic = Intrinsic::x86_mmx_psra_d; + break; + default: llvm_unreachable("Impossible intrinsic"); // Can't reach here. + } + + // The vector shift intrinsics with scalars uses 32b shift amounts but + // the sse2/mmx shift instructions reads 64 bits. Set the upper 32 bits + // to be zero. + // We must do this early because v2i32 is not a legal type. + DebugLoc dl = getCurDebugLoc(); + SDValue ShOps[2]; + ShOps[0] = ShAmt; + ShOps[1] = DAG.getConstant(0, MVT::i32); + ShAmt = DAG.getNode(ISD::BUILD_VECTOR, dl, ShAmtVT, &ShOps[0], 2); + EVT DestVT = TLI.getValueType(I.getType()); + ShAmt = DAG.getNode(ISD::BITCAST, dl, DestVT, ShAmt); + Res = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, DestVT, + DAG.getConstant(NewIntrinsic, MVT::i32), + getValue(I.getArgOperand(0)), ShAmt); + setValue(&I, Res); + return 0; + } case Intrinsic::convertff: case Intrinsic::convertfsi: case Intrinsic::convertfui: @@ -4430,8 +4619,8 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { // Store the stack protector onto the stack. Res = DAG.getStore(getRoot(), getCurDebugLoc(), Src, FIN, - PseudoSourceValue::getFixedStack(FI), - 0, true, false, 0); + MachinePointerInfo::getFixedStack(FI), + true, false, 0); setValue(&I, Res); DAG.setRoot(Res); return 0; @@ -4510,14 +4699,22 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { case Intrinsic::prefetch: { SDValue Ops[4]; + unsigned rw = cast(I.getArgOperand(1))->getZExtValue(); Ops[0] = getRoot(); Ops[1] = getValue(I.getArgOperand(0)); Ops[2] = getValue(I.getArgOperand(1)); Ops[3] = getValue(I.getArgOperand(2)); - DAG.setRoot(DAG.getNode(ISD::PREFETCH, dl, MVT::Other, &Ops[0], 4)); + DAG.setRoot(DAG.getMemIntrinsicNode(ISD::PREFETCH, dl, + DAG.getVTList(MVT::Other), + &Ops[0], 4, + EVT::getIntegerVT(*Context, 8), + MachinePointerInfo(I.getArgOperand(0)), + 0, /* align */ + false, /* volatile */ + rw==0, /* read */ + rw==1)); /* write */ return 0; } - case Intrinsic::memory_barrier: { SDValue Ops[6]; Ops[0] = getRoot(); @@ -4536,7 +4733,7 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { getValue(I.getArgOperand(0)), getValue(I.getArgOperand(1)), getValue(I.getArgOperand(2)), - I.getArgOperand(0)); + MachinePointerInfo(I.getArgOperand(0))); setValue(&I, L); DAG.setRoot(L.getValue(1)); return 0; @@ -4599,6 +4796,7 @@ void SelectionDAGBuilder::LowerCallTo(ImmutableCallSite CS, SDValue Callee, FTy->isVarArg(), Outs, FTy->getContext()); SDValue DemoteStackSlot; + int DemoteStackIdx = -100; if (!CanLowerReturn) { uint64_t TySize = TLI.getTargetData()->getTypeAllocSize( @@ -4606,10 +4804,10 @@ void SelectionDAGBuilder::LowerCallTo(ImmutableCallSite CS, SDValue Callee, unsigned Align = TLI.getTargetData()->getPrefTypeAlignment( FTy->getReturnType()); MachineFunction &MF = DAG.getMachineFunction(); - int SSFI = MF.getFrameInfo()->CreateStackObject(TySize, Align, false); + DemoteStackIdx = MF.getFrameInfo()->CreateStackObject(TySize, Align, false); const Type *StackSlotPtrType = PointerType::getUnqual(FTy->getReturnType()); - DemoteStackSlot = DAG.getFrameIndex(SSFI, TLI.getPointerTy()); + DemoteStackSlot = DAG.getFrameIndex(DemoteStackIdx, TLI.getPointerTy()); Entry.Node = DemoteStackSlot; Entry.Ty = StackSlotPtrType; Entry.isSExt = false; @@ -4703,7 +4901,9 @@ void SelectionDAGBuilder::LowerCallTo(ImmutableCallSite CS, SDValue Callee, DemoteStackSlot, DAG.getConstant(Offsets[i], PtrVT)); SDValue L = DAG.getLoad(Outs[i].VT, getCurDebugLoc(), Result.second, - Add, NULL, Offsets[i], false, false, 1); + Add, + MachinePointerInfo::getFixedStack(DemoteStackIdx, Offsets[i]), + false, false, 1); Values[i] = L; Chains[i] = L.getValue(1); } @@ -4711,7 +4911,7 @@ void SelectionDAGBuilder::LowerCallTo(ImmutableCallSite CS, SDValue Callee, SDValue Chain = DAG.getNode(ISD::TokenFactor, getCurDebugLoc(), MVT::Other, &Chains[0], NumValues); PendingLoads.push_back(Chain); - + // Collect the legal value parts into potentially illegal values // that correspond to the original function's return values. SmallVector RetTys; @@ -4724,7 +4924,7 @@ void SelectionDAGBuilder::LowerCallTo(ImmutableCallSite CS, SDValue Callee, EVT VT = RetTys[I]; EVT RegisterVT = TLI.getRegisterType(RetTy->getContext(), VT); unsigned NumRegs = TLI.getNumRegisters(RetTy->getContext(), VT); - + SDValue ReturnValue = getCopyFromParts(DAG, getCurDebugLoc(), &Values[CurReg], NumRegs, RegisterVT, VT, AssertOp); @@ -4806,7 +5006,7 @@ static SDValue getMemCmpLoad(const Value *PtrVal, MVT LoadVT, SDValue Ptr = Builder.getValue(PtrVal); SDValue LoadVal = Builder.DAG.getLoad(LoadVT, Builder.getCurDebugLoc(), Root, - Ptr, PtrVal /*SrcValue*/, 0/*SVOffset*/, + Ptr, MachinePointerInfo(PtrVal), false /*volatile*/, false /*nontemporal*/, 1 /* align=1 */); @@ -4902,7 +5102,25 @@ void SelectionDAGBuilder::visitCall(const CallInst &I) { visitInlineAsm(&I); return; } - + + // See if any floating point values are being passed to this function. This is + // used to emit an undefined reference to fltused on Windows. + const FunctionType *FT = + cast(I.getCalledValue()->getType()->getContainedType(0)); + MachineModuleInfo &MMI = DAG.getMachineFunction().getMMI(); + if (FT->isVarArg() && + !MMI.callsExternalVAFunctionWithFloatingPointArguments()) { + for (unsigned i = 0, e = I.getNumArgOperands(); i != e; ++i) { + const Type* T = I.getArgOperand(i)->getType(); + for (po_iterator i = po_begin(T), e = po_end(T); + i != e; ++i) { + if (!i->isFloatingPointTy()) continue; + MMI.setCallsExternalVAFunctionWithFloatingPointArguments(true); + break; + } + } + } + const char *RenameFn = 0; if (Function *F = I.getCalledFunction()) { if (F->isDeclaration()) { @@ -4980,7 +5198,7 @@ void SelectionDAGBuilder::visitCall(const CallInst &I) { } } } - + SDValue Callee; if (!RenameFn) Callee = getValue(I.getCalledValue()); @@ -5008,7 +5226,7 @@ public: /// contains the set of register corresponding to the operand. RegsForValue AssignedRegs; - explicit SDISelAsmOperandInfo(const InlineAsm::ConstraintInfo &info) + explicit SDISelAsmOperandInfo(const TargetLowering::AsmOperandInfo &info) : TargetLowering::AsmOperandInfo(info), CallOperand(0,0) { } @@ -5083,6 +5301,8 @@ private: } }; +typedef SmallVector SDISelAsmOperandInfoVector; + } // end llvm namespace. /// isAllocatableRegister - If the specified register is safe to allocate, @@ -5192,7 +5412,7 @@ GetRegistersForValue(SDISelAsmOperandInfo &OpInfo, // vector types). EVT RegVT = *PhysReg.second->vt_begin(); if (RegVT.getSizeInBits() == OpInfo.ConstraintVT.getSizeInBits()) { - OpInfo.CallOperand = DAG.getNode(ISD::BIT_CONVERT, getCurDebugLoc(), + OpInfo.CallOperand = DAG.getNode(ISD::BITCAST, getCurDebugLoc(), RegVT, OpInfo.CallOperand); OpInfo.ConstraintVT = RegVT; } else if (RegVT.isInteger() && OpInfo.ConstraintVT.isFloatingPoint()) { @@ -5202,7 +5422,7 @@ GetRegistersForValue(SDISelAsmOperandInfo &OpInfo, // machine. RegVT = EVT::getIntegerVT(Context, OpInfo.ConstraintVT.getSizeInBits()); - OpInfo.CallOperand = DAG.getNode(ISD::BIT_CONVERT, getCurDebugLoc(), + OpInfo.CallOperand = DAG.getNode(ISD::BITCAST, getCurDebugLoc(), RegVT, OpInfo.CallOperand); OpInfo.ConstraintVT = RegVT; } @@ -5320,30 +5540,17 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { const InlineAsm *IA = cast(CS.getCalledValue()); /// ConstraintOperands - Information about all of the constraints. - std::vector ConstraintOperands; + SDISelAsmOperandInfoVector ConstraintOperands; std::set OutputRegs, InputRegs; - // Do a prepass over the constraints, canonicalizing them, and building up the - // ConstraintOperands list. - std::vector - ConstraintInfos = IA->ParseConstraints(); - - bool hasMemory = hasInlineAsmMemConstraint(ConstraintInfos, TLI); - - SDValue Chain, Flag; - - // We won't need to flush pending loads if this asm doesn't touch - // memory and is nonvolatile. - if (hasMemory || IA->hasSideEffects()) - Chain = getRoot(); - else - Chain = DAG.getRoot(); + TargetLowering::AsmOperandInfoVector TargetConstraints = TLI.ParseConstraints(CS); + bool hasMemory = false; unsigned ArgNo = 0; // ArgNo - The argument of the CallInst. unsigned ResNo = 0; // ResNo - The result number of the next output. - for (unsigned i = 0, e = ConstraintInfos.size(); i != e; ++i) { - ConstraintOperands.push_back(SDISelAsmOperandInfo(ConstraintInfos[i])); + for (unsigned i = 0, e = TargetConstraints.size(); i != e; ++i) { + ConstraintOperands.push_back(SDISelAsmOperandInfo(TargetConstraints[i])); SDISelAsmOperandInfo &OpInfo = ConstraintOperands.back(); EVT OpVT = MVT::Other; @@ -5380,9 +5587,6 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { // If this is an input or an indirect output, process the call argument. // BasicBlocks are labels, currently appearing only in asm's. if (OpInfo.CallOperandVal) { - // Strip bitcasts, if any. This mostly comes up for functions. - OpInfo.CallOperandVal = OpInfo.CallOperandVal->stripPointerCasts(); - if (const BasicBlock *BB = dyn_cast(OpInfo.CallOperandVal)) { OpInfo.CallOperand = DAG.getBasicBlock(FuncInfo.MBBMap[BB]); } else { @@ -5393,11 +5597,33 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { } OpInfo.ConstraintVT = OpVT; + + // Indirect operand accesses access memory. + if (OpInfo.isIndirect) + hasMemory = true; + else { + for (unsigned j = 0, ee = OpInfo.Codes.size(); j != ee; ++j) { + TargetLowering::ConstraintType CType = TLI.getConstraintType(OpInfo.Codes[j]); + if (CType == TargetLowering::C_Memory) { + hasMemory = true; + break; + } + } + } } + SDValue Chain, Flag; + + // We won't need to flush pending loads if this asm doesn't touch + // memory and is nonvolatile. + if (hasMemory || IA->hasSideEffects()) + Chain = getRoot(); + else + Chain = DAG.getRoot(); + // Second pass over the constraints: compute which constraint option to use // and assign registers to constraints that want a specific physreg. - for (unsigned i = 0, e = ConstraintInfos.size(); i != e; ++i) { + for (unsigned i = 0, e = ConstraintOperands.size(); i != e; ++i) { SDISelAsmOperandInfo &OpInfo = ConstraintOperands[i]; // If this is an output operand with a matching input operand, look up the @@ -5406,7 +5632,7 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { // error. if (OpInfo.hasMatchingInput()) { SDISelAsmOperandInfo &Input = ConstraintOperands[OpInfo.MatchingInput]; - + if (OpInfo.ConstraintVT != Input.ConstraintVT) { if ((OpInfo.ConstraintVT.isInteger() != Input.ConstraintVT.isInteger()) || @@ -5427,7 +5653,7 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { // need to to provide an address for the memory input. if (OpInfo.ConstraintType == TargetLowering::C_Memory && !OpInfo.isIndirect) { - assert(OpInfo.Type == InlineAsm::isInput && + assert((OpInfo.isMultipleAlternative || (OpInfo.Type == InlineAsm::isInput)) && "Can only indirectify direct input operands!"); // Memory operands really want the address of the value. If we don't have @@ -5451,7 +5677,8 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { int SSFI = MF.getFrameInfo()->CreateStackObject(TySize, Align, false); SDValue StackSlot = DAG.getFrameIndex(SSFI, TLI.getPointerTy()); Chain = DAG.getStore(Chain, getCurDebugLoc(), - OpInfo.CallOperand, StackSlot, NULL, 0, + OpInfo.CallOperand, StackSlot, + MachinePointerInfo::getFixedStack(SSFI), false, false, 0); OpInfo.CallOperand = StackSlot; } @@ -5469,8 +5696,6 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { GetRegistersForValue(OpInfo, OutputRegs, InputRegs); } - ConstraintInfos.clear(); - // Second pass - Loop over all of the operands, assigning virtual or physregs // to register class operands. for (unsigned i = 0, e = ConstraintOperands.size(); i != e; ++i) { @@ -5495,9 +5720,14 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { const MDNode *SrcLoc = CS.getInstruction()->getMetadata("srcloc"); AsmNodeOperands.push_back(DAG.getMDNode(SrcLoc)); - // Remember the AlignStack bit as operand 3. - AsmNodeOperands.push_back(DAG.getTargetConstant(IA->isAlignStack() ? 1 : 0, - MVT::i1)); + // Remember the HasSideEffect and AlignStack bits as operand 3. + unsigned ExtraInfo = 0; + if (IA->hasSideEffects()) + ExtraInfo |= InlineAsm::Extra_HasSideEffects; + if (IA->isAlignStack()) + ExtraInfo |= InlineAsm::Extra_IsAlignStack; + AsmNodeOperands.push_back(DAG.getTargetConstant(ExtraInfo, + TLI.getPointerTy())); // Loop over all of the inputs, copying the operand values into the // appropriate registers and processing the output regs. @@ -5588,7 +5818,7 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { " don't know how to handle tied " "indirect register inputs"); } - + RegsForValue MatchedRegs; MatchedRegs.ValueVTs.push_back(InOperandVal.getValueType()); EVT RegVT = AsmNodeOperands[CurOp+1].getValueType(); @@ -5607,7 +5837,7 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { DAG, AsmNodeOperands); break; } - + assert(InlineAsm::isMemKind(OpFlag) && "Unknown matching constraint!"); assert(InlineAsm::getNumOperandRegisters(OpFlag) == 1 && "Unexpected number of operands"); @@ -5622,8 +5852,8 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { } // Treat indirect 'X' constraint as memory. - if (OpInfo.ConstraintType == TargetLowering::C_Other && - OpInfo.isIndirect) + if (OpInfo.ConstraintType == TargetLowering::C_Other && + OpInfo.isIndirect) OpInfo.ConstraintType = TargetLowering::C_Memory; if (OpInfo.ConstraintType == TargetLowering::C_Other) { @@ -5642,7 +5872,7 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { AsmNodeOperands.insert(AsmNodeOperands.end(), Ops.begin(), Ops.end()); break; } - + if (OpInfo.ConstraintType == TargetLowering::C_Memory) { assert(OpInfo.isIndirect && "Operand must be indirect to be a mem!"); assert(InOperandVal.getValueType() == TLI.getPointerTy() && @@ -5693,7 +5923,7 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { if (Flag.getNode()) AsmNodeOperands.push_back(Flag); Chain = DAG.getNode(ISD::INLINEASM, getCurDebugLoc(), - DAG.getVTList(MVT::Other, MVT::Flag), + DAG.getVTList(MVT::Other, MVT::Glue), &AsmNodeOperands[0], AsmNodeOperands.size()); Flag = Chain.getValue(1); @@ -5713,7 +5943,7 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { // not have the same VT as was expected. Convert it to the right type // with bit_convert. if (ResultType != Val.getValueType() && Val.getValueType().isVector()) { - Val = DAG.getNode(ISD::BIT_CONVERT, getCurDebugLoc(), + Val = DAG.getNode(ISD::BITCAST, getCurDebugLoc(), ResultType, Val); } else if (ResultType != Val.getValueType() && @@ -5751,7 +5981,7 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { SDValue Val = DAG.getStore(Chain, getCurDebugLoc(), StoresToEmit[i].first, getValue(StoresToEmit[i].second), - StoresToEmit[i].second, 0, + MachinePointerInfo(StoresToEmit[i].second), false, false, 0); OutChains.push_back(Val); } @@ -5888,7 +6118,7 @@ TargetLowering::LowerCallTo(SDValue Chain, const Type *RetTy, unsigned NumRegs = getNumRegisters(RetTy->getContext(), VT); for (unsigned i = 0; i != NumRegs; ++i) { ISD::InputArg MyFlags; - MyFlags.VT = RegisterVT; + MyFlags.VT = RegisterVT.getSimpleVT(); MyFlags.Used = isReturnValueUsed; if (RetSExt) MyFlags.Flags.setSExt(); @@ -5924,7 +6154,7 @@ TargetLowering::LowerCallTo(SDValue Chain, const Type *RetTy, DEBUG(for (unsigned i = 0, e = Ins.size(); i != e; ++i) { assert(InVals[i].getNode() && "LowerCall emitted a null value!"); - assert(Ins[i].VT == InVals[i].getValueType() && + assert(EVT(Ins[i].VT) == InVals[i].getValueType() && "LowerCall emitted a value with the wrong type!"); }); @@ -6085,7 +6315,7 @@ void SelectionDAGISel::LowerArguments(const BasicBlock *LLVMBB) { for (unsigned i = 0, e = Ins.size(); i != e; ++i) { assert(InVals[i].getNode() && "LowerFormalArguments emitted a null value!"); - assert(Ins[i].VT == InVals[i].getValueType() && + assert(EVT(Ins[i].VT) == InVals[i].getValueType() && "LowerFormalArguments emitted a value with the wrong type!"); } }); @@ -6154,7 +6384,7 @@ void SelectionDAGISel::LowerArguments(const BasicBlock *LLVMBB) { // Note down frame index for byval arguments. if (I->hasByValAttr() && !ArgValues.empty()) - if (FrameIndexSDNode *FI = + if (FrameIndexSDNode *FI = dyn_cast(ArgValues[0].getNode())) FuncInfo->setByValArgumentFrameIndex(I, FI->getIndex()); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h index 5f400e9c83ac..a1a70c394a51 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h @@ -258,15 +258,16 @@ private: struct BitTestBlock { BitTestBlock(APInt F, APInt R, const Value* SV, - unsigned Rg, bool E, + unsigned Rg, EVT RgVT, bool E, MachineBasicBlock* P, MachineBasicBlock* D, const BitTestInfo& C): - First(F), Range(R), SValue(SV), Reg(Rg), Emitted(E), + First(F), Range(R), SValue(SV), Reg(Rg), RegVT(RgVT), Emitted(E), Parent(P), Default(D), Cases(C) { } APInt First; APInt Range; const Value *SValue; unsigned Reg; + EVT RegVT; bool Emitted; MachineBasicBlock *Parent; MachineBasicBlock *Default; @@ -347,7 +348,7 @@ public: SDValue getControlRoot(); DebugLoc getCurDebugLoc() const { return CurDebugLoc; } - + void setCurDebugLoc(DebugLoc dl){ CurDebugLoc = dl; } unsigned getSDNodeOrder() const { return SDNodeOrder; } void CopyValueToVirtualRegister(const Value *V, unsigned Reg); @@ -398,6 +399,10 @@ public: void LowerCallTo(ImmutableCallSite CS, SDValue Callee, bool IsTailCall, MachineBasicBlock *LandingPad = NULL); + /// UpdateSplitBlock - When an MBB was split during scheduling, update the + /// references that ned to refer to the last resulting block. + void UpdateSplitBlock(MachineBasicBlock *First, MachineBasicBlock *Last); + private: // Terminator instructions. void visitRet(const ReturnInst &I); @@ -431,7 +436,8 @@ public: void visitSwitchCase(CaseBlock &CB, MachineBasicBlock *SwitchBB); void visitBitTestHeader(BitTestBlock &B, MachineBasicBlock *SwitchBB); - void visitBitTestCase(MachineBasicBlock* NextMBB, + void visitBitTestCase(BitTestBlock &BB, + MachineBasicBlock* NextMBB, unsigned Reg, BitTestCase &B, MachineBasicBlock *SwitchBB); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 66cb5ceb09e5..62ebc81ef86e 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -43,6 +43,7 @@ #include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" @@ -53,8 +54,17 @@ using namespace llvm; STATISTIC(NumFastIselFailures, "Number of instructions fast isel failed on"); +STATISTIC(NumFastIselBlocks, "Number of blocks selected entirely by fast isel"); +STATISTIC(NumDAGBlocks, "Number of blocks selected using DAG"); STATISTIC(NumDAGIselRetries,"Number of times dag isel has to try another path"); +#ifndef NDEBUG +STATISTIC(NumBBWithOutOfOrderLineInfo, + "Number of blocks with out of order line number info"); +STATISTIC(NumMBBWithOutOfOrderLineInfo, + "Number of machine blocks with out of order line number info"); +#endif + static cl::opt EnableFastISelVerbose("fast-isel-verbose", cl::Hidden, cl::desc("Enable verbose messages in the \"fast\" " @@ -170,15 +180,18 @@ TargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, // SelectionDAGISel code //===----------------------------------------------------------------------===// -SelectionDAGISel::SelectionDAGISel(const TargetMachine &tm, CodeGenOpt::Level OL) : +SelectionDAGISel::SelectionDAGISel(const TargetMachine &tm, + CodeGenOpt::Level OL) : MachineFunctionPass(ID), TM(tm), TLI(*tm.getTargetLowering()), FuncInfo(new FunctionLoweringInfo(TLI)), CurDAG(new SelectionDAG(tm)), SDB(new SelectionDAGBuilder(*CurDAG, *FuncInfo, OL)), GFI(), OptLevel(OL), - DAGSize(0) -{} + DAGSize(0) { + initializeGCModuleInfoPass(*PassRegistry::getPassRegistry()); + initializeAliasAnalysisAnalysisGroup(*PassRegistry::getPassRegistry()); + } SelectionDAGISel::~SelectionDAGISel() { delete SDB; @@ -202,6 +215,7 @@ void SelectionDAGISel::getAnalysisUsage(AnalysisUsage &AU) const { static bool FunctionCallsSetJmp(const Function *F) { const Module *M = F->getParent(); static const char *ReturnsTwiceFns[] = { + "_setjmp", "setjmp", "sigsetjmp", "setjmp_syscall", @@ -227,6 +241,44 @@ static bool FunctionCallsSetJmp(const Function *F) { #undef NUM_RETURNS_TWICE_FNS } +/// SplitCriticalSideEffectEdges - Look for critical edges with a PHI value that +/// may trap on it. In this case we have to split the edge so that the path +/// through the predecessor block that doesn't go to the phi block doesn't +/// execute the possibly trapping instruction. +/// +/// This is required for correctness, so it must be done at -O0. +/// +static void SplitCriticalSideEffectEdges(Function &Fn, Pass *SDISel) { + // Loop for blocks with phi nodes. + for (Function::iterator BB = Fn.begin(), E = Fn.end(); BB != E; ++BB) { + PHINode *PN = dyn_cast(BB->begin()); + if (PN == 0) continue; + + ReprocessBlock: + // For each block with a PHI node, check to see if any of the input values + // are potentially trapping constant expressions. Constant expressions are + // the only potentially trapping value that can occur as the argument to a + // PHI. + for (BasicBlock::iterator I = BB->begin(); (PN = dyn_cast(I)); ++I) + for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { + ConstantExpr *CE = dyn_cast(PN->getIncomingValue(i)); + if (CE == 0 || !CE->canTrap()) continue; + + // The only case we have to worry about is when the edge is critical. + // Since this block has a PHI Node, we assume it has multiple input + // edges: check to see if the pred has multiple successors. + BasicBlock *Pred = PN->getIncomingBlock(i); + if (Pred->getTerminator()->getNumSuccessors() == 1) + continue; + + // Okay, we have to split this edge. + SplitCriticalEdge(Pred->getTerminator(), + GetSuccessorNumber(Pred, BB), SDISel, true); + goto ReprocessBlock; + } + } +} + bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) { // Do some sanity-checking on the command-line options. assert((!EnableFastISelVerbose || EnableFastISel) && @@ -245,6 +297,8 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) { DEBUG(dbgs() << "\n\n\n=== " << Fn.getName() << "\n"); + SplitCriticalSideEffectEdges(const_cast(Fn), this); + CurDAG->init(*MF); FuncInfo->set(Fn, *MF); SDB->init(GFI, *AA); @@ -261,7 +315,7 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) { if (!FuncInfo->ArgDbgValues.empty()) for (MachineRegisterInfo::livein_iterator LI = RegInfo->livein_begin(), E = RegInfo->livein_end(); LI != E; ++LI) - if (LI->second) + if (LI->second) LiveInMap.insert(std::make_pair(LI->first, LI->second)); // Insert DBG_VALUE instructions for function arguments to the entry block. @@ -282,14 +336,37 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) { if (LDI != LiveInMap.end()) { MachineInstr *Def = RegInfo->getVRegDef(LDI->second); MachineBasicBlock::iterator InsertPos = Def; - const MDNode *Variable = + const MDNode *Variable = MI->getOperand(MI->getNumOperands()-1).getMetadata(); unsigned Offset = MI->getOperand(1).getImm(); // Def is never a terminator here, so it is ok to increment InsertPos. - BuildMI(*EntryMBB, ++InsertPos, MI->getDebugLoc(), + BuildMI(*EntryMBB, ++InsertPos, MI->getDebugLoc(), TII.get(TargetOpcode::DBG_VALUE)) .addReg(LDI->second, RegState::Debug) .addImm(Offset).addMetadata(Variable); + + // If this vreg is directly copied into an exported register then + // that COPY instructions also need DBG_VALUE, if it is the only + // user of LDI->second. + MachineInstr *CopyUseMI = NULL; + for (MachineRegisterInfo::use_iterator + UI = RegInfo->use_begin(LDI->second); + MachineInstr *UseMI = UI.skipInstruction();) { + if (UseMI->isDebugValue()) continue; + if (UseMI->isCopy() && !CopyUseMI && UseMI->getParent() == EntryMBB) { + CopyUseMI = UseMI; continue; + } + // Otherwise this is another use or second copy use. + CopyUseMI = NULL; break; + } + if (CopyUseMI) { + MachineInstr *NewMI = + BuildMI(*MF, CopyUseMI->getDebugLoc(), + TII.get(TargetOpcode::DBG_VALUE)) + .addReg(CopyUseMI->getOperand(0).getReg(), RegState::Debug) + .addImm(Offset).addMetadata(Variable); + EntryMBB->insertAfter(CopyUseMI, NewMI); + } } } @@ -303,10 +380,8 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) { II = MBB->begin(), IE = MBB->end(); II != IE; ++II) { const TargetInstrDesc &TID = TM.getInstrInfo()->get(II->getOpcode()); - // Operand 1 of an inline asm instruction indicates whether the asm - // needs stack or not. - if ((II->isInlineAsm() && II->getOperand(1).getImm()) || - (TID.isCall() && !TID.isReturn())) { + if ((TID.isCall() && !TID.isReturn()) || + II->isStackAligningInlineAsm()) { MFI->setHasCalls(true); goto done; } @@ -362,6 +437,7 @@ SelectionDAGISel::SelectBasicBlock(BasicBlock::const_iterator Begin, // Final step, emit the lowered DAG as machine code. CodeGenAndEmitDAG(); + return; } void SelectionDAGISel::ComputeLiveOutVRegInfo() { @@ -406,9 +482,7 @@ void SelectionDAGISel::ComputeLiveOutVRegInfo() { // Only install this information if it tells us something. if (NumSignBits != 1 || KnownZero != 0 || KnownOne != 0) { - DestReg -= TargetRegisterInfo::FirstVirtualRegister; - if (DestReg >= FuncInfo->LiveOutRegInfo.size()) - FuncInfo->LiveOutRegInfo.resize(DestReg+1); + FuncInfo->LiveOutRegInfo.grow(DestReg); FunctionLoweringInfo::LiveOutInfo &LOI = FuncInfo->LiveOutRegInfo[DestReg]; LOI.NumSignBits = NumSignBits; @@ -541,13 +615,19 @@ void SelectionDAGISel::CodeGenAndEmitDAG() { // Emit machine code to BB. This can change 'BB' to the last block being // inserted into. + MachineBasicBlock *FirstMBB = FuncInfo->MBB, *LastMBB; { NamedRegionTimer T("Instruction Creation", GroupName, TimePassesIsEnabled); - FuncInfo->MBB = Scheduler->EmitSchedule(); + LastMBB = FuncInfo->MBB = Scheduler->EmitSchedule(); FuncInfo->InsertPt = Scheduler->InsertPos; } + // If the block was split, make sure we update any references that are used to + // update PHI nodes later on. + if (FirstMBB != LastMBB) + SDB->UpdateSplitBlock(FirstMBB, LastMBB); + // Free the scheduler state. { NamedRegionTimer T("Instruction Scheduling Cleanup", GroupName, @@ -563,19 +643,19 @@ void SelectionDAGISel::DoInstructionSelection() { DEBUG(errs() << "===== Instruction selection begins:\n"); PreprocessISelDAG(); - + // Select target instructions for the DAG. { // Number all nodes with a topological order and set DAGSize. DAGSize = CurDAG->AssignTopologicalOrder(); - + // Create a dummy node (which is not added to allnodes), that adds // a reference to the root node, preventing it from being deleted, // and tracking any changes of the root. HandleSDNode Dummy(CurDAG->getRoot()); ISelPosition = SelectionDAG::allnodes_iterator(CurDAG->getRoot().getNode()); ++ISelPosition; - + // The AllNodes list is now topological-sorted. Visit the // nodes by starting at the end of the list (the root of the // graph) and preceding back toward the beginning (the entry @@ -587,19 +667,19 @@ void SelectionDAGISel::DoInstructionSelection() { // makes it theoretically possible to disable the DAGCombiner. if (Node->use_empty()) continue; - + SDNode *ResNode = Select(Node); - + // FIXME: This is pretty gross. 'Select' should be changed to not return // anything at all and this code should be nuked with a tactical strike. - + // If node should not be replaced, continue with the next one. if (ResNode == Node || Node->getOpcode() == ISD::DELETED_NODE) continue; // Replace node. if (ResNode) ReplaceUses(Node, ResNode); - + // If after the replacement this node is not used any more, // remove this dead node. if (Node->use_empty()) { // Don't delete EntryToken, etc. @@ -607,9 +687,9 @@ void SelectionDAGISel::DoInstructionSelection() { CurDAG->RemoveDeadNode(Node, &ISU); } } - + CurDAG->setRoot(Dummy.getValue()); - } + } DEBUG(errs() << "===== Instruction selection ends:\n"); @@ -661,6 +741,90 @@ void SelectionDAGISel::PrepareEHLandingPad() { } } + + + +bool SelectionDAGISel::TryToFoldFastISelLoad(const LoadInst *LI, + FastISel *FastIS) { + // Don't try to fold volatile loads. Target has to deal with alignment + // constraints. + if (LI->isVolatile()) return false; + + // Figure out which vreg this is going into. + unsigned LoadReg = FastIS->getRegForValue(LI); + assert(LoadReg && "Load isn't already assigned a vreg? "); + + // Check to see what the uses of this vreg are. If it has no uses, or more + // than one use (at the machine instr level) then we can't fold it. + MachineRegisterInfo::reg_iterator RI = RegInfo->reg_begin(LoadReg); + if (RI == RegInfo->reg_end()) + return false; + + // See if there is exactly one use of the vreg. If there are multiple uses, + // then the instruction got lowered to multiple machine instructions or the + // use of the loaded value ended up being multiple operands of the result, in + // either case, we can't fold this. + MachineRegisterInfo::reg_iterator PostRI = RI; ++PostRI; + if (PostRI != RegInfo->reg_end()) + return false; + + assert(RI.getOperand().isUse() && + "The only use of the vreg must be a use, we haven't emitted the def!"); + + MachineInstr *User = &*RI; + + // Set the insertion point properly. Folding the load can cause generation of + // other random instructions (like sign extends) for addressing modes, make + // sure they get inserted in a logical place before the new instruction. + FuncInfo->InsertPt = User; + FuncInfo->MBB = User->getParent(); + + // Ask the target to try folding the load. + return FastIS->TryToFoldLoad(User, RI.getOperandNo(), LI); +} + +#ifndef NDEBUG +/// CheckLineNumbers - Check if basic block instructions follow source order +/// or not. +static void CheckLineNumbers(const BasicBlock *BB) { + unsigned Line = 0; + unsigned Col = 0; + for (BasicBlock::const_iterator BI = BB->begin(), + BE = BB->end(); BI != BE; ++BI) { + const DebugLoc DL = BI->getDebugLoc(); + if (DL.isUnknown()) continue; + unsigned L = DL.getLine(); + unsigned C = DL.getCol(); + if (L < Line || (L == Line && C < Col)) { + ++NumBBWithOutOfOrderLineInfo; + return; + } + Line = L; + Col = C; + } +} + +/// CheckLineNumbers - Check if machine basic block instructions follow source +/// order or not. +static void CheckLineNumbers(const MachineBasicBlock *MBB) { + unsigned Line = 0; + unsigned Col = 0; + for (MachineBasicBlock::const_iterator MBI = MBB->begin(), + MBE = MBB->end(); MBI != MBE; ++MBI) { + const DebugLoc DL = MBI->getDebugLoc(); + if (DL.isUnknown()) continue; + unsigned L = DL.getLine(); + unsigned C = DL.getCol(); + if (L < Line || (L == Line && C < Col)) { + ++NumMBBWithOutOfOrderLineInfo; + return; + } + Line = L; + Col = C; + } +} +#endif + void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) { // Initialize the Fast-ISel state, if needed. FastISel *FastIS = 0; @@ -670,6 +834,9 @@ void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) { // Iterate over all basic blocks in the function. for (Function::const_iterator I = Fn.begin(), E = Fn.end(); I != E; ++I) { const BasicBlock *LLVMBB = &*I; +#ifndef NDEBUG + CheckLineNumbers(LLVMBB); +#endif FuncInfo->MBB = FuncInfo->MBBMap[LLVMBB]; FuncInfo->InsertPt = FuncInfo->MBB->getFirstNonPHI(); @@ -682,10 +849,19 @@ void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) { // Setup an EH landing-pad block. if (FuncInfo->MBB->isLandingPad()) PrepareEHLandingPad(); - + // Lower any arguments needed in this block if this is the entry block. - if (LLVMBB == &Fn.getEntryBlock()) + if (LLVMBB == &Fn.getEntryBlock()) { + for (BasicBlock::const_iterator DBI = LLVMBB->begin(), DBE = LLVMBB->end(); + DBI != DBE; ++DBI) { + if (const DbgInfoIntrinsic *DI = dyn_cast(DBI)) { + const DebugLoc DL = DI->getDebugLoc(); + SDB->setCurDebugLoc(DL); + break; + } + } LowerArguments(LLVMBB); + } // Before doing SelectionDAG ISel, see if FastISel has been requested. if (FastIS) { @@ -723,8 +899,19 @@ void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) { FastIS->recomputeInsertPt(); // Try to select the instruction with FastISel. - if (FastIS->SelectInstruction(Inst)) + if (FastIS->SelectInstruction(Inst)) { + // If fast isel succeeded, check to see if there is a single-use + // non-volatile load right before the selected instruction, and see if + // the load is used by the instruction. If so, try to fold it. + const Instruction *BeforeInst = 0; + if (Inst != Begin) + BeforeInst = llvm::prior(llvm::prior(BI)); + if (BeforeInst && isa(BeforeInst) && + BeforeInst->hasOneUse() && *BeforeInst->use_begin() == Inst && + TryToFoldFastISelLoad(cast(BeforeInst), FastIS)) + --BI; // If we succeeded, don't re-select the load. continue; + } // Then handle certain instructions as single-LLVM-Instruction blocks. if (isa(Inst)) { @@ -771,6 +958,11 @@ void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) { FastIS->recomputeInsertPt(); } + if (Begin != BI) + ++NumDAGBlocks; + else + ++NumFastIselBlocks; + // Run SelectionDAG instruction selection on the remainder of the block // not handled by FastISel. If FastISel is not run, this is the entire // block. @@ -782,6 +974,11 @@ void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) { } delete FastIS; +#ifndef NDEBUG + for (MachineFunction::const_iterator MBI = MF->begin(), MBE = MF->end(); + MBI != MBE; ++MBI) + CheckLineNumbers(MBI); +#endif } void @@ -831,12 +1028,14 @@ SelectionDAGISel::FinishBasicBlock() { FuncInfo->InsertPt = FuncInfo->MBB->end(); // Emit the code if (j+1 != ej) - SDB->visitBitTestCase(SDB->BitTestCases[i].Cases[j+1].ThisBB, + SDB->visitBitTestCase(SDB->BitTestCases[i], + SDB->BitTestCases[i].Cases[j+1].ThisBB, SDB->BitTestCases[i].Reg, SDB->BitTestCases[i].Cases[j], FuncInfo->MBB); else - SDB->visitBitTestCase(SDB->BitTestCases[i].Default, + SDB->visitBitTestCase(SDB->BitTestCases[i], + SDB->BitTestCases[i].Default, SDB->BitTestCases[i].Reg, SDB->BitTestCases[i].Cases[j], FuncInfo->MBB); @@ -951,7 +1150,7 @@ SelectionDAGISel::FinishBasicBlock() { // additional DAGs necessary. for (unsigned i = 0, e = SDB->SwitchCases.size(); i != e; ++i) { // Set the current basic block to the mbb we wish to insert the code into - MachineBasicBlock *ThisBB = FuncInfo->MBB = SDB->SwitchCases[i].ThisBB; + FuncInfo->MBB = SDB->SwitchCases[i].ThisBB; FuncInfo->InsertPt = FuncInfo->MBB->end(); // Determine the unique successors. @@ -960,13 +1159,15 @@ SelectionDAGISel::FinishBasicBlock() { if (SDB->SwitchCases[i].TrueBB != SDB->SwitchCases[i].FalseBB) Succs.push_back(SDB->SwitchCases[i].FalseBB); - // Emit the code. Note that this could result in ThisBB being split, so - // we need to check for updates. + // Emit the code. Note that this could result in FuncInfo->MBB being split. SDB->visitSwitchCase(SDB->SwitchCases[i], FuncInfo->MBB); CurDAG->setRoot(SDB->getRoot()); SDB->clear(); CodeGenAndEmitDAG(); - ThisBB = FuncInfo->MBB; + + // Remember the last block, now that any splitting is done, for use in + // populating PHI nodes in successors. + MachineBasicBlock *ThisBB = FuncInfo->MBB; // Handle any PHI nodes in successors of this chunk, as if we were coming // from the original BB before switch expansion. Note that PHI nodes can @@ -1016,10 +1217,6 @@ ScheduleDAGSDNodes *SelectionDAGISel::CreateScheduler() { return Ctor(this, OptLevel); } -ScheduleHazardRecognizer *SelectionDAGISel::CreateTargetHazardRecognizer() { - return new ScheduleHazardRecognizer(); -} - //===----------------------------------------------------------------------===// // Helper functions used by the generated instruction selector. //===----------------------------------------------------------------------===// @@ -1099,11 +1296,11 @@ SelectInlineAsmMemoryOperands(std::vector &Ops) { Ops.push_back(InOps[InlineAsm::Op_InputChain]); // 0 Ops.push_back(InOps[InlineAsm::Op_AsmString]); // 1 Ops.push_back(InOps[InlineAsm::Op_MDNode]); // 2, !srcloc - Ops.push_back(InOps[InlineAsm::Op_IsAlignStack]); // 3 + Ops.push_back(InOps[InlineAsm::Op_ExtraInfo]); // 3 (SideEffect, AlignStack) unsigned i = InlineAsm::Op_FirstOperand, e = InOps.size(); - if (InOps[e-1].getValueType() == MVT::Flag) - --e; // Don't process a flag operand if it is here. + if (InOps[e-1].getValueType() == MVT::Glue) + --e; // Don't process a glue operand if it is here. while (i != e) { unsigned Flags = cast(InOps[i])->getZExtValue(); @@ -1130,15 +1327,15 @@ SelectInlineAsmMemoryOperands(std::vector &Ops) { } } - // Add the flag input back if present. + // Add the glue input back if present. if (e != InOps.size()) Ops.push_back(InOps.back()); } -/// findFlagUse - Return use of EVT::Flag value produced by the specified +/// findGlueUse - Return use of MVT::Glue value produced by the specified /// SDNode. /// -static SDNode *findFlagUse(SDNode *N) { +static SDNode *findGlueUse(SDNode *N) { unsigned FlagResNo = N->getNumValues()-1; for (SDNode::use_iterator I = N->use_begin(), E = N->use_end(); I != E; ++I) { SDUse &Use = I.getUse(); @@ -1160,11 +1357,11 @@ static bool findNonImmUse(SDNode *Use, SDNode* Def, SDNode *ImmedUse, // never find it. // // The Use may be -1 (unassigned) if it is a newly allocated node. This can - // happen because we scan down to newly selected nodes in the case of flag + // happen because we scan down to newly selected nodes in the case of glue // uses. if ((Use->getNodeId() < Def->getNodeId() && Use->getNodeId() != -1)) return false; - + // Don't revisit nodes if we already scanned it and didn't fail, we know we // won't fail if we scan it again. if (!Visited.insert(Use)) @@ -1174,7 +1371,7 @@ static bool findNonImmUse(SDNode *Use, SDNode* Def, SDNode *ImmedUse, // Ignore chain uses, they are validated by HandleMergeInputChains. if (Use->getOperand(i).getValueType() == MVT::Other && IgnoreChains) continue; - + SDNode *N = Use->getOperand(i).getNode(); if (N == Def) { if (Use == ImmedUse || Use == Root) @@ -1221,8 +1418,8 @@ bool SelectionDAGISel::IsLegalToFold(SDValue N, SDNode *U, SDNode *Root, // // * indicates nodes to be folded together. // - // If Root produces a flag, then it gets (even more) interesting. Since it - // will be "glued" together with its flag use in the scheduler, we need to + // If Root produces glue, then it gets (even more) interesting. Since it + // will be "glued" together with its glue use in the scheduler, we need to // check if it might reach N. // // [N*] // @@ -1240,30 +1437,30 @@ bool SelectionDAGISel::IsLegalToFold(SDValue N, SDNode *U, SDNode *Root, // ^ / // // f / // // | / // - // [FU] // + // [GU] // // - // If FU (flag use) indirectly reaches N (the load), and Root folds N - // (call it Fold), then X is a predecessor of FU and a successor of - // Fold. But since Fold and FU are flagged together, this will create + // If GU (glue use) indirectly reaches N (the load), and Root folds N + // (call it Fold), then X is a predecessor of GU and a successor of + // Fold. But since Fold and GU are glued together, this will create // a cycle in the scheduling graph. - // If the node has flags, walk down the graph to the "lowest" node in the - // flagged set. + // If the node has glue, walk down the graph to the "lowest" node in the + // glueged set. EVT VT = Root->getValueType(Root->getNumValues()-1); - while (VT == MVT::Flag) { - SDNode *FU = findFlagUse(Root); - if (FU == NULL) + while (VT == MVT::Glue) { + SDNode *GU = findGlueUse(Root); + if (GU == NULL) break; - Root = FU; + Root = GU; VT = Root->getValueType(Root->getNumValues()-1); - - // If our query node has a flag result with a use, we've walked up it. If + + // If our query node has a glue result with a use, we've walked up it. If // the user (which has already been selected) has a chain or indirectly uses // the chain, our WalkChainUsers predicate will not consider it. Because of // this, we cannot ignore chains in this predicate. IgnoreChains = false; } - + SmallPtrSet Visited; return !findNonImmUse(Root, N.getNode(), U, Root, Visited, IgnoreChains); @@ -1272,10 +1469,10 @@ bool SelectionDAGISel::IsLegalToFold(SDValue N, SDNode *U, SDNode *Root, SDNode *SelectionDAGISel::Select_INLINEASM(SDNode *N) { std::vector Ops(N->op_begin(), N->op_end()); SelectInlineAsmMemoryOperands(Ops); - + std::vector VTs; VTs.push_back(MVT::Other); - VTs.push_back(MVT::Flag); + VTs.push_back(MVT::Glue); SDValue New = CurDAG->getNode(ISD::INLINEASM, N->getDebugLoc(), VTs, &Ops[0], Ops.size()); New->setNodeId(-1); @@ -1287,11 +1484,11 @@ SDNode *SelectionDAGISel::Select_UNDEF(SDNode *N) { } /// GetVBR - decode a vbr encoding whose top bit is set. -ALWAYS_INLINE static uint64_t +LLVM_ATTRIBUTE_ALWAYS_INLINE static uint64_t GetVBR(uint64_t Val, const unsigned char *MatcherTable, unsigned &Idx) { assert(Val >= 128 && "Not a VBR"); Val &= 127; // Remove first vbr bit. - + unsigned Shift = 7; uint64_t NextBits; do { @@ -1299,25 +1496,25 @@ GetVBR(uint64_t Val, const unsigned char *MatcherTable, unsigned &Idx) { Val |= (NextBits&127) << Shift; Shift += 7; } while (NextBits & 128); - + return Val; } -/// UpdateChainsAndFlags - When a match is complete, this method updates uses of -/// interior flag and chain results to use the new flag and chain results. +/// UpdateChainsAndGlue - When a match is complete, this method updates uses of +/// interior glue and chain results to use the new glue and chain results. void SelectionDAGISel:: -UpdateChainsAndFlags(SDNode *NodeToMatch, SDValue InputChain, - const SmallVectorImpl &ChainNodesMatched, - SDValue InputFlag, - const SmallVectorImpl &FlagResultNodesMatched, - bool isMorphNodeTo) { +UpdateChainsAndGlue(SDNode *NodeToMatch, SDValue InputChain, + const SmallVectorImpl &ChainNodesMatched, + SDValue InputGlue, + const SmallVectorImpl &GlueResultNodesMatched, + bool isMorphNodeTo) { SmallVector NowDeadNodes; - + ISelUpdater ISU(ISelPosition); // Now that all the normal results are replaced, we replace the chain and - // flag results if present. + // glue results if present. if (!ChainNodesMatched.empty()) { assert(InputChain.getNode() != 0 && "Matched input chains but didn't produce a chain"); @@ -1325,55 +1522,55 @@ UpdateChainsAndFlags(SDNode *NodeToMatch, SDValue InputChain, // Replace all the chain results with the final chain we ended up with. for (unsigned i = 0, e = ChainNodesMatched.size(); i != e; ++i) { SDNode *ChainNode = ChainNodesMatched[i]; - + // If this node was already deleted, don't look at it. if (ChainNode->getOpcode() == ISD::DELETED_NODE) continue; - + // Don't replace the results of the root node if we're doing a // MorphNodeTo. if (ChainNode == NodeToMatch && isMorphNodeTo) continue; - + SDValue ChainVal = SDValue(ChainNode, ChainNode->getNumValues()-1); - if (ChainVal.getValueType() == MVT::Flag) + if (ChainVal.getValueType() == MVT::Glue) ChainVal = ChainVal.getValue(ChainVal->getNumValues()-2); assert(ChainVal.getValueType() == MVT::Other && "Not a chain?"); CurDAG->ReplaceAllUsesOfValueWith(ChainVal, InputChain, &ISU); - + // If the node became dead and we haven't already seen it, delete it. if (ChainNode->use_empty() && !std::count(NowDeadNodes.begin(), NowDeadNodes.end(), ChainNode)) NowDeadNodes.push_back(ChainNode); } } - - // If the result produces a flag, update any flag results in the matched - // pattern with the flag result. - if (InputFlag.getNode() != 0) { + + // If the result produces glue, update any glue results in the matched + // pattern with the glue result. + if (InputGlue.getNode() != 0) { // Handle any interior nodes explicitly marked. - for (unsigned i = 0, e = FlagResultNodesMatched.size(); i != e; ++i) { - SDNode *FRN = FlagResultNodesMatched[i]; - + for (unsigned i = 0, e = GlueResultNodesMatched.size(); i != e; ++i) { + SDNode *FRN = GlueResultNodesMatched[i]; + // If this node was already deleted, don't look at it. if (FRN->getOpcode() == ISD::DELETED_NODE) continue; - - assert(FRN->getValueType(FRN->getNumValues()-1) == MVT::Flag && - "Doesn't have a flag result"); + + assert(FRN->getValueType(FRN->getNumValues()-1) == MVT::Glue && + "Doesn't have a glue result"); CurDAG->ReplaceAllUsesOfValueWith(SDValue(FRN, FRN->getNumValues()-1), - InputFlag, &ISU); - + InputGlue, &ISU); + // If the node became dead and we haven't already seen it, delete it. if (FRN->use_empty() && !std::count(NowDeadNodes.begin(), NowDeadNodes.end(), FRN)) NowDeadNodes.push_back(FRN); } } - + if (!NowDeadNodes.empty()) CurDAG->RemoveDeadNodes(NowDeadNodes, &ISU); - + DEBUG(errs() << "ISEL: Match complete!\n"); } @@ -1392,17 +1589,17 @@ enum ChainResult { /// /// The walk we do here is guaranteed to be small because we quickly get down to /// already selected nodes "below" us. -static ChainResult +static ChainResult WalkChainUsers(SDNode *ChainedNode, SmallVectorImpl &ChainedNodesInPattern, SmallVectorImpl &InteriorChainedNodes) { ChainResult Result = CR_Simple; - + for (SDNode::use_iterator UI = ChainedNode->use_begin(), E = ChainedNode->use_end(); UI != E; ++UI) { // Make sure the use is of the chain, not some other value we produce. if (UI.getUse().getValueType() != MVT::Other) continue; - + SDNode *User = *UI; // If we see an already-selected machine node, then we've gone beyond the @@ -1411,7 +1608,7 @@ WalkChainUsers(SDNode *ChainedNode, if (User->isMachineOpcode() || User->getOpcode() == ISD::HANDLENODE) // Root of the graph. continue; - + if (User->getOpcode() == ISD::CopyToReg || User->getOpcode() == ISD::CopyFromReg || User->getOpcode() == ISD::INLINEASM || @@ -1437,7 +1634,7 @@ WalkChainUsers(SDNode *ChainedNode, if (!std::count(ChainedNodesInPattern.begin(), ChainedNodesInPattern.end(), User)) return CR_InducesCycle; - + // Otherwise we found a node that is part of our pattern. For example in: // x = load ptr // y = x+4 @@ -1449,7 +1646,7 @@ WalkChainUsers(SDNode *ChainedNode, InteriorChainedNodes.push_back(User); continue; } - + // If we found a TokenFactor, there are two cases to consider: first if the // TokenFactor is just hanging "below" the pattern we're matching (i.e. no // uses of the TF are in our pattern) we just want to ignore it. Second, @@ -1486,7 +1683,7 @@ WalkChainUsers(SDNode *ChainedNode, case CR_LeadsToInteriorNode: break; // Otherwise, keep processing. } - + // Okay, we know we're in the interesting interior case. The TokenFactor // is now going to be considered part of the pattern so that we rewrite its // uses (it may have uses that are not part of the pattern) with the @@ -1497,7 +1694,7 @@ WalkChainUsers(SDNode *ChainedNode, InteriorChainedNodes.push_back(User); continue; } - + return Result; } @@ -1519,7 +1716,7 @@ HandleMergeInputChains(SmallVectorImpl &ChainNodesMatched, InteriorChainedNodes) == CR_InducesCycle) return SDValue(); // Would induce a cycle. } - + // Okay, we have walked all the matched nodes and collected TokenFactor nodes // that we are interested in. Form our input TokenFactor node. SmallVector InputChains; @@ -1530,14 +1727,14 @@ HandleMergeInputChains(SmallVectorImpl &ChainNodesMatched, if (N->getOpcode() != ISD::TokenFactor) { if (std::count(InteriorChainedNodes.begin(),InteriorChainedNodes.end(),N)) continue; - + // Otherwise, add the input chain. SDValue InChain = ChainNodesMatched[i]->getOperand(0); assert(InChain.getValueType() == MVT::Other && "Not a chain"); InputChains.push_back(InChain); continue; } - + // If we have a token factor, we want to add all inputs of the token factor // that are not part of the pattern we're matching. for (unsigned op = 0, e = N->getNumOperands(); op != e; ++op) { @@ -1546,13 +1743,13 @@ HandleMergeInputChains(SmallVectorImpl &ChainNodesMatched, InputChains.push_back(N->getOperand(op)); } } - + SDValue Res; if (InputChains.size() == 1) return InputChains[0]; return CurDAG->getNode(ISD::TokenFactor, ChainNodesMatched[0]->getDebugLoc(), MVT::Other, &InputChains[0], InputChains.size()); -} +} /// MorphNode - Handle morphing a node in place for the selector. SDNode *SelectionDAGISel:: @@ -1560,15 +1757,15 @@ MorphNode(SDNode *Node, unsigned TargetOpc, SDVTList VTList, const SDValue *Ops, unsigned NumOps, unsigned EmitNodeInfo) { // It is possible we're using MorphNodeTo to replace a node with no // normal results with one that has a normal result (or we could be - // adding a chain) and the input could have flags and chains as well. + // adding a chain) and the input could have glue and chains as well. // In this case we need to shift the operands down. // FIXME: This is a horrible hack and broken in obscure cases, no worse // than the old isel though. - int OldFlagResultNo = -1, OldChainResultNo = -1; + int OldGlueResultNo = -1, OldChainResultNo = -1; unsigned NTMNumResults = Node->getNumValues(); - if (Node->getValueType(NTMNumResults-1) == MVT::Flag) { - OldFlagResultNo = NTMNumResults-1; + if (Node->getValueType(NTMNumResults-1) == MVT::Glue) { + OldGlueResultNo = NTMNumResults-1; if (NTMNumResults != 1 && Node->getValueType(NTMNumResults-2) == MVT::Other) OldChainResultNo = NTMNumResults-2; @@ -1589,54 +1786,55 @@ MorphNode(SDNode *Node, unsigned TargetOpc, SDVTList VTList, } unsigned ResNumResults = Res->getNumValues(); - // Move the flag if needed. - if ((EmitNodeInfo & OPFL_FlagOutput) && OldFlagResultNo != -1 && - (unsigned)OldFlagResultNo != ResNumResults-1) - CurDAG->ReplaceAllUsesOfValueWith(SDValue(Node, OldFlagResultNo), + // Move the glue if needed. + if ((EmitNodeInfo & OPFL_GlueOutput) && OldGlueResultNo != -1 && + (unsigned)OldGlueResultNo != ResNumResults-1) + CurDAG->ReplaceAllUsesOfValueWith(SDValue(Node, OldGlueResultNo), SDValue(Res, ResNumResults-1)); - if ((EmitNodeInfo & OPFL_FlagOutput) != 0) + if ((EmitNodeInfo & OPFL_GlueOutput) != 0) --ResNumResults; // Move the chain reference if needed. if ((EmitNodeInfo & OPFL_Chain) && OldChainResultNo != -1 && (unsigned)OldChainResultNo != ResNumResults-1) - CurDAG->ReplaceAllUsesOfValueWith(SDValue(Node, OldChainResultNo), + CurDAG->ReplaceAllUsesOfValueWith(SDValue(Node, OldChainResultNo), SDValue(Res, ResNumResults-1)); // Otherwise, no replacement happened because the node already exists. Replace // Uses of the old node with the new one. if (Res != Node) CurDAG->ReplaceAllUsesWith(Node, Res); - + return Res; } /// CheckPatternPredicate - Implements OP_CheckPatternPredicate. -ALWAYS_INLINE static bool +LLVM_ATTRIBUTE_ALWAYS_INLINE static bool CheckSame(const unsigned char *MatcherTable, unsigned &MatcherIndex, - SDValue N, const SmallVectorImpl &RecordedNodes) { + SDValue N, + const SmallVectorImpl > &RecordedNodes) { // Accept if it is exactly the same as a previously recorded node. unsigned RecNo = MatcherTable[MatcherIndex++]; assert(RecNo < RecordedNodes.size() && "Invalid CheckSame"); - return N == RecordedNodes[RecNo]; + return N == RecordedNodes[RecNo].first; } - + /// CheckPatternPredicate - Implements OP_CheckPatternPredicate. -ALWAYS_INLINE static bool +LLVM_ATTRIBUTE_ALWAYS_INLINE static bool CheckPatternPredicate(const unsigned char *MatcherTable, unsigned &MatcherIndex, SelectionDAGISel &SDISel) { return SDISel.CheckPatternPredicate(MatcherTable[MatcherIndex++]); } /// CheckNodePredicate - Implements OP_CheckNodePredicate. -ALWAYS_INLINE static bool +LLVM_ATTRIBUTE_ALWAYS_INLINE static bool CheckNodePredicate(const unsigned char *MatcherTable, unsigned &MatcherIndex, SelectionDAGISel &SDISel, SDNode *N) { return SDISel.CheckNodePredicate(N, MatcherTable[MatcherIndex++]); } -ALWAYS_INLINE static bool +LLVM_ATTRIBUTE_ALWAYS_INLINE static bool CheckOpcode(const unsigned char *MatcherTable, unsigned &MatcherIndex, SDNode *N) { uint16_t Opc = MatcherTable[MatcherIndex++]; @@ -1644,17 +1842,17 @@ CheckOpcode(const unsigned char *MatcherTable, unsigned &MatcherIndex, return N->getOpcode() == Opc; } -ALWAYS_INLINE static bool +LLVM_ATTRIBUTE_ALWAYS_INLINE static bool CheckType(const unsigned char *MatcherTable, unsigned &MatcherIndex, SDValue N, const TargetLowering &TLI) { MVT::SimpleValueType VT = (MVT::SimpleValueType)MatcherTable[MatcherIndex++]; if (N.getValueType() == VT) return true; - + // Handle the case when VT is iPTR. return VT == MVT::iPTR && N.getValueType() == TLI.getPointerTy(); } -ALWAYS_INLINE static bool +LLVM_ATTRIBUTE_ALWAYS_INLINE static bool CheckChildType(const unsigned char *MatcherTable, unsigned &MatcherIndex, SDValue N, const TargetLowering &TLI, unsigned ChildNo) { @@ -1664,57 +1862,57 @@ CheckChildType(const unsigned char *MatcherTable, unsigned &MatcherIndex, } -ALWAYS_INLINE static bool +LLVM_ATTRIBUTE_ALWAYS_INLINE static bool CheckCondCode(const unsigned char *MatcherTable, unsigned &MatcherIndex, SDValue N) { return cast(N)->get() == (ISD::CondCode)MatcherTable[MatcherIndex++]; } -ALWAYS_INLINE static bool +LLVM_ATTRIBUTE_ALWAYS_INLINE static bool CheckValueType(const unsigned char *MatcherTable, unsigned &MatcherIndex, SDValue N, const TargetLowering &TLI) { MVT::SimpleValueType VT = (MVT::SimpleValueType)MatcherTable[MatcherIndex++]; if (cast(N)->getVT() == VT) return true; - + // Handle the case when VT is iPTR. return VT == MVT::iPTR && cast(N)->getVT() == TLI.getPointerTy(); } -ALWAYS_INLINE static bool +LLVM_ATTRIBUTE_ALWAYS_INLINE static bool CheckInteger(const unsigned char *MatcherTable, unsigned &MatcherIndex, SDValue N) { int64_t Val = MatcherTable[MatcherIndex++]; if (Val & 128) Val = GetVBR(Val, MatcherTable, MatcherIndex); - + ConstantSDNode *C = dyn_cast(N); return C != 0 && C->getSExtValue() == Val; } -ALWAYS_INLINE static bool +LLVM_ATTRIBUTE_ALWAYS_INLINE static bool CheckAndImm(const unsigned char *MatcherTable, unsigned &MatcherIndex, SDValue N, SelectionDAGISel &SDISel) { int64_t Val = MatcherTable[MatcherIndex++]; if (Val & 128) Val = GetVBR(Val, MatcherTable, MatcherIndex); - + if (N->getOpcode() != ISD::AND) return false; - + ConstantSDNode *C = dyn_cast(N->getOperand(1)); return C != 0 && SDISel.CheckAndMask(N.getOperand(0), C, Val); } -ALWAYS_INLINE static bool +LLVM_ATTRIBUTE_ALWAYS_INLINE static bool CheckOrImm(const unsigned char *MatcherTable, unsigned &MatcherIndex, SDValue N, SelectionDAGISel &SDISel) { int64_t Val = MatcherTable[MatcherIndex++]; if (Val & 128) Val = GetVBR(Val, MatcherTable, MatcherIndex); - + if (N->getOpcode() != ISD::OR) return false; - + ConstantSDNode *C = dyn_cast(N->getOperand(1)); return C != 0 && SDISel.CheckOrMask(N.getOperand(0), C, Val); } @@ -1724,11 +1922,11 @@ CheckOrImm(const unsigned char *MatcherTable, unsigned &MatcherIndex, /// fail, set Result=true and return anything. If the current predicate is /// known to pass, set Result=false and return the MatcherIndex to continue /// with. If the current predicate is unknown, set Result=false and return the -/// MatcherIndex to continue with. +/// MatcherIndex to continue with. static unsigned IsPredicateKnownToFail(const unsigned char *Table, unsigned Index, SDValue N, bool &Result, SelectionDAGISel &SDISel, - SmallVectorImpl &RecordedNodes){ + SmallVectorImpl > &RecordedNodes) { switch (Table[Index++]) { default: Result = false; @@ -1782,21 +1980,21 @@ namespace { struct MatchScope { /// FailIndex - If this match fails, this is the index to continue with. unsigned FailIndex; - + /// NodeStack - The node stack when the scope was formed. SmallVector NodeStack; - + /// NumRecordedNodes - The number of recorded nodes when the scope was formed. unsigned NumRecordedNodes; - + /// NumMatchedMemRefs - The number of matched memref entries. unsigned NumMatchedMemRefs; - - /// InputChain/InputFlag - The current chain/flag - SDValue InputChain, InputFlag; + + /// InputChain/InputGlue - The current chain/glue + SDValue InputChain, InputGlue; /// HasChainNodesMatched - True if the ChainNodesMatched list is non-empty. - bool HasChainNodesMatched, HasFlagResultNodesMatched; + bool HasChainNodesMatched, HasGlueResultNodesMatched; }; } @@ -1838,7 +2036,7 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, case ISD::INLINEASM: return Select_INLINEASM(NodeToMatch); case ISD::UNDEF: return Select_UNDEF(NodeToMatch); } - + assert(!NodeToMatch->isMachineOpcode() && "Node already selected!"); // Set up the node stack with NodeToMatch as the only node on the stack. @@ -1849,37 +2047,38 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, // MatchScopes - Scopes used when matching, if a match failure happens, this // indicates where to continue checking. SmallVector MatchScopes; - + // RecordedNodes - This is the set of nodes that have been recorded by the - // state machine. - SmallVector RecordedNodes; - + // state machine. The second value is the parent of the node, or null if the + // root is recorded. + SmallVector, 8> RecordedNodes; + // MatchedMemRefs - This is the set of MemRef's we've seen in the input // pattern. SmallVector MatchedMemRefs; - - // These are the current input chain and flag for use when generating nodes. + + // These are the current input chain and glue for use when generating nodes. // Various Emit operations change these. For example, emitting a copytoreg // uses and updates these. - SDValue InputChain, InputFlag; - + SDValue InputChain, InputGlue; + // ChainNodesMatched - If a pattern matches nodes that have input/output // chains, the OPC_EmitMergeInputChains operation is emitted which indicates // which ones they are. The result is captured into this list so that we can // update the chain results when the pattern is complete. SmallVector ChainNodesMatched; - SmallVector FlagResultNodesMatched; - + SmallVector GlueResultNodesMatched; + DEBUG(errs() << "ISEL: Starting pattern match on root node: "; NodeToMatch->dump(CurDAG); errs() << '\n'); - + // Determine where to start the interpreter. Normally we start at opcode #0, // but if the state machine starts with an OPC_SwitchOpcode, then we // accelerate the first lookup (which is guaranteed to be hot) with the // OpcodeOffset table. unsigned MatcherIndex = 0; - + if (!OpcodeOffset.empty()) { // Already computed the OpcodeOffset table, just index into it. if (N.getOpcode() < OpcodeOffset.size()) @@ -1911,7 +2110,7 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, if (N.getOpcode() < OpcodeOffset.size()) MatcherIndex = OpcodeOffset[N.getOpcode()]; } - + while (1) { assert(MatcherIndex < TableSize && "Invalid index"); #ifndef NDEBUG @@ -1926,7 +2125,7 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, // determine immediately that the first check (or first several) will // immediately fail, don't even bother pushing a scope for them. unsigned FailIndex; - + while (1) { unsigned NumToSkip = MatcherTable[MatcherIndex++]; if (NumToSkip & 128) @@ -1936,12 +2135,12 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, FailIndex = 0; break; } - + FailIndex = MatcherIndex+NumToSkip; - + unsigned MatcherIndexOfPredicate = MatcherIndex; (void)MatcherIndexOfPredicate; // silence warning. - + // If we can't evaluate this predicate without pushing a scope (e.g. if // it is a 'MoveParent') or if the predicate succeeds on this node, we // push the scope and evaluate the full predicate chain. @@ -1950,20 +2149,20 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, Result, *this, RecordedNodes); if (!Result) break; - + DEBUG(errs() << " Skipped scope entry (due to false predicate) at " << "index " << MatcherIndexOfPredicate << ", continuing at " << FailIndex << "\n"); ++NumDAGIselRetries; - + // Otherwise, we know that this case of the Scope is guaranteed to fail, // move to the next case. MatcherIndex = FailIndex; } - + // If the whole scope failed to match, bail. if (FailIndex == 0) break; - + // Push a MatchScope which indicates where to go if the first child fails // to match. MatchScope NewEntry; @@ -1972,17 +2171,21 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, NewEntry.NumRecordedNodes = RecordedNodes.size(); NewEntry.NumMatchedMemRefs = MatchedMemRefs.size(); NewEntry.InputChain = InputChain; - NewEntry.InputFlag = InputFlag; + NewEntry.InputGlue = InputGlue; NewEntry.HasChainNodesMatched = !ChainNodesMatched.empty(); - NewEntry.HasFlagResultNodesMatched = !FlagResultNodesMatched.empty(); + NewEntry.HasGlueResultNodesMatched = !GlueResultNodesMatched.empty(); MatchScopes.push_back(NewEntry); continue; } - case OPC_RecordNode: + case OPC_RecordNode: { // Remember this node, it may end up being an operand in the pattern. - RecordedNodes.push_back(N); + SDNode *Parent = 0; + if (NodeStack.size() > 1) + Parent = NodeStack[NodeStack.size()-2].getNode(); + RecordedNodes.push_back(std::make_pair(N, Parent)); continue; - + } + case OPC_RecordChild0: case OPC_RecordChild1: case OPC_RecordChild2: case OPC_RecordChild3: case OPC_RecordChild4: case OPC_RecordChild5: @@ -1991,20 +2194,21 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, if (ChildNo >= N.getNumOperands()) break; // Match fails if out of range child #. - RecordedNodes.push_back(N->getOperand(ChildNo)); + RecordedNodes.push_back(std::make_pair(N->getOperand(ChildNo), + N.getNode())); continue; } case OPC_RecordMemRef: MatchedMemRefs.push_back(cast(N)->getMemOperand()); continue; - - case OPC_CaptureFlagInput: - // If the current node has an input flag, capture it in InputFlag. + + case OPC_CaptureGlueInput: + // If the current node has an input glue, capture it in InputGlue. if (N->getNumOperands() != 0 && - N->getOperand(N->getNumOperands()-1).getValueType() == MVT::Flag) - InputFlag = N->getOperand(N->getNumOperands()-1); + N->getOperand(N->getNumOperands()-1).getValueType() == MVT::Glue) + InputGlue = N->getOperand(N->getNumOperands()-1); continue; - + case OPC_MoveChild: { unsigned ChildNo = MatcherTable[MatcherIndex++]; if (ChildNo >= N.getNumOperands()) @@ -2013,14 +2217,14 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, NodeStack.push_back(N); continue; } - + case OPC_MoveParent: // Pop the current node off the NodeStack. NodeStack.pop_back(); assert(!NodeStack.empty() && "Node stack imbalance!"); - N = NodeStack.back(); + N = NodeStack.back(); continue; - + case OPC_CheckSame: if (!::CheckSame(MatcherTable, MatcherIndex, N, RecordedNodes)) break; continue; @@ -2036,7 +2240,8 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, unsigned CPNum = MatcherTable[MatcherIndex++]; unsigned RecNo = MatcherTable[MatcherIndex++]; assert(RecNo < RecordedNodes.size() && "Invalid CheckComplexPat"); - if (!CheckComplexPattern(NodeToMatch, RecordedNodes[RecNo], CPNum, + if (!CheckComplexPattern(NodeToMatch, RecordedNodes[RecNo].second, + RecordedNodes[RecNo].first, CPNum, RecordedNodes)) break; continue; @@ -2044,11 +2249,11 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, case OPC_CheckOpcode: if (!::CheckOpcode(MatcherTable, MatcherIndex, N.getNode())) break; continue; - + case OPC_CheckType: if (!::CheckType(MatcherTable, MatcherIndex, N, TLI)) break; continue; - + case OPC_SwitchOpcode: { unsigned CurNodeOpcode = N.getOpcode(); unsigned SwitchStart = MatcherIndex-1; (void)SwitchStart; @@ -2066,22 +2271,22 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, // If the opcode matches, then we will execute this case. if (CurNodeOpcode == Opc) break; - + // Otherwise, skip over this case. MatcherIndex += CaseSize; } - + // If no cases matched, bail out. if (CaseSize == 0) break; - + // Otherwise, execute the case we found. DEBUG(errs() << " OpcodeSwitch from " << SwitchStart << " to " << MatcherIndex << "\n"); continue; } - + case OPC_SwitchType: { - MVT::SimpleValueType CurNodeVT = N.getValueType().getSimpleVT().SimpleTy; + MVT CurNodeVT = N.getValueType().getSimpleVT(); unsigned SwitchStart = MatcherIndex-1; (void)SwitchStart; unsigned CaseSize; while (1) { @@ -2090,23 +2295,22 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, if (CaseSize & 128) CaseSize = GetVBR(CaseSize, MatcherTable, MatcherIndex); if (CaseSize == 0) break; - - MVT::SimpleValueType CaseVT = - (MVT::SimpleValueType)MatcherTable[MatcherIndex++]; + + MVT CaseVT = (MVT::SimpleValueType)MatcherTable[MatcherIndex++]; if (CaseVT == MVT::iPTR) - CaseVT = TLI.getPointerTy().SimpleTy; - + CaseVT = TLI.getPointerTy(); + // If the VT matches, then we will execute this case. if (CurNodeVT == CaseVT) break; - + // Otherwise, skip over this case. MatcherIndex += CaseSize; } - + // If no cases matched, bail out. if (CaseSize == 0) break; - + // Otherwise, execute the case we found. DEBUG(errs() << " TypeSwitch[" << EVT(CurNodeVT).getEVTString() << "] from " << SwitchStart << " to " << MatcherIndex<<'\n'); @@ -2135,7 +2339,7 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, case OPC_CheckOrImm: if (!::CheckOrImm(MatcherTable, MatcherIndex, N, *this)) break; continue; - + case OPC_CheckFoldableChainNode: { assert(NodeStack.size() != 1 && "No parent node"); // Verify that all intermediate nodes between the root and this one have @@ -2156,7 +2360,7 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, NodeToMatch, OptLevel, true/*We validate our own chains*/)) break; - + continue; } case OPC_EmitInteger: { @@ -2165,22 +2369,24 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, int64_t Val = MatcherTable[MatcherIndex++]; if (Val & 128) Val = GetVBR(Val, MatcherTable, MatcherIndex); - RecordedNodes.push_back(CurDAG->getTargetConstant(Val, VT)); + RecordedNodes.push_back(std::pair( + CurDAG->getTargetConstant(Val, VT), (SDNode*)0)); continue; } case OPC_EmitRegister: { MVT::SimpleValueType VT = (MVT::SimpleValueType)MatcherTable[MatcherIndex++]; unsigned RegNo = MatcherTable[MatcherIndex++]; - RecordedNodes.push_back(CurDAG->getRegister(RegNo, VT)); + RecordedNodes.push_back(std::pair( + CurDAG->getRegister(RegNo, VT), (SDNode*)0)); continue; } - + case OPC_EmitConvertToTarget: { // Convert from IMM/FPIMM to target version. unsigned RecNo = MatcherTable[MatcherIndex++]; assert(RecNo < RecordedNodes.size() && "Invalid CheckSame"); - SDValue Imm = RecordedNodes[RecNo]; + SDValue Imm = RecordedNodes[RecNo].first; if (Imm->getOpcode() == ISD::Constant) { int64_t Val = cast(Imm)->getZExtValue(); @@ -2189,11 +2395,11 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, const ConstantFP *Val=cast(Imm)->getConstantFPValue(); Imm = CurDAG->getTargetConstantFP(*Val, Imm.getValueType()); } - - RecordedNodes.push_back(Imm); + + RecordedNodes.push_back(std::make_pair(Imm, RecordedNodes[RecNo].second)); continue; } - + case OPC_EmitMergeInputChains1_0: // OPC_EmitMergeInputChains, 1, 0 case OPC_EmitMergeInputChains1_1: { // OPC_EmitMergeInputChains, 1, 1 // These are space-optimized forms of OPC_EmitMergeInputChains. @@ -2201,28 +2407,28 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, "EmitMergeInputChains should be the first chain producing node"); assert(ChainNodesMatched.empty() && "Should only have one EmitMergeInputChains per match"); - + // Read all of the chained nodes. unsigned RecNo = Opcode == OPC_EmitMergeInputChains1_1; assert(RecNo < RecordedNodes.size() && "Invalid CheckSame"); - ChainNodesMatched.push_back(RecordedNodes[RecNo].getNode()); - + ChainNodesMatched.push_back(RecordedNodes[RecNo].first.getNode()); + // FIXME: What if other value results of the node have uses not matched // by this pattern? if (ChainNodesMatched.back() != NodeToMatch && - !RecordedNodes[RecNo].hasOneUse()) { + !RecordedNodes[RecNo].first.hasOneUse()) { ChainNodesMatched.clear(); break; } - + // Merge the input chains if they are not intra-pattern references. InputChain = HandleMergeInputChains(ChainNodesMatched, CurDAG); - + if (InputChain.getNode() == 0) break; // Failed to merge. continue; } - + case OPC_EmitMergeInputChains: { assert(InputChain.getNode() == 0 && "EmitMergeInputChains should be the first chain producing node"); @@ -2242,54 +2448,55 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, for (unsigned i = 0; i != NumChains; ++i) { unsigned RecNo = MatcherTable[MatcherIndex++]; assert(RecNo < RecordedNodes.size() && "Invalid CheckSame"); - ChainNodesMatched.push_back(RecordedNodes[RecNo].getNode()); - + ChainNodesMatched.push_back(RecordedNodes[RecNo].first.getNode()); + // FIXME: What if other value results of the node have uses not matched // by this pattern? if (ChainNodesMatched.back() != NodeToMatch && - !RecordedNodes[RecNo].hasOneUse()) { + !RecordedNodes[RecNo].first.hasOneUse()) { ChainNodesMatched.clear(); break; } } - + // If the inner loop broke out, the match fails. if (ChainNodesMatched.empty()) break; // Merge the input chains if they are not intra-pattern references. InputChain = HandleMergeInputChains(ChainNodesMatched, CurDAG); - + if (InputChain.getNode() == 0) break; // Failed to merge. continue; } - + case OPC_EmitCopyToReg: { unsigned RecNo = MatcherTable[MatcherIndex++]; assert(RecNo < RecordedNodes.size() && "Invalid CheckSame"); unsigned DestPhysReg = MatcherTable[MatcherIndex++]; - + if (InputChain.getNode() == 0) InputChain = CurDAG->getEntryNode(); - + InputChain = CurDAG->getCopyToReg(InputChain, NodeToMatch->getDebugLoc(), - DestPhysReg, RecordedNodes[RecNo], - InputFlag); - - InputFlag = InputChain.getValue(1); + DestPhysReg, RecordedNodes[RecNo].first, + InputGlue); + + InputGlue = InputChain.getValue(1); continue; } - + case OPC_EmitNodeXForm: { unsigned XFormNo = MatcherTable[MatcherIndex++]; unsigned RecNo = MatcherTable[MatcherIndex++]; assert(RecNo < RecordedNodes.size() && "Invalid CheckSame"); - RecordedNodes.push_back(RunSDNodeXForm(RecordedNodes[RecNo], XFormNo)); + SDValue Res = RunSDNodeXForm(RecordedNodes[RecNo].first, XFormNo); + RecordedNodes.push_back(std::pair(Res, (SDNode*) 0)); continue; } - + case OPC_EmitNode: case OPC_MorphNodeTo: { uint16_t TargetOpc = MatcherTable[MatcherIndex++]; @@ -2304,12 +2511,12 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, if (VT == MVT::iPTR) VT = TLI.getPointerTy().SimpleTy; VTs.push_back(VT); } - + if (EmitNodeInfo & OPFL_Chain) VTs.push_back(MVT::Other); - if (EmitNodeInfo & OPFL_FlagOutput) - VTs.push_back(MVT::Flag); - + if (EmitNodeInfo & OPFL_GlueOutput) + VTs.push_back(MVT::Glue); + // This is hot code, so optimize the two most common cases of 1 and 2 // results. SDVTList VTList; @@ -2327,11 +2534,11 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, unsigned RecNo = MatcherTable[MatcherIndex++]; if (RecNo & 128) RecNo = GetVBR(RecNo, MatcherTable, MatcherIndex); - + assert(RecNo < RecordedNodes.size() && "Invalid EmitNode"); - Ops.push_back(RecordedNodes[RecNo]); + Ops.push_back(RecordedNodes[RecNo].first); } - + // If there are variadic operands to add, handle them now. if (EmitNodeInfo & OPFL_VariadicInfo) { // Determine the start index to copy from. @@ -2339,22 +2546,22 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, FirstOpToCopy += (EmitNodeInfo & OPFL_Chain) ? 1 : 0; assert(NodeToMatch->getNumOperands() >= FirstOpToCopy && "Invalid variadic node"); - // Copy all of the variadic operands, not including a potential flag + // Copy all of the variadic operands, not including a potential glue // input. for (unsigned i = FirstOpToCopy, e = NodeToMatch->getNumOperands(); i != e; ++i) { SDValue V = NodeToMatch->getOperand(i); - if (V.getValueType() == MVT::Flag) break; + if (V.getValueType() == MVT::Glue) break; Ops.push_back(V); } } - - // If this has chain/flag inputs, add them. + + // If this has chain/glue inputs, add them. if (EmitNodeInfo & OPFL_Chain) Ops.push_back(InputChain); - if ((EmitNodeInfo & OPFL_FlagInput) && InputFlag.getNode() != 0) - Ops.push_back(InputFlag); - + if ((EmitNodeInfo & OPFL_GlueInput) && InputGlue.getNode() != 0) + Ops.push_back(InputGlue); + // Create the node. SDNode *Res = 0; if (Opcode != OPC_MorphNodeTo) { @@ -2362,28 +2569,29 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, // add the results to the RecordedNodes list. Res = CurDAG->getMachineNode(TargetOpc, NodeToMatch->getDebugLoc(), VTList, Ops.data(), Ops.size()); - - // Add all the non-flag/non-chain results to the RecordedNodes list. + + // Add all the non-glue/non-chain results to the RecordedNodes list. for (unsigned i = 0, e = VTs.size(); i != e; ++i) { - if (VTs[i] == MVT::Other || VTs[i] == MVT::Flag) break; - RecordedNodes.push_back(SDValue(Res, i)); + if (VTs[i] == MVT::Other || VTs[i] == MVT::Glue) break; + RecordedNodes.push_back(std::pair(SDValue(Res, i), + (SDNode*) 0)); } - + } else { Res = MorphNode(NodeToMatch, TargetOpc, VTList, Ops.data(), Ops.size(), EmitNodeInfo); } - - // If the node had chain/flag results, update our notion of the current - // chain and flag. - if (EmitNodeInfo & OPFL_FlagOutput) { - InputFlag = SDValue(Res, VTs.size()-1); + + // If the node had chain/glue results, update our notion of the current + // chain and glue. + if (EmitNodeInfo & OPFL_GlueOutput) { + InputGlue = SDValue(Res, VTs.size()-1); if (EmitNodeInfo & OPFL_Chain) InputChain = SDValue(Res, VTs.size()-2); } else if (EmitNodeInfo & OPFL_Chain) InputChain = SDValue(Res, VTs.size()-1); - // If the OPFL_MemRefs flag is set on this node, slap all of the + // If the OPFL_MemRefs glue is set on this node, slap all of the // accumulated memrefs onto it. // // FIXME: This is vastly incorrect for patterns with multiple outputs @@ -2396,37 +2604,37 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, cast(Res) ->setMemRefs(MemRefs, MemRefs + MatchedMemRefs.size()); } - + DEBUG(errs() << " " << (Opcode == OPC_MorphNodeTo ? "Morphed" : "Created") << " node: "; Res->dump(CurDAG); errs() << "\n"); - + // If this was a MorphNodeTo then we're completely done! if (Opcode == OPC_MorphNodeTo) { - // Update chain and flag uses. - UpdateChainsAndFlags(NodeToMatch, InputChain, ChainNodesMatched, - InputFlag, FlagResultNodesMatched, true); + // Update chain and glue uses. + UpdateChainsAndGlue(NodeToMatch, InputChain, ChainNodesMatched, + InputGlue, GlueResultNodesMatched, true); return Res; } - + continue; } - - case OPC_MarkFlagResults: { + + case OPC_MarkGlueResults: { unsigned NumNodes = MatcherTable[MatcherIndex++]; - - // Read and remember all the flag-result nodes. + + // Read and remember all the glue-result nodes. for (unsigned i = 0; i != NumNodes; ++i) { unsigned RecNo = MatcherTable[MatcherIndex++]; if (RecNo & 128) RecNo = GetVBR(RecNo, MatcherTable, MatcherIndex); assert(RecNo < RecordedNodes.size() && "Invalid CheckSame"); - FlagResultNodesMatched.push_back(RecordedNodes[RecNo].getNode()); + GlueResultNodesMatched.push_back(RecordedNodes[RecNo].first.getNode()); } continue; } - + case OPC_CompleteMatch: { // The match has been completed, and any new nodes (if any) have been // created. Patch up references to the matched dag to use the newly @@ -2437,13 +2645,13 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, unsigned ResSlot = MatcherTable[MatcherIndex++]; if (ResSlot & 128) ResSlot = GetVBR(ResSlot, MatcherTable, MatcherIndex); - + assert(ResSlot < RecordedNodes.size() && "Invalid CheckSame"); - SDValue Res = RecordedNodes[ResSlot]; - + SDValue Res = RecordedNodes[ResSlot].first; + assert(i < NodeToMatch->getNumValues() && NodeToMatch->getValueType(i) != MVT::Other && - NodeToMatch->getValueType(i) != MVT::Flag && + NodeToMatch->getValueType(i) != MVT::Glue && "Invalid number of results to complete!"); assert((NodeToMatch->getValueType(i) == Res.getValueType() || NodeToMatch->getValueType(i) == MVT::iPTR || @@ -2454,24 +2662,23 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, CurDAG->ReplaceAllUsesOfValueWith(SDValue(NodeToMatch, i), Res); } - // If the root node defines a flag, add it to the flag nodes to update - // list. - if (NodeToMatch->getValueType(NodeToMatch->getNumValues()-1) == MVT::Flag) - FlagResultNodesMatched.push_back(NodeToMatch); - - // Update chain and flag uses. - UpdateChainsAndFlags(NodeToMatch, InputChain, ChainNodesMatched, - InputFlag, FlagResultNodesMatched, false); - + // If the root node defines glue, add it to the glue nodes to update list. + if (NodeToMatch->getValueType(NodeToMatch->getNumValues()-1) == MVT::Glue) + GlueResultNodesMatched.push_back(NodeToMatch); + + // Update chain and glue uses. + UpdateChainsAndGlue(NodeToMatch, InputChain, ChainNodesMatched, + InputGlue, GlueResultNodesMatched, false); + assert(NodeToMatch->use_empty() && "Didn't replace all uses of the node?"); - + // FIXME: We just return here, which interacts correctly with SelectRoot // above. We should fix this to not return an SDNode* anymore. return 0; } } - + // If the code reached this point, then the match failed. See if there is // another child to try in the current 'Scope', otherwise pop it until we // find a case to check. @@ -2494,15 +2701,15 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, if (LastScope.NumMatchedMemRefs != MatchedMemRefs.size()) MatchedMemRefs.resize(LastScope.NumMatchedMemRefs); MatcherIndex = LastScope.FailIndex; - + DEBUG(errs() << " Continuing at " << MatcherIndex << "\n"); - + InputChain = LastScope.InputChain; - InputFlag = LastScope.InputFlag; + InputGlue = LastScope.InputGlue; if (!LastScope.HasChainNodesMatched) ChainNodesMatched.clear(); - if (!LastScope.HasFlagResultNodesMatched) - FlagResultNodesMatched.clear(); + if (!LastScope.HasGlueResultNodesMatched) + GlueResultNodesMatched.clear(); // Check to see what the offset is at the new MatcherIndex. If it is zero // we have reached the end of this scope, otherwise we have another child @@ -2517,21 +2724,21 @@ SelectCodeCommon(SDNode *NodeToMatch, const unsigned char *MatcherTable, LastScope.FailIndex = MatcherIndex+NumToSkip; break; } - + // End of this scope, pop it and try the next child in the containing // scope. MatchScopes.pop_back(); } } } - + void SelectionDAGISel::CannotYetSelect(SDNode *N) { std::string msg; raw_string_ostream Msg(msg); - Msg << "Cannot yet select: "; - + Msg << "Cannot select: "; + if (N->getOpcode() != ISD::INTRINSIC_W_CHAIN && N->getOpcode() != ISD::INTRINSIC_WO_CHAIN && N->getOpcode() != ISD::INTRINSIC_VOID) { diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp index 8313de5e32bb..76eb9453561e 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGPrinter.cpp @@ -93,7 +93,7 @@ namespace llvm { static std::string getEdgeAttributes(const void *Node, EdgeIter EI) { SDValue Op = EI.getNode()->getOperand(EI.getOperand()); EVT VT = Op.getValueType(); - if (VT == MVT::Flag) + if (VT == MVT::Glue) return "color=red,style=bold"; else if (VT == MVT::Other) return "color=blue,style=dashed"; @@ -273,14 +273,14 @@ std::string ScheduleDAGSDNodes::getGraphNodeLabel(const SUnit *SU) const { raw_string_ostream O(s); O << "SU(" << SU->NodeNum << "): "; if (SU->getNode()) { - SmallVector FlaggedNodes; - for (SDNode *N = SU->getNode(); N; N = N->getFlaggedNode()) - FlaggedNodes.push_back(N); - while (!FlaggedNodes.empty()) { + SmallVector GluedNodes; + for (SDNode *N = SU->getNode(); N; N = N->getGluedNode()) + GluedNodes.push_back(N); + while (!GluedNodes.empty()) { O << DOTGraphTraits - ::getSimpleNodeLabel(FlaggedNodes.back(), DAG); - FlaggedNodes.pop_back(); - if (!FlaggedNodes.empty()) + ::getSimpleNodeLabel(GluedNodes.back(), DAG); + GluedNodes.pop_back(); + if (!GluedNodes.empty()) O << "\n "; } } else { diff --git a/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/lib/CodeGen/SelectionDAG/TargetLowering.cpp index b74f600cfa2d..691390e2a0e4 100644 --- a/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -28,6 +28,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" +#include using namespace llvm; namespace llvm { @@ -530,7 +531,7 @@ TargetLowering::TargetLowering(const TargetMachine &tm, setIndexedLoadAction(IM, (MVT::SimpleValueType)VT, Expand); setIndexedStoreAction(IM, (MVT::SimpleValueType)VT, Expand); } - + // These operations default to expand. setOperationAction(ISD::FGETSIGN, (MVT::SimpleValueType)VT, Expand); setOperationAction(ISD::CONCAT_VECTORS, (MVT::SimpleValueType)VT, Expand); @@ -538,8 +539,8 @@ TargetLowering::TargetLowering(const TargetMachine &tm, // Most targets ignore the @llvm.prefetch intrinsic. setOperationAction(ISD::PREFETCH, MVT::Other, Expand); - - // ConstantFP nodes default to expand. Targets can either change this to + + // ConstantFP nodes default to expand. Targets can either change this to // Legal, in which case all fp constants are legal, or use isFPImmLegal() // to optimize expansions for certain constants. setOperationAction(ISD::ConstantFP, MVT::f32, Expand); @@ -560,18 +561,21 @@ TargetLowering::TargetLowering(const TargetMachine &tm, // Default ISD::TRAP to expand (which turns it into abort). setOperationAction(ISD::TRAP, MVT::Other, Expand); - + IsLittleEndian = TD->isLittleEndian(); ShiftAmountTy = PointerTy = MVT::getIntegerVT(8*TD->getPointerSize()); memset(RegClassForVT, 0,MVT::LAST_VALUETYPE*sizeof(TargetRegisterClass*)); memset(TargetDAGCombineArray, 0, array_lengthof(TargetDAGCombineArray)); maxStoresPerMemset = maxStoresPerMemcpy = maxStoresPerMemmove = 8; + maxStoresPerMemsetOptSize = maxStoresPerMemcpyOptSize + = maxStoresPerMemmoveOptSize = 4; benefitFromCodePlacementOpt = false; UseUnderscoreSetJmp = false; UseUnderscoreLongJmp = false; SelectIsExpensive = false; IntDivIsCheap = false; Pow2DivIsCheap = false; + JumpIsExpensive = false; StackPointerRegisterToSaveRestore = 0; ExceptionPointerRegister = 0; ExceptionSelectorRegister = 0; @@ -617,16 +621,16 @@ static unsigned getVectorTypeBreakdownMVT(MVT VT, MVT &IntermediateVT, // Figure out the right, legal destination reg to copy into. unsigned NumElts = VT.getVectorNumElements(); MVT EltTy = VT.getVectorElementType(); - + unsigned NumVectorRegs = 1; - - // FIXME: We don't support non-power-of-2-sized vectors for now. Ideally we + + // FIXME: We don't support non-power-of-2-sized vectors for now. Ideally we // could break down into LHS/RHS like LegalizeDAG does. if (!isPowerOf2_32(NumElts)) { NumVectorRegs = NumElts; NumElts = 1; } - + // Divide the input until we get to a supported size. This will always // end with a scalar if the target doesn't support vectors. while (NumElts > 1 && !TLI->isTypeLegal(MVT::getVectorVT(EltTy, NumElts))) { @@ -635,7 +639,7 @@ static unsigned getVectorTypeBreakdownMVT(MVT VT, MVT &IntermediateVT, } NumIntermediates = NumVectorRegs; - + MVT NewVT = MVT::getVectorVT(EltTy, NumElts); if (!TLI->isTypeLegal(NewVT)) NewVT = EltTy; @@ -645,7 +649,7 @@ static unsigned getVectorTypeBreakdownMVT(MVT VT, MVT &IntermediateVT, RegisterVT = DestVT; if (EVT(DestVT).bitsLT(NewVT)) // Value is expanded, e.g. i64 -> i16. return NumVectorRegs*(NewVT.getSizeInBits()/DestVT.getSizeInBits()); - + // Otherwise, promotion or legal types use the same number of registers as // the vector decimated to the appropriate level. return NumVectorRegs; @@ -750,7 +754,7 @@ void TargetLowering::computeRegisterProperties() { RegisterTypeForVT[MVT::ppcf128] = MVT::f64; TransformToType[MVT::ppcf128] = MVT::f64; ValueTypeActions.setTypeAction(MVT::ppcf128, Expand); - } + } // Decide how to handle f64. If the target does not have native f64 support, // expand it to i64 and we will be generating soft float library calls. @@ -776,13 +780,13 @@ void TargetLowering::computeRegisterProperties() { ValueTypeActions.setTypeAction(MVT::f32, Expand); } } - + // Loop over all of the vector value types to see which need transformations. for (unsigned i = MVT::FIRST_VECTOR_VALUETYPE; i <= (unsigned)MVT::LAST_VECTOR_VALUETYPE; ++i) { MVT VT = (MVT::SimpleValueType)i; if (isTypeLegal(VT)) continue; - + // Determine if there is a legal wider type. If so, we should promote to // that wider vector type. EVT EltVT = VT.getVectorElementType(); @@ -792,8 +796,8 @@ void TargetLowering::computeRegisterProperties() { for (unsigned nVT = i+1; nVT <= MVT::LAST_VECTOR_VALUETYPE; ++nVT) { EVT SVT = (MVT::SimpleValueType)nVT; if (SVT.getVectorElementType() == EltVT && - SVT.getVectorNumElements() > NElts && - isTypeSynthesizable(SVT)) { + SVT.getVectorNumElements() > NElts && + isTypeLegal(SVT)) { TransformToType[i] = SVT; RegisterTypeForVT[i] = SVT; NumRegistersForVT[i] = 1; @@ -804,7 +808,7 @@ void TargetLowering::computeRegisterProperties() { } if (IsLegalWiderType) continue; } - + MVT IntermediateVT; EVT RegisterVT; unsigned NumIntermediates; @@ -812,7 +816,7 @@ void TargetLowering::computeRegisterProperties() { getVectorTypeBreakdownMVT(VT, IntermediateVT, NumIntermediates, RegisterVT, this); RegisterTypeForVT[i] = RegisterVT; - + EVT NVT = VT.getPow2VectorType(); if (NVT == VT) { // Type is already a power of 2. The default action is to split. @@ -865,7 +869,7 @@ unsigned TargetLowering::getVectorTypeBreakdown(LLVMContext &Context, EVT VT, unsigned &NumIntermediates, EVT &RegisterVT) const { unsigned NumElts = VT.getVectorNumElements(); - + // If there is a wider vector type with the same element type as this one, // we should widen to that legal vector type. This handles things like // <2 x float> -> <4 x float>. @@ -877,19 +881,19 @@ unsigned TargetLowering::getVectorTypeBreakdown(LLVMContext &Context, EVT VT, return 1; } } - + // Figure out the right, legal destination reg to copy into. EVT EltTy = VT.getVectorElementType(); - + unsigned NumVectorRegs = 1; - - // FIXME: We don't support non-power-of-2-sized vectors for now. Ideally we + + // FIXME: We don't support non-power-of-2-sized vectors for now. Ideally we // could break down into LHS/RHS like LegalizeDAG does. if (!isPowerOf2_32(NumElts)) { NumVectorRegs = NumElts; NumElts = 1; } - + // Divide the input until we get to a supported size. This will always // end with a scalar if the target doesn't support vectors. while (NumElts > 1 && !isTypeLegal( @@ -899,7 +903,7 @@ unsigned TargetLowering::getVectorTypeBreakdown(LLVMContext &Context, EVT VT, } NumIntermediates = NumVectorRegs; - + EVT NewVT = EVT::getVectorVT(Context, EltTy, NumElts); if (!isTypeLegal(NewVT)) NewVT = EltTy; @@ -909,13 +913,13 @@ unsigned TargetLowering::getVectorTypeBreakdown(LLVMContext &Context, EVT VT, RegisterVT = DestVT; if (DestVT.bitsLT(NewVT)) // Value is expanded, e.g. i64 -> i16. return NumVectorRegs*(NewVT.getSizeInBits()/DestVT.getSizeInBits()); - + // Otherwise, promotion or legal types use the same number of registers as // the vector decimated to the appropriate level. return NumVectorRegs; } -/// Get the EVTs and ArgFlags collections that represent the legalized return +/// Get the EVTs and ArgFlags collections that represent the legalized return /// type of the given function. This does not require a DAG or a return value, /// and is suitable for use before any DAGs for the function are constructed. /// TODO: Move this out of TargetLowering.cpp. @@ -988,11 +992,11 @@ unsigned TargetLowering::getJumpTableEncoding() const { // In non-pic modes, just use the address of a block. if (getTargetMachine().getRelocationModel() != Reloc::PIC_) return MachineJumpTableInfo::EK_BlockAddress; - + // In PIC mode, if the target supports a GPRel32 directive, use it. if (getTargetMachine().getMCAsmInfo()->getGPRel32Directive() != 0) return MachineJumpTableInfo::EK_GPRel32BlockAddress; - + // Otherwise, use a label difference. return MachineJumpTableInfo::EK_LabelDifference32; } @@ -1036,11 +1040,11 @@ TargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { // Optimization Methods //===----------------------------------------------------------------------===// -/// ShrinkDemandedConstant - Check to see if the specified operand of the +/// ShrinkDemandedConstant - Check to see if the specified operand of the /// specified instruction is a constant integer. If so, check to see if there /// are any bits set in the constant that are not demanded. If so, shrink the /// constant and return true. -bool TargetLowering::TargetLoweringOpt::ShrinkDemandedConstant(SDValue Op, +bool TargetLowering::TargetLoweringOpt::ShrinkDemandedConstant(SDValue Op, const APInt &Demanded) { DebugLoc dl = Op.getDebugLoc(); @@ -1062,7 +1066,7 @@ bool TargetLowering::TargetLoweringOpt::ShrinkDemandedConstant(SDValue Op, EVT VT = Op.getValueType(); SDValue New = DAG.getNode(Op.getOpcode(), dl, VT, Op.getOperand(0), DAG.getConstant(Demanded & - C->getAPIntValue(), + C->getAPIntValue(), VT)); return CombineTo(Op, New); } @@ -1139,9 +1143,9 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, KnownZero = KnownOne = APInt(BitWidth, 0); // Other users may use these bits. - if (!Op.getNode()->hasOneUse()) { + if (!Op.getNode()->hasOneUse()) { if (Depth != 0) { - // If not at the root, Just compute the KnownZero/KnownOne bits to + // If not at the root, Just compute the KnownZero/KnownOne bits to // simplify things downstream. TLO.DAG.ComputeMaskedBits(Op, DemandedMask, KnownZero, KnownOne, Depth); return false; @@ -1149,7 +1153,7 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, // If this is the root being simplified, allow it to have multiple uses, // just set the NewMask to all bits. NewMask = APInt::getAllOnesValue(BitWidth); - } else if (DemandedMask == 0) { + } else if (DemandedMask == 0) { // Not demanding any bits from Op. if (Op.getOpcode() != ISD::UNDEF) return TLO.CombineTo(Op, TLO.DAG.getUNDEF(Op.getValueType())); @@ -1172,8 +1176,9 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, // the RHS. if (ConstantSDNode *RHSC = dyn_cast(Op.getOperand(1))) { APInt LHSZero, LHSOne; + // Do not increment Depth here; that can cause an infinite loop. TLO.DAG.ComputeMaskedBits(Op.getOperand(0), NewMask, - LHSZero, LHSOne, Depth+1); + LHSZero, LHSOne, Depth); // If the LHS already has zeros where RHSC does, this and is dead. if ((LHSZero & NewMask) == (~RHSC->getAPIntValue() & NewMask)) return TLO.CombineTo(Op, Op.getOperand(0)); @@ -1182,16 +1187,16 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, if (TLO.ShrinkDemandedConstant(Op, ~LHSZero & NewMask)) return true; } - + if (SimplifyDemandedBits(Op.getOperand(1), NewMask, KnownZero, KnownOne, TLO, Depth+1)) return true; - assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); + assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); if (SimplifyDemandedBits(Op.getOperand(0), ~KnownZero & NewMask, KnownZero2, KnownOne2, TLO, Depth+1)) return true; - assert((KnownZero2 & KnownOne2) == 0 && "Bits known to be one AND zero?"); - + assert((KnownZero2 & KnownOne2) == 0 && "Bits known to be one AND zero?"); + // If all of the demanded bits are known one on one side, return the other. // These bits cannot contribute to the result of the 'and'. if ((NewMask & ~KnownZero2 & KnownOne) == (~KnownZero2 & NewMask)) @@ -1214,15 +1219,15 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, KnownZero |= KnownZero2; break; case ISD::OR: - if (SimplifyDemandedBits(Op.getOperand(1), NewMask, KnownZero, + if (SimplifyDemandedBits(Op.getOperand(1), NewMask, KnownZero, KnownOne, TLO, Depth+1)) return true; - assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); + assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); if (SimplifyDemandedBits(Op.getOperand(0), ~KnownOne & NewMask, KnownZero2, KnownOne2, TLO, Depth+1)) return true; - assert((KnownZero2 & KnownOne2) == 0 && "Bits known to be one AND zero?"); - + assert((KnownZero2 & KnownOne2) == 0 && "Bits known to be one AND zero?"); + // If all of the demanded bits are known zero on one side, return the other. // These bits cannot contribute to the result of the 'or'. if ((NewMask & ~KnownOne2 & KnownZero) == (~KnownOne2 & NewMask)) @@ -1248,15 +1253,15 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, KnownOne |= KnownOne2; break; case ISD::XOR: - if (SimplifyDemandedBits(Op.getOperand(1), NewMask, KnownZero, + if (SimplifyDemandedBits(Op.getOperand(1), NewMask, KnownZero, KnownOne, TLO, Depth+1)) return true; - assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); + assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); if (SimplifyDemandedBits(Op.getOperand(0), NewMask, KnownZero2, KnownOne2, TLO, Depth+1)) return true; - assert((KnownZero2 & KnownOne2) == 0 && "Bits known to be one AND zero?"); - + assert((KnownZero2 & KnownOne2) == 0 && "Bits known to be one AND zero?"); + // If all of the demanded bits are known zero on one side, return the other. // These bits cannot contribute to the result of the 'xor'. if ((KnownZero & NewMask) == NewMask) @@ -1274,12 +1279,12 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, return TLO.CombineTo(Op, TLO.DAG.getNode(ISD::OR, dl, Op.getValueType(), Op.getOperand(0), Op.getOperand(1))); - + // Output known-0 bits are known if clear or set in both the LHS & RHS. KnownZeroOut = (KnownZero & KnownZero2) | (KnownOne & KnownOne2); // Output known-1 are known to be set if set in only one of the LHS, RHS. KnownOneOut = (KnownZero & KnownOne2) | (KnownOne & KnownZero2); - + // If all of the demanded bits on one side are known, and all of the set // bits on that side are also known to be set on the other side, turn this // into an AND, as we know the bits will be cleared. @@ -1288,11 +1293,11 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, if ((KnownOne & KnownOne2) == KnownOne) { EVT VT = Op.getValueType(); SDValue ANDC = TLO.DAG.getConstant(~KnownOne & NewMask, VT); - return TLO.CombineTo(Op, TLO.DAG.getNode(ISD::AND, dl, VT, + return TLO.CombineTo(Op, TLO.DAG.getNode(ISD::AND, dl, VT, Op.getOperand(0), ANDC)); } } - + // If the RHS is a constant, see if we can simplify it. // for XOR, we prefer to force bits to 1 if they will make a -1. // if we can't force bits, try to shrink constant @@ -1317,37 +1322,37 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, KnownOne = KnownOneOut; break; case ISD::SELECT: - if (SimplifyDemandedBits(Op.getOperand(2), NewMask, KnownZero, + if (SimplifyDemandedBits(Op.getOperand(2), NewMask, KnownZero, KnownOne, TLO, Depth+1)) return true; if (SimplifyDemandedBits(Op.getOperand(1), NewMask, KnownZero2, KnownOne2, TLO, Depth+1)) return true; - assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); - assert((KnownZero2 & KnownOne2) == 0 && "Bits known to be one AND zero?"); - + assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); + assert((KnownZero2 & KnownOne2) == 0 && "Bits known to be one AND zero?"); + // If the operands are constants, see if we can simplify them. if (TLO.ShrinkDemandedConstant(Op, NewMask)) return true; - + // Only known if known in both the LHS and RHS. KnownOne &= KnownOne2; KnownZero &= KnownZero2; break; case ISD::SELECT_CC: - if (SimplifyDemandedBits(Op.getOperand(3), NewMask, KnownZero, + if (SimplifyDemandedBits(Op.getOperand(3), NewMask, KnownZero, KnownOne, TLO, Depth+1)) return true; if (SimplifyDemandedBits(Op.getOperand(2), NewMask, KnownZero2, KnownOne2, TLO, Depth+1)) return true; - assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); - assert((KnownZero2 & KnownOne2) == 0 && "Bits known to be one AND zero?"); - + assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); + assert((KnownZero2 & KnownOne2) == 0 && "Bits known to be one AND zero?"); + // If the operands are constants, see if we can simplify them. if (TLO.ShrinkDemandedConstant(Op, NewMask)) return true; - + // Only known if known in both the LHS and RHS. KnownOne &= KnownOne2; KnownZero &= KnownZero2; @@ -1373,16 +1378,16 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, if (Diff < 0) { Diff = -Diff; Opc = ISD::SRL; - } - - SDValue NewSA = + } + + SDValue NewSA = TLO.DAG.getConstant(Diff, Op.getOperand(1).getValueType()); EVT VT = Op.getValueType(); return TLO.CombineTo(Op, TLO.DAG.getNode(Opc, dl, VT, InOp.getOperand(0), NewSA)); } - } - + } + if (SimplifyDemandedBits(InOp, NewMask.lshr(ShAmt), KnownZero, KnownOne, TLO, Depth+1)) return true; @@ -1421,7 +1426,7 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, unsigned ShAmt = SA->getZExtValue(); unsigned VTSize = VT.getSizeInBits(); SDValue InOp = Op.getOperand(0); - + // If the shift count is an invalid immediate, don't do anything. if (ShAmt >= BitWidth) break; @@ -1438,20 +1443,20 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, if (Diff < 0) { Diff = -Diff; Opc = ISD::SHL; - } - + } + SDValue NewSA = TLO.DAG.getConstant(Diff, Op.getOperand(1).getValueType()); return TLO.CombineTo(Op, TLO.DAG.getNode(Opc, dl, VT, InOp.getOperand(0), NewSA)); } - } - + } + // Compute the new bits that are at the top now. if (SimplifyDemandedBits(InOp, (NewMask << ShAmt), KnownZero, KnownOne, TLO, Depth+1)) return true; - assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); + assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); KnownZero = KnownZero.lshr(ShAmt); KnownOne = KnownOne.lshr(ShAmt); @@ -1472,7 +1477,7 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, if (ConstantSDNode *SA = dyn_cast(Op.getOperand(1))) { EVT VT = Op.getValueType(); unsigned ShAmt = SA->getZExtValue(); - + // If the shift count is an invalid immediate, don't do anything. if (ShAmt >= BitWidth) break; @@ -1484,21 +1489,21 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, APInt HighBits = APInt::getHighBitsSet(BitWidth, ShAmt); if (HighBits.intersects(NewMask)) InDemandedMask |= APInt::getSignBit(VT.getScalarType().getSizeInBits()); - + if (SimplifyDemandedBits(Op.getOperand(0), InDemandedMask, KnownZero, KnownOne, TLO, Depth+1)) return true; - assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); + assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); KnownZero = KnownZero.lshr(ShAmt); KnownOne = KnownOne.lshr(ShAmt); - + // Handle the sign bit, adjusted to where it is now in the mask. APInt SignBit = APInt::getSignBit(BitWidth).lshr(ShAmt); - + // If the input sign bit is known to be zero, or if none of the top bits // are demanded, turn this into an unsigned shift right. if (KnownZero.intersects(SignBit) || (HighBits & ~NewMask) == HighBits) { - return TLO.CombineTo(Op, TLO.DAG.getNode(ISD::SRL, dl, VT, + return TLO.CombineTo(Op, TLO.DAG.getNode(ISD::SRL, dl, VT, Op.getOperand(0), Op.getOperand(1))); } else if (KnownOne.intersects(SignBit)) { // New bits are known one. @@ -1509,23 +1514,23 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, case ISD::SIGN_EXTEND_INREG: { EVT EVT = cast(Op.getOperand(1))->getVT(); - // Sign extension. Compute the demanded bits in the result that are not + // Sign extension. Compute the demanded bits in the result that are not // present in the input. APInt NewBits = APInt::getHighBitsSet(BitWidth, BitWidth - EVT.getScalarType().getSizeInBits()); - + // If none of the extended bits are demanded, eliminate the sextinreg. if ((NewBits & NewMask) == 0) return TLO.CombineTo(Op, Op.getOperand(0)); - APInt InSignBit = APInt::getSignBit(EVT.getScalarType().getSizeInBits()); - InSignBit.zext(BitWidth); + APInt InSignBit = + APInt::getSignBit(EVT.getScalarType().getSizeInBits()).zext(BitWidth); APInt InputDemandedBits = APInt::getLowBitsSet(BitWidth, EVT.getScalarType().getSizeInBits()) & NewMask; - + // Since the sign extended bits are demanded, we know that the sign // bit is demanded. InputDemandedBits |= InSignBit; @@ -1533,16 +1538,16 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, if (SimplifyDemandedBits(Op.getOperand(0), InputDemandedBits, KnownZero, KnownOne, TLO, Depth+1)) return true; - assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); + assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); // If the sign bit of the input is known set or clear, then we know the // top bits of the result. - + // If the input sign bit is known zero, convert this into a zero extension. if (KnownZero.intersects(InSignBit)) - return TLO.CombineTo(Op, + return TLO.CombineTo(Op, TLO.DAG.getZeroExtendInReg(Op.getOperand(0),dl,EVT)); - + if (KnownOne.intersects(InSignBit)) { // Input sign bit known set KnownOne |= NewBits; KnownZero &= ~NewBits; @@ -1555,23 +1560,22 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, case ISD::ZERO_EXTEND: { unsigned OperandBitWidth = Op.getOperand(0).getValueType().getScalarType().getSizeInBits(); - APInt InMask = NewMask; - InMask.trunc(OperandBitWidth); - + APInt InMask = NewMask.trunc(OperandBitWidth); + // If none of the top bits are demanded, convert this into an any_extend. APInt NewBits = APInt::getHighBitsSet(BitWidth, BitWidth - OperandBitWidth) & NewMask; if (!NewBits.intersects(NewMask)) return TLO.CombineTo(Op, TLO.DAG.getNode(ISD::ANY_EXTEND, dl, - Op.getValueType(), + Op.getValueType(), Op.getOperand(0))); - + if (SimplifyDemandedBits(Op.getOperand(0), InMask, KnownZero, KnownOne, TLO, Depth+1)) return true; - assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); - KnownZero.zext(BitWidth); - KnownOne.zext(BitWidth); + assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); + KnownZero = KnownZero.zext(BitWidth); + KnownOne = KnownOne.zext(BitWidth); KnownZero |= NewBits; break; } @@ -1581,31 +1585,31 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, APInt InMask = APInt::getLowBitsSet(BitWidth, InBits); APInt InSignBit = APInt::getBitsSet(BitWidth, InBits - 1, InBits); APInt NewBits = ~InMask & NewMask; - + // If none of the top bits are demanded, convert this into an any_extend. if (NewBits == 0) return TLO.CombineTo(Op,TLO.DAG.getNode(ISD::ANY_EXTEND, dl, Op.getValueType(), Op.getOperand(0))); - + // Since some of the sign extended bits are demanded, we know that the sign // bit is demanded. APInt InDemandedBits = InMask & NewMask; InDemandedBits |= InSignBit; - InDemandedBits.trunc(InBits); - - if (SimplifyDemandedBits(Op.getOperand(0), InDemandedBits, KnownZero, + InDemandedBits = InDemandedBits.trunc(InBits); + + if (SimplifyDemandedBits(Op.getOperand(0), InDemandedBits, KnownZero, KnownOne, TLO, Depth+1)) return true; - KnownZero.zext(BitWidth); - KnownOne.zext(BitWidth); - + KnownZero = KnownZero.zext(BitWidth); + KnownOne = KnownOne.zext(BitWidth); + // If the sign bit is known zero, convert this to a zero extend. if (KnownZero.intersects(InSignBit)) return TLO.CombineTo(Op, TLO.DAG.getNode(ISD::ZERO_EXTEND, dl, - Op.getValueType(), + Op.getValueType(), Op.getOperand(0))); - + // If the sign bit is known one, the top bits match. if (KnownOne.intersects(InSignBit)) { KnownOne |= NewBits; @@ -1619,14 +1623,13 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, case ISD::ANY_EXTEND: { unsigned OperandBitWidth = Op.getOperand(0).getValueType().getScalarType().getSizeInBits(); - APInt InMask = NewMask; - InMask.trunc(OperandBitWidth); + APInt InMask = NewMask.trunc(OperandBitWidth); if (SimplifyDemandedBits(Op.getOperand(0), InMask, KnownZero, KnownOne, TLO, Depth+1)) return true; - assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); - KnownZero.zext(BitWidth); - KnownOne.zext(BitWidth); + assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); + KnownZero = KnownZero.zext(BitWidth); + KnownOne = KnownOne.zext(BitWidth); break; } case ISD::TRUNCATE: { @@ -1634,14 +1637,13 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, // zero/one bits live out. unsigned OperandBitWidth = Op.getOperand(0).getValueType().getScalarType().getSizeInBits(); - APInt TruncMask = NewMask; - TruncMask.zext(OperandBitWidth); + APInt TruncMask = NewMask.zext(OperandBitWidth); if (SimplifyDemandedBits(Op.getOperand(0), TruncMask, KnownZero, KnownOne, TLO, Depth+1)) return true; - KnownZero.trunc(BitWidth); - KnownOne.trunc(BitWidth); - + KnownZero = KnownZero.trunc(BitWidth); + KnownOne = KnownOne.trunc(BitWidth); + // If the input is only used by this truncate, see if we can shrink it based // on the known demanded bits. if (Op.getOperand(0).getNode()->hasOneUse()) { @@ -1661,25 +1663,24 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, break; APInt HighBits = APInt::getHighBitsSet(OperandBitWidth, OperandBitWidth - BitWidth); - HighBits = HighBits.lshr(ShAmt->getZExtValue()); - HighBits.trunc(BitWidth); + HighBits = HighBits.lshr(ShAmt->getZExtValue()).trunc(BitWidth); if (ShAmt->getZExtValue() < BitWidth && !(HighBits & NewMask)) { // None of the shifted in bits are needed. Add a truncate of the // shift input, then shift it. SDValue NewTrunc = TLO.DAG.getNode(ISD::TRUNCATE, dl, - Op.getValueType(), + Op.getValueType(), In.getOperand(0)); return TLO.CombineTo(Op, TLO.DAG.getNode(ISD::SRL, dl, Op.getValueType(), - NewTrunc, + NewTrunc, In.getOperand(1))); } break; } } - - assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); + + assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); break; } case ISD::AssertZext: { @@ -1689,7 +1690,7 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, if (SimplifyDemandedBits(Op.getOperand(0), NewMask, KnownZero, KnownOne, TLO, Depth+1)) return true; - assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); + assert((KnownZero & KnownOne) == 0 && "Bits known to be one AND zero?"); EVT VT = cast(Op.getOperand(1))->getVT(); APInt InMask = APInt::getLowBitsSet(BitWidth, @@ -1697,7 +1698,7 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, KnownZero |= ~InMask & NewMask; break; } - case ISD::BIT_CONVERT: + case ISD::BITCAST: #if 0 // If this is an FP->Int bitcast and if the sign bit is the only thing that // is demanded, turn this into a FGETSIGN. @@ -1709,7 +1710,7 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, isOperationLegal(ISD::FGETSIGN, Op.getValueType())) { // Make a FGETSIGN + SHL to move the sign bit into the appropriate // place. We expect the SHL to be eliminated by other optimizations. - SDValue Sign = TLO.DAG.getNode(ISD::FGETSIGN, Op.getValueType(), + SDValue Sign = TLO.DAG.getNode(ISD::FGETSIGN, Op.getValueType(), Op.getOperand(0)); unsigned ShVal = Op.getValueType().getSizeInBits()-1; SDValue ShAmt = TLO.DAG.getConstant(ShVal, getShiftAmountTy()); @@ -1742,21 +1743,21 @@ bool TargetLowering::SimplifyDemandedBits(SDValue Op, TLO.DAG.ComputeMaskedBits(Op, NewMask, KnownZero, KnownOne, Depth); break; } - + // If we know the value of all of the demanded bits, return this as a // constant. if ((NewMask & (KnownZero|KnownOne)) == NewMask) return TLO.CombineTo(Op, TLO.DAG.getConstant(KnownOne, Op.getValueType())); - + return false; } -/// computeMaskedBitsForTargetNode - Determine which of the bits specified -/// in Mask are known to be either zero or one and return them in the +/// computeMaskedBitsForTargetNode - Determine which of the bits specified +/// in Mask are known to be either zero or one and return them in the /// KnownZero/KnownOne bitsets. -void TargetLowering::computeMaskedBitsForTargetNode(const SDValue Op, +void TargetLowering::computeMaskedBitsForTargetNode(const SDValue Op, const APInt &Mask, - APInt &KnownZero, + APInt &KnownZero, APInt &KnownOne, const SelectionDAG &DAG, unsigned Depth) const { @@ -1817,7 +1818,7 @@ static bool ValueHasExactlyOneBitSet(SDValue Val, const SelectionDAG &DAG) { (KnownOne.countPopulation() == 1); } -/// SimplifySetCC - Try to simplify a setcc built with the specified operands +/// SimplifySetCC - Try to simplify a setcc built with the specified operands /// and cc. If it is unable to simplify it, return a null SDValue. SDValue TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, @@ -1869,6 +1870,30 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, } } + SDValue CTPOP = N0; + // Look through truncs that don't change the value of a ctpop. + if (N0.hasOneUse() && N0.getOpcode() == ISD::TRUNCATE) + CTPOP = N0.getOperand(0); + + if (CTPOP.hasOneUse() && CTPOP.getOpcode() == ISD::CTPOP && + (N0 == CTPOP || N0.getValueType().getSizeInBits() > + Log2_32_Ceil(CTPOP.getValueType().getSizeInBits()))) { + EVT CTVT = CTPOP.getValueType(); + SDValue CTOp = CTPOP.getOperand(0); + + // (ctpop x) u< 2 -> (x & x-1) == 0 + // (ctpop x) u> 1 -> (x & x-1) != 0 + if ((Cond == ISD::SETULT && C1 == 2) || (Cond == ISD::SETUGT && C1 == 1)){ + SDValue Sub = DAG.getNode(ISD::SUB, dl, CTVT, CTOp, + DAG.getConstant(1, CTVT)); + SDValue And = DAG.getNode(ISD::AND, dl, CTVT, CTOp, Sub); + ISD::CondCode CC = Cond == ISD::SETULT ? ISD::SETEQ : ISD::SETNE; + return DAG.getSetCC(dl, VT, And, DAG.getConstant(0, CTVT), CC); + } + + // TODO: (ctpop x) == 1 -> x && (x & x-1) == 0 iff ctpop is illegal. + } + // If the LHS is '(and load, const)', the RHS is 0, // the test is for equality or unsigned, and all 1 bits of the const are // in the same partial word, see if we can shorten the load. @@ -1884,7 +1909,7 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, if (!Lod->isVolatile() && Lod->isUnindexed()) { unsigned origWidth = N0.getValueType().getSizeInBits(); unsigned maskWidth = origWidth; - // We can narrow (e.g.) 16-bit extending loads on 32-bit target to + // We can narrow (e.g.) 16-bit extending loads on 32-bit target to // 8 bits, but have to be careful... if (Lod->getExtensionType() != ISD::NON_EXTLOAD) origWidth = Lod->getMemoryVT().getSizeInBits(); @@ -1916,10 +1941,9 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, DAG.getConstant(bestOffset, PtrType)); unsigned NewAlign = MinAlign(Lod->getAlignment(), bestOffset); SDValue NewLoad = DAG.getLoad(newVT, dl, Lod->getChain(), Ptr, - Lod->getSrcValue(), - Lod->getSrcValueOffset() + bestOffset, + Lod->getPointerInfo().getWithOffset(bestOffset), false, false, NewAlign); - return DAG.getSetCC(dl, VT, + return DAG.getSetCC(dl, VT, DAG.getNode(ISD::AND, dl, newVT, NewLoad, DAG.getConstant(bestMask.trunc(bestWidth), newVT)), @@ -1969,7 +1993,7 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, (isOperationLegal(ISD::SETCC, newVT) && getCondCodeAction(Cond, newVT)==Legal)) return DAG.getSetCC(dl, VT, N0.getOperand(0), - DAG.getConstant(APInt(C1).trunc(InSize), newVT), + DAG.getConstant(C1.trunc(InSize), newVT), Cond); break; } @@ -1987,7 +2011,7 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, // the sign extension, it is impossible for both sides to be equal. if (C1.getMinSignedBits() > ExtSrcTyBits) return DAG.getConstant(Cond == ISD::SETNE, VT); - + SDValue ZextOp; EVT Op0Ty = N0.getOperand(0).getValueType(); if (Op0Ty == ExtSrcTy) { @@ -2000,10 +2024,10 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, if (!DCI.isCalledByLegalizer()) DCI.AddToWorklist(ZextOp.getNode()); // Otherwise, make this a use of a zext. - return DAG.getSetCC(dl, VT, ZextOp, + return DAG.getSetCC(dl, VT, ZextOp, DAG.getConstant(C1 & APInt::getLowBitsSet( ExtDstTyBits, - ExtSrcTyBits), + ExtSrcTyBits), ExtDstTy), Cond); } else if ((N1C->isNullValue() || N1C->getAPIntValue() == 1) && @@ -2013,16 +2037,16 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, isTypeLegal(VT) && VT.bitsLE(N0.getValueType())) { bool TrueWhenTrue = (Cond == ISD::SETEQ) ^ (N1C->getAPIntValue() != 1); if (TrueWhenTrue) - return DAG.getNode(ISD::TRUNCATE, dl, VT, N0); + return DAG.getNode(ISD::TRUNCATE, dl, VT, N0); // Invert the condition. ISD::CondCode CC = cast(N0.getOperand(2))->get(); - CC = ISD::getSetCCInverse(CC, + CC = ISD::getSetCCInverse(CC, N0.getOperand(0).getValueType().isInteger()); return DAG.getSetCC(dl, VT, N0.getOperand(0), N0.getOperand(1), CC); } if ((N0.getOpcode() == ISD::XOR || - (N0.getOpcode() == ISD::AND && + (N0.getOpcode() == ISD::AND && N0.getOperand(0).getOpcode() == ISD::XOR && N0.getOperand(1) == N0.getOperand(0).getOperand(1))) && isa(N0.getOperand(1)) && @@ -2038,7 +2062,7 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, if (N0.getOpcode() == ISD::XOR) Val = N0.getOperand(0); else { - assert(N0.getOpcode() == ISD::AND && + assert(N0.getOpcode() == ISD::AND && N0.getOperand(0).getOpcode() == ISD::XOR); // ((X^1)&1)^1 -> X & 1 Val = DAG.getNode(ISD::AND, dl, N0.getValueType(), @@ -2082,7 +2106,7 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, } } } - + APInt MinVal, MaxVal; unsigned OperandBitSize = N1C->getValueType(0).getSizeInBits(); if (ISD::isSignedIntSetCC(Cond)) { @@ -2097,7 +2121,7 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, if (Cond == ISD::SETGE || Cond == ISD::SETUGE) { if (C1 == MinVal) return DAG.getConstant(1, VT); // X >= MIN --> true // X >= C0 --> X > (C0-1) - return DAG.getSetCC(dl, VT, N0, + return DAG.getSetCC(dl, VT, N0, DAG.getConstant(C1-1, N1.getValueType()), (Cond == ISD::SETGE) ? ISD::SETGT : ISD::SETUGT); } @@ -2105,7 +2129,7 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, if (Cond == ISD::SETLE || Cond == ISD::SETULE) { if (C1 == MaxVal) return DAG.getConstant(1, VT); // X <= MAX --> true // X <= C0 --> X < (C0+1) - return DAG.getSetCC(dl, VT, N0, + return DAG.getSetCC(dl, VT, N0, DAG.getConstant(C1+1, N1.getValueType()), (Cond == ISD::SETLE) ? ISD::SETLT : ISD::SETULT); } @@ -2128,12 +2152,12 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, // If we have setult X, 1, turn it into seteq X, 0 if ((Cond == ISD::SETLT || Cond == ISD::SETULT) && C1 == MinVal+1) - return DAG.getSetCC(dl, VT, N0, - DAG.getConstant(MinVal, N0.getValueType()), + return DAG.getSetCC(dl, VT, N0, + DAG.getConstant(MinVal, N0.getValueType()), ISD::SETEQ); // If we have setugt X, Max-1, turn it into seteq X, Max else if ((Cond == ISD::SETGT || Cond == ISD::SETUGT) && C1 == MaxVal-1) - return DAG.getSetCC(dl, VT, N0, + return DAG.getSetCC(dl, VT, N0, DAG.getConstant(MaxVal, N0.getValueType()), ISD::SETEQ); @@ -2141,9 +2165,9 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, // by changing cc. // SETUGT X, SINTMAX -> SETLT X, 0 - if (Cond == ISD::SETUGT && + if (Cond == ISD::SETUGT && C1 == APInt::getSignedMaxValue(OperandBitSize)) - return DAG.getSetCC(dl, VT, N0, + return DAG.getSetCC(dl, VT, N0, DAG.getConstant(0, N1.getValueType()), ISD::SETLT); @@ -2203,7 +2227,7 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, return DAG.getUNDEF(VT); } } - + // Otherwise, we know the RHS is not a NaN. Simplify the node to drop the // constant if knowing that the operand is non-nan is enough. We prefer to // have SETO(x,x) instead of SETO(x, 0.0) because this avoids having to @@ -2278,14 +2302,14 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, if (DAG.isCommutativeBinOp(N0.getOpcode())) { // If X op Y == Y op X, try other combinations. if (N0.getOperand(0) == N1.getOperand(1)) - return DAG.getSetCC(dl, VT, N0.getOperand(1), N1.getOperand(0), + return DAG.getSetCC(dl, VT, N0.getOperand(1), N1.getOperand(0), Cond); if (N0.getOperand(1) == N1.getOperand(0)) - return DAG.getSetCC(dl, VT, N0.getOperand(0), N1.getOperand(1), + return DAG.getSetCC(dl, VT, N0.getOperand(0), N1.getOperand(1), Cond); } } - + if (ConstantSDNode *RHSC = dyn_cast(N1)) { if (ConstantSDNode *LHSR = dyn_cast(N0.getOperand(1))) { // Turn (X+C1) == C2 --> X == C2-C1 @@ -2295,7 +2319,7 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, LHSR->getAPIntValue(), N0.getValueType()), Cond); } - + // Turn (X^C1) == C2 into X == C1^C2 iff X&~C1 = 0. if (N0.getOpcode() == ISD::XOR) // If we know that all of the inverted bits are zero, don't bother @@ -2308,7 +2332,7 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, N0.getValueType()), Cond); } - + // Turn (C1-X) == C2 --> X == C1-C2 if (ConstantSDNode *SUBC = dyn_cast(N0.getOperand(0))) { if (N0.getOpcode() == ISD::SUB && N0.getNode()->hasOneUse()) { @@ -2319,7 +2343,7 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, N0.getValueType()), Cond); } - } + } } // Simplify (X+Z) == X --> Z == 0 @@ -2334,7 +2358,7 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, assert(N0.getOpcode() == ISD::SUB && "Unexpected operation!"); // (Z-X) == X --> Z == X<<1 SDValue SH = DAG.getNode(ISD::SHL, dl, N1.getValueType(), - N1, + N1, DAG.getConstant(1, getShiftAmountTy())); if (!DCI.isCalledByLegalizer()) DCI.AddToWorklist(SH.getNode()); @@ -2356,7 +2380,7 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, } else if (N1.getNode()->hasOneUse()) { assert(N1.getOpcode() == ISD::SUB && "Unexpected operation!"); // X == (Z-X) --> X<<1 == Z - SDValue SH = DAG.getNode(ISD::SHL, dl, N1.getValueType(), N0, + SDValue SH = DAG.getNode(ISD::SHL, dl, N1.getValueType(), N0, DAG.getConstant(1, getShiftAmountTy())); if (!DCI.isCalledByLegalizer()) DCI.AddToWorklist(SH.getNode()); @@ -2443,7 +2467,7 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1, /// isGAPlusOffset - Returns true (and the GlobalValue and the offset) if the /// node is a GlobalAddress + offset. -bool TargetLowering::isGAPlusOffset(SDNode *N, const GlobalValue* &GA, +bool TargetLowering::isGAPlusOffset(SDNode *N, const GlobalValue *&GA, int64_t &Offset) const { if (isa(N)) { GlobalAddressSDNode *GASD = cast(N); @@ -2469,6 +2493,7 @@ bool TargetLowering::isGAPlusOffset(SDNode *N, const GlobalValue* &GA, } } } + return false; } @@ -2497,7 +2522,10 @@ TargetLowering::getConstraintType(const std::string &Constraint) const { return C_Memory; case 'i': // Simple Integer or Relocatable Constant case 'n': // Simple Integer + case 'E': // Floating Point Constant + case 'F': // Floating Point Constant case 's': // Relocatable Constant + case 'p': // Address. case 'X': // Allow ANY value. case 'I': // Target registers. case 'J': @@ -2507,11 +2535,13 @@ TargetLowering::getConstraintType(const std::string &Constraint) const { case 'N': case 'O': case 'P': + case '<': + case '>': return C_Other; } } - - if (Constraint.size() > 1 && Constraint[0] == '{' && + + if (Constraint.size() > 1 && Constraint[0] == '{' && Constraint[Constraint.size()-1] == '}') return C_Register; return C_Unknown; @@ -2550,7 +2580,7 @@ void TargetLowering::LowerAsmOperandForConstraint(SDValue Op, // is possible and fine if either GV or C are missing. ConstantSDNode *C = dyn_cast(Op); GlobalAddressSDNode *GA = dyn_cast(Op); - + // If we have "(add GV, C)", pull out GV/C if (Op.getOpcode() == ISD::ADD) { C = dyn_cast(Op.getOperand(1)); @@ -2562,14 +2592,14 @@ void TargetLowering::LowerAsmOperandForConstraint(SDValue Op, if (C == 0 || GA == 0) C = 0, GA = 0; } - + // If we find a valid operand, map to the TargetXXX version so that the // value itself doesn't get selected. if (GA) { // Either &GV or &GV+C if (ConstraintLetter != 'n') { int64_t Offs = GA->getOffset(); if (C) Offs += C->getZExtValue(); - Ops.push_back(DAG.getTargetGlobalAddress(GA->getGlobal(), + Ops.push_back(DAG.getTargetGlobalAddress(GA->getGlobal(), C ? C->getDebugLoc() : DebugLoc(), Op.getValueType(), Offs)); return; @@ -2613,8 +2643,8 @@ getRegForInlineAsmConstraint(const std::string &Constraint, for (TargetRegisterInfo::regclass_iterator RCI = RI->regclass_begin(), E = RI->regclass_end(); RCI != E; ++RCI) { const TargetRegisterClass *RC = *RCI; - - // If none of the value types for this register class are valid, we + + // If none of the value types for this register class are valid, we // can't use it. For example, 64-bit reg classes on 32-bit targets. bool isLegal = false; for (TargetRegisterClass::vt_iterator I = RC->vt_begin(), E = RC->vt_end(); @@ -2624,16 +2654,16 @@ getRegForInlineAsmConstraint(const std::string &Constraint, break; } } - + if (!isLegal) continue; - - for (TargetRegisterClass::iterator I = RC->begin(), E = RC->end(); + + for (TargetRegisterClass::iterator I = RC->begin(), E = RC->end(); I != E; ++I) { if (RegName.equals_lower(RI->getName(*I))) return std::make_pair(*I, RC); } } - + return std::make_pair(0u, static_cast(0)); } @@ -2655,6 +2685,186 @@ unsigned TargetLowering::AsmOperandInfo::getMatchedOperand() const { } +/// ParseConstraints - Split up the constraint string from the inline +/// assembly value into the specific constraints and their prefixes, +/// and also tie in the associated operand values. +/// If this returns an empty vector, and if the constraint string itself +/// isn't empty, there was an error parsing. +TargetLowering::AsmOperandInfoVector TargetLowering::ParseConstraints( + ImmutableCallSite CS) const { + /// ConstraintOperands - Information about all of the constraints. + AsmOperandInfoVector ConstraintOperands; + const InlineAsm *IA = cast(CS.getCalledValue()); + unsigned maCount = 0; // Largest number of multiple alternative constraints. + + // Do a prepass over the constraints, canonicalizing them, and building up the + // ConstraintOperands list. + InlineAsm::ConstraintInfoVector + ConstraintInfos = IA->ParseConstraints(); + + unsigned ArgNo = 0; // ArgNo - The argument of the CallInst. + unsigned ResNo = 0; // ResNo - The result number of the next output. + + for (unsigned i = 0, e = ConstraintInfos.size(); i != e; ++i) { + ConstraintOperands.push_back(AsmOperandInfo(ConstraintInfos[i])); + AsmOperandInfo &OpInfo = ConstraintOperands.back(); + + // Update multiple alternative constraint count. + if (OpInfo.multipleAlternatives.size() > maCount) + maCount = OpInfo.multipleAlternatives.size(); + + OpInfo.ConstraintVT = MVT::Other; + + // Compute the value type for each operand. + switch (OpInfo.Type) { + case InlineAsm::isOutput: + // Indirect outputs just consume an argument. + if (OpInfo.isIndirect) { + OpInfo.CallOperandVal = const_cast(CS.getArgument(ArgNo++)); + break; + } + + // The return value of the call is this value. As such, there is no + // corresponding argument. + assert(!CS.getType()->isVoidTy() && + "Bad inline asm!"); + if (const StructType *STy = dyn_cast(CS.getType())) { + OpInfo.ConstraintVT = getValueType(STy->getElementType(ResNo)); + } else { + assert(ResNo == 0 && "Asm only has one result!"); + OpInfo.ConstraintVT = getValueType(CS.getType()); + } + ++ResNo; + break; + case InlineAsm::isInput: + OpInfo.CallOperandVal = const_cast(CS.getArgument(ArgNo++)); + break; + case InlineAsm::isClobber: + // Nothing to do. + break; + } + + if (OpInfo.CallOperandVal) { + const llvm::Type *OpTy = OpInfo.CallOperandVal->getType(); + if (OpInfo.isIndirect) { + const llvm::PointerType *PtrTy = dyn_cast(OpTy); + if (!PtrTy) + report_fatal_error("Indirect operand for inline asm not a pointer!"); + OpTy = PtrTy->getElementType(); + } + // If OpTy is not a single value, it may be a struct/union that we + // can tile with integers. + if (!OpTy->isSingleValueType() && OpTy->isSized()) { + unsigned BitSize = TD->getTypeSizeInBits(OpTy); + switch (BitSize) { + default: break; + case 1: + case 8: + case 16: + case 32: + case 64: + case 128: + OpInfo.ConstraintVT = + EVT::getEVT(IntegerType::get(OpTy->getContext(), BitSize), true); + break; + } + } else if (dyn_cast(OpTy)) { + OpInfo.ConstraintVT = MVT::getIntegerVT(8*TD->getPointerSize()); + } else { + OpInfo.ConstraintVT = EVT::getEVT(OpTy, true); + } + } + } + + // If we have multiple alternative constraints, select the best alternative. + if (ConstraintInfos.size()) { + if (maCount) { + unsigned bestMAIndex = 0; + int bestWeight = -1; + // weight: -1 = invalid match, and 0 = so-so match to 5 = good match. + int weight = -1; + unsigned maIndex; + // Compute the sums of the weights for each alternative, keeping track + // of the best (highest weight) one so far. + for (maIndex = 0; maIndex < maCount; ++maIndex) { + int weightSum = 0; + for (unsigned cIndex = 0, eIndex = ConstraintOperands.size(); + cIndex != eIndex; ++cIndex) { + AsmOperandInfo& OpInfo = ConstraintOperands[cIndex]; + if (OpInfo.Type == InlineAsm::isClobber) + continue; + + // If this is an output operand with a matching input operand, + // look up the matching input. If their types mismatch, e.g. one + // is an integer, the other is floating point, or their sizes are + // different, flag it as an maCantMatch. + if (OpInfo.hasMatchingInput()) { + AsmOperandInfo &Input = ConstraintOperands[OpInfo.MatchingInput]; + if (OpInfo.ConstraintVT != Input.ConstraintVT) { + if ((OpInfo.ConstraintVT.isInteger() != + Input.ConstraintVT.isInteger()) || + (OpInfo.ConstraintVT.getSizeInBits() != + Input.ConstraintVT.getSizeInBits())) { + weightSum = -1; // Can't match. + break; + } + } + } + weight = getMultipleConstraintMatchWeight(OpInfo, maIndex); + if (weight == -1) { + weightSum = -1; + break; + } + weightSum += weight; + } + // Update best. + if (weightSum > bestWeight) { + bestWeight = weightSum; + bestMAIndex = maIndex; + } + } + + // 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); + } + } + } + + // Check and hook up tied operands, choose constraint code to use. + for (unsigned cIndex = 0, eIndex = ConstraintOperands.size(); + cIndex != eIndex; ++cIndex) { + AsmOperandInfo& OpInfo = ConstraintOperands[cIndex]; + + // If this is an output operand with a matching input operand, look up the + // matching input. If their types mismatch, e.g. one is an integer, the + // other is floating point, or their sizes are different, flag it as an + // error. + if (OpInfo.hasMatchingInput()) { + AsmOperandInfo &Input = ConstraintOperands[OpInfo.MatchingInput]; + + if (OpInfo.ConstraintVT != Input.ConstraintVT) { + if ((OpInfo.ConstraintVT.isInteger() != + Input.ConstraintVT.isInteger()) || + (OpInfo.ConstraintVT.getSizeInBits() != + Input.ConstraintVT.getSizeInBits())) { + report_fatal_error("Unsupported asm: input constraint" + " with a matching output constraint of" + " incompatible type!"); + } + } + + } + } + + return ConstraintOperands; +} + + /// getConstraintGenerality - Return an integer indicating how general CT /// is. static unsigned getConstraintGenerality(TargetLowering::ConstraintType CT) { @@ -2672,6 +2882,79 @@ static unsigned getConstraintGenerality(TargetLowering::ConstraintType CT) { } } +/// Examine constraint type and operand type and determine a weight value. +/// This object must already have been set up with the operand type +/// and the current alternative constraint selected. +TargetLowering::ConstraintWeight + TargetLowering::getMultipleConstraintMatchWeight( + AsmOperandInfo &info, int maIndex) const { + InlineAsm::ConstraintCodeVector *rCodes; + if (maIndex >= (int)info.multipleAlternatives.size()) + rCodes = &info.Codes; + else + rCodes = &info.multipleAlternatives[maIndex].Codes; + 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) { + ConstraintWeight weight = + getSingleConstraintMatchWeight(info, (*rCodes)[i].c_str()); + if (weight > BestWeight) + BestWeight = weight; + } + + return BestWeight; +} + +/// Examine constraint type and operand type and determine a weight value. +/// This object must already have been set up with the operand type +/// and the current alternative constraint selected. +TargetLowering::ConstraintWeight + TargetLowering::getSingleConstraintMatchWeight( + AsmOperandInfo &info, const char *constraint) const { + ConstraintWeight weight = CW_Invalid; + Value *CallOperandVal = info.CallOperandVal; + // If we don't have a value, we can't do a match, + // but allow it at the lowest weight. + if (CallOperandVal == NULL) + return CW_Default; + // Look at the constraint type. + switch (*constraint) { + case 'i': // immediate integer. + case 'n': // immediate integer with a known value. + if (isa(CallOperandVal)) + weight = CW_Constant; + break; + case 's': // non-explicit intregal immediate. + if (isa(CallOperandVal)) + weight = CW_Constant; + break; + case 'E': // immediate float if host format. + case 'F': // immediate float. + if (isa(CallOperandVal)) + weight = CW_Constant; + break; + case '<': // memory operand with autodecrement. + case '>': // memory operand with autoincrement. + case 'm': // memory operand. + case 'o': // offsettable memory operand + case 'V': // non-offsettable memory operand + weight = CW_Memory; + break; + case 'r': // general register. + case 'g': // general register, memory operand or immediate integer. + // note: Clang converts "g" to "imr". + if (CallOperandVal->getType()->isIntegerTy()) + weight = CW_Register; + break; + case 'X': // any operand. + default: + weight = CW_Default; + break; + } + return weight; +} + /// ChooseConstraint - If there are multiple different constraints that we /// could pick for this operand (e.g. "imr") try to pick the 'best' one. /// This is somewhat tricky: constraints fall into four classes: @@ -2721,12 +3004,12 @@ static void ChooseConstraint(TargetLowering::AsmOperandInfo &OpInfo, break; } } - + // Things with matching constraints can only be registers, per gcc // documentation. This mainly affects "g" constraints. if (CType == TargetLowering::C_Memory && OpInfo.hasMatchingInput()) continue; - + // This constraint letter is more general than the previous one, use it. int Generality = getConstraintGenerality(CType); if (Generality > BestGenerality) { @@ -2735,7 +3018,7 @@ static void ChooseConstraint(TargetLowering::AsmOperandInfo &OpInfo, BestGenerality = Generality; } } - + OpInfo.ConstraintCode = OpInfo.Codes[BestIdx]; OpInfo.ConstraintType = BestType; } @@ -2744,10 +3027,10 @@ static void ChooseConstraint(TargetLowering::AsmOperandInfo &OpInfo, /// type to use for the specific AsmOperandInfo, setting /// OpInfo.ConstraintCode and OpInfo.ConstraintType. void TargetLowering::ComputeConstraintToUse(AsmOperandInfo &OpInfo, - SDValue Op, + SDValue Op, SelectionDAG *DAG) const { assert(!OpInfo.Codes.empty() && "Must have at least one constraint"); - + // Single-letter constraints ('r') are very common. if (OpInfo.Codes.size() == 1) { OpInfo.ConstraintCode = OpInfo.Codes[0]; @@ -2755,7 +3038,7 @@ void TargetLowering::ComputeConstraintToUse(AsmOperandInfo &OpInfo, } else { ChooseConstraint(OpInfo, *this, Op, DAG); } - + // 'X' matches anything. if (OpInfo.ConstraintCode == "X" && OpInfo.CallOperandVal) { // Labels and constants are handled elsewhere ('X' is the only thing @@ -2766,7 +3049,7 @@ void TargetLowering::ComputeConstraintToUse(AsmOperandInfo &OpInfo, OpInfo.CallOperandVal = v; return; } - + // Otherwise, try to resolve it to something we know about by looking at // the actual operand type. if (const char *Repl = LowerXConstraint(OpInfo.ConstraintVT)) { @@ -2782,7 +3065,7 @@ void TargetLowering::ComputeConstraintToUse(AsmOperandInfo &OpInfo, /// isLegalAddressingMode - Return true if the addressing mode represented /// by AM is legal for this target, for a load/store of the specified type. -bool TargetLowering::isLegalAddressingMode(const AddrMode &AM, +bool TargetLowering::isLegalAddressingMode(const AddrMode &AM, const Type *Ty) const { // The default implementation of this implements a conservative RISCy, r+r and // r+i addr mode. @@ -2790,12 +3073,12 @@ bool TargetLowering::isLegalAddressingMode(const AddrMode &AM, // Allows a sign-extended 16-bit immediate field. if (AM.BaseOffs <= -(1LL << 16) || AM.BaseOffs >= (1LL << 16)-1) return false; - + // No global is ever allowed as a base. if (AM.BaseGV) return false; - - // Only support r+r, + + // Only support r+r, switch (AM.Scale) { case 0: // "r+i" or just "i", depending on HasBaseReg. break; @@ -2810,7 +3093,7 @@ bool TargetLowering::isLegalAddressingMode(const AddrMode &AM, // Allow 2*r as r+r. break; } - + return true; } @@ -2818,19 +3101,19 @@ bool TargetLowering::isLegalAddressingMode(const AddrMode &AM, /// return a DAG expression to select that will generate the same value by /// multiplying by a magic number. See: /// -SDValue TargetLowering::BuildSDIV(SDNode *N, SelectionDAG &DAG, +SDValue TargetLowering::BuildSDIV(SDNode *N, SelectionDAG &DAG, std::vector* Created) const { EVT VT = N->getValueType(0); DebugLoc dl= N->getDebugLoc(); - + // Check to see if we can do this. // FIXME: We should be more aggressive here. if (!isTypeLegal(VT)) return SDValue(); - + APInt d = cast(N->getOperand(1))->getAPIntValue(); APInt::ms magics = d.magic(); - + // Multiply the numerator (operand 0) by the magic value // FIXME: We should support doing a MUL in a wider type SDValue Q; @@ -2844,7 +3127,7 @@ SDValue TargetLowering::BuildSDIV(SDNode *N, SelectionDAG &DAG, else return SDValue(); // No mulhs or equvialent // If d > 0 and m < 0, add the numerator - if (d.isStrictlyPositive() && magics.m.isNegative()) { + if (d.isStrictlyPositive() && magics.m.isNegative()) { Q = DAG.getNode(ISD::ADD, dl, VT, Q, N->getOperand(0)); if (Created) Created->push_back(Q.getNode()); @@ -2857,7 +3140,7 @@ SDValue TargetLowering::BuildSDIV(SDNode *N, SelectionDAG &DAG, } // Shift right algebraic if shift value is nonzero if (magics.s > 0) { - Q = DAG.getNode(ISD::SRA, dl, VT, Q, + Q = DAG.getNode(ISD::SRA, dl, VT, Q, DAG.getConstant(magics.s, getShiftAmountTy())); if (Created) Created->push_back(Q.getNode()); @@ -2908,20 +3191,20 @@ SDValue TargetLowering::BuildUDIV(SDNode *N, SelectionDAG &DAG, if (magics.a == 0) { assert(magics.s < N1C->getAPIntValue().getBitWidth() && "We shouldn't generate an undefined shift!"); - return DAG.getNode(ISD::SRL, dl, VT, Q, + return DAG.getNode(ISD::SRL, dl, VT, Q, DAG.getConstant(magics.s, getShiftAmountTy())); } else { SDValue NPQ = DAG.getNode(ISD::SUB, dl, VT, N->getOperand(0), Q); if (Created) Created->push_back(NPQ.getNode()); - NPQ = DAG.getNode(ISD::SRL, dl, VT, NPQ, + NPQ = DAG.getNode(ISD::SRL, dl, VT, NPQ, DAG.getConstant(1, getShiftAmountTy())); if (Created) Created->push_back(NPQ.getNode()); NPQ = DAG.getNode(ISD::ADD, dl, VT, NPQ, Q); if (Created) Created->push_back(NPQ.getNode()); - return DAG.getNode(ISD::SRL, dl, VT, NPQ, + return DAG.getNode(ISD::SRL, dl, VT, NPQ, DAG.getConstant(magics.s-1, getShiftAmountTy())); } } diff --git a/lib/CodeGen/ShrinkWrapping.cpp b/lib/CodeGen/ShrinkWrapping.cpp index aeaa38b56433..7b5bca495206 100644 --- a/lib/CodeGen/ShrinkWrapping.cpp +++ b/lib/CodeGen/ShrinkWrapping.cpp @@ -226,7 +226,7 @@ bool PEI::calcAnticInOut(MachineBasicBlock* MBB) { // AnticIn[MBB] = UNION(CSRUsed[MBB], AnticOut[MBB]); CSRegSet prevAnticIn = AnticIn[MBB]; AnticIn[MBB] = CSRUsed[MBB] | AnticOut[MBB]; - if (prevAnticIn |= AnticIn[MBB]) + if (prevAnticIn != AnticIn[MBB]) changed = true; return changed; } @@ -264,7 +264,7 @@ bool PEI::calcAvailInOut(MachineBasicBlock* MBB) { // AvailOut[MBB] = UNION(CSRUsed[MBB], AvailIn[MBB]); CSRegSet prevAvailOut = AvailOut[MBB]; AvailOut[MBB] = CSRUsed[MBB] | AvailIn[MBB]; - if (prevAvailOut |= AvailOut[MBB]) + if (prevAvailOut != AvailOut[MBB]) changed = true; return changed; } diff --git a/lib/CodeGen/SimpleRegisterCoalescing.cpp b/lib/CodeGen/SimpleRegisterCoalescing.cpp index b29ea19835bc..2843c1a5b6d8 100644 --- a/lib/CodeGen/SimpleRegisterCoalescing.cpp +++ b/lib/CodeGen/SimpleRegisterCoalescing.cpp @@ -15,6 +15,7 @@ #define DEBUG_TYPE "regcoalescing" #include "SimpleRegisterCoalescing.h" #include "VirtRegMap.h" +#include "LiveDebugVariables.h" #include "llvm/CodeGen/LiveIntervalAnalysis.h" #include "llvm/Value.h" #include "llvm/Analysis/AliasAnalysis.h" @@ -64,9 +65,25 @@ DisablePhysicalJoin("disable-physical-join", cl::desc("Avoid coalescing physical register copies"), cl::init(false), cl::Hidden); -INITIALIZE_AG_PASS(SimpleRegisterCoalescing, RegisterCoalescer, +static cl::opt +VerifyCoalescing("verify-coalescing", + cl::desc("Verify machine instrs before and after register coalescing"), + cl::Hidden); + +INITIALIZE_AG_PASS_BEGIN(SimpleRegisterCoalescing, RegisterCoalescer, "simple-register-coalescing", "Simple Register Coalescing", - false, false, true); + false, false, true) +INITIALIZE_PASS_DEPENDENCY(LiveIntervals) +INITIALIZE_PASS_DEPENDENCY(LiveDebugVariables) +INITIALIZE_PASS_DEPENDENCY(SlotIndexes) +INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo) +INITIALIZE_PASS_DEPENDENCY(StrongPHIElimination) +INITIALIZE_PASS_DEPENDENCY(PHIElimination) +INITIALIZE_PASS_DEPENDENCY(TwoAddressInstructionPass) +INITIALIZE_AG_DEPENDENCY(AliasAnalysis) +INITIALIZE_AG_PASS_END(SimpleRegisterCoalescing, RegisterCoalescer, + "simple-register-coalescing", "Simple Register Coalescing", + false, false, true) char &llvm::SimpleRegisterCoalescingID = SimpleRegisterCoalescing::ID; @@ -75,14 +92,14 @@ void SimpleRegisterCoalescing::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); AU.addRequired(); AU.addPreserved(); + AU.addRequired(); + AU.addPreserved(); AU.addPreserved(); AU.addRequired(); AU.addPreserved(); AU.addPreservedID(MachineDominatorsID); - if (StrongPHIElim) - AU.addPreservedID(StrongPHIEliminationID); - else - AU.addPreservedID(PHIEliminationID); + AU.addPreservedID(StrongPHIEliminationID); + AU.addPreservedID(PHIEliminationID); AU.addPreservedID(TwoAddressInstructionPassID); MachineFunctionPass::getAnalysisUsage(AU); } @@ -124,7 +141,7 @@ bool SimpleRegisterCoalescing::AdjustCopiesBackFrom(const CoalescerPair &CP, // Get the location that B is defined at. Two options: either this value has // an unknown definition point or it is defined at CopyIdx. If unknown, we // can't process it. - if (!BValNo->getCopy()) return false; + if (!BValNo->isDefByCopy()) return false; assert(BValNo->def == CopyIdx && "Copy doesn't define the value?"); // AValNo is the value number in A that defines the copy, A3 in the example. @@ -218,7 +235,7 @@ bool SimpleRegisterCoalescing::AdjustCopiesBackFrom(const CoalescerPair &CP, continue; LiveInterval &SRLI = li_->getInterval(*SR); SRLI.addRange(LiveRange(FillerStart, FillerEnd, - SRLI.getNextValue(FillerStart, 0, true, + SRLI.getNextValue(FillerStart, 0, li_->getVNInfoAllocator()))); } } @@ -266,9 +283,6 @@ bool SimpleRegisterCoalescing::HasOtherReachingDefs(LiveInterval &IntA, for (; BI != IntB.ranges.end() && AI->end >= BI->start; ++BI) { if (BI->valno == BValNo) continue; - // When BValNo is null, we're looking for a dummy clobber-value for a subreg. - if (!BValNo && !BI->valno->isDefAccurate() && !BI->valno->getCopy()) - continue; if (BI->start <= AI->start && BI->end > AI->start) return true; if (BI->start > AI->start && BI->start < AI->end) @@ -278,16 +292,6 @@ bool SimpleRegisterCoalescing::HasOtherReachingDefs(LiveInterval &IntA, return false; } -static void -TransferImplicitOps(MachineInstr *MI, MachineInstr *NewMI) { - for (unsigned i = MI->getDesc().getNumOperands(), e = MI->getNumOperands(); - i != e; ++i) { - MachineOperand &MO = MI->getOperand(i); - if (MO.isReg() && MO.isImplicit()) - NewMI->addOperand(MO); - } -} - /// RemoveCopyByCommutingDef - We found a non-trivially-coalescable copy with /// IntA being the source and IntB being the dest, thus this defines a value /// number in IntB. If the source value number (in IntA) is defined by a @@ -324,8 +328,7 @@ bool SimpleRegisterCoalescing::RemoveCopyByCommutingDef(const CoalescerPair &CP, if (!li_->hasInterval(CP.getDstReg())) return false; - SlotIndex CopyIdx = - li_->getInstructionIndex(CopyMI).getDefIndex(); + SlotIndex CopyIdx = li_->getInstructionIndex(CopyMI).getDefIndex(); LiveInterval &IntA = li_->getInterval(CP.isFlipped() ? CP.getDstReg() : CP.getSrcReg()); @@ -334,27 +337,19 @@ bool SimpleRegisterCoalescing::RemoveCopyByCommutingDef(const CoalescerPair &CP, // BValNo is a value number in B that is defined by a copy from A. 'B3' in // the example above. - LiveInterval::iterator BLR = IntB.FindLiveRangeContaining(CopyIdx); - if (BLR == IntB.end()) return false; - VNInfo *BValNo = BLR->valno; + VNInfo *BValNo = IntB.getVNInfoAt(CopyIdx); + if (!BValNo || !BValNo->isDefByCopy()) + return false; - // Get the location that B is defined at. Two options: either this value has - // an unknown definition point or it is defined at CopyIdx. If unknown, we - // can't process it. - if (!BValNo->getCopy()) return false; assert(BValNo->def == CopyIdx && "Copy doesn't define the value?"); // AValNo is the value number in A that defines the copy, A3 in the example. - LiveInterval::iterator ALR = - IntA.FindLiveRangeContaining(CopyIdx.getUseIndex()); // + VNInfo *AValNo = IntA.getVNInfoAt(CopyIdx.getUseIndex()); + assert(AValNo && "COPY source not live"); - assert(ALR != IntA.end() && "Live range not found!"); - VNInfo *AValNo = ALR->valno; // If other defs can reach uses of this def, then it's not safe to perform - // the optimization. FIXME: Do isPHIDef and isDefAccurate both need to be - // tested? - if (AValNo->isPHIDef() || !AValNo->isDefAccurate() || - AValNo->isUnused() || AValNo->hasPHIKill()) + // the optimization. + if (AValNo->isPHIDef() || AValNo->isUnused() || AValNo->hasPHIKill()) return false; MachineInstr *DefMI = li_->getInstructionFromIndex(AValNo->def); if (!DefMI) @@ -411,7 +406,8 @@ bool SimpleRegisterCoalescing::RemoveCopyByCommutingDef(const CoalescerPair &CP, return false; } - DEBUG(dbgs() << "\tRemoveCopyByCommutingDef: " << *DefMI); + DEBUG(dbgs() << "\tRemoveCopyByCommutingDef: " << AValNo->def << '\t' + << *DefMI); // At this point we have decided that it is legal to do this // transformation. Start by commuting the instruction. @@ -427,10 +423,6 @@ bool SimpleRegisterCoalescing::RemoveCopyByCommutingDef(const CoalescerPair &CP, unsigned OpIdx = NewMI->findRegisterUseOperandIdx(IntA.reg, false); NewMI->getOperand(OpIdx).setIsKill(); - bool BHasPHIKill = BValNo->hasPHIKill(); - SmallVector BDeadValNos; - std::map BExtend; - // If ALR and BLR overlaps and end of BLR extends beyond end of ALR, e.g. // A = or A, B // ... @@ -439,9 +431,6 @@ bool SimpleRegisterCoalescing::RemoveCopyByCommutingDef(const CoalescerPair &CP, // C = A // ... // = B - bool Extended = BLR->end > ALR->end && ALR->end != ALR->start; - if (Extended) - BExtend[ALR->end] = BLR->end; // Update uses of IntA of the specific Val# with IntB. for (MachineRegisterInfo::use_iterator UI = mri_->use_begin(IntA.reg), @@ -467,52 +456,24 @@ bool SimpleRegisterCoalescing::RemoveCopyByCommutingDef(const CoalescerPair &CP, UseMO.setReg(NewReg); if (UseMI == CopyMI) continue; - if (UseMO.isKill()) { - if (Extended) - UseMO.setIsKill(false); - } if (!UseMI->isCopy()) continue; if (UseMI->getOperand(0).getReg() != IntB.reg || UseMI->getOperand(0).getSubReg()) continue; - // This copy will become a noop. If it's defining a new val#, - // remove that val# as well. However this live range is being - // extended to the end of the existing live range defined by the copy. + // This copy will become a noop. If it's defining a new val#, merge it into + // BValNo. SlotIndex DefIdx = UseIdx.getDefIndex(); - const LiveRange *DLR = IntB.getLiveRangeContaining(DefIdx); - if (!DLR) + VNInfo *DVNI = IntB.getVNInfoAt(DefIdx); + if (!DVNI) continue; - BHasPHIKill |= DLR->valno->hasPHIKill(); - assert(DLR->valno->def == DefIdx); - BDeadValNos.push_back(DLR->valno); - BExtend[DLR->start] = DLR->end; + DEBUG(dbgs() << "\t\tnoop: " << DefIdx << '\t' << *UseMI); + assert(DVNI->def == DefIdx); + BValNo = IntB.MergeValueNumberInto(BValNo, DVNI); JoinedCopies.insert(UseMI); } - // We need to insert a new liverange: [ALR.start, LastUse). It may be we can - // simply extend BLR if CopyMI doesn't end the range. - DEBUG({ - dbgs() << "Extending: "; - IntB.print(dbgs(), tri_); - }); - - // Remove val#'s defined by copies that will be coalesced away. - for (unsigned i = 0, e = BDeadValNos.size(); i != e; ++i) { - VNInfo *DeadVNI = BDeadValNos[i]; - if (TargetRegisterInfo::isPhysicalRegister(IntB.reg)) { - for (const unsigned *AS = tri_->getAliasSet(IntB.reg); *AS; ++AS) { - if (!li_->hasInterval(*AS)) - continue; - LiveInterval &ASLI = li_->getInterval(*AS); - if (const LiveRange *ASLR = ASLI.getLiveRangeContaining(DeadVNI->def)) - ASLI.removeValNo(ASLR->valno); - } - } - IntB.removeValNo(BDeadValNos[i]); - } - // Extend BValNo by merging in IntA live ranges of AValNo. Val# definition // is updated. VNInfo *ValNo = BValNo; @@ -521,30 +482,12 @@ bool SimpleRegisterCoalescing::RemoveCopyByCommutingDef(const CoalescerPair &CP, for (LiveInterval::iterator AI = IntA.begin(), AE = IntA.end(); AI != AE; ++AI) { if (AI->valno != AValNo) continue; - SlotIndex End = AI->end; - std::map::iterator - EI = BExtend.find(End); - if (EI != BExtend.end()) - End = EI->second; - IntB.addRange(LiveRange(AI->start, End, ValNo)); + IntB.addRange(LiveRange(AI->start, AI->end, ValNo)); } - ValNo->setHasPHIKill(BHasPHIKill); - - DEBUG({ - dbgs() << " result = "; - IntB.print(dbgs(), tri_); - dbgs() << "\nShortening: "; - IntA.print(dbgs(), tri_); - }); + DEBUG(dbgs() << "\t\textended: " << IntB << '\n'); IntA.removeValNo(AValNo); - - DEBUG({ - dbgs() << " result = "; - IntA.print(dbgs(), tri_); - dbgs() << '\n'; - }); - + DEBUG(dbgs() << "\t\ttrimmed: " << IntA << '\n'); ++numCommutes; return true; } @@ -644,6 +587,7 @@ SimpleRegisterCoalescing::TrimLiveIntervalToLastUse(SlotIndex CopyIdx, /// ReMaterializeTrivialDef - If the source of a copy is defined by a trivial /// computation, replace the copy by rematerialize the definition. bool SimpleRegisterCoalescing::ReMaterializeTrivialDef(LiveInterval &SrcInt, + bool preserveSrcInt, unsigned DstReg, unsigned DstSubIdx, MachineInstr *CopyMI) { @@ -652,12 +596,12 @@ bool SimpleRegisterCoalescing::ReMaterializeTrivialDef(LiveInterval &SrcInt, assert(SrcLR != SrcInt.end() && "Live range not found!"); VNInfo *ValNo = SrcLR->valno; // If other defs can reach uses of this def, then it's not safe to perform - // the optimization. FIXME: Do isPHIDef and isDefAccurate both need to be - // tested? - if (ValNo->isPHIDef() || !ValNo->isDefAccurate() || - ValNo->isUnused() || ValNo->hasPHIKill()) + // the optimization. + if (ValNo->isPHIDef() || ValNo->isUnused() || ValNo->hasPHIKill()) return false; MachineInstr *DefMI = li_->getInstructionFromIndex(ValNo->def); + if (!DefMI) + return false; assert(DefMI && "Defining instruction disappeared"); const TargetInstrDesc &TID = DefMI->getDesc(); if (!TID.isAsCheapAsAMove()) @@ -681,8 +625,8 @@ bool SimpleRegisterCoalescing::ReMaterializeTrivialDef(LiveInterval &SrcInt, return false; } - // If destination register has a sub-register index on it, make sure it mtches - // the instruction register class. + // If destination register has a sub-register index on it, make sure it + // matches the instruction register class. if (DstSubIdx) { const TargetInstrDesc &TID = DefMI->getDesc(); if (TID.getNumDefs() != 1) @@ -699,30 +643,12 @@ bool SimpleRegisterCoalescing::ReMaterializeTrivialDef(LiveInterval &SrcInt, RemoveCopyFlag(DstReg, CopyMI); - // If copy kills the source register, find the last use and propagate - // kill. - bool checkForDeadDef = false; MachineBasicBlock *MBB = CopyMI->getParent(); - if (SrcLR->end == CopyIdx.getDefIndex()) - if (!TrimLiveIntervalToLastUse(CopyIdx, MBB, SrcInt, SrcLR)) { - checkForDeadDef = true; - } - MachineBasicBlock::iterator MII = llvm::next(MachineBasicBlock::iterator(CopyMI)); tii_->reMaterialize(*MBB, MII, DstReg, DstSubIdx, DefMI, *tri_); MachineInstr *NewMI = prior(MII); - if (checkForDeadDef) { - // PR4090 fix: Trim interval failed because there was no use of the - // source interval in this MBB. If the def is in this MBB too then we - // should mark it dead: - if (DefMI->getParent() == MBB) { - DefMI->addRegisterDead(SrcInt.reg, tri_); - SrcLR->end = SrcLR->start.getNextSlot(); - } - } - // CopyMI may have implicit operands, transfer them over to the newly // rematerialized instruction. And update implicit def interval valnos. for (unsigned i = CopyMI->getDesc().getNumOperands(), @@ -734,13 +660,18 @@ bool SimpleRegisterCoalescing::ReMaterializeTrivialDef(LiveInterval &SrcInt, RemoveCopyFlag(MO.getReg(), CopyMI); } - TransferImplicitOps(CopyMI, NewMI); + NewMI->copyImplicitOps(CopyMI); li_->ReplaceMachineInstrInMaps(CopyMI, NewMI); CopyMI->eraseFromParent(); ReMatCopies.insert(CopyMI); ReMatDefs.insert(DefMI); DEBUG(dbgs() << "Remat: " << *NewMI); ++NumReMats; + + // The source interval can become smaller because we removed a use. + if (preserveSrcInt) + li_->shrinkToUses(&SrcInt); + return true; } @@ -756,6 +687,9 @@ SimpleRegisterCoalescing::UpdateRegDefsUses(const CoalescerPair &CP) { unsigned DstReg = CP.getDstReg(); unsigned SubIdx = CP.getSubIdx(); + // Update LiveDebugVariables. + ldv_->renameRegister(SrcReg, DstReg, SubIdx); + for (MachineRegisterInfo::reg_iterator I = mri_->reg_begin(SrcReg); MachineInstr *UseMI = I.skipInstruction();) { // A PhysReg copy that won't be coalesced can perhaps be rematerialized @@ -768,7 +702,7 @@ SimpleRegisterCoalescing::UpdateRegDefsUses(const CoalescerPair &CP) { UseMI->getOperand(0).getReg() != SrcReg && UseMI->getOperand(0).getReg() != DstReg && !JoinedCopies.count(UseMI) && - ReMaterializeTrivialDef(li_->getInterval(SrcReg), + ReMaterializeTrivialDef(li_->getInterval(SrcReg), false, UseMI->getOperand(0).getReg(), 0, UseMI)) continue; } @@ -874,7 +808,7 @@ void SimpleRegisterCoalescing::RemoveCopyFlag(unsigned DstReg, if (li_->hasInterval(DstReg)) { LiveInterval &LI = li_->getInterval(DstReg); if (const LiveRange *LR = LI.getLiveRangeContaining(DefIdx)) - if (LR->valno->getCopy() == CopyMI) + if (LR->valno->def == DefIdx) LR->valno->setCopy(0); } if (!TargetRegisterInfo::isPhysicalRegister(DstReg)) @@ -884,7 +818,7 @@ void SimpleRegisterCoalescing::RemoveCopyFlag(unsigned DstReg, continue; LiveInterval &LI = li_->getInterval(*AS); if (const LiveRange *LR = LI.getLiveRangeContaining(DefIdx)) - if (LR->valno->getCopy() == CopyMI) + if (LR->valno->def == DefIdx) LR->valno->setCopy(0); } } @@ -1044,23 +978,19 @@ bool SimpleRegisterCoalescing::JoinCopy(CopyRec &TheCopy, bool &Again) { return false; } - DEBUG(dbgs() << "\tConsidering merging %reg" << CP.getSrcReg()); + DEBUG(dbgs() << "\tConsidering merging " << PrintReg(CP.getSrcReg(), tri_)); // Enforce policies. if (CP.isPhys()) { - DEBUG(dbgs() <<" with physreg %" << tri_->getName(CP.getDstReg()) << "\n"); + DEBUG(dbgs() <<" with physreg " << PrintReg(CP.getDstReg(), tri_) << "\n"); // Only coalesce to allocatable physreg. if (!li_->isAllocatable(CP.getDstReg())) { DEBUG(dbgs() << "\tRegister is an unallocatable physreg.\n"); return false; // Not coalescable. } } else { - DEBUG({ - dbgs() << " with reg%" << CP.getDstReg(); - if (CP.getSubIdx()) - dbgs() << ":" << tri_->getSubRegIndexName(CP.getSubIdx()); - dbgs() << " to " << CP.getNewRC()->getName() << "\n"; - }); + DEBUG(dbgs() << " with " << PrintReg(CP.getDstReg(), tri_, CP.getSubIdx()) + << " to " << CP.getNewRC()->getName() << "\n"); // Avoid constraining virtual register regclass too much. if (CP.isCrossClass()) { @@ -1114,7 +1044,7 @@ bool SimpleRegisterCoalescing::JoinCopy(CopyRec &TheCopy, bool &Again) { // Before giving up coalescing, if definition of source is defined by // trivial computation, try rematerializing it. if (!CP.isFlipped() && - ReMaterializeTrivialDef(JoinVInt, CP.getDstReg(), 0, CopyMI)) + ReMaterializeTrivialDef(JoinVInt, true, CP.getDstReg(), 0, CopyMI)) return true; ++numAborts; @@ -1134,7 +1064,7 @@ bool SimpleRegisterCoalescing::JoinCopy(CopyRec &TheCopy, bool &Again) { // If definition of source is defined by trivial computation, try // rematerializing it. if (!CP.isFlipped() && - ReMaterializeTrivialDef(li_->getInterval(CP.getSrcReg()), + ReMaterializeTrivialDef(li_->getInterval(CP.getSrcReg()), true, CP.getDstReg(), 0, CopyMI)) return true; @@ -1317,7 +1247,7 @@ bool SimpleRegisterCoalescing::JoinIntervals(CoalescerPair &CP) { for (LiveInterval::vni_iterator i = LHS.vni_begin(), e = LHS.vni_end(); i != e; ++i) { VNInfo *VNI = *i; - if (VNI->isUnused() || VNI->getCopy() == 0) // Src not defined by a copy? + if (VNI->isUnused() || !VNI->isDefByCopy()) // Src not defined by a copy? continue; // Never join with a register that has EarlyClobber redefs. @@ -1341,7 +1271,7 @@ bool SimpleRegisterCoalescing::JoinIntervals(CoalescerPair &CP) { for (LiveInterval::vni_iterator i = RHS.vni_begin(), e = RHS.vni_end(); i != e; ++i) { VNInfo *VNI = *i; - if (VNI->isUnused() || VNI->getCopy() == 0) // Src not defined by a copy? + if (VNI->isUnused() || !VNI->isDefByCopy()) // Src not defined by a copy? continue; // Never join with a register that has EarlyClobber redefs. @@ -1495,9 +1425,9 @@ void SimpleRegisterCoalescing::CopyCoalesceInMBB(MachineBasicBlock *MBB, std::vector &TryAgain) { DEBUG(dbgs() << MBB->getName() << ":\n"); - std::vector VirtCopies; - std::vector PhysCopies; - std::vector ImpDefCopies; + SmallVector VirtCopies; + SmallVector PhysCopies; + SmallVector ImpDefCopies; for (MachineBasicBlock::iterator MII = MBB->begin(), E = MBB->end(); MII != E;) { MachineInstr *Inst = MII++; @@ -1690,6 +1620,7 @@ bool SimpleRegisterCoalescing::runOnMachineFunction(MachineFunction &fn) { tri_ = tm_->getRegisterInfo(); tii_ = tm_->getInstrInfo(); li_ = &getAnalysis(); + ldv_ = &getAnalysis(); AA = &getAnalysis(); loopInfo = &getAnalysis(); @@ -1697,6 +1628,9 @@ bool SimpleRegisterCoalescing::runOnMachineFunction(MachineFunction &fn) { << "********** Function: " << ((Value*)mf_->getFunction())->getName() << '\n'); + if (VerifyCoalescing) + mf_->verify(this, "Before register coalescing"); + for (TargetRegisterInfo::regclass_iterator I = tri_->regclass_begin(), E = tri_->regclass_end(); I != E; ++I) allocatableRCRegs_.insert(std::make_pair(*I, @@ -1739,9 +1673,11 @@ bool SimpleRegisterCoalescing::runOnMachineFunction(MachineFunction &fn) { DoDelete = false; if (MI->allDefsAreDead()) { - LiveInterval &li = li_->getInterval(SrcReg); - if (!ShortenDeadCopySrcLiveRange(li, MI)) - ShortenDeadCopyLiveRange(li, MI); + if (li_->hasInterval(SrcReg)) { + LiveInterval &li = li_->getInterval(SrcReg); + if (!ShortenDeadCopySrcLiveRange(li, MI)) + ShortenDeadCopyLiveRange(li, MI); + } DoDelete = true; } if (!DoDelete) { @@ -1821,13 +1757,26 @@ bool SimpleRegisterCoalescing::runOnMachineFunction(MachineFunction &fn) { if (!MO.isReg() || !MO.isKill()) continue; unsigned reg = MO.getReg(); if (!reg || !li_->hasInterval(reg)) continue; - if (!li_->getInterval(reg).killedAt(DefIdx)) + if (!li_->getInterval(reg).killedAt(DefIdx)) { MO.setIsKill(false); + continue; + } + // When leaving a kill flag on a physreg, check if any subregs should + // remain alive. + if (!TargetRegisterInfo::isPhysicalRegister(reg)) + continue; + for (const unsigned *SR = tri_->getSubRegisters(reg); + unsigned S = *SR; ++SR) + if (li_->hasInterval(S) && li_->getInterval(S).liveAt(DefIdx)) + MI->addRegisterDefined(S, tri_); } } } DEBUG(dump()); + DEBUG(ldv_->dump()); + if (VerifyCoalescing) + mf_->verify(this, "After register coalescing"); return true; } diff --git a/lib/CodeGen/SimpleRegisterCoalescing.h b/lib/CodeGen/SimpleRegisterCoalescing.h index 855bdb98b36c..56703dfa2ddd 100644 --- a/lib/CodeGen/SimpleRegisterCoalescing.h +++ b/lib/CodeGen/SimpleRegisterCoalescing.h @@ -21,7 +21,7 @@ namespace llvm { class SimpleRegisterCoalescing; - class LiveVariables; + class LiveDebugVariables; class TargetRegisterInfo; class TargetInstrInfo; class VirtRegMap; @@ -44,6 +44,7 @@ namespace llvm { const TargetRegisterInfo* tri_; const TargetInstrInfo* tii_; LiveIntervals *li_; + LiveDebugVariables *ldv_; const MachineLoopInfo* loopInfo; AliasAnalysis *AA; @@ -63,7 +64,9 @@ namespace llvm { public: static char ID; // Pass identifcation, replacement for typeid - SimpleRegisterCoalescing() : MachineFunctionPass(ID) {} + SimpleRegisterCoalescing() : MachineFunctionPass(ID) { + initializeSimpleRegisterCoalescingPass(*PassRegistry::getPassRegistry()); + } struct InstrSlots { enum { @@ -140,8 +143,10 @@ namespace llvm { /// ReMaterializeTrivialDef - If the source of a copy is defined by a trivial /// computation, replace the copy by rematerialize the definition. - bool ReMaterializeTrivialDef(LiveInterval &SrcInt, unsigned DstReg, - unsigned DstSubIdx, MachineInstr *CopyMI); + /// If PreserveSrcInt is true, make sure SrcInt is valid after the call. + bool ReMaterializeTrivialDef(LiveInterval &SrcInt, bool PreserveSrcInt, + unsigned DstReg, unsigned DstSubIdx, + MachineInstr *CopyMI); /// isWinToJoinCrossClass - Return true if it's profitable to coalesce /// two virtual registers from different register classes. diff --git a/lib/CodeGen/SjLjEHPrepare.cpp b/lib/CodeGen/SjLjEHPrepare.cpp index b637980f885c..13e1454fa5f3 100644 --- a/lib/CodeGen/SjLjEHPrepare.cpp +++ b/lib/CodeGen/SjLjEHPrepare.cpp @@ -21,15 +21,14 @@ #include "llvm/LLVMContext.h" #include "llvm/Module.h" #include "llvm/Pass.h" -#include "llvm/CodeGen/Passes.h" -#include "llvm/Transforms/Utils/BasicBlockUtils.h" -#include "llvm/Transforms/Utils/Local.h" -#include "llvm/ADT/Statistic.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Support/CommandLine.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/CodeGen/Passes.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetLowering.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/Local.h" +#include using namespace llvm; STATISTIC(NumInvokes, "Number of invokes replaced"); @@ -53,6 +52,7 @@ namespace { Constant *SelectorFn; Constant *ExceptionFn; Constant *CallSiteFn; + Constant *DispatchSetupFn; Value *CallSite; public: @@ -116,6 +116,8 @@ bool SjLjEHPass::doInitialization(Module &M) { SelectorFn = Intrinsic::getDeclaration(&M, Intrinsic::eh_selector); ExceptionFn = Intrinsic::getDeclaration(&M, Intrinsic::eh_exception); CallSiteFn = Intrinsic::getDeclaration(&M, Intrinsic::eh_sjlj_callsite); + DispatchSetupFn + = Intrinsic::getDeclaration(&M, Intrinsic::eh_sjlj_dispatch_setup); PersonalityFn = 0; return true; @@ -317,8 +319,12 @@ bool SjLjEHPass::insertSjLjEHSupport(Function &F) { Unwinds.push_back(UI); } } - // If we don't have any invokes or unwinds, there's nothing to do. - if (Unwinds.empty() && Invokes.empty()) return false; + + NumInvokes += Invokes.size(); + NumUnwinds += Unwinds.size(); + + // If we don't have any invokes, there's nothing to do. + if (Invokes.empty()) return false; // Find the eh.selector.*, eh.exception and alloca calls. // @@ -332,6 +338,7 @@ bool SjLjEHPass::insertSjLjEHSupport(Function &F) { SmallVector EH_Selectors; SmallVector EH_Exceptions; SmallVector JmpbufUpdatePoints; + // Note: Skip the entry block since there's nothing there that interests // us. eh.selector and eh.exception shouldn't ever be there, and we // want to disregard any allocas that are there. @@ -351,228 +358,231 @@ bool SjLjEHPass::insertSjLjEHSupport(Function &F) { } } } + // If we don't have any eh.selector calls, we can't determine the personality // function. Without a personality function, we can't process exceptions. if (!PersonalityFn) return false; - NumInvokes += Invokes.size(); - NumUnwinds += Unwinds.size(); + // We have invokes, so we need to add register/unregister calls to get this + // function onto the global unwind stack. + // + // First thing we need to do is scan the whole function for values that are + // live across unwind edges. Each value that is live across an unwind edge we + // spill into a stack location, guaranteeing that there is nothing live across + // the unwind edge. This process also splits all critical edges coming out of + // invoke's. + splitLiveRangesAcrossInvokes(Invokes); + + BasicBlock *EntryBB = F.begin(); + // Create an alloca for the incoming jump buffer ptr and the new jump buffer + // that needs to be restored on all exits from the function. This is an + // alloca because the value needs to be added to the global context list. + unsigned Align = 4; // FIXME: Should be a TLI check? + AllocaInst *FunctionContext = + new AllocaInst(FunctionContextTy, 0, Align, + "fcn_context", F.begin()->begin()); + + Value *Idxs[2]; + const Type *Int32Ty = Type::getInt32Ty(F.getContext()); + Value *Zero = ConstantInt::get(Int32Ty, 0); + // We need to also keep around a reference to the call_site field + Idxs[0] = Zero; + Idxs[1] = ConstantInt::get(Int32Ty, 1); + CallSite = GetElementPtrInst::Create(FunctionContext, Idxs, Idxs+2, + "call_site", + EntryBB->getTerminator()); + + // The exception selector comes back in context->data[1] + Idxs[1] = ConstantInt::get(Int32Ty, 2); + Value *FCData = GetElementPtrInst::Create(FunctionContext, Idxs, Idxs+2, + "fc_data", + EntryBB->getTerminator()); + Idxs[1] = ConstantInt::get(Int32Ty, 1); + Value *SelectorAddr = GetElementPtrInst::Create(FCData, Idxs, Idxs+2, + "exc_selector_gep", + EntryBB->getTerminator()); + // The exception value comes back in context->data[0] + Idxs[1] = Zero; + Value *ExceptionAddr = GetElementPtrInst::Create(FCData, Idxs, Idxs+2, + "exception_gep", + EntryBB->getTerminator()); + + // The result of the eh.selector call will be replaced with a a reference to + // the selector value returned in the function context. We leave the selector + // itself so the EH analysis later can use it. + for (int i = 0, e = EH_Selectors.size(); i < e; ++i) { + CallInst *I = EH_Selectors[i]; + Value *SelectorVal = new LoadInst(SelectorAddr, "select_val", true, I); + I->replaceAllUsesWith(SelectorVal); + } - if (!Invokes.empty()) { - // We have invokes, so we need to add register/unregister calls to get - // this function onto the global unwind stack. - // - // First thing we need to do is scan the whole function for values that are - // live across unwind edges. Each value that is live across an unwind edge - // we spill into a stack location, guaranteeing that there is nothing live - // across the unwind edge. This process also splits all critical edges - // coming out of invoke's. - splitLiveRangesAcrossInvokes(Invokes); - - BasicBlock *EntryBB = F.begin(); - // Create an alloca for the incoming jump buffer ptr and the new jump buffer - // that needs to be restored on all exits from the function. This is an - // alloca because the value needs to be added to the global context list. - unsigned Align = 4; // FIXME: Should be a TLI check? - AllocaInst *FunctionContext = - new AllocaInst(FunctionContextTy, 0, Align, - "fcn_context", F.begin()->begin()); - - Value *Idxs[2]; - const Type *Int32Ty = Type::getInt32Ty(F.getContext()); - Value *Zero = ConstantInt::get(Int32Ty, 0); - // We need to also keep around a reference to the call_site field - Idxs[0] = Zero; - Idxs[1] = ConstantInt::get(Int32Ty, 1); - CallSite = GetElementPtrInst::Create(FunctionContext, Idxs, Idxs+2, - "call_site", - EntryBB->getTerminator()); - - // The exception selector comes back in context->data[1] - Idxs[1] = ConstantInt::get(Int32Ty, 2); - Value *FCData = GetElementPtrInst::Create(FunctionContext, Idxs, Idxs+2, - "fc_data", - EntryBB->getTerminator()); - Idxs[1] = ConstantInt::get(Int32Ty, 1); - Value *SelectorAddr = GetElementPtrInst::Create(FCData, Idxs, Idxs+2, - "exc_selector_gep", - EntryBB->getTerminator()); - // The exception value comes back in context->data[0] - Idxs[1] = Zero; - Value *ExceptionAddr = GetElementPtrInst::Create(FCData, Idxs, Idxs+2, - "exception_gep", - EntryBB->getTerminator()); - - // The result of the eh.selector call will be replaced with a - // a reference to the selector value returned in the function - // context. We leave the selector itself so the EH analysis later - // can use it. - for (int i = 0, e = EH_Selectors.size(); i < e; ++i) { - CallInst *I = EH_Selectors[i]; - Value *SelectorVal = new LoadInst(SelectorAddr, "select_val", true, I); - I->replaceAllUsesWith(SelectorVal); - } - // eh.exception calls are replaced with references to the proper - // location in the context. Unlike eh.selector, the eh.exception - // calls are removed entirely. - for (int i = 0, e = EH_Exceptions.size(); i < e; ++i) { - CallInst *I = EH_Exceptions[i]; - // Possible for there to be duplicates, so check to make sure - // the instruction hasn't already been removed. - if (!I->getParent()) continue; - Value *Val = new LoadInst(ExceptionAddr, "exception", true, I); - const Type *Ty = Type::getInt8PtrTy(F.getContext()); - Val = CastInst::Create(Instruction::IntToPtr, Val, Ty, "", I); - - I->replaceAllUsesWith(Val); - I->eraseFromParent(); - } + // eh.exception calls are replaced with references to the proper location in + // the context. Unlike eh.selector, the eh.exception calls are removed + // entirely. + for (int i = 0, e = EH_Exceptions.size(); i < e; ++i) { + CallInst *I = EH_Exceptions[i]; + // Possible for there to be duplicates, so check to make sure the + // instruction hasn't already been removed. + if (!I->getParent()) continue; + Value *Val = new LoadInst(ExceptionAddr, "exception", true, I); + const Type *Ty = Type::getInt8PtrTy(F.getContext()); + Val = CastInst::Create(Instruction::IntToPtr, Val, Ty, "", I); + + I->replaceAllUsesWith(Val); + I->eraseFromParent(); + } - // The entry block changes to have the eh.sjlj.setjmp, with a conditional - // branch to a dispatch block for non-zero returns. If we return normally, - // we're not handling an exception and just register the function context - // and continue. - - // Create the dispatch block. The dispatch block is basically a big switch - // statement that goes to all of the invoke landing pads. - BasicBlock *DispatchBlock = - BasicBlock::Create(F.getContext(), "eh.sjlj.setjmp.catch", &F); - - // Insert a load in the Catch block, and a switch on its value. By default, - // we go to a block that just does an unwind (which is the correct action - // for a standard call). - BasicBlock *UnwindBlock = - BasicBlock::Create(F.getContext(), "unwindbb", &F); - Unwinds.push_back(new UnwindInst(F.getContext(), UnwindBlock)); - - Value *DispatchLoad = new LoadInst(CallSite, "invoke.num", true, - DispatchBlock); - SwitchInst *DispatchSwitch = - SwitchInst::Create(DispatchLoad, UnwindBlock, Invokes.size(), - DispatchBlock); - // Split the entry block to insert the conditional branch for the setjmp. - BasicBlock *ContBlock = EntryBB->splitBasicBlock(EntryBB->getTerminator(), - "eh.sjlj.setjmp.cont"); - - // Populate the Function Context - // 1. LSDA address - // 2. Personality function address - // 3. jmpbuf (save SP, FP and call eh.sjlj.setjmp) - - // LSDA address - Idxs[0] = Zero; - Idxs[1] = ConstantInt::get(Int32Ty, 4); - Value *LSDAFieldPtr = - GetElementPtrInst::Create(FunctionContext, Idxs, Idxs+2, - "lsda_gep", - EntryBB->getTerminator()); - Value *LSDA = CallInst::Create(LSDAAddrFn, "lsda_addr", - EntryBB->getTerminator()); - new StoreInst(LSDA, LSDAFieldPtr, true, EntryBB->getTerminator()); - - Idxs[1] = ConstantInt::get(Int32Ty, 3); - Value *PersonalityFieldPtr = - GetElementPtrInst::Create(FunctionContext, Idxs, Idxs+2, - "lsda_gep", + // The entry block changes to have the eh.sjlj.setjmp, with a conditional + // branch to a dispatch block for non-zero returns. If we return normally, + // we're not handling an exception and just register the function context and + // continue. + + // Create the dispatch block. The dispatch block is basically a big switch + // statement that goes to all of the invoke landing pads. + BasicBlock *DispatchBlock = + BasicBlock::Create(F.getContext(), "eh.sjlj.setjmp.catch", &F); + + // Add a call to dispatch_setup at the start of the dispatch block. This is + // expanded to any target-specific setup that needs to be done. + Value *SetupArg = + CastInst::Create(Instruction::BitCast, FunctionContext, + Type::getInt8PtrTy(F.getContext()), "", + DispatchBlock); + CallInst::Create(DispatchSetupFn, SetupArg, "", DispatchBlock); + + // Insert a load of the callsite in the dispatch block, and a switch on its + // value. By default, we go to a block that just does an unwind (which is the + // correct action for a standard call). + BasicBlock *UnwindBlock = + BasicBlock::Create(F.getContext(), "unwindbb", &F); + Unwinds.push_back(new UnwindInst(F.getContext(), UnwindBlock)); + + Value *DispatchLoad = new LoadInst(CallSite, "invoke.num", true, + DispatchBlock); + SwitchInst *DispatchSwitch = + SwitchInst::Create(DispatchLoad, UnwindBlock, Invokes.size(), + DispatchBlock); + // Split the entry block to insert the conditional branch for the setjmp. + BasicBlock *ContBlock = EntryBB->splitBasicBlock(EntryBB->getTerminator(), + "eh.sjlj.setjmp.cont"); + + // Populate the Function Context + // 1. LSDA address + // 2. Personality function address + // 3. jmpbuf (save SP, FP and call eh.sjlj.setjmp) + + // LSDA address + Idxs[0] = Zero; + Idxs[1] = ConstantInt::get(Int32Ty, 4); + Value *LSDAFieldPtr = + GetElementPtrInst::Create(FunctionContext, Idxs, Idxs+2, + "lsda_gep", + EntryBB->getTerminator()); + Value *LSDA = CallInst::Create(LSDAAddrFn, "lsda_addr", + EntryBB->getTerminator()); + new StoreInst(LSDA, LSDAFieldPtr, true, EntryBB->getTerminator()); + + Idxs[1] = ConstantInt::get(Int32Ty, 3); + Value *PersonalityFieldPtr = + GetElementPtrInst::Create(FunctionContext, Idxs, Idxs+2, + "lsda_gep", + EntryBB->getTerminator()); + new StoreInst(PersonalityFn, PersonalityFieldPtr, true, + EntryBB->getTerminator()); + + // Save the frame pointer. + Idxs[1] = ConstantInt::get(Int32Ty, 5); + Value *JBufPtr + = GetElementPtrInst::Create(FunctionContext, Idxs, Idxs+2, + "jbuf_gep", EntryBB->getTerminator()); - new StoreInst(PersonalityFn, PersonalityFieldPtr, true, - EntryBB->getTerminator()); - - // Save the frame pointer. - Idxs[1] = ConstantInt::get(Int32Ty, 5); - Value *JBufPtr - = GetElementPtrInst::Create(FunctionContext, Idxs, Idxs+2, - "jbuf_gep", - EntryBB->getTerminator()); - Idxs[1] = ConstantInt::get(Int32Ty, 0); - Value *FramePtr = - GetElementPtrInst::Create(JBufPtr, Idxs, Idxs+2, "jbuf_fp_gep", + Idxs[1] = ConstantInt::get(Int32Ty, 0); + Value *FramePtr = + GetElementPtrInst::Create(JBufPtr, Idxs, Idxs+2, "jbuf_fp_gep", + EntryBB->getTerminator()); + + Value *Val = CallInst::Create(FrameAddrFn, + ConstantInt::get(Int32Ty, 0), + "fp", EntryBB->getTerminator()); + new StoreInst(Val, FramePtr, true, EntryBB->getTerminator()); + + // Save the stack pointer. + Idxs[1] = ConstantInt::get(Int32Ty, 2); + Value *StackPtr = + GetElementPtrInst::Create(JBufPtr, Idxs, Idxs+2, "jbuf_sp_gep", + EntryBB->getTerminator()); + + Val = CallInst::Create(StackAddrFn, "sp", EntryBB->getTerminator()); + new StoreInst(Val, StackPtr, true, EntryBB->getTerminator()); + + // Call the setjmp instrinsic. It fills in the rest of the jmpbuf. + Value *SetjmpArg = + CastInst::Create(Instruction::BitCast, JBufPtr, + Type::getInt8PtrTy(F.getContext()), "", + EntryBB->getTerminator()); + Value *DispatchVal = CallInst::Create(BuiltinSetjmpFn, SetjmpArg, + "dispatch", + EntryBB->getTerminator()); + // check the return value of the setjmp. non-zero goes to dispatcher. + Value *IsNormal = new ICmpInst(EntryBB->getTerminator(), + ICmpInst::ICMP_EQ, DispatchVal, Zero, + "notunwind"); + // Nuke the uncond branch. + EntryBB->getTerminator()->eraseFromParent(); + + // Put in a new condbranch in its place. + BranchInst::Create(ContBlock, DispatchBlock, IsNormal, EntryBB); + + // Register the function context and make sure it's known to not throw + CallInst *Register = + CallInst::Create(RegisterFn, FunctionContext, "", + ContBlock->getTerminator()); + Register->setDoesNotThrow(); + + // At this point, we are all set up, update the invoke instructions to mark + // their call_site values, and fill in the dispatch switch accordingly. + for (unsigned i = 0, e = Invokes.size(); i != e; ++i) + markInvokeCallSite(Invokes[i], i+1, CallSite, DispatchSwitch); + + // Mark call instructions that aren't nounwind as no-action (call_site == + // -1). Skip the entry block, as prior to then, no function context has been + // created for this function and any unexpected exceptions thrown will go + // directly to the caller's context, which is what we want anyway, so no need + // to do anything here. + for (Function::iterator BB = F.begin(), E = F.end(); ++BB != E;) { + for (BasicBlock::iterator I = BB->begin(), end = BB->end(); I != end; ++I) + if (CallInst *CI = dyn_cast(I)) { + // Ignore calls to the EH builtins (eh.selector, eh.exception) + Constant *Callee = CI->getCalledFunction(); + if (Callee != SelectorFn && Callee != ExceptionFn + && !CI->doesNotThrow()) + insertCallSiteStore(CI, -1, CallSite); + } + } - Value *Val = CallInst::Create(FrameAddrFn, - ConstantInt::get(Int32Ty, 0), - "fp", - EntryBB->getTerminator()); - new StoreInst(Val, FramePtr, true, EntryBB->getTerminator()); - - // Save the stack pointer. - Idxs[1] = ConstantInt::get(Int32Ty, 2); - Value *StackPtr = - GetElementPtrInst::Create(JBufPtr, Idxs, Idxs+2, "jbuf_sp_gep", - EntryBB->getTerminator()); - - Val = CallInst::Create(StackAddrFn, "sp", EntryBB->getTerminator()); - new StoreInst(Val, StackPtr, true, EntryBB->getTerminator()); - - // Call the setjmp instrinsic. It fills in the rest of the jmpbuf. - Value *SetjmpArg = - CastInst::Create(Instruction::BitCast, JBufPtr, - Type::getInt8PtrTy(F.getContext()), "", - EntryBB->getTerminator()); - Value *DispatchVal = CallInst::Create(BuiltinSetjmpFn, SetjmpArg, - "dispatch", - EntryBB->getTerminator()); - // check the return value of the setjmp. non-zero goes to dispatcher. - Value *IsNormal = new ICmpInst(EntryBB->getTerminator(), - ICmpInst::ICMP_EQ, DispatchVal, Zero, - "notunwind"); - // Nuke the uncond branch. - EntryBB->getTerminator()->eraseFromParent(); - - // Put in a new condbranch in its place. - BranchInst::Create(ContBlock, DispatchBlock, IsNormal, EntryBB); - - // Register the function context and make sure it's known to not throw - CallInst *Register = - CallInst::Create(RegisterFn, FunctionContext, "", - ContBlock->getTerminator()); - Register->setDoesNotThrow(); - - // At this point, we are all set up, update the invoke instructions - // to mark their call_site values, and fill in the dispatch switch - // accordingly. - for (unsigned i = 0, e = Invokes.size(); i != e; ++i) - markInvokeCallSite(Invokes[i], i+1, CallSite, DispatchSwitch); - - // Mark call instructions that aren't nounwind as no-action - // (call_site == -1). Skip the entry block, as prior to then, no function - // context has been created for this function and any unexpected exceptions - // thrown will go directly to the caller's context, which is what we want - // anyway, so no need to do anything here. - for (Function::iterator BB = F.begin(), E = F.end(); ++BB != E;) { - for (BasicBlock::iterator I = BB->begin(), end = BB->end(); I != end; ++I) - if (CallInst *CI = dyn_cast(I)) { - // Ignore calls to the EH builtins (eh.selector, eh.exception) - Constant *Callee = CI->getCalledFunction(); - if (Callee != SelectorFn && Callee != ExceptionFn - && !CI->doesNotThrow()) - insertCallSiteStore(CI, -1, CallSite); - } - } - - // Replace all unwinds with a branch to the unwind handler. - // ??? Should this ever happen with sjlj exceptions? - for (unsigned i = 0, e = Unwinds.size(); i != e; ++i) { - BranchInst::Create(UnwindBlock, Unwinds[i]); - Unwinds[i]->eraseFromParent(); - } - - // Following any allocas not in the entry block, update the saved SP - // in the jmpbuf to the new value. - for (unsigned i = 0, e = JmpbufUpdatePoints.size(); i != e; ++i) { - Instruction *AI = JmpbufUpdatePoints[i]; - Instruction *StackAddr = CallInst::Create(StackAddrFn, "sp"); - StackAddr->insertAfter(AI); - Instruction *StoreStackAddr = new StoreInst(StackAddr, StackPtr, true); - StoreStackAddr->insertAfter(StackAddr); - } + // Replace all unwinds with a branch to the unwind handler. + // ??? Should this ever happen with sjlj exceptions? + for (unsigned i = 0, e = Unwinds.size(); i != e; ++i) { + BranchInst::Create(UnwindBlock, Unwinds[i]); + Unwinds[i]->eraseFromParent(); + } - // Finally, for any returns from this function, if this function contains an - // invoke, add a call to unregister the function context. - for (unsigned i = 0, e = Returns.size(); i != e; ++i) - CallInst::Create(UnregisterFn, FunctionContext, "", Returns[i]); + // Following any allocas not in the entry block, update the saved SP in the + // jmpbuf to the new value. + for (unsigned i = 0, e = JmpbufUpdatePoints.size(); i != e; ++i) { + Instruction *AI = JmpbufUpdatePoints[i]; + Instruction *StackAddr = CallInst::Create(StackAddrFn, "sp"); + StackAddr->insertAfter(AI); + Instruction *StoreStackAddr = new StoreInst(StackAddr, StackPtr, true); + StoreStackAddr->insertAfter(StackAddr); } + // Finally, for any returns from this function, if this function contains an + // invoke, add a call to unregister the function context. + for (unsigned i = 0, e = Returns.size(); i != e; ++i) + CallInst::Create(UnregisterFn, FunctionContext, "", Returns[i]); + return true; } diff --git a/lib/CodeGen/SlotIndexes.cpp b/lib/CodeGen/SlotIndexes.cpp index 1bc148f160bc..6e3fa90e4341 100644 --- a/lib/CodeGen/SlotIndexes.cpp +++ b/lib/CodeGen/SlotIndexes.cpp @@ -41,7 +41,7 @@ namespace { char SlotIndexes::ID = 0; INITIALIZE_PASS(SlotIndexes, "slotindexes", - "Slot index numbering", false, false); + "Slot index numbering", false, false) IndexListEntry* IndexListEntry::getEmptyKeyEntry() { return &*IndexListEntryEmptyKey; @@ -61,7 +61,6 @@ void SlotIndexes::releaseMemory() { mi2iMap.clear(); mbb2IdxMap.clear(); idx2MBBMap.clear(); - terminatorGaps.clear(); clearList(); } @@ -112,13 +111,6 @@ bool SlotIndexes::runOnMachineFunction(MachineFunction &fn) { if (mi->isDebugValue()) continue; - if (miItr == mbb->getFirstTerminator()) { - push_back(createEntry(0, index)); - terminatorGaps.insert( - std::make_pair(mbb, SlotIndex(back(), SlotIndex::PHI_BIT))); - index += SlotIndex::NUM; - } - // Insert a store index for the instr. push_back(createEntry(mi, index)); @@ -135,15 +127,12 @@ bool SlotIndexes::runOnMachineFunction(MachineFunction &fn) { index += (Slots + 1) * SlotIndex::NUM; } - if (mbb->getFirstTerminator() == mbb->end()) { - push_back(createEntry(0, index)); - terminatorGaps.insert( - std::make_pair(mbb, SlotIndex(back(), SlotIndex::PHI_BIT))); - index += SlotIndex::NUM; - } + // We insert two blank instructions between basic blocks. + // One to represent live-out registers and one to represent live-ins. + push_back(createEntry(0, index)); + index += SlotIndex::NUM; - // One blank instruction at the end. - push_back(createEntry(0, index)); + push_back(createEntry(0, index)); SlotIndex blockEndIndex(back(), SlotIndex::LOAD); mbb2IdxMap.insert( @@ -169,6 +158,7 @@ void SlotIndexes::renumberIndexes() { // resulting numbering will match what would have been generated by the // pass during the initial numbering of the function if the new instructions // had been present. + DEBUG(dbgs() << "\n*** Renumbering SlotIndexes ***\n"); functionSize = 0; unsigned index = 0; @@ -179,7 +169,7 @@ void SlotIndexes::renumberIndexes() { curEntry->setIndex(index); if (curEntry->getInstr() == 0) { - // MBB start entry or terminator gap. Just step index by 1. + // MBB start entry. Just step index by 1. index += SlotIndex::NUM; } else { @@ -214,11 +204,10 @@ void SlotIndexes::dump() const { // Print a SlotIndex to a raw_ostream. void SlotIndex::print(raw_ostream &os) const { - os << entry().getIndex(); - if (isPHI()) - os << "*"; + if (isValid()) + os << entry().getIndex() << "LudS"[getSlot()]; else - os << "LudS"[getSlot()]; + os << "invalid"; } // Dump a SlotIndex to stderr. diff --git a/lib/CodeGen/SpillPlacement.cpp b/lib/CodeGen/SpillPlacement.cpp new file mode 100644 index 000000000000..9c0bf1629a14 --- /dev/null +++ b/lib/CodeGen/SpillPlacement.cpp @@ -0,0 +1,330 @@ +//===-- SpillPlacement.cpp - Optimal Spill Code Placement -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the spill code placement analysis. +// +// Each edge bundle corresponds to a node in a Hopfield network. Constraints on +// basic blocks are weighted by the block frequency and added to become the node +// bias. +// +// Transparent basic blocks have the variable live through, but don't care if it +// is spilled or in a register. These blocks become connections in the Hopfield +// network, again weighted by block frequency. +// +// The Hopfield network minimizes (possibly locally) its energy function: +// +// E = -sum_n V_n * ( B_n + sum_{n, m linked by b} V_m * F_b ) +// +// The energy function represents the expected spill code execution frequency, +// or the cost of spilling. This is a Lyapunov function which never increases +// when a node is updated. It is guaranteed to converge to a local minimum. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "spillplacement" +#include "SpillPlacement.h" +#include "llvm/CodeGen/EdgeBundles.h" +#include "llvm/CodeGen/LiveIntervalAnalysis.h" +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineLoopInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" + +using namespace llvm; + +char SpillPlacement::ID = 0; +INITIALIZE_PASS_BEGIN(SpillPlacement, "spill-code-placement", + "Spill Code Placement Analysis", true, true) +INITIALIZE_PASS_DEPENDENCY(EdgeBundles) +INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo) +INITIALIZE_PASS_END(SpillPlacement, "spill-code-placement", + "Spill Code Placement Analysis", true, true) + +char &llvm::SpillPlacementID = SpillPlacement::ID; + +void SpillPlacement::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesAll(); + AU.addRequiredTransitive(); + AU.addRequiredTransitive(); + MachineFunctionPass::getAnalysisUsage(AU); +} + +/// Node - Each edge bundle corresponds to a Hopfield node. +/// +/// The node contains precomputed frequency data that only depends on the CFG, +/// but Bias and Links are computed each time placeSpills is called. +/// +/// The node Value is positive when the variable should be in a register. The +/// value can change when linked nodes change, but convergence is very fast +/// because all weights are positive. +/// +struct SpillPlacement::Node { + /// Frequency - Total block frequency feeding into[0] or out of[1] the bundle. + /// Ideally, these two numbers should be identical, but inaccuracies in the + /// block frequency estimates means that we need to normalize ingoing and + /// outgoing frequencies separately so they are commensurate. + float Frequency[2]; + + /// Bias - Normalized contributions from non-transparent blocks. + /// A bundle connected to a MustSpill block has a huge negative bias, + /// otherwise it is a number in the range [-2;2]. + float Bias; + + /// Value - Output value of this node computed from the Bias and links. + /// This is always in the range [-1;1]. A positive number means the variable + /// should go in a register through this bundle. + float Value; + + typedef SmallVector, 4> LinkVector; + + /// Links - (Weight, BundleNo) for all transparent blocks connecting to other + /// bundles. The weights are all positive and add up to at most 2, weights + /// from ingoing and outgoing nodes separately add up to a most 1. The weight + /// sum can be less than 2 when the variable is not live into / out of some + /// connected basic blocks. + LinkVector Links; + + /// preferReg - Return true when this node prefers to be in a register. + bool preferReg() const { + // Undecided nodes (Value==0) go on the stack. + return Value > 0; + } + + /// mustSpill - Return True if this node is so biased that it must spill. + bool mustSpill() const { + // Actually, we must spill if Bias < sum(weights). + // It may be worth it to compute the weight sum here? + return Bias < -2.0f; + } + + /// Node - Create a blank Node. + Node() { + Frequency[0] = Frequency[1] = 0; + } + + /// clear - Reset per-query data, but preserve frequencies that only depend on + // the CFG. + void clear() { + Bias = Value = 0; + Links.clear(); + } + + /// addLink - Add a link to bundle b with weight w. + /// out=0 for an ingoing link, and 1 for an outgoing link. + void addLink(unsigned b, float w, bool out) { + // Normalize w relative to all connected blocks from that direction. + w /= Frequency[out]; + + // There can be multiple links to the same bundle, add them up. + for (LinkVector::iterator I = Links.begin(), E = Links.end(); I != E; ++I) + if (I->second == b) { + I->first += w; + return; + } + // This must be the first link to b. + Links.push_back(std::make_pair(w, b)); + } + + /// addBias - Bias this node from an ingoing[0] or outgoing[1] link. + void addBias(float w, bool out) { + // Normalize w relative to all connected blocks from that direction. + w /= Frequency[out]; + Bias += w; + } + + /// update - Recompute Value from Bias and Links. Return true when node + /// preference changes. + bool update(const Node nodes[]) { + // Compute the weighted sum of inputs. + float Sum = Bias; + for (LinkVector::iterator I = Links.begin(), E = Links.end(); I != E; ++I) + Sum += I->first * nodes[I->second].Value; + + // The weighted sum is going to be in the range [-2;2]. Ideally, we should + // simply set Value = sign(Sum), but we will add a dead zone around 0 for + // two reasons: + // 1. It avoids arbitrary bias when all links are 0 as is possible during + // initial iterations. + // 2. It helps tame rounding errors when the links nominally sum to 0. + const float Thres = 1e-4f; + bool Before = preferReg(); + if (Sum < -Thres) + Value = -1; + else if (Sum > Thres) + Value = 1; + else + Value = 0; + return Before != preferReg(); + } +}; + +bool SpillPlacement::runOnMachineFunction(MachineFunction &mf) { + MF = &mf; + bundles = &getAnalysis(); + loops = &getAnalysis(); + + assert(!nodes && "Leaking node array"); + nodes = new Node[bundles->getNumBundles()]; + + // Compute total ingoing and outgoing block frequencies for all bundles. + for (MachineFunction::iterator I = mf.begin(), E = mf.end(); I != E; ++I) { + float Freq = getBlockFrequency(I); + unsigned Num = I->getNumber(); + nodes[bundles->getBundle(Num, 1)].Frequency[0] += Freq; + nodes[bundles->getBundle(Num, 0)].Frequency[1] += Freq; + } + + // We never change the function. + return false; +} + +void SpillPlacement::releaseMemory() { + delete[] nodes; + nodes = 0; +} + +/// activate - mark node n as active if it wasn't already. +void SpillPlacement::activate(unsigned n) { + if (ActiveNodes->test(n)) + return; + ActiveNodes->set(n); + nodes[n].clear(); +} + + +/// prepareNodes - Compute node biases and weights from a set of constraints. +/// Set a bit in NodeMask for each active node. +void SpillPlacement:: +prepareNodes(const SmallVectorImpl &LiveBlocks) { + for (SmallVectorImpl::const_iterator I = LiveBlocks.begin(), + E = LiveBlocks.end(); I != E; ++I) { + MachineBasicBlock *MBB = MF->getBlockNumbered(I->Number); + float Freq = getBlockFrequency(MBB); + + // Is this a transparent block? Link ingoing and outgoing bundles. + if (I->Entry == DontCare && I->Exit == DontCare) { + unsigned ib = bundles->getBundle(I->Number, 0); + unsigned ob = bundles->getBundle(I->Number, 1); + + // Ignore self-loops. + if (ib == ob) + continue; + activate(ib); + activate(ob); + nodes[ib].addLink(ob, Freq, 1); + nodes[ob].addLink(ib, Freq, 0); + continue; + } + + // This block is not transparent, but it can still add bias. + const float Bias[] = { + 0, // DontCare, + 1, // PrefReg, + -1, // PrefSpill + -HUGE_VALF // MustSpill + }; + + // Live-in to block? + if (I->Entry != DontCare) { + unsigned ib = bundles->getBundle(I->Number, 0); + activate(ib); + nodes[ib].addBias(Freq * Bias[I->Entry], 1); + } + + // Live-out from block? + if (I->Exit != DontCare) { + unsigned ob = bundles->getBundle(I->Number, 1); + activate(ob); + nodes[ob].addBias(Freq * Bias[I->Exit], 0); + } + } +} + +/// iterate - Repeatedly update the Hopfield nodes until stability or the +/// maximum number of iterations is reached. +/// @param Linked - Numbers of linked nodes that need updating. +void SpillPlacement::iterate(const SmallVectorImpl &Linked) { + if (Linked.empty()) + return; + + // Run up to 10 iterations. The edge bundle numbering is closely related to + // basic block numbering, so there is a strong tendency towards chains of + // linked nodes with sequential numbers. By scanning the linked nodes + // backwards and forwards, we make it very likely that a single node can + // affect the entire network in a single iteration. That means very fast + // convergence, usually in a single iteration. + for (unsigned iteration = 0; iteration != 10; ++iteration) { + // Scan backwards, skipping the last node which was just updated. + bool Changed = false; + for (SmallVectorImpl::const_reverse_iterator I = + llvm::next(Linked.rbegin()), E = Linked.rend(); I != E; ++I) { + unsigned n = *I; + bool C = nodes[n].update(nodes); + Changed |= C; + } + if (!Changed) + return; + + // Scan forwards, skipping the first node which was just updated. + Changed = false; + for (SmallVectorImpl::const_iterator I = + llvm::next(Linked.begin()), E = Linked.end(); I != E; ++I) { + unsigned n = *I; + bool C = nodes[n].update(nodes); + Changed |= C; + } + if (!Changed) + return; + } +} + +bool +SpillPlacement::placeSpills(const SmallVectorImpl &LiveBlocks, + BitVector &RegBundles) { + // Reuse RegBundles as our ActiveNodes vector. + ActiveNodes = &RegBundles; + ActiveNodes->clear(); + ActiveNodes->resize(bundles->getNumBundles()); + + // Compute active nodes, links and biases. + prepareNodes(LiveBlocks); + + // Update all active nodes, and find the ones that are actually linked to + // something so their value may change when iterating. + SmallVector Linked; + for (int n = RegBundles.find_first(); n>=0; n = RegBundles.find_next(n)) { + nodes[n].update(nodes); + // A node that must spill, or a node without any links is not going to + // change its value ever again, so exclude it from iterations. + if (!nodes[n].Links.empty() && !nodes[n].mustSpill()) + Linked.push_back(n); + } + + // Iterate the network to convergence. + iterate(Linked); + + // Write preferences back to RegBundles. + bool Perfect = true; + for (int n = RegBundles.find_first(); n>=0; n = RegBundles.find_next(n)) + if (!nodes[n].preferReg()) { + RegBundles.reset(n); + Perfect = false; + } + return Perfect; +} + +/// getBlockFrequency - Return our best estimate of the block frequency which is +/// the expected number of block executions per function invocation. +float SpillPlacement::getBlockFrequency(const MachineBasicBlock *MBB) { + // Use the unnormalized spill weight for real block frequencies. + return LiveIntervals::getSpillWeight(true, false, loops->getLoopDepth(MBB)); +} + diff --git a/lib/CodeGen/SpillPlacement.h b/lib/CodeGen/SpillPlacement.h new file mode 100644 index 000000000000..ef2d516cdce7 --- /dev/null +++ b/lib/CodeGen/SpillPlacement.h @@ -0,0 +1,108 @@ +//===-- SpillPlacement.h - Optimal Spill Code Placement --------*- C++ -*--===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This analysis computes the optimal spill code placement between basic blocks. +// +// The runOnMachineFunction() method only precomputes some profiling information +// about the CFG. The real work is done by placeSpills() which is called by the +// register allocator. +// +// Given a variable that is live across multiple basic blocks, and given +// constraints on the basic blocks where the variable is live, determine which +// edge bundles should have the variable in a register and which edge bundles +// should have the variable in a stack slot. +// +// The returned bit vector can be used to place optimal spill code at basic +// block entries and exits. Spill code placement inside a basic block is not +// considered. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_SPILLPLACEMENT_H +#define LLVM_CODEGEN_SPILLPLACEMENT_H + +#include "llvm/CodeGen/MachineFunctionPass.h" + +namespace llvm { + +class BitVector; +class EdgeBundles; +class MachineBasicBlock; +class MachineLoopInfo; +template class SmallVectorImpl; + +class SpillPlacement : public MachineFunctionPass { + struct Node; + const MachineFunction *MF; + const EdgeBundles *bundles; + const MachineLoopInfo *loops; + Node *nodes; + + // Nodes that are active in the current computation. Owned by the placeSpills + // caller. + BitVector *ActiveNodes; + +public: + static char ID; // Pass identification, replacement for typeid. + + SpillPlacement() : MachineFunctionPass(ID), nodes(0) {} + ~SpillPlacement() { releaseMemory(); } + + /// BorderConstraint - A basic block has separate constraints for entry and + /// exit. + enum BorderConstraint { + DontCare, ///< Block doesn't care / variable not live. + PrefReg, ///< Block entry/exit prefers a register. + PrefSpill, ///< Block entry/exit prefers a stack slot. + MustSpill ///< A register is impossible, variable must be spilled. + }; + + /// BlockConstraint - Entry and exit constraints for a basic block. + struct BlockConstraint { + unsigned Number; ///< Basic block number (from MBB::getNumber()). + BorderConstraint Entry : 8; ///< Constraint on block entry. + BorderConstraint Exit : 8; ///< Constraint on block exit. + }; + + /// placeSpills - Compute the optimal spill code placement given the + /// constraints. No MustSpill constraints will be violated, and the smallest + /// possible number of PrefX constraints will be violated, weighted by + /// expected execution frequencies. + /// @param LiveBlocks Constraints for blocks that have the variable live in or + /// live out. DontCare/DontCare means the variable is live + /// through the block. DontCare/X means the variable is live + /// out, but not live in. + /// @param RegBundles Bit vector to receive the edge bundles where the + /// variable should be kept in a register. Each bit + /// corresponds to an edge bundle, a set bit means the + /// variable should be kept in a register through the + /// bundle. A clear bit means the variable should be + /// spilled. + /// @return True if a perfect solution was found, allowing the variable to be + /// in a register through all relevant bundles. + bool placeSpills(const SmallVectorImpl &LiveBlocks, + BitVector &RegBundles); + + /// getBlockFrequency - Return the estimated block execution frequency per + /// function invocation. + float getBlockFrequency(const MachineBasicBlock*); + +private: + virtual bool runOnMachineFunction(MachineFunction&); + virtual void getAnalysisUsage(AnalysisUsage&) const; + virtual void releaseMemory(); + + void activate(unsigned); + void prepareNodes(const SmallVectorImpl&); + void iterate(const SmallVectorImpl&); +}; + +} // end namespace llvm + +#endif diff --git a/lib/CodeGen/Spiller.cpp b/lib/CodeGen/Spiller.cpp index 59d5ab33c994..fd385824aff9 100644 --- a/lib/CodeGen/Spiller.cpp +++ b/lib/CodeGen/Spiller.cpp @@ -12,6 +12,7 @@ #include "Spiller.h" #include "VirtRegMap.h" #include "llvm/CodeGen/LiveIntervalAnalysis.h" +#include "llvm/CodeGen/LiveStackAnalysis.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" @@ -28,7 +29,7 @@ using namespace llvm; namespace { - enum SpillerName { trivial, standard, splitting, inline_ }; + enum SpillerName { trivial, standard, inline_ }; } static cl::opt @@ -37,7 +38,6 @@ spillerOpt("spiller", cl::Prefix, cl::values(clEnumVal(trivial, "trivial spiller"), clEnumVal(standard, "default spiller"), - clEnumVal(splitting, "splitting spiller"), clEnumValN(inline_, "inline", "inline spiller"), clEnumValEnd), cl::init(standard)); @@ -80,7 +80,7 @@ protected: assert(li->weight != HUGE_VALF && "Attempting to spill already spilled value."); - assert(!li->isStackSlot() && + assert(!TargetRegisterInfo::isStackSlot(li->reg) && "Trying to spill a stack slot."); DEBUG(dbgs() << "Trivial spill everywhere of reg" << li->reg << "\n"); @@ -144,7 +144,7 @@ protected: vrm->addSpillSlotUse(ss, loadInstr); SlotIndex endIndex = loadIndex.getNextIndex(); VNInfo *loadVNI = - newLI->getNextValue(loadIndex, 0, true, lis->getVNInfoAllocator()); + newLI->getNextValue(loadIndex, 0, lis->getVNInfoAllocator()); newLI->addRange(LiveRange(loadIndex, endIndex, loadVNI)); } @@ -158,7 +158,7 @@ protected: vrm->addSpillSlotUse(ss, storeInstr); SlotIndex beginIndex = storeIndex.getPrevIndex(); VNInfo *storeVNI = - newLI->getNextValue(beginIndex, 0, true, lis->getVNInfoAllocator()); + newLI->getNextValue(beginIndex, 0, lis->getVNInfoAllocator()); newLI->addRange(LiveRange(beginIndex, storeIndex, storeVNI)); } @@ -182,7 +182,7 @@ public: void spill(LiveInterval *li, SmallVectorImpl &newIntervals, - SmallVectorImpl &) { + const SmallVectorImpl &) { // Ignore spillIs - we don't use it. trivialSpillEverywhere(li, newIntervals); } @@ -195,315 +195,42 @@ namespace { /// Falls back on LiveIntervals::addIntervalsForSpills. class StandardSpiller : public Spiller { protected: + MachineFunction *mf; LiveIntervals *lis; + LiveStacks *lss; MachineLoopInfo *loopInfo; VirtRegMap *vrm; public: StandardSpiller(MachineFunctionPass &pass, MachineFunction &mf, VirtRegMap &vrm) - : lis(&pass.getAnalysis()), + : mf(&mf), + lis(&pass.getAnalysis()), + lss(&pass.getAnalysis()), loopInfo(pass.getAnalysisIfAvailable()), vrm(&vrm) {} /// Falls back on LiveIntervals::addIntervalsForSpills. void spill(LiveInterval *li, SmallVectorImpl &newIntervals, - SmallVectorImpl &spillIs) { + const SmallVectorImpl &spillIs) { std::vector added = lis->addIntervalsForSpills(*li, spillIs, loopInfo, *vrm); newIntervals.insert(newIntervals.end(), added.begin(), added.end()); - } -}; - -} // end anonymous namespace - -namespace { - -/// When a call to spill is placed this spiller will first try to break the -/// interval up into its component values (one new interval per value). -/// If this fails, or if a call is placed to spill a previously split interval -/// then the spiller falls back on the standard spilling mechanism. -class SplittingSpiller : public StandardSpiller { -public: - SplittingSpiller(MachineFunctionPass &pass, MachineFunction &mf, - VirtRegMap &vrm) - : StandardSpiller(pass, mf, vrm) { - mri = &mf.getRegInfo(); - tii = mf.getTarget().getInstrInfo(); - tri = mf.getTarget().getRegisterInfo(); - } - void spill(LiveInterval *li, - SmallVectorImpl &newIntervals, - SmallVectorImpl &spillIs) { - if (worthTryingToSplit(li)) - tryVNISplit(li); - else - StandardSpiller::spill(li, newIntervals, spillIs); + // Update LiveStacks. + int SS = vrm->getStackSlot(li->reg); + if (SS == VirtRegMap::NO_STACK_SLOT) + return; + const TargetRegisterClass *RC = mf->getRegInfo().getRegClass(li->reg); + LiveInterval &SI = lss->getOrCreateInterval(SS, RC); + if (!SI.hasAtLeastOneValue()) + SI.getNextValue(SlotIndex(), 0, lss->getVNInfoAllocator()); + SI.MergeRangesInAsValue(*li, SI.getValNumInfo(0)); } - -private: - - MachineRegisterInfo *mri; - const TargetInstrInfo *tii; - const TargetRegisterInfo *tri; - DenseSet alreadySplit; - - bool worthTryingToSplit(LiveInterval *li) const { - return (!alreadySplit.count(li) && li->getNumValNums() > 1); - } - - /// Try to break a LiveInterval into its component values. - std::vector tryVNISplit(LiveInterval *li) { - - DEBUG(dbgs() << "Trying VNI split of %reg" << *li << "\n"); - - std::vector added; - SmallVector vnis; - - std::copy(li->vni_begin(), li->vni_end(), std::back_inserter(vnis)); - - for (SmallVectorImpl::iterator vniItr = vnis.begin(), - vniEnd = vnis.end(); vniItr != vniEnd; ++vniItr) { - VNInfo *vni = *vniItr; - - // Skip unused VNIs. - if (vni->isUnused()) - continue; - - DEBUG(dbgs() << " Extracted Val #" << vni->id << " as "); - LiveInterval *splitInterval = extractVNI(li, vni); - - if (splitInterval != 0) { - DEBUG(dbgs() << *splitInterval << "\n"); - added.push_back(splitInterval); - alreadySplit.insert(splitInterval); - } else { - DEBUG(dbgs() << "0\n"); - } - } - - DEBUG(dbgs() << "Original LI: " << *li << "\n"); - - // If there original interval still contains some live ranges - // add it to added and alreadySplit. - if (!li->empty()) { - added.push_back(li); - alreadySplit.insert(li); - } - - return added; - } - - /// Extract the given value number from the interval. - LiveInterval* extractVNI(LiveInterval *li, VNInfo *vni) const { - assert(vni->isDefAccurate() || vni->isPHIDef()); - - // Create a new vreg and live interval, copy VNI ranges over. - const TargetRegisterClass *trc = mri->getRegClass(li->reg); - unsigned newVReg = mri->createVirtualRegister(trc); - vrm->grow(); - LiveInterval *newLI = &lis->getOrCreateInterval(newVReg); - VNInfo *newVNI = newLI->createValueCopy(vni, lis->getVNInfoAllocator()); - - // Start by copying all live ranges in the VN to the new interval. - for (LiveInterval::iterator rItr = li->begin(), rEnd = li->end(); - rItr != rEnd; ++rItr) { - if (rItr->valno == vni) { - newLI->addRange(LiveRange(rItr->start, rItr->end, newVNI)); - } - } - - // Erase the old VNI & ranges. - li->removeValNo(vni); - - // Collect all current uses of the register belonging to the given VNI. - // We'll use this to rename the register after we've dealt with the def. - std::set uses; - for (MachineRegisterInfo::use_iterator - useItr = mri->use_begin(li->reg), useEnd = mri->use_end(); - useItr != useEnd; ++useItr) { - uses.insert(&*useItr); - } - - // Process the def instruction for this VNI. - if (newVNI->isPHIDef()) { - // Insert a copy at the start of the MBB. The range proceeding the - // copy will be attached to the original LiveInterval. - MachineBasicBlock *defMBB = lis->getMBBFromIndex(newVNI->def); - MachineInstr *copyMI = BuildMI(*defMBB, defMBB->begin(), DebugLoc(), - tii->get(TargetOpcode::COPY), newVReg) - .addReg(li->reg, RegState::Kill); - SlotIndex copyIdx = lis->InsertMachineInstrInMaps(copyMI); - VNInfo *phiDefVNI = li->getNextValue(lis->getMBBStartIdx(defMBB), - 0, false, lis->getVNInfoAllocator()); - phiDefVNI->setIsPHIDef(true); - li->addRange(LiveRange(phiDefVNI->def, copyIdx.getDefIndex(), phiDefVNI)); - LiveRange *oldPHIDefRange = - newLI->getLiveRangeContaining(lis->getMBBStartIdx(defMBB)); - - // If the old phi def starts in the middle of the range chop it up. - if (oldPHIDefRange->start < lis->getMBBStartIdx(defMBB)) { - LiveRange oldPHIDefRange2(copyIdx.getDefIndex(), oldPHIDefRange->end, - oldPHIDefRange->valno); - oldPHIDefRange->end = lis->getMBBStartIdx(defMBB); - newLI->addRange(oldPHIDefRange2); - } else if (oldPHIDefRange->start == lis->getMBBStartIdx(defMBB)) { - // Otherwise if it's at the start of the range just trim it. - oldPHIDefRange->start = copyIdx.getDefIndex(); - } else { - assert(false && "PHI def range doesn't cover PHI def?"); - } - - newVNI->def = copyIdx.getDefIndex(); - newVNI->setCopy(copyMI); - newVNI->setIsPHIDef(false); // not a PHI def anymore. - newVNI->setIsDefAccurate(true); - } else { - // non-PHI def. Rename the def. If it's two-addr that means renaming the - // use and inserting a new copy too. - MachineInstr *defInst = lis->getInstructionFromIndex(newVNI->def); - // We'll rename this now, so we can remove it from uses. - uses.erase(defInst); - unsigned defOpIdx = defInst->findRegisterDefOperandIdx(li->reg); - bool isTwoAddr = defInst->isRegTiedToUseOperand(defOpIdx), - twoAddrUseIsUndef = false; - - for (unsigned i = 0; i < defInst->getNumOperands(); ++i) { - MachineOperand &mo = defInst->getOperand(i); - if (mo.isReg() && (mo.isDef() || isTwoAddr) && (mo.getReg()==li->reg)) { - mo.setReg(newVReg); - if (isTwoAddr && mo.isUse() && mo.isUndef()) - twoAddrUseIsUndef = true; - } - } - - SlotIndex defIdx = lis->getInstructionIndex(defInst); - newVNI->def = defIdx.getDefIndex(); - - if (isTwoAddr && !twoAddrUseIsUndef) { - MachineBasicBlock *defMBB = defInst->getParent(); - MachineInstr *copyMI = BuildMI(*defMBB, defInst, DebugLoc(), - tii->get(TargetOpcode::COPY), newVReg) - .addReg(li->reg, RegState::Kill); - SlotIndex copyIdx = lis->InsertMachineInstrInMaps(copyMI); - LiveRange *origUseRange = - li->getLiveRangeContaining(newVNI->def.getUseIndex()); - origUseRange->end = copyIdx.getDefIndex(); - VNInfo *copyVNI = newLI->getNextValue(copyIdx.getDefIndex(), copyMI, - true, lis->getVNInfoAllocator()); - LiveRange copyRange(copyIdx.getDefIndex(),defIdx.getDefIndex(),copyVNI); - newLI->addRange(copyRange); - } - } - - for (std::set::iterator - usesItr = uses.begin(), usesEnd = uses.end(); - usesItr != usesEnd; ++usesItr) { - MachineInstr *useInst = *usesItr; - SlotIndex useIdx = lis->getInstructionIndex(useInst); - LiveRange *useRange = - newLI->getLiveRangeContaining(useIdx.getUseIndex()); - - // If this use doesn't belong to the new interval skip it. - if (useRange == 0) - continue; - - // This use doesn't belong to the VNI, skip it. - if (useRange->valno != newVNI) - continue; - - // Check if this instr is two address. - unsigned useOpIdx = useInst->findRegisterUseOperandIdx(li->reg); - bool isTwoAddress = useInst->isRegTiedToDefOperand(useOpIdx); - - // Rename uses (and defs for two-address instrs). - for (unsigned i = 0; i < useInst->getNumOperands(); ++i) { - MachineOperand &mo = useInst->getOperand(i); - if (mo.isReg() && (mo.isUse() || isTwoAddress) && - (mo.getReg() == li->reg)) { - mo.setReg(newVReg); - } - } - - // If this is a two address instruction we've got some extra work to do. - if (isTwoAddress) { - // We modified the def operand, so we need to copy back to the original - // reg. - MachineBasicBlock *useMBB = useInst->getParent(); - MachineBasicBlock::iterator useItr(useInst); - MachineInstr *copyMI = BuildMI(*useMBB, llvm::next(useItr), DebugLoc(), - tii->get(TargetOpcode::COPY), newVReg) - .addReg(li->reg, RegState::Kill); - SlotIndex copyIdx = lis->InsertMachineInstrInMaps(copyMI); - - // Change the old two-address defined range & vni to start at - // (and be defined by) the copy. - LiveRange *origDefRange = - li->getLiveRangeContaining(useIdx.getDefIndex()); - origDefRange->start = copyIdx.getDefIndex(); - origDefRange->valno->def = copyIdx.getDefIndex(); - origDefRange->valno->setCopy(copyMI); - - // Insert a new range & vni for the two-address-to-copy value. This - // will be attached to the new live interval. - VNInfo *copyVNI = - newLI->getNextValue(useIdx.getDefIndex(), 0, true, - lis->getVNInfoAllocator()); - LiveRange copyRange(useIdx.getDefIndex(),copyIdx.getDefIndex(),copyVNI); - newLI->addRange(copyRange); - } - } - - // Iterate over any PHI kills - we'll need to insert new copies for them. - for (LiveInterval::iterator LRI = newLI->begin(), LRE = newLI->end(); - LRI != LRE; ++LRI) { - if (LRI->valno != newVNI || LRI->end.isPHI()) - continue; - SlotIndex killIdx = LRI->end; - MachineBasicBlock *killMBB = lis->getMBBFromIndex(killIdx); - MachineInstr *copyMI = BuildMI(*killMBB, killMBB->getFirstTerminator(), - DebugLoc(), tii->get(TargetOpcode::COPY), - li->reg) - .addReg(newVReg, RegState::Kill); - SlotIndex copyIdx = lis->InsertMachineInstrInMaps(copyMI); - - // Save the current end. We may need it to add a new range if the - // current range runs of the end of the MBB. - SlotIndex newKillRangeEnd = LRI->end; - LRI->end = copyIdx.getDefIndex(); - - if (newKillRangeEnd != lis->getMBBEndIdx(killMBB)) { - assert(newKillRangeEnd > lis->getMBBEndIdx(killMBB) && - "PHI kill range doesn't reach kill-block end. Not sane."); - newLI->addRange(LiveRange(lis->getMBBEndIdx(killMBB), - newKillRangeEnd, newVNI)); - } - - VNInfo *newKillVNI = li->getNextValue(copyIdx.getDefIndex(), - copyMI, true, - lis->getVNInfoAllocator()); - newKillVNI->setHasPHIKill(true); - li->addRange(LiveRange(copyIdx.getDefIndex(), - lis->getMBBEndIdx(killMBB), - newKillVNI)); - } - newVNI->setHasPHIKill(false); - - return newLI; - } - }; } // end anonymous namespace - -namespace llvm { -Spiller *createInlineSpiller(MachineFunctionPass &pass, - MachineFunction &mf, - VirtRegMap &vrm); -} - llvm::Spiller* llvm::createSpiller(MachineFunctionPass &pass, MachineFunction &mf, VirtRegMap &vrm) { @@ -511,7 +238,6 @@ llvm::Spiller* llvm::createSpiller(MachineFunctionPass &pass, default: assert(0 && "unknown spiller"); case trivial: return new TrivialSpiller(pass, mf, vrm); case standard: return new StandardSpiller(pass, mf, vrm); - case splitting: return new SplittingSpiller(pass, mf, vrm); case inline_: return createInlineSpiller(pass, mf, vrm); } } diff --git a/lib/CodeGen/Spiller.h b/lib/CodeGen/Spiller.h index 59bc0ec6ae70..f017583494ed 100644 --- a/lib/CodeGen/Spiller.h +++ b/lib/CodeGen/Spiller.h @@ -10,14 +10,13 @@ #ifndef LLVM_CODEGEN_SPILLER_H #define LLVM_CODEGEN_SPILLER_H -#include "llvm/ADT/SmallVector.h" - namespace llvm { class LiveInterval; class MachineFunction; class MachineFunctionPass; class SlotIndex; + template class SmallVectorImpl; class VirtRegMap; /// Spiller interface. @@ -37,7 +36,7 @@ namespace llvm { /// @param newIntervals The newly created intervals will be appended here. virtual void spill(LiveInterval *li, SmallVectorImpl &newIntervals, - SmallVectorImpl &spillIs) = 0; + const SmallVectorImpl &spillIs) = 0; }; @@ -45,6 +44,13 @@ namespace llvm { Spiller* createSpiller(MachineFunctionPass &pass, MachineFunction &mf, VirtRegMap &vrm); + + /// Create and return a spiller that will insert spill code directly instead + /// of deferring though VirtRegMap. + Spiller *createInlineSpiller(MachineFunctionPass &pass, + MachineFunction &mf, + VirtRegMap &vrm); + } #endif diff --git a/lib/CodeGen/SplitKit.cpp b/lib/CodeGen/SplitKit.cpp index 29474f0d5512..5663936bf3aa 100644 --- a/lib/CodeGen/SplitKit.cpp +++ b/lib/CodeGen/SplitKit.cpp @@ -12,13 +12,14 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "splitter" +#define DEBUG_TYPE "regalloc" #include "SplitKit.h" +#include "LiveRangeEdit.h" #include "VirtRegMap.h" #include "llvm/CodeGen/CalcSpillWeights.h" #include "llvm/CodeGen/LiveIntervalAnalysis.h" +#include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/CodeGen/MachineLoopInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -36,371 +37,231 @@ AllowSplit("spiller-splits-edges", // Split Analysis //===----------------------------------------------------------------------===// -SplitAnalysis::SplitAnalysis(const MachineFunction &mf, +SplitAnalysis::SplitAnalysis(const VirtRegMap &vrm, const LiveIntervals &lis, const MachineLoopInfo &mli) - : mf_(mf), - lis_(lis), - loops_(mli), - tii_(*mf.getTarget().getInstrInfo()), - curli_(0) {} + : MF(vrm.getMachineFunction()), + VRM(vrm), + LIS(lis), + Loops(mli), + TII(*MF.getTarget().getInstrInfo()), + CurLI(0) {} void SplitAnalysis::clear() { - usingInstrs_.clear(); - usingBlocks_.clear(); - usingLoops_.clear(); - curli_ = 0; + UseSlots.clear(); + UsingInstrs.clear(); + UsingBlocks.clear(); + LiveBlocks.clear(); + CurLI = 0; } bool SplitAnalysis::canAnalyzeBranch(const MachineBasicBlock *MBB) { MachineBasicBlock *T, *F; SmallVector Cond; - return !tii_.AnalyzeBranch(const_cast(*MBB), T, F, Cond); + return !TII.AnalyzeBranch(const_cast(*MBB), T, F, Cond); } -/// analyzeUses - Count instructions, basic blocks, and loops using curli. +/// analyzeUses - Count instructions, basic blocks, and loops using CurLI. void SplitAnalysis::analyzeUses() { - const MachineRegisterInfo &MRI = mf_.getRegInfo(); - for (MachineRegisterInfo::reg_iterator I = MRI.reg_begin(curli_->reg); - MachineInstr *MI = I.skipInstruction();) { - if (MI->isDebugValue() || !usingInstrs_.insert(MI)) + const MachineRegisterInfo &MRI = MF.getRegInfo(); + for (MachineRegisterInfo::reg_iterator I = MRI.reg_begin(CurLI->reg), + E = MRI.reg_end(); I != E; ++I) { + MachineOperand &MO = I.getOperand(); + if (MO.isUse() && MO.isUndef()) continue; - MachineBasicBlock *MBB = MI->getParent(); - if (usingBlocks_[MBB]++) + MachineInstr *MI = MO.getParent(); + if (MI->isDebugValue() || !UsingInstrs.insert(MI)) continue; - if (MachineLoop *Loop = loops_.getLoopFor(MBB)) - usingLoops_[Loop]++; + UseSlots.push_back(LIS.getInstructionIndex(MI).getDefIndex()); + MachineBasicBlock *MBB = MI->getParent(); + UsingBlocks[MBB]++; } + array_pod_sort(UseSlots.begin(), UseSlots.end()); + calcLiveBlockInfo(); DEBUG(dbgs() << " counted " - << usingInstrs_.size() << " instrs, " - << usingBlocks_.size() << " blocks, " - << usingLoops_.size() << " loops.\n"); + << UsingInstrs.size() << " instrs, " + << UsingBlocks.size() << " blocks.\n"); } -/// removeUse - Update statistics by noting that MI no longer uses curli. -void SplitAnalysis::removeUse(const MachineInstr *MI) { - if (!usingInstrs_.erase(MI)) +/// calcLiveBlockInfo - Fill the LiveBlocks array with information about blocks +/// where CurLI is live. +void SplitAnalysis::calcLiveBlockInfo() { + if (CurLI->empty()) return; - // Decrement MBB count. - const MachineBasicBlock *MBB = MI->getParent(); - BlockCountMap::iterator bi = usingBlocks_.find(MBB); - assert(bi != usingBlocks_.end() && "MBB missing"); - assert(bi->second && "0 count in map"); - if (--bi->second) - return; - // No more uses in MBB. - usingBlocks_.erase(bi); + LiveInterval::const_iterator LVI = CurLI->begin(); + LiveInterval::const_iterator LVE = CurLI->end(); + + SmallVectorImpl::const_iterator UseI, UseE; + UseI = UseSlots.begin(); + UseE = UseSlots.end(); + + // Loop over basic blocks where CurLI is live. + MachineFunction::iterator MFI = LIS.getMBBFromIndex(LVI->start); + for (;;) { + BlockInfo BI; + BI.MBB = MFI; + SlotIndex Start, Stop; + tie(Start, Stop) = LIS.getSlotIndexes()->getMBBRange(BI.MBB); + + // The last split point is the latest possible insertion point that dominates + // all successor blocks. If interference reaches LastSplitPoint, it is not + // possible to insert a split or reload that makes CurLI live in the + // outgoing bundle. + MachineBasicBlock::iterator LSP = LIS.getLastSplitPoint(*CurLI, BI.MBB); + if (LSP == BI.MBB->end()) + BI.LastSplitPoint = Stop; + else + BI.LastSplitPoint = LIS.getInstructionIndex(LSP); + + // LVI is the first live segment overlapping MBB. + BI.LiveIn = LVI->start <= Start; + if (!BI.LiveIn) + BI.Def = LVI->start; + + // Find the first and last uses in the block. + BI.Uses = hasUses(MFI); + if (BI.Uses && UseI != UseE) { + BI.FirstUse = *UseI; + assert(BI.FirstUse >= Start); + do ++UseI; + while (UseI != UseE && *UseI < Stop); + BI.LastUse = UseI[-1]; + assert(BI.LastUse < Stop); + } - // Decrement loop count. - MachineLoop *Loop = loops_.getLoopFor(MBB); - if (!Loop) - return; - LoopCountMap::iterator li = usingLoops_.find(Loop); - assert(li != usingLoops_.end() && "Loop missing"); - assert(li->second && "0 count in map"); - if (--li->second) - return; - // No more blocks in Loop. - usingLoops_.erase(li); -} + // Look for gaps in the live range. + bool hasGap = false; + BI.LiveOut = true; + while (LVI->end < Stop) { + SlotIndex LastStop = LVI->end; + if (++LVI == LVE || LVI->start >= Stop) { + BI.Kill = LastStop; + BI.LiveOut = false; + break; + } + if (LastStop < LVI->start) { + hasGap = true; + BI.Kill = LastStop; + BI.Def = LVI->start; + } + } -// Get three sets of basic blocks surrounding a loop: Blocks inside the loop, -// predecessor blocks, and exit blocks. -void SplitAnalysis::getLoopBlocks(const MachineLoop *Loop, LoopBlocks &Blocks) { - Blocks.clear(); - - // Blocks in the loop. - Blocks.Loop.insert(Loop->block_begin(), Loop->block_end()); - - // Predecessor blocks. - const MachineBasicBlock *Header = Loop->getHeader(); - for (MachineBasicBlock::const_pred_iterator I = Header->pred_begin(), - E = Header->pred_end(); I != E; ++I) - if (!Blocks.Loop.count(*I)) - Blocks.Preds.insert(*I); - - // Exit blocks. - for (MachineLoop::block_iterator I = Loop->block_begin(), - E = Loop->block_end(); I != E; ++I) { - const MachineBasicBlock *MBB = *I; - for (MachineBasicBlock::const_succ_iterator SI = MBB->succ_begin(), - SE = MBB->succ_end(); SI != SE; ++SI) - if (!Blocks.Loop.count(*SI)) - Blocks.Exits.insert(*SI); - } -} + // Don't set LiveThrough when the block has a gap. + BI.LiveThrough = !hasGap && BI.LiveIn && BI.LiveOut; + LiveBlocks.push_back(BI); -/// analyzeLoopPeripheralUse - Return an enum describing how curli_ is used in -/// and around the Loop. -SplitAnalysis::LoopPeripheralUse SplitAnalysis:: -analyzeLoopPeripheralUse(const SplitAnalysis::LoopBlocks &Blocks) { - LoopPeripheralUse use = ContainedInLoop; - for (BlockCountMap::iterator I = usingBlocks_.begin(), E = usingBlocks_.end(); - I != E; ++I) { - const MachineBasicBlock *MBB = I->first; - // Is this a peripheral block? - if (use < MultiPeripheral && - (Blocks.Preds.count(MBB) || Blocks.Exits.count(MBB))) { - if (I->second > 1) use = MultiPeripheral; - else use = SinglePeripheral; - continue; - } - // Is it a loop block? - if (Blocks.Loop.count(MBB)) - continue; - // It must be an unrelated block. - return OutsideLoop; - } - return use; -} + // LVI is now at LVE or LVI->end >= Stop. + if (LVI == LVE) + break; -/// getCriticalExits - It may be necessary to partially break critical edges -/// leaving the loop if an exit block has phi uses of curli. Collect the exit -/// blocks that need special treatment into CriticalExits. -void SplitAnalysis::getCriticalExits(const SplitAnalysis::LoopBlocks &Blocks, - BlockPtrSet &CriticalExits) { - CriticalExits.clear(); - - // A critical exit block contains a phi def of curli, and has a predecessor - // that is not in the loop nor a loop predecessor. - // For such an exit block, the edges carrying the new variable must be moved - // to a new pre-exit block. - for (BlockPtrSet::iterator I = Blocks.Exits.begin(), E = Blocks.Exits.end(); - I != E; ++I) { - const MachineBasicBlock *Succ = *I; - SlotIndex SuccIdx = lis_.getMBBStartIdx(Succ); - VNInfo *SuccVNI = curli_->getVNInfoAt(SuccIdx); - // This exit may not have curli live in at all. No need to split. - if (!SuccVNI) - continue; - // If this is not a PHI def, it is either using a value from before the - // loop, or a value defined inside the loop. Both are safe. - if (!SuccVNI->isPHIDef() || SuccVNI->def.getBaseIndex() != SuccIdx) - continue; - // This exit block does have a PHI. Does it also have a predecessor that is - // not a loop block or loop predecessor? - for (MachineBasicBlock::const_pred_iterator PI = Succ->pred_begin(), - PE = Succ->pred_end(); PI != PE; ++PI) { - const MachineBasicBlock *Pred = *PI; - if (Blocks.Loop.count(Pred) || Blocks.Preds.count(Pred)) - continue; - // This is a critical exit block, and we need to split the exit edge. - CriticalExits.insert(Succ); + // Live segment ends exactly at Stop. Move to the next segment. + if (LVI->end == Stop && ++LVI == LVE) break; - } + + // Pick the next basic block. + if (LVI->start < Stop) + ++MFI; + else + MFI = LIS.getMBBFromIndex(LVI->start); } } -/// canSplitCriticalExits - Return true if it is possible to insert new exit -/// blocks before the blocks in CriticalExits. -bool -SplitAnalysis::canSplitCriticalExits(const SplitAnalysis::LoopBlocks &Blocks, - BlockPtrSet &CriticalExits) { - // If we don't allow critical edge splitting, require no critical exits. - if (!AllowSplit) - return CriticalExits.empty(); - - for (BlockPtrSet::iterator I = CriticalExits.begin(), E = CriticalExits.end(); - I != E; ++I) { - const MachineBasicBlock *Succ = *I; - // We want to insert a new pre-exit MBB before Succ, and change all the - // in-loop blocks to branch to the pre-exit instead of Succ. - // Check that all the in-loop predecessors can be changed. - for (MachineBasicBlock::const_pred_iterator PI = Succ->pred_begin(), - PE = Succ->pred_end(); PI != PE; ++PI) { - const MachineBasicBlock *Pred = *PI; - // The external predecessors won't be altered. - if (!Blocks.Loop.count(Pred) && !Blocks.Preds.count(Pred)) - continue; - if (!canAnalyzeBranch(Pred)) - return false; - } - - // If Succ's layout predecessor falls through, that too must be analyzable. - // We need to insert the pre-exit block in the gap. - MachineFunction::const_iterator MFI = Succ; - if (MFI == mf_.begin()) - continue; - if (!canAnalyzeBranch(--MFI)) - return false; +void SplitAnalysis::print(const BlockPtrSet &B, raw_ostream &OS) const { + for (BlockPtrSet::const_iterator I = B.begin(), E = B.end(); I != E; ++I) { + unsigned count = UsingBlocks.lookup(*I); + OS << " BB#" << (*I)->getNumber(); + if (count) + OS << '(' << count << ')'; } - // No problems found. - return true; } void SplitAnalysis::analyze(const LiveInterval *li) { clear(); - curli_ = li; + CurLI = li; analyzeUses(); } -const MachineLoop *SplitAnalysis::getBestSplitLoop() { - assert(curli_ && "Call analyze() before getBestSplitLoop"); - if (usingLoops_.empty()) - return 0; - - LoopPtrSet Loops, SecondLoops; - LoopBlocks Blocks; - BlockPtrSet CriticalExits; - - // Find first-class and second class candidate loops. - // We prefer to split around loops where curli is used outside the periphery. - for (LoopCountMap::const_iterator I = usingLoops_.begin(), - E = usingLoops_.end(); I != E; ++I) { - const MachineLoop *Loop = I->first; - getLoopBlocks(Loop, Blocks); - - // FIXME: We need an SSA updater to properly handle multiple exit blocks. - if (Blocks.Exits.size() > 1) { - DEBUG(dbgs() << " multiple exits from " << *Loop); - continue; - } - - LoopPtrSet *LPS = 0; - switch(analyzeLoopPeripheralUse(Blocks)) { - case OutsideLoop: - LPS = &Loops; - break; - case MultiPeripheral: - LPS = &SecondLoops; - break; - case ContainedInLoop: - DEBUG(dbgs() << " contained in " << *Loop); - continue; - case SinglePeripheral: - DEBUG(dbgs() << " single peripheral use in " << *Loop); - continue; - } - // Will it be possible to split around this loop? - getCriticalExits(Blocks, CriticalExits); - DEBUG(dbgs() << " " << CriticalExits.size() << " critical exits from " - << *Loop); - if (!canSplitCriticalExits(Blocks, CriticalExits)) - continue; - // This is a possible split. - assert(LPS); - LPS->insert(Loop); - } - - DEBUG(dbgs() << " getBestSplitLoop found " << Loops.size() << " + " - << SecondLoops.size() << " candidate loops.\n"); - - // If there are no first class loops available, look at second class loops. - if (Loops.empty()) - Loops = SecondLoops; - if (Loops.empty()) - return 0; +//===----------------------------------------------------------------------===// +// LiveIntervalMap +//===----------------------------------------------------------------------===// - // Pick the earliest loop. - // FIXME: Are there other heuristics to consider? - const MachineLoop *Best = 0; - SlotIndex BestIdx; - for (LoopPtrSet::const_iterator I = Loops.begin(), E = Loops.end(); I != E; - ++I) { - SlotIndex Idx = lis_.getMBBStartIdx((*I)->getHeader()); - if (!Best || Idx < BestIdx) - Best = *I, BestIdx = Idx; - } - DEBUG(dbgs() << " getBestSplitLoop found " << *Best); - return Best; +// Work around the fact that the std::pair constructors are broken for pointer +// pairs in some implementations. makeVV(x, 0) works. +static inline std::pair +makeVV(const VNInfo *a, VNInfo *b) { + return std::make_pair(a, b); } -/// getMultiUseBlocks - if curli has more than one use in a basic block, it -/// may be an advantage to split curli for the duration of the block. -bool SplitAnalysis::getMultiUseBlocks(BlockPtrSet &Blocks) { - // If curli is local to one block, there is no point to splitting it. - if (usingBlocks_.size() <= 1) - return false; - // Add blocks with multiple uses. - for (BlockCountMap::iterator I = usingBlocks_.begin(), E = usingBlocks_.end(); - I != E; ++I) - switch (I->second) { - case 0: - case 1: - continue; - case 2: { - // It doesn't pay to split a 2-instr block if it redefines curli. - VNInfo *VN1 = curli_->getVNInfoAt(lis_.getMBBStartIdx(I->first)); - VNInfo *VN2 = - curli_->getVNInfoAt(lis_.getMBBEndIdx(I->first).getPrevIndex()); - // live-in and live-out with a different value. - if (VN1 && VN2 && VN1 != VN2) - continue; - } // Fall through. - default: - Blocks.insert(I->first); - } - return !Blocks.empty(); +void LiveIntervalMap::reset(LiveInterval *li) { + LI = li; + Values.clear(); + LiveOutCache.clear(); } -//===----------------------------------------------------------------------===// -// LiveIntervalMap -//===----------------------------------------------------------------------===// +bool LiveIntervalMap::isComplexMapped(const VNInfo *ParentVNI) const { + ValueMap::const_iterator i = Values.find(ParentVNI); + return i != Values.end() && i->second == 0; +} -// defValue - Introduce a li_ def for ParentVNI that could be later than +// defValue - Introduce a LI def for ParentVNI that could be later than // ParentVNI->def. VNInfo *LiveIntervalMap::defValue(const VNInfo *ParentVNI, SlotIndex Idx) { + assert(LI && "call reset first"); assert(ParentVNI && "Mapping NULL value"); assert(Idx.isValid() && "Invalid SlotIndex"); - assert(parentli_.getVNInfoAt(Idx) == ParentVNI && "Bad ParentVNI"); - - // Is this a simple 1-1 mapping? Not likely. - if (Idx == ParentVNI->def) - return mapValue(ParentVNI, Idx); - - // This is a complex def. Mark with a NULL in valueMap. - VNInfo *OldVNI = - valueMap_.insert( - ValueMap::value_type(ParentVNI, static_cast(0))).first->second; - // The static_cast is only needed to work around a bug in an - // old version of the C++0x standard which the following compilers - // implemented and have yet to fix: - // - // Microsoft Visual Studio 2010 Version 10.0.30319.1 RTMRel - // Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 - // - // If/When we move to C++0x, this can be replaced by nullptr. - (void)OldVNI; - assert(OldVNI == 0 && "Simple/Complex values mixed"); - - // Should we insert a minimal snippet of VNI LiveRange, or can we count on - // callers to do that? We need it for lookups of complex values. - VNInfo *VNI = li_.getNextValue(Idx, 0, true, lis_.getVNInfoAllocator()); + assert(ParentLI.getVNInfoAt(Idx) == ParentVNI && "Bad ParentVNI"); + + // Create a new value. + VNInfo *VNI = LI->getNextValue(Idx, 0, LIS.getVNInfoAllocator()); + + // Preserve the PHIDef bit. + if (ParentVNI->isPHIDef() && Idx == ParentVNI->def) + VNI->setIsPHIDef(true); + + // Use insert for lookup, so we can add missing values with a second lookup. + std::pair InsP = + Values.insert(makeVV(ParentVNI, Idx == ParentVNI->def ? VNI : 0)); + + // This is now a complex def. Mark with a NULL in valueMap. + if (!InsP.second) + InsP.first->second = 0; + return VNI; } + // mapValue - Find the mapped value for ParentVNI at Idx. // Potentially create phi-def values. -VNInfo *LiveIntervalMap::mapValue(const VNInfo *ParentVNI, SlotIndex Idx) { +VNInfo *LiveIntervalMap::mapValue(const VNInfo *ParentVNI, SlotIndex Idx, + bool *simple) { + assert(LI && "call reset first"); assert(ParentVNI && "Mapping NULL value"); assert(Idx.isValid() && "Invalid SlotIndex"); - assert(parentli_.getVNInfoAt(Idx) == ParentVNI && "Bad ParentVNI"); + assert(ParentLI.getVNInfoAt(Idx) == ParentVNI && "Bad ParentVNI"); // Use insert for lookup, so we can add missing values with a second lookup. std::pair InsP = - valueMap_.insert(ValueMap::value_type(ParentVNI, static_cast(0))); - // The static_cast is only needed to work around a bug in an - // old version of the C++0x standard which the following compilers - // implemented and have yet to fix: - // - // Microsoft Visual Studio 2010 Version 10.0.30319.1 RTMRel - // Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 - // - // If/When we move to C++0x, this can be replaced by nullptr. + Values.insert(makeVV(ParentVNI, 0)); // This was an unknown value. Create a simple mapping. - if (InsP.second) - return InsP.first->second = li_.createValueCopy(ParentVNI, - lis_.getVNInfoAllocator()); + if (InsP.second) { + if (simple) *simple = true; + return InsP.first->second = LI->createValueCopy(ParentVNI, + LIS.getVNInfoAllocator()); + } + // This was a simple mapped value. - if (InsP.first->second) + if (InsP.first->second) { + if (simple) *simple = true; return InsP.first->second; + } // This is a complex mapped value. There may be multiple defs, and we may need // to create phi-defs. - MachineBasicBlock *IdxMBB = lis_.getMBBFromIndex(Idx); + if (simple) *simple = false; + MachineBasicBlock *IdxMBB = LIS.getMBBFromIndex(Idx); assert(IdxMBB && "No MBB at Idx"); // Is there a def in the same MBB we can extend? @@ -409,157 +270,260 @@ VNInfo *LiveIntervalMap::mapValue(const VNInfo *ParentVNI, SlotIndex Idx) { // Now for the fun part. We know that ParentVNI potentially has multiple defs, // and we may need to create even more phi-defs to preserve VNInfo SSA form. - // Perform a depth-first search for predecessor blocks where we know the - // dominating VNInfo. Insert phi-def VNInfos along the path back to IdxMBB. - - // Track MBBs where we have created or learned the dominating value. - // This may change during the DFS as we create new phi-defs. - typedef DenseMap MBBValueMap; - MBBValueMap DomValue; - - for (idf_iterator - IDFI = idf_begin(IdxMBB), - IDFE = idf_end(IdxMBB); IDFI != IDFE;) { - MachineBasicBlock *MBB = *IDFI; - SlotIndex End = lis_.getMBBEndIdx(MBB); - - // We are operating on the restricted CFG where ParentVNI is live. - if (parentli_.getVNInfoAt(End.getPrevSlot()) != ParentVNI) { - IDFI.skipChildren(); - continue; - } - - // Do we have a dominating value in this block? - VNInfo *VNI = extendTo(MBB, End); - if (!VNI) { - ++IDFI; - continue; + // Perform a search for all predecessor blocks where we know the dominating + // VNInfo. Insert phi-def VNInfos along the path back to IdxMBB. + DEBUG(dbgs() << "\n Reaching defs for BB#" << IdxMBB->getNumber() + << " at " << Idx << " in " << *LI << '\n'); + + // Blocks where LI should be live-in. + SmallVector LiveIn; + LiveIn.push_back(MDT[IdxMBB]); + + // Using LiveOutCache as a visited set, perform a BFS for all reaching defs. + for (unsigned i = 0; i != LiveIn.size(); ++i) { + MachineBasicBlock *MBB = LiveIn[i]->getBlock(); + for (MachineBasicBlock::pred_iterator PI = MBB->pred_begin(), + PE = MBB->pred_end(); PI != PE; ++PI) { + MachineBasicBlock *Pred = *PI; + // Is this a known live-out block? + std::pair LOIP = + LiveOutCache.insert(std::make_pair(Pred, LiveOutPair())); + // Yes, we have been here before. + if (!LOIP.second) { + DEBUG(if (VNInfo *VNI = LOIP.first->second.first) + dbgs() << " known valno #" << VNI->id + << " at BB#" << Pred->getNumber() << '\n'); + continue; + } + + // Does Pred provide a live-out value? + SlotIndex Last = LIS.getMBBEndIdx(Pred).getPrevSlot(); + if (VNInfo *VNI = extendTo(Pred, Last)) { + MachineBasicBlock *DefMBB = LIS.getMBBFromIndex(VNI->def); + DEBUG(dbgs() << " found valno #" << VNI->id + << " from BB#" << DefMBB->getNumber() + << " at BB#" << Pred->getNumber() << '\n'); + LiveOutPair &LOP = LOIP.first->second; + LOP.first = VNI; + LOP.second = MDT[DefMBB]; + continue; + } + // No, we need a live-in value for Pred as well + if (Pred != IdxMBB) + LiveIn.push_back(MDT[Pred]); } + } - // Yes, VNI dominates MBB. Track the path back to IdxMBB, creating phi-defs - // as needed along the way. - for (unsigned PI = IDFI.getPathLength()-1; PI != 0; --PI) { - // Start from MBB's immediate successor. End at IdxMBB. - MachineBasicBlock *Succ = IDFI.getPath(PI-1); - std::pair InsP = - DomValue.insert(MBBValueMap::value_type(Succ, VNI)); - - // This is the first time we backtrack to Succ. - if (InsP.second) - continue; - - // We reached Succ again with the same VNI. Nothing is going to change. - VNInfo *OVNI = InsP.first->second; - if (OVNI == VNI) - break; + // We may need to add phi-def values to preserve the SSA form. + // This is essentially the same iterative algorithm that SSAUpdater uses, + // except we already have a dominator tree, so we don't have to recompute it. + VNInfo *IdxVNI = 0; + unsigned Changes; + do { + Changes = 0; + DEBUG(dbgs() << " Iterating over " << LiveIn.size() << " blocks.\n"); + // Propagate live-out values down the dominator tree, inserting phi-defs when + // necessary. Since LiveIn was created by a BFS, going backwards makes it more + // likely for us to visit immediate dominators before their children. + for (unsigned i = LiveIn.size(); i; --i) { + MachineDomTreeNode *Node = LiveIn[i-1]; + MachineBasicBlock *MBB = Node->getBlock(); + MachineDomTreeNode *IDom = Node->getIDom(); + LiveOutPair IDomValue; + // We need a live-in value to a block with no immediate dominator? + // This is probably an unreachable block that has survived somehow. + bool needPHI = !IDom; + + // Get the IDom live-out value. + if (!needPHI) { + LiveOutMap::iterator I = LiveOutCache.find(IDom->getBlock()); + if (I != LiveOutCache.end()) + IDomValue = I->second; + else + // If IDom is outside our set of live-out blocks, there must be new + // defs, and we need a phi-def here. + needPHI = true; + } - // Succ already has a phi-def. No need to continue. - SlotIndex Start = lis_.getMBBStartIdx(Succ); - if (OVNI->def == Start) - break; + // IDom dominates all of our predecessors, but it may not be the immediate + // dominator. Check if any of them have live-out values that are properly + // dominated by IDom. If so, we need a phi-def here. + if (!needPHI) { + for (MachineBasicBlock::pred_iterator PI = MBB->pred_begin(), + PE = MBB->pred_end(); PI != PE; ++PI) { + LiveOutPair Value = LiveOutCache[*PI]; + if (!Value.first || Value.first == IDomValue.first) + continue; + // This predecessor is carrying something other than IDomValue. + // It could be because IDomValue hasn't propagated yet, or it could be + // because MBB is in the dominance frontier of that value. + if (MDT.dominates(IDom, Value.second)) { + needPHI = true; + break; + } + } + } - // We have a collision between the old and new VNI at Succ. That means - // neither dominates and we need a new phi-def. - VNI = li_.getNextValue(Start, 0, true, lis_.getVNInfoAllocator()); - VNI->setIsPHIDef(true); - InsP.first->second = VNI; - - // Replace OVNI with VNI in the remaining path. - for (; PI > 1 ; --PI) { - MBBValueMap::iterator I = DomValue.find(IDFI.getPath(PI-2)); - if (I == DomValue.end() || I->second != OVNI) - break; - I->second = VNI; + // Create a phi-def if required. + if (needPHI) { + ++Changes; + SlotIndex Start = LIS.getMBBStartIdx(MBB); + VNInfo *VNI = LI->getNextValue(Start, 0, LIS.getVNInfoAllocator()); + VNI->setIsPHIDef(true); + DEBUG(dbgs() << " - BB#" << MBB->getNumber() + << " phi-def #" << VNI->id << " at " << Start << '\n'); + // We no longer need LI to be live-in. + LiveIn.erase(LiveIn.begin()+(i-1)); + // Blocks in LiveIn are either IdxMBB, or have a value live-through. + if (MBB == IdxMBB) + IdxVNI = VNI; + // Check if we need to update live-out info. + LiveOutMap::iterator I = LiveOutCache.find(MBB); + if (I == LiveOutCache.end() || I->second.second == Node) { + // We already have a live-out defined in MBB, so this must be IdxMBB. + assert(MBB == IdxMBB && "Adding phi-def to known live-out"); + LI->addRange(LiveRange(Start, Idx.getNextSlot(), VNI)); + } else { + // This phi-def is also live-out, so color the whole block. + LI->addRange(LiveRange(Start, LIS.getMBBEndIdx(MBB), VNI)); + I->second = LiveOutPair(VNI, Node); + } + } else if (IDomValue.first) { + // No phi-def here. Remember incoming value for IdxMBB. + if (MBB == IdxMBB) + IdxVNI = IDomValue.first; + // Propagate IDomValue if needed: + // MBB is live-out and doesn't define its own value. + LiveOutMap::iterator I = LiveOutCache.find(MBB); + if (I != LiveOutCache.end() && I->second.second != Node && + I->second.first != IDomValue.first) { + ++Changes; + I->second = IDomValue; + DEBUG(dbgs() << " - BB#" << MBB->getNumber() + << " idom valno #" << IDomValue.first->id + << " from BB#" << IDom->getBlock()->getNumber() << '\n'); + } } } + DEBUG(dbgs() << " - made " << Changes << " changes.\n"); + } while (Changes); - // No need to search the children, we found a dominating value. - IDFI.skipChildren(); - } + assert(IdxVNI && "Didn't find value for Idx"); - // The search should at least find a dominating value for IdxMBB. - assert(!DomValue.empty() && "Couldn't find a reaching definition"); +#ifndef NDEBUG + // Check the LiveOutCache invariants. + for (LiveOutMap::iterator I = LiveOutCache.begin(), E = LiveOutCache.end(); + I != E; ++I) { + assert(I->first && "Null MBB entry in cache"); + assert(I->second.first && "Null VNInfo in cache"); + assert(I->second.second && "Null DomTreeNode in cache"); + if (I->second.second->getBlock() == I->first) + continue; + for (MachineBasicBlock::pred_iterator PI = I->first->pred_begin(), + PE = I->first->pred_end(); PI != PE; ++PI) + assert(LiveOutCache.lookup(*PI) == I->second && "Bad invariant"); + } +#endif - // Since we went through the trouble of a full DFS visiting all reaching defs, - // the values in DomValue are now accurate. No more phi-defs are needed for - // these blocks, so we can color the live ranges. + // Since we went through the trouble of a full BFS visiting all reaching defs, + // the values in LiveIn are now accurate. No more phi-defs are needed + // for these blocks, so we can color the live ranges. // This makes the next mapValue call much faster. - VNInfo *IdxVNI = 0; - for (MBBValueMap::iterator I = DomValue.begin(), E = DomValue.end(); I != E; - ++I) { - MachineBasicBlock *MBB = I->first; - VNInfo *VNI = I->second; - SlotIndex Start = lis_.getMBBStartIdx(MBB); - if (MBB == IdxMBB) { - // Don't add full liveness to IdxMBB, stop at Idx. - if (Start != Idx) - li_.addRange(LiveRange(Start, Idx, VNI)); - // The caller had better add some liveness to IdxVNI, or it leaks. - IdxVNI = VNI; - } else - li_.addRange(LiveRange(Start, lis_.getMBBEndIdx(MBB), VNI)); + for (unsigned i = 0, e = LiveIn.size(); i != e; ++i) { + MachineBasicBlock *MBB = LiveIn[i]->getBlock(); + SlotIndex Start = LIS.getMBBStartIdx(MBB); + VNInfo *VNI = LiveOutCache.lookup(MBB).first; + + // Anything in LiveIn other than IdxMBB is live-through. + // In IdxMBB, we should stop at Idx unless the same value is live-out. + if (MBB == IdxMBB && IdxVNI != VNI) + LI->addRange(LiveRange(Start, Idx.getNextSlot(), IdxVNI)); + else + LI->addRange(LiveRange(Start, LIS.getMBBEndIdx(MBB), VNI)); } - assert(IdxVNI && "Didn't find value for Idx"); return IdxVNI; } -// extendTo - Find the last li_ value defined in MBB at or before Idx. The -// parentli_ is assumed to be live at Idx. Extend the live range to Idx. +#ifndef NDEBUG +void LiveIntervalMap::dumpCache() { + for (LiveOutMap::iterator I = LiveOutCache.begin(), E = LiveOutCache.end(); + I != E; ++I) { + assert(I->first && "Null MBB entry in cache"); + assert(I->second.first && "Null VNInfo in cache"); + assert(I->second.second && "Null DomTreeNode in cache"); + dbgs() << " cache: BB#" << I->first->getNumber() + << " has valno #" << I->second.first->id << " from BB#" + << I->second.second->getBlock()->getNumber() << ", preds"; + for (MachineBasicBlock::pred_iterator PI = I->first->pred_begin(), + PE = I->first->pred_end(); PI != PE; ++PI) + dbgs() << " BB#" << (*PI)->getNumber(); + dbgs() << '\n'; + } + dbgs() << " cache: " << LiveOutCache.size() << " entries.\n"; +} +#endif + +// extendTo - Find the last LI value defined in MBB at or before Idx. The +// ParentLI is assumed to be live at Idx. Extend the live range to Idx. // Return the found VNInfo, or NULL. -VNInfo *LiveIntervalMap::extendTo(MachineBasicBlock *MBB, SlotIndex Idx) { - LiveInterval::iterator I = std::upper_bound(li_.begin(), li_.end(), Idx); - if (I == li_.begin()) +VNInfo *LiveIntervalMap::extendTo(const MachineBasicBlock *MBB, SlotIndex Idx) { + assert(LI && "call reset first"); + LiveInterval::iterator I = std::upper_bound(LI->begin(), LI->end(), Idx); + if (I == LI->begin()) return 0; --I; - if (I->start < lis_.getMBBStartIdx(MBB)) + if (I->end <= LIS.getMBBStartIdx(MBB)) return 0; - if (I->end < Idx) - I->end = Idx; + if (I->end <= Idx) + I->end = Idx.getNextSlot(); return I->valno; } -// addSimpleRange - Add a simple range from parentli_ to li_. +// addSimpleRange - Add a simple range from ParentLI to LI. // ParentVNI must be live in the [Start;End) interval. void LiveIntervalMap::addSimpleRange(SlotIndex Start, SlotIndex End, const VNInfo *ParentVNI) { - VNInfo *VNI = mapValue(ParentVNI, Start); - // A simple mappoing is easy. - if (VNI->def == ParentVNI->def) { - li_.addRange(LiveRange(Start, End, VNI)); + assert(LI && "call reset first"); + bool simple; + VNInfo *VNI = mapValue(ParentVNI, Start, &simple); + // A simple mapping is easy. + if (simple) { + LI->addRange(LiveRange(Start, End, VNI)); return; } // ParentVNI is a complex value. We must map per MBB. - MachineFunction::iterator MBB = lis_.getMBBFromIndex(Start); - MachineFunction::iterator MBBE = lis_.getMBBFromIndex(End); + MachineFunction::iterator MBB = LIS.getMBBFromIndex(Start); + MachineFunction::iterator MBBE = LIS.getMBBFromIndex(End.getPrevSlot()); if (MBB == MBBE) { - li_.addRange(LiveRange(Start, End, VNI)); + LI->addRange(LiveRange(Start, End, VNI)); return; } // First block. - li_.addRange(LiveRange(Start, lis_.getMBBEndIdx(MBB), VNI)); + LI->addRange(LiveRange(Start, LIS.getMBBEndIdx(MBB), VNI)); // Run sequence of full blocks. for (++MBB; MBB != MBBE; ++MBB) { - Start = lis_.getMBBStartIdx(MBB); - li_.addRange(LiveRange(Start, lis_.getMBBEndIdx(MBB), - mapValue(ParentVNI, Start))); + Start = LIS.getMBBStartIdx(MBB); + LI->addRange(LiveRange(Start, LIS.getMBBEndIdx(MBB), + mapValue(ParentVNI, Start))); } // Final block. - Start = lis_.getMBBStartIdx(MBB); + Start = LIS.getMBBStartIdx(MBB); if (Start != End) - li_.addRange(LiveRange(Start, End, mapValue(ParentVNI, Start))); + LI->addRange(LiveRange(Start, End, mapValue(ParentVNI, Start))); } -/// addRange - Add live ranges to li_ where [Start;End) intersects parentli_. +/// addRange - Add live ranges to LI where [Start;End) intersects ParentLI. /// All needed values whose def is not inside [Start;End) must be defined /// beforehand so mapValue will work. void LiveIntervalMap::addRange(SlotIndex Start, SlotIndex End) { - LiveInterval::const_iterator B = parentli_.begin(), E = parentli_.end(); + assert(LI && "call reset first"); + LiveInterval::const_iterator B = ParentLI.begin(), E = ParentLI.end(); LiveInterval::const_iterator I = std::lower_bound(B, E, Start); // Check if --I begins before Start and overlaps. @@ -575,403 +539,374 @@ void LiveIntervalMap::addRange(SlotIndex Start, SlotIndex End) { addSimpleRange(I->start, std::min(End, I->end), I->valno); } + //===----------------------------------------------------------------------===// // Split Editor //===----------------------------------------------------------------------===// /// Create a new SplitEditor for editing the LiveInterval analyzed by SA. -SplitEditor::SplitEditor(SplitAnalysis &sa, LiveIntervals &lis, VirtRegMap &vrm, - SmallVectorImpl &intervals) - : sa_(sa), lis_(lis), vrm_(vrm), - mri_(vrm.getMachineFunction().getRegInfo()), - tii_(*vrm.getMachineFunction().getTarget().getInstrInfo()), - curli_(sa_.getCurLI()), - dupli_(0), openli_(0), - intervals_(intervals), - firstInterval(intervals_.size()) +SplitEditor::SplitEditor(SplitAnalysis &sa, + LiveIntervals &lis, + VirtRegMap &vrm, + MachineDominatorTree &mdt, + LiveRangeEdit &edit) + : SA(sa), LIS(lis), VRM(vrm), + MRI(vrm.getMachineFunction().getRegInfo()), + MDT(mdt), + TII(*vrm.getMachineFunction().getTarget().getInstrInfo()), + TRI(*vrm.getMachineFunction().getTarget().getRegisterInfo()), + Edit(edit), + OpenIdx(0), + RegAssign(Allocator) { - assert(curli_ && "SplitEditor created from empty SplitAnalysis"); - - // Make sure curli_ is assigned a stack slot, so all our intervals get the - // same slot as curli_. - if (vrm_.getStackSlot(curli_->reg) == VirtRegMap::NO_STACK_SLOT) - vrm_.assignVirt2StackSlot(curli_->reg); - + // We don't need an AliasAnalysis since we will only be performing + // cheap-as-a-copy remats anyway. + Edit.anyRematerializable(LIS, TII, 0); } -LiveInterval *SplitEditor::createInterval() { - unsigned curli = sa_.getCurLI()->reg; - unsigned Reg = mri_.createVirtualRegister(mri_.getRegClass(curli)); - LiveInterval &Intv = lis_.getOrCreateInterval(Reg); - vrm_.grow(); - vrm_.assignVirt2StackSlot(Reg, vrm_.getStackSlot(curli)); - return &Intv; +void SplitEditor::dump() const { + if (RegAssign.empty()) { + dbgs() << " empty\n"; + return; + } + + for (RegAssignMap::const_iterator I = RegAssign.begin(); I.valid(); ++I) + dbgs() << " [" << I.start() << ';' << I.stop() << "):" << I.value(); + dbgs() << '\n'; } -LiveInterval *SplitEditor::getDupLI() { - if (!dupli_) { - // Create an interval for dupli that is a copy of curli. - dupli_ = createInterval(); - dupli_->Copy(*curli_, &mri_, lis_.getVNInfoAllocator()); +VNInfo *SplitEditor::defFromParent(unsigned RegIdx, + VNInfo *ParentVNI, + SlotIndex UseIdx, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I) { + MachineInstr *CopyMI = 0; + SlotIndex Def; + LiveInterval *LI = Edit.get(RegIdx); + + // Attempt cheap-as-a-copy rematerialization. + LiveRangeEdit::Remat RM(ParentVNI); + if (Edit.canRematerializeAt(RM, UseIdx, true, LIS)) { + Def = Edit.rematerializeAt(MBB, I, LI->reg, RM, LIS, TII, TRI); + } else { + // Can't remat, just insert a copy from parent. + CopyMI = BuildMI(MBB, I, DebugLoc(), TII.get(TargetOpcode::COPY), LI->reg) + .addReg(Edit.getReg()); + Def = LIS.InsertMachineInstrInMaps(CopyMI).getDefIndex(); } - return dupli_; -} -VNInfo *SplitEditor::mapValue(const VNInfo *curliVNI) { - VNInfo *&VNI = valueMap_[curliVNI]; - if (!VNI) - VNI = openli_->createValueCopy(curliVNI, lis_.getVNInfoAllocator()); - return VNI; -} + // Define the value in Reg. + VNInfo *VNI = LIMappers[RegIdx].defValue(ParentVNI, Def); + VNI->setCopy(CopyMI); -/// Insert a COPY instruction curli -> li. Allocate a new value from li -/// defined by the COPY. Note that rewrite() will deal with the curli -/// register, so this function can be used to copy from any interval - openli, -/// curli, or dupli. -VNInfo *SplitEditor::insertCopy(LiveInterval &LI, - MachineBasicBlock &MBB, - MachineBasicBlock::iterator I) { - MachineInstr *MI = BuildMI(MBB, I, DebugLoc(), tii_.get(TargetOpcode::COPY), - LI.reg).addReg(curli_->reg); - SlotIndex DefIdx = lis_.InsertMachineInstrInMaps(MI).getDefIndex(); - return LI.getNextValue(DefIdx, MI, true, lis_.getVNInfoAllocator()); + // Add minimal liveness for the new value. + Edit.get(RegIdx)->addRange(LiveRange(Def, Def.getNextSlot(), VNI)); + return VNI; } /// Create a new virtual register and live interval. void SplitEditor::openIntv() { - assert(!openli_ && "Previous LI not closed before openIntv"); - openli_ = createInterval(); - intervals_.push_back(openli_); - liveThrough_ = false; -} + assert(!OpenIdx && "Previous LI not closed before openIntv"); -/// enterIntvBefore - Enter openli before the instruction at Idx. If curli is -/// not live before Idx, a COPY is not inserted. -void SplitEditor::enterIntvBefore(SlotIndex Idx) { - assert(openli_ && "openIntv not called before enterIntvBefore"); - - // Copy from curli_ if it is live. - if (VNInfo *CurVNI = curli_->getVNInfoAt(Idx.getUseIndex())) { - MachineInstr *MI = lis_.getInstructionFromIndex(Idx); - assert(MI && "enterIntvBefore called with invalid index"); - VNInfo *VNI = insertCopy(*openli_, *MI->getParent(), MI); - openli_->addRange(LiveRange(VNI->def, Idx.getDefIndex(), VNI)); - - // Make sure CurVNI is properly mapped. - VNInfo *&mapVNI = valueMap_[CurVNI]; - // We dont have SSA update yet, so only one entry per value is allowed. - assert(!mapVNI && "enterIntvBefore called more than once for the same value"); - mapVNI = VNI; + // Create the complement as index 0. + if (Edit.empty()) { + Edit.create(MRI, LIS, VRM); + LIMappers.push_back(LiveIntervalMap(LIS, MDT, Edit.getParent())); + LIMappers.back().reset(Edit.get(0)); } - DEBUG(dbgs() << " enterIntvBefore " << Idx << ": " << *openli_ << '\n'); -} -/// enterIntvAtEnd - Enter openli at the end of MBB. -/// PhiMBB is a successor inside openli where a PHI value is created. -/// Currently, all entries must share the same PhiMBB. -void SplitEditor::enterIntvAtEnd(MachineBasicBlock &A, MachineBasicBlock &B) { - assert(openli_ && "openIntv not called before enterIntvAtEnd"); - - SlotIndex EndA = lis_.getMBBEndIdx(&A); - VNInfo *CurVNIA = curli_->getVNInfoAt(EndA.getPrevIndex()); - if (!CurVNIA) { - DEBUG(dbgs() << " enterIntvAtEnd, curli not live out of BB#" - << A.getNumber() << ".\n"); - return; - } + // Create the open interval. + OpenIdx = Edit.size(); + Edit.create(MRI, LIS, VRM); + LIMappers.push_back(LiveIntervalMap(LIS, MDT, Edit.getParent())); + LIMappers[OpenIdx].reset(Edit.get(OpenIdx)); +} - // Add a phi kill value and live range out of A. - VNInfo *VNIA = insertCopy(*openli_, A, A.getFirstTerminator()); - openli_->addRange(LiveRange(VNIA->def, EndA, VNIA)); - - // FIXME: If this is the only entry edge, we don't need the extra PHI value. - // FIXME: If there are multiple entry blocks (so not a loop), we need proper - // SSA update. - - // Now look at the start of B. - SlotIndex StartB = lis_.getMBBStartIdx(&B); - SlotIndex EndB = lis_.getMBBEndIdx(&B); - const LiveRange *CurB = curli_->getLiveRangeContaining(StartB); - if (!CurB) { - DEBUG(dbgs() << " enterIntvAtEnd: curli not live in to BB#" - << B.getNumber() << ".\n"); - return; +SlotIndex SplitEditor::enterIntvBefore(SlotIndex Idx) { + assert(OpenIdx && "openIntv not called before enterIntvBefore"); + DEBUG(dbgs() << " enterIntvBefore " << Idx); + Idx = Idx.getBaseIndex(); + VNInfo *ParentVNI = Edit.getParent().getVNInfoAt(Idx); + if (!ParentVNI) { + DEBUG(dbgs() << ": not live\n"); + return Idx; } + DEBUG(dbgs() << ": valno " << ParentVNI->id << '\n'); + MachineInstr *MI = LIS.getInstructionFromIndex(Idx); + assert(MI && "enterIntvBefore called with invalid index"); - VNInfo *VNIB = openli_->getVNInfoAt(StartB); - if (!VNIB) { - // Create a phi value. - VNIB = openli_->getNextValue(SlotIndex(StartB, true), 0, false, - lis_.getVNInfoAllocator()); - VNIB->setIsPHIDef(true); - VNInfo *&mapVNI = valueMap_[CurB->valno]; - if (mapVNI) { - // Multiple copies - must create PHI value. - abort(); - } else { - // This is the first copy of dupLR. Mark the mapping. - mapVNI = VNIB; - } + VNInfo *VNI = defFromParent(OpenIdx, ParentVNI, Idx, *MI->getParent(), MI); + return VNI->def; +} +SlotIndex SplitEditor::enterIntvAtEnd(MachineBasicBlock &MBB) { + assert(OpenIdx && "openIntv not called before enterIntvAtEnd"); + SlotIndex End = LIS.getMBBEndIdx(&MBB); + SlotIndex Last = End.getPrevSlot(); + DEBUG(dbgs() << " enterIntvAtEnd BB#" << MBB.getNumber() << ", " << Last); + VNInfo *ParentVNI = Edit.getParent().getVNInfoAt(Last); + if (!ParentVNI) { + DEBUG(dbgs() << ": not live\n"); + return End; } - - DEBUG(dbgs() << " enterIntvAtEnd: " << *openli_ << '\n'); + DEBUG(dbgs() << ": valno " << ParentVNI->id); + VNInfo *VNI = defFromParent(OpenIdx, ParentVNI, Last, MBB, + LIS.getLastSplitPoint(Edit.getParent(), &MBB)); + RegAssign.insert(VNI->def, End, OpenIdx); + DEBUG(dump()); + return VNI->def; } -/// useIntv - indicate that all instructions in MBB should use openli. +/// useIntv - indicate that all instructions in MBB should use OpenLI. void SplitEditor::useIntv(const MachineBasicBlock &MBB) { - useIntv(lis_.getMBBStartIdx(&MBB), lis_.getMBBEndIdx(&MBB)); + useIntv(LIS.getMBBStartIdx(&MBB), LIS.getMBBEndIdx(&MBB)); } void SplitEditor::useIntv(SlotIndex Start, SlotIndex End) { - assert(openli_ && "openIntv not called before useIntv"); + assert(OpenIdx && "openIntv not called before useIntv"); + DEBUG(dbgs() << " useIntv [" << Start << ';' << End << "):"); + RegAssign.insert(Start, End, OpenIdx); + DEBUG(dump()); +} - // Map the curli values from the interval into openli_ - LiveInterval::const_iterator B = curli_->begin(), E = curli_->end(); - LiveInterval::const_iterator I = std::lower_bound(B, E, Start); +SlotIndex SplitEditor::leaveIntvAfter(SlotIndex Idx) { + assert(OpenIdx && "openIntv not called before leaveIntvAfter"); + DEBUG(dbgs() << " leaveIntvAfter " << Idx); - if (I != B) { - --I; - // I begins before Start, but overlaps. - if (I->end > Start) - openli_->addRange(LiveRange(Start, std::min(End, I->end), - mapValue(I->valno))); - ++I; + // The interval must be live beyond the instruction at Idx. + Idx = Idx.getBoundaryIndex(); + VNInfo *ParentVNI = Edit.getParent().getVNInfoAt(Idx); + if (!ParentVNI) { + DEBUG(dbgs() << ": not live\n"); + return Idx.getNextSlot(); } + DEBUG(dbgs() << ": valno " << ParentVNI->id << '\n'); - // The remaining ranges begin after Start. - for (;I != E && I->start < End; ++I) - openli_->addRange(LiveRange(I->start, std::min(End, I->end), - mapValue(I->valno))); - DEBUG(dbgs() << " use [" << Start << ';' << End << "): " << *openli_ - << '\n'); + MachineInstr *MI = LIS.getInstructionFromIndex(Idx); + assert(MI && "No instruction at index"); + VNInfo *VNI = defFromParent(0, ParentVNI, Idx, *MI->getParent(), + llvm::next(MachineBasicBlock::iterator(MI))); + return VNI->def; } -/// leaveIntvAfter - Leave openli after the instruction at Idx. -void SplitEditor::leaveIntvAfter(SlotIndex Idx) { - assert(openli_ && "openIntv not called before leaveIntvAfter"); +SlotIndex SplitEditor::leaveIntvBefore(SlotIndex Idx) { + assert(OpenIdx && "openIntv not called before leaveIntvBefore"); + DEBUG(dbgs() << " leaveIntvBefore " << Idx); - const LiveRange *CurLR = curli_->getLiveRangeContaining(Idx.getDefIndex()); - if (!CurLR || CurLR->end <= Idx.getBoundaryIndex()) { - DEBUG(dbgs() << " leaveIntvAfter " << Idx << ": not live\n"); - return; + // The interval must be live into the instruction at Idx. + Idx = Idx.getBoundaryIndex(); + VNInfo *ParentVNI = Edit.getParent().getVNInfoAt(Idx); + if (!ParentVNI) { + DEBUG(dbgs() << ": not live\n"); + return Idx.getNextSlot(); } + DEBUG(dbgs() << ": valno " << ParentVNI->id << '\n'); - // Was this value of curli live through openli? - if (!openli_->liveAt(CurLR->valno->def)) { - DEBUG(dbgs() << " leaveIntvAfter " << Idx << ": using external value\n"); - liveThrough_ = true; - return; - } - - // We are going to insert a back copy, so we must have a dupli_. - LiveRange *DupLR = getDupLI()->getLiveRangeContaining(Idx.getDefIndex()); - assert(DupLR && "dupli not live into black, but curli is?"); - - // Insert the COPY instruction. - MachineBasicBlock::iterator I = lis_.getInstructionFromIndex(Idx); - MachineInstr *MI = BuildMI(*I->getParent(), llvm::next(I), I->getDebugLoc(), - tii_.get(TargetOpcode::COPY), dupli_->reg) - .addReg(openli_->reg); - SlotIndex CopyIdx = lis_.InsertMachineInstrInMaps(MI).getDefIndex(); - openli_->addRange(LiveRange(Idx.getDefIndex(), CopyIdx, - mapValue(CurLR->valno))); - DupLR->valno->def = CopyIdx; - DEBUG(dbgs() << " leaveIntvAfter " << Idx << ": " << *openli_ << '\n'); + MachineInstr *MI = LIS.getInstructionFromIndex(Idx); + assert(MI && "No instruction at index"); + VNInfo *VNI = defFromParent(0, ParentVNI, Idx, *MI->getParent(), MI); + return VNI->def; } -/// leaveIntvAtTop - Leave the interval at the top of MBB. -/// Currently, only one value can leave the interval. -void SplitEditor::leaveIntvAtTop(MachineBasicBlock &MBB) { - assert(openli_ && "openIntv not called before leaveIntvAtTop"); - - SlotIndex Start = lis_.getMBBStartIdx(&MBB); - const LiveRange *CurLR = curli_->getLiveRangeContaining(Start); - - // Is curli even live-in to MBB? - if (!CurLR) { - DEBUG(dbgs() << " leaveIntvAtTop at " << Start << ": not live\n"); - return; - } - - // Is curli defined by PHI at the beginning of MBB? - bool isPHIDef = CurLR->valno->isPHIDef() && - CurLR->valno->def.getBaseIndex() == Start; +SlotIndex SplitEditor::leaveIntvAtTop(MachineBasicBlock &MBB) { + assert(OpenIdx && "openIntv not called before leaveIntvAtTop"); + SlotIndex Start = LIS.getMBBStartIdx(&MBB); + DEBUG(dbgs() << " leaveIntvAtTop BB#" << MBB.getNumber() << ", " << Start); - // If MBB is using a value of curli that was defined outside the openli range, - // we don't want to copy it back here. - if (!isPHIDef && !openli_->liveAt(CurLR->valno->def)) { - DEBUG(dbgs() << " leaveIntvAtTop at " << Start - << ": using external value\n"); - liveThrough_ = true; - return; + VNInfo *ParentVNI = Edit.getParent().getVNInfoAt(Start); + if (!ParentVNI) { + DEBUG(dbgs() << ": not live\n"); + return Start; } - // We are going to insert a back copy, so we must have a dupli_. - LiveRange *DupLR = getDupLI()->getLiveRangeContaining(Start); - assert(DupLR && "dupli not live into black, but curli is?"); - - // Insert the COPY instruction. - MachineInstr *MI = BuildMI(MBB, MBB.begin(), DebugLoc(), - tii_.get(TargetOpcode::COPY), dupli_->reg) - .addReg(openli_->reg); - SlotIndex Idx = lis_.InsertMachineInstrInMaps(MI).getDefIndex(); - - // Adjust dupli and openli values. - if (isPHIDef) { - // dupli was already a PHI on entry to MBB. Simply insert an openli PHI, - // and shift the dupli def down to the COPY. - VNInfo *VNI = openli_->getNextValue(SlotIndex(Start, true), 0, false, - lis_.getVNInfoAllocator()); - VNI->setIsPHIDef(true); - openli_->addRange(LiveRange(VNI->def, Idx, VNI)); - - dupli_->removeRange(Start, Idx); - DupLR->valno->def = Idx; - DupLR->valno->setIsPHIDef(false); - } else { - // The dupli value was defined somewhere inside the openli range. - DEBUG(dbgs() << " leaveIntvAtTop source value defined at " - << DupLR->valno->def << "\n"); - // FIXME: We may not need a PHI here if all predecessors have the same - // value. - VNInfo *VNI = openli_->getNextValue(SlotIndex(Start, true), 0, false, - lis_.getVNInfoAllocator()); - VNI->setIsPHIDef(true); - openli_->addRange(LiveRange(VNI->def, Idx, VNI)); - - // FIXME: What if DupLR->valno is used by multiple exits? SSA Update. - - // closeIntv is going to remove the superfluous live ranges. - DupLR->valno->def = Idx; - DupLR->valno->setIsPHIDef(false); - } + VNInfo *VNI = defFromParent(0, ParentVNI, Start, MBB, + MBB.SkipPHIsAndLabels(MBB.begin())); + RegAssign.insert(Start, VNI->def, OpenIdx); + DEBUG(dump()); + return VNI->def; +} - DEBUG(dbgs() << " leaveIntvAtTop at " << Idx << ": " << *openli_ << '\n'); +void SplitEditor::overlapIntv(SlotIndex Start, SlotIndex End) { + assert(OpenIdx && "openIntv not called before overlapIntv"); + assert(Edit.getParent().getVNInfoAt(Start) == + Edit.getParent().getVNInfoAt(End.getPrevSlot()) && + "Parent changes value in extended range"); + assert(Edit.get(0)->getVNInfoAt(Start) && "Start must come from leaveIntv*"); + assert(LIS.getMBBFromIndex(Start) == LIS.getMBBFromIndex(End) && + "Range cannot span basic blocks"); + + // Treat this as useIntv() for now. The complement interval will be extended + // as needed by mapValue(). + DEBUG(dbgs() << " overlapIntv [" << Start << ';' << End << "):"); + RegAssign.insert(Start, End, OpenIdx); + DEBUG(dump()); } /// closeIntv - Indicate that we are done editing the currently open /// LiveInterval, and ranges can be trimmed. void SplitEditor::closeIntv() { - assert(openli_ && "openIntv not called before closeIntv"); - - DEBUG(dbgs() << " closeIntv cleaning up\n"); - DEBUG(dbgs() << " open " << *openli_ << '\n'); - - if (liveThrough_) { - DEBUG(dbgs() << " value live through region, leaving dupli as is.\n"); - } else { - // live out with copies inserted, or killed by region. Either way we need to - // remove the overlapping region from dupli. - getDupLI(); - for (LiveInterval::iterator I = openli_->begin(), E = openli_->end(); - I != E; ++I) { - dupli_->removeRange(I->start, I->end); - } - // FIXME: A block branching to the entry block may also branch elsewhere - // curli is live. We need both openli and curli to be live in that case. - DEBUG(dbgs() << " dup2 " << *dupli_ << '\n'); - } - openli_ = 0; - valueMap_.clear(); + assert(OpenIdx && "openIntv not called before closeIntv"); + OpenIdx = 0; } -/// rewrite - after all the new live ranges have been created, rewrite -/// instructions using curli to use the new intervals. -void SplitEditor::rewrite() { - assert(!openli_ && "Previous LI not closed before rewrite"); - const LiveInterval *curli = sa_.getCurLI(); - for (MachineRegisterInfo::reg_iterator RI = mri_.reg_begin(curli->reg), - RE = mri_.reg_end(); RI != RE;) { +/// rewriteAssigned - Rewrite all uses of Edit.getReg(). +void SplitEditor::rewriteAssigned() { + for (MachineRegisterInfo::reg_iterator RI = MRI.reg_begin(Edit.getReg()), + RE = MRI.reg_end(); RI != RE;) { MachineOperand &MO = RI.getOperand(); MachineInstr *MI = MO.getParent(); ++RI; + // LiveDebugVariables should have handled all DBG_VALUE instructions. if (MI->isDebugValue()) { DEBUG(dbgs() << "Zapping " << *MI); - // FIXME: We can do much better with debug values. MO.setReg(0); continue; } - SlotIndex Idx = lis_.getInstructionIndex(MI); - Idx = MO.isUse() ? Idx.getUseIndex() : Idx.getDefIndex(); - LiveInterval *LI = dupli_; - for (unsigned i = firstInterval, e = intervals_.size(); i != e; ++i) { - LiveInterval *testli = intervals_[i]; - if (testli->liveAt(Idx)) { - LI = testli; - break; - } - } - if (LI) { - MO.setReg(LI->reg); - sa_.removeUse(MI); - DEBUG(dbgs() << " rewrite " << Idx << '\t' << *MI); - } - } - // dupli_ goes in last, after rewriting. - if (dupli_) { - if (dupli_->empty()) { - DEBUG(dbgs() << " dupli became empty?\n"); - lis_.removeInterval(dupli_->reg); - dupli_ = 0; - } else { - dupli_->RenumberValues(lis_); - intervals_.push_back(dupli_); + // operands don't really read the register, so just assign them to + // the complement. + if (MO.isUse() && MO.isUndef()) { + MO.setReg(Edit.get(0)->reg); + continue; } + + SlotIndex Idx = LIS.getInstructionIndex(MI); + Idx = MO.isUse() ? Idx.getUseIndex() : Idx.getDefIndex(); + + // Rewrite to the mapped register at Idx. + unsigned RegIdx = RegAssign.lookup(Idx); + MO.setReg(Edit.get(RegIdx)->reg); + DEBUG(dbgs() << " rewr BB#" << MI->getParent()->getNumber() << '\t' + << Idx << ':' << RegIdx << '\t' << *MI); + + // Extend liveness to Idx. + const VNInfo *ParentVNI = Edit.getParent().getVNInfoAt(Idx); + LIMappers[RegIdx].mapValue(ParentVNI, Idx); } +} - // Calculate spill weight and allocation hints for new intervals. - VirtRegAuxInfo vrai(vrm_.getMachineFunction(), lis_, sa_.loops_); - for (unsigned i = firstInterval, e = intervals_.size(); i != e; ++i) { - LiveInterval &li = *intervals_[i]; - vrai.CalculateRegClass(li.reg); - vrai.CalculateWeightAndHint(li); - DEBUG(dbgs() << " new interval " << mri_.getRegClass(li.reg)->getName() - << ":" << li << '\n'); +/// rewriteSplit - Rewrite uses of Intvs[0] according to the ConEQ mapping. +void SplitEditor::rewriteComponents(const SmallVectorImpl &Intvs, + const ConnectedVNInfoEqClasses &ConEq) { + for (MachineRegisterInfo::reg_iterator RI = MRI.reg_begin(Intvs[0]->reg), + RE = MRI.reg_end(); RI != RE;) { + MachineOperand &MO = RI.getOperand(); + MachineInstr *MI = MO.getParent(); + ++RI; + if (MO.isUse() && MO.isUndef()) + continue; + // DBG_VALUE instructions should have been eliminated earlier. + SlotIndex Idx = LIS.getInstructionIndex(MI); + Idx = MO.isUse() ? Idx.getUseIndex() : Idx.getDefIndex(); + DEBUG(dbgs() << " rewr BB#" << MI->getParent()->getNumber() << '\t' + << Idx << ':'); + const VNInfo *VNI = Intvs[0]->getVNInfoAt(Idx); + assert(VNI && "Interval not live at use."); + MO.setReg(Intvs[ConEq.getEqClass(VNI)]->reg); + DEBUG(dbgs() << VNI->id << '\t' << *MI); } } +void SplitEditor::finish() { + assert(OpenIdx == 0 && "Previous LI not closed before rewrite"); -//===----------------------------------------------------------------------===// -// Loop Splitting -//===----------------------------------------------------------------------===// + // At this point, the live intervals in Edit contain VNInfos corresponding to + // the inserted copies. -bool SplitEditor::splitAroundLoop(const MachineLoop *Loop) { - SplitAnalysis::LoopBlocks Blocks; - sa_.getLoopBlocks(Loop, Blocks); + // Add the original defs from the parent interval. + for (LiveInterval::const_vni_iterator I = Edit.getParent().vni_begin(), + E = Edit.getParent().vni_end(); I != E; ++I) { + const VNInfo *ParentVNI = *I; + if (ParentVNI->isUnused()) + continue; + LiveIntervalMap &LIM = LIMappers[RegAssign.lookup(ParentVNI->def)]; + VNInfo *VNI = LIM.defValue(ParentVNI, ParentVNI->def); + LIM.getLI()->addRange(LiveRange(ParentVNI->def, + ParentVNI->def.getNextSlot(), VNI)); + // Mark all values as complex to force liveness computation. + // This should really only be necessary for remat victims, but we are lazy. + LIM.markComplexMapped(ParentVNI); + } - // Break critical edges as needed. - SplitAnalysis::BlockPtrSet CriticalExits; - sa_.getCriticalExits(Blocks, CriticalExits); - assert(CriticalExits.empty() && "Cannot break critical exits yet"); +#ifndef NDEBUG + // Every new interval must have a def by now, otherwise the split is bogus. + for (LiveRangeEdit::iterator I = Edit.begin(), E = Edit.end(); I != E; ++I) + assert((*I)->hasAtLeastOneValue() && "Split interval has no value"); +#endif + + // FIXME: Don't recompute the liveness of all values, infer it from the + // overlaps between the parent live interval and RegAssign. + // The mapValue algorithm is only necessary when: + // - The parent value maps to multiple defs, and new phis are needed, or + // - The value has been rematerialized before some uses, and we want to + // minimize the live range so it only reaches the remaining uses. + // All other values have simple liveness that can be computed from RegAssign + // and the parent live interval. + + // Extend live ranges to be live-out for successor PHI values. + for (LiveInterval::const_vni_iterator I = Edit.getParent().vni_begin(), + E = Edit.getParent().vni_end(); I != E; ++I) { + const VNInfo *PHIVNI = *I; + if (PHIVNI->isUnused() || !PHIVNI->isPHIDef()) + continue; + unsigned RegIdx = RegAssign.lookup(PHIVNI->def); + LiveIntervalMap &LIM = LIMappers[RegIdx]; + MachineBasicBlock *MBB = LIS.getMBBFromIndex(PHIVNI->def); + DEBUG(dbgs() << " map phi in BB#" << MBB->getNumber() << '@' << PHIVNI->def + << " -> " << RegIdx << '\n'); + for (MachineBasicBlock::pred_iterator PI = MBB->pred_begin(), + PE = MBB->pred_end(); PI != PE; ++PI) { + SlotIndex End = LIS.getMBBEndIdx(*PI).getPrevSlot(); + DEBUG(dbgs() << " pred BB#" << (*PI)->getNumber() << '@' << End); + // The predecessor may not have a live-out value. That is OK, like an + // undef PHI operand. + if (VNInfo *VNI = Edit.getParent().getVNInfoAt(End)) { + DEBUG(dbgs() << " has parent valno #" << VNI->id << " live out\n"); + assert(RegAssign.lookup(End) == RegIdx && + "Different register assignment in phi predecessor"); + LIM.mapValue(VNI, End); + } + else + DEBUG(dbgs() << " is not live-out\n"); + } + DEBUG(dbgs() << " " << *LIM.getLI() << '\n'); + } - // Create new live interval for the loop. - openIntv(); + // Rewrite instructions. + rewriteAssigned(); - // Insert copies in the predecessors. - for (SplitAnalysis::BlockPtrSet::iterator I = Blocks.Preds.begin(), - E = Blocks.Preds.end(); I != E; ++I) { - MachineBasicBlock &MBB = const_cast(**I); - enterIntvAtEnd(MBB, *Loop->getHeader()); - } + // FIXME: Delete defs that were rematted everywhere. - // Switch all loop blocks. - for (SplitAnalysis::BlockPtrSet::iterator I = Blocks.Loop.begin(), - E = Blocks.Loop.end(); I != E; ++I) - useIntv(**I); + // Get rid of unused values and set phi-kill flags. + for (LiveRangeEdit::iterator I = Edit.begin(), E = Edit.end(); I != E; ++I) + (*I)->RenumberValues(LIS); - // Insert back copies in the exit blocks. - for (SplitAnalysis::BlockPtrSet::iterator I = Blocks.Exits.begin(), - E = Blocks.Exits.end(); I != E; ++I) { - MachineBasicBlock &MBB = const_cast(**I); - leaveIntvAtTop(MBB); + // Now check if any registers were separated into multiple components. + ConnectedVNInfoEqClasses ConEQ(LIS); + for (unsigned i = 0, e = Edit.size(); i != e; ++i) { + // Don't use iterators, they are invalidated by create() below. + LiveInterval *li = Edit.get(i); + unsigned NumComp = ConEQ.Classify(li); + if (NumComp <= 1) + continue; + DEBUG(dbgs() << " " << NumComp << " components: " << *li << '\n'); + SmallVector dups; + dups.push_back(li); + for (unsigned i = 1; i != NumComp; ++i) + dups.push_back(&Edit.create(MRI, LIS, VRM)); + rewriteComponents(dups, ConEQ); + ConEQ.Distribute(&dups[0]); } - // Done. - closeIntv(); - rewrite(); - return dupli_; + // Calculate spill weight and allocation hints for new intervals. + VirtRegAuxInfo vrai(VRM.getMachineFunction(), LIS, SA.Loops); + for (LiveRangeEdit::iterator I = Edit.begin(), E = Edit.end(); I != E; ++I){ + LiveInterval &li = **I; + vrai.CalculateRegClass(li.reg); + vrai.CalculateWeightAndHint(li); + DEBUG(dbgs() << " new interval " << MRI.getRegClass(li.reg)->getName() + << ":" << li << '\n'); + } } @@ -979,45 +914,50 @@ bool SplitEditor::splitAroundLoop(const MachineLoop *Loop) { // Single Block Splitting //===----------------------------------------------------------------------===// -/// splitSingleBlocks - Split curli into a separate live interval inside each -/// basic block in Blocks. Return true if curli has been completely replaced, -/// false if curli is still intact, and needs to be spilled or split further. -bool SplitEditor::splitSingleBlocks(const SplitAnalysis::BlockPtrSet &Blocks) { - DEBUG(dbgs() << " splitSingleBlocks for " << Blocks.size() << " blocks.\n"); - // Determine the first and last instruction using curli in each block. - typedef std::pair IndexPair; - typedef DenseMap IndexPairMap; - IndexPairMap MBBRange; - for (SplitAnalysis::InstrPtrSet::const_iterator I = sa_.usingInstrs_.begin(), - E = sa_.usingInstrs_.end(); I != E; ++I) { - const MachineBasicBlock *MBB = (*I)->getParent(); - if (!Blocks.count(MBB)) +/// getMultiUseBlocks - if CurLI has more than one use in a basic block, it +/// may be an advantage to split CurLI for the duration of the block. +bool SplitAnalysis::getMultiUseBlocks(BlockPtrSet &Blocks) { + // If CurLI is local to one block, there is no point to splitting it. + if (LiveBlocks.size() <= 1) + return false; + // Add blocks with multiple uses. + for (unsigned i = 0, e = LiveBlocks.size(); i != e; ++i) { + const BlockInfo &BI = LiveBlocks[i]; + if (!BI.Uses) continue; - SlotIndex Idx = lis_.getInstructionIndex(*I); - DEBUG(dbgs() << " BB#" << MBB->getNumber() << '\t' << Idx << '\t' << **I); - IndexPair &IP = MBBRange[MBB]; - if (!IP.first.isValid() || Idx < IP.first) - IP.first = Idx; - if (!IP.second.isValid() || Idx > IP.second) - IP.second = Idx; + unsigned Instrs = UsingBlocks.lookup(BI.MBB); + if (Instrs <= 1) + continue; + if (Instrs == 2 && BI.LiveIn && BI.LiveOut && !BI.LiveThrough) + continue; + Blocks.insert(BI.MBB); } + return !Blocks.empty(); +} + +/// splitSingleBlocks - Split CurLI into a separate live interval inside each +/// basic block in Blocks. +void SplitEditor::splitSingleBlocks(const SplitAnalysis::BlockPtrSet &Blocks) { + DEBUG(dbgs() << " splitSingleBlocks for " << Blocks.size() << " blocks.\n"); - // Create a new interval for each block. - for (SplitAnalysis::BlockPtrSet::const_iterator I = Blocks.begin(), - E = Blocks.end(); I != E; ++I) { - IndexPair &IP = MBBRange[*I]; - DEBUG(dbgs() << " splitting for BB#" << (*I)->getNumber() << ": [" - << IP.first << ';' << IP.second << ")\n"); - assert(IP.first.isValid() && IP.second.isValid()); + for (unsigned i = 0, e = SA.LiveBlocks.size(); i != e; ++i) { + const SplitAnalysis::BlockInfo &BI = SA.LiveBlocks[i]; + if (!BI.Uses || !Blocks.count(BI.MBB)) + continue; openIntv(); - enterIntvBefore(IP.first); - useIntv(IP.first.getBaseIndex(), IP.second.getBoundaryIndex()); - leaveIntvAfter(IP.second); + SlotIndex SegStart = enterIntvBefore(BI.FirstUse); + if (BI.LastUse < BI.LastSplitPoint) { + useIntv(SegStart, leaveIntvAfter(BI.LastUse)); + } else { + // THe last use os after tha last valid split point. + SlotIndex SegStop = leaveIntvBefore(BI.LastSplitPoint); + useIntv(SegStart, SegStop); + overlapIntv(SegStop, BI.LastUse); + } closeIntv(); } - rewrite(); - return dupli_; + finish(); } @@ -1025,31 +965,29 @@ bool SplitEditor::splitSingleBlocks(const SplitAnalysis::BlockPtrSet &Blocks) { // Sub Block Splitting //===----------------------------------------------------------------------===// -/// getBlockForInsideSplit - If curli is contained inside a single basic block, +/// getBlockForInsideSplit - If CurLI is contained inside a single basic block, /// and it wou pay to subdivide the interval inside that block, return it. /// Otherwise return NULL. The returned block can be passed to /// SplitEditor::splitInsideBlock. const MachineBasicBlock *SplitAnalysis::getBlockForInsideSplit() { // The interval must be exclusive to one block. - if (usingBlocks_.size() != 1) + if (UsingBlocks.size() != 1) return 0; // Don't to this for less than 4 instructions. We want to be sure that // splitting actually reduces the instruction count per interval. - if (usingInstrs_.size() < 4) + if (UsingInstrs.size() < 4) return 0; - return usingBlocks_.begin()->first; + return UsingBlocks.begin()->first; } -/// splitInsideBlock - Split curli into multiple intervals inside MBB. Return -/// true if curli has been completely replaced, false if curli is still -/// intact, and needs to be spilled or split further. -bool SplitEditor::splitInsideBlock(const MachineBasicBlock *MBB) { +/// splitInsideBlock - Split CurLI into multiple intervals inside MBB. +void SplitEditor::splitInsideBlock(const MachineBasicBlock *MBB) { SmallVector Uses; - Uses.reserve(sa_.usingInstrs_.size()); - for (SplitAnalysis::InstrPtrSet::const_iterator I = sa_.usingInstrs_.begin(), - E = sa_.usingInstrs_.end(); I != E; ++I) + Uses.reserve(SA.UsingInstrs.size()); + for (SplitAnalysis::InstrPtrSet::const_iterator I = SA.UsingInstrs.begin(), + E = SA.UsingInstrs.end(); I != E; ++I) if ((*I)->getParent() == MBB) - Uses.push_back(lis_.getInstructionIndex(*I)); + Uses.push_back(LIS.getInstructionIndex(*I)); DEBUG(dbgs() << " splitInsideBlock BB#" << MBB->getNumber() << " for " << Uses.size() << " instructions.\n"); assert(Uses.size() >= 3 && "Need at least 3 instructions"); @@ -1077,21 +1015,16 @@ bool SplitEditor::splitInsideBlock(const MachineBasicBlock *MBB) { // First interval before the gap. Don't create single-instr intervals. if (bestPos > 1) { openIntv(); - enterIntvBefore(Uses.front()); - useIntv(Uses.front().getBaseIndex(), Uses[bestPos-1].getBoundaryIndex()); - leaveIntvAfter(Uses[bestPos-1]); + useIntv(enterIntvBefore(Uses.front()), leaveIntvAfter(Uses[bestPos-1])); closeIntv(); } // Second interval after the gap. if (bestPos < Uses.size()-1) { openIntv(); - enterIntvBefore(Uses[bestPos]); - useIntv(Uses[bestPos].getBaseIndex(), Uses.back().getBoundaryIndex()); - leaveIntvAfter(Uses.back()); + useIntv(enterIntvBefore(Uses[bestPos]), leaveIntvAfter(Uses.back())); closeIntv(); } - rewrite(); - return dupli_; + finish(); } diff --git a/lib/CodeGen/SplitKit.h b/lib/CodeGen/SplitKit.h index ddef7461dc3d..5c34afd1c819 100644 --- a/lib/CodeGen/SplitKit.h +++ b/lib/CodeGen/SplitKit.h @@ -1,4 +1,4 @@ -//===---------- SplitKit.cpp - Toolkit for splitting live ranges ----------===// +//===-------- SplitKit.h - Toolkit for splitting live ranges ----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -12,125 +12,132 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IntervalMap.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/CodeGen/SlotIndexes.h" namespace llvm { +class ConnectedVNInfoEqClasses; class LiveInterval; class LiveIntervals; +class LiveRangeEdit; class MachineInstr; -class MachineLoop; class MachineLoopInfo; class MachineRegisterInfo; class TargetInstrInfo; +class TargetRegisterInfo; class VirtRegMap; class VNInfo; +class raw_ostream; + +/// At some point we should just include MachineDominators.h: +class MachineDominatorTree; +template class DomTreeNodeBase; +typedef DomTreeNodeBase MachineDomTreeNode; + /// SplitAnalysis - Analyze a LiveInterval, looking for live range splitting /// opportunities. class SplitAnalysis { public: - const MachineFunction &mf_; - const LiveIntervals &lis_; - const MachineLoopInfo &loops_; - const TargetInstrInfo &tii_; + const MachineFunction &MF; + const VirtRegMap &VRM; + const LiveIntervals &LIS; + const MachineLoopInfo &Loops; + const TargetInstrInfo &TII; // Instructions using the the current register. typedef SmallPtrSet InstrPtrSet; - InstrPtrSet usingInstrs_; + InstrPtrSet UsingInstrs; + + // Sorted slot indexes of using instructions. + SmallVector UseSlots; - // The number of instructions using curli in each basic block. + // The number of instructions using CurLI in each basic block. typedef DenseMap BlockCountMap; - BlockCountMap usingBlocks_; + BlockCountMap UsingBlocks; + + /// Additional information about basic blocks where the current variable is + /// live. Such a block will look like one of these templates: + /// + /// 1. | o---x | Internal to block. Variable is only live in this block. + /// 2. |---x | Live-in, kill. + /// 3. | o---| Def, live-out. + /// 4. |---x o---| Live-in, kill, def, live-out. + /// 5. |---o---o---| Live-through with uses or defs. + /// 6. |-----------| Live-through without uses. Transparent. + /// + struct BlockInfo { + MachineBasicBlock *MBB; + SlotIndex FirstUse; ///< First instr using current reg. + SlotIndex LastUse; ///< Last instr using current reg. + SlotIndex Kill; ///< Interval end point inside block. + SlotIndex Def; ///< Interval start point inside block. + /// Last possible point for splitting live ranges. + SlotIndex LastSplitPoint; + bool Uses; ///< Current reg has uses or defs in block. + bool LiveThrough; ///< Live in whole block (Templ 5. or 6. above). + bool LiveIn; ///< Current reg is live in. + bool LiveOut; ///< Current reg is live out. + + // Per-interference pattern scratch data. + bool OverlapEntry; ///< Interference overlaps entering interval. + bool OverlapExit; ///< Interference overlaps exiting interval. + }; - // The number of basic block using curli in each loop. - typedef DenseMap LoopCountMap; - LoopCountMap usingLoops_; + /// Basic blocks where var is live. This array is parallel to + /// SpillConstraints. + SmallVector LiveBlocks; private: // Current live interval. - const LiveInterval *curli_; + const LiveInterval *CurLI; - // Sumarize statistics by counting instructions using curli_. + // Sumarize statistics by counting instructions using CurLI. void analyzeUses(); + /// calcLiveBlockInfo - Compute per-block information about CurLI. + void calcLiveBlockInfo(); + /// canAnalyzeBranch - Return true if MBB ends in a branch that can be /// analyzed. bool canAnalyzeBranch(const MachineBasicBlock *MBB); public: - SplitAnalysis(const MachineFunction &mf, const LiveIntervals &lis, + SplitAnalysis(const VirtRegMap &vrm, const LiveIntervals &lis, const MachineLoopInfo &mli); - /// analyze - set curli to the specified interval, and analyze how it may be + /// analyze - set CurLI to the specified interval, and analyze how it may be /// split. void analyze(const LiveInterval *li); - /// removeUse - Update statistics by noting that mi no longer uses curli. - void removeUse(const MachineInstr *mi); - - const LiveInterval *getCurLI() { return curli_; } - /// clear - clear all data structures so SplitAnalysis is ready to analyze a /// new interval. void clear(); - typedef SmallPtrSet BlockPtrSet; - typedef SmallPtrSet LoopPtrSet; - - // Sets of basic blocks surrounding a machine loop. - struct LoopBlocks { - BlockPtrSet Loop; // Blocks in the loop. - BlockPtrSet Preds; // Loop predecessor blocks. - BlockPtrSet Exits; // Loop exit blocks. - - void clear() { - Loop.clear(); - Preds.clear(); - Exits.clear(); - } - }; - - // Calculate the block sets surrounding the loop. - void getLoopBlocks(const MachineLoop *Loop, LoopBlocks &Blocks); - - /// LoopPeripheralUse - how is a variable used in and around a loop? - /// Peripheral blocks are the loop predecessors and exit blocks. - enum LoopPeripheralUse { - ContainedInLoop, // All uses are inside the loop. - SinglePeripheral, // At most one instruction per peripheral block. - MultiPeripheral, // Multiple instructions in some peripheral blocks. - OutsideLoop // Uses outside loop periphery. - }; - - /// analyzeLoopPeripheralUse - Return an enum describing how curli_ is used in - /// and around the Loop. - LoopPeripheralUse analyzeLoopPeripheralUse(const LoopBlocks&); + /// getParent - Return the last analyzed interval. + const LiveInterval &getParent() const { return *CurLI; } - /// getCriticalExits - It may be necessary to partially break critical edges - /// leaving the loop if an exit block has phi uses of curli. Collect the exit - /// blocks that need special treatment into CriticalExits. - void getCriticalExits(const LoopBlocks &Blocks, BlockPtrSet &CriticalExits); + /// hasUses - Return true if MBB has any uses of CurLI. + bool hasUses(const MachineBasicBlock *MBB) const { + return UsingBlocks.lookup(MBB); + } - /// canSplitCriticalExits - Return true if it is possible to insert new exit - /// blocks before the blocks in CriticalExits. - bool canSplitCriticalExits(const LoopBlocks &Blocks, - BlockPtrSet &CriticalExits); + typedef SmallPtrSet BlockPtrSet; - /// getBestSplitLoop - Return the loop where curli may best be split to a - /// separate register, or NULL. - const MachineLoop *getBestSplitLoop(); + // Print a set of blocks with use counts. + void print(const BlockPtrSet&, raw_ostream&) const; /// getMultiUseBlocks - Add basic blocks to Blocks that may benefit from - /// having curli split to a new live interval. Return true if Blocks can be + /// having CurLI split to a new live interval. Return true if Blocks can be /// passed to SplitEditor::splitSingleBlocks. bool getMultiUseBlocks(BlockPtrSet &Blocks); - /// getBlockForInsideSplit - If curli is contained inside a single basic block, - /// and it wou pay to subdivide the interval inside that block, return it. - /// Otherwise return NULL. The returned block can be passed to + /// getBlockForInsideSplit - If CurLI is contained inside a single basic + /// block, and it would pay to subdivide the interval inside that block, + /// return it. Otherwise return NULL. The returned block can be passed to /// SplitEditor::splitInsideBlock. const MachineBasicBlock *getBlockForInsideSplit(); }; @@ -140,58 +147,102 @@ public: /// interval that is a subset. Insert phi-def values as needed. This class is /// used by SplitEditor to create new smaller LiveIntervals. /// -/// parentli_ is the larger interval, li_ is the subset interval. Every value -/// in li_ corresponds to exactly one value in parentli_, and the live range -/// of the value is contained within the live range of the parentli_ value. -/// Values in parentli_ may map to any number of openli_ values, including 0. +/// ParentLI is the larger interval, LI is the subset interval. Every value +/// in LI corresponds to exactly one value in ParentLI, and the live range +/// of the value is contained within the live range of the ParentLI value. +/// Values in ParentLI may map to any number of OpenLI values, including 0. class LiveIntervalMap { - LiveIntervals &lis_; + LiveIntervals &LIS; + MachineDominatorTree &MDT; // The parent interval is never changed. - const LiveInterval &parentli_; + const LiveInterval &ParentLI; - // The child interval's values are fully contained inside parentli_ values. - LiveInterval &li_; + // The child interval's values are fully contained inside ParentLI values. + LiveInterval *LI; typedef DenseMap ValueMap; - // Map parentli_ values to simple values in li_ that are defined at the same - // SlotIndex, or NULL for parentli_ values that have complex li_ defs. + // Map ParentLI values to simple values in LI that are defined at the same + // SlotIndex, or NULL for ParentLI values that have complex LI defs. // Note there is a difference between values mapping to NULL (complex), and // values not present (unknown/unmapped). - ValueMap valueMap_; - - // extendTo - Find the last li_ value defined in MBB at or before Idx. The - // parentli_ is assumed to be live at Idx. Extend the live range to Idx. - // Return the found VNInfo, or NULL. - VNInfo *extendTo(MachineBasicBlock *MBB, SlotIndex Idx); - - // addSimpleRange - Add a simple range from parentli_ to li_. - // ParentVNI must be live in the [Start;End) interval. - void addSimpleRange(SlotIndex Start, SlotIndex End, const VNInfo *ParentVNI); + ValueMap Values; + + typedef std::pair LiveOutPair; + typedef DenseMap LiveOutMap; + + // LiveOutCache - Map each basic block where LI is live out to the live-out + // value and its defining block. One of these conditions shall be true: + // + // 1. !LiveOutCache.count(MBB) + // 2. LiveOutCache[MBB].second.getNode() == MBB + // 3. forall P in preds(MBB): LiveOutCache[P] == LiveOutCache[MBB] + // + // This is only a cache, the values can be computed as: + // + // VNI = LI->getVNInfoAt(LIS.getMBBEndIdx(MBB)) + // Node = mbt_[LIS.getMBBFromIndex(VNI->def)] + // + // The cache is also used as a visiteed set by mapValue(). + LiveOutMap LiveOutCache; + + // Dump the live-out cache to dbgs(). + void dumpCache(); public: LiveIntervalMap(LiveIntervals &lis, - const LiveInterval &parentli, - LiveInterval &li) - : lis_(lis), parentli_(parentli), li_(li) {} + MachineDominatorTree &mdt, + const LiveInterval &parentli) + : LIS(lis), MDT(mdt), ParentLI(parentli), LI(0) {} + + /// reset - clear all data structures and start a new live interval. + void reset(LiveInterval *); + + /// getLI - return the current live interval. + LiveInterval *getLI() const { return LI; } - /// defValue - define a value in li_ from the parentli_ value VNI and Idx. + /// defValue - define a value in LI from the ParentLI value VNI and Idx. /// Idx does not have to be ParentVNI->def, but it must be contained within - /// ParentVNI's live range in parentli_. - /// Return the new li_ value. + /// ParentVNI's live range in ParentLI. + /// Return the new LI value. VNInfo *defValue(const VNInfo *ParentVNI, SlotIndex Idx); - /// mapValue - map ParentVNI to the corresponding li_ value at Idx. It is + /// mapValue - map ParentVNI to the corresponding LI value at Idx. It is /// assumed that ParentVNI is live at Idx. /// If ParentVNI has not been defined by defValue, it is assumed that /// ParentVNI->def dominates Idx. /// If ParentVNI has been defined by defValue one or more times, a value that /// dominates Idx will be returned. This may require creating extra phi-def - /// values and adding live ranges to li_. - VNInfo *mapValue(const VNInfo *ParentVNI, SlotIndex Idx); + /// values and adding live ranges to LI. + /// If simple is not NULL, *simple will indicate if ParentVNI is a simply + /// mapped value. + VNInfo *mapValue(const VNInfo *ParentVNI, SlotIndex Idx, bool *simple = 0); + + // extendTo - Find the last LI value defined in MBB at or before Idx. The + // parentli is assumed to be live at Idx. Extend the live range to include + // Idx. Return the found VNInfo, or NULL. + VNInfo *extendTo(const MachineBasicBlock *MBB, SlotIndex Idx); + + /// isMapped - Return true is ParentVNI is a known mapped value. It may be a + /// simple 1-1 mapping or a complex mapping to later defs. + bool isMapped(const VNInfo *ParentVNI) const { + return Values.count(ParentVNI); + } + + /// isComplexMapped - Return true if ParentVNI has received new definitions + /// with defValue. + bool isComplexMapped(const VNInfo *ParentVNI) const; + + /// markComplexMapped - Mark ParentVNI as complex mapped regardless of the + /// number of definitions. + void markComplexMapped(const VNInfo *ParentVNI) { Values[ParentVNI] = 0; } + + // addSimpleRange - Add a simple range from ParentLI to LI. + // ParentVNI must be live in the [Start;End) interval. + void addSimpleRange(SlotIndex Start, SlotIndex End, const VNInfo *ParentVNI); - /// addRange - Add live ranges to li_ where [Start;End) intersects parentli_. + /// addRange - Add live ranges to LI where [Start;End) intersects ParentLI. /// All needed values whose def is not inside [Start;End) must be defined /// beforehand so mapValue will work. void addRange(SlotIndex Start, SlotIndex End); @@ -207,115 +258,129 @@ public: /// - Mark the ranges where the new interval is used with useIntv* /// - Mark the places where the interval is exited with exitIntv*. /// - Finish the current interval with closeIntv and repeat from 2. -/// - Rewrite instructions with rewrite(). +/// - Rewrite instructions with finish(). /// class SplitEditor { - SplitAnalysis &sa_; - LiveIntervals &lis_; - VirtRegMap &vrm_; - MachineRegisterInfo &mri_; - const TargetInstrInfo &tii_; - - /// curli_ - The immutable interval we are currently splitting. - const LiveInterval *const curli_; - - /// dupli_ - Created as a copy of curli_, ranges are carved out as new - /// intervals get added through openIntv / closeIntv. This is used to avoid - /// editing curli_. - LiveInterval *dupli_; - - /// Currently open LiveInterval. - LiveInterval *openli_; - - /// createInterval - Create a new virtual register and LiveInterval with same - /// register class and spill slot as curli. - LiveInterval *createInterval(); - - /// getDupLI - Ensure dupli is created and return it. - LiveInterval *getDupLI(); - - /// valueMap_ - Map values in cupli to values in openli. These are direct 1-1 - /// mappings, and do not include values created by inserted copies. - DenseMap valueMap_; - - /// mapValue - Return the openIntv value that corresponds to the given curli - /// value. - VNInfo *mapValue(const VNInfo *curliVNI); - - /// A dupli value is live through openIntv. - bool liveThrough_; - - /// All the new intervals created for this split are added to intervals_. - SmallVectorImpl &intervals_; - - /// The index into intervals_ of the first interval we added. There may be - /// others from before we got it. - unsigned firstInterval; - - /// Insert a COPY instruction curli -> li. Allocate a new value from li - /// defined by the COPY - VNInfo *insertCopy(LiveInterval &LI, - MachineBasicBlock &MBB, - MachineBasicBlock::iterator I); + SplitAnalysis &SA; + LiveIntervals &LIS; + VirtRegMap &VRM; + MachineRegisterInfo &MRI; + MachineDominatorTree &MDT; + const TargetInstrInfo &TII; + const TargetRegisterInfo &TRI; + + /// Edit - The current parent register and new intervals created. + LiveRangeEdit &Edit; + + /// Index into Edit of the currently open interval. + /// The index 0 is used for the complement, so the first interval started by + /// openIntv will be 1. + unsigned OpenIdx; + + typedef IntervalMap RegAssignMap; + + /// Allocator for the interval map. This will eventually be shared with + /// SlotIndexes and LiveIntervals. + RegAssignMap::Allocator Allocator; + + /// RegAssign - Map of the assigned register indexes. + /// Edit.get(RegAssign.lookup(Idx)) is the register that should be live at + /// Idx. + RegAssignMap RegAssign; + + /// LIMappers - One LiveIntervalMap or each interval in Edit. + SmallVector LIMappers; + + /// defFromParent - Define Reg from ParentVNI at UseIdx using either + /// rematerialization or a COPY from parent. Return the new value. + VNInfo *defFromParent(unsigned RegIdx, + VNInfo *ParentVNI, + SlotIndex UseIdx, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator I); + + /// rewriteAssigned - Rewrite all uses of Edit.getReg() to assigned registers. + void rewriteAssigned(); + + /// rewriteComponents - Rewrite all uses of Intv[0] according to the eq + /// classes in ConEQ. + /// This must be done when Intvs[0] is styill live at all uses, before calling + /// ConEq.Distribute(). + void rewriteComponents(const SmallVectorImpl &Intvs, + const ConnectedVNInfoEqClasses &ConEq); public: /// Create a new SplitEditor for editing the LiveInterval analyzed by SA. /// Newly created intervals will be appended to newIntervals. SplitEditor(SplitAnalysis &SA, LiveIntervals&, VirtRegMap&, - SmallVectorImpl &newIntervals); + MachineDominatorTree&, LiveRangeEdit&); /// getAnalysis - Get the corresponding analysis. - SplitAnalysis &getAnalysis() { return sa_; } + SplitAnalysis &getAnalysis() { return SA; } /// Create a new virtual register and live interval. void openIntv(); - /// enterIntvBefore - Enter openli before the instruction at Idx. If curli is - /// not live before Idx, a COPY is not inserted. - void enterIntvBefore(SlotIndex Idx); + /// enterIntvBefore - Enter the open interval before the instruction at Idx. + /// If the parent interval is not live before Idx, a COPY is not inserted. + /// Return the beginning of the new live range. + SlotIndex enterIntvBefore(SlotIndex Idx); - /// enterIntvAtEnd - Enter openli at the end of MBB. - /// PhiMBB is a successor inside openli where a PHI value is created. - /// Currently, all entries must share the same PhiMBB. - void enterIntvAtEnd(MachineBasicBlock &MBB, MachineBasicBlock &PhiMBB); + /// enterIntvAtEnd - Enter the open interval at the end of MBB. + /// Use the open interval from he inserted copy to the MBB end. + /// Return the beginning of the new live range. + SlotIndex enterIntvAtEnd(MachineBasicBlock &MBB); - /// useIntv - indicate that all instructions in MBB should use openli. + /// useIntv - indicate that all instructions in MBB should use OpenLI. void useIntv(const MachineBasicBlock &MBB); - /// useIntv - indicate that all instructions in range should use openli. + /// useIntv - indicate that all instructions in range should use OpenLI. void useIntv(SlotIndex Start, SlotIndex End); - /// leaveIntvAfter - Leave openli after the instruction at Idx. - void leaveIntvAfter(SlotIndex Idx); + /// leaveIntvAfter - Leave the open interval after the instruction at Idx. + /// Return the end of the live range. + SlotIndex leaveIntvAfter(SlotIndex Idx); + + /// leaveIntvBefore - Leave the open interval before the instruction at Idx. + /// Return the end of the live range. + SlotIndex leaveIntvBefore(SlotIndex Idx); /// leaveIntvAtTop - Leave the interval at the top of MBB. - /// Currently, only one value can leave the interval. - void leaveIntvAtTop(MachineBasicBlock &MBB); + /// Add liveness from the MBB top to the copy. + /// Return the end of the live range. + SlotIndex leaveIntvAtTop(MachineBasicBlock &MBB); + + /// overlapIntv - Indicate that all instructions in range should use the open + /// interval, but also let the complement interval be live. + /// + /// This doubles the register pressure, but is sometimes required to deal with + /// register uses after the last valid split point. + /// + /// The Start index should be a return value from a leaveIntv* call, and End + /// should be in the same basic block. The parent interval must have the same + /// value across the range. + /// + void overlapIntv(SlotIndex Start, SlotIndex End); /// closeIntv - Indicate that we are done editing the currently open /// LiveInterval, and ranges can be trimmed. void closeIntv(); - /// rewrite - after all the new live ranges have been created, rewrite - /// instructions using curli to use the new intervals. - void rewrite(); + /// finish - after all the new live ranges have been created, compute the + /// remaining live range, and rewrite instructions to use the new registers. + void finish(); - // ===--- High level methods ---=== + /// dump - print the current interval maping to dbgs(). + void dump() const; - /// splitAroundLoop - Split curli into a separate live interval inside - /// the loop. Return true if curli has been completely replaced, false if - /// curli is still intact, and needs to be spilled or split further. - bool splitAroundLoop(const MachineLoop*); + // ===--- High level methods ---=== - /// splitSingleBlocks - Split curli into a separate live interval inside each - /// basic block in Blocks. Return true if curli has been completely replaced, - /// false if curli is still intact, and needs to be spilled or split further. - bool splitSingleBlocks(const SplitAnalysis::BlockPtrSet &Blocks); + /// splitSingleBlocks - Split CurLI into a separate live interval inside each + /// basic block in Blocks. + void splitSingleBlocks(const SplitAnalysis::BlockPtrSet &Blocks); - /// splitInsideBlock - Split curli into multiple intervals inside MBB. Return - /// true if curli has been completely replaced, false if curli is still - /// intact, and needs to be spilled or split further. - bool splitInsideBlock(const MachineBasicBlock *); + /// splitInsideBlock - Split CurLI into multiple intervals inside MBB. + void splitInsideBlock(const MachineBasicBlock *); }; } diff --git a/lib/CodeGen/Splitter.cpp b/lib/CodeGen/Splitter.cpp index 38f3b1f4d35e..08aee82b8c5c 100644 --- a/lib/CodeGen/Splitter.cpp +++ b/lib/CodeGen/Splitter.cpp @@ -29,8 +29,14 @@ using namespace llvm; char LoopSplitter::ID = 0; -INITIALIZE_PASS(LoopSplitter, "loop-splitting", - "Split virtual regists across loop boundaries.", false, false); +INITIALIZE_PASS_BEGIN(LoopSplitter, "loop-splitting", + "Split virtual regists across loop boundaries.", false, false) +INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree) +INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo) +INITIALIZE_PASS_DEPENDENCY(SlotIndexes) +INITIALIZE_PASS_DEPENDENCY(LiveIntervals) +INITIALIZE_PASS_END(LoopSplitter, "loop-splitting", + "Split virtual regists across loop boundaries.", false, false) namespace llvm { @@ -140,7 +146,6 @@ namespace llvm { VNInfo *newVal = getNewVNI(preHeaderRange->valno); newVal->def = copyDefIdx; newVal->setCopy(copy); - newVal->setIsDefAccurate(true); li.removeRange(copyDefIdx, ls.lis->getMBBEndIdx(preHeader), true); getNewLI()->addRange(LiveRange(copyDefIdx, @@ -174,13 +179,13 @@ namespace llvm { // Blow away output range definition. outRange->valno->def = ls.lis->getInvalidIndex(); - outRange->valno->setIsDefAccurate(false); li.removeRange(ls.lis->getMBBStartIdx(outBlock), copyDefIdx); + SlotIndex newDefIdx = ls.lis->getMBBStartIdx(outBlock); + assert(ls.lis->getInstructionFromIndex(newDefIdx) == 0 && + "PHI def index points at actual instruction."); VNInfo *newVal = - getNewLI()->getNextValue(SlotIndex(ls.lis->getMBBStartIdx(outBlock), - true), - 0, false, ls.lis->getVNInfoAllocator()); + getNewLI()->getNextValue(newDefIdx, 0, ls.lis->getVNInfoAllocator()); getNewLI()->addRange(LiveRange(ls.lis->getMBBStartIdx(outBlock), copyDefIdx, newVal)); @@ -514,8 +519,10 @@ namespace llvm { if (!insertRange) continue; - VNInfo *newVal = li.getNextValue(lis->getMBBStartIdx(preHeader), - 0, false, lis->getVNInfoAllocator()); + SlotIndex newDefIdx = lis->getMBBStartIdx(preHeader); + assert(lis->getInstructionFromIndex(newDefIdx) == 0 && + "PHI def index points at actual instruction."); + VNInfo *newVal = li.getNextValue(newDefIdx, 0, lis->getVNInfoAllocator()); li.addRange(LiveRange(lis->getMBBStartIdx(preHeader), lis->getMBBEndIdx(preHeader), newVal)); @@ -612,8 +619,11 @@ namespace llvm { lis->getMBBEndIdx(splitBlock), true); } } else if (intersects) { - VNInfo *newVal = li.getNextValue(lis->getMBBStartIdx(splitBlock), - 0, false, lis->getVNInfoAllocator()); + SlotIndex newDefIdx = lis->getMBBStartIdx(splitBlock); + assert(lis->getInstructionFromIndex(newDefIdx) == 0 && + "PHI def index points at actual instruction."); + VNInfo *newVal = li.getNextValue(newDefIdx, 0, + lis->getVNInfoAllocator()); li.addRange(LiveRange(lis->getMBBStartIdx(splitBlock), lis->getMBBEndIdx(splitBlock), newVal)); diff --git a/lib/CodeGen/Splitter.h b/lib/CodeGen/Splitter.h index a726a7b834fb..9fb1b8b30139 100644 --- a/lib/CodeGen/Splitter.h +++ b/lib/CodeGen/Splitter.h @@ -36,7 +36,9 @@ namespace llvm { public: static char ID; - LoopSplitter() : MachineFunctionPass(ID) {} + LoopSplitter() : MachineFunctionPass(ID) { + initializeLoopSplitterPass(*PassRegistry::getPassRegistry()); + } virtual void getAnalysisUsage(AnalysisUsage &au) const; diff --git a/lib/CodeGen/StackProtector.cpp b/lib/CodeGen/StackProtector.cpp index 9f51778da756..fcaee4208ba3 100644 --- a/lib/CodeGen/StackProtector.cpp +++ b/lib/CodeGen/StackProtector.cpp @@ -16,6 +16,7 @@ #define DEBUG_TYPE "stack-protector" #include "llvm/CodeGen/Passes.h" +#include "llvm/Analysis/Dominators.h" #include "llvm/Attributes.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" @@ -45,6 +46,8 @@ namespace { Function *F; Module *M; + DominatorTree* DT; + /// InsertStackProtectors - Insert code into the prologue and epilogue of /// the function. /// @@ -62,9 +65,17 @@ namespace { bool RequiresStackProtector() const; public: static char ID; // Pass identification, replacement for typeid. - StackProtector() : FunctionPass(ID), TLI(0) {} + StackProtector() : FunctionPass(ID), TLI(0) { + initializeStackProtectorPass(*PassRegistry::getPassRegistry()); + } StackProtector(const TargetLowering *tli) - : FunctionPass(ID), TLI(tli) {} + : FunctionPass(ID), TLI(tli) { + initializeStackProtectorPass(*PassRegistry::getPassRegistry()); + } + + virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addPreserved(); + } virtual bool runOnFunction(Function &Fn); }; @@ -72,7 +83,7 @@ namespace { char StackProtector::ID = 0; INITIALIZE_PASS(StackProtector, "stack-protector", - "Insert stack protectors", false, false); + "Insert stack protectors", false, false) FunctionPass *llvm::createStackProtectorPass(const TargetLowering *tli) { return new StackProtector(tli); @@ -81,6 +92,7 @@ FunctionPass *llvm::createStackProtectorPass(const TargetLowering *tli) { bool StackProtector::runOnFunction(Function &Fn) { F = &Fn; M = F->getParent(); + DT = getAnalysisIfAvailable(); if (!RequiresStackProtector()) return false; @@ -135,6 +147,7 @@ bool StackProtector::RequiresStackProtector() const { /// value. It calls __stack_chk_fail if they differ. bool StackProtector::InsertStackProtectors() { BasicBlock *FailBB = 0; // The basic block to jump to if check fails. + BasicBlock *FailBBDom = 0; // FailBB's dominator. AllocaInst *AI = 0; // Place on stack that stores the stack guard. Value *StackGuardVar = 0; // The stack guard variable. @@ -178,6 +191,8 @@ bool StackProtector::InsertStackProtectors() { // Create the basic block to jump to when the guard check fails. FailBB = CreateFailBB(); + if (DT) + FailBBDom = DT->isReachableFromEntry(BB) ? BB : 0; } // For each block with a return instruction, convert this: @@ -204,6 +219,10 @@ bool StackProtector::InsertStackProtectors() { // Split the basic block before the return instruction. BasicBlock *NewBB = BB->splitBasicBlock(RI, "SP_return"); + if (DT) { + DT->addNewBlock(NewBB, DT->isReachableFromEntry(BB) ? BB : 0); + FailBBDom = DT->findNearestCommonDominator(FailBBDom, BB); + } // Remove default branch instruction to the new BB. BB->getTerminator()->eraseFromParent(); @@ -223,6 +242,9 @@ bool StackProtector::InsertStackProtectors() { // statements in the function. if (!FailBB) return false; + if (DT) + DT->addNewBlock(FailBB, FailBBDom); + return true; } diff --git a/lib/CodeGen/StackSlotColoring.cpp b/lib/CodeGen/StackSlotColoring.cpp index 8d57ae95dde2..01f5b5627f4f 100644 --- a/lib/CodeGen/StackSlotColoring.cpp +++ b/lib/CodeGen/StackSlotColoring.cpp @@ -95,9 +95,13 @@ namespace { public: static char ID; // Pass identification StackSlotColoring() : - MachineFunctionPass(ID), ColorWithRegs(false), NextColor(-1) {} + MachineFunctionPass(ID), ColorWithRegs(false), NextColor(-1) { + initializeStackSlotColoringPass(*PassRegistry::getPassRegistry()); + } StackSlotColoring(bool RegColor) : - MachineFunctionPass(ID), ColorWithRegs(RegColor), NextColor(-1) {} + MachineFunctionPass(ID), ColorWithRegs(RegColor), NextColor(-1) { + initializeStackSlotColoringPass(*PassRegistry::getPassRegistry()); + } virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); @@ -145,8 +149,14 @@ namespace { char StackSlotColoring::ID = 0; -INITIALIZE_PASS(StackSlotColoring, "stack-slot-coloring", - "Stack Slot Coloring", false, false); +INITIALIZE_PASS_BEGIN(StackSlotColoring, "stack-slot-coloring", + "Stack Slot Coloring", false, false) +INITIALIZE_PASS_DEPENDENCY(SlotIndexes) +INITIALIZE_PASS_DEPENDENCY(LiveStacks) +INITIALIZE_PASS_DEPENDENCY(VirtRegMap) +INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo) +INITIALIZE_PASS_END(StackSlotColoring, "stack-slot-coloring", + "Stack Slot Coloring", false, false) FunctionPass *llvm::createStackSlotColoringPass(bool RegColor) { return new StackSlotColoring(RegColor); @@ -208,7 +218,7 @@ void StackSlotColoring::InitializeSlots() { for (LiveStacks::iterator i = LS->begin(), e = LS->end(); i != e; ++i) { LiveInterval &li = i->second; DEBUG(li.dump()); - int FI = li.getStackSlotIndex(); + int FI = TargetRegisterInfo::stackSlot2Index(li.reg); if (MFI->isDeadObjectIndex(FI)) continue; SSIntervals.push_back(&li); @@ -251,7 +261,7 @@ StackSlotColoring::ColorSlotsWithFreeRegs(SmallVector &SlotMapping, DEBUG(dbgs() << "Assigning unused registers to spill slots:\n"); for (unsigned i = 0, e = SSIntervals.size(); i != e; ++i) { LiveInterval *li = SSIntervals[i]; - int SS = li->getStackSlotIndex(); + int SS = TargetRegisterInfo::stackSlot2Index(li->reg); if (!UsedColors[SS] || li->weight < 20) // If the weight is < 20, i.e. two references in a loop with depth 1, // don't bother with it. @@ -340,7 +350,7 @@ int StackSlotColoring::ColorSlot(LiveInterval *li) { // Record the assignment. Assignments[Color].push_back(li); - int FI = li->getStackSlotIndex(); + int FI = TargetRegisterInfo::stackSlot2Index(li->reg); DEBUG(dbgs() << "Assigning fi#" << FI << " to fi#" << Color << "\n"); // Change size and alignment of the allocated slot. If there are multiple @@ -369,7 +379,7 @@ bool StackSlotColoring::ColorSlots(MachineFunction &MF) { bool Changed = false; for (unsigned i = 0, e = SSIntervals.size(); i != e; ++i) { LiveInterval *li = SSIntervals[i]; - int SS = li->getStackSlotIndex(); + int SS = TargetRegisterInfo::stackSlot2Index(li->reg); int NewSS = ColorSlot(li); assert(NewSS >= 0 && "Stack coloring failed?"); SlotMapping[SS] = NewSS; @@ -382,7 +392,7 @@ bool StackSlotColoring::ColorSlots(MachineFunction &MF) { DEBUG(dbgs() << "\nSpill slots after coloring:\n"); for (unsigned i = 0, e = SSIntervals.size(); i != e; ++i) { LiveInterval *li = SSIntervals[i]; - int SS = li->getStackSlotIndex(); + int SS = TargetRegisterInfo::stackSlot2Index(li->reg); li->weight = SlotWeights[SS]; } // Sort them by new weight. @@ -636,7 +646,7 @@ StackSlotColoring::UnfoldAndRewriteInstruction(MachineInstr *MI, int OldFI, } else { SmallVector NewMIs; bool Success = TII->unfoldMemoryOperand(MF, MI, Reg, false, false, NewMIs); - Success = Success; // Silence compiler warning. + (void)Success; // Silence compiler warning. assert(Success && "Failed to unfold!"); MachineInstr *NewMI = NewMIs[0]; MBB->insert(MI, NewMI); diff --git a/lib/CodeGen/StrongPHIElimination.cpp b/lib/CodeGen/StrongPHIElimination.cpp index 894dbfa28bac..ec7829ec39fe 100644 --- a/lib/CodeGen/StrongPHIElimination.cpp +++ b/lib/CodeGen/StrongPHIElimination.cpp @@ -1,4 +1,4 @@ -//===- StrongPhiElimination.cpp - Eliminate PHI nodes by inserting copies -===// +//===- StrongPHIElimination.cpp - Eliminate PHI nodes by inserting copies -===// // // The LLVM Compiler Infrastructure // @@ -7,1039 +7,823 @@ // //===----------------------------------------------------------------------===// // -// This pass eliminates machine instruction PHI nodes by inserting copy -// instructions, using an intelligent copy-folding technique based on -// dominator information. This is technique is derived from: +// This pass eliminates PHI instructions by aggressively coalescing the copies +// that would be inserted by a naive algorithm and only inserting the copies +// that are necessary. The coalescing technique initially assumes that all +// registers appearing in a PHI instruction do not interfere. It then eliminates +// proven interferences, using dominators to only perform a linear number of +// interference tests instead of the quadratic number of interference tests +// that this would naively require. This is a technique derived from: // // Budimlic, et al. Fast copy coalescing and live-range identification. // In Proceedings of the ACM SIGPLAN 2002 Conference on Programming Language // Design and Implementation (Berlin, Germany, June 17 - 19, 2002). // PLDI '02. ACM, New York, NY, 25-32. -// DOI= http://doi.acm.org/10.1145/512529.512534 +// +// The original implementation constructs a data structure they call a dominance +// forest for this purpose. The dominance forest was shown to be unnecessary, +// as it is possible to emulate the creation and traversal of a dominance forest +// by directly using the dominator tree, rather than actually constructing the +// dominance forest. This technique is explained in: +// +// Boissinot, et al. Revisiting Out-of-SSA Translation for Correctness, Code +// Quality and Efficiency, +// In Proceedings of the 7th annual IEEE/ACM International Symposium on Code +// Generation and Optimization (Seattle, Washington, March 22 - 25, 2009). +// CGO '09. IEEE, Washington, DC, 114-125. +// +// Careful implementation allows for all of the dominator forest interference +// checks to be performed at once in a single depth-first traversal of the +// dominator tree, which is what is implemented here. // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "strongphielim" +#include "PHIEliminationUtils.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/LiveIntervalAnalysis.h" #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/CodeGen/MachineLoopInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" -#include "llvm/CodeGen/RegisterCoalescer.h" #include "llvm/Target/TargetInstrInfo.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" using namespace llvm; namespace { - struct StrongPHIElimination : public MachineFunctionPass { + class StrongPHIElimination : public MachineFunctionPass { + public: static char ID; // Pass identification, replacement for typeid - StrongPHIElimination() : MachineFunctionPass(ID) {} - - // Waiting stores, for each MBB, the set of copies that need to - // be inserted into that MBB - DenseMap > Waiting; - - // Stacks holds the renaming stack for each register - std::map > Stacks; - - // Registers in UsedByAnother are PHI nodes that are themselves - // used as operands to another PHI node - std::set UsedByAnother; - - // RenameSets are the is a map from a PHI-defined register - // to the input registers to be coalesced along with the - // predecessor block for those input registers. - std::map > RenameSets; - - // PhiValueNumber holds the ID numbers of the VNs for each phi that we're - // eliminating, indexed by the register defined by that phi. - std::map PhiValueNumber; - - // Store the DFS-in number of each block - DenseMap preorder; - - // Store the DFS-out number of each block - DenseMap maxpreorder; - - bool runOnMachineFunction(MachineFunction &Fn); - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesCFG(); - AU.addRequired(); - AU.addRequired(); - AU.addPreserved(); - AU.addRequired(); - - // TODO: Actually make this true. - AU.addPreserved(); - AU.addPreserved(); - MachineFunctionPass::getAnalysisUsage(AU); - } - - virtual void releaseMemory() { - preorder.clear(); - maxpreorder.clear(); - - Waiting.clear(); - Stacks.clear(); - UsedByAnother.clear(); - RenameSets.clear(); + StrongPHIElimination() : MachineFunctionPass(ID) { + initializeStrongPHIEliminationPass(*PassRegistry::getPassRegistry()); } + virtual void getAnalysisUsage(AnalysisUsage&) const; + bool runOnMachineFunction(MachineFunction&); + private: - - /// DomForestNode - Represents a node in the "dominator forest". This is - /// a forest in which the nodes represent registers and the edges - /// represent a dominance relation in the block defining those registers. - struct DomForestNode { - private: - // Store references to our children - std::vector children; - // The register we represent - unsigned reg; - - // Add another node as our child - void addChild(DomForestNode* DFN) { children.push_back(DFN); } - - public: - typedef std::vector::iterator iterator; - - // Create a DomForestNode by providing the register it represents, and - // the node to be its parent. The virtual root node has register 0 - // and a null parent. - DomForestNode(unsigned r, DomForestNode* parent) : reg(r) { - if (parent) - parent->addChild(this); - } - - ~DomForestNode() { - for (iterator I = begin(), E = end(); I != E; ++I) - delete *I; - } - - /// getReg - Return the regiser that this node represents - inline unsigned getReg() { return reg; } - - // Provide iterator access to our children - inline DomForestNode::iterator begin() { return children.begin(); } - inline DomForestNode::iterator end() { return children.end(); } + /// This struct represents a single node in the union-find data structure + /// representing the variable congruence classes. There is one difference + /// from a normal union-find data structure. We steal two bits from the parent + /// pointer . One of these bits is used to represent whether the register + /// itself has been isolated, and the other is used to represent whether the + /// PHI with that register as its destination has been isolated. + /// + /// Note that this leads to the strange situation where the leader of a + /// congruence class may no longer logically be a member, due to being + /// isolated. + struct Node { + enum Flags { + kRegisterIsolatedFlag = 1, + kPHIIsolatedFlag = 2 + }; + Node(unsigned v) : value(v), rank(0) { parent.setPointer(this); } + + Node *getLeader(); + + PointerIntPair parent; + unsigned value; + unsigned rank; }; - - void computeDFS(MachineFunction& MF); - void processBlock(MachineBasicBlock* MBB); - - std::vector computeDomForest( - std::map& instrs, - MachineRegisterInfo& MRI); - void processPHIUnion(MachineInstr* Inst, - std::map& PHIUnion, - std::vector& DF, - std::vector >& locals); - void ScheduleCopies(MachineBasicBlock* MBB, std::set& pushed); - void InsertCopies(MachineDomTreeNode* MBB, - SmallPtrSet& v); - bool mergeLiveIntervals(unsigned primary, unsigned secondary); - }; -} -char StrongPHIElimination::ID = 0; -INITIALIZE_PASS(StrongPHIElimination, "strong-phi-node-elimination", - "Eliminate PHI nodes for register allocation, intelligently", false, false); + /// Add a register in a new congruence class containing only itself. + void addReg(unsigned); -char &llvm::StrongPHIEliminationID = StrongPHIElimination::ID; + /// Join the congruence classes of two registers. This function is biased + /// towards the left argument, i.e. after + /// + /// addReg(r2); + /// unionRegs(r1, r2); + /// + /// the leader of the unioned congruence class is the same as the leader of + /// r1's congruence class prior to the union. This is actually relied upon + /// in the copy insertion code. + void unionRegs(unsigned, unsigned); -/// computeDFS - Computes the DFS-in and DFS-out numbers of the dominator tree -/// of the given MachineFunction. These numbers are then used in other parts -/// of the PHI elimination process. -void StrongPHIElimination::computeDFS(MachineFunction& MF) { - SmallPtrSet frontier; - SmallPtrSet visited; - - unsigned time = 0; - - MachineDominatorTree& DT = getAnalysis(); - - MachineDomTreeNode* node = DT.getRootNode(); - - std::vector worklist; - worklist.push_back(node); - - while (!worklist.empty()) { - MachineDomTreeNode* currNode = worklist.back(); - - if (!frontier.count(currNode)) { - frontier.insert(currNode); - ++time; - preorder.insert(std::make_pair(currNode->getBlock(), time)); - } - - bool inserted = false; - for (MachineDomTreeNode::iterator I = currNode->begin(), E = currNode->end(); - I != E; ++I) - if (!frontier.count(*I) && !visited.count(*I)) { - worklist.push_back(*I); - inserted = true; - break; - } - - if (!inserted) { - frontier.erase(currNode); - visited.insert(currNode); - maxpreorder.insert(std::make_pair(currNode->getBlock(), time)); - - worklist.pop_back(); + /// Get the color of a register. The color is 0 if the register has been + /// isolated. + unsigned getRegColor(unsigned); + + // Isolate a register. + void isolateReg(unsigned); + + /// Get the color of a PHI. The color of a PHI is 0 if the PHI has been + /// isolated. Otherwise, it is the original color of its destination and + /// all of its operands (before they were isolated, if they were). + unsigned getPHIColor(MachineInstr*); + + /// Isolate a PHI. + void isolatePHI(MachineInstr*); + + /// Traverses a basic block, splitting any interferences found between + /// registers in the same congruence class. It takes two DenseMaps as + /// arguments that it also updates: CurrentDominatingParent, which maps + /// a color to the register in that congruence class whose definition was + /// most recently seen, and ImmediateDominatingParent, which maps a register + /// to the register in the same congruence class that most immediately + /// dominates it. + /// + /// This function assumes that it is being called in a depth-first traversal + /// of the dominator tree. + void SplitInterferencesForBasicBlock( + MachineBasicBlock&, + DenseMap &CurrentDominatingParent, + DenseMap &ImmediateDominatingParent); + + // Lowers a PHI instruction, inserting copies of the source and destination + // registers as necessary. + void InsertCopiesForPHI(MachineInstr*, MachineBasicBlock*); + + // Merges the live interval of Reg into NewReg and renames Reg to NewReg + // everywhere that Reg appears. Requires Reg and NewReg to have non- + // overlapping lifetimes. + void MergeLIsAndRename(unsigned Reg, unsigned NewReg); + + MachineRegisterInfo *MRI; + const TargetInstrInfo *TII; + MachineDominatorTree *DT; + LiveIntervals *LI; + + BumpPtrAllocator Allocator; + + DenseMap RegNodeMap; + + // Maps a basic block to a list of its defs of registers that appear as PHI + // sources. + DenseMap > PHISrcDefs; + + // Maps a color to a pair of a MachineInstr* and a virtual register, which + // is the operand of that PHI corresponding to the current basic block. + DenseMap > CurrentPHIForColor; + + // FIXME: Can these two data structures be combined? Would a std::multimap + // be any better? + + // Stores pairs of predecessor basic blocks and the source registers of + // inserted copy instructions. + typedef DenseSet > SrcCopySet; + SrcCopySet InsertedSrcCopySet; + + // Maps pairs of predecessor basic blocks and colors to their defining copy + // instructions. + typedef DenseMap, MachineInstr*> + SrcCopyMap; + SrcCopyMap InsertedSrcCopyMap; + + // Maps inserted destination copy registers to their defining copy + // instructions. + typedef DenseMap DestCopyMap; + DestCopyMap InsertedDestCopies; + }; + + struct MIIndexCompare { + MIIndexCompare(LiveIntervals *LiveIntervals) : LI(LiveIntervals) { } + + bool operator()(const MachineInstr *LHS, const MachineInstr *RHS) const { + return LI->getInstructionIndex(LHS) < LI->getInstructionIndex(RHS); } - } -} -namespace { + LiveIntervals *LI; + }; +} // namespace -/// PreorderSorter - a helper class that is used to sort registers -/// according to the preorder number of their defining blocks -class PreorderSorter { -private: - DenseMap& preorder; - MachineRegisterInfo& MRI; - -public: - PreorderSorter(DenseMap& p, - MachineRegisterInfo& M) : preorder(p), MRI(M) { } - - bool operator()(unsigned A, unsigned B) { - if (A == B) - return false; - - MachineBasicBlock* ABlock = MRI.getVRegDef(A)->getParent(); - MachineBasicBlock* BBlock = MRI.getVRegDef(B)->getParent(); - - if (preorder[ABlock] < preorder[BBlock]) - return true; - else if (preorder[ABlock] > preorder[BBlock]) - return false; - - return false; - } -}; +STATISTIC(NumPHIsLowered, "Number of PHIs lowered"); +STATISTIC(NumDestCopiesInserted, "Number of destination copies inserted"); +STATISTIC(NumSrcCopiesInserted, "Number of source copies inserted"); +char StrongPHIElimination::ID = 0; +INITIALIZE_PASS_BEGIN(StrongPHIElimination, "strong-phi-node-elimination", + "Eliminate PHI nodes for register allocation, intelligently", false, false) +INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree) +INITIALIZE_PASS_DEPENDENCY(SlotIndexes) +INITIALIZE_PASS_DEPENDENCY(LiveIntervals) +INITIALIZE_PASS_END(StrongPHIElimination, "strong-phi-node-elimination", + "Eliminate PHI nodes for register allocation, intelligently", false, false) + +char &llvm::StrongPHIEliminationID = StrongPHIElimination::ID; + +void StrongPHIElimination::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesCFG(); + AU.addRequired(); + AU.addRequired(); + AU.addPreserved(); + AU.addRequired(); + AU.addPreserved(); + MachineFunctionPass::getAnalysisUsage(AU); } -/// computeDomForest - compute the subforest of the DomTree corresponding -/// to the defining blocks of the registers in question -std::vector -StrongPHIElimination::computeDomForest( - std::map& regs, - MachineRegisterInfo& MRI) { - // Begin by creating a virtual root node, since the actual results - // may well be a forest. Assume this node has maximum DFS-out number. - DomForestNode* VirtualRoot = new DomForestNode(0, 0); - maxpreorder.insert(std::make_pair((MachineBasicBlock*)0, ~0UL)); - - // Populate a worklist with the registers - std::vector worklist; - worklist.reserve(regs.size()); - for (std::map::iterator I = regs.begin(), - E = regs.end(); I != E; ++I) - worklist.push_back(I->first); - - // Sort the registers by the DFS-in number of their defining block - PreorderSorter PS(preorder, MRI); - std::sort(worklist.begin(), worklist.end(), PS); - - // Create a "current parent" stack, and put the virtual root on top of it - DomForestNode* CurrentParent = VirtualRoot; - std::vector stack; - stack.push_back(VirtualRoot); - - // Iterate over all the registers in the previously computed order - for (std::vector::iterator I = worklist.begin(), E = worklist.end(); - I != E; ++I) { - unsigned pre = preorder[MRI.getVRegDef(*I)->getParent()]; - MachineBasicBlock* parentBlock = CurrentParent->getReg() ? - MRI.getVRegDef(CurrentParent->getReg())->getParent() : - 0; - - // If the DFS-in number of the register is greater than the DFS-out number - // of the current parent, repeatedly pop the parent stack until it isn't. - while (pre > maxpreorder[parentBlock]) { - stack.pop_back(); - CurrentParent = stack.back(); - - parentBlock = CurrentParent->getReg() ? - MRI.getVRegDef(CurrentParent->getReg())->getParent() : - 0; +static MachineOperand *findLastUse(MachineBasicBlock *MBB, unsigned Reg) { + // FIXME: This only needs to check from the first terminator, as only the + // first terminator can use a virtual register. + for (MachineBasicBlock::reverse_iterator RI = MBB->rbegin(); ; ++RI) { + assert (RI != MBB->rend()); + MachineInstr *MI = &*RI; + + for (MachineInstr::mop_iterator OI = MI->operands_begin(), + OE = MI->operands_end(); OI != OE; ++OI) { + MachineOperand &MO = *OI; + if (MO.isReg() && MO.isUse() && MO.getReg() == Reg) + return &MO; } - - // Now that we've found the appropriate parent, create a DomForestNode for - // this register and attach it to the forest - DomForestNode* child = new DomForestNode(*I, CurrentParent); - - // Push this new node on the "current parent" stack - stack.push_back(child); - CurrentParent = child; } - - // Return a vector containing the children of the virtual root node - std::vector ret; - ret.insert(ret.end(), VirtualRoot->begin(), VirtualRoot->end()); - return ret; + return NULL; } -/// isLiveIn - helper method that determines, from a regno, if a register -/// is live into a block -static bool isLiveIn(unsigned r, MachineBasicBlock* MBB, - LiveIntervals& LI) { - LiveInterval& I = LI.getOrCreateInterval(r); - SlotIndex idx = LI.getMBBStartIdx(MBB); - return I.liveAt(idx); -} +bool StrongPHIElimination::runOnMachineFunction(MachineFunction &MF) { + MRI = &MF.getRegInfo(); + TII = MF.getTarget().getInstrInfo(); + DT = &getAnalysis(); + LI = &getAnalysis(); -/// isLiveOut - help method that determines, from a regno, if a register is -/// live out of a block. -static bool isLiveOut(unsigned r, MachineBasicBlock* MBB, - LiveIntervals& LI) { - for (MachineBasicBlock::succ_iterator PI = MBB->succ_begin(), - E = MBB->succ_end(); PI != E; ++PI) - if (isLiveIn(r, *PI, LI)) - return true; - - return false; -} + for (MachineFunction::iterator I = MF.begin(), E = MF.end(); + I != E; ++I) { + for (MachineBasicBlock::iterator BBI = I->begin(), BBE = I->end(); + BBI != BBE && BBI->isPHI(); ++BBI) { + unsigned DestReg = BBI->getOperand(0).getReg(); + addReg(DestReg); + PHISrcDefs[I].push_back(BBI); -/// interferes - checks for local interferences by scanning a block. The only -/// trick parameter is 'mode' which tells it the relationship of the two -/// registers. 0 - defined in the same block, 1 - first properly dominates -/// second, 2 - second properly dominates first -static bool interferes(unsigned a, unsigned b, MachineBasicBlock* scan, - LiveIntervals& LV, unsigned mode) { - MachineInstr* def = 0; - MachineInstr* kill = 0; - - // The code is still in SSA form at this point, so there is only one - // definition per VReg. Thus we can safely use MRI->getVRegDef(). - const MachineRegisterInfo* MRI = &scan->getParent()->getRegInfo(); - - bool interference = false; - - // Wallk the block, checking for interferences - for (MachineBasicBlock::iterator MBI = scan->begin(), MBE = scan->end(); - MBI != MBE; ++MBI) { - MachineInstr* curr = MBI; - - // Same defining block... - if (mode == 0) { - if (curr == MRI->getVRegDef(a)) { - // If we find our first definition, save it - if (!def) { - def = curr; - // If there's already an unkilled definition, then - // this is an interference - } else if (!kill) { - interference = true; - break; - // If there's a definition followed by a KillInst, then - // they can't interfere - } else { - interference = false; - break; - } - // Symmetric with the above - } else if (curr == MRI->getVRegDef(b)) { - if (!def) { - def = curr; - } else if (!kill) { - interference = true; - break; - } else { - interference = false; - break; - } - // Store KillInsts if they match up with the definition - } else if (curr->killsRegister(a)) { - if (def == MRI->getVRegDef(a)) { - kill = curr; - } else if (curr->killsRegister(b)) { - if (def == MRI->getVRegDef(b)) { - kill = curr; - } - } - } - // First properly dominates second... - } else if (mode == 1) { - if (curr == MRI->getVRegDef(b)) { - // Definition of second without kill of first is an interference - if (!kill) { - interference = true; - break; - // Definition after a kill is a non-interference - } else { - interference = false; - break; - } - // Save KillInsts of First - } else if (curr->killsRegister(a)) { - kill = curr; - } - // Symmetric with the above - } else if (mode == 2) { - if (curr == MRI->getVRegDef(a)) { - if (!kill) { - interference = true; - break; - } else { - interference = false; - break; - } - } else if (curr->killsRegister(b)) { - kill = curr; + for (unsigned i = 1; i < BBI->getNumOperands(); i += 2) { + MachineOperand &SrcMO = BBI->getOperand(i); + unsigned SrcReg = SrcMO.getReg(); + addReg(SrcReg); + unionRegs(DestReg, SrcReg); + + MachineInstr *DefMI = MRI->getVRegDef(SrcReg); + if (DefMI) + PHISrcDefs[DefMI->getParent()].push_back(DefMI); } } } - - return interference; -} -/// processBlock - Determine how to break up PHIs in the current block. Each -/// PHI is broken up by some combination of renaming its operands and inserting -/// copies. This method is responsible for determining which operands receive -/// which treatment. -void StrongPHIElimination::processBlock(MachineBasicBlock* MBB) { - LiveIntervals& LI = getAnalysis(); - MachineRegisterInfo& MRI = MBB->getParent()->getRegInfo(); - - // Holds names that have been added to a set in any PHI within this block - // before the current one. - std::set ProcessedNames; - - // Iterate over all the PHI nodes in this block - MachineBasicBlock::iterator P = MBB->begin(); - while (P != MBB->end() && P->isPHI()) { - unsigned DestReg = P->getOperand(0).getReg(); - - // Don't both doing PHI elimination for dead PHI's. - if (P->registerDefIsDead(DestReg)) { - ++P; - continue; - } + // Perform a depth-first traversal of the dominator tree, splitting + // interferences amongst PHI-congruence classes. + DenseMap CurrentDominatingParent; + DenseMap ImmediateDominatingParent; + for (df_iterator DI = df_begin(DT->getRootNode()), + DE = df_end(DT->getRootNode()); DI != DE; ++DI) { + SplitInterferencesForBasicBlock(*DI->getBlock(), + CurrentDominatingParent, + ImmediateDominatingParent); + } - LiveInterval& PI = LI.getOrCreateInterval(DestReg); - SlotIndex pIdx = LI.getInstructionIndex(P).getDefIndex(); - VNInfo* PVN = PI.getLiveRangeContaining(pIdx)->valno; - PhiValueNumber.insert(std::make_pair(DestReg, PVN->id)); - - // PHIUnion is the set of incoming registers to the PHI node that - // are going to be renames rather than having copies inserted. This set - // is refinded over the course of this function. UnionedBlocks is the set - // of corresponding MBBs. - std::map PHIUnion; - SmallPtrSet UnionedBlocks; - - // Iterate over the operands of the PHI node - for (int i = P->getNumOperands() - 1; i >= 2; i-=2) { - unsigned SrcReg = P->getOperand(i-1).getReg(); - - // Don't need to try to coalesce a register with itself. - if (SrcReg == DestReg) { - ProcessedNames.insert(SrcReg); - continue; - } - - // We don't need to insert copies for implicit_defs. - MachineInstr* DefMI = MRI.getVRegDef(SrcReg); - if (DefMI->isImplicitDef()) - ProcessedNames.insert(SrcReg); - - // Check for trivial interferences via liveness information, allowing us - // to avoid extra work later. Any registers that interfere cannot both - // be in the renaming set, so choose one and add copies for it instead. - // The conditions are: - // 1) if the operand is live into the PHI node's block OR - // 2) if the PHI node is live out of the operand's defining block OR - // 3) if the operand is itself a PHI node and the original PHI is - // live into the operand's defining block OR - // 4) if the operand is already being renamed for another PHI node - // in this block OR - // 5) if any two operands are defined in the same block, insert copies - // for one of them - if (isLiveIn(SrcReg, P->getParent(), LI) || - isLiveOut(P->getOperand(0).getReg(), - MRI.getVRegDef(SrcReg)->getParent(), LI) || - ( MRI.getVRegDef(SrcReg)->isPHI() && - isLiveIn(P->getOperand(0).getReg(), - MRI.getVRegDef(SrcReg)->getParent(), LI) ) || - ProcessedNames.count(SrcReg) || - UnionedBlocks.count(MRI.getVRegDef(SrcReg)->getParent())) { - - // Add a copy for the selected register - MachineBasicBlock* From = P->getOperand(i).getMBB(); - Waiting[From].insert(std::make_pair(SrcReg, DestReg)); - UsedByAnother.insert(SrcReg); - } else { - // Otherwise, add it to the renaming set - PHIUnion.insert(std::make_pair(SrcReg,P->getOperand(i).getMBB())); - UnionedBlocks.insert(MRI.getVRegDef(SrcReg)->getParent()); - } + // Insert copies for all PHI source and destination registers. + for (MachineFunction::iterator I = MF.begin(), E = MF.end(); + I != E; ++I) { + for (MachineBasicBlock::iterator BBI = I->begin(), BBE = I->end(); + BBI != BBE && BBI->isPHI(); ++BBI) { + InsertCopiesForPHI(BBI, I); } - - // Compute the dominator forest for the renaming set. This is a forest - // where the nodes are the registers and the edges represent dominance - // relations between the defining blocks of the registers - std::vector DF = - computeDomForest(PHIUnion, MRI); - - // Walk DomForest to resolve interferences at an inter-block level. This - // will remove registers from the renaming set (and insert copies for them) - // if interferences are found. - std::vector > localInterferences; - processPHIUnion(P, PHIUnion, DF, localInterferences); - - // If one of the inputs is defined in the same block as the current PHI - // then we need to check for a local interference between that input and - // the PHI. - for (std::map::iterator I = PHIUnion.begin(), - E = PHIUnion.end(); I != E; ++I) - if (MRI.getVRegDef(I->first)->getParent() == P->getParent()) - localInterferences.push_back(std::make_pair(I->first, - P->getOperand(0).getReg())); - - // The dominator forest walk may have returned some register pairs whose - // interference cannot be determined from dominator analysis. We now - // examine these pairs for local interferences. - for (std::vector >::iterator I = - localInterferences.begin(), E = localInterferences.end(); I != E; ++I) { - std::pair p = *I; - - MachineDominatorTree& MDT = getAnalysis(); - - // Determine the block we need to scan and the relationship between - // the two registers - MachineBasicBlock* scan = 0; - unsigned mode = 0; - if (MRI.getVRegDef(p.first)->getParent() == - MRI.getVRegDef(p.second)->getParent()) { - scan = MRI.getVRegDef(p.first)->getParent(); - mode = 0; // Same block - } else if (MDT.dominates(MRI.getVRegDef(p.first)->getParent(), - MRI.getVRegDef(p.second)->getParent())) { - scan = MRI.getVRegDef(p.second)->getParent(); - mode = 1; // First dominates second - } else { - scan = MRI.getVRegDef(p.first)->getParent(); - mode = 2; // Second dominates first - } - - // If there's an interference, we need to insert copies - if (interferes(p.first, p.second, scan, LI, mode)) { - // Insert copies for First - for (int i = P->getNumOperands() - 1; i >= 2; i-=2) { - if (P->getOperand(i-1).getReg() == p.first) { - unsigned SrcReg = p.first; - MachineBasicBlock* From = P->getOperand(i).getMBB(); - - Waiting[From].insert(std::make_pair(SrcReg, - P->getOperand(0).getReg())); - UsedByAnother.insert(SrcReg); - - PHIUnion.erase(SrcReg); - } - } + } + + // FIXME: Preserve the equivalence classes during copy insertion and use + // the preversed equivalence classes instead of recomputing them. + RegNodeMap.clear(); + for (MachineFunction::iterator I = MF.begin(), E = MF.end(); + I != E; ++I) { + for (MachineBasicBlock::iterator BBI = I->begin(), BBE = I->end(); + BBI != BBE && BBI->isPHI(); ++BBI) { + unsigned DestReg = BBI->getOperand(0).getReg(); + addReg(DestReg); + + for (unsigned i = 1; i < BBI->getNumOperands(); i += 2) { + unsigned SrcReg = BBI->getOperand(i).getReg(); + addReg(SrcReg); + unionRegs(DestReg, SrcReg); } } - - // Add the renaming set for this PHI node to our overall renaming information - for (std::map::iterator QI = PHIUnion.begin(), - QE = PHIUnion.end(); QI != QE; ++QI) { - DEBUG(dbgs() << "Adding Renaming: " << QI->first << " -> " - << P->getOperand(0).getReg() << "\n"); - } - - RenameSets.insert(std::make_pair(P->getOperand(0).getReg(), PHIUnion)); - - // Remember which registers are already renamed, so that we don't try to - // rename them for another PHI node in this block - for (std::map::iterator I = PHIUnion.begin(), - E = PHIUnion.end(); I != E; ++I) - ProcessedNames.insert(I->first); - - ++P; } -} -/// processPHIUnion - Take a set of candidate registers to be coalesced when -/// decomposing the PHI instruction. Use the DominanceForest to remove the ones -/// that are known to interfere, and flag others that need to be checked for -/// local interferences. -void StrongPHIElimination::processPHIUnion(MachineInstr* Inst, - std::map& PHIUnion, - std::vector& DF, - std::vector >& locals) { - - std::vector worklist(DF.begin(), DF.end()); - SmallPtrSet visited; - - // Code is still in SSA form, so we can use MRI::getVRegDef() - MachineRegisterInfo& MRI = Inst->getParent()->getParent()->getRegInfo(); - - LiveIntervals& LI = getAnalysis(); - unsigned DestReg = Inst->getOperand(0).getReg(); - - // DF walk on the DomForest - while (!worklist.empty()) { - DomForestNode* DFNode = worklist.back(); - - visited.insert(DFNode); - - bool inserted = false; - for (DomForestNode::iterator CI = DFNode->begin(), CE = DFNode->end(); - CI != CE; ++CI) { - DomForestNode* child = *CI; - - // If the current node is live-out of the defining block of one of its - // children, insert a copy for it. NOTE: The paper actually calls for - // a more elaborate heuristic for determining whether to insert copies - // for the child or the parent. In the interest of simplicity, we're - // just always choosing the parent. - if (isLiveOut(DFNode->getReg(), - MRI.getVRegDef(child->getReg())->getParent(), LI)) { - // Insert copies for parent - for (int i = Inst->getNumOperands() - 1; i >= 2; i-=2) { - if (Inst->getOperand(i-1).getReg() == DFNode->getReg()) { - unsigned SrcReg = DFNode->getReg(); - MachineBasicBlock* From = Inst->getOperand(i).getMBB(); - - Waiting[From].insert(std::make_pair(SrcReg, DestReg)); - UsedByAnother.insert(SrcReg); - - PHIUnion.erase(SrcReg); - } - } - - // If a node is live-in to the defining block of one of its children, but - // not live-out, then we need to scan that block for local interferences. - } else if (isLiveIn(DFNode->getReg(), - MRI.getVRegDef(child->getReg())->getParent(), LI) || - MRI.getVRegDef(DFNode->getReg())->getParent() == - MRI.getVRegDef(child->getReg())->getParent()) { - // Add (p, c) to possible local interferences - locals.push_back(std::make_pair(DFNode->getReg(), child->getReg())); + DenseMap RegRenamingMap; + bool Changed = false; + for (MachineFunction::iterator I = MF.begin(), E = MF.end(); + I != E; ++I) { + MachineBasicBlock::iterator BBI = I->begin(), BBE = I->end(); + while (BBI != BBE && BBI->isPHI()) { + MachineInstr *PHI = BBI; + + assert(PHI->getNumOperands() > 0); + + unsigned SrcReg = PHI->getOperand(1).getReg(); + unsigned SrcColor = getRegColor(SrcReg); + unsigned NewReg = RegRenamingMap[SrcColor]; + if (!NewReg) { + NewReg = SrcReg; + RegRenamingMap[SrcColor] = SrcReg; } - - if (!visited.count(child)) { - worklist.push_back(child); - inserted = true; + MergeLIsAndRename(SrcReg, NewReg); + + unsigned DestReg = PHI->getOperand(0).getReg(); + if (!InsertedDestCopies.count(DestReg)) + MergeLIsAndRename(DestReg, NewReg); + + for (unsigned i = 3; i < PHI->getNumOperands(); i += 2) { + unsigned SrcReg = PHI->getOperand(i).getReg(); + MergeLIsAndRename(SrcReg, NewReg); } + + ++BBI; + LI->RemoveMachineInstrFromMaps(PHI); + PHI->eraseFromParent(); + Changed = true; } - - if (!inserted) worklist.pop_back(); } -} -/// ScheduleCopies - Insert copies into predecessor blocks, scheduling -/// them properly so as to avoid the 'lost copy' and the 'virtual swap' -/// problems. -/// -/// Based on "Practical Improvements to the Construction and Destruction -/// of Static Single Assignment Form" by Briggs, et al. -void StrongPHIElimination::ScheduleCopies(MachineBasicBlock* MBB, - std::set& pushed) { - // FIXME: This function needs to update LiveIntervals - std::multimap& copy_set= Waiting[MBB]; - - std::multimap worklist; - std::map map; - - // Setup worklist of initial copies - for (std::multimap::iterator I = copy_set.begin(), - E = copy_set.end(); I != E; ) { - map.insert(std::make_pair(I->first, I->first)); - map.insert(std::make_pair(I->second, I->second)); - - if (!UsedByAnother.count(I->second)) { - worklist.insert(*I); - - // Avoid iterator invalidation - std::multimap::iterator OI = I; - ++I; - copy_set.erase(OI); - } else { - ++I; + // Due to the insertion of copies to split live ranges, the live intervals are + // guaranteed to not overlap, except in one case: an original PHI source and a + // PHI destination copy. In this case, they have the same value and thus don't + // truly intersect, so we merge them into the value live at that point. + // FIXME: Is there some better way we can handle this? + for (DestCopyMap::iterator I = InsertedDestCopies.begin(), + E = InsertedDestCopies.end(); I != E; ++I) { + unsigned DestReg = I->first; + unsigned DestColor = getRegColor(DestReg); + unsigned NewReg = RegRenamingMap[DestColor]; + + LiveInterval &DestLI = LI->getInterval(DestReg); + LiveInterval &NewLI = LI->getInterval(NewReg); + + assert(DestLI.ranges.size() == 1 + && "PHI destination copy's live interval should be a single live " + "range from the beginning of the BB to the copy instruction."); + LiveRange *DestLR = DestLI.begin(); + VNInfo *NewVNI = NewLI.getVNInfoAt(DestLR->start); + if (!NewVNI) { + NewVNI = NewLI.createValueCopy(DestLR->valno, LI->getVNInfoAllocator()); + MachineInstr *CopyInstr = I->second; + CopyInstr->getOperand(1).setIsKill(true); } + + LiveRange NewLR(DestLR->start, DestLR->end, NewVNI); + NewLI.addRange(NewLR); + + LI->removeInterval(DestReg); + MRI->replaceRegWith(DestReg, NewReg); } - - LiveIntervals& LI = getAnalysis(); - MachineFunction* MF = MBB->getParent(); - MachineRegisterInfo& MRI = MF->getRegInfo(); - const TargetInstrInfo *TII = MF->getTarget().getInstrInfo(); - - SmallVector, 4> InsertedPHIDests; - - // Iterate over the worklist, inserting copies - while (!worklist.empty() || !copy_set.empty()) { - while (!worklist.empty()) { - std::multimap::iterator WI = worklist.begin(); - std::pair curr = *WI; - worklist.erase(WI); - - const TargetRegisterClass *RC = MF->getRegInfo().getRegClass(curr.first); - - if (isLiveOut(curr.second, MBB, LI)) { - // Create a temporary - unsigned t = MF->getRegInfo().createVirtualRegister(RC); - - // Insert copy from curr.second to a temporary at - // the Phi defining curr.second - MachineBasicBlock::iterator PI = MRI.getVRegDef(curr.second); - BuildMI(*PI->getParent(), PI, DebugLoc(), TII->get(TargetOpcode::COPY), - t).addReg(curr.second); - DEBUG(dbgs() << "Inserted copy from " << curr.second << " to " << t - << "\n"); - - // Push temporary on Stacks - Stacks[curr.second].push_back(t); - - // Insert curr.second in pushed - pushed.insert(curr.second); - - // Create a live interval for this temporary - InsertedPHIDests.push_back(std::make_pair(t, --PI)); - } - - // Insert copy from map[curr.first] to curr.second - BuildMI(*MBB, MBB->getFirstTerminator(), DebugLoc(), - TII->get(TargetOpcode::COPY), curr.second).addReg(map[curr.first]); - map[curr.first] = curr.second; - DEBUG(dbgs() << "Inserted copy from " << curr.first << " to " - << curr.second << "\n"); - - // Push this copy onto InsertedPHICopies so we can - // update LiveIntervals with it. - MachineBasicBlock::iterator MI = MBB->getFirstTerminator(); - InsertedPHIDests.push_back(std::make_pair(curr.second, --MI)); - - // If curr.first is a destination in copy_set... - for (std::multimap::iterator I = copy_set.begin(), - E = copy_set.end(); I != E; ) - if (curr.first == I->second) { - std::pair temp = *I; - worklist.insert(temp); - - // Avoid iterator invalidation - std::multimap::iterator OI = I; - ++I; - copy_set.erase(OI); - - break; - } else { - ++I; - } - } - - if (!copy_set.empty()) { - std::multimap::iterator CI = copy_set.begin(); - std::pair curr = *CI; - worklist.insert(curr); - copy_set.erase(CI); - - LiveInterval& I = LI.getInterval(curr.second); - MachineBasicBlock::iterator term = MBB->getFirstTerminator(); - SlotIndex endIdx = SlotIndex(); - if (term != MBB->end()) - endIdx = LI.getInstructionIndex(term); - else - endIdx = LI.getMBBEndIdx(MBB); - - if (I.liveAt(endIdx)) { - const TargetRegisterClass *RC = - MF->getRegInfo().getRegClass(curr.first); - - // Insert a copy from dest to a new temporary t at the end of b - unsigned t = MF->getRegInfo().createVirtualRegister(RC); - BuildMI(*MBB, MBB->getFirstTerminator(), DebugLoc(), - TII->get(TargetOpcode::COPY), t).addReg(curr.second); - map[curr.second] = t; - - MachineBasicBlock::iterator TI = MBB->getFirstTerminator(); - InsertedPHIDests.push_back(std::make_pair(t, --TI)); + + // Adjust the live intervals of all PHI source registers to handle the case + // where the PHIs in successor blocks were the only later uses of the source + // register. + for (SrcCopySet::iterator I = InsertedSrcCopySet.begin(), + E = InsertedSrcCopySet.end(); I != E; ++I) { + MachineBasicBlock *MBB = I->first; + unsigned SrcReg = I->second; + if (unsigned RenamedRegister = RegRenamingMap[getRegColor(SrcReg)]) + SrcReg = RenamedRegister; + + LiveInterval &SrcLI = LI->getInterval(SrcReg); + + bool isLiveOut = false; + for (MachineBasicBlock::succ_iterator SI = MBB->succ_begin(), + SE = MBB->succ_end(); SI != SE; ++SI) { + if (SrcLI.liveAt(LI->getMBBStartIdx(*SI))) { + isLiveOut = true; + break; } } + + if (isLiveOut) + continue; + + MachineOperand *LastUse = findLastUse(MBB, SrcReg); + assert(LastUse); + SlotIndex LastUseIndex = LI->getInstructionIndex(LastUse->getParent()); + SrcLI.removeRange(LastUseIndex.getDefIndex(), LI->getMBBEndIdx(MBB)); + LastUse->setIsKill(true); } - - // Renumber the instructions so that we can perform the index computations - // needed to create new live intervals. - LI.renumber(); - - // For copies that we inserted at the ends of predecessors, we construct - // live intervals. This is pretty easy, since we know that the destination - // register cannot have be in live at that point previously. We just have - // to make sure that, for registers that serve as inputs to more than one - // PHI, we don't create multiple overlapping live intervals. - std::set RegHandled; - for (SmallVector, 4>::iterator I = - InsertedPHIDests.begin(), E = InsertedPHIDests.end(); I != E; ++I) { - if (RegHandled.insert(I->first).second) { - LiveInterval& Int = LI.getOrCreateInterval(I->first); - SlotIndex instrIdx = LI.getInstructionIndex(I->second); - if (Int.liveAt(instrIdx.getDefIndex())) - Int.removeRange(instrIdx.getDefIndex(), - LI.getMBBEndIdx(I->second->getParent()).getNextSlot(), - true); - - LiveRange R = LI.addLiveRangeToEndOfBlock(I->first, I->second); - R.valno->setCopy(I->second); - R.valno->def = LI.getInstructionIndex(I->second).getDefIndex(); - } + + LI->renumber(); + + Allocator.Reset(); + RegNodeMap.clear(); + PHISrcDefs.clear(); + InsertedSrcCopySet.clear(); + InsertedSrcCopyMap.clear(); + InsertedDestCopies.clear(); + + return Changed; +} + +void StrongPHIElimination::addReg(unsigned Reg) { + if (RegNodeMap.count(Reg)) + return; + RegNodeMap[Reg] = new (Allocator) Node(Reg); +} + +StrongPHIElimination::Node* +StrongPHIElimination::Node::getLeader() { + Node *N = this; + Node *Parent = parent.getPointer(); + Node *Grandparent = Parent->parent.getPointer(); + + while (Parent != Grandparent) { + N->parent.setPointer(Grandparent); + N = Grandparent; + Parent = Parent->parent.getPointer(); + Grandparent = Parent->parent.getPointer(); } + + return Parent; } -/// InsertCopies - insert copies into MBB and all of its successors -void StrongPHIElimination::InsertCopies(MachineDomTreeNode* MDTN, - SmallPtrSet& visited) { - MachineBasicBlock* MBB = MDTN->getBlock(); - visited.insert(MBB); - - std::set pushed; - - LiveIntervals& LI = getAnalysis(); - // Rewrite register uses from Stacks - for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); - I != E; ++I) { - if (I->isPHI()) - continue; - - for (unsigned i = 0; i < I->getNumOperands(); ++i) - if (I->getOperand(i).isReg() && - Stacks[I->getOperand(i).getReg()].size()) { - // Remove the live range for the old vreg. - LiveInterval& OldInt = LI.getInterval(I->getOperand(i).getReg()); - LiveInterval::iterator OldLR = - OldInt.FindLiveRangeContaining(LI.getInstructionIndex(I).getUseIndex()); - if (OldLR != OldInt.end()) - OldInt.removeRange(*OldLR, true); - - // Change the register - I->getOperand(i).setReg(Stacks[I->getOperand(i).getReg()].back()); - - // Add a live range for the new vreg - LiveInterval& Int = LI.getInterval(I->getOperand(i).getReg()); - VNInfo* FirstVN = *Int.vni_begin(); - FirstVN->setHasPHIKill(false); - LiveRange LR (LI.getMBBStartIdx(I->getParent()), - LI.getInstructionIndex(I).getUseIndex().getNextSlot(), - FirstVN); - - Int.addRange(LR); - } - } - - // Schedule the copies for this block - ScheduleCopies(MBB, pushed); - - // Recur down the dominator tree. - for (MachineDomTreeNode::iterator I = MDTN->begin(), - E = MDTN->end(); I != E; ++I) - if (!visited.count((*I)->getBlock())) - InsertCopies(*I, visited); - - // As we exit this block, pop the names we pushed while processing it - for (std::set::iterator I = pushed.begin(), - E = pushed.end(); I != E; ++I) - Stacks[*I].pop_back(); +unsigned StrongPHIElimination::getRegColor(unsigned Reg) { + DenseMap::iterator RI = RegNodeMap.find(Reg); + if (RI == RegNodeMap.end()) + return 0; + Node *Node = RI->second; + if (Node->parent.getInt() & Node::kRegisterIsolatedFlag) + return 0; + return Node->getLeader()->value; } -bool StrongPHIElimination::mergeLiveIntervals(unsigned primary, - unsigned secondary) { - - LiveIntervals& LI = getAnalysis(); - LiveInterval& LHS = LI.getOrCreateInterval(primary); - LiveInterval& RHS = LI.getOrCreateInterval(secondary); - - LI.renumber(); - - DenseMap VNMap; - for (LiveInterval::iterator I = RHS.begin(), E = RHS.end(); I != E; ++I) { - LiveRange R = *I; - - SlotIndex Start = R.start; - SlotIndex End = R.end; - if (LHS.getLiveRangeContaining(Start)) - return false; - - if (LHS.getLiveRangeContaining(End)) - return false; - - LiveInterval::iterator RI = std::upper_bound(LHS.begin(), LHS.end(), R); - if (RI != LHS.end() && RI->start < End) - return false; +void StrongPHIElimination::unionRegs(unsigned Reg1, unsigned Reg2) { + Node *Node1 = RegNodeMap[Reg1]->getLeader(); + Node *Node2 = RegNodeMap[Reg2]->getLeader(); + + if (Node1->rank > Node2->rank) { + Node2->parent.setPointer(Node1->getLeader()); + } else if (Node1->rank < Node2->rank) { + Node1->parent.setPointer(Node2->getLeader()); + } else if (Node1 != Node2) { + Node2->parent.setPointer(Node1->getLeader()); + Node1->rank++; } - - for (LiveInterval::iterator I = RHS.begin(), E = RHS.end(); I != E; ++I) { - LiveRange R = *I; - VNInfo* OldVN = R.valno; - VNInfo*& NewVN = VNMap[OldVN]; - if (!NewVN) { - NewVN = LHS.createValueCopy(OldVN, LI.getVNInfoAllocator()); - } - - LiveRange LR (R.start, R.end, NewVN); - LHS.addRange(LR); +} + +void StrongPHIElimination::isolateReg(unsigned Reg) { + Node *Node = RegNodeMap[Reg]; + Node->parent.setInt(Node->parent.getInt() | Node::kRegisterIsolatedFlag); +} + +unsigned StrongPHIElimination::getPHIColor(MachineInstr *PHI) { + assert(PHI->isPHI()); + + unsigned DestReg = PHI->getOperand(0).getReg(); + Node *DestNode = RegNodeMap[DestReg]; + if (DestNode->parent.getInt() & Node::kPHIIsolatedFlag) + return 0; + + for (unsigned i = 1; i < PHI->getNumOperands(); i += 2) { + unsigned SrcColor = getRegColor(PHI->getOperand(i).getReg()); + if (SrcColor) + return SrcColor; } - - LI.removeInterval(RHS.reg); - - return true; + return 0; } -bool StrongPHIElimination::runOnMachineFunction(MachineFunction &Fn) { - LiveIntervals& LI = getAnalysis(); - - // Compute DFS numbers of each block - computeDFS(Fn); - - // Determine which phi node operands need copies - for (MachineFunction::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I) - if (!I->empty() && I->begin()->isPHI()) - processBlock(I); - - // Break interferences where two different phis want to coalesce - // in the same register. - std::set seen; - typedef std::map > - RenameSetType; - for (RenameSetType::iterator I = RenameSets.begin(), E = RenameSets.end(); - I != E; ++I) { - for (std::map::iterator - OI = I->second.begin(), OE = I->second.end(); OI != OE; ) { - if (!seen.count(OI->first)) { - seen.insert(OI->first); - ++OI; +void StrongPHIElimination::isolatePHI(MachineInstr *PHI) { + assert(PHI->isPHI()); + Node *Node = RegNodeMap[PHI->getOperand(0).getReg()]; + Node->parent.setInt(Node->parent.getInt() | Node::kPHIIsolatedFlag); +} + +/// SplitInterferencesForBasicBlock - traverses a basic block, splitting any +/// interferences found between registers in the same congruence class. It +/// takes two DenseMaps as arguments that it also updates: +/// +/// 1) CurrentDominatingParent, which maps a color to the register in that +/// congruence class whose definition was most recently seen. +/// +/// 2) ImmediateDominatingParent, which maps a register to the register in the +/// same congruence class that most immediately dominates it. +/// +/// This function assumes that it is being called in a depth-first traversal +/// of the dominator tree. +/// +/// The algorithm used here is a generalization of the dominance-based SSA test +/// for two variables. If there are variables a_1, ..., a_n such that +/// +/// def(a_1) dom ... dom def(a_n), +/// +/// then we can test for an interference between any two a_i by only using O(n) +/// interference tests between pairs of variables. If i < j and a_i and a_j +/// interfere, then a_i is alive at def(a_j), so it is also alive at def(a_i+1). +/// Thus, in order to test for an interference involving a_i, we need only check +/// for a potential interference with a_i+1. +/// +/// This method can be generalized to arbitrary sets of variables by performing +/// a depth-first traversal of the dominator tree. As we traverse down a branch +/// of the dominator tree, we keep track of the current dominating variable and +/// only perform an interference test with that variable. However, when we go to +/// another branch of the dominator tree, the definition of the current dominating +/// variable may no longer dominate the current block. In order to correct this, +/// we need to use a stack of past choices of the current dominating variable +/// and pop from this stack until we find a variable whose definition actually +/// dominates the current block. +/// +/// There will be one push on this stack for each variable that has become the +/// current dominating variable, so instead of using an explicit stack we can +/// simply associate the previous choice for a current dominating variable with +/// the new choice. This works better in our implementation, where we test for +/// interference in multiple distinct sets at once. +void +StrongPHIElimination::SplitInterferencesForBasicBlock( + MachineBasicBlock &MBB, + DenseMap &CurrentDominatingParent, + DenseMap &ImmediateDominatingParent) { + // Sort defs by their order in the original basic block, as the code below + // assumes that it is processing definitions in dominance order. + std::vector &DefInstrs = PHISrcDefs[&MBB]; + std::sort(DefInstrs.begin(), DefInstrs.end(), MIIndexCompare(LI)); + + for (std::vector::const_iterator BBI = DefInstrs.begin(), + BBE = DefInstrs.end(); BBI != BBE; ++BBI) { + for (MachineInstr::const_mop_iterator I = (*BBI)->operands_begin(), + E = (*BBI)->operands_end(); I != E; ++I) { + const MachineOperand &MO = *I; + + // FIXME: This would be faster if it were possible to bail out of checking + // an instruction's operands after the explicit defs, but this is incorrect + // for variadic instructions, which may appear before register allocation + // in the future. + if (!MO.isReg() || !MO.isDef()) + continue; + + unsigned DestReg = MO.getReg(); + if (!DestReg || !TargetRegisterInfo::isVirtualRegister(DestReg)) + continue; + + // If the virtual register being defined is not used in any PHI or has + // already been isolated, then there are no more interferences to check. + unsigned DestColor = getRegColor(DestReg); + if (!DestColor) + continue; + + // The input to this pass sometimes is not in SSA form in every basic + // block, as some virtual registers have redefinitions. We could eliminate + // this by fixing the passes that generate the non-SSA code, or we could + // handle it here by tracking defining machine instructions rather than + // virtual registers. For now, we just handle the situation conservatively + // in a way that will possibly lead to false interferences. + unsigned &CurrentParent = CurrentDominatingParent[DestColor]; + unsigned NewParent = CurrentParent; + if (NewParent == DestReg) + continue; + + // Pop registers from the stack represented by ImmediateDominatingParent + // until we find a parent that dominates the current instruction. + while (NewParent && (!DT->dominates(MRI->getVRegDef(NewParent), *BBI) + || !getRegColor(NewParent))) + NewParent = ImmediateDominatingParent[NewParent]; + + // If NewParent is nonzero, then its definition dominates the current + // instruction, so it is only necessary to check for the liveness of + // NewParent in order to check for an interference. + if (NewParent + && LI->getInterval(NewParent).liveAt(LI->getInstructionIndex(*BBI))) { + // If there is an interference, always isolate the new register. This + // could be improved by using a heuristic that decides which of the two + // registers to isolate. + isolateReg(DestReg); + CurrentParent = NewParent; } else { - Waiting[OI->second].insert(std::make_pair(OI->first, I->first)); - unsigned reg = OI->first; - ++OI; - I->second.erase(reg); - DEBUG(dbgs() << "Removing Renaming: " << reg << " -> " << I->first - << "\n"); + // If there is no interference, update ImmediateDominatingParent and set + // the CurrentDominatingParent for this color to the current register. + ImmediateDominatingParent[DestReg] = NewParent; + CurrentParent = DestReg; } } } - - // Insert copies - // FIXME: This process should probably preserve LiveIntervals - SmallPtrSet visited; - MachineDominatorTree& MDT = getAnalysis(); - InsertCopies(MDT.getRootNode(), visited); - - // Perform renaming - for (RenameSetType::iterator I = RenameSets.begin(), E = RenameSets.end(); - I != E; ++I) - while (I->second.size()) { - std::map::iterator SI = I->second.begin(); - - DEBUG(dbgs() << "Renaming: " << SI->first << " -> " << I->first << "\n"); - - if (SI->first != I->first) { - if (mergeLiveIntervals(I->first, SI->first)) { - Fn.getRegInfo().replaceRegWith(SI->first, I->first); - - if (RenameSets.count(SI->first)) { - I->second.insert(RenameSets[SI->first].begin(), - RenameSets[SI->first].end()); - RenameSets.erase(SI->first); - } - } else { - // Insert a last-minute copy if a conflict was detected. - const TargetInstrInfo *TII = Fn.getTarget().getInstrInfo(); - BuildMI(*SI->second, SI->second->getFirstTerminator(), DebugLoc(), - TII->get(TargetOpcode::COPY), I->first).addReg(SI->first); - - LI.renumber(); - - LiveInterval& Int = LI.getOrCreateInterval(I->first); - SlotIndex instrIdx = - LI.getInstructionIndex(--SI->second->getFirstTerminator()); - if (Int.liveAt(instrIdx.getDefIndex())) - Int.removeRange(instrIdx.getDefIndex(), - LI.getMBBEndIdx(SI->second).getNextSlot(), true); - - LiveRange R = LI.addLiveRangeToEndOfBlock(I->first, - --SI->second->getFirstTerminator()); - R.valno->setCopy(--SI->second->getFirstTerminator()); - R.valno->def = instrIdx.getDefIndex(); - - DEBUG(dbgs() << "Renaming failed: " << SI->first << " -> " - << I->first << "\n"); - } + + // We now walk the PHIs in successor blocks and check for interferences. This + // is necesary because the use of a PHI's operands are logically contained in + // the predecessor block. The def of a PHI's destination register is processed + // along with the other defs in a basic block. + + CurrentPHIForColor.clear(); + + for (MachineBasicBlock::succ_iterator SI = MBB.succ_begin(), + SE = MBB.succ_end(); SI != SE; ++SI) { + for (MachineBasicBlock::iterator BBI = (*SI)->begin(), BBE = (*SI)->end(); + BBI != BBE && BBI->isPHI(); ++BBI) { + MachineInstr *PHI = BBI; + + // If a PHI is already isolated, either by being isolated directly or + // having all of its operands isolated, ignore it. + unsigned Color = getPHIColor(PHI); + if (!Color) + continue; + + // Find the index of the PHI operand that corresponds to this basic block. + unsigned PredIndex; + for (PredIndex = 1; PredIndex < PHI->getNumOperands(); PredIndex += 2) { + if (PHI->getOperand(PredIndex + 1).getMBB() == &MBB) + break; } - - LiveInterval& Int = LI.getOrCreateInterval(I->first); - const LiveRange* LR = - Int.getLiveRangeContaining(LI.getMBBEndIdx(SI->second)); - LR->valno->setHasPHIKill(true); - - I->second.erase(SI->first); + assert(PredIndex < PHI->getNumOperands()); + unsigned PredOperandReg = PHI->getOperand(PredIndex).getReg(); + + // Pop registers from the stack represented by ImmediateDominatingParent + // until we find a parent that dominates the current instruction. + unsigned &CurrentParent = CurrentDominatingParent[Color]; + unsigned NewParent = CurrentParent; + while (NewParent + && (!DT->dominates(MRI->getVRegDef(NewParent)->getParent(), &MBB) + || !getRegColor(NewParent))) + NewParent = ImmediateDominatingParent[NewParent]; + CurrentParent = NewParent; + + // If there is an interference with a register, always isolate the + // register rather than the PHI. It is also possible to isolate the + // PHI, but that introduces copies for all of the registers involved + // in that PHI. + if (NewParent && LI->isLiveOutOfMBB(LI->getInterval(NewParent), &MBB) + && NewParent != PredOperandReg) + isolateReg(NewParent); + + std::pair + &CurrentPHI = CurrentPHIForColor[Color]; + + // If two PHIs have the same operand from every shared predecessor, then + // they don't actually interfere. Otherwise, isolate the current PHI. This + // could possibly be improved, e.g. we could isolate the PHI with the + // fewest operands. + if (CurrentPHI.first && CurrentPHI.second != PredOperandReg) + isolatePHI(PHI); + else + CurrentPHI = std::make_pair(PHI, PredOperandReg); } - - // Remove PHIs - std::vector phis; - for (MachineFunction::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I) { - for (MachineBasicBlock::iterator BI = I->begin(), BE = I->end(); - BI != BE; ++BI) - if (BI->isPHI()) - phis.push_back(BI); } - - for (std::vector::iterator I = phis.begin(), E = phis.end(); - I != E; ) { - MachineInstr* PInstr = *(I++); - - // If this is a dead PHI node, then remove it from LiveIntervals. - unsigned DestReg = PInstr->getOperand(0).getReg(); - LiveInterval& PI = LI.getInterval(DestReg); - if (PInstr->registerDefIsDead(DestReg)) { - if (PI.containsOneValue()) { - LI.removeInterval(DestReg); +} + +void StrongPHIElimination::InsertCopiesForPHI(MachineInstr *PHI, + MachineBasicBlock *MBB) { + assert(PHI->isPHI()); + ++NumPHIsLowered; + unsigned PHIColor = getPHIColor(PHI); + + for (unsigned i = 1; i < PHI->getNumOperands(); i += 2) { + MachineOperand &SrcMO = PHI->getOperand(i); + + // If a source is defined by an implicit def, there is no need to insert a + // copy in the predecessor. + if (SrcMO.isUndef()) + continue; + + unsigned SrcReg = SrcMO.getReg(); + assert(TargetRegisterInfo::isVirtualRegister(SrcReg) && + "Machine PHI Operands must all be virtual registers!"); + + MachineBasicBlock *PredBB = PHI->getOperand(i + 1).getMBB(); + unsigned SrcColor = getRegColor(SrcReg); + + // If neither the PHI nor the operand were isolated, then we only need to + // set the phi-kill flag on the VNInfo at this PHI. + if (PHIColor && SrcColor == PHIColor) { + LiveInterval &SrcInterval = LI->getInterval(SrcReg); + SlotIndex PredIndex = LI->getMBBEndIdx(PredBB); + VNInfo *SrcVNI = SrcInterval.getVNInfoAt(PredIndex.getPrevIndex()); + assert(SrcVNI); + SrcVNI->setHasPHIKill(true); + continue; + } + + unsigned CopyReg = 0; + if (PHIColor) { + SrcCopyMap::const_iterator I + = InsertedSrcCopyMap.find(std::make_pair(PredBB, PHIColor)); + CopyReg + = I != InsertedSrcCopyMap.end() ? I->second->getOperand(0).getReg() : 0; + } + + if (!CopyReg) { + const TargetRegisterClass *RC = MRI->getRegClass(SrcReg); + CopyReg = MRI->createVirtualRegister(RC); + + MachineBasicBlock::iterator + CopyInsertPoint = findPHICopyInsertPoint(PredBB, MBB, SrcReg); + unsigned SrcSubReg = SrcMO.getSubReg(); + MachineInstr *CopyInstr = BuildMI(*PredBB, + CopyInsertPoint, + PHI->getDebugLoc(), + TII->get(TargetOpcode::COPY), + CopyReg).addReg(SrcReg, 0, SrcSubReg); + LI->InsertMachineInstrInMaps(CopyInstr); + ++NumSrcCopiesInserted; + + // addLiveRangeToEndOfBlock() also adds the phikill flag to the VNInfo for + // the newly added range. + LI->addLiveRangeToEndOfBlock(CopyReg, CopyInstr); + InsertedSrcCopySet.insert(std::make_pair(PredBB, SrcReg)); + + addReg(CopyReg); + if (PHIColor) { + unionRegs(PHIColor, CopyReg); + assert(getRegColor(CopyReg) != CopyReg); } else { - SlotIndex idx = LI.getInstructionIndex(PInstr).getDefIndex(); - PI.removeRange(*PI.getLiveRangeContaining(idx), true); - } - } else { - // Trim live intervals of input registers. They are no longer live into - // this block if they died after the PHI. If they lived after it, don't - // trim them because they might have other legitimate uses. - for (unsigned i = 1; i < PInstr->getNumOperands(); i += 2) { - unsigned reg = PInstr->getOperand(i).getReg(); - - MachineBasicBlock* MBB = PInstr->getOperand(i+1).getMBB(); - LiveInterval& InputI = LI.getInterval(reg); - if (MBB != PInstr->getParent() && - InputI.liveAt(LI.getMBBStartIdx(PInstr->getParent())) && - InputI.expiredAt(LI.getInstructionIndex(PInstr).getNextIndex())) - InputI.removeRange(LI.getMBBStartIdx(PInstr->getParent()), - LI.getInstructionIndex(PInstr), - true); + PHIColor = CopyReg; + assert(getRegColor(CopyReg) == CopyReg); } - - // If the PHI is not dead, then the valno defined by the PHI - // now has an unknown def. - SlotIndex idx = LI.getInstructionIndex(PInstr).getDefIndex(); - const LiveRange* PLR = PI.getLiveRangeContaining(idx); - PLR->valno->setIsPHIDef(true); - LiveRange R (LI.getMBBStartIdx(PInstr->getParent()), - PLR->start, PLR->valno); - PI.addRange(R); + + if (!InsertedSrcCopyMap.count(std::make_pair(PredBB, PHIColor))) + InsertedSrcCopyMap[std::make_pair(PredBB, PHIColor)] = CopyInstr; } - - LI.RemoveMachineInstrFromMaps(PInstr); - PInstr->eraseFromParent(); + + SrcMO.setReg(CopyReg); + + // If SrcReg is not live beyond the PHI, trim its interval so that it is no + // longer live-in to MBB. Note that SrcReg may appear in other PHIs that are + // processed later, but this is still correct to do at this point because we + // never rely on LiveIntervals being correct while inserting copies. + // FIXME: Should this just count uses at PHIs like the normal PHIElimination + // pass does? + LiveInterval &SrcLI = LI->getInterval(SrcReg); + SlotIndex MBBStartIndex = LI->getMBBStartIdx(MBB); + SlotIndex PHIIndex = LI->getInstructionIndex(PHI); + SlotIndex NextInstrIndex = PHIIndex.getNextIndex(); + if (SrcLI.liveAt(MBBStartIndex) && SrcLI.expiredAt(NextInstrIndex)) + SrcLI.removeRange(MBBStartIndex, PHIIndex, true); } - - LI.renumber(); - - return true; + + unsigned DestReg = PHI->getOperand(0).getReg(); + unsigned DestColor = getRegColor(DestReg); + + if (PHIColor && DestColor == PHIColor) { + LiveInterval &DestLI = LI->getInterval(DestReg); + + // Set the phi-def flag for the VN at this PHI. + SlotIndex PHIIndex = LI->getInstructionIndex(PHI); + VNInfo *DestVNI = DestLI.getVNInfoAt(PHIIndex.getDefIndex()); + assert(DestVNI); + DestVNI->setIsPHIDef(true); + + // Prior to PHI elimination, the live ranges of PHIs begin at their defining + // instruction. After PHI elimination, PHI instructions are replaced by VNs + // with the phi-def flag set, and the live ranges of these VNs start at the + // beginning of the basic block. + SlotIndex MBBStartIndex = LI->getMBBStartIdx(MBB); + DestVNI->def = MBBStartIndex; + DestLI.addRange(LiveRange(MBBStartIndex, + PHIIndex.getDefIndex(), + DestVNI)); + return; + } + + const TargetRegisterClass *RC = MRI->getRegClass(DestReg); + unsigned CopyReg = MRI->createVirtualRegister(RC); + + MachineInstr *CopyInstr = BuildMI(*MBB, + MBB->SkipPHIsAndLabels(MBB->begin()), + PHI->getDebugLoc(), + TII->get(TargetOpcode::COPY), + DestReg).addReg(CopyReg); + LI->InsertMachineInstrInMaps(CopyInstr); + PHI->getOperand(0).setReg(CopyReg); + ++NumDestCopiesInserted; + + // Add the region from the beginning of MBB to the copy instruction to + // CopyReg's live interval, and give the VNInfo the phidef flag. + LiveInterval &CopyLI = LI->getOrCreateInterval(CopyReg); + SlotIndex MBBStartIndex = LI->getMBBStartIdx(MBB); + SlotIndex DestCopyIndex = LI->getInstructionIndex(CopyInstr); + VNInfo *CopyVNI = CopyLI.getNextValue(MBBStartIndex, + CopyInstr, + LI->getVNInfoAllocator()); + CopyVNI->setIsPHIDef(true); + CopyLI.addRange(LiveRange(MBBStartIndex, + DestCopyIndex.getDefIndex(), + CopyVNI)); + + // Adjust DestReg's live interval to adjust for its new definition at + // CopyInstr. + LiveInterval &DestLI = LI->getOrCreateInterval(DestReg); + SlotIndex PHIIndex = LI->getInstructionIndex(PHI); + DestLI.removeRange(PHIIndex.getDefIndex(), DestCopyIndex.getDefIndex()); + + VNInfo *DestVNI = DestLI.getVNInfoAt(DestCopyIndex.getDefIndex()); + assert(DestVNI); + DestVNI->def = DestCopyIndex.getDefIndex(); + + InsertedDestCopies[CopyReg] = CopyInstr; +} + +void StrongPHIElimination::MergeLIsAndRename(unsigned Reg, unsigned NewReg) { + if (Reg == NewReg) + return; + + LiveInterval &OldLI = LI->getInterval(Reg); + LiveInterval &NewLI = LI->getInterval(NewReg); + + // Merge the live ranges of the two registers. + DenseMap VNMap; + for (LiveInterval::iterator LRI = OldLI.begin(), LRE = OldLI.end(); + LRI != LRE; ++LRI) { + LiveRange OldLR = *LRI; + VNInfo *OldVN = OldLR.valno; + + VNInfo *&NewVN = VNMap[OldVN]; + if (!NewVN) { + NewVN = NewLI.createValueCopy(OldVN, LI->getVNInfoAllocator()); + VNMap[OldVN] = NewVN; + } + + LiveRange LR(OldLR.start, OldLR.end, NewVN); + NewLI.addRange(LR); + } + + // Remove the LiveInterval for the register being renamed and replace all + // of its defs and uses with the new register. + LI->removeInterval(Reg); + MRI->replaceRegWith(Reg, NewReg); } diff --git a/lib/CodeGen/TailDuplication.cpp b/lib/CodeGen/TailDuplication.cpp index a815b364d54e..04d3d311b416 100644 --- a/lib/CodeGen/TailDuplication.cpp +++ b/lib/CodeGen/TailDuplication.cpp @@ -350,7 +350,7 @@ void TailDuplicatePass::DuplicateInstruction(MachineInstr *MI, if (!MO.isReg()) continue; unsigned Reg = MO.getReg(); - if (!Reg || TargetRegisterInfo::isPhysicalRegister(Reg)) + if (!TargetRegisterInfo::isVirtualRegister(Reg)) continue; if (MO.isDef()) { const TargetRegisterClass *RC = MRI->getRegClass(Reg); @@ -459,15 +459,19 @@ TailDuplicatePass::TailDuplicate(MachineBasicBlock *TailBB, MachineFunction &MF, // duplicate only one, because one branch instruction can be eliminated to // compensate for the duplication. unsigned MaxDuplicateCount; - if (MF.getFunction()->hasFnAttr(Attribute::OptimizeForSize)) + if (TailDuplicateSize.getNumOccurrences() == 0 && + MF.getFunction()->hasFnAttr(Attribute::OptimizeForSize)) MaxDuplicateCount = 1; else MaxDuplicateCount = TailDuplicateSize; if (PreRegAlloc) { - // Pre-regalloc tail duplication hurts compile time and doesn't help - // much except for indirect branches. - if (TailBB->empty() || !TailBB->back().getDesc().isIndirectBranch()) + if (TailBB->empty()) + return false; + const TargetInstrDesc &TID = TailBB->back().getDesc(); + // Pre-regalloc tail duplication hurts compile time and doesn't help + // much except for indirect branches and returns. + if (!TID.isIndirectBranch() && !TID.isReturn()) return false; // If the target has hardware branch prediction that can handle indirect // branches, duplicating them can often make them predictable when there @@ -500,9 +504,10 @@ TailDuplicatePass::TailDuplicate(MachineBasicBlock *TailBB, MachineFunction &MF, if (!I->isPHI() && !I->isDebugValue()) InstrCount += 1; } - // Heuristically, don't tail-duplicate calls if it would expand code size, - // as it's less likely to be worth the extra cost. - if (InstrCount > 1 && HasCall) + // Don't tail-duplicate calls before register allocation. Calls presents a + // barrier to register allocation so duplicating them may end up increasing + // spills. + if (InstrCount > 1 && (PreRegAlloc && HasCall)) return false; DEBUG(dbgs() << "\n*** Tail-duplicating BB#" << TailBB->getNumber() << '\n'); diff --git a/lib/CodeGen/TargetInstrInfoImpl.cpp b/lib/CodeGen/TargetInstrInfoImpl.cpp index 6e4a0d837ecd..15340a3f1084 100644 --- a/lib/CodeGen/TargetInstrInfoImpl.cpp +++ b/lib/CodeGen/TargetInstrInfoImpl.cpp @@ -22,13 +22,18 @@ #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" -#include "llvm/CodeGen/PostRAHazardRecognizer.h" +#include "llvm/CodeGen/ScoreboardHazardRecognizer.h" #include "llvm/CodeGen/PseudoSourceValue.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; +static cl::opt DisableHazardRecognizer( + "disable-sched-hazard", cl::Hidden, cl::init(false), + cl::desc("Disable hazard detection during preRA scheduling")); + /// ReplaceTailWithBranchTo - Delete the instruction OldInst and everything /// after it, replacing it with an unconditional branch to NewDest. void @@ -135,7 +140,7 @@ bool TargetInstrInfoImpl::PredicateInstruction(MachineInstr *MI, const TargetInstrDesc &TID = MI->getDesc(); if (!TID.isPredicable()) return false; - + for (unsigned j = 0, i = 0, e = MI->getNumOperands(); i != e; ++i) { if (TID.OpInfo[i].isPredicate()) { MachineOperand &MO = MI->getOperand(i); @@ -166,8 +171,10 @@ void TargetInstrInfoImpl::reMaterialize(MachineBasicBlock &MBB, MBB.insert(I, MI); } -bool TargetInstrInfoImpl::produceSameValue(const MachineInstr *MI0, - const MachineInstr *MI1) const { +bool +TargetInstrInfoImpl::produceSameValue(const MachineInstr *MI0, + const MachineInstr *MI1, + const MachineRegisterInfo *MRI) const { return MI0->isIdenticalTo(MI1, MachineInstr::IgnoreVRegDefs); } @@ -252,9 +259,9 @@ TargetInstrInfo::foldMemoryOperand(MachineBasicBlock::iterator MI, const MachineFrameInfo &MFI = *MF.getFrameInfo(); assert(MFI.getObjectOffset(FI) != -1); MachineMemOperand *MMO = - MF.getMachineMemOperand(PseudoSourceValue::getFixedStack(FI), - Flags, /*Offset=*/0, - MFI.getObjectSize(FI), + MF.getMachineMemOperand( + MachinePointerInfo(PseudoSourceValue::getFixedStack(FI)), + Flags, MFI.getObjectSize(FI), MFI.getObjectAlignment(FI)); NewMI->addMemOperand(MF, MMO); @@ -329,8 +336,13 @@ isReallyTriviallyReMaterializableGeneric(const MachineInstr *MI, const TargetInstrDesc &TID = MI->getDesc(); // Avoid instructions obviously unsafe for remat. - if (TID.hasUnmodeledSideEffects() || TID.isNotDuplicable() || - TID.mayStore()) + if (TID.isNotDuplicable() || TID.mayStore() || + MI->hasUnmodeledSideEffects()) + return false; + + // Don't remat inline asm. We have no idea how expensive it is + // even if it's side effect free. + if (MI->isInlineAsm()) return false; // Avoid instructions which load from potentially varying memory. @@ -414,8 +426,24 @@ bool TargetInstrInfoImpl::isSchedulingBoundary(const MachineInstr *MI, return false; } +// Provide a global flag for disabling the PreRA hazard recognizer that targets +// may choose to honor. +bool TargetInstrInfoImpl::usePreRAHazardRecognizer() const { + return !DisableHazardRecognizer; +} + +// Default implementation of CreateTargetRAHazardRecognizer. +ScheduleHazardRecognizer *TargetInstrInfoImpl:: +CreateTargetHazardRecognizer(const TargetMachine *TM, + const ScheduleDAG *DAG) const { + // Dummy hazard recognizer allows all instructions to issue. + return new ScheduleHazardRecognizer(); +} + // Default implementation of CreateTargetPostRAHazardRecognizer. ScheduleHazardRecognizer *TargetInstrInfoImpl:: -CreateTargetPostRAHazardRecognizer(const InstrItineraryData &II) const { - return (ScheduleHazardRecognizer *)new PostRAHazardRecognizer(II); +CreateTargetPostRAHazardRecognizer(const InstrItineraryData *II, + const ScheduleDAG *DAG) const { + return (ScheduleHazardRecognizer *) + new ScoreboardHazardRecognizer(II, DAG, "post-RA-sched"); } diff --git a/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index f1e10eec724c..0b7bd98cc692 100644 --- a/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -29,10 +29,12 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Support/Dwarf.h" +#include "llvm/Support/ELF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Triple.h" using namespace llvm; using namespace dwarf; @@ -45,81 +47,81 @@ void TargetLoweringObjectFileELF::Initialize(MCContext &Ctx, TargetLoweringObjectFile::Initialize(Ctx, TM); BSSSection = - getContext().getELFSection(".bss", MCSectionELF::SHT_NOBITS, - MCSectionELF::SHF_WRITE |MCSectionELF::SHF_ALLOC, + getContext().getELFSection(".bss", ELF::SHT_NOBITS, + ELF::SHF_WRITE |ELF::SHF_ALLOC, SectionKind::getBSS()); TextSection = - getContext().getELFSection(".text", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_EXECINSTR | - MCSectionELF::SHF_ALLOC, + getContext().getELFSection(".text", ELF::SHT_PROGBITS, + ELF::SHF_EXECINSTR | + ELF::SHF_ALLOC, SectionKind::getText()); DataSection = - getContext().getELFSection(".data", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_WRITE |MCSectionELF::SHF_ALLOC, + getContext().getELFSection(".data", ELF::SHT_PROGBITS, + ELF::SHF_WRITE |ELF::SHF_ALLOC, SectionKind::getDataRel()); ReadOnlySection = - getContext().getELFSection(".rodata", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC, + getContext().getELFSection(".rodata", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC, SectionKind::getReadOnly()); TLSDataSection = - getContext().getELFSection(".tdata", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC | MCSectionELF::SHF_TLS | - MCSectionELF::SHF_WRITE, + getContext().getELFSection(".tdata", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | ELF::SHF_TLS | + ELF::SHF_WRITE, SectionKind::getThreadData()); TLSBSSSection = - getContext().getELFSection(".tbss", MCSectionELF::SHT_NOBITS, - MCSectionELF::SHF_ALLOC | MCSectionELF::SHF_TLS | - MCSectionELF::SHF_WRITE, + getContext().getELFSection(".tbss", ELF::SHT_NOBITS, + ELF::SHF_ALLOC | ELF::SHF_TLS | + ELF::SHF_WRITE, SectionKind::getThreadBSS()); DataRelSection = - getContext().getELFSection(".data.rel", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC |MCSectionELF::SHF_WRITE, + getContext().getELFSection(".data.rel", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC |ELF::SHF_WRITE, SectionKind::getDataRel()); DataRelLocalSection = - getContext().getELFSection(".data.rel.local", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC |MCSectionELF::SHF_WRITE, + getContext().getELFSection(".data.rel.local", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC |ELF::SHF_WRITE, SectionKind::getDataRelLocal()); DataRelROSection = - getContext().getELFSection(".data.rel.ro", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC |MCSectionELF::SHF_WRITE, + getContext().getELFSection(".data.rel.ro", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC |ELF::SHF_WRITE, SectionKind::getReadOnlyWithRel()); DataRelROLocalSection = - getContext().getELFSection(".data.rel.ro.local", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC |MCSectionELF::SHF_WRITE, + getContext().getELFSection(".data.rel.ro.local", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC |ELF::SHF_WRITE, SectionKind::getReadOnlyWithRelLocal()); MergeableConst4Section = - getContext().getELFSection(".rodata.cst4", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC |MCSectionELF::SHF_MERGE, + getContext().getELFSection(".rodata.cst4", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC |ELF::SHF_MERGE, SectionKind::getMergeableConst4()); MergeableConst8Section = - getContext().getELFSection(".rodata.cst8", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC |MCSectionELF::SHF_MERGE, + getContext().getELFSection(".rodata.cst8", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC |ELF::SHF_MERGE, SectionKind::getMergeableConst8()); MergeableConst16Section = - getContext().getELFSection(".rodata.cst16", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC |MCSectionELF::SHF_MERGE, + getContext().getELFSection(".rodata.cst16", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC |ELF::SHF_MERGE, SectionKind::getMergeableConst16()); StaticCtorSection = - getContext().getELFSection(".ctors", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC |MCSectionELF::SHF_WRITE, + getContext().getELFSection(".ctors", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC |ELF::SHF_WRITE, SectionKind::getDataRel()); StaticDtorSection = - getContext().getELFSection(".dtors", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC |MCSectionELF::SHF_WRITE, + getContext().getELFSection(".dtors", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC |ELF::SHF_WRITE, SectionKind::getDataRel()); // Exception Handling Sections. @@ -129,50 +131,50 @@ void TargetLoweringObjectFileELF::Initialize(MCContext &Ctx, // runtime hit for C++ apps. Either the contents of the LSDA need to be // adjusted or this should be a data section. LSDASection = - getContext().getELFSection(".gcc_except_table", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC, + getContext().getELFSection(".gcc_except_table", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC, SectionKind::getReadOnly()); - EHFrameSection = - getContext().getELFSection(".eh_frame", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC |MCSectionELF::SHF_WRITE, - SectionKind::getDataRel()); - // Debug Info Sections. DwarfAbbrevSection = - getContext().getELFSection(".debug_abbrev", MCSectionELF::SHT_PROGBITS, 0, + getContext().getELFSection(".debug_abbrev", ELF::SHT_PROGBITS, 0, SectionKind::getMetadata()); DwarfInfoSection = - getContext().getELFSection(".debug_info", MCSectionELF::SHT_PROGBITS, 0, + getContext().getELFSection(".debug_info", ELF::SHT_PROGBITS, 0, SectionKind::getMetadata()); DwarfLineSection = - getContext().getELFSection(".debug_line", MCSectionELF::SHT_PROGBITS, 0, + getContext().getELFSection(".debug_line", ELF::SHT_PROGBITS, 0, SectionKind::getMetadata()); DwarfFrameSection = - getContext().getELFSection(".debug_frame", MCSectionELF::SHT_PROGBITS, 0, + getContext().getELFSection(".debug_frame", ELF::SHT_PROGBITS, 0, SectionKind::getMetadata()); DwarfPubNamesSection = - getContext().getELFSection(".debug_pubnames", MCSectionELF::SHT_PROGBITS, 0, + getContext().getELFSection(".debug_pubnames", ELF::SHT_PROGBITS, 0, SectionKind::getMetadata()); DwarfPubTypesSection = - getContext().getELFSection(".debug_pubtypes", MCSectionELF::SHT_PROGBITS, 0, + getContext().getELFSection(".debug_pubtypes", ELF::SHT_PROGBITS, 0, SectionKind::getMetadata()); DwarfStrSection = - getContext().getELFSection(".debug_str", MCSectionELF::SHT_PROGBITS, 0, + getContext().getELFSection(".debug_str", ELF::SHT_PROGBITS, 0, SectionKind::getMetadata()); DwarfLocSection = - getContext().getELFSection(".debug_loc", MCSectionELF::SHT_PROGBITS, 0, + getContext().getELFSection(".debug_loc", ELF::SHT_PROGBITS, 0, SectionKind::getMetadata()); DwarfARangesSection = - getContext().getELFSection(".debug_aranges", MCSectionELF::SHT_PROGBITS, 0, + getContext().getELFSection(".debug_aranges", ELF::SHT_PROGBITS, 0, SectionKind::getMetadata()); DwarfRangesSection = - getContext().getELFSection(".debug_ranges", MCSectionELF::SHT_PROGBITS, 0, + getContext().getELFSection(".debug_ranges", ELF::SHT_PROGBITS, 0, SectionKind::getMetadata()); DwarfMacroInfoSection = - getContext().getELFSection(".debug_macinfo", MCSectionELF::SHT_PROGBITS, 0, + getContext().getELFSection(".debug_macinfo", ELF::SHT_PROGBITS, 0, SectionKind::getMetadata()); } +const MCSection *TargetLoweringObjectFileELF::getEHFrameSection() const { + return getContext().getELFSection(".eh_frame", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC, + SectionKind::getDataRel()); +} static SectionKind getELFKindForNamedSection(StringRef Name, SectionKind K) { @@ -208,18 +210,18 @@ getELFKindForNamedSection(StringRef Name, SectionKind K) { static unsigned getELFSectionType(StringRef Name, SectionKind K) { if (Name == ".init_array") - return MCSectionELF::SHT_INIT_ARRAY; + return ELF::SHT_INIT_ARRAY; if (Name == ".fini_array") - return MCSectionELF::SHT_FINI_ARRAY; + return ELF::SHT_FINI_ARRAY; if (Name == ".preinit_array") - return MCSectionELF::SHT_PREINIT_ARRAY; + return ELF::SHT_PREINIT_ARRAY; if (K.isBSS() || K.isThreadBSS()) - return MCSectionELF::SHT_NOBITS; + return ELF::SHT_NOBITS; - return MCSectionELF::SHT_PROGBITS; + return ELF::SHT_PROGBITS; } @@ -228,24 +230,24 @@ getELFSectionFlags(SectionKind K) { unsigned Flags = 0; if (!K.isMetadata()) - Flags |= MCSectionELF::SHF_ALLOC; + Flags |= ELF::SHF_ALLOC; if (K.isText()) - Flags |= MCSectionELF::SHF_EXECINSTR; + Flags |= ELF::SHF_EXECINSTR; if (K.isWriteable()) - Flags |= MCSectionELF::SHF_WRITE; + Flags |= ELF::SHF_WRITE; if (K.isThreadLocal()) - Flags |= MCSectionELF::SHF_TLS; + Flags |= ELF::SHF_TLS; // K.isMergeableConst() is left out to honour PR4650 if (K.isMergeableCString() || K.isMergeableConst4() || K.isMergeableConst8() || K.isMergeableConst16()) - Flags |= MCSectionELF::SHF_MERGE; + Flags |= ELF::SHF_MERGE; if (K.isMergeableCString()) - Flags |= MCSectionELF::SHF_STRINGS; + Flags |= ELF::SHF_STRINGS; return Flags; } @@ -261,23 +263,7 @@ getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind, return getContext().getELFSection(SectionName, getELFSectionType(SectionName, Kind), - getELFSectionFlags(Kind), Kind, true); -} - -static const char *getSectionPrefixForUniqueGlobal(SectionKind Kind) { - if (Kind.isText()) return ".gnu.linkonce.t."; - if (Kind.isReadOnly()) return ".gnu.linkonce.r."; - - if (Kind.isThreadData()) return ".gnu.linkonce.td."; - if (Kind.isThreadBSS()) return ".gnu.linkonce.tb."; - - if (Kind.isDataNoRel()) return ".gnu.linkonce.d."; - if (Kind.isDataRelLocal()) return ".gnu.linkonce.d.rel.local."; - if (Kind.isDataRel()) return ".gnu.linkonce.d.rel."; - if (Kind.isReadOnlyWithRelLocal()) return ".gnu.linkonce.d.rel.ro.local."; - - assert(Kind.isReadOnlyWithRel() && "Unknown section kind"); - return ".gnu.linkonce.d.rel.ro."; + getELFSectionFlags(Kind), Kind); } /// getSectionPrefixForGlobal - Return the section prefix name used by options @@ -307,7 +293,7 @@ SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, bool EmitUniquedSection; if (Kind.isText()) EmitUniquedSection = TM.getFunctionSections(); - else + else EmitUniquedSection = TM.getDataSections(); // If this global is linkonce/weak and the target handles this by emitting it @@ -315,19 +301,21 @@ SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, if ((GV->isWeakForLinker() || EmitUniquedSection) && !Kind.isCommon() && !Kind.isBSS()) { const char *Prefix; - if (GV->isWeakForLinker()) - Prefix = getSectionPrefixForUniqueGlobal(Kind); - else { - assert(EmitUniquedSection); - Prefix = getSectionPrefixForGlobal(Kind); - } + Prefix = getSectionPrefixForGlobal(Kind); SmallString<128> Name(Prefix, Prefix+strlen(Prefix)); MCSymbol *Sym = Mang->getSymbol(GV); Name.append(Sym->getName().begin(), Sym->getName().end()); + StringRef Group = ""; + unsigned Flags = getELFSectionFlags(Kind); + if (GV->isWeakForLinker()) { + Group = Sym->getName(); + Flags |= ELF::SHF_GROUP; + } + return getContext().getELFSection(Name.str(), getELFSectionType(Name.str(), Kind), - getELFSectionFlags(Kind), Kind); + Flags, Kind, 0, Group); } if (Kind.isText()) return TextSection; @@ -352,10 +340,10 @@ SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, std::string Name = SizeSpec + utostr(Align); - return getContext().getELFSection(Name, MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC | - MCSectionELF::SHF_MERGE | - MCSectionELF::SHF_STRINGS, + return getContext().getELFSection(Name, ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | + ELF::SHF_MERGE | + ELF::SHF_STRINGS, Kind); } @@ -450,7 +438,16 @@ void TargetLoweringObjectFileMachO::Initialize(MCContext &Ctx, IsFunctionEHSymbolGlobal = true; IsFunctionEHFrameSymbolPrivate = false; SupportsWeakOmittedEHFrame = false; - + + Triple T(((LLVMTargetMachine&)TM).getTargetTriple()); + if (T.getOS() == Triple::Darwin) { + unsigned MajNum = T.getDarwinMajorNumber(); + if (MajNum == 7 || MajNum == 8) // 10.3 Panther, 10.4 Tiger + CommDirectiveSupportsAlignment = false; + if (MajNum > 9) // 10.6 SnowLeopard + IsFunctionEHSymbolGlobal = false; + } + TargetLoweringObjectFile::Initialize(Ctx, TM); TextSection // .text @@ -469,20 +466,20 @@ void TargetLoweringObjectFileMachO::Initialize(MCContext &Ctx, = getContext().getMachOSection("__DATA", "__thread_bss", MCSectionMachO::S_THREAD_LOCAL_ZEROFILL, SectionKind::getThreadBSS()); - + // TODO: Verify datarel below. TLSTLVSection // .tlv = getContext().getMachOSection("__DATA", "__thread_vars", MCSectionMachO::S_THREAD_LOCAL_VARIABLES, SectionKind::getDataRel()); - + TLSThreadInitSection = getContext().getMachOSection("__DATA", "__thread_init", MCSectionMachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS, SectionKind::getDataRel()); - + CStringSection // .cstring - = getContext().getMachOSection("__TEXT", "__cstring", + = getContext().getMachOSection("__TEXT", "__cstring", MCSectionMachO::S_CSTRING_LITERALS, SectionKind::getMergeable1ByteCString()); UStringSection @@ -493,7 +490,7 @@ void TargetLoweringObjectFileMachO::Initialize(MCContext &Ctx, MCSectionMachO::S_4BYTE_LITERALS, SectionKind::getMergeableConst4()); EightByteConstantSection // .literal8 - = getContext().getMachOSection("__TEXT", "__literal8", + = getContext().getMachOSection("__TEXT", "__literal8", MCSectionMachO::S_8BYTE_LITERALS, SectionKind::getMergeableConst8()); @@ -517,14 +514,14 @@ void TargetLoweringObjectFileMachO::Initialize(MCContext &Ctx, MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, SectionKind::getText()); ConstTextCoalSection - = getContext().getMachOSection("__TEXT", "__const_coal", + = getContext().getMachOSection("__TEXT", "__const_coal", MCSectionMachO::S_COALESCED, SectionKind::getReadOnly()); ConstDataSection // .const_data = getContext().getMachOSection("__DATA", "__const", 0, SectionKind::getReadOnlyWithRel()); DataCoalSection - = getContext().getMachOSection("__DATA","__datacoal_nt", + = getContext().getMachOSection("__DATA","__datacoal_nt", MCSectionMachO::S_COALESCED, SectionKind::getDataRel()); DataCommonSection @@ -534,7 +531,7 @@ void TargetLoweringObjectFileMachO::Initialize(MCContext &Ctx, DataBSSSection = getContext().getMachOSection("__DATA","__bss", MCSectionMachO::S_ZEROFILL, SectionKind::getBSS()); - + LazySymbolPointerSection = getContext().getMachOSection("__DATA", "__la_symbol_ptr", @@ -566,17 +563,9 @@ void TargetLoweringObjectFileMachO::Initialize(MCContext &Ctx, // Exception Handling. LSDASection = getContext().getMachOSection("__TEXT", "__gcc_except_tab", 0, SectionKind::getReadOnlyWithRel()); - EHFrameSection = - getContext().getMachOSection("__TEXT", "__eh_frame", - MCSectionMachO::S_COALESCED | - MCSectionMachO::S_ATTR_NO_TOC | - MCSectionMachO::S_ATTR_STRIP_STATIC_SYMS | - MCSectionMachO::S_ATTR_LIVE_SUPPORT, - SectionKind::getReadOnly()); - // Debug Information. DwarfAbbrevSection = - getContext().getMachOSection("__DWARF", "__debug_abbrev", + getContext().getMachOSection("__DWARF", "__debug_abbrev", MCSectionMachO::S_ATTR_DEBUG, SectionKind::getMetadata()); DwarfInfoSection = @@ -623,10 +612,19 @@ void TargetLoweringObjectFileMachO::Initialize(MCContext &Ctx, getContext().getMachOSection("__DWARF", "__debug_inlined", MCSectionMachO::S_ATTR_DEBUG, SectionKind::getMetadata()); - + TLSExtraDataSection = TLSTLVSection; } +const MCSection *TargetLoweringObjectFileMachO::getEHFrameSection() const { + return getContext().getMachOSection("__TEXT", "__eh_frame", + MCSectionMachO::S_COALESCED | + MCSectionMachO::S_ATTR_NO_TOC | + MCSectionMachO::S_ATTR_STRIP_STATIC_SYMS | + MCSectionMachO::S_ATTR_LIVE_SUPPORT, + SectionKind::getReadOnly()); +} + const MCSection *TargetLoweringObjectFileMachO:: getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind, Mangler *Mang, const TargetMachine &TM) const { @@ -665,7 +663,7 @@ getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind, const MCSection *TargetLoweringObjectFileMachO:: SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, Mangler *Mang, const TargetMachine &TM) const { - + // Handle thread local data. if (Kind.isThreadBSS()) return TLSBSSSection; if (Kind.isThreadData()) return TLSDataSection; @@ -685,7 +683,7 @@ SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, if (Kind.isMergeable1ByteCString() && TM.getTargetData()->getPreferredAlignment(cast(GV)) < 32) return CStringSection; - + // Do not put 16-bit arrays in the UString section if they have an // externally visible label, this runs into issues with certain linker // versions. @@ -721,7 +719,7 @@ SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, // with the .zerofill directive (aka .lcomm). if (Kind.isBSSLocal()) return DataBSSSection; - + // Otherwise, just drop the variable in the normal data section. return DataSection; } @@ -858,13 +856,6 @@ void TargetLoweringObjectFileCOFF::Initialize(MCContext &Ctx, COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ, SectionKind::getReadOnly()); - EHFrameSection = - getContext().getCOFFSection(".eh_frame", - COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | - COFF::IMAGE_SCN_MEM_READ | - COFF::IMAGE_SCN_MEM_WRITE, - SectionKind::getDataRel()); - // Debug info. DwarfAbbrevSection = getContext().getCOFFSection(".debug_abbrev", @@ -928,6 +919,15 @@ void TargetLoweringObjectFileCOFF::Initialize(MCContext &Ctx, SectionKind::getMetadata()); } +const MCSection *TargetLoweringObjectFileCOFF::getEHFrameSection() const { + return getContext().getCOFFSection(".eh_frame", + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ | + COFF::IMAGE_SCN_MEM_WRITE, + SectionKind::getDataRel()); +} + + static unsigned getCOFFSectionFlags(SectionKind K) { unsigned Flags = 0; @@ -938,6 +938,7 @@ getCOFFSectionFlags(SectionKind K) { else if (K.isText()) Flags |= COFF::IMAGE_SCN_MEM_EXECUTE | + COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_CNT_CODE; else if (K.isBSS ()) Flags |= @@ -967,12 +968,12 @@ getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind, static const char *getCOFFSectionPrefixForUniqueGlobal(SectionKind Kind) { if (Kind.isText()) - return ".text$linkonce"; + return ".text$"; if (Kind.isBSS ()) - return ".bss$linkonce"; + return ".bss$"; if (Kind.isWriteable()) - return ".data$linkonce"; - return ".rdata$linkonce"; + return ".data$"; + return ".rdata$"; } @@ -987,14 +988,14 @@ SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, const char *Prefix = getCOFFSectionPrefixForUniqueGlobal(Kind); SmallString<128> Name(Prefix, Prefix+strlen(Prefix)); MCSymbol *Sym = Mang->getSymbol(GV); - Name.append(Sym->getName().begin(), Sym->getName().end()); + Name.append(Sym->getName().begin() + 1, Sym->getName().end()); unsigned Characteristics = getCOFFSectionFlags(Kind); Characteristics |= COFF::IMAGE_SCN_LNK_COMDAT; return getContext().getCOFFSection(Name.str(), Characteristics, - COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH, Kind); + COFF::IMAGE_COMDAT_SELECT_ANY, Kind); } if (Kind.isText()) diff --git a/lib/CodeGen/TwoAddressInstructionPass.cpp b/lib/CodeGen/TwoAddressInstructionPass.cpp index 78989c567e42..b3120b8be1ab 100644 --- a/lib/CodeGen/TwoAddressInstructionPass.cpp +++ b/lib/CodeGen/TwoAddressInstructionPass.cpp @@ -110,7 +110,7 @@ namespace { bool ConvertInstTo3Addr(MachineBasicBlock::iterator &mi, MachineBasicBlock::iterator &nmi, MachineFunction::iterator &mbbi, - unsigned RegB, unsigned Dist); + unsigned RegA, unsigned RegB, unsigned Dist); typedef std::pair, MachineInstr*> NewKill; bool canUpdateDeletedKills(SmallVector &Kills, @@ -138,7 +138,9 @@ namespace { public: static char ID; // Pass identification, replacement for typeid - TwoAddressInstructionPass() : MachineFunctionPass(ID) {} + TwoAddressInstructionPass() : MachineFunctionPass(ID) { + initializeTwoAddressInstructionPassPass(*PassRegistry::getPassRegistry()); + } virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.setPreservesCFG(); @@ -146,10 +148,7 @@ namespace { AU.addPreserved(); AU.addPreservedID(MachineLoopInfoID); AU.addPreservedID(MachineDominatorsID); - if (StrongPHIElim) - AU.addPreservedID(StrongPHIEliminationID); - else - AU.addPreservedID(PHIEliminationID); + AU.addPreservedID(PHIEliminationID); MachineFunctionPass::getAnalysisUsage(AU); } @@ -159,8 +158,11 @@ namespace { } char TwoAddressInstructionPass::ID = 0; -INITIALIZE_PASS(TwoAddressInstructionPass, "twoaddressinstruction", - "Two-Address instruction pass", false, false); +INITIALIZE_PASS_BEGIN(TwoAddressInstructionPass, "twoaddressinstruction", + "Two-Address instruction pass", false, false) +INITIALIZE_AG_DEPENDENCY(AliasAnalysis) +INITIALIZE_PASS_END(TwoAddressInstructionPass, "twoaddressinstruction", + "Two-Address instruction pass", false, false) char &llvm::TwoAddressInstructionPassID = TwoAddressInstructionPass::ID; @@ -548,8 +550,9 @@ TwoAddressInstructionPass::isProfitableToCommute(unsigned regB, unsigned regC, unsigned FromRegC = getMappedReg(regC, SrcRegMap); unsigned ToRegB = getMappedReg(regB, DstRegMap); unsigned ToRegC = getMappedReg(regC, DstRegMap); - if (!regsAreCompatible(FromRegB, ToRegB, TRI) && - (regsAreCompatible(FromRegB, ToRegC, TRI) || + if ((FromRegB && ToRegB && !regsAreCompatible(FromRegB, ToRegB, TRI)) && + ((!FromRegC && !ToRegC) || + regsAreCompatible(FromRegB, ToRegC, TRI) || regsAreCompatible(FromRegC, ToRegB, TRI))) return true; @@ -630,7 +633,8 @@ bool TwoAddressInstructionPass::ConvertInstTo3Addr(MachineBasicBlock::iterator &mi, MachineBasicBlock::iterator &nmi, MachineFunction::iterator &mbbi, - unsigned RegB, unsigned Dist) { + unsigned RegA, unsigned RegB, + unsigned Dist) { MachineInstr *NewMI = TII->convertToThreeAddress(mbbi, mi, LV); if (NewMI) { DEBUG(dbgs() << "2addr: CONVERTING 2-ADDR: " << *mi); @@ -650,6 +654,10 @@ TwoAddressInstructionPass::ConvertInstTo3Addr(MachineBasicBlock::iterator &mi, mi = NewMI; nmi = llvm::next(mi); } + + // Update source and destination register maps. + SrcRegMap.erase(RegA); + DstRegMap.erase(RegB); return true; } @@ -740,7 +748,7 @@ static bool isSafeToDelete(MachineInstr *MI, const TargetInstrDesc &TID = MI->getDesc(); if (TID.mayStore() || TID.isCall()) return false; - if (TID.isTerminator() || TID.hasUnmodeledSideEffects()) + if (TID.isTerminator() || MI->hasUnmodeledSideEffects()) return false; for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { @@ -884,7 +892,7 @@ TryInstructionTransform(MachineBasicBlock::iterator &mi, // three-address instruction. Check if it is profitable. if (!regBKilled || isProfitableToConv3Addr(regA)) { // Try to convert it. - if (ConvertInstTo3Addr(mi, nmi, mbbi, regB, Dist)) { + if (ConvertInstTo3Addr(mi, nmi, mbbi, regA, regB, Dist)) { ++NumConvertedTo3Addr; return true; // Done with this instruction. } @@ -951,7 +959,7 @@ TryInstructionTransform(MachineBasicBlock::iterator &mi, if (LV) { for (unsigned i = 0, e = mi->getNumOperands(); i != e; ++i) { MachineOperand &MO = mi->getOperand(i); - if (MO.isReg() && MO.getReg() != 0 && + if (MO.isReg() && TargetRegisterInfo::isVirtualRegister(MO.getReg())) { if (MO.isUse()) { if (MO.isKill()) { @@ -1013,8 +1021,7 @@ bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &MF) { << MF.getFunction()->getName() << '\n'); // ReMatRegs - Keep track of the registers whose def's are remat'ed. - BitVector ReMatRegs; - ReMatRegs.resize(MRI->getLastVirtReg()+1); + BitVector ReMatRegs(MRI->getNumVirtRegs()); typedef DenseMap, 4> > TiedOperandMap; @@ -1143,7 +1150,7 @@ bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &MF) { DEBUG(dbgs() << "2addr: REMATTING : " << *DefMI << "\n"); unsigned regASubIdx = mi->getOperand(DstIdx).getSubReg(); TII->reMaterialize(*mbbi, mi, regA, regASubIdx, DefMI, *TRI); - ReMatRegs.set(regB); + ReMatRegs.set(TargetRegisterInfo::virtReg2Index(regB)); ++NumReMats; } else { BuildMI(*mbbi, mi, mi->getDebugLoc(), TII->get(TargetOpcode::COPY), @@ -1229,13 +1236,12 @@ bool TwoAddressInstructionPass::runOnMachineFunction(MachineFunction &MF) { } // Some remat'ed instructions are dead. - int VReg = ReMatRegs.find_first(); - while (VReg != -1) { + for (int i = ReMatRegs.find_first(); i != -1; i = ReMatRegs.find_next(i)) { + unsigned VReg = TargetRegisterInfo::index2VirtReg(i); if (MRI->use_nodbg_empty(VReg)) { MachineInstr *DefMI = MRI->getVRegDef(VReg); DefMI->eraseFromParent(); } - VReg = ReMatRegs.find_next(VReg); } // Eliminate REG_SEQUENCE instructions. Their whole purpose was to preseve @@ -1346,7 +1352,6 @@ TwoAddressInstructionPass::CoalesceExtSubRegs(SmallVector &Srcs, continue; // Insert a copy to replace the original. - MachineBasicBlock::iterator InsertLoc = SomeMI; MachineInstr *CopyMI = BuildMI(*SomeMI->getParent(), SomeMI, SomeMI->getDebugLoc(), TII->get(TargetOpcode::COPY)) @@ -1412,6 +1417,7 @@ bool TwoAddressInstructionPass::EliminateRegSequences() { SmallSet Seen; for (unsigned i = 1, e = MI->getNumOperands(); i < e; i += 2) { unsigned SrcReg = MI->getOperand(i).getReg(); + unsigned SubIdx = MI->getOperand(i+1).getImm(); if (MI->getOperand(i).getSubReg() || TargetRegisterInfo::isPhysicalRegister(SrcReg)) { DEBUG(dbgs() << "Illegal REG_SEQUENCE instruction:" << *MI); @@ -1431,7 +1437,9 @@ bool TwoAddressInstructionPass::EliminateRegSequences() { bool isKill = MI->getOperand(i).isKill(); if (!Seen.insert(SrcReg) || MI->getParent() != DefMI->getParent() || - !isKill || HasOtherRegSequenceUses(SrcReg, MI, MRI)) { + !isKill || HasOtherRegSequenceUses(SrcReg, MI, MRI) || + !TRI->getMatchingSuperRegClass(MRI->getRegClass(DstReg), + MRI->getRegClass(SrcReg), SubIdx)) { // REG_SEQUENCE cannot have duplicated operands, add a copy. // Also add an copy if the source is live-in the block. We don't want // to end up with a partial-redef of a livein, e.g. @@ -1460,7 +1468,7 @@ bool TwoAddressInstructionPass::EliminateRegSequences() { MachineBasicBlock::iterator InsertLoc = MI; MachineInstr *CopyMI = BuildMI(*MI->getParent(), InsertLoc, MI->getDebugLoc(), TII->get(TargetOpcode::COPY)) - .addReg(DstReg, RegState::Define, MI->getOperand(i+1).getImm()) + .addReg(DstReg, RegState::Define, SubIdx) .addReg(SrcReg, getKillRegState(isKill)); MI->getOperand(i).setReg(0); if (LV && isKill) diff --git a/lib/CodeGen/UnreachableBlockElim.cpp b/lib/CodeGen/UnreachableBlockElim.cpp index 6dd333358bc4..48d8ab1658da 100644 --- a/lib/CodeGen/UnreachableBlockElim.cpp +++ b/lib/CodeGen/UnreachableBlockElim.cpp @@ -26,6 +26,7 @@ #include "llvm/Function.h" #include "llvm/Pass.h" #include "llvm/Type.h" +#include "llvm/Analysis/Dominators.h" #include "llvm/Analysis/ProfileInfo.h" #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineFunctionPass.h" @@ -43,16 +44,19 @@ namespace { virtual bool runOnFunction(Function &F); public: static char ID; // Pass identification, replacement for typeid - UnreachableBlockElim() : FunctionPass(ID) {} + UnreachableBlockElim() : FunctionPass(ID) { + initializeUnreachableBlockElimPass(*PassRegistry::getPassRegistry()); + } virtual void getAnalysisUsage(AnalysisUsage &AU) const { + AU.addPreserved(); AU.addPreserved(); } }; } char UnreachableBlockElim::ID = 0; INITIALIZE_PASS(UnreachableBlockElim, "unreachableblockelim", - "Remove unreachable blocks from the CFG", false, false); + "Remove unreachable blocks from the CFG", false, false) FunctionPass *llvm::createUnreachableBlockEliminationPass() { return new UnreachableBlockElim(); @@ -106,7 +110,7 @@ namespace { char UnreachableMachineBlockElim::ID = 0; INITIALIZE_PASS(UnreachableMachineBlockElim, "unreachable-mbb-elimination", - "Remove unreachable machine basic blocks", false, false); + "Remove unreachable machine basic blocks", false, false) char &llvm::UnreachableMachineBlockElimID = UnreachableMachineBlockElim::ID; @@ -118,6 +122,7 @@ void UnreachableMachineBlockElim::getAnalysisUsage(AnalysisUsage &AU) const { bool UnreachableMachineBlockElim::runOnMachineFunction(MachineFunction &F) { SmallPtrSet Reachable; + bool ModifiedPHI = false; MMI = getAnalysisIfAvailable(); MachineDominatorTree *MDT = getAnalysisIfAvailable(); @@ -179,6 +184,7 @@ bool UnreachableMachineBlockElim::runOnMachineFunction(MachineFunction &F) { if (!preds.count(phi->getOperand(i).getMBB())) { phi->RemoveOperand(i); phi->RemoveOperand(i-1); + ModifiedPHI = true; } if (phi->getNumOperands() == 3) { @@ -188,6 +194,7 @@ bool UnreachableMachineBlockElim::runOnMachineFunction(MachineFunction &F) { MachineInstr* temp = phi; ++phi; temp->eraseFromParent(); + ModifiedPHI = true; if (Input != Output) F.getRegInfo().replaceRegWith(Output, Input); @@ -201,5 +208,5 @@ bool UnreachableMachineBlockElim::runOnMachineFunction(MachineFunction &F) { F.RenumberBlocks(); - return DeadBlocks.size(); + return (DeadBlocks.size() || ModifiedPHI); } diff --git a/lib/CodeGen/VirtRegMap.cpp b/lib/CodeGen/VirtRegMap.cpp index 20ffcffa70d3..734b87e62f62 100644 --- a/lib/CodeGen/VirtRegMap.cpp +++ b/lib/CodeGen/VirtRegMap.cpp @@ -24,6 +24,7 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SlotIndexes.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetRegisterInfo.h" @@ -48,7 +49,7 @@ STATISTIC(NumSpills , "Number of register spills"); char VirtRegMap::ID = 0; -INITIALIZE_PASS(VirtRegMap, "virtregmap", "Virtual Register Map", false, false); +INITIALIZE_PASS(VirtRegMap, "virtregmap", "Virtual Register Map", false, false) bool VirtRegMap::runOnMachineFunction(MachineFunction &mf) { MRI = &mf.getRegInfo(); @@ -74,8 +75,7 @@ bool VirtRegMap::runOnMachineFunction(MachineFunction &mf) { EmergencySpillSlots.clear(); SpillSlotToUsesMap.resize(8); - ImplicitDefed.resize(MF->getRegInfo().getLastVirtReg()+1- - TargetRegisterInfo::FirstVirtualRegister); + ImplicitDefed.resize(MF->getRegInfo().getNumVirtRegs()); allocatableRCRegs.clear(); for (TargetRegisterInfo::regclass_iterator I = TRI->regclass_begin(), @@ -89,24 +89,37 @@ bool VirtRegMap::runOnMachineFunction(MachineFunction &mf) { } void VirtRegMap::grow() { - unsigned LastVirtReg = MF->getRegInfo().getLastVirtReg(); - Virt2PhysMap.grow(LastVirtReg); - Virt2StackSlotMap.grow(LastVirtReg); - Virt2ReMatIdMap.grow(LastVirtReg); - Virt2SplitMap.grow(LastVirtReg); - Virt2SplitKillMap.grow(LastVirtReg); - ReMatMap.grow(LastVirtReg); - ImplicitDefed.resize(LastVirtReg-TargetRegisterInfo::FirstVirtualRegister+1); + unsigned NumRegs = MF->getRegInfo().getNumVirtRegs(); + Virt2PhysMap.resize(NumRegs); + Virt2StackSlotMap.resize(NumRegs); + Virt2ReMatIdMap.resize(NumRegs); + Virt2SplitMap.resize(NumRegs); + Virt2SplitKillMap.resize(NumRegs); + ReMatMap.resize(NumRegs); + ImplicitDefed.resize(NumRegs); +} + +unsigned VirtRegMap::createSpillSlot(const TargetRegisterClass *RC) { + int SS = MF->getFrameInfo()->CreateSpillStackObject(RC->getSize(), + RC->getAlignment()); + if (LowSpillSlot == NO_STACK_SLOT) + LowSpillSlot = SS; + if (HighSpillSlot == NO_STACK_SLOT || SS > HighSpillSlot) + HighSpillSlot = SS; + assert(SS >= LowSpillSlot && "Unexpected low spill slot"); + unsigned Idx = SS-LowSpillSlot; + while (Idx >= SpillSlotToUsesMap.size()) + SpillSlotToUsesMap.resize(SpillSlotToUsesMap.size()*2); + return SS; } unsigned VirtRegMap::getRegAllocPref(unsigned virtReg) { std::pair Hint = MRI->getRegAllocationHint(virtReg); unsigned physReg = Hint.second; - if (physReg && - TargetRegisterInfo::isVirtualRegister(physReg) && hasPhys(physReg)) + if (TargetRegisterInfo::isVirtualRegister(physReg) && hasPhys(physReg)) physReg = getPhys(physReg); if (Hint.first == 0) - return (physReg && TargetRegisterInfo::isPhysicalRegister(physReg)) + return (TargetRegisterInfo::isPhysicalRegister(physReg)) ? physReg : 0; return TRI->ResolveRegAllocHint(Hint.first, physReg, *MF); } @@ -116,18 +129,8 @@ int VirtRegMap::assignVirt2StackSlot(unsigned virtReg) { assert(Virt2StackSlotMap[virtReg] == NO_STACK_SLOT && "attempt to assign stack slot to already spilled register"); const TargetRegisterClass* RC = MF->getRegInfo().getRegClass(virtReg); - int SS = MF->getFrameInfo()->CreateSpillStackObject(RC->getSize(), - RC->getAlignment()); - if (LowSpillSlot == NO_STACK_SLOT) - LowSpillSlot = SS; - if (HighSpillSlot == NO_STACK_SLOT || SS > HighSpillSlot) - HighSpillSlot = SS; - unsigned Idx = SS-LowSpillSlot; - while (Idx >= SpillSlotToUsesMap.size()) - SpillSlotToUsesMap.resize(SpillSlotToUsesMap.size()*2); - Virt2StackSlotMap[virtReg] = SS; ++NumSpills; - return SS; + return Virt2StackSlotMap[virtReg] = createSpillSlot(RC); } void VirtRegMap::assignVirt2StackSlot(unsigned virtReg, int SS) { @@ -160,14 +163,7 @@ int VirtRegMap::getEmergencySpillSlot(const TargetRegisterClass *RC) { EmergencySpillSlots.find(RC); if (I != EmergencySpillSlots.end()) return I->second; - int SS = MF->getFrameInfo()->CreateSpillStackObject(RC->getSize(), - RC->getAlignment()); - if (LowSpillSlot == NO_STACK_SLOT) - LowSpillSlot = SS; - if (HighSpillSlot == NO_STACK_SLOT || SS > HighSpillSlot) - HighSpillSlot = SS; - EmergencySpillSlots[RC] = SS; - return SS; + return EmergencySpillSlots[RC] = createSpillSlot(RC); } void VirtRegMap::addSpillSlotUse(int FI, MachineInstr *MI) { @@ -232,10 +228,11 @@ bool VirtRegMap::FindUnusedRegisters(LiveIntervals* LIs) { UnusedRegs.resize(NumRegs); BitVector Used(NumRegs); - for (unsigned i = TargetRegisterInfo::FirstVirtualRegister, - e = MF->getRegInfo().getLastVirtReg(); i <= e; ++i) - if (Virt2PhysMap[i] != (unsigned)VirtRegMap::NO_PHYS_REG) - Used.set(Virt2PhysMap[i]); + for (unsigned i = 0, e = MRI->getNumVirtRegs(); i != e; ++i) { + unsigned Reg = TargetRegisterInfo::index2VirtReg(i); + if (Virt2PhysMap[Reg] != (unsigned)VirtRegMap::NO_PHYS_REG) + Used.set(Virt2PhysMap[Reg]); + } BitVector Allocatable = TRI->getAllocatableSet(*MF); bool AnyUnused = false; @@ -258,23 +255,97 @@ bool VirtRegMap::FindUnusedRegisters(LiveIntervals* LIs) { return AnyUnused; } +void VirtRegMap::rewrite(SlotIndexes *Indexes) { + DEBUG(dbgs() << "********** REWRITE VIRTUAL REGISTERS **********\n" + << "********** Function: " + << MF->getFunction()->getName() << '\n'); + + SmallVector SuperKills; + + for (MachineFunction::iterator MBBI = MF->begin(), MBBE = MF->end(); + MBBI != MBBE; ++MBBI) { + DEBUG(MBBI->print(dbgs(), Indexes)); + for (MachineBasicBlock::iterator MII = MBBI->begin(), MIE = MBBI->end(); + MII != MIE;) { + MachineInstr *MI = MII; + ++MII; + + for (MachineInstr::mop_iterator MOI = MI->operands_begin(), + MOE = MI->operands_end(); MOI != MOE; ++MOI) { + MachineOperand &MO = *MOI; + if (!MO.isReg() || !TargetRegisterInfo::isVirtualRegister(MO.getReg())) + continue; + unsigned VirtReg = MO.getReg(); + unsigned PhysReg = getPhys(VirtReg); + assert(PhysReg != NO_PHYS_REG && "Instruction uses unmapped VirtReg"); + + // Preserve semantics of sub-register operands. + if (MO.getSubReg()) { + // A virtual register kill refers to the whole register, so we may + // have to add operands for the super-register. + if (MO.isUse() && MO.isKill() && !MO.isUndef()) + SuperKills.push_back(PhysReg); + + // We don't have to deal with sub-register defs because + // LiveIntervalAnalysis already added the necessary + // operands. + + // PhysReg operands cannot have subregister indexes. + PhysReg = TRI->getSubReg(PhysReg, MO.getSubReg()); + assert(PhysReg && "Invalid SubReg for physical register"); + MO.setSubReg(0); + } + // Rewrite. Note we could have used MachineOperand::substPhysReg(), but + // we need the inlining here. + MO.setReg(PhysReg); + } + + // Add any missing super-register kills after rewriting the whole + // instruction. + while (!SuperKills.empty()) + MI->addRegisterKilled(SuperKills.pop_back_val(), TRI, true); + + DEBUG(dbgs() << "> " << *MI); + + // Finally, remove any identity copies. + if (MI->isIdentityCopy()) { + DEBUG(dbgs() << "Deleting identity copy.\n"); + RemoveMachineInstrFromMaps(MI); + if (Indexes) + Indexes->removeMachineInstrFromMaps(MI); + // It's safe to erase MI because MII has already been incremented. + MI->eraseFromParent(); + } + } + } + + // Tell MRI about physical registers in use. + for (unsigned Reg = 1, RegE = TRI->getNumRegs(); Reg != RegE; ++Reg) + if (!MRI->reg_nodbg_empty(Reg)) + MRI->setPhysRegUsed(Reg); +} + void VirtRegMap::print(raw_ostream &OS, const Module* M) const { const TargetRegisterInfo* TRI = MF->getTarget().getRegisterInfo(); const MachineRegisterInfo &MRI = MF->getRegInfo(); OS << "********** REGISTER MAP **********\n"; - for (unsigned i = TargetRegisterInfo::FirstVirtualRegister, - e = MF->getRegInfo().getLastVirtReg(); i <= e; ++i) { - if (Virt2PhysMap[i] != (unsigned)VirtRegMap::NO_PHYS_REG) - OS << "[reg" << i << " -> " << TRI->getName(Virt2PhysMap[i]) - << "] " << MRI.getRegClass(i)->getName() << "\n"; + for (unsigned i = 0, e = MRI.getNumVirtRegs(); i != e; ++i) { + unsigned Reg = TargetRegisterInfo::index2VirtReg(i); + if (Virt2PhysMap[Reg] != (unsigned)VirtRegMap::NO_PHYS_REG) { + OS << '[' << PrintReg(Reg, TRI) << " -> " + << PrintReg(Virt2PhysMap[Reg], TRI) << "] " + << MRI.getRegClass(Reg)->getName() << "\n"; + } } - for (unsigned i = TargetRegisterInfo::FirstVirtualRegister, - e = MF->getRegInfo().getLastVirtReg(); i <= e; ++i) - if (Virt2StackSlotMap[i] != VirtRegMap::NO_STACK_SLOT) - OS << "[reg" << i << " -> fi#" << Virt2StackSlotMap[i] - << "] " << MRI.getRegClass(i)->getName() << "\n"; + for (unsigned i = 0, e = MRI.getNumVirtRegs(); i != e; ++i) { + unsigned Reg = TargetRegisterInfo::index2VirtReg(i); + if (Virt2StackSlotMap[Reg] != VirtRegMap::NO_STACK_SLOT) { + OS << '[' << PrintReg(Reg, TRI) << " -> fi#" << Virt2StackSlotMap[Reg] + << "] " << MRI.getRegClass(Reg)->getName() << "\n"; + } + } OS << '\n'; } diff --git a/lib/CodeGen/VirtRegMap.h b/lib/CodeGen/VirtRegMap.h index 8b6082d18193..ba50f4e42302 100644 --- a/lib/CodeGen/VirtRegMap.h +++ b/lib/CodeGen/VirtRegMap.h @@ -35,6 +35,7 @@ namespace llvm { class TargetInstrInfo; class TargetRegisterInfo; class raw_ostream; + class SlotIndexes; class VirtRegMap : public MachineFunctionPass { public: @@ -80,7 +81,7 @@ namespace llvm { /// Virt2SplitKillMap - This is splitted virtual register to its last use /// (kill) index mapping. - IndexedMap Virt2SplitKillMap; + IndexedMap Virt2SplitKillMap; /// ReMatMap - This is virtual register to re-materialized instruction /// mapping. Each virtual register whose definition is going to be @@ -134,6 +135,9 @@ namespace llvm { /// UnusedRegs - A list of physical registers that have not been used. BitVector UnusedRegs; + /// createSpillSlot - Allocate a spill slot for RC from MFI. + unsigned createSpillSlot(const TargetRegisterClass *RC); + VirtRegMap(const VirtRegMap&); // DO NOT IMPLEMENT void operator=(const VirtRegMap&); // DO NOT IMPLEMENT @@ -153,10 +157,13 @@ namespace llvm { } MachineFunction &getMachineFunction() const { - assert(MF && "getMachineFunction called before runOnMAchineFunction"); + assert(MF && "getMachineFunction called before runOnMachineFunction"); return *MF; } + MachineRegisterInfo &getRegInfo() const { return *MRI; } + const TargetRegisterInfo &getTargetRegInfo() const { return *TRI; } + void grow(); /// @brief returns true if the specified virtual register is @@ -207,10 +214,19 @@ namespace llvm { } /// @brief returns the live interval virtReg is split from. - unsigned getPreSplitReg(unsigned virtReg) { + unsigned getPreSplitReg(unsigned virtReg) const { return Virt2SplitMap[virtReg]; } + /// getOriginal - Return the original virtual register that VirtReg descends + /// from through splitting. + /// A register that was not created by splitting is its own original. + /// This operation is idempotent. + unsigned getOriginal(unsigned VirtReg) const { + unsigned Orig = getPreSplitReg(VirtReg); + return Orig ? Orig : VirtReg; + } + /// @brief returns true if the specified virtual register is not /// mapped to a stack slot or rematerialized. bool isAssignedReg(unsigned virtReg) const { @@ -426,12 +442,12 @@ namespace llvm { /// @brief Mark the specified register as being implicitly defined. void setIsImplicitlyDefined(unsigned VirtReg) { - ImplicitDefed.set(VirtReg-TargetRegisterInfo::FirstVirtualRegister); + ImplicitDefed.set(TargetRegisterInfo::virtReg2Index(VirtReg)); } /// @brief Returns true if the virtual register is implicitly defined. bool isImplicitlyDefined(unsigned VirtReg) const { - return ImplicitDefed[VirtReg-TargetRegisterInfo::FirstVirtualRegister]; + return ImplicitDefed[TargetRegisterInfo::virtReg2Index(VirtReg)]; } /// @brief Updates information about the specified virtual register's value @@ -487,6 +503,13 @@ namespace llvm { return 0; } + /// rewrite - Rewrite all instructions in MF to use only physical registers + /// by mapping all virtual register operands to their assigned physical + /// registers. + /// + /// @param Indexes Optionally remove deleted instructions from indexes. + void rewrite(SlotIndexes *Indexes); + void print(raw_ostream &OS, const Module* M = 0) const; void dump() const; }; diff --git a/lib/CodeGen/VirtRegRewriter.cpp b/lib/CodeGen/VirtRegRewriter.cpp index 240d28cf3011..458a2134bf4a 100644 --- a/lib/CodeGen/VirtRegRewriter.cpp +++ b/lib/CodeGen/VirtRegRewriter.cpp @@ -22,8 +22,8 @@ #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetLowering.h" #include "llvm/ADT/DepthFirstIterator.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" -#include using namespace llvm; STATISTIC(NumDSE , "Number of dead stores elided"); @@ -216,7 +216,8 @@ public: << SlotOrReMat-VirtRegMap::MAX_STACK_SLOT-1); else DEBUG(dbgs() << "Remembering SS#" << SlotOrReMat); - DEBUG(dbgs() << " in physreg " << TRI->getName(Reg) << "\n"); + DEBUG(dbgs() << " in physreg " << TRI->getName(Reg) + << (CanClobber ? " canclobber" : "") << "\n"); } /// canClobberPhysRegForSS - Return true if the spiller is allowed to change @@ -297,7 +298,7 @@ ComputeReloadLoc(MachineBasicBlock::iterator const InsertLoc, const TargetLowering *TL = MF.getTarget().getTargetLowering(); if (!TL->isTypeLegal(TL->getPointerTy())) - // Believe it or not, this is true on PIC16. + // Believe it or not, this is true on 16-bit targets like PIC16. return InsertLoc; const TargetRegisterClass *ptrRegClass = @@ -462,25 +463,70 @@ static void findSinglePredSuccessor(MachineBasicBlock *MBB, } } -/// InvalidateKill - Invalidate register kill information for a specific -/// register. This also unsets the kills marker on the last kill operand. -static void InvalidateKill(unsigned Reg, - const TargetRegisterInfo* TRI, - BitVector &RegKills, - std::vector &KillOps) { - if (RegKills[Reg]) { - KillOps[Reg]->setIsKill(false); - // KillOps[Reg] might be a def of a super-register. - unsigned KReg = KillOps[Reg]->getReg(); - KillOps[KReg] = NULL; - RegKills.reset(KReg); - for (const unsigned *SR = TRI->getSubRegisters(KReg); *SR; ++SR) { - if (RegKills[*SR]) { - KillOps[*SR]->setIsKill(false); - KillOps[*SR] = NULL; - RegKills.reset(*SR); - } - } +/// ResurrectConfirmedKill - Helper for ResurrectKill. This register is killed +/// but not re-defined and it's being reused. Remove the kill flag for the +/// register and unset the kill's marker and last kill operand. +static void ResurrectConfirmedKill(unsigned Reg, const TargetRegisterInfo* TRI, + BitVector &RegKills, + std::vector &KillOps) { + DEBUG(dbgs() << "Resurrect " << TRI->getName(Reg) << "\n"); + + MachineOperand *KillOp = KillOps[Reg]; + KillOp->setIsKill(false); + // KillOps[Reg] might be a def of a super-register. + unsigned KReg = KillOp->getReg(); + if (!RegKills[KReg]) + return; + + assert(KillOps[KReg] == KillOp && "invalid superreg kill flags"); + KillOps[KReg] = NULL; + RegKills.reset(KReg); + + // If it's a def of a super-register. Its other sub-regsters are no + // longer killed as well. + for (const unsigned *SR = TRI->getSubRegisters(KReg); *SR; ++SR) { + DEBUG(dbgs() << " Resurrect subreg " << TRI->getName(*SR) << "\n"); + + assert(KillOps[*SR] == KillOp && "invalid subreg kill flags"); + KillOps[*SR] = NULL; + RegKills.reset(*SR); + } +} + +/// ResurrectKill - Invalidate kill info associated with a previous MI. An +/// optimization may have decided that it's safe to reuse a previously killed +/// register. If we fail to erase the invalid kill flags, then the register +/// scavenger may later clobber the register used by this MI. Note that this +/// must be done even if this MI is being deleted! Consider: +/// +/// USE $r1 (vreg1) +/// ... +/// $r1(vreg3) = COPY $r1 (vreg2) +/// +/// RegAlloc has smartly assigned all three vregs to the same physreg. Initially +/// vreg1's only use is a kill. The rewriter doesn't know it should be live +/// until it rewrites vreg2. At that points it sees that the copy is dead and +/// deletes it. However, deleting the copy implicitly forwards liveness of $r1 +/// (it's copy coalescing). We must resurrect $r1 by removing the kill flag at +/// vreg1 before deleting the copy. +static void ResurrectKill(MachineInstr &MI, unsigned Reg, + const TargetRegisterInfo* TRI, BitVector &RegKills, + std::vector &KillOps) { + if (RegKills[Reg] && KillOps[Reg]->getParent() != &MI) { + ResurrectConfirmedKill(Reg, TRI, RegKills, KillOps); + return; + } + // No previous kill for this reg. Check for subreg kills as well. + // d4 = + // store d4, fi#0 + // ... + // = s8 + // ... + // = d4 + for (const unsigned *SR = TRI->getSubRegisters(Reg); *SR; ++SR) { + unsigned SReg = *SR; + if (RegKills[SReg] && KillOps[SReg]->getParent() != &MI) + ResurrectConfirmedKill(SReg, TRI, RegKills, KillOps); } } @@ -502,15 +548,22 @@ static void InvalidateKills(MachineInstr &MI, KillRegs->push_back(Reg); assert(Reg < KillOps.size()); if (KillOps[Reg] == &MO) { + // This operand was the kill, now no longer. KillOps[Reg] = NULL; RegKills.reset(Reg); for (const unsigned *SR = TRI->getSubRegisters(Reg); *SR; ++SR) { if (RegKills[*SR]) { + assert(KillOps[*SR] == &MO && "bad subreg kill flags"); KillOps[*SR] = NULL; RegKills.reset(*SR); } } } + else { + // This operand may have reused a previously killed reg. Keep it live in + // case it continues to be used after erasing this instruction. + ResurrectKill(MI, Reg, TRI, RegKills, KillOps); + } } } @@ -578,44 +631,8 @@ static void UpdateKills(MachineInstr &MI, const TargetRegisterInfo* TRI, if (Reg == 0) continue; - if (RegKills[Reg] && KillOps[Reg]->getParent() != &MI) { - // That can't be right. Register is killed but not re-defined and it's - // being reused. Let's fix that. - KillOps[Reg]->setIsKill(false); - // KillOps[Reg] might be a def of a super-register. - unsigned KReg = KillOps[Reg]->getReg(); - KillOps[KReg] = NULL; - RegKills.reset(KReg); - - // Must be a def of a super-register. Its other sub-regsters are no - // longer killed as well. - for (const unsigned *SR = TRI->getSubRegisters(KReg); *SR; ++SR) { - KillOps[*SR] = NULL; - RegKills.reset(*SR); - } - } else { - // Check for subreg kills as well. - // d4 = - // store d4, fi#0 - // ... - // = s8 - // ... - // = d4 - for (const unsigned *SR = TRI->getSubRegisters(Reg); *SR; ++SR) { - unsigned SReg = *SR; - if (RegKills[SReg] && KillOps[SReg]->getParent() != &MI) { - KillOps[SReg]->setIsKill(false); - unsigned KReg = KillOps[SReg]->getReg(); - KillOps[KReg] = NULL; - RegKills.reset(KReg); - - for (const unsigned *SSR = TRI->getSubRegisters(KReg); *SSR; ++SSR) { - KillOps[*SSR] = NULL; - RegKills.reset(*SSR); - } - } - } - } + // This operand may have reused a previously killed reg. Keep it live. + ResurrectKill(MI, Reg, TRI, RegKills, KillOps); if (MO.isKill()) { RegKills.set(Reg); @@ -770,7 +787,8 @@ void AvailableSpills::AddAvailableRegsToLiveIn(MachineBasicBlock &MBB, NotAvailable.insert(Reg); else { MBB.addLiveIn(Reg); - InvalidateKill(Reg, TRI, RegKills, KillOps); + if (RegKills[Reg]) + ResurrectConfirmedKill(Reg, TRI, RegKills, KillOps); } // Skip over the same register. @@ -1056,6 +1074,7 @@ class LocalRewriter : public VirtRegRewriter { const TargetRegisterInfo *TRI; const TargetInstrInfo *TII; VirtRegMap *VRM; + LiveIntervals *LIs; BitVector AllocatableRegs; DenseMap DistanceMap; DenseMap > Slot2DbgValues; @@ -1068,6 +1087,11 @@ public: LiveIntervals* LIs); private: + void EraseInstr(MachineInstr *MI) { + VRM->RemoveMachineInstrFromMaps(MI); + LIs->RemoveMachineInstrFromMaps(MI); + MI->eraseFromParent(); + } bool OptimizeByUnfold2(unsigned VirtReg, int SS, MachineBasicBlock::iterator &MII, @@ -1110,6 +1134,12 @@ private: bool InsertSpills(MachineInstr *MI); + void ProcessUses(MachineInstr &MI, AvailableSpills &Spills, + std::vector &MaybeDeadStores, + BitVector &RegKills, + ReuseInfo &ReusedOperands, + std::vector &KillOps); + void RewriteMBB(LiveIntervals *LIs, AvailableSpills &Spills, BitVector &RegKills, std::vector &KillOps); @@ -1117,17 +1147,18 @@ private: } bool LocalRewriter::runOnMachineFunction(MachineFunction &MF, VirtRegMap &vrm, - LiveIntervals* LIs) { + LiveIntervals* lis) { MRI = &MF.getRegInfo(); TRI = MF.getTarget().getRegisterInfo(); TII = MF.getTarget().getInstrInfo(); VRM = &vrm; + LIs = lis; AllocatableRegs = TRI->getAllocatableSet(MF); DEBUG(dbgs() << "\n**** Local spiller rewriting function '" << MF.getFunction()->getName() << "':\n"); DEBUG(dbgs() << "**** Machine Instrs (NOTE! Does not include spills and" " reloads!) ****\n"); - DEBUG(MF.dump()); + DEBUG(MF.print(dbgs(), LIs->getSlotIndexes())); // Spills - Keep track of which spilled values are available in physregs // so that we can choose to reuse the physregs instead of emitting @@ -1178,7 +1209,7 @@ bool LocalRewriter::runOnMachineFunction(MachineFunction &MF, VirtRegMap &vrm, } DEBUG(dbgs() << "**** Post Machine Instrs ****\n"); - DEBUG(MF.dump()); + DEBUG(MF.print(dbgs(), LIs->getSlotIndexes())); // Mark unused spill slots. MachineFrameInfo *MFI = MF.getFrameInfo(); @@ -1190,10 +1221,8 @@ bool LocalRewriter::runOnMachineFunction(MachineFunction &MF, VirtRegMap &vrm, MFI->RemoveStackObject(SS); for (unsigned j = 0, ee = DbgValues.size(); j != ee; ++j) { MachineInstr *DVMI = DbgValues[j]; - MachineBasicBlock *DVMBB = DVMI->getParent(); DEBUG(dbgs() << "Removing debug info referencing FI#" << SS << '\n'); - VRM->RemoveMachineInstrFromMaps(DVMI); - DVMBB->erase(DVMI); + EraseInstr(DVMI); } ++NumDSS; } @@ -1273,8 +1302,7 @@ OptimizeByUnfold2(unsigned VirtReg, int SS, VRM->transferRestorePts(&MI, NewMIs[0]); MII = MBB->insert(MII, NewMIs[0]); InvalidateKills(MI, TRI, RegKills, KillOps); - VRM->RemoveMachineInstrFromMaps(&MI); - MBB->erase(&MI); + EraseInstr(&MI); ++NumModRefUnfold; // Unfold next instructions that fold the same SS. @@ -1289,8 +1317,7 @@ OptimizeByUnfold2(unsigned VirtReg, int SS, VRM->transferRestorePts(&NextMI, NewMIs[0]); MBB->insert(NextMII, NewMIs[0]); InvalidateKills(NextMI, TRI, RegKills, KillOps); - VRM->RemoveMachineInstrFromMaps(&NextMI); - MBB->erase(&NextMI); + EraseInstr(&NextMI); ++NumModRefUnfold; // Skip over dbg_value instructions. while (NextMII != MBB->end() && NextMII->isDebugValue()) @@ -1417,8 +1444,7 @@ OptimizeByUnfold(MachineBasicBlock::iterator &MII, VRM->virtFolded(VirtReg, FoldedMI, VirtRegMap::isRef); MII = FoldedMI; InvalidateKills(MI, TRI, RegKills, KillOps); - VRM->RemoveMachineInstrFromMaps(&MI); - MBB->erase(&MI); + EraseInstr(&MI); return true; } } @@ -1524,14 +1550,11 @@ CommuteToFoldReload(MachineBasicBlock::iterator &MII, // Delete all 3 old instructions. InvalidateKills(*ReloadMI, TRI, RegKills, KillOps); - VRM->RemoveMachineInstrFromMaps(ReloadMI); - MBB->erase(ReloadMI); + EraseInstr(ReloadMI); InvalidateKills(*DefMI, TRI, RegKills, KillOps); - VRM->RemoveMachineInstrFromMaps(DefMI); - MBB->erase(DefMI); + EraseInstr(DefMI); InvalidateKills(MI, TRI, RegKills, KillOps); - VRM->RemoveMachineInstrFromMaps(&MI); - MBB->erase(&MI); + EraseInstr(&MI); // If NewReg was previously holding value of some SS, it's now clobbered. // This has to be done now because it's a physical register. When this @@ -1574,8 +1597,7 @@ SpillRegToStackSlot(MachineBasicBlock::iterator &MII, bool CheckDef = PrevMII != MBB->begin(); if (CheckDef) --PrevMII; - VRM->RemoveMachineInstrFromMaps(LastStore); - MBB->erase(LastStore); + EraseInstr(LastStore); if (CheckDef) { // Look at defs of killed registers on the store. Mark the defs // as dead since the store has been deleted and they aren't @@ -1586,8 +1608,7 @@ SpillRegToStackSlot(MachineBasicBlock::iterator &MII, MachineInstr *DeadDef = PrevMII; if (ReMatDefs.count(DeadDef) && !HasOtherDef) { // FIXME: This assumes a remat def does not have side effects. - VRM->RemoveMachineInstrFromMaps(DeadDef); - MBB->erase(DeadDef); + EraseInstr(DeadDef); ++NumDRM; } } @@ -1612,10 +1633,18 @@ SpillRegToStackSlot(MachineBasicBlock::iterator &MII, /// effect and all of its defs are dead. static bool isSafeToDelete(MachineInstr &MI) { const TargetInstrDesc &TID = MI.getDesc(); - if (TID.mayLoad() || TID.mayStore() || TID.isCall() || TID.isTerminator() || + if (TID.mayLoad() || TID.mayStore() || TID.isTerminator() || TID.isCall() || TID.isBarrier() || TID.isReturn() || - TID.hasUnmodeledSideEffects()) + MI.isLabel() || MI.isDebugValue() || + MI.hasUnmodeledSideEffects()) return false; + + // Technically speaking inline asm without side effects and no defs can still + // be deleted. But there is so much bad inline asm code out there, we should + // let them be. + if (MI.isInlineAsm()) + return false; + for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { MachineOperand &MO = MI.getOperand(i); if (!MO.isReg() || !MO.getReg()) @@ -1675,8 +1704,7 @@ TransferDeadness(unsigned Reg, BitVector &RegKills, LastUD->setIsDead(); break; } - VRM->RemoveMachineInstrFromMaps(LastUDMI); - MBB->erase(LastUDMI); + EraseInstr(LastUDMI); } else { LastUD->setIsKill(); RegKills.set(Reg); @@ -1764,6 +1792,10 @@ bool LocalRewriter::InsertRestores(MachineInstr *MI, << TRI->getName(InReg) << " for vreg" << VirtReg <<" instead of reloading into physreg " << TRI->getName(Phys) << '\n'); + + // Reusing a physreg may resurrect it. But we expect ProcessUses to update + // the kill flags for the current instruction after processing it. + ++NumOmitted; continue; } else if (InReg && InReg != Phys) { @@ -1828,7 +1860,7 @@ bool LocalRewriter::InsertRestores(MachineInstr *MI, return true; } -/// InsertEmergencySpills - Insert spills after MI if requested by VRM. Return +/// InsertSpills - Insert spills after MI if requested by VRM. Return /// true if spills were inserted. bool LocalRewriter::InsertSpills(MachineInstr *MI) { if (!VRM->isSpillPt(MI)) @@ -1856,6 +1888,349 @@ bool LocalRewriter::InsertSpills(MachineInstr *MI) { } +/// ProcessUses - Process all of MI's spilled operands and all available +/// operands. +void LocalRewriter::ProcessUses(MachineInstr &MI, AvailableSpills &Spills, + std::vector &MaybeDeadStores, + BitVector &RegKills, + ReuseInfo &ReusedOperands, + std::vector &KillOps) { + // Clear kill info. + SmallSet KilledMIRegs; + SmallVector VirtUseOps; + for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { + MachineOperand &MO = MI.getOperand(i); + if (!MO.isReg() || MO.getReg() == 0) + continue; // Ignore non-register operands. + + unsigned VirtReg = MO.getReg(); + + if (TargetRegisterInfo::isPhysicalRegister(VirtReg)) { + // Ignore physregs for spilling, but remember that it is used by this + // function. + MRI->setPhysRegUsed(VirtReg); + continue; + } + + // We want to process implicit virtual register uses first. + if (MO.isImplicit()) + // If the virtual register is implicitly defined, emit a implicit_def + // before so scavenger knows it's "defined". + // FIXME: This is a horrible hack done the by register allocator to + // remat a definition with virtual register operand. + VirtUseOps.insert(VirtUseOps.begin(), i); + else + VirtUseOps.push_back(i); + + // A partial def causes problems because the same operand both reads and + // writes the register. This rewriter is designed to rewrite uses and defs + // separately, so a partial def would already have been rewritten to a + // physreg by the time we get to processing defs. + // Add an implicit use operand to model the partial def. + if (MO.isDef() && MO.getSubReg() && MI.readsVirtualRegister(VirtReg) && + MI.findRegisterUseOperandIdx(VirtReg) == -1) { + VirtUseOps.insert(VirtUseOps.begin(), MI.getNumOperands()); + MI.addOperand(MachineOperand::CreateReg(VirtReg, + false, // isDef + true)); // isImplicit + DEBUG(dbgs() << "Partial redef: " << MI); + } + } + + // Process all of the spilled uses and all non spilled reg references. + SmallVector PotentialDeadStoreSlots; + KilledMIRegs.clear(); + for (unsigned j = 0, e = VirtUseOps.size(); j != e; ++j) { + unsigned i = VirtUseOps[j]; + unsigned VirtReg = MI.getOperand(i).getReg(); + assert(TargetRegisterInfo::isVirtualRegister(VirtReg) && + "Not a virtual register?"); + + unsigned SubIdx = MI.getOperand(i).getSubReg(); + if (VRM->isAssignedReg(VirtReg)) { + // This virtual register was assigned a physreg! + unsigned Phys = VRM->getPhys(VirtReg); + MRI->setPhysRegUsed(Phys); + if (MI.getOperand(i).isDef()) + ReusedOperands.markClobbered(Phys); + substitutePhysReg(MI.getOperand(i), Phys, *TRI); + if (VRM->isImplicitlyDefined(VirtReg)) + // FIXME: Is this needed? + BuildMI(*MBB, &MI, MI.getDebugLoc(), + TII->get(TargetOpcode::IMPLICIT_DEF), Phys); + continue; + } + + // This virtual register is now known to be a spilled value. + if (!MI.getOperand(i).isUse()) + continue; // Handle defs in the loop below (handle use&def here though) + + bool AvoidReload = MI.getOperand(i).isUndef(); + // Check if it is defined by an implicit def. It should not be spilled. + // Note, this is for correctness reason. e.g. + // 8 %reg1024 = IMPLICIT_DEF + // 12 %reg1024 = INSERT_SUBREG %reg1024, %reg1025, 2 + // The live range [12, 14) are not part of the r1024 live interval since + // it's defined by an implicit def. It will not conflicts with live + // interval of r1025. Now suppose both registers are spilled, you can + // easily see a situation where both registers are reloaded before + // the INSERT_SUBREG and both target registers that would overlap. + bool DoReMat = VRM->isReMaterialized(VirtReg); + int SSorRMId = DoReMat + ? VRM->getReMatId(VirtReg) : VRM->getStackSlot(VirtReg); + int ReuseSlot = SSorRMId; + + // Check to see if this stack slot is available. + unsigned PhysReg = Spills.getSpillSlotOrReMatPhysReg(SSorRMId); + + // If this is a sub-register use, make sure the reuse register is in the + // right register class. For example, for x86 not all of the 32-bit + // registers have accessible sub-registers. + // Similarly so for EXTRACT_SUBREG. Consider this: + // EDI = op + // MOV32_mr fi#1, EDI + // ... + // = EXTRACT_SUBREG fi#1 + // fi#1 is available in EDI, but it cannot be reused because it's not in + // the right register file. + if (PhysReg && !AvoidReload && SubIdx) { + const TargetRegisterClass* RC = MRI->getRegClass(VirtReg); + if (!RC->contains(PhysReg)) + PhysReg = 0; + } + + if (PhysReg && !AvoidReload) { + // This spilled operand might be part of a two-address operand. If this + // is the case, then changing it will necessarily require changing the + // def part of the instruction as well. However, in some cases, we + // aren't allowed to modify the reused register. If none of these cases + // apply, reuse it. + bool CanReuse = true; + bool isTied = MI.isRegTiedToDefOperand(i); + if (isTied) { + // Okay, we have a two address operand. We can reuse this physreg as + // long as we are allowed to clobber the value and there isn't an + // earlier def that has already clobbered the physreg. + CanReuse = !ReusedOperands.isClobbered(PhysReg) && + Spills.canClobberPhysReg(PhysReg); + } + // If this is an asm, and a PhysReg alias is used elsewhere as an + // earlyclobber operand, we can't also use it as an input. + if (MI.isInlineAsm()) { + for (unsigned k = 0, e = MI.getNumOperands(); k != e; ++k) { + MachineOperand &MOk = MI.getOperand(k); + if (MOk.isReg() && MOk.isEarlyClobber() && + TRI->regsOverlap(MOk.getReg(), PhysReg)) { + CanReuse = false; + DEBUG(dbgs() << "Not reusing physreg " << TRI->getName(PhysReg) + << " for vreg" << VirtReg << ": " << MOk << '\n'); + break; + } + } + } + + if (CanReuse) { + // If this stack slot value is already available, reuse it! + if (ReuseSlot > VirtRegMap::MAX_STACK_SLOT) + DEBUG(dbgs() << "Reusing RM#" + << ReuseSlot-VirtRegMap::MAX_STACK_SLOT-1); + else + DEBUG(dbgs() << "Reusing SS#" << ReuseSlot); + DEBUG(dbgs() << " from physreg " + << TRI->getName(PhysReg) << " for vreg" + << VirtReg <<" instead of reloading into physreg " + << TRI->getName(VRM->getPhys(VirtReg)) << '\n'); + unsigned RReg = SubIdx ? TRI->getSubReg(PhysReg, SubIdx) : PhysReg; + MI.getOperand(i).setReg(RReg); + MI.getOperand(i).setSubReg(0); + + // Reusing a physreg may resurrect it. But we expect ProcessUses to + // update the kill flags for the current instr after processing it. + + // The only technical detail we have is that we don't know that + // PhysReg won't be clobbered by a reloaded stack slot that occurs + // later in the instruction. In particular, consider 'op V1, V2'. + // If V1 is available in physreg R0, we would choose to reuse it + // here, instead of reloading it into the register the allocator + // indicated (say R1). However, V2 might have to be reloaded + // later, and it might indicate that it needs to live in R0. When + // this occurs, we need to have information available that + // indicates it is safe to use R1 for the reload instead of R0. + // + // To further complicate matters, we might conflict with an alias, + // or R0 and R1 might not be compatible with each other. In this + // case, we actually insert a reload for V1 in R1, ensuring that + // we can get at R0 or its alias. + ReusedOperands.addReuse(i, ReuseSlot, PhysReg, + VRM->getPhys(VirtReg), VirtReg); + if (isTied) + // Only mark it clobbered if this is a use&def operand. + ReusedOperands.markClobbered(PhysReg); + ++NumReused; + + if (MI.getOperand(i).isKill() && + ReuseSlot <= VirtRegMap::MAX_STACK_SLOT) { + + // The store of this spilled value is potentially dead, but we + // won't know for certain until we've confirmed that the re-use + // above is valid, which means waiting until the other operands + // are processed. For now we just track the spill slot, we'll + // remove it after the other operands are processed if valid. + + PotentialDeadStoreSlots.push_back(ReuseSlot); + } + + // Mark is isKill if it's there no other uses of the same virtual + // register and it's not a two-address operand. IsKill will be + // unset if reg is reused. + if (!isTied && KilledMIRegs.count(VirtReg) == 0) { + MI.getOperand(i).setIsKill(); + KilledMIRegs.insert(VirtReg); + } + continue; + } // CanReuse + + // Otherwise we have a situation where we have a two-address instruction + // whose mod/ref operand needs to be reloaded. This reload is already + // available in some register "PhysReg", but if we used PhysReg as the + // operand to our 2-addr instruction, the instruction would modify + // PhysReg. This isn't cool if something later uses PhysReg and expects + // to get its initial value. + // + // To avoid this problem, and to avoid doing a load right after a store, + // we emit a copy from PhysReg into the designated register for this + // operand. + // + // This case also applies to an earlyclobber'd PhysReg. + unsigned DesignatedReg = VRM->getPhys(VirtReg); + assert(DesignatedReg && "Must map virtreg to physreg!"); + + // Note that, if we reused a register for a previous operand, the + // register we want to reload into might not actually be + // available. If this occurs, use the register indicated by the + // reuser. + if (ReusedOperands.hasReuses()) + DesignatedReg = ReusedOperands. + GetRegForReload(VirtReg, DesignatedReg, &MI, Spills, + MaybeDeadStores, RegKills, KillOps, *VRM); + + // If the mapped designated register is actually the physreg we have + // incoming, we don't need to inserted a dead copy. + if (DesignatedReg == PhysReg) { + // If this stack slot value is already available, reuse it! + if (ReuseSlot > VirtRegMap::MAX_STACK_SLOT) + DEBUG(dbgs() << "Reusing RM#" + << ReuseSlot-VirtRegMap::MAX_STACK_SLOT-1); + else + DEBUG(dbgs() << "Reusing SS#" << ReuseSlot); + DEBUG(dbgs() << " from physreg " << TRI->getName(PhysReg) + << " for vreg" << VirtReg + << " instead of reloading into same physreg.\n"); + unsigned RReg = SubIdx ? TRI->getSubReg(PhysReg, SubIdx) : PhysReg; + MI.getOperand(i).setReg(RReg); + MI.getOperand(i).setSubReg(0); + ReusedOperands.markClobbered(RReg); + ++NumReused; + continue; + } + + MRI->setPhysRegUsed(DesignatedReg); + ReusedOperands.markClobbered(DesignatedReg); + + // Back-schedule reloads and remats. + MachineBasicBlock::iterator InsertLoc = + ComputeReloadLoc(&MI, MBB->begin(), PhysReg, TRI, DoReMat, + SSorRMId, TII, *MBB->getParent()); + MachineInstr *CopyMI = BuildMI(*MBB, InsertLoc, MI.getDebugLoc(), + TII->get(TargetOpcode::COPY), + DesignatedReg).addReg(PhysReg); + CopyMI->setAsmPrinterFlag(MachineInstr::ReloadReuse); + UpdateKills(*CopyMI, TRI, RegKills, KillOps); + + // This invalidates DesignatedReg. + Spills.ClobberPhysReg(DesignatedReg); + + Spills.addAvailable(ReuseSlot, DesignatedReg); + unsigned RReg = + SubIdx ? TRI->getSubReg(DesignatedReg, SubIdx) : DesignatedReg; + MI.getOperand(i).setReg(RReg); + MI.getOperand(i).setSubReg(0); + DEBUG(dbgs() << '\t' << *prior(InsertLoc)); + ++NumReused; + continue; + } // if (PhysReg) + + // Otherwise, reload it and remember that we have it. + PhysReg = VRM->getPhys(VirtReg); + assert(PhysReg && "Must map virtreg to physreg!"); + + // Note that, if we reused a register for a previous operand, the + // register we want to reload into might not actually be + // available. If this occurs, use the register indicated by the + // reuser. + if (ReusedOperands.hasReuses()) + PhysReg = ReusedOperands.GetRegForReload(VirtReg, PhysReg, &MI, + Spills, MaybeDeadStores, RegKills, KillOps, *VRM); + + MRI->setPhysRegUsed(PhysReg); + ReusedOperands.markClobbered(PhysReg); + if (AvoidReload) + ++NumAvoided; + else { + // Back-schedule reloads and remats. + MachineBasicBlock::iterator InsertLoc = + ComputeReloadLoc(MI, MBB->begin(), PhysReg, TRI, DoReMat, + SSorRMId, TII, *MBB->getParent()); + + if (DoReMat) { + ReMaterialize(*MBB, InsertLoc, PhysReg, VirtReg, TII, TRI, *VRM); + } else { + const TargetRegisterClass* RC = MRI->getRegClass(VirtReg); + TII->loadRegFromStackSlot(*MBB, InsertLoc, PhysReg, SSorRMId, RC,TRI); + MachineInstr *LoadMI = prior(InsertLoc); + VRM->addSpillSlotUse(SSorRMId, LoadMI); + ++NumLoads; + DistanceMap.insert(std::make_pair(LoadMI, DistanceMap.size())); + } + // This invalidates PhysReg. + Spills.ClobberPhysReg(PhysReg); + + // Any stores to this stack slot are not dead anymore. + if (!DoReMat) + MaybeDeadStores[SSorRMId] = NULL; + Spills.addAvailable(SSorRMId, PhysReg); + // Assumes this is the last use. IsKill will be unset if reg is reused + // unless it's a two-address operand. + if (!MI.isRegTiedToDefOperand(i) && + KilledMIRegs.count(VirtReg) == 0) { + MI.getOperand(i).setIsKill(); + KilledMIRegs.insert(VirtReg); + } + + UpdateKills(*prior(InsertLoc), TRI, RegKills, KillOps); + DEBUG(dbgs() << '\t' << *prior(InsertLoc)); + } + unsigned RReg = SubIdx ? TRI->getSubReg(PhysReg, SubIdx) : PhysReg; + MI.getOperand(i).setReg(RReg); + MI.getOperand(i).setSubReg(0); + } + + // Ok - now we can remove stores that have been confirmed dead. + for (unsigned j = 0, e = PotentialDeadStoreSlots.size(); j != e; ++j) { + // This was the last use and the spilled value is still available + // for reuse. That means the spill was unnecessary! + int PDSSlot = PotentialDeadStoreSlots[j]; + MachineInstr* DeadStore = MaybeDeadStores[PDSSlot]; + if (DeadStore) { + DEBUG(dbgs() << "Removed dead store:\t" << *DeadStore); + InvalidateKills(*DeadStore, TRI, RegKills, KillOps); + EraseInstr(DeadStore); + MaybeDeadStores[PDSSlot] = NULL; + ++NumDSE; + } + } +} + /// rewriteMBB - Keep track of which spills are available even after the /// register allocator is done with them. If possible, avoid reloading vregs. void @@ -1880,9 +2255,6 @@ LocalRewriter::RewriteMBB(LiveIntervals *LIs, // ReMatDefs - These are rematerializable def MIs which are not deleted. SmallSet ReMatDefs; - // Clear kill info. - SmallSet KilledMIRegs; - // Keep track of the registers we have already spilled in case there are // multiple defs of the same register in MI. SmallSet SpilledMIRegs; @@ -1918,323 +2290,8 @@ LocalRewriter::RewriteMBB(LiveIntervals *LIs, /// ReusedOperands - Keep track of operand reuse in case we need to undo /// reuse. ReuseInfo ReusedOperands(MI, TRI); - SmallVector VirtUseOps; - for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) { - MachineOperand &MO = MI.getOperand(i); - if (!MO.isReg() || MO.getReg() == 0) - continue; // Ignore non-register operands. - - unsigned VirtReg = MO.getReg(); - if (TargetRegisterInfo::isPhysicalRegister(VirtReg)) { - // Ignore physregs for spilling, but remember that it is used by this - // function. - MRI->setPhysRegUsed(VirtReg); - continue; - } - - // We want to process implicit virtual register uses first. - if (MO.isImplicit()) - // If the virtual register is implicitly defined, emit a implicit_def - // before so scavenger knows it's "defined". - // FIXME: This is a horrible hack done the by register allocator to - // remat a definition with virtual register operand. - VirtUseOps.insert(VirtUseOps.begin(), i); - else - VirtUseOps.push_back(i); - } - - // Process all of the spilled uses and all non spilled reg references. - SmallVector PotentialDeadStoreSlots; - KilledMIRegs.clear(); - for (unsigned j = 0, e = VirtUseOps.size(); j != e; ++j) { - unsigned i = VirtUseOps[j]; - unsigned VirtReg = MI.getOperand(i).getReg(); - assert(TargetRegisterInfo::isVirtualRegister(VirtReg) && - "Not a virtual register?"); - - unsigned SubIdx = MI.getOperand(i).getSubReg(); - if (VRM->isAssignedReg(VirtReg)) { - // This virtual register was assigned a physreg! - unsigned Phys = VRM->getPhys(VirtReg); - MRI->setPhysRegUsed(Phys); - if (MI.getOperand(i).isDef()) - ReusedOperands.markClobbered(Phys); - substitutePhysReg(MI.getOperand(i), Phys, *TRI); - if (VRM->isImplicitlyDefined(VirtReg)) - // FIXME: Is this needed? - BuildMI(*MBB, &MI, MI.getDebugLoc(), - TII->get(TargetOpcode::IMPLICIT_DEF), Phys); - continue; - } - - // This virtual register is now known to be a spilled value. - if (!MI.getOperand(i).isUse()) - continue; // Handle defs in the loop below (handle use&def here though) - - bool AvoidReload = MI.getOperand(i).isUndef(); - // Check if it is defined by an implicit def. It should not be spilled. - // Note, this is for correctness reason. e.g. - // 8 %reg1024 = IMPLICIT_DEF - // 12 %reg1024 = INSERT_SUBREG %reg1024, %reg1025, 2 - // The live range [12, 14) are not part of the r1024 live interval since - // it's defined by an implicit def. It will not conflicts with live - // interval of r1025. Now suppose both registers are spilled, you can - // easily see a situation where both registers are reloaded before - // the INSERT_SUBREG and both target registers that would overlap. - bool DoReMat = VRM->isReMaterialized(VirtReg); - int SSorRMId = DoReMat - ? VRM->getReMatId(VirtReg) : VRM->getStackSlot(VirtReg); - int ReuseSlot = SSorRMId; - - // Check to see if this stack slot is available. - unsigned PhysReg = Spills.getSpillSlotOrReMatPhysReg(SSorRMId); - - // If this is a sub-register use, make sure the reuse register is in the - // right register class. For example, for x86 not all of the 32-bit - // registers have accessible sub-registers. - // Similarly so for EXTRACT_SUBREG. Consider this: - // EDI = op - // MOV32_mr fi#1, EDI - // ... - // = EXTRACT_SUBREG fi#1 - // fi#1 is available in EDI, but it cannot be reused because it's not in - // the right register file. - if (PhysReg && !AvoidReload && SubIdx) { - const TargetRegisterClass* RC = MRI->getRegClass(VirtReg); - if (!RC->contains(PhysReg)) - PhysReg = 0; - } - - if (PhysReg && !AvoidReload) { - // This spilled operand might be part of a two-address operand. If this - // is the case, then changing it will necessarily require changing the - // def part of the instruction as well. However, in some cases, we - // aren't allowed to modify the reused register. If none of these cases - // apply, reuse it. - bool CanReuse = true; - bool isTied = MI.isRegTiedToDefOperand(i); - if (isTied) { - // Okay, we have a two address operand. We can reuse this physreg as - // long as we are allowed to clobber the value and there isn't an - // earlier def that has already clobbered the physreg. - CanReuse = !ReusedOperands.isClobbered(PhysReg) && - Spills.canClobberPhysReg(PhysReg); - } - // If this is an asm, and a PhysReg alias is used elsewhere as an - // earlyclobber operand, we can't also use it as an input. - if (MI.isInlineAsm()) { - for (unsigned k = 0, e = MI.getNumOperands(); k != e; ++k) { - MachineOperand &MOk = MI.getOperand(k); - if (MOk.isReg() && MOk.isEarlyClobber() && - TRI->regsOverlap(MOk.getReg(), PhysReg)) { - CanReuse = false; - DEBUG(dbgs() << "Not reusing physreg " << TRI->getName(PhysReg) - << " for vreg" << VirtReg << ": " << MOk << '\n'); - break; - } - } - } - - if (CanReuse) { - // If this stack slot value is already available, reuse it! - if (ReuseSlot > VirtRegMap::MAX_STACK_SLOT) - DEBUG(dbgs() << "Reusing RM#" - << ReuseSlot-VirtRegMap::MAX_STACK_SLOT-1); - else - DEBUG(dbgs() << "Reusing SS#" << ReuseSlot); - DEBUG(dbgs() << " from physreg " - << TRI->getName(PhysReg) << " for vreg" - << VirtReg <<" instead of reloading into physreg " - << TRI->getName(VRM->getPhys(VirtReg)) << '\n'); - unsigned RReg = SubIdx ? TRI->getSubReg(PhysReg, SubIdx) : PhysReg; - MI.getOperand(i).setReg(RReg); - MI.getOperand(i).setSubReg(0); - - // The only technical detail we have is that we don't know that - // PhysReg won't be clobbered by a reloaded stack slot that occurs - // later in the instruction. In particular, consider 'op V1, V2'. - // If V1 is available in physreg R0, we would choose to reuse it - // here, instead of reloading it into the register the allocator - // indicated (say R1). However, V2 might have to be reloaded - // later, and it might indicate that it needs to live in R0. When - // this occurs, we need to have information available that - // indicates it is safe to use R1 for the reload instead of R0. - // - // To further complicate matters, we might conflict with an alias, - // or R0 and R1 might not be compatible with each other. In this - // case, we actually insert a reload for V1 in R1, ensuring that - // we can get at R0 or its alias. - ReusedOperands.addReuse(i, ReuseSlot, PhysReg, - VRM->getPhys(VirtReg), VirtReg); - if (isTied) - // Only mark it clobbered if this is a use&def operand. - ReusedOperands.markClobbered(PhysReg); - ++NumReused; - - if (MI.getOperand(i).isKill() && - ReuseSlot <= VirtRegMap::MAX_STACK_SLOT) { - - // The store of this spilled value is potentially dead, but we - // won't know for certain until we've confirmed that the re-use - // above is valid, which means waiting until the other operands - // are processed. For now we just track the spill slot, we'll - // remove it after the other operands are processed if valid. - - PotentialDeadStoreSlots.push_back(ReuseSlot); - } - - // Mark is isKill if it's there no other uses of the same virtual - // register and it's not a two-address operand. IsKill will be - // unset if reg is reused. - if (!isTied && KilledMIRegs.count(VirtReg) == 0) { - MI.getOperand(i).setIsKill(); - KilledMIRegs.insert(VirtReg); - } - - continue; - } // CanReuse - - // Otherwise we have a situation where we have a two-address instruction - // whose mod/ref operand needs to be reloaded. This reload is already - // available in some register "PhysReg", but if we used PhysReg as the - // operand to our 2-addr instruction, the instruction would modify - // PhysReg. This isn't cool if something later uses PhysReg and expects - // to get its initial value. - // - // To avoid this problem, and to avoid doing a load right after a store, - // we emit a copy from PhysReg into the designated register for this - // operand. - // - // This case also applies to an earlyclobber'd PhysReg. - unsigned DesignatedReg = VRM->getPhys(VirtReg); - assert(DesignatedReg && "Must map virtreg to physreg!"); - - // Note that, if we reused a register for a previous operand, the - // register we want to reload into might not actually be - // available. If this occurs, use the register indicated by the - // reuser. - if (ReusedOperands.hasReuses()) - DesignatedReg = ReusedOperands. - GetRegForReload(VirtReg, DesignatedReg, &MI, Spills, - MaybeDeadStores, RegKills, KillOps, *VRM); - - // If the mapped designated register is actually the physreg we have - // incoming, we don't need to inserted a dead copy. - if (DesignatedReg == PhysReg) { - // If this stack slot value is already available, reuse it! - if (ReuseSlot > VirtRegMap::MAX_STACK_SLOT) - DEBUG(dbgs() << "Reusing RM#" - << ReuseSlot-VirtRegMap::MAX_STACK_SLOT-1); - else - DEBUG(dbgs() << "Reusing SS#" << ReuseSlot); - DEBUG(dbgs() << " from physreg " << TRI->getName(PhysReg) - << " for vreg" << VirtReg - << " instead of reloading into same physreg.\n"); - unsigned RReg = SubIdx ? TRI->getSubReg(PhysReg, SubIdx) : PhysReg; - MI.getOperand(i).setReg(RReg); - MI.getOperand(i).setSubReg(0); - ReusedOperands.markClobbered(RReg); - ++NumReused; - continue; - } - - MRI->setPhysRegUsed(DesignatedReg); - ReusedOperands.markClobbered(DesignatedReg); - - // Back-schedule reloads and remats. - MachineBasicBlock::iterator InsertLoc = - ComputeReloadLoc(&MI, MBB->begin(), PhysReg, TRI, DoReMat, - SSorRMId, TII, MF); - MachineInstr *CopyMI = BuildMI(*MBB, InsertLoc, MI.getDebugLoc(), - TII->get(TargetOpcode::COPY), - DesignatedReg).addReg(PhysReg); - CopyMI->setAsmPrinterFlag(MachineInstr::ReloadReuse); - UpdateKills(*CopyMI, TRI, RegKills, KillOps); - - // This invalidates DesignatedReg. - Spills.ClobberPhysReg(DesignatedReg); - - Spills.addAvailable(ReuseSlot, DesignatedReg); - unsigned RReg = - SubIdx ? TRI->getSubReg(DesignatedReg, SubIdx) : DesignatedReg; - MI.getOperand(i).setReg(RReg); - MI.getOperand(i).setSubReg(0); - DEBUG(dbgs() << '\t' << *prior(MII)); - ++NumReused; - continue; - } // if (PhysReg) - - // Otherwise, reload it and remember that we have it. - PhysReg = VRM->getPhys(VirtReg); - assert(PhysReg && "Must map virtreg to physreg!"); - - // Note that, if we reused a register for a previous operand, the - // register we want to reload into might not actually be - // available. If this occurs, use the register indicated by the - // reuser. - if (ReusedOperands.hasReuses()) - PhysReg = ReusedOperands.GetRegForReload(VirtReg, PhysReg, &MI, - Spills, MaybeDeadStores, RegKills, KillOps, *VRM); - - MRI->setPhysRegUsed(PhysReg); - ReusedOperands.markClobbered(PhysReg); - if (AvoidReload) - ++NumAvoided; - else { - // Back-schedule reloads and remats. - MachineBasicBlock::iterator InsertLoc = - ComputeReloadLoc(MII, MBB->begin(), PhysReg, TRI, DoReMat, - SSorRMId, TII, MF); - - if (DoReMat) { - ReMaterialize(*MBB, InsertLoc, PhysReg, VirtReg, TII, TRI, *VRM); - } else { - const TargetRegisterClass* RC = MRI->getRegClass(VirtReg); - TII->loadRegFromStackSlot(*MBB, InsertLoc, PhysReg, SSorRMId, RC,TRI); - MachineInstr *LoadMI = prior(InsertLoc); - VRM->addSpillSlotUse(SSorRMId, LoadMI); - ++NumLoads; - DistanceMap.insert(std::make_pair(LoadMI, DistanceMap.size())); - } - // This invalidates PhysReg. - Spills.ClobberPhysReg(PhysReg); - - // Any stores to this stack slot are not dead anymore. - if (!DoReMat) - MaybeDeadStores[SSorRMId] = NULL; - Spills.addAvailable(SSorRMId, PhysReg); - // Assumes this is the last use. IsKill will be unset if reg is reused - // unless it's a two-address operand. - if (!MI.isRegTiedToDefOperand(i) && - KilledMIRegs.count(VirtReg) == 0) { - MI.getOperand(i).setIsKill(); - KilledMIRegs.insert(VirtReg); - } - - UpdateKills(*prior(InsertLoc), TRI, RegKills, KillOps); - DEBUG(dbgs() << '\t' << *prior(InsertLoc)); - } - unsigned RReg = SubIdx ? TRI->getSubReg(PhysReg, SubIdx) : PhysReg; - MI.getOperand(i).setReg(RReg); - MI.getOperand(i).setSubReg(0); - } - - // Ok - now we can remove stores that have been confirmed dead. - for (unsigned j = 0, e = PotentialDeadStoreSlots.size(); j != e; ++j) { - // This was the last use and the spilled value is still available - // for reuse. That means the spill was unnecessary! - int PDSSlot = PotentialDeadStoreSlots[j]; - MachineInstr* DeadStore = MaybeDeadStores[PDSSlot]; - if (DeadStore) { - DEBUG(dbgs() << "Removed dead store:\t" << *DeadStore); - InvalidateKills(*DeadStore, TRI, RegKills, KillOps); - VRM->RemoveMachineInstrFromMaps(DeadStore); - MBB->erase(DeadStore); - MaybeDeadStores[PDSSlot] = NULL; - ++NumDSE; - } - } + ProcessUses(MI, Spills, MaybeDeadStores, RegKills, ReusedOperands, KillOps); DEBUG(dbgs() << '\t' << MI); @@ -2288,14 +2345,13 @@ LocalRewriter::RewriteMBB(LiveIntervals *LIs, BackTracked = true; } else { DEBUG(dbgs() << "Removing now-noop copy: " << MI); - // Unset last kill since it's being reused. - InvalidateKill(InReg, TRI, RegKills, KillOps); + // InvalidateKills resurrects any prior kill of the copy's source + // allowing the source reg to be reused in place of the copy. Spills.disallowClobberPhysReg(InReg); } InvalidateKills(MI, TRI, RegKills, KillOps); - VRM->RemoveMachineInstrFromMaps(&MI); - MBB->erase(&MI); + EraseInstr(&MI); Erased = true; goto ProcessNextInst; } @@ -2306,8 +2362,7 @@ LocalRewriter::RewriteMBB(LiveIntervals *LIs, TII->unfoldMemoryOperand(MF, &MI, PhysReg, false, false, NewMIs)){ MBB->insert(MII, NewMIs[0]); InvalidateKills(MI, TRI, RegKills, KillOps); - VRM->RemoveMachineInstrFromMaps(&MI); - MBB->erase(&MI); + EraseInstr(&MI); Erased = true; --NextMII; // backtrack to the unfolded instruction. BackTracked = true; @@ -2343,8 +2398,7 @@ LocalRewriter::RewriteMBB(LiveIntervals *LIs, MBB->insert(MII, NewStore); VRM->addSpillSlotUse(SS, NewStore); InvalidateKills(MI, TRI, RegKills, KillOps); - VRM->RemoveMachineInstrFromMaps(&MI); - MBB->erase(&MI); + EraseInstr(&MI); Erased = true; --NextMII; --NextMII; // backtrack to the unfolded instruction. @@ -2359,8 +2413,7 @@ LocalRewriter::RewriteMBB(LiveIntervals *LIs, // If we get here, the store is dead, nuke it now. DEBUG(dbgs() << "Removed dead store:\t" << *DeadStore); InvalidateKills(*DeadStore, TRI, RegKills, KillOps); - VRM->RemoveMachineInstrFromMaps(DeadStore); - MBB->erase(DeadStore); + EraseInstr(DeadStore); if (!NewStore) ++NumDSE; } @@ -2437,8 +2490,7 @@ LocalRewriter::RewriteMBB(LiveIntervals *LIs, // Last def is now dead. TransferDeadness(MI.getOperand(1).getReg(), RegKills, KillOps); } - VRM->RemoveMachineInstrFromMaps(&MI); - MBB->erase(&MI); + EraseInstr(&MI); Erased = true; Spills.disallowClobberPhysReg(VirtReg); goto ProcessNextInst; @@ -2514,8 +2566,7 @@ LocalRewriter::RewriteMBB(LiveIntervals *LIs, ++NumDCE; DEBUG(dbgs() << "Removing now-noop copy: " << MI); InvalidateKills(MI, TRI, RegKills, KillOps); - VRM->RemoveMachineInstrFromMaps(&MI); - MBB->erase(&MI); + EraseInstr(&MI); Erased = true; UpdateKills(*LastStore, TRI, RegKills, KillOps); goto ProcessNextInst; @@ -2526,8 +2577,7 @@ LocalRewriter::RewriteMBB(LiveIntervals *LIs, // Delete dead instructions without side effects. if (!Erased && !BackTracked && isSafeToDelete(MI)) { InvalidateKills(MI, TRI, RegKills, KillOps); - VRM->RemoveMachineInstrFromMaps(&MI); - MBB->erase(&MI); + EraseInstr(&MI); Erased = true; } if (!Erased) diff --git a/lib/CompilerDriver/Action.cpp b/lib/CompilerDriver/Action.cpp index 0be80496a3cb..a8d625c7ac04 100644 --- a/lib/CompilerDriver/Action.cpp +++ b/lib/CompilerDriver/Action.cpp @@ -14,11 +14,12 @@ #include "llvm/CompilerDriver/Action.h" #include "llvm/CompilerDriver/BuiltinOptions.h" #include "llvm/CompilerDriver/Error.h" +#include "llvm/CompilerDriver/Main.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/SystemUtils.h" -#include "llvm/System/Program.h" -#include "llvm/System/TimeValue.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/TimeValue.h" #include #include @@ -28,7 +29,6 @@ using namespace llvmc; namespace llvmc { -extern int Main(int argc, char** argv); extern const char* ProgramName; } @@ -53,15 +53,19 @@ namespace { #endif } - int ExecuteProgram (const std::string& name, - const StrVector& args) { - sys::Path prog = sys::Program::FindProgramByName(name); + int ExecuteProgram (const std::string& name, const StrVector& args) { + sys::Path prog(name); - if (prog.isEmpty()) { - prog = FindExecutable(name, ProgramName, (void *)(intptr_t)&Main); - if (prog.isEmpty()) { - PrintError("Can't find program '" + name + "'"); - return -1; + if (sys::path::is_relative(prog.str())) { + prog = PrependMainExecutablePath(name, ProgramName, + (void *)(intptr_t)&Main); + + if (!prog.canExecute()) { + prog = sys::Program::FindProgramByName(name); + if (prog.isEmpty()) { + PrintError("Can't find program '" + name + "'"); + return -1; + } } } if (!prog.canExecute()) { diff --git a/lib/CompilerDriver/CMakeLists.txt b/lib/CompilerDriver/CMakeLists.txt index 153dd443cbf2..2248de01b954 100644 --- a/lib/CompilerDriver/CMakeLists.txt +++ b/lib/CompilerDriver/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS support system) +set(LLVM_LINK_COMPONENTS support) set(LLVM_REQUIRES_EH 1) add_llvm_tool(llvmc diff --git a/lib/CompilerDriver/CompilationGraph.cpp b/lib/CompilerDriver/CompilationGraph.cpp index d0c0e15bcdb7..33c6566499b8 100644 --- a/lib/CompilerDriver/CompilationGraph.cpp +++ b/lib/CompilerDriver/CompilationGraph.cpp @@ -32,7 +32,8 @@ using namespace llvmc; namespace llvmc { const std::string* LanguageMap::GetLanguage(const sys::Path& File) const { - StringRef suf = File.getSuffix(); + // Remove the '.'. + StringRef suf = sys::path::extension(File.str()).substr(1); LanguageMap::const_iterator Lang = this->find(suf.empty() ? "*empty*" : suf); if (Lang == this->end()) { @@ -218,10 +219,11 @@ FindToolChain(const sys::Path& In, const std::string* ForceLanguage, InputLanguagesSet& InLangs, const LanguageMap& LangMap) const { // Determine the input language. - const std::string* InLang = LangMap.GetLanguage(In); + const std::string* InLang = (ForceLanguage ? ForceLanguage + : LangMap.GetLanguage(In)); if (InLang == 0) return 0; - const std::string& InLanguage = (ForceLanguage ? *ForceLanguage : *InLang); + const std::string& InLanguage = *InLang; // Add the current input language to the input language set. InLangs.insert(InLanguage); @@ -439,13 +441,17 @@ int CompilationGraph::CheckLanguageNames() const { continue; } - const char* OutLang = N1.ToolPtr->OutputLanguage(); + const char** OutLangs = N1.ToolPtr->OutputLanguages(); const char** InLangs = N2->ToolPtr->InputLanguages(); bool eq = false; - for (;*InLangs; ++InLangs) { - if (std::strcmp(OutLang, *InLangs) == 0) { - eq = true; - break; + const char* OutLang = 0; + for (;*OutLangs; ++OutLangs) { + OutLang = *OutLangs; + for (;*InLangs; ++InLangs) { + if (std::strcmp(OutLang, *InLangs) == 0) { + eq = true; + break; + } } } @@ -480,7 +486,7 @@ int CompilationGraph::CheckMultipleDefaultEdges() const { for (const_nodes_iterator B = this->NodesMap.begin(), E = this->NodesMap.end(); B != E; ++B) { const Node& N = B->second; - int MaxWeight = 0; + int MaxWeight = -1024; // Ignore the root node. if (!N.ToolPtr) @@ -572,6 +578,26 @@ int CompilationGraph::Check () { // Code related to graph visualization. +namespace { + +std::string SquashStrArray (const char** StrArr) { + std::string ret; + + for (; *StrArr; ++StrArr) { + if (*(StrArr + 1)) { + ret += *StrArr; + ret += ", "; + } + else { + ret += *StrArr; + } + } + + return ret; +} + +} // End anonymous namespace. + namespace llvm { template <> struct DOTGraphTraits @@ -586,7 +612,8 @@ namespace llvm { if (N->ToolPtr->IsJoin()) return N->Name() + "\n (join" + (N->HasChildren() ? ")" - : std::string(": ") + N->ToolPtr->OutputLanguage() + ')'); + : std::string(": ") + + SquashStrArray(N->ToolPtr->OutputLanguages()) + ')'); else return N->Name(); else @@ -596,28 +623,15 @@ namespace llvm { template static std::string getEdgeSourceLabel(const Node* N, EdgeIter I) { if (N->ToolPtr) { - return N->ToolPtr->OutputLanguage(); + return SquashStrArray(N->ToolPtr->OutputLanguages()); } else { - const char** InLangs = I->ToolPtr->InputLanguages(); - std::string ret; - - for (; *InLangs; ++InLangs) { - if (*(InLangs + 1)) { - ret += *InLangs; - ret += ", "; - } - else { - ret += *InLangs; - } - } - - return ret; + return SquashStrArray(I->ToolPtr->InputLanguages()); } } }; -} +} // End namespace llvm int CompilationGraph::writeGraph(const std::string& OutputFilename) { std::string ErrorInfo; diff --git a/lib/CompilerDriver/Main.cpp b/lib/CompilerDriver/Main.cpp index 0a6613aa77a3..7120027f7ce0 100644 --- a/lib/CompilerDriver/Main.cpp +++ b/lib/CompilerDriver/Main.cpp @@ -16,8 +16,9 @@ #include "llvm/CompilerDriver/CompilationGraph.h" #include "llvm/CompilerDriver/Error.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Path.h" #include #include @@ -43,15 +44,15 @@ namespace { return 0; } else if (SaveTemps == SaveTempsEnum::Obj && !OutputFilename.empty()) { - tempDir = OutputFilename; - tempDir = tempDir.getDirname(); + tempDir = sys::path::parent_path(OutputFilename); } else { // SaveTemps == Cwd --> use current dir (leave tempDir empty). return 0; } - if (!tempDir.exists()) { + bool Exists; + if (llvm::sys::fs::exists(tempDir.str(), Exists) || !Exists) { std::string ErrMsg; if (tempDir.createDirectoryOnDisk(true, &ErrMsg)) { PrintError(ErrMsg); diff --git a/lib/CompilerDriver/Makefile b/lib/CompilerDriver/Makefile index 8e8b73ca8f83..10cfa4f02923 100644 --- a/lib/CompilerDriver/Makefile +++ b/lib/CompilerDriver/Makefile @@ -13,7 +13,7 @@ LEVEL = ../.. # name doesn't start with "LLVM" and NO_LLVM_CONFIG is set. LIBRARYNAME = CompilerDriver -LINK_COMPONENTS = support system +LINK_COMPONENTS = support NO_LLVM_CONFIG = 1 diff --git a/lib/CompilerDriver/Tool.cpp b/lib/CompilerDriver/Tool.cpp index c8488b226e28..876759aa72b0 100644 --- a/lib/CompilerDriver/Tool.cpp +++ b/lib/CompilerDriver/Tool.cpp @@ -15,7 +15,7 @@ #include "llvm/CompilerDriver/Tool.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Path.h" #include @@ -61,7 +61,7 @@ sys::Path Tool::OutFilename(const sys::Path& In, Out.appendSuffix(OutputSuffix); } else { - Out.set(In.getBasename()); + Out.set(sys::path::stem(In.str())); Out.appendSuffix(OutputSuffix); } } @@ -69,7 +69,7 @@ sys::Path Tool::OutFilename(const sys::Path& In, if (IsJoin()) Out = MakeTempFile(TempDir, "tmp", OutputSuffix); else - Out = MakeTempFile(TempDir, In.getBasename(), OutputSuffix); + Out = MakeTempFile(TempDir, sys::path::stem(In.str()), OutputSuffix); } return Out; } diff --git a/lib/ExecutionEngine/CMakeLists.txt b/lib/ExecutionEngine/CMakeLists.txt index 0e118ccd904f..b5632d2bc5c3 100644 --- a/lib/ExecutionEngine/CMakeLists.txt +++ b/lib/ExecutionEngine/CMakeLists.txt @@ -2,3 +2,7 @@ add_llvm_library(LLVMExecutionEngine ExecutionEngine.cpp ExecutionEngineBindings.cpp ) + +add_subdirectory(Interpreter) +add_subdirectory(JIT) +add_subdirectory(MCJIT) diff --git a/lib/ExecutionEngine/ExecutionEngine.cpp b/lib/ExecutionEngine/ExecutionEngine.cpp index be7f1f56a958..f28697530b3d 100644 --- a/lib/ExecutionEngine/ExecutionEngine.cpp +++ b/lib/ExecutionEngine/ExecutionEngine.cpp @@ -19,14 +19,15 @@ #include "llvm/DerivedTypes.h" #include "llvm/Module.h" #include "llvm/ExecutionEngine/GenericValue.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MutexGuard.h" #include "llvm/Support/ValueHandle.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/DynamicLibrary.h" -#include "llvm/System/Host.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/Host.h" #include "llvm/Target/TargetData.h" #include #include @@ -45,14 +46,24 @@ ExecutionEngine *(*ExecutionEngine::JITCtor)( StringRef MArch, StringRef MCPU, const SmallVectorImpl& MAttrs) = 0; +ExecutionEngine *(*ExecutionEngine::MCJITCtor)( + Module *M, + std::string *ErrorStr, + JITMemoryManager *JMM, + CodeGenOpt::Level OptLevel, + bool GVsWithCode, + CodeModel::Model CMM, + StringRef MArch, + StringRef MCPU, + const SmallVectorImpl& MAttrs) = 0; ExecutionEngine *(*ExecutionEngine::InterpCtor)(Module *M, std::string *ErrorStr) = 0; -ExecutionEngine::EERegisterFn ExecutionEngine::ExceptionTableRegister = 0; - ExecutionEngine::ExecutionEngine(Module *M) : EEState(*this), - LazyFunctionCreator(0) { + LazyFunctionCreator(0), + ExceptionTableRegister(0), + ExceptionTableDeregister(0) { CompilingLazily = false; GVCompilationDisabled = false; SymbolSearchingDisabled = false; @@ -66,16 +77,25 @@ ExecutionEngine::~ExecutionEngine() { delete Modules[i]; } +void ExecutionEngine::DeregisterAllTables() { + if (ExceptionTableDeregister) { + for (std::vector::iterator it = AllExceptionTables.begin(), + ie = AllExceptionTables.end(); it != ie; ++it) + ExceptionTableDeregister(*it); + AllExceptionTables.clear(); + } +} + namespace { -// This class automatically deletes the memory block when the GlobalVariable is -// destroyed. +/// \brief Helper class which uses a value handler to automatically deletes the +/// memory block when the GlobalVariable is destroyed. class GVMemoryBlock : public CallbackVH { GVMemoryBlock(const GlobalVariable *GV) : CallbackVH(const_cast(GV)) {} public: - // Returns the address the GlobalVariable should be written into. The - // GVMemoryBlock object prefixes that. + /// \brief Returns the address the GlobalVariable should be written into. The + /// GVMemoryBlock object prefixes that. static char *Create(const GlobalVariable *GV, const TargetData& TD) { const Type *ElTy = GV->getType()->getElementType(); size_t GVSize = (size_t)TD.getTypeAllocSize(ElTy); @@ -97,13 +117,12 @@ public: }; } // anonymous namespace -char* ExecutionEngine::getMemoryForGV(const GlobalVariable* GV) { +char *ExecutionEngine::getMemoryForGV(const GlobalVariable *GV) { return GVMemoryBlock::Create(GV, *getTargetData()); } -/// removeModule - Remove a Module from the list of modules. bool ExecutionEngine::removeModule(Module *M) { - for(SmallVector::iterator I = Modules.begin(), + for(SmallVector::iterator I = Modules.begin(), E = Modules.end(); I != E; ++I) { Module *Found = *I; if (Found == M) { @@ -115,9 +134,6 @@ bool ExecutionEngine::removeModule(Module *M) { return false; } -/// FindFunctionNamed - Search all of the active modules to find the one that -/// defines FnName. This is very slow operation and shouldn't be used for -/// general code. Function *ExecutionEngine::FindFunctionNamed(const char *FnName) { for (unsigned i = 0, e = Modules.size(); i != e; ++i) { if (Function *F = Modules[i]->getFunction(FnName)) @@ -127,10 +143,13 @@ Function *ExecutionEngine::FindFunctionNamed(const char *FnName) { } -void *ExecutionEngineState::RemoveMapping( - const MutexGuard &, const GlobalValue *ToUnmap) { +void *ExecutionEngineState::RemoveMapping(const MutexGuard &, + const GlobalValue *ToUnmap) { GlobalAddressMapTy::iterator I = GlobalAddressMap.find(ToUnmap); void *OldVal; + + // FIXME: This is silly, we shouldn't end up with a mapping -> 0 in the + // GlobalAddressMap. if (I == GlobalAddressMap.end()) OldVal = 0; else { @@ -142,21 +161,16 @@ void *ExecutionEngineState::RemoveMapping( return OldVal; } -/// addGlobalMapping - Tell the execution engine that the specified global is -/// at the specified location. This is used internally as functions are JIT'd -/// and as global variables are laid out in memory. It can and should also be -/// used by clients of the EE that want to have an LLVM global overlay -/// existing data in memory. void ExecutionEngine::addGlobalMapping(const GlobalValue *GV, void *Addr) { MutexGuard locked(lock); - DEBUG(dbgs() << "JIT: Map \'" << GV->getName() + DEBUG(dbgs() << "JIT: Map \'" << GV->getName() << "\' to [" << Addr << "]\n";); void *&CurVal = EEState.getGlobalAddressMap(locked)[GV]; assert((CurVal == 0 || Addr == 0) && "GlobalMapping already established!"); CurVal = Addr; - - // If we are using the reverse mapping, add it too + + // If we are using the reverse mapping, add it too. if (!EEState.getGlobalAddressReverseMap(locked).empty()) { AssertingVH &V = EEState.getGlobalAddressReverseMap(locked)[Addr]; @@ -165,32 +179,23 @@ void ExecutionEngine::addGlobalMapping(const GlobalValue *GV, void *Addr) { } } -/// clearAllGlobalMappings - Clear all global mappings and start over again -/// use in dynamic compilation scenarios when you want to move globals void ExecutionEngine::clearAllGlobalMappings() { MutexGuard locked(lock); - + EEState.getGlobalAddressMap(locked).clear(); EEState.getGlobalAddressReverseMap(locked).clear(); } -/// clearGlobalMappingsFromModule - Clear all global mappings that came from a -/// particular module, because it has been removed from the JIT. void ExecutionEngine::clearGlobalMappingsFromModule(Module *M) { MutexGuard locked(lock); - - for (Module::iterator FI = M->begin(), FE = M->end(); FI != FE; ++FI) { + + for (Module::iterator FI = M->begin(), FE = M->end(); FI != FE; ++FI) EEState.RemoveMapping(locked, FI); - } - for (Module::global_iterator GI = M->global_begin(), GE = M->global_end(); - GI != GE; ++GI) { + for (Module::global_iterator GI = M->global_begin(), GE = M->global_end(); + GI != GE; ++GI) EEState.RemoveMapping(locked, GI); - } } -/// updateGlobalMapping - Replace an existing mapping for GV with a new -/// address. This updates both maps as required. If "Addr" is null, the -/// entry for the global is removed from the mappings. void *ExecutionEngine::updateGlobalMapping(const GlobalValue *GV, void *Addr) { MutexGuard locked(lock); @@ -198,18 +203,17 @@ void *ExecutionEngine::updateGlobalMapping(const GlobalValue *GV, void *Addr) { EEState.getGlobalAddressMap(locked); // Deleting from the mapping? - if (Addr == 0) { + if (Addr == 0) return EEState.RemoveMapping(locked, GV); - } - + void *&CurVal = Map[GV]; void *OldVal = CurVal; if (CurVal && !EEState.getGlobalAddressReverseMap(locked).empty()) EEState.getGlobalAddressReverseMap(locked).erase(CurVal); CurVal = Addr; - - // If we are using the reverse mapping, add it too + + // If we are using the reverse mapping, add it too. if (!EEState.getGlobalAddressReverseMap(locked).empty()) { AssertingVH &V = EEState.getGlobalAddressReverseMap(locked)[Addr]; @@ -219,20 +223,14 @@ void *ExecutionEngine::updateGlobalMapping(const GlobalValue *GV, void *Addr) { return OldVal; } -/// getPointerToGlobalIfAvailable - This returns the address of the specified -/// global value if it is has already been codegen'd, otherwise it returns null. -/// void *ExecutionEngine::getPointerToGlobalIfAvailable(const GlobalValue *GV) { MutexGuard locked(lock); - + ExecutionEngineState::GlobalAddressMapTy::iterator I = EEState.getGlobalAddressMap(locked).find(GV); return I != EEState.getGlobalAddressMap(locked).end() ? I->second : 0; } -/// getGlobalValueAtAddress - Return the LLVM global value object that starts -/// at the specified address. -/// const GlobalValue *ExecutionEngine::getGlobalValueAtAddress(void *Addr) { MutexGuard locked(lock); @@ -241,8 +239,8 @@ const GlobalValue *ExecutionEngine::getGlobalValueAtAddress(void *Addr) { for (ExecutionEngineState::GlobalAddressMapTy::iterator I = EEState.getGlobalAddressMap(locked).begin(), E = EEState.getGlobalAddressMap(locked).end(); I != E; ++I) - EEState.getGlobalAddressReverseMap(locked).insert(std::make_pair(I->second, - I->first)); + EEState.getGlobalAddressReverseMap(locked).insert(std::make_pair( + I->second, I->first)); } std::map >::iterator I = @@ -301,54 +299,50 @@ void *ArgvArray::reset(LLVMContext &C, ExecutionEngine *EE, return Array; } - -/// runStaticConstructorsDestructors - This method is used to execute all of -/// the static constructors or destructors for a module, depending on the -/// value of isDtors. void ExecutionEngine::runStaticConstructorsDestructors(Module *module, bool isDtors) { const char *Name = isDtors ? "llvm.global_dtors" : "llvm.global_ctors"; - - // Execute global ctors/dtors for each module in the program. - - GlobalVariable *GV = module->getNamedGlobal(Name); - - // If this global has internal linkage, or if it has a use, then it must be - // an old-style (llvmgcc3) static ctor with __main linked in and in use. If - // this is the case, don't execute any of the global ctors, __main will do - // it. - if (!GV || GV->isDeclaration() || GV->hasLocalLinkage()) return; - - // Should be an array of '{ int, void ()* }' structs. The first value is - // the init priority, which we ignore. - ConstantArray *InitList = dyn_cast(GV->getInitializer()); - if (!InitList) return; - for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) - if (ConstantStruct *CS = - dyn_cast(InitList->getOperand(i))) { - if (CS->getNumOperands() != 2) return; // Not array of 2-element structs. - - Constant *FP = CS->getOperand(1); - if (FP->isNullValue()) - break; // Found a null terminator, exit. - - if (ConstantExpr *CE = dyn_cast(FP)) - if (CE->isCast()) - FP = CE->getOperand(0); - if (Function *F = dyn_cast(FP)) { - // Execute the ctor/dtor function! - runFunction(F, std::vector()); - } - } + GlobalVariable *GV = module->getNamedGlobal(Name); + + // If this global has internal linkage, or if it has a use, then it must be + // an old-style (llvmgcc3) static ctor with __main linked in and in use. If + // this is the case, don't execute any of the global ctors, __main will do + // it. + if (!GV || GV->isDeclaration() || GV->hasLocalLinkage()) return; + + // Should be an array of '{ int, void ()* }' structs. The first value is + // the init priority, which we ignore. + ConstantArray *InitList = dyn_cast(GV->getInitializer()); + if (!InitList) return; + for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) { + ConstantStruct *CS = + dyn_cast(InitList->getOperand(i)); + if (!CS) continue; + if (CS->getNumOperands() != 2) return; // Not array of 2-element structs. + + Constant *FP = CS->getOperand(1); + if (FP->isNullValue()) + break; // Found a null terminator, exit. + + // Strip off constant expression casts. + if (ConstantExpr *CE = dyn_cast(FP)) + if (CE->isCast()) + FP = CE->getOperand(0); + + // Execute the ctor/dtor function! + if (Function *F = dyn_cast(FP)) + runFunction(F, std::vector()); + + // FIXME: It is marginally lame that we just do nothing here if we see an + // entry we don't recognize. It might not be unreasonable for the verifier + // to not even allow this and just assert here. + } } -/// runStaticConstructorsDestructors - This method is used to execute all of -/// the static constructors or destructors for a program, depending on the -/// value of isDtors. void ExecutionEngine::runStaticConstructorsDestructors(bool isDtors) { // Execute global ctors/dtors for each module in the program. - for (unsigned m = 0, e = Modules.size(); m != e; ++m) - runStaticConstructorsDestructors(Modules[m], isDtors); + for (unsigned i = 0, e = Modules.size(); i != e; ++i) + runStaticConstructorsDestructors(Modules[i], isDtors); } #ifndef NDEBUG @@ -362,9 +356,6 @@ static bool isTargetNullPtr(ExecutionEngine *EE, void *Loc) { } #endif -/// runFunctionAsMain - This is a helper function which wraps runFunction to -/// handle the common task of starting up main with the specified argc, argv, -/// and envp parameters. int ExecutionEngine::runFunctionAsMain(Function *Fn, const std::vector &argv, const char * const * envp) { @@ -376,32 +367,20 @@ int ExecutionEngine::runFunctionAsMain(Function *Fn, unsigned NumArgs = Fn->getFunctionType()->getNumParams(); const FunctionType *FTy = Fn->getFunctionType(); const Type* PPInt8Ty = Type::getInt8PtrTy(Fn->getContext())->getPointerTo(); - switch (NumArgs) { - case 3: - if (FTy->getParamType(2) != PPInt8Ty) { - report_fatal_error("Invalid type for third argument of main() supplied"); - } - // FALLS THROUGH - case 2: - if (FTy->getParamType(1) != PPInt8Ty) { - report_fatal_error("Invalid type for second argument of main() supplied"); - } - // FALLS THROUGH - case 1: - if (!FTy->getParamType(0)->isIntegerTy(32)) { - report_fatal_error("Invalid type for first argument of main() supplied"); - } - // FALLS THROUGH - case 0: - if (!FTy->getReturnType()->isIntegerTy() && - !FTy->getReturnType()->isVoidTy()) { - report_fatal_error("Invalid return type of main() supplied"); - } - break; - default: - report_fatal_error("Invalid number of arguments of main() supplied"); - } - + + // Check the argument types. + if (NumArgs > 3) + report_fatal_error("Invalid number of arguments of main() supplied"); + if (NumArgs >= 3 && FTy->getParamType(2) != PPInt8Ty) + report_fatal_error("Invalid type for third argument of main() supplied"); + if (NumArgs >= 2 && FTy->getParamType(1) != PPInt8Ty) + report_fatal_error("Invalid type for second argument of main() supplied"); + if (NumArgs >= 1 && !FTy->getParamType(0)->isIntegerTy(32)) + report_fatal_error("Invalid type for first argument of main() supplied"); + if (!FTy->getReturnType()->isIntegerTy() && + !FTy->getReturnType()->isVoidTy()) + report_fatal_error("Invalid return type of main() supplied"); + ArgvArray CArgv; ArgvArray CEnv; if (NumArgs) { @@ -420,13 +399,10 @@ int ExecutionEngine::runFunctionAsMain(Function *Fn, } } } + return runFunction(Fn, GVArgs).IntVal.getZExtValue(); } -/// If possible, create a JIT, unless the caller specifically requests an -/// Interpreter or there's an error. If even an Interpreter cannot be created, -/// NULL is returned. -/// ExecutionEngine *ExecutionEngine::create(Module *M, bool ForceInterpreter, std::string *ErrorStr, @@ -464,7 +440,13 @@ ExecutionEngine *EngineBuilder::create() { // Unless the interpreter was explicitly selected or the JIT is not linked, // try making a JIT. if (WhichEngine & EngineKind::JIT) { - if (ExecutionEngine::JITCtor) { + if (UseMCJIT && ExecutionEngine::MCJITCtor) { + ExecutionEngine *EE = + ExecutionEngine::MCJITCtor(M, ErrorStr, JMM, OptLevel, + AllocateGVsWithCode, CMModel, + MArch, MCPU, MAttrs); + if (EE) return EE; + } else if (ExecutionEngine::JITCtor) { ExecutionEngine *EE = ExecutionEngine::JITCtor(M, ErrorStr, JMM, OptLevel, AllocateGVsWithCode, CMModel, @@ -486,21 +468,18 @@ ExecutionEngine *EngineBuilder::create() { if ((WhichEngine & EngineKind::JIT) && ExecutionEngine::JITCtor == 0) { if (ErrorStr) *ErrorStr = "JIT has not been linked in."; - } + } + return 0; } -/// getPointerToGlobal - This returns the address of the specified global -/// value. This may involve code generation if it's a function. -/// void *ExecutionEngine::getPointerToGlobal(const GlobalValue *GV) { if (Function *F = const_cast(dyn_cast(GV))) return getPointerToFunction(F); MutexGuard locked(lock); - void *p = EEState.getGlobalAddressMap(locked)[GV]; - if (p) - return p; + if (void *P = EEState.getGlobalAddressMap(locked)[GV]) + return P; // Global variable might have been added since interpreter started. if (GlobalVariable *GVar = @@ -508,12 +487,12 @@ void *ExecutionEngine::getPointerToGlobal(const GlobalValue *GV) { EmitGlobalVariable(GVar); else llvm_unreachable("Global hasn't had an address allocated yet!"); + return EEState.getGlobalAddressMap(locked)[GV]; } -/// This function converts a Constant* into a GenericValue. The interesting -/// part is if C is a ConstantExpr. -/// @brief Get a GenericValue for a Constant* +/// \brief Converts a Constant* into a GenericValue, including handling of +/// ConstantExpr values. GenericValue ExecutionEngine::getConstantValue(const Constant *C) { // If its undefined, return the garbage. if (isa(C)) { @@ -533,12 +512,12 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) { return Result; } - // If the value is a ConstantExpr + // Otherwise, if the value is a ConstantExpr... if (const ConstantExpr *CE = dyn_cast(C)) { Constant *Op0 = CE->getOperand(0); switch (CE->getOpcode()) { case Instruction::GetElementPtr: { - // Compute the index + // Compute the index GenericValue Result = getConstantValue(Op0); SmallVector Indices(CE->op_begin()+1, CE->op_end()); uint64_t Offset = @@ -585,9 +564,8 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) { else if (CE->getType()->isDoubleTy()) GV.DoubleVal = GV.IntVal.roundToDouble(); else if (CE->getType()->isX86_FP80Ty()) { - const uint64_t zero[] = {0, 0}; - APFloat apf = APFloat(APInt(80, 2, zero)); - (void)apf.convertFromAPInt(GV.IntVal, + APFloat apf = APFloat::getZero(APFloat::x87DoubleExtended); + (void)apf.convertFromAPInt(GV.IntVal, false, APFloat::rmNearestTiesToEven); GV.IntVal = apf.bitcastToAPInt(); @@ -601,9 +579,8 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) { else if (CE->getType()->isDoubleTy()) GV.DoubleVal = GV.IntVal.signedRoundToDouble(); else if (CE->getType()->isX86_FP80Ty()) { - const uint64_t zero[] = { 0, 0}; - APFloat apf = APFloat(APInt(80, 2, zero)); - (void)apf.convertFromAPInt(GV.IntVal, + APFloat apf = APFloat::getZero(APFloat::x87DoubleExtended); + (void)apf.convertFromAPInt(GV.IntVal, true, APFloat::rmNearestTiesToEven); GV.IntVal = apf.bitcastToAPInt(); @@ -623,7 +600,7 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) { uint64_t v; bool ignored; (void)apf.convertToInteger(&v, BitWidth, - CE->getOpcode()==Instruction::FPToSI, + CE->getOpcode()==Instruction::FPToSI, APFloat::rmTowardZero, &ignored); GV.IntVal = v; // endian? } @@ -656,13 +633,13 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) { else if (DestTy->isDoubleTy()) GV.DoubleVal = GV.IntVal.bitsToDouble(); break; - case Type::FloatTyID: + case Type::FloatTyID: assert(DestTy->isIntegerTy(32) && "Invalid bitcast"); - GV.IntVal.floatToBits(GV.FloatVal); + GV.IntVal = APInt::floatToBits(GV.FloatVal); break; case Type::DoubleTyID: assert(DestTy->isIntegerTy(64) && "Invalid bitcast"); - GV.IntVal.doubleToBits(GV.DoubleVal); + GV.IntVal = APInt::doubleToBits(GV.DoubleVal); break; case Type::PointerTyID: assert(DestTy->isPointerTy() && "Invalid bitcast"); @@ -712,9 +689,9 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) { GV.FloatVal = LHS.FloatVal - RHS.FloatVal; break; case Instruction::FMul: GV.FloatVal = LHS.FloatVal * RHS.FloatVal; break; - case Instruction::FDiv: + case Instruction::FDiv: GV.FloatVal = LHS.FloatVal / RHS.FloatVal; break; - case Instruction::FRem: + case Instruction::FRem: GV.FloatVal = std::fmod(LHS.FloatVal,RHS.FloatVal); break; } break; @@ -727,9 +704,9 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) { GV.DoubleVal = LHS.DoubleVal - RHS.DoubleVal; break; case Instruction::FMul: GV.DoubleVal = LHS.DoubleVal * RHS.DoubleVal; break; - case Instruction::FDiv: + case Instruction::FDiv: GV.DoubleVal = LHS.DoubleVal / RHS.DoubleVal; break; - case Instruction::FRem: + case Instruction::FRem: GV.DoubleVal = std::fmod(LHS.DoubleVal,RHS.DoubleVal); break; } break; @@ -738,7 +715,7 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) { case Type::FP128TyID: { APFloat apfLHS = APFloat(LHS.IntVal); switch (CE->getOpcode()) { - default: llvm_unreachable("Invalid long double opcode");llvm_unreachable(0); + default: llvm_unreachable("Invalid long double opcode"); case Instruction::FAdd: apfLHS.add(APFloat(RHS.IntVal), APFloat::rmNearestTiesToEven); GV.IntVal = apfLHS.bitcastToAPInt(); @@ -751,11 +728,11 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) { apfLHS.multiply(APFloat(RHS.IntVal), APFloat::rmNearestTiesToEven); GV.IntVal = apfLHS.bitcastToAPInt(); break; - case Instruction::FDiv: + case Instruction::FDiv: apfLHS.divide(APFloat(RHS.IntVal), APFloat::rmNearestTiesToEven); GV.IntVal = apfLHS.bitcastToAPInt(); break; - case Instruction::FRem: + case Instruction::FRem: apfLHS.mod(APFloat(RHS.IntVal), APFloat::rmNearestTiesToEven); GV.IntVal = apfLHS.bitcastToAPInt(); break; @@ -768,16 +745,18 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) { default: break; } - std::string msg; - raw_string_ostream Msg(msg); - Msg << "ConstantExpr not handled: " << *CE; - report_fatal_error(Msg.str()); + + SmallString<256> Msg; + raw_svector_ostream OS(Msg); + OS << "ConstantExpr not handled: " << *CE; + report_fatal_error(OS.str()); } + // Otherwise, we have a simple constant. GenericValue Result; switch (C->getType()->getTypeID()) { - case Type::FloatTyID: - Result.FloatVal = cast(C)->getValueAPF().convertToFloat(); + case Type::FloatTyID: + Result.FloatVal = cast(C)->getValueAPF().convertToFloat(); break; case Type::DoubleTyID: Result.DoubleVal = cast(C)->getValueAPF().convertToDouble(); @@ -804,11 +783,12 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) { llvm_unreachable("Unknown constant pointer type!"); break; default: - std::string msg; - raw_string_ostream Msg(msg); - Msg << "ERROR: Constant unimplemented for type: " << *C->getType(); - report_fatal_error(Msg.str()); + SmallString<256> Msg; + raw_svector_ostream OS(Msg); + OS << "ERROR: Constant unimplemented for type: " << *C->getType(); + report_fatal_error(OS.str()); } + return Result; } @@ -819,11 +799,11 @@ static void StoreIntToMemory(const APInt &IntVal, uint8_t *Dst, assert((IntVal.getBitWidth()+7)/8 >= StoreBytes && "Integer too small!"); uint8_t *Src = (uint8_t *)IntVal.getRawData(); - if (sys::isLittleEndianHost()) + if (sys::isLittleEndianHost()) { // Little-endian host - the source is ordered from LSB to MSB. Order the // destination from LSB to MSB: Do a straight copy. memcpy(Dst, Src, StoreBytes); - else { + } else { // Big-endian host - the source is an array of 64 bit words ordered from // LSW to MSW. Each word is ordered from MSB to LSB. Order the destination // from MSB to LSB: Reverse the word order, but not the bytes in a word. @@ -838,10 +818,6 @@ static void StoreIntToMemory(const APInt &IntVal, uint8_t *Dst, } } -/// StoreValueToMemory - Stores the data in Val of type Ty at address Ptr. Ptr -/// is the address of the memory at which to store Val, cast to GenericValue *. -/// It is not a pointer to a GenericValue containing the address at which to -/// store Val. void ExecutionEngine::StoreValueToMemory(const GenericValue &Val, GenericValue *Ptr, const Type *Ty) { const unsigned StoreBytes = getTargetData()->getTypeStoreSize(Ty); @@ -932,16 +908,13 @@ void ExecutionEngine::LoadValueFromMemory(GenericValue &Result, break; } default: - std::string msg; - raw_string_ostream Msg(msg); - Msg << "Cannot load value of type " << *Ty << "!"; - report_fatal_error(Msg.str()); + SmallString<256> Msg; + raw_svector_ostream OS(Msg); + OS << "Cannot load value of type " << *Ty << "!"; + report_fatal_error(OS.str()); } } -// InitializeMemory - Recursive function to apply a Constant value into the -// specified memory location... -// void ExecutionEngine::InitializeMemory(const Constant *Init, void *Addr) { DEBUG(dbgs() << "JIT: Initializing " << Addr << " "); DEBUG(Init->dump()); @@ -974,20 +947,17 @@ void ExecutionEngine::InitializeMemory(const Constant *Init, void *Addr) { return; } - dbgs() << "Bad Type: " << *Init->getType() << "\n"; + DEBUG(dbgs() << "Bad Type: " << *Init->getType() << "\n"); llvm_unreachable("Unknown constant type to initialize memory with!"); } /// EmitGlobals - Emit all of the global variables to memory, storing their /// addresses into GlobalAddress. This must make sure to copy the contents of /// their initializers into the memory. -/// void ExecutionEngine::emitGlobals() { - // Loop over all of the global variables in the program, allocating the memory // to hold them. If there is more than one module, do a prepass over globals // to figure out how the different modules should link together. - // std::map, const GlobalValue*> LinkedGlobalsMap; @@ -1000,8 +970,8 @@ void ExecutionEngine::emitGlobals() { if (GV->hasLocalLinkage() || GV->isDeclaration() || GV->hasAppendingLinkage() || !GV->hasName()) continue;// Ignore external globals and globals with internal linkage. - - const GlobalValue *&GVEntry = + + const GlobalValue *&GVEntry = LinkedGlobalsMap[std::make_pair(GV->getName(), GV->getType())]; // If this is the first time we've seen this global, it is the canonical @@ -1010,13 +980,13 @@ void ExecutionEngine::emitGlobals() { GVEntry = GV; continue; } - + // If the existing global is strong, never replace it. if (GVEntry->hasExternalLinkage() || GVEntry->hasDLLImportLinkage() || GVEntry->hasDLLExportLinkage()) continue; - + // Otherwise, we know it's linkonce/weak, replace it if this is a strong // symbol. FIXME is this right for common? if (GV->hasExternalLinkage() || GVEntry->hasExternalWeakLinkage()) @@ -1024,7 +994,7 @@ void ExecutionEngine::emitGlobals() { } } } - + std::vector NonCanonicalGlobals; for (unsigned m = 0, e = Modules.size(); m != e; ++m) { Module &M = *Modules[m]; @@ -1032,7 +1002,7 @@ void ExecutionEngine::emitGlobals() { I != E; ++I) { // In the multi-module case, see what this global maps to. if (!LinkedGlobalsMap.empty()) { - if (const GlobalValue *GVEntry = + if (const GlobalValue *GVEntry = LinkedGlobalsMap[std::make_pair(I->getName(), I->getType())]) { // If something else is the canonical global, ignore this one. if (GVEntry != &*I) { @@ -1041,7 +1011,7 @@ void ExecutionEngine::emitGlobals() { } } } - + if (!I->isDeclaration()) { addGlobalMapping(I, getMemoryForGV(I)); } else { @@ -1056,7 +1026,7 @@ void ExecutionEngine::emitGlobals() { } } } - + // If there are multiple modules, map the non-canonical globals to their // canonical location. if (!NonCanonicalGlobals.empty()) { @@ -1069,14 +1039,14 @@ void ExecutionEngine::emitGlobals() { addGlobalMapping(GV, Ptr); } } - - // Now that all of the globals are set up in memory, loop through them all + + // Now that all of the globals are set up in memory, loop through them all // and initialize their contents. for (Module::const_global_iterator I = M.global_begin(), E = M.global_end(); I != E; ++I) { if (!I->isDeclaration()) { if (!LinkedGlobalsMap.empty()) { - if (const GlobalValue *GVEntry = + if (const GlobalValue *GVEntry = LinkedGlobalsMap[std::make_pair(I->getName(), I->getType())]) if (GVEntry != &*I) // Not the canonical variable. continue; @@ -1098,11 +1068,11 @@ void ExecutionEngine::EmitGlobalVariable(const GlobalVariable *GV) { GA = getMemoryForGV(GV); addGlobalMapping(GV, GA); } - + // Don't initialize if it's thread local, let the client do it. if (!GV->isThreadLocal()) InitializeMemory(GV->getInitializer(), GA); - + const Type *ElTy = GV->getType()->getElementType(); size_t GVSize = (size_t)getTargetData()->getTypeAllocSize(ElTy); NumInitBytes += (unsigned)GVSize; @@ -1113,18 +1083,20 @@ ExecutionEngineState::ExecutionEngineState(ExecutionEngine &EE) : EE(EE), GlobalAddressMap(this) { } -sys::Mutex *ExecutionEngineState::AddressMapConfig::getMutex( - ExecutionEngineState *EES) { +sys::Mutex * +ExecutionEngineState::AddressMapConfig::getMutex(ExecutionEngineState *EES) { return &EES->EE.lock; } -void ExecutionEngineState::AddressMapConfig::onDelete( - ExecutionEngineState *EES, const GlobalValue *Old) { + +void ExecutionEngineState::AddressMapConfig::onDelete(ExecutionEngineState *EES, + const GlobalValue *Old) { void *OldVal = EES->GlobalAddressMap.lookup(Old); EES->GlobalAddressReverseMap.erase(OldVal); } -void ExecutionEngineState::AddressMapConfig::onRAUW( - ExecutionEngineState *, const GlobalValue *, const GlobalValue *) { +void ExecutionEngineState::AddressMapConfig::onRAUW(ExecutionEngineState *, + const GlobalValue *, + const GlobalValue *) { assert(false && "The ExecutionEngine doesn't know how to handle a" " RAUW on a value it has a global mapping for."); } diff --git a/lib/ExecutionEngine/Interpreter/CMakeLists.txt b/lib/ExecutionEngine/Interpreter/CMakeLists.txt index dff97fa26e8f..d331f830b62e 100644 --- a/lib/ExecutionEngine/Interpreter/CMakeLists.txt +++ b/lib/ExecutionEngine/Interpreter/CMakeLists.txt @@ -1,5 +1,17 @@ +# Make sure that the path to libffi headers is on the command +# line. That path can be a compiler's non-default path even when +# FFI_INCLUDE_DIR was not used, because cmake has its own paths for +# searching for headers (CMAKE_SYSTEM_INCLUDE_PATH, for instance): +if( FFI_INCLUDE_PATH ) + include_directories( ${FFI_INCLUDE_PATH} ) +endif() + add_llvm_library(LLVMInterpreter Execution.cpp ExternalFunctions.cpp Interpreter.cpp ) + +if( LLVM_ENABLE_FFI ) + target_link_libraries( LLVMInterpreter ${FFI_LIBRARY_PATH} ) +endif() diff --git a/lib/ExecutionEngine/Interpreter/Execution.cpp b/lib/ExecutionEngine/Interpreter/Execution.cpp index 59ebe6e2a885..498063bf6555 100644 --- a/lib/ExecutionEngine/Interpreter/Execution.cpp +++ b/lib/ExecutionEngine/Interpreter/Execution.cpp @@ -1060,11 +1060,9 @@ GenericValue Interpreter::executeBitCastInst(Value *SrcVal, const Type *DstTy, Dest.PointerVal = Src.PointerVal; } else if (DstTy->isIntegerTy()) { if (SrcTy->isFloatTy()) { - Dest.IntVal.zext(sizeof(Src.FloatVal) * CHAR_BIT); - Dest.IntVal.floatToBits(Src.FloatVal); + Dest.IntVal = APInt::floatToBits(Src.FloatVal); } else if (SrcTy->isDoubleTy()) { - Dest.IntVal.zext(sizeof(Src.DoubleVal) * CHAR_BIT); - Dest.IntVal.doubleToBits(Src.DoubleVal); + Dest.IntVal = APInt::doubleToBits(Src.DoubleVal); } else if (SrcTy->isIntegerTy()) { Dest.IntVal = Src.IntVal; } else diff --git a/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp b/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp index 57d12606bc77..062256a2ac73 100644 --- a/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp +++ b/lib/ExecutionEngine/Interpreter/ExternalFunctions.cpp @@ -24,10 +24,10 @@ #include "llvm/Module.h" #include "llvm/Config/config.h" // Detect libffi #include "llvm/Support/ErrorHandling.h" -#include "llvm/System/DynamicLibrary.h" +#include "llvm/Support/DynamicLibrary.h" #include "llvm/Target/TargetData.h" #include "llvm/Support/ManagedStatic.h" -#include "llvm/System/Mutex.h" +#include "llvm/Support/Mutex.h" #include #include #include diff --git a/lib/ExecutionEngine/Interpreter/Interpreter.h b/lib/ExecutionEngine/Interpreter/Interpreter.h index 564e9abad9e7..bfebe3debfcd 100644 --- a/lib/ExecutionEngine/Interpreter/Interpreter.h +++ b/lib/ExecutionEngine/Interpreter/Interpreter.h @@ -19,7 +19,7 @@ #include "llvm/ExecutionEngine/GenericValue.h" #include "llvm/Target/TargetData.h" #include "llvm/Support/CallSite.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/InstVisitor.h" #include "llvm/Support/raw_ostream.h" diff --git a/lib/ExecutionEngine/JIT/Intercept.cpp b/lib/ExecutionEngine/JIT/Intercept.cpp index 274f816f39e1..169e1bae547b 100644 --- a/lib/ExecutionEngine/JIT/Intercept.cpp +++ b/lib/ExecutionEngine/JIT/Intercept.cpp @@ -17,7 +17,7 @@ #include "JIT.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/System/DynamicLibrary.h" +#include "llvm/Support/DynamicLibrary.h" #include "llvm/Config/config.h" using namespace llvm; diff --git a/lib/ExecutionEngine/JIT/JIT.cpp b/lib/ExecutionEngine/JIT/JIT.cpp index 63125b79c8e2..cc76b138a8a6 100644 --- a/lib/ExecutionEngine/JIT/JIT.cpp +++ b/lib/ExecutionEngine/JIT/JIT.cpp @@ -30,7 +30,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MutexGuard.h" -#include "llvm/System/DynamicLibrary.h" +#include "llvm/Support/DynamicLibrary.h" #include "llvm/Config/config.h" using namespace llvm; @@ -66,8 +66,15 @@ static struct RegisterJIT { extern "C" void LLVMLinkInJIT() { } +// Determine whether we can register EH tables. +#if (defined(__GNUC__) && !defined(__ARM_EABI__) && \ + !defined(__USING_SJLJ_EXCEPTIONS__)) +#define HAVE_EHTABLE_SUPPORT 1 +#else +#define HAVE_EHTABLE_SUPPORT 0 +#endif -#if defined(__GNUC__) && !defined(__ARM_EABI__) && !defined(__USING_SJLJ_EXCEPTIONS__) +#if HAVE_EHTABLE_SUPPORT // libgcc defines the __register_frame function to dynamically register new // dwarf frames for exception handling. This functionality is not portable @@ -87,6 +94,7 @@ extern "C" void LLVMLinkInJIT() { // values of an opaque key, used by libgcc to find dwarf tables. extern "C" void __register_frame(void*); +extern "C" void __deregister_frame(void*); #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED <= 1050 # define USE_KEYMGR 1 @@ -190,7 +198,7 @@ void DarwinRegisterFrame(void* FrameBegin) { } #endif // __APPLE__ -#endif // __GNUC__ +#endif // HAVE_EHTABLE_SUPPORT /// createJIT - This is the factory method for creating a JIT for the current /// machine, it does not fall back to the interpreter. This takes ownership @@ -306,7 +314,7 @@ JIT::JIT(Module *M, TargetMachine &tm, TargetJITInfo &tji, } // Register routine for informing unwinding runtime about new EH frames -#if defined(__GNUC__) && !defined(__ARM_EABI__) && !defined(__USING_SJLJ_EXCEPTIONS__) +#if HAVE_EHTABLE_SUPPORT #if USE_KEYMGR struct LibgccObjectInfo* LOI = (struct LibgccObjectInfo*) _keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST); @@ -318,16 +326,21 @@ JIT::JIT(Module *M, TargetMachine &tm, TargetJITInfo &tji, LOI = (LibgccObjectInfo*)calloc(sizeof(struct LibgccObjectInfo), 1); _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, LOI); InstallExceptionTableRegister(DarwinRegisterFrame); + // Not sure about how to deregister on Darwin. #else InstallExceptionTableRegister(__register_frame); + InstallExceptionTableDeregister(__deregister_frame); #endif // __APPLE__ -#endif // __GNUC__ +#endif // HAVE_EHTABLE_SUPPORT // Initialize passes. PM.doInitialization(); } JIT::~JIT() { + // Unregister all exception tables registered by this JIT. + DeregisterAllTables(); + // Cleanup. AllJits->Remove(this); delete jitstate; delete JCE; diff --git a/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp b/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp index 6e11a3cd9368..3b5acb7ecc48 100644 --- a/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp +++ b/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp @@ -25,7 +25,7 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/MutexGuard.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Mutex.h" +#include "llvm/Support/Mutex.h" #include #include @@ -35,7 +35,7 @@ namespace llvm { extern "C" { // Debuggers puts a breakpoint in this function. - DISABLE_INLINE void __jit_debug_register_code() { } + LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() { } // We put information about the JITed function in this global, which the // debugger reads. Make sure to specify the version statically, because the diff --git a/lib/ExecutionEngine/JIT/JITDebugRegisterer.h b/lib/ExecutionEngine/JIT/JITDebugRegisterer.h index 7e53d7847139..dce506bbfefd 100644 --- a/lib/ExecutionEngine/JIT/JITDebugRegisterer.h +++ b/lib/ExecutionEngine/JIT/JITDebugRegisterer.h @@ -16,7 +16,7 @@ #define LLVM_EXECUTION_ENGINE_JIT_DEBUGREGISTERER_H #include "llvm/ADT/DenseMap.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include // This must be kept in sync with gdb/gdb/jit.h . diff --git a/lib/ExecutionEngine/JIT/JITDwarfEmitter.cpp b/lib/ExecutionEngine/JIT/JITDwarfEmitter.cpp index 1105bcc0437f..f54cccadea65 100644 --- a/lib/ExecutionEngine/JIT/JITDwarfEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITDwarfEmitter.cpp @@ -26,7 +26,7 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetInstrInfo.h" -#include "llvm/Target/TargetFrameInfo.h" +#include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetRegisterInfo.h" using namespace llvm; @@ -43,8 +43,9 @@ unsigned char* JITDwarfEmitter::EmitDwarfTable(MachineFunction& F, const TargetMachine& TM = F.getTarget(); TD = TM.getTargetData(); - stackGrowthDirection = TM.getFrameInfo()->getStackGrowthDirection(); + stackGrowthDirection = TM.getFrameLowering()->getStackGrowthDirection(); RI = TM.getRegisterInfo(); + TFI = TM.getFrameLowering(); JCE = &jce; unsigned char* ExceptionTable = EmitExceptionTable(&F, StartFunction, @@ -66,7 +67,7 @@ void JITDwarfEmitter::EmitFrameMoves(intptr_t BaseLabelPtr, const std::vector &Moves) const { unsigned PointerSize = TD->getPointerSize(); - int stackGrowth = stackGrowthDirection == TargetFrameInfo::StackGrowsUp ? + int stackGrowth = stackGrowthDirection == TargetFrameLowering::StackGrowsUp ? PointerSize : -PointerSize; MCSymbol *BaseLabel = 0; @@ -481,7 +482,7 @@ unsigned char* JITDwarfEmitter::EmitExceptionTable(MachineFunction* MF, unsigned char* JITDwarfEmitter::EmitCommonEHFrame(const Function* Personality) const { unsigned PointerSize = TD->getPointerSize(); - int stackGrowth = stackGrowthDirection == TargetFrameInfo::StackGrowsUp ? + int stackGrowth = stackGrowthDirection == TargetFrameLowering::StackGrowsUp ? PointerSize : -PointerSize; unsigned char* StartCommonPtr = (unsigned char*)JCE->getCurrentPCValue(); @@ -523,7 +524,7 @@ JITDwarfEmitter::EmitCommonEHFrame(const Function* Personality) const { } std::vector Moves; - RI->getInitialFrameState(Moves); + TFI->getInitialFrameState(Moves); EmitFrameMoves(0, Moves); JCE->emitAlignmentWithFill(PointerSize, dwarf::DW_CFA_nop); diff --git a/lib/ExecutionEngine/JIT/JITDwarfEmitter.h b/lib/ExecutionEngine/JIT/JITDwarfEmitter.h index 30956820f357..9495697a1aa4 100644 --- a/lib/ExecutionEngine/JIT/JITDwarfEmitter.h +++ b/lib/ExecutionEngine/JIT/JITDwarfEmitter.h @@ -23,6 +23,7 @@ class MachineFunction; class MachineModuleInfo; class MachineMove; class TargetData; +class TargetFrameLowering; class TargetMachine; class TargetRegisterInfo; @@ -30,6 +31,7 @@ class JITDwarfEmitter { const TargetData* TD; JITCodeEmitter* JCE; const TargetRegisterInfo* RI; + const TargetFrameLowering *TFI; MachineModuleInfo* MMI; JIT& Jit; bool stackGrowthDirection; diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp index 4c0d0789cced..4cd8757ad0b8 100644 --- a/lib/ExecutionEngine/JIT/JITEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp @@ -42,8 +42,8 @@ #include "llvm/Support/MutexGuard.h" #include "llvm/Support/ValueHandle.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Disassembler.h" -#include "llvm/System/Memory.h" +#include "llvm/Support/Disassembler.h" +#include "llvm/Support/Memory.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" diff --git a/lib/ExecutionEngine/JIT/JITMemoryManager.cpp b/lib/ExecutionEngine/JIT/JITMemoryManager.cpp index 653e6f1fc07c..eec23cec0af9 100644 --- a/lib/ExecutionEngine/JIT/JITMemoryManager.cpp +++ b/lib/ExecutionEngine/JIT/JITMemoryManager.cpp @@ -22,7 +22,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Memory.h" +#include "llvm/Support/Memory.h" #include #include #include diff --git a/lib/ExecutionEngine/JIT/OProfileJITEventListener.cpp b/lib/ExecutionEngine/JIT/OProfileJITEventListener.cpp index 1ca084b5808b..670fa7da1fed 100644 --- a/lib/ExecutionEngine/JIT/OProfileJITEventListener.cpp +++ b/lib/ExecutionEngine/JIT/OProfileJITEventListener.cpp @@ -26,7 +26,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ValueHandle.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Errno.h" +#include "llvm/Support/Errno.h" #include "llvm/Config/config.h" #include using namespace llvm; diff --git a/lib/ExecutionEngine/JIT/TargetSelect.cpp b/lib/ExecutionEngine/JIT/TargetSelect.cpp index 3349c338052b..6b7173cece18 100644 --- a/lib/ExecutionEngine/JIT/TargetSelect.cpp +++ b/lib/ExecutionEngine/JIT/TargetSelect.cpp @@ -18,7 +18,7 @@ #include "llvm/ADT/Triple.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Host.h" +#include "llvm/Support/Host.h" #include "llvm/Target/SubtargetFeature.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetRegistry.h" diff --git a/lib/ExecutionEngine/MCJIT/CMakeLists.txt b/lib/ExecutionEngine/MCJIT/CMakeLists.txt new file mode 100644 index 000000000000..f7ed176fef78 --- /dev/null +++ b/lib/ExecutionEngine/MCJIT/CMakeLists.txt @@ -0,0 +1,4 @@ +add_llvm_library(LLVMMCJIT + MCJIT.cpp + TargetSelect.cpp + ) diff --git a/lib/ExecutionEngine/MCJIT/MCJIT.cpp b/lib/ExecutionEngine/MCJIT/MCJIT.cpp new file mode 100644 index 000000000000..f1e9dab250bf --- /dev/null +++ b/lib/ExecutionEngine/MCJIT/MCJIT.cpp @@ -0,0 +1,92 @@ +//===-- JIT.cpp - MC-based Just-in-Time Compiler --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MCJIT.h" +#include "llvm/ExecutionEngine/GenericValue.h" +#include "llvm/ExecutionEngine/MCJIT.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/DynamicLibrary.h" + +using namespace llvm; + +namespace { + +static struct RegisterJIT { + RegisterJIT() { MCJIT::Register(); } +} JITRegistrator; + +} + +extern "C" void LLVMLinkInMCJIT() { +} + +ExecutionEngine *MCJIT::createJIT(Module *M, + std::string *ErrorStr, + JITMemoryManager *JMM, + CodeGenOpt::Level OptLevel, + bool GVsWithCode, + CodeModel::Model CMM, + StringRef MArch, + StringRef MCPU, + const SmallVectorImpl& MAttrs) { + // Try to register the program as a source of symbols to resolve against. + // + // FIXME: Don't do this here. + sys::DynamicLibrary::LoadLibraryPermanently(0, NULL); + + // Pick a target either via -march or by guessing the native arch. + // + // FIXME: This should be lifted out of here, it isn't something which should + // be part of the JIT policy, rather the burden for this selection should be + // pushed to clients. + TargetMachine *TM = MCJIT::selectTarget(M, MArch, MCPU, MAttrs, ErrorStr); + if (!TM || (ErrorStr && ErrorStr->length() > 0)) return 0; + TM->setCodeModel(CMM); + + // If the target supports JIT code generation, create the JIT. + if (TargetJITInfo *TJ = TM->getJITInfo()) + return new MCJIT(M, *TM, *TJ, JMM, OptLevel, GVsWithCode); + + if (ErrorStr) + *ErrorStr = "target does not support JIT code generation"; + return 0; +} + +MCJIT::MCJIT(Module *M, TargetMachine &tm, TargetJITInfo &tji, + JITMemoryManager *JMM, CodeGenOpt::Level OptLevel, + bool AllocateGVsWithCode) + : ExecutionEngine(M) { +} + +MCJIT::~MCJIT() { +} + +void *MCJIT::getPointerToBasicBlock(BasicBlock *BB) { + report_fatal_error("not yet implemented"); + return 0; +} + +void *MCJIT::getPointerToFunction(Function *F) { + report_fatal_error("not yet implemented"); + return 0; +} + +void *MCJIT::recompileAndRelinkFunction(Function *F) { + report_fatal_error("not yet implemented"); +} + +void MCJIT::freeMachineCodeForFunction(Function *F) { + report_fatal_error("not yet implemented"); +} + +GenericValue MCJIT::runFunction(Function *F, + const std::vector &ArgValues) { + report_fatal_error("not yet implemented"); + return GenericValue(); +} diff --git a/lib/ExecutionEngine/MCJIT/MCJIT.h b/lib/ExecutionEngine/MCJIT/MCJIT.h new file mode 100644 index 000000000000..cd1f989b10c7 --- /dev/null +++ b/lib/ExecutionEngine/MCJIT/MCJIT.h @@ -0,0 +1,68 @@ +//===-- MCJIT.h - Class definition for the MCJIT ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_EXECUTIONENGINE_MCJIT_H +#define LLVM_LIB_EXECUTIONENGINE_MCJIT_H + +#include "llvm/ExecutionEngine/ExecutionEngine.h" + +namespace llvm { + +class MCJIT : public ExecutionEngine { + MCJIT(Module *M, TargetMachine &tm, TargetJITInfo &tji, + JITMemoryManager *JMM, CodeGenOpt::Level OptLevel, + bool AllocateGVsWithCode); +public: + ~MCJIT(); + + /// @name ExecutionEngine interface implementation + /// @{ + + virtual void *getPointerToBasicBlock(BasicBlock *BB); + + virtual void *getPointerToFunction(Function *F); + + virtual void *recompileAndRelinkFunction(Function *F); + + virtual void freeMachineCodeForFunction(Function *F); + + virtual GenericValue runFunction(Function *F, + const std::vector &ArgValues); + + /// @} + /// @name (Private) Registration Interfaces + /// @{ + + static void Register() { + MCJITCtor = createJIT; + } + + // FIXME: This routine is scheduled for termination. Do not use it. + static TargetMachine *selectTarget(Module *M, + StringRef MArch, + StringRef MCPU, + const SmallVectorImpl& MAttrs, + std::string *Err); + + static ExecutionEngine *createJIT(Module *M, + std::string *ErrorStr, + JITMemoryManager *JMM, + CodeGenOpt::Level OptLevel, + bool GVsWithCode, + CodeModel::Model CMM, + StringRef MArch, + StringRef MCPU, + const SmallVectorImpl& MAttrs); + + // @} +}; + +} // End llvm namespace + +#endif diff --git a/lib/ExecutionEngine/MCJIT/Makefile b/lib/ExecutionEngine/MCJIT/Makefile new file mode 100644 index 000000000000..967efbc0efa4 --- /dev/null +++ b/lib/ExecutionEngine/MCJIT/Makefile @@ -0,0 +1,13 @@ +##===- lib/ExecutionEngine/MCJIT/Makefile ------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../.. +LIBRARYNAME = LLVMMCJIT + +include $(LEVEL)/Makefile.common diff --git a/lib/ExecutionEngine/MCJIT/TargetSelect.cpp b/lib/ExecutionEngine/MCJIT/TargetSelect.cpp new file mode 100644 index 000000000000..50f65938bb0a --- /dev/null +++ b/lib/ExecutionEngine/MCJIT/TargetSelect.cpp @@ -0,0 +1,91 @@ +//===-- TargetSelect.cpp - Target Chooser Code ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This just asks the TargetRegistry for the appropriate JIT to use, and allows +// the user to specify a specific one on the commandline with -march=x. Clients +// should initialize targets prior to calling createJIT. +// +//===----------------------------------------------------------------------===// + +#include "MCJIT.h" +#include "llvm/Module.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Host.h" +#include "llvm/Target/SubtargetFeature.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetRegistry.h" +using namespace llvm; + +/// selectTarget - Pick a target either via -march or by guessing the native +/// arch. Add any CPU features specified via -mcpu or -mattr. +TargetMachine *MCJIT::selectTarget(Module *Mod, + StringRef MArch, + StringRef MCPU, + const SmallVectorImpl& MAttrs, + std::string *ErrorStr) { + Triple TheTriple(Mod->getTargetTriple()); + if (TheTriple.getTriple().empty()) + TheTriple.setTriple(sys::getHostTriple()); + + // Adjust the triple to match what the user requested. + const Target *TheTarget = 0; + if (!MArch.empty()) { + for (TargetRegistry::iterator it = TargetRegistry::begin(), + ie = TargetRegistry::end(); it != ie; ++it) { + if (MArch == it->getName()) { + TheTarget = &*it; + break; + } + } + + if (!TheTarget) { + *ErrorStr = "No available targets are compatible with this -march, " + "see -version for the available targets.\n"; + return 0; + } + + // Adjust the triple to match (if known), otherwise stick with the + // module/host triple. + Triple::ArchType Type = Triple::getArchTypeForLLVMName(MArch); + if (Type != Triple::UnknownArch) + TheTriple.setArch(Type); + } else { + std::string Error; + TheTarget = TargetRegistry::lookupTarget(TheTriple.getTriple(), Error); + if (TheTarget == 0) { + if (ErrorStr) + *ErrorStr = Error; + return 0; + } + } + + if (!TheTarget->hasJIT()) { + errs() << "WARNING: This target JIT is not designed for the host you are" + << " running. If bad things happen, please choose a different " + << "-march switch.\n"; + } + + // Package up features to be passed to target/subtarget + std::string FeaturesStr; + if (!MCPU.empty() || !MAttrs.empty()) { + SubtargetFeatures Features; + Features.setCPU(MCPU); + for (unsigned i = 0; i != MAttrs.size(); ++i) + Features.AddFeature(MAttrs[i]); + FeaturesStr = Features.getString(); + } + + // Allocate a target... + TargetMachine *Target = + TheTarget->createTargetMachine(TheTriple.getTriple(), FeaturesStr); + assert(Target && "Could not allocate target machine!"); + return Target; +} diff --git a/lib/ExecutionEngine/Makefile b/lib/ExecutionEngine/Makefile index e0e050e89728..1858d776616c 100644 --- a/lib/ExecutionEngine/Makefile +++ b/lib/ExecutionEngine/Makefile @@ -8,6 +8,6 @@ ##===----------------------------------------------------------------------===## LEVEL = ../.. LIBRARYNAME = LLVMExecutionEngine -PARALLEL_DIRS = Interpreter JIT +PARALLEL_DIRS = Interpreter JIT MCJIT include $(LEVEL)/Makefile.common diff --git a/lib/Linker/LinkItems.cpp b/lib/Linker/LinkItems.cpp index 1be2becc86c3..52a0d175a5cd 100644 --- a/lib/Linker/LinkItems.cpp +++ b/lib/Linker/LinkItems.cpp @@ -15,9 +15,10 @@ #include "llvm/Linker.h" #include "llvm/Module.h" #include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Path.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/system_error.h" using namespace llvm; // LinkItems - This function is the main entry point into linking. It takes a @@ -160,19 +161,19 @@ bool Linker::LinkInFile(const sys::Path &File, bool &is_native) { // Check for a file of name "-", which means "read standard input" if (File.str() == "-") { std::auto_ptr M; - if (MemoryBuffer *Buffer = MemoryBuffer::getSTDIN(&Error)) { + OwningPtr Buffer; + error_code ec; + if (!(ec = MemoryBuffer::getSTDIN(Buffer))) { if (!Buffer->getBufferSize()) { - delete Buffer; Error = "standard input is empty"; } else { - M.reset(ParseBitcodeFile(Buffer, Context, &Error)); - delete Buffer; + M.reset(ParseBitcodeFile(Buffer.get(), Context, &Error)); if (M.get()) if (!LinkInModule(M.get(), &Error)) return false; } } - return error("Cannot link stdin: " + Error); + return error("Cannot link stdin: " + ec.message()); } // Determine what variety of file it is. diff --git a/lib/Linker/LinkModules.cpp b/lib/Linker/LinkModules.cpp index 7e8245a9e3a6..5aa06abdd989 100644 --- a/lib/Linker/LinkModules.cpp +++ b/lib/Linker/LinkModules.cpp @@ -28,7 +28,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Path.h" #include "llvm/Transforms/Utils/ValueMapper.h" #include "llvm/ADT/DenseMap.h" using namespace llvm; @@ -434,8 +434,10 @@ static bool GetLinkageResult(GlobalValue *Dest, const GlobalValue *Src, } // Check visibility - if (Dest && Src->getVisibility() != Dest->getVisibility()) - if (!Src->isDeclaration() && !Dest->isDeclaration()) + if (Dest && Src->getVisibility() != Dest->getVisibility() && + !Src->isDeclaration() && !Dest->isDeclaration() && + !Src->hasAvailableExternallyLinkage() && + !Dest->hasAvailableExternallyLinkage()) return Error(Err, "Linking globals named '" + Src->getName() + "': symbols have different visibilities!"); return false; @@ -449,10 +451,9 @@ static void LinkNamedMDNodes(Module *Dest, Module *Src, const NamedMDNode *SrcNMD = I; NamedMDNode *DestNMD = Dest->getOrInsertNamedMetadata(SrcNMD->getName()); // Add Src elements into Dest node. - for (unsigned i = 0, e = SrcNMD->getNumOperands(); i != e; ++i) + for (unsigned i = 0, e = SrcNMD->getNumOperands(); i != e; ++i) DestNMD->addOperand(cast(MapValue(SrcNMD->getOperand(i), - ValueMap, - true))); + ValueMap))); } } @@ -520,6 +521,8 @@ static bool LinkGlobals(Module *Dest, const Module *Src, continue; } + bool HasUnnamedAddr = SGV->hasUnnamedAddr() && DGV->hasUnnamedAddr(); + // If the visibilities of the symbols disagree and the destination is a // prototype, take the visibility of its input. if (DGV->isDeclaration()) @@ -559,14 +562,17 @@ static bool LinkGlobals(Module *Dest, const Module *Src, // we are replacing may be a function (if a prototype, weak, etc) or a // global variable. GlobalVariable *NewDGV = - new GlobalVariable(*Dest, SGV->getType()->getElementType(), - SGV->isConstant(), NewLinkage, /*init*/0, + new GlobalVariable(*Dest, SGV->getType()->getElementType(), + SGV->isConstant(), NewLinkage, /*init*/0, DGV->getName(), 0, false, SGV->getType()->getAddressSpace()); + // Set the unnamed_addr. + NewDGV->setUnnamedAddr(HasUnnamedAddr); + // Propagate alignment, section, and visibility info. CopyGVAttributes(NewDGV, SGV); - DGV->replaceAllUsesWith(ConstantExpr::getBitCast(NewDGV, + DGV->replaceAllUsesWith(ConstantExpr::getBitCast(NewDGV, DGV->getType())); // DGV will conflict with NewDGV because they both had the same @@ -608,8 +614,9 @@ static bool LinkGlobals(Module *Dest, const Module *Src, "': symbol multiple defined"); } - // Set calculated linkage + // Set calculated linkage and unnamed_addr DGV->setLinkage(NewLinkage); + DGV->setUnnamedAddr(HasUnnamedAddr); // Make sure to remember this mapping... ValueMap[SGV] = ConstantExpr::getBitCast(DGV, SGV->getType()); @@ -668,6 +675,13 @@ static bool LinkAlias(Module *Dest, const Module *Src, GlobalValue* DAliasee = cast(VMI->second); GlobalValue* DGV = NULL; + // Fixup aliases to bitcasts. Note that aliases to GEPs are still broken + // by this, but aliases to GEPs are broken to a lot of other things, so + // it's less important. + Constant *DAliaseeConst = DAliasee; + if (SGA->getType() != DAliasee->getType()) + DAliaseeConst = ConstantExpr::getBitCast(DAliasee, SGA->getType()); + // Try to find something 'similar' to SGA in destination module. if (!DGV && !SGA->hasLocalLinkage()) { DGV = Dest->getNamedAlias(SGA->getName()); @@ -721,7 +735,7 @@ static bool LinkAlias(Module *Dest, const Module *Src, "': aliasee is not global variable"); NewGA = new GlobalAlias(SGA->getType(), SGA->getLinkage(), - SGA->getName(), DAliasee, Dest); + SGA->getName(), DAliaseeConst, Dest); CopyGVAttributes(NewGA, SGA); // Any uses of DGV need to change to NewGA, with cast, if needed. @@ -750,7 +764,7 @@ static bool LinkAlias(Module *Dest, const Module *Src, "': aliasee is not function"); NewGA = new GlobalAlias(SGA->getType(), SGA->getLinkage(), - SGA->getName(), DAliasee, Dest); + SGA->getName(), DAliaseeConst, Dest); CopyGVAttributes(NewGA, SGA); // Any uses of DF need to change to NewGA, with cast, if needed. @@ -772,14 +786,8 @@ static bool LinkAlias(Module *Dest, const Module *Src, } else { // No linking to be performed, simply create an identical version of the // alias over in the dest module... - Constant *Aliasee = DAliasee; - // Fixup aliases to bitcasts. Note that aliases to GEPs are still broken - // by this, but aliases to GEPs are broken to a lot of other things, so - // it's less important. - if (SGA->getType() != DAliasee->getType()) - Aliasee = ConstantExpr::getBitCast(DAliasee, SGA->getType()); NewGA = new GlobalAlias(SGA->getType(), SGA->getLinkage(), - SGA->getName(), Aliasee, Dest); + SGA->getName(), DAliaseeConst, Dest); CopyGVAttributes(NewGA, SGA); // Proceed to 'common' steps @@ -813,9 +821,9 @@ static bool LinkGlobalInits(Module *Dest, const Module *Src, const GlobalVariable *SGV = I; if (SGV->hasInitializer()) { // Only process initialized GV's - // Figure out what the initializer looks like in the dest module... + // Figure out what the initializer looks like in the dest module. Constant *SInit = - cast(MapValue(SGV->getInitializer(), ValueMap, true)); + cast(MapValue(SGV->getInitializer(), ValueMap)); // Grab destination global variable or alias. GlobalValue *DGV = cast(ValueMap[SGV]->stripPointerCasts()); @@ -927,7 +935,7 @@ static bool LinkFunctionProtos(Module *Dest, const Module *Src, CopyGVAttributes(NewDF, SF); // Any uses of DF need to change to NewDF, with cast - DGV->replaceAllUsesWith(ConstantExpr::getBitCast(NewDF, + DGV->replaceAllUsesWith(ConstantExpr::getBitCast(NewDF, DGV->getType())); // DF will conflict with NewDF because they both had the same. We must @@ -995,32 +1003,10 @@ static bool LinkFunctionBody(Function *Dest, Function *Src, // At this point, all of the instructions and values of the function are now // copied over. The only problem is that they are still referencing values in // the Source function as operands. Loop through all of the operands of the - // functions and patch them up to point to the local versions... - // - // This is the same as RemapInstruction, except that it avoids remapping - // instruction and basic block operands. - // + // functions and patch them up to point to the local versions. for (Function::iterator BB = Dest->begin(), BE = Dest->end(); BB != BE; ++BB) - for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) { - // Remap operands. - for (Instruction::op_iterator OI = I->op_begin(), OE = I->op_end(); - OI != OE; ++OI) - if (!isa(*OI) && !isa(*OI)) - *OI = MapValue(*OI, ValueMap, true); - - // Remap attached metadata. - SmallVector, 4> MDs; - I->getAllMetadata(MDs); - for (SmallVectorImpl >::iterator - MI = MDs.begin(), ME = MDs.end(); MI != ME; ++MI) { - Value *Old = MI->second; - if (!isa(Old) && !isa(Old)) { - Value *New = MapValue(Old, ValueMap, true); - if (New != Old) - I->setMetadata(MI->first, cast(New)); - } - } - } + for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) + RemapInstruction(I, ValueMap, RF_IgnoreMissingEntries); // There is no need to map the arguments anymore. for (Function::arg_iterator I = Src->arg_begin(), E = Src->arg_end(); @@ -1099,7 +1085,7 @@ static bool LinkAppendingVars(Module *M, "Appending variables with different section name need to be linked!"); unsigned NewSize = T1->getNumElements() + T2->getNumElements(); - ArrayType *NewType = ArrayType::get(T1->getElementType(), + ArrayType *NewType = ArrayType::get(T1->getElementType(), NewSize); G1->setName(""); // Clear G1's name in case of a conflict! @@ -1143,7 +1129,7 @@ static bool LinkAppendingVars(Module *M, // getelementptr instructions to not use the Cast! G1->replaceAllUsesWith(ConstantExpr::getBitCast(NG, G1->getType())); - G2->replaceAllUsesWith(ConstantExpr::getBitCast(NG, + G2->replaceAllUsesWith(ConstantExpr::getBitCast(NG, G2->getType())); // Remove the two globals from the module now... @@ -1217,8 +1203,13 @@ Linker::LinkModules(Module *Dest, Module *Src, std::string *ErrorMsg) { Src->getDataLayout() != Dest->getDataLayout()) errs() << "WARNING: Linking two modules of different data layouts!\n"; if (!Src->getTargetTriple().empty() && - Dest->getTargetTriple() != Src->getTargetTriple()) - errs() << "WARNING: Linking two modules of different target triples!\n"; + Dest->getTargetTriple() != Src->getTargetTriple()) { + errs() << "WARNING: Linking two modules of different target triples: "; + if (!Src->getModuleIdentifier().empty()) + errs() << Src->getModuleIdentifier() << ": "; + errs() << "'" << Src->getTargetTriple() << "' and '" + << Dest->getTargetTriple() << "'\n"; + } // Append the module inline asm string. if (!Src->getModuleInlineAsm().empty()) { @@ -1300,10 +1291,9 @@ Linker::LinkModules(Module *Dest, Module *Src, std::string *ErrorMsg) { // If the source library's module id is in the dependent library list of the // destination library, remove it since that module is now linked in. - sys::Path modId; - modId.set(Src->getModuleIdentifier()); - if (!modId.isEmpty()) - Dest->removeLibrary(modId.getBasename()); + const std::string &modId = Src->getModuleIdentifier(); + if (!modId.empty()) + Dest->removeLibrary(sys::path::stem(modId)); return false; } diff --git a/lib/Linker/Linker.cpp b/lib/Linker/Linker.cpp index 32aa0f901121..fba91da5ddd1 100644 --- a/lib/Linker/Linker.cpp +++ b/lib/Linker/Linker.cpp @@ -14,10 +14,11 @@ #include "llvm/Linker.h" #include "llvm/Module.h" #include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Path.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Config/config.h" +#include "llvm/Support/system_error.h" using namespace llvm; Linker::Linker(StringRef progname, StringRef modname, @@ -97,13 +98,14 @@ std::auto_ptr Linker::LoadObject(const sys::Path &FN) { std::string ParseErrorMessage; Module *Result = 0; - - std::auto_ptr Buffer(MemoryBuffer::getFileOrSTDIN(FN.c_str())); - if (Buffer.get()) - Result = ParseBitcodeFile(Buffer.get(), Context, &ParseErrorMessage); + + OwningPtr Buffer; + if (error_code ec = MemoryBuffer::getFileOrSTDIN(FN.c_str(), Buffer)) + ParseErrorMessage = "Error reading file '" + FN.str() + "'" + ": " + + ec.message(); else - ParseErrorMessage = "Error reading file '" + FN.str() + "'"; - + Result = ParseBitcodeFile(Buffer.get(), Context, &ParseErrorMessage); + if (Result) return std::auto_ptr(Result); Error = "Bitcode file '" + FN.str() + "' could not be loaded"; @@ -133,7 +135,7 @@ static inline sys::Path IsLibrary(StringRef Name, // Try the libX.so (or .dylib) form FullPath.eraseSuffix(); - FullPath.appendSuffix(&(LTDL_SHLIB_EXT[1])); + FullPath.appendSuffix(sys::Path::GetDLLSuffix()); if (FullPath.isDynamicLibrary()) // Native shared library? return FullPath; if (FullPath.isBitcodeFile()) // .so file containing bitcode? diff --git a/lib/MC/CMakeLists.txt b/lib/MC/CMakeLists.txt index 60a3a3e3e312..f1811a1716fb 100644 --- a/lib/MC/CMakeLists.txt +++ b/lib/MC/CMakeLists.txt @@ -8,6 +8,7 @@ add_llvm_library(LLVMMC MCCodeEmitter.cpp MCContext.cpp MCDisassembler.cpp + MCELFObjectTargetWriter.cpp MCELFStreamer.cpp MCExpr.cpp MCInst.cpp @@ -16,9 +17,11 @@ add_llvm_library(LLVMMC MCDwarf.cpp MCLoggingStreamer.cpp MCMachOStreamer.cpp + MCMachObjectTargetWriter.cpp MCNullStreamer.cpp MCObjectStreamer.cpp MCObjectWriter.cpp + MCPureStreamer.cpp MCSection.cpp MCSectionCOFF.cpp MCSectionELF.cpp @@ -31,3 +34,6 @@ add_llvm_library(LLVMMC WinCOFFObjectWriter.cpp TargetAsmBackend.cpp ) + +add_subdirectory(MCParser) +add_subdirectory(MCDisassembler) diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp index cf35b45715e1..8a00a16cfb4a 100644 --- a/lib/MC/ELFObjectWriter.cpp +++ b/lib/MC/ELFObjectWriter.cpp @@ -11,7 +11,8 @@ // //===----------------------------------------------------------------------===// -#include "llvm/MC/ELFObjectWriter.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/Twine.h" @@ -20,6 +21,7 @@ #include "llvm/MC/MCContext.h" #include "llvm/MC/MCELFSymbolFlags.h" #include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCELFObjectWriter.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSymbol.h" @@ -28,27 +30,76 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ELF.h" #include "llvm/Target/TargetAsmBackend.h" +#include "llvm/ADT/StringSwitch.h" #include "../Target/X86/X86FixupKinds.h" +#include "../Target/ARM/ARMFixupKinds.h" #include using namespace llvm; -namespace { +static unsigned GetType(const MCSymbolData &SD) { + uint32_t Type = (SD.getFlags() & (0xf << ELF_STT_Shift)) >> ELF_STT_Shift; + assert(Type == ELF::STT_NOTYPE || Type == ELF::STT_OBJECT || + Type == ELF::STT_FUNC || Type == ELF::STT_SECTION || + Type == ELF::STT_FILE || Type == ELF::STT_COMMON || + Type == ELF::STT_TLS); + return Type; +} - class ELFObjectWriterImpl { - static bool isFixupKindX86PCRel(unsigned Kind) { - switch (Kind) { - default: - return false; - case X86::reloc_pcrel_1byte: - case X86::reloc_pcrel_4byte: - case X86::reloc_riprel_4byte: - case X86::reloc_riprel_4byte_movq_load: - return true; - } - } +static unsigned GetBinding(const MCSymbolData &SD) { + uint32_t Binding = (SD.getFlags() & (0xf << ELF_STB_Shift)) >> ELF_STB_Shift; + assert(Binding == ELF::STB_LOCAL || Binding == ELF::STB_GLOBAL || + Binding == ELF::STB_WEAK); + return Binding; +} + +static void SetBinding(MCSymbolData &SD, unsigned Binding) { + assert(Binding == ELF::STB_LOCAL || Binding == ELF::STB_GLOBAL || + Binding == ELF::STB_WEAK); + uint32_t OtherFlags = SD.getFlags() & ~(0xf << ELF_STB_Shift); + SD.setFlags(OtherFlags | (Binding << ELF_STB_Shift)); +} +static unsigned GetVisibility(MCSymbolData &SD) { + unsigned Visibility = + (SD.getFlags() & (0xf << ELF_STV_Shift)) >> ELF_STV_Shift; + assert(Visibility == ELF::STV_DEFAULT || Visibility == ELF::STV_INTERNAL || + Visibility == ELF::STV_HIDDEN || Visibility == ELF::STV_PROTECTED); + return Visibility; +} + + +static bool RelocNeedsGOT(MCSymbolRefExpr::VariantKind Variant) { + switch (Variant) { + default: + return false; + case MCSymbolRefExpr::VK_GOT: + case MCSymbolRefExpr::VK_PLT: + case MCSymbolRefExpr::VK_GOTPCREL: + case MCSymbolRefExpr::VK_TPOFF: + case MCSymbolRefExpr::VK_TLSGD: + case MCSymbolRefExpr::VK_GOTTPOFF: + case MCSymbolRefExpr::VK_INDNTPOFF: + case MCSymbolRefExpr::VK_NTPOFF: + case MCSymbolRefExpr::VK_GOTNTPOFF: + case MCSymbolRefExpr::VK_TLSLDM: + case MCSymbolRefExpr::VK_DTPOFF: + case MCSymbolRefExpr::VK_TLSLD: + return true; + } +} + +static bool isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind) { + const MCFixupKindInfo &FKI = + Asm.getBackend().getFixupKindInfo((MCFixupKind) Kind); + + return FKI.Flags & MCFixupKindInfo::FKF_IsPCRel; +} + +namespace { + class ELFObjectWriter : public MCObjectWriter { + protected: /*static bool isFixupKindX86RIPRel(unsigned Kind) { return Kind == X86::reloc_riprel_4byte || Kind == X86::reloc_riprel_4byte_movq_load; @@ -64,6 +115,10 @@ namespace { // Support lexicographic sorting. bool operator<(const ELFSymbolData &RHS) const { + if (GetType(*SymbolData) == ELF::STT_FILE) + return true; + if (GetType(*RHS.SymbolData) == ELF::STT_FILE) + return false; return SymbolData->getSymbol().getName() < RHS.SymbolData->getSymbol().getName(); } @@ -75,15 +130,33 @@ namespace { struct ELFRelocationEntry { // Make these big enough for both 32-bit and 64-bit uint64_t r_offset; - uint64_t r_info; + int Index; + unsigned Type; + const MCSymbol *Symbol; uint64_t r_addend; + ELFRelocationEntry() + : r_offset(0), Index(0), Type(0), Symbol(0), r_addend(0) {} + + ELFRelocationEntry(uint64_t RelocOffset, int Idx, + unsigned RelType, const MCSymbol *Sym, + uint64_t Addend) + : r_offset(RelocOffset), Index(Idx), Type(RelType), + Symbol(Sym), r_addend(Addend) {} + // Support lexicographic sorting. bool operator<(const ELFRelocationEntry &RE) const { return RE.r_offset < r_offset; } }; + /// The target specific ELF writer instance. + llvm::OwningPtr TargetObjectWriter; + + SmallPtrSet UsedInReloc; + SmallPtrSet WeakrefUsedInReloc; + DenseMap Renames; + llvm::DenseMap > Relocations; DenseMap SectionStringTableIndex; @@ -99,49 +172,52 @@ namespace { /// @} - ELFObjectWriter *Writer; - - raw_ostream &OS; - - // This holds the current offset into the object file. - size_t FileOff; - - unsigned Is64Bit : 1; + bool NeedsGOT; - bool HasRelocationAddend; + bool NeedsSymtabShndx; // This holds the symbol table index of the last local symbol. unsigned LastLocalSymbolIndex; // This holds the .strtab section index. unsigned StringTableIndex; + // This holds the .symtab section index. + unsigned SymbolTableIndex; unsigned ShstrtabIndex; + + const MCSymbol *SymbolToReloc(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F) const; + + // For arch-specific emission of explicit reloc symbol + virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F, + bool IsBSS) const { + return NULL; + } + + bool is64Bit() const { return TargetObjectWriter->is64Bit(); } + bool hasRelocationAddend() const { + return TargetObjectWriter->hasRelocationAddend(); + } + public: - ELFObjectWriterImpl(ELFObjectWriter *_Writer, bool _Is64Bit, - bool _HasRelAddend) - : Writer(_Writer), OS(Writer->getStream()), FileOff(0), - Is64Bit(_Is64Bit), HasRelocationAddend(_HasRelAddend) { + ELFObjectWriter(MCELFObjectTargetWriter *MOTW, + raw_ostream &_OS, bool IsLittleEndian) + : MCObjectWriter(_OS, IsLittleEndian), + TargetObjectWriter(MOTW), + NeedsGOT(false), NeedsSymtabShndx(false){ } - void Write8(uint8_t Value) { Writer->Write8(Value); } - void Write16(uint16_t Value) { Writer->Write16(Value); } - void Write32(uint32_t Value) { Writer->Write32(Value); } - //void Write64(uint64_t Value) { Writer->Write64(Value); } - void WriteZeros(unsigned N) { Writer->WriteZeros(N); } - //void WriteBytes(StringRef Str, unsigned ZeroFillSize = 0) { - // Writer->WriteBytes(Str, ZeroFillSize); - //} + virtual ~ELFObjectWriter(); void WriteWord(uint64_t W) { - if (Is64Bit) - Writer->Write64(W); + if (is64Bit()) + Write64(W); else - Writer->Write32(W); - } - - void String8(char *buf, uint8_t Value) { - buf[0] = Value; + Write32(W); } void StringLE16(char *buf, uint16_t Value) { @@ -174,86 +250,191 @@ namespace { StringBE32(buf + 4, uint32_t(Value >> 0)); } - void String16(char *buf, uint16_t Value) { - if (Writer->isLittleEndian()) + void String8(MCDataFragment &F, uint8_t Value) { + char buf[1]; + buf[0] = Value; + F.getContents() += StringRef(buf, 1); + } + + void String16(MCDataFragment &F, uint16_t Value) { + char buf[2]; + if (isLittleEndian()) StringLE16(buf, Value); else StringBE16(buf, Value); + F.getContents() += StringRef(buf, 2); } - void String32(char *buf, uint32_t Value) { - if (Writer->isLittleEndian()) + void String32(MCDataFragment &F, uint32_t Value) { + char buf[4]; + if (isLittleEndian()) StringLE32(buf, Value); else StringBE32(buf, Value); + F.getContents() += StringRef(buf, 4); } - void String64(char *buf, uint64_t Value) { - if (Writer->isLittleEndian()) + void String64(MCDataFragment &F, uint64_t Value) { + char buf[8]; + if (isLittleEndian()) StringLE64(buf, Value); else StringBE64(buf, Value); + F.getContents() += StringRef(buf, 8); } - void WriteHeader(uint64_t SectionDataSize, unsigned NumberOfSections); + virtual void WriteHeader(uint64_t SectionDataSize, unsigned NumberOfSections); + + /// Default e_flags = 0 + virtual void WriteEFlags() { Write32(0); } - void WriteSymbolEntry(MCDataFragment *F, uint64_t name, uint8_t info, + virtual void WriteSymbolEntry(MCDataFragment *SymtabF, MCDataFragment *ShndxF, + uint64_t name, uint8_t info, uint64_t value, uint64_t size, - uint8_t other, uint16_t shndx); + uint8_t other, uint32_t shndx, + bool Reserved); - void WriteSymbol(MCDataFragment *F, ELFSymbolData &MSD, + virtual void WriteSymbol(MCDataFragment *SymtabF, MCDataFragment *ShndxF, + ELFSymbolData &MSD, const MCAsmLayout &Layout); - void WriteSymbolTable(MCDataFragment *F, const MCAssembler &Asm, - const MCAsmLayout &Layout); + typedef DenseMap SectionIndexMapTy; + virtual void WriteSymbolTable(MCDataFragment *SymtabF, MCDataFragment *ShndxF, + const MCAssembler &Asm, + const MCAsmLayout &Layout, + const SectionIndexMapTy &SectionIndexMap); - void RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, - const MCFragment *Fragment, const MCFixup &Fixup, - MCValue Target, uint64_t &FixedValue); + virtual void RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, + const MCFragment *Fragment, const MCFixup &Fixup, + MCValue Target, uint64_t &FixedValue); - uint64_t getSymbolIndexInSymbolTable(const MCAssembler &Asm, + virtual uint64_t getSymbolIndexInSymbolTable(const MCAssembler &Asm, const MCSymbol *S); + // Map from a group section to the signature symbol + typedef DenseMap GroupMapTy; + // Map from a signature symbol to the group section + typedef DenseMap RevGroupMapTy; + /// ComputeSymbolTable - Compute the symbol table data /// /// \param StringTable [out] - The string table data. /// \param StringIndexMap [out] - Map from symbol names to offsets in the /// string table. - void ComputeSymbolTable(MCAssembler &Asm); + virtual void ComputeSymbolTable(MCAssembler &Asm, + const SectionIndexMapTy &SectionIndexMap, + RevGroupMapTy RevGroupMap); - void WriteRelocation(MCAssembler &Asm, MCAsmLayout &Layout, + virtual void ComputeIndexMap(MCAssembler &Asm, + SectionIndexMapTy &SectionIndexMap); + + virtual void WriteRelocation(MCAssembler &Asm, MCAsmLayout &Layout, const MCSectionData &SD); - void WriteRelocations(MCAssembler &Asm, MCAsmLayout &Layout) { + virtual void WriteRelocations(MCAssembler &Asm, MCAsmLayout &Layout) { for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { WriteRelocation(Asm, Layout, *it); } } - void CreateMetadataSections(MCAssembler &Asm, MCAsmLayout &Layout); + virtual void CreateMetadataSections(MCAssembler &Asm, MCAsmLayout &Layout, + const SectionIndexMapTy &SectionIndexMap); - void ExecutePostLayoutBinding(MCAssembler &Asm) { - // Compute symbol table information. - ComputeSymbolTable(Asm); - } + // Create the sections that show up in the symbol table. Currently + // those are the .note.GNU-stack section and the group sections. + virtual void CreateIndexedSections(MCAssembler &Asm, MCAsmLayout &Layout, + GroupMapTy &GroupMap, + RevGroupMapTy &RevGroupMap); - void WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags, + virtual void ExecutePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout); + + virtual void WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags, uint64_t Address, uint64_t Offset, uint64_t Size, uint32_t Link, uint32_t Info, uint64_t Alignment, uint64_t EntrySize); - void WriteRelocationsFragment(const MCAssembler &Asm, MCDataFragment *F, - const MCSectionData *SD); + virtual void WriteRelocationsFragment(const MCAssembler &Asm, + MCDataFragment *F, + const MCSectionData *SD); + + virtual void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout); + virtual void WriteSection(MCAssembler &Asm, + const SectionIndexMapTy &SectionIndexMap, + uint32_t GroupSymbolIndex, + uint64_t Offset, uint64_t Size, uint64_t Alignment, + const MCSectionELF &Section); + + protected: + virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, + bool IsPCRel, bool IsRelocWithSymbol, + int64_t Addend) = 0; + }; + + //===- X86ELFObjectWriter -------------------------------------------===// + + class X86ELFObjectWriter : public ELFObjectWriter { + public: + X86ELFObjectWriter(MCELFObjectTargetWriter *MOTW, + raw_ostream &_OS, + bool IsLittleEndian); + + virtual ~X86ELFObjectWriter(); + protected: + virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, + bool IsPCRel, bool IsRelocWithSymbol, + int64_t Addend); + }; + + + //===- ARMELFObjectWriter -------------------------------------------===// + + class ARMELFObjectWriter : public ELFObjectWriter { + public: + // FIXME: MCAssembler can't yet return the Subtarget, + enum { DefaultEABIVersion = 0x05000000U }; + + ARMELFObjectWriter(MCELFObjectTargetWriter *MOTW, + raw_ostream &_OS, + bool IsLittleEndian); - void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout); + virtual ~ARMELFObjectWriter(); + + virtual void WriteEFlags(); + protected: + virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F, + bool IsBSS) const; + + virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, + bool IsPCRel, bool IsRelocWithSymbol, + int64_t Addend); }; + //===- MBlazeELFObjectWriter -------------------------------------------===// + + class MBlazeELFObjectWriter : public ELFObjectWriter { + public: + MBlazeELFObjectWriter(MCELFObjectTargetWriter *MOTW, + raw_ostream &_OS, + bool IsLittleEndian); + + virtual ~MBlazeELFObjectWriter(); + protected: + virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, + bool IsPCRel, bool IsRelocWithSymbol, + int64_t Addend); + }; } +ELFObjectWriter::~ELFObjectWriter() +{} + // Emit the ELF header. -void ELFObjectWriterImpl::WriteHeader(uint64_t SectionDataSize, - unsigned NumberOfSections) { +void ELFObjectWriter::WriteHeader(uint64_t SectionDataSize, + unsigned NumberOfSections) { // ELF Header // ---------- // @@ -267,140 +448,193 @@ void ELFObjectWriterImpl::WriteHeader(uint64_t SectionDataSize, Write8('L'); // e_ident[EI_MAG2] Write8('F'); // e_ident[EI_MAG3] - Write8(Is64Bit ? ELF::ELFCLASS64 : ELF::ELFCLASS32); // e_ident[EI_CLASS] + Write8(is64Bit() ? ELF::ELFCLASS64 : ELF::ELFCLASS32); // e_ident[EI_CLASS] // e_ident[EI_DATA] - Write8(Writer->isLittleEndian() ? ELF::ELFDATA2LSB : ELF::ELFDATA2MSB); + Write8(isLittleEndian() ? ELF::ELFDATA2LSB : ELF::ELFDATA2MSB); Write8(ELF::EV_CURRENT); // e_ident[EI_VERSION] - Write8(ELF::ELFOSABI_LINUX); // e_ident[EI_OSABI] + // e_ident[EI_OSABI] + switch (TargetObjectWriter->getOSType()) { + case Triple::FreeBSD: Write8(ELF::ELFOSABI_FREEBSD); break; + case Triple::Linux: Write8(ELF::ELFOSABI_LINUX); break; + default: Write8(ELF::ELFOSABI_NONE); break; + } Write8(0); // e_ident[EI_ABIVERSION] WriteZeros(ELF::EI_NIDENT - ELF::EI_PAD); Write16(ELF::ET_REL); // e_type - // FIXME: Make this configurable - Write16(Is64Bit ? ELF::EM_X86_64 : ELF::EM_386); // e_machine = target + Write16(TargetObjectWriter->getEMachine()); // e_machine = target Write32(ELF::EV_CURRENT); // e_version WriteWord(0); // e_entry, no entry point in .o file WriteWord(0); // e_phoff, no program header for .o - WriteWord(SectionDataSize + (Is64Bit ? sizeof(ELF::Elf64_Ehdr) : + WriteWord(SectionDataSize + (is64Bit() ? sizeof(ELF::Elf64_Ehdr) : sizeof(ELF::Elf32_Ehdr))); // e_shoff = sec hdr table off in bytes - // FIXME: Make this configurable. - Write32(0); // e_flags = whatever the target wants + // e_flags = whatever the target wants + WriteEFlags(); // e_ehsize = ELF header size - Write16(Is64Bit ? sizeof(ELF::Elf64_Ehdr) : sizeof(ELF::Elf32_Ehdr)); + Write16(is64Bit() ? sizeof(ELF::Elf64_Ehdr) : sizeof(ELF::Elf32_Ehdr)); Write16(0); // e_phentsize = prog header entry size Write16(0); // e_phnum = # prog header entries = 0 // e_shentsize = Section header entry size - Write16(Is64Bit ? sizeof(ELF::Elf64_Shdr) : sizeof(ELF::Elf32_Shdr)); + Write16(is64Bit() ? sizeof(ELF::Elf64_Shdr) : sizeof(ELF::Elf32_Shdr)); // e_shnum = # of section header ents - Write16(NumberOfSections); + if (NumberOfSections >= ELF::SHN_LORESERVE) + Write16(0); + else + Write16(NumberOfSections); // e_shstrndx = Section # of '.shstrtab' - Write16(ShstrtabIndex); + if (NumberOfSections >= ELF::SHN_LORESERVE) + Write16(ELF::SHN_XINDEX); + else + Write16(ShstrtabIndex); } -void ELFObjectWriterImpl::WriteSymbolEntry(MCDataFragment *F, uint64_t name, - uint8_t info, uint64_t value, - uint64_t size, uint8_t other, - uint16_t shndx) { - if (Is64Bit) { - char buf[8]; +void ELFObjectWriter::WriteSymbolEntry(MCDataFragment *SymtabF, + MCDataFragment *ShndxF, + uint64_t name, + uint8_t info, uint64_t value, + uint64_t size, uint8_t other, + uint32_t shndx, + bool Reserved) { + if (ShndxF) { + if (shndx >= ELF::SHN_LORESERVE && !Reserved) + String32(*ShndxF, shndx); + else + String32(*ShndxF, 0); + } - String32(buf, name); - F->getContents() += StringRef(buf, 4); // st_name + uint16_t Index = (shndx >= ELF::SHN_LORESERVE && !Reserved) ? + uint16_t(ELF::SHN_XINDEX) : shndx; - String8(buf, info); - F->getContents() += StringRef(buf, 1); // st_info + if (is64Bit()) { + String32(*SymtabF, name); // st_name + String8(*SymtabF, info); // st_info + String8(*SymtabF, other); // st_other + String16(*SymtabF, Index); // st_shndx + String64(*SymtabF, value); // st_value + String64(*SymtabF, size); // st_size + } else { + String32(*SymtabF, name); // st_name + String32(*SymtabF, value); // st_value + String32(*SymtabF, size); // st_size + String8(*SymtabF, info); // st_info + String8(*SymtabF, other); // st_other + String16(*SymtabF, Index); // st_shndx + } +} - String8(buf, other); - F->getContents() += StringRef(buf, 1); // st_other +static uint64_t SymbolValue(MCSymbolData &Data, const MCAsmLayout &Layout) { + if (Data.isCommon() && Data.isExternal()) + return Data.getCommonAlignment(); - String16(buf, shndx); - F->getContents() += StringRef(buf, 2); // st_shndx + const MCSymbol &Symbol = Data.getSymbol(); - String64(buf, value); - F->getContents() += StringRef(buf, 8); // st_value + if (Symbol.isAbsolute() && Symbol.isVariable()) { + if (const MCExpr *Value = Symbol.getVariableValue()) { + int64_t IntValue; + if (Value->EvaluateAsAbsolute(IntValue, Layout)) + return (uint64_t)IntValue; + } + } - String64(buf, size); - F->getContents() += StringRef(buf, 8); // st_size - } else { - char buf[4]; + if (!Symbol.isInSection()) + return 0; + + if (Data.getFragment()) + return Layout.getSymbolOffset(&Data); + + return 0; +} - String32(buf, name); - F->getContents() += StringRef(buf, 4); // st_name +void ELFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout) { + // The presence of symbol versions causes undefined symbols and + // versions declared with @@@ to be renamed. - String32(buf, value); - F->getContents() += StringRef(buf, 4); // st_value + for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), + ie = Asm.symbol_end(); it != ie; ++it) { + const MCSymbol &Alias = it->getSymbol(); + const MCSymbol &Symbol = Alias.AliasedSymbol(); + MCSymbolData &SD = Asm.getSymbolData(Symbol); + + // Not an alias. + if (&Symbol == &Alias) + continue; + + StringRef AliasName = Alias.getName(); + size_t Pos = AliasName.find('@'); + if (Pos == StringRef::npos) + continue; - String32(buf, size); - F->getContents() += StringRef(buf, 4); // st_size + // Aliases defined with .symvar copy the binding from the symbol they alias. + // This is the first place we are able to copy this information. + it->setExternal(SD.isExternal()); + SetBinding(*it, GetBinding(SD)); - String8(buf, info); - F->getContents() += StringRef(buf, 1); // st_info + StringRef Rest = AliasName.substr(Pos); + if (!Symbol.isUndefined() && !Rest.startswith("@@@")) + continue; - String8(buf, other); - F->getContents() += StringRef(buf, 1); // st_other + // FIXME: produce a better error message. + if (Symbol.isUndefined() && Rest.startswith("@@") && + !Rest.startswith("@@@")) + report_fatal_error("A @@ version cannot be undefined"); - String16(buf, shndx); - F->getContents() += StringRef(buf, 2); // st_shndx + Renames.insert(std::make_pair(&Symbol, &Alias)); } } -void ELFObjectWriterImpl::WriteSymbol(MCDataFragment *F, ELFSymbolData &MSD, - const MCAsmLayout &Layout) { - MCSymbolData &Data = *MSD.SymbolData; - uint8_t Info = (Data.getFlags() & 0xff); - uint8_t Other = ((Data.getFlags() & 0xf00) >> ELF_STV_Shift); - uint64_t Value = 0; +void ELFObjectWriter::WriteSymbol(MCDataFragment *SymtabF, + MCDataFragment *ShndxF, + ELFSymbolData &MSD, + const MCAsmLayout &Layout) { + MCSymbolData &OrigData = *MSD.SymbolData; + MCSymbolData &Data = + Layout.getAssembler().getSymbolData(OrigData.getSymbol().AliasedSymbol()); + + bool IsReserved = Data.isCommon() || Data.getSymbol().isAbsolute() || + Data.getSymbol().isVariable(); + + uint8_t Binding = GetBinding(OrigData); + uint8_t Visibility = GetVisibility(OrigData); + uint8_t Type = GetType(Data); + + uint8_t Info = (Binding << ELF_STB_Shift) | (Type << ELF_STT_Shift); + uint8_t Other = Visibility; + + uint64_t Value = SymbolValue(Data, Layout); uint64_t Size = 0; - const MCExpr *ESize; - if (Data.isCommon() && Data.isExternal()) - Value = Data.getCommonAlignment(); - - if (!Data.isCommon()) - if (MCFragment *FF = Data.getFragment()) - Value = Layout.getSymbolAddress(&Data) - - Layout.getSectionAddress(FF->getParent()); - - ESize = Data.getSize(); - if (Data.getSize()) { - MCValue Res; - if (ESize->getKind() == MCExpr::Binary) { - const MCBinaryExpr *BE = static_cast(ESize); - - if (BE->EvaluateAsRelocatable(Res, &Layout)) { - MCSymbolData &A = - Layout.getAssembler().getSymbolData(Res.getSymA()->getSymbol()); - MCSymbolData &B = - Layout.getAssembler().getSymbolData(Res.getSymB()->getSymbol()); - - Size = Layout.getSymbolAddress(&A) - Layout.getSymbolAddress(&B); - } - } else if (ESize->getKind() == MCExpr::Constant) { - Size = static_cast(ESize)->getValue(); - } else { - assert(0 && "Unsupported size expression"); - } + assert(!(Data.isCommon() && !Data.isExternal())); + + const MCExpr *ESize = Data.getSize(); + if (ESize) { + int64_t Res; + if (!ESize->EvaluateAsAbsolute(Res, Layout)) + report_fatal_error("Size expression must be absolute."); + Size = Res; } // Write out the symbol table entry - WriteSymbolEntry(F, MSD.StringIndex, Info, Value, - Size, Other, MSD.SectionIndex); + WriteSymbolEntry(SymtabF, ShndxF, MSD.StringIndex, Info, Value, + Size, Other, MSD.SectionIndex, IsReserved); } -void ELFObjectWriterImpl::WriteSymbolTable(MCDataFragment *F, - const MCAssembler &Asm, - const MCAsmLayout &Layout) { +void ELFObjectWriter::WriteSymbolTable(MCDataFragment *SymtabF, + MCDataFragment *ShndxF, + const MCAssembler &Asm, + const MCAsmLayout &Layout, + const SectionIndexMapTy &SectionIndexMap) { // The string table must be emitted first because we need the index // into the string table for all the symbol names. assert(StringTable.size() && "Missing string table"); @@ -408,258 +642,343 @@ void ELFObjectWriterImpl::WriteSymbolTable(MCDataFragment *F, // FIXME: Make sure the start of the symbol table is aligned. // The first entry is the undefined symbol entry. - unsigned EntrySize = Is64Bit ? ELF::SYMENTRY_SIZE64 : ELF::SYMENTRY_SIZE32; - F->getContents().append(EntrySize, '\x00'); + WriteSymbolEntry(SymtabF, ShndxF, 0, 0, 0, 0, 0, 0, false); // Write the symbol table entries. LastLocalSymbolIndex = LocalSymbolData.size() + 1; for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) { ELFSymbolData &MSD = LocalSymbolData[i]; - WriteSymbol(F, MSD, Layout); + WriteSymbol(SymtabF, ShndxF, MSD, Layout); } - // Write out a symbol table entry for each section. - // leaving out the just added .symtab which is at - // the very end - unsigned Index = 1; - for (MCAssembler::const_iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it, ++Index) { + // Write out a symbol table entry for each regular section. + for (MCAssembler::const_iterator i = Asm.begin(), e = Asm.end(); i != e; + ++i) { const MCSectionELF &Section = - static_cast(it->getSection()); - // Leave out relocations so we don't have indexes within - // the relocations messed up - if (Section.getType() == ELF::SHT_RELA || Section.getType() == ELF::SHT_REL) - continue; - if (Index == Asm.size()) + static_cast(i->getSection()); + if (Section.getType() == ELF::SHT_RELA || + Section.getType() == ELF::SHT_REL || + Section.getType() == ELF::SHT_STRTAB || + Section.getType() == ELF::SHT_SYMTAB) continue; - WriteSymbolEntry(F, 0, ELF::STT_SECTION, 0, 0, ELF::STV_DEFAULT, Index); + WriteSymbolEntry(SymtabF, ShndxF, 0, ELF::STT_SECTION, 0, 0, + ELF::STV_DEFAULT, SectionIndexMap.lookup(&Section), false); LastLocalSymbolIndex++; } for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) { ELFSymbolData &MSD = ExternalSymbolData[i]; MCSymbolData &Data = *MSD.SymbolData; - assert((Data.getFlags() & ELF_STB_Global) && - "External symbol requires STB_GLOBAL flag"); - WriteSymbol(F, MSD, Layout); - if (Data.getFlags() & ELF_STB_Local) + assert(((Data.getFlags() & ELF_STB_Global) || + (Data.getFlags() & ELF_STB_Weak)) && + "External symbol requires STB_GLOBAL or STB_WEAK flag"); + WriteSymbol(SymtabF, ShndxF, MSD, Layout); + if (GetBinding(Data) == ELF::STB_LOCAL) LastLocalSymbolIndex++; } for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) { ELFSymbolData &MSD = UndefinedSymbolData[i]; MCSymbolData &Data = *MSD.SymbolData; - Data.setFlags(Data.getFlags() | ELF_STB_Global); - WriteSymbol(F, MSD, Layout); - if (Data.getFlags() & ELF_STB_Local) + WriteSymbol(SymtabF, ShndxF, MSD, Layout); + if (GetBinding(Data) == ELF::STB_LOCAL) LastLocalSymbolIndex++; } } -// FIXME: this is currently X86/X86_64 only -void ELFObjectWriterImpl::RecordRelocation(const MCAssembler &Asm, - const MCAsmLayout &Layout, - const MCFragment *Fragment, - const MCFixup &Fixup, - MCValue Target, - uint64_t &FixedValue) { +const MCSymbol *ELFObjectWriter::SymbolToReloc(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F) const { + const MCSymbol &Symbol = Target.getSymA()->getSymbol(); + const MCSymbol &ASymbol = Symbol.AliasedSymbol(); + const MCSymbol *Renamed = Renames.lookup(&Symbol); + const MCSymbolData &SD = Asm.getSymbolData(Symbol); + + if (ASymbol.isUndefined()) { + if (Renamed) + return Renamed; + return &ASymbol; + } + + if (SD.isExternal()) { + if (Renamed) + return Renamed; + return &Symbol; + } + + const MCSectionELF &Section = + static_cast(ASymbol.getSection()); + const SectionKind secKind = Section.getKind(); + + if (secKind.isBSS()) + return ExplicitRelSym(Asm, Target, F, true); + + if (secKind.isThreadLocal()) { + if (Renamed) + return Renamed; + return &Symbol; + } + + MCSymbolRefExpr::VariantKind Kind = Target.getSymA()->getKind(); + const MCSectionELF &Sec2 = + static_cast(F.getParent()->getSection()); + + if (&Sec2 != &Section && + (Kind == MCSymbolRefExpr::VK_PLT || + Kind == MCSymbolRefExpr::VK_GOTPCREL || + Kind == MCSymbolRefExpr::VK_GOTOFF)) { + if (Renamed) + return Renamed; + return &Symbol; + } + + if (Section.getFlags() & ELF::SHF_MERGE) { + if (Target.getConstant() == 0) + return NULL; + if (Renamed) + return Renamed; + return &Symbol; + } + + return ExplicitRelSym(Asm, Target, F, false); +} + + +void ELFObjectWriter::RecordRelocation(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, + MCValue Target, + uint64_t &FixedValue) { int64_t Addend = 0; - unsigned Index = 0; + int Index = 0; int64_t Value = Target.getConstant(); + const MCSymbol *RelocSymbol = NULL; + bool IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); if (!Target.isAbsolute()) { - const MCSymbol *Symbol = &Target.getSymA()->getSymbol(); - MCSymbolData &SD = Asm.getSymbolData(*Symbol); - const MCSymbolData *Base = Asm.getAtom(Layout, &SD); - MCFragment *F = SD.getFragment(); - - if (Base) { - if (F && (!Symbol->isInSection() || SD.isCommon()) && !SD.isExternal()) { - Index = F->getParent()->getOrdinal() + LocalSymbolData.size() + 1; - Value += Layout.getSymbolAddress(&SD); - } else - Index = getSymbolIndexInSymbolTable(Asm, Symbol); - if (Base != &SD) - Value += Layout.getSymbolAddress(&SD) - Layout.getSymbolAddress(Base); - Addend = Value; - // Compensate for the addend on i386. - if (Is64Bit) - Value = 0; - } else { - if (F) { - // Index of the section in .symtab against this symbol - // is being relocated + 2 (empty section + abs. symbols). - Index = F->getParent()->getOrdinal() + LocalSymbolData.size() + 1; - - MCSectionData *FSD = F->getParent(); - // Offset of the symbol in the section - Addend = Layout.getSymbolAddress(&SD) - Layout.getSectionAddress(FSD); - } else { - FixedValue = Value; - return; - } - } - } + const MCSymbol &Symbol = Target.getSymA()->getSymbol(); + const MCSymbol &ASymbol = Symbol.AliasedSymbol(); + RelocSymbol = SymbolToReloc(Asm, Target, *Fragment); - FixedValue = Value; + if (const MCSymbolRefExpr *RefB = Target.getSymB()) { + const MCSymbol &SymbolB = RefB->getSymbol(); + MCSymbolData &SDB = Asm.getSymbolData(SymbolB); + IsPCRel = true; - // determine the type of the relocation - bool IsPCRel = isFixupKindX86PCRel(Fixup.getKind()); - unsigned Type; - if (Is64Bit) { - if (IsPCRel) { - Type = ELF::R_X86_64_PC32; - } else { - switch ((unsigned)Fixup.getKind()) { - default: llvm_unreachable("invalid fixup kind!"); - case FK_Data_8: Type = ELF::R_X86_64_64; break; - case X86::reloc_pcrel_4byte: - case FK_Data_4: - // check that the offset fits within a signed long - if (isInt<32>(Target.getConstant())) - Type = ELF::R_X86_64_32S; - else - Type = ELF::R_X86_64_32; - break; - case FK_Data_2: Type = ELF::R_X86_64_16; break; - case X86::reloc_pcrel_1byte: - case FK_Data_1: Type = ELF::R_X86_64_8; break; - } + // Offset of the symbol in the section + int64_t a = Layout.getSymbolOffset(&SDB); + + // Ofeset of the relocation in the section + int64_t b = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); + Value += b - a; } - } else { - if (IsPCRel) { - Type = ELF::R_386_PC32; + + if (!RelocSymbol) { + MCSymbolData &SD = Asm.getSymbolData(ASymbol); + MCFragment *F = SD.getFragment(); + + Index = F->getParent()->getOrdinal() + 1; + + // Offset of the symbol in the section + Value += Layout.getSymbolOffset(&SD); } else { - switch ((unsigned)Fixup.getKind()) { - default: llvm_unreachable("invalid fixup kind!"); - case X86::reloc_pcrel_4byte: - case FK_Data_4: Type = ELF::R_386_32; break; - case FK_Data_2: Type = ELF::R_386_16; break; - case X86::reloc_pcrel_1byte: - case FK_Data_1: Type = ELF::R_386_8; break; - } + if (Asm.getSymbolData(Symbol).getFlags() & ELF_Other_Weakref) + WeakrefUsedInReloc.insert(RelocSymbol); + else + UsedInReloc.insert(RelocSymbol); + Index = -1; } + Addend = Value; + // Compensate for the addend on i386. + if (is64Bit()) + Value = 0; } - ELFRelocationEntry ERE; + FixedValue = Value; + unsigned Type = GetRelocType(Target, Fixup, IsPCRel, + (RelocSymbol != 0), Addend); + + uint64_t RelocOffset = Layout.getFragmentOffset(Fragment) + + Fixup.getOffset(); + + if (!hasRelocationAddend()) + Addend = 0; + ELFRelocationEntry ERE(RelocOffset, Index, Type, RelocSymbol, Addend); + Relocations[Fragment->getParent()].push_back(ERE); +} - if (Is64Bit) { - struct ELF::Elf64_Rela ERE64; - ERE64.setSymbolAndType(Index, Type); - ERE.r_info = ERE64.r_info; - } else { - struct ELF::Elf32_Rela ERE32; - ERE32.setSymbolAndType(Index, Type); - ERE.r_info = ERE32.r_info; - } - ERE.r_offset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); +uint64_t +ELFObjectWriter::getSymbolIndexInSymbolTable(const MCAssembler &Asm, + const MCSymbol *S) { + MCSymbolData &SD = Asm.getSymbolData(*S); + return SD.getIndex(); +} - if (HasRelocationAddend) - ERE.r_addend = Addend; - else - ERE.r_addend = 0; // Silence compiler warning. +static bool isInSymtab(const MCAssembler &Asm, const MCSymbolData &Data, + bool Used, bool Renamed) { + if (Data.getFlags() & ELF_Other_Weakref) + return false; - Relocations[Fragment->getParent()].push_back(ERE); + if (Used) + return true; + + if (Renamed) + return false; + + const MCSymbol &Symbol = Data.getSymbol(); + + if (Symbol.getName() == "_GLOBAL_OFFSET_TABLE_") + return true; + + const MCSymbol &A = Symbol.AliasedSymbol(); + if (!A.isVariable() && A.isUndefined() && !Data.isCommon()) + return false; + + if (!Asm.isSymbolLinkerVisible(Symbol) && !Symbol.isUndefined()) + return false; + + if (Symbol.isTemporary()) + return false; + + return true; } -uint64_t -ELFObjectWriterImpl::getSymbolIndexInSymbolTable(const MCAssembler &Asm, - const MCSymbol *S) { - MCSymbolData &SD = Asm.getSymbolData(*S); +static bool isLocal(const MCSymbolData &Data, bool isSignature, + bool isUsedInReloc) { + if (Data.isExternal()) + return false; + + const MCSymbol &Symbol = Data.getSymbol(); + const MCSymbol &RefSymbol = Symbol.AliasedSymbol(); - // Local symbol. - if (!SD.isExternal() && !S->isUndefined()) - return SD.getIndex() + /* empty symbol */ 1; + if (RefSymbol.isUndefined() && !RefSymbol.isVariable()) { + if (isSignature && !isUsedInReloc) + return true; - // External or undefined symbol. - return SD.getIndex() + Asm.size() + /* empty symbol */ 1; + return false; + } + + return true; } -void ELFObjectWriterImpl::ComputeSymbolTable(MCAssembler &Asm) { - // Build section lookup table. - DenseMap SectionIndexMap; +void ELFObjectWriter::ComputeIndexMap(MCAssembler &Asm, + SectionIndexMapTy &SectionIndexMap) { unsigned Index = 1; for (MCAssembler::iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it, ++Index) - SectionIndexMap[&it->getSection()] = Index; + ie = Asm.end(); it != ie; ++it) { + const MCSectionELF &Section = + static_cast(it->getSection()); + if (Section.getType() != ELF::SHT_GROUP) + continue; + SectionIndexMap[&Section] = Index++; + } + + for (MCAssembler::iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + const MCSectionELF &Section = + static_cast(it->getSection()); + if (Section.getType() == ELF::SHT_GROUP) + continue; + SectionIndexMap[&Section] = Index++; + } +} + +void ELFObjectWriter::ComputeSymbolTable(MCAssembler &Asm, + const SectionIndexMapTy &SectionIndexMap, + RevGroupMapTy RevGroupMap) { + // FIXME: Is this the correct place to do this? + if (NeedsGOT) { + llvm::StringRef Name = "_GLOBAL_OFFSET_TABLE_"; + MCSymbol *Sym = Asm.getContext().GetOrCreateSymbol(Name); + MCSymbolData &Data = Asm.getOrCreateSymbolData(*Sym); + Data.setExternal(true); + SetBinding(Data, ELF::STB_GLOBAL); + } + + // Build section lookup table. + int NumRegularSections = Asm.size(); // Index 0 is always the empty string. StringMap StringIndexMap; StringTable += '\x00'; - // Add the data for local symbols. + // Add the data for the symbols. for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), ie = Asm.symbol_end(); it != ie; ++it) { const MCSymbol &Symbol = it->getSymbol(); - // Ignore non-linker visible symbols. - if (!Asm.isSymbolLinkerVisible(Symbol)) - continue; + bool Used = UsedInReloc.count(&Symbol); + bool WeakrefUsed = WeakrefUsedInReloc.count(&Symbol); + bool isSignature = RevGroupMap.count(&Symbol); - if (it->isExternal() || Symbol.isUndefined()) + if (!isInSymtab(Asm, *it, + Used || WeakrefUsed || isSignature, + Renames.count(&Symbol))) continue; - uint64_t &Entry = StringIndexMap[Symbol.getName()]; - if (!Entry) { - Entry = StringTable.size(); - StringTable += Symbol.getName(); - StringTable += '\x00'; - } - ELFSymbolData MSD; MSD.SymbolData = it; - MSD.StringIndex = Entry; + const MCSymbol &RefSymbol = Symbol.AliasedSymbol(); + + // Undefined symbols are global, but this is the first place we + // are able to set it. + bool Local = isLocal(*it, isSignature, Used); + if (!Local && GetBinding(*it) == ELF::STB_LOCAL) { + MCSymbolData &SD = Asm.getSymbolData(RefSymbol); + SetBinding(*it, ELF::STB_GLOBAL); + SetBinding(SD, ELF::STB_GLOBAL); + } + + if (RefSymbol.isUndefined() && !Used && WeakrefUsed) + SetBinding(*it, ELF::STB_WEAK); - if (Symbol.isAbsolute()) { + if (it->isCommon()) { + assert(!Local); + MSD.SectionIndex = ELF::SHN_COMMON; + } else if (Symbol.isAbsolute() || RefSymbol.isVariable()) { MSD.SectionIndex = ELF::SHN_ABS; - LocalSymbolData.push_back(MSD); + } else if (RefSymbol.isUndefined()) { + if (isSignature && !Used) + MSD.SectionIndex = SectionIndexMap.lookup(RevGroupMap[&Symbol]); + else + MSD.SectionIndex = ELF::SHN_UNDEF; } else { - MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); + const MCSectionELF &Section = + static_cast(RefSymbol.getSection()); + MSD.SectionIndex = SectionIndexMap.lookup(&Section); + if (MSD.SectionIndex >= ELF::SHN_LORESERVE) + NeedsSymtabShndx = true; assert(MSD.SectionIndex && "Invalid section index!"); - LocalSymbolData.push_back(MSD); } - } - - // Now add non-local symbols. - for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), - ie = Asm.symbol_end(); it != ie; ++it) { - const MCSymbol &Symbol = it->getSymbol(); - // Ignore non-linker visible symbols. - if (!Asm.isSymbolLinkerVisible(Symbol)) - continue; - - if (!it->isExternal() && !Symbol.isUndefined()) - continue; + // The @@@ in symbol version is replaced with @ in undefined symbols and + // @@ in defined ones. + StringRef Name = Symbol.getName(); + SmallString<32> Buf; + + size_t Pos = Name.find("@@@"); + if (Pos != StringRef::npos) { + Buf += Name.substr(0, Pos); + unsigned Skip = MSD.SectionIndex == ELF::SHN_UNDEF ? 2 : 1; + Buf += Name.substr(Pos + Skip); + Name = Buf; + } - uint64_t &Entry = StringIndexMap[Symbol.getName()]; + uint64_t &Entry = StringIndexMap[Name]; if (!Entry) { Entry = StringTable.size(); - StringTable += Symbol.getName(); + StringTable += Name; StringTable += '\x00'; } - - ELFSymbolData MSD; - MSD.SymbolData = it; MSD.StringIndex = Entry; - - if (Symbol.isUndefined()) { - MSD.SectionIndex = ELF::SHN_UNDEF; - // XXX: for some reason we dont Emit* this - it->setFlags(it->getFlags() | ELF_STB_Global); + if (MSD.SectionIndex == ELF::SHN_UNDEF) UndefinedSymbolData.push_back(MSD); - } else if (Symbol.isAbsolute()) { - MSD.SectionIndex = ELF::SHN_ABS; - ExternalSymbolData.push_back(MSD); - } else if (it->isCommon()) { - MSD.SectionIndex = ELF::SHN_COMMON; - ExternalSymbolData.push_back(MSD); - } else { - MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); - assert(MSD.SectionIndex && "Invalid section index!"); + else if (Local) + LocalSymbolData.push_back(MSD); + else ExternalSymbolData.push_back(MSD); - } } // Symbols are required to be in lexicographic order. @@ -669,55 +988,56 @@ void ELFObjectWriterImpl::ComputeSymbolTable(MCAssembler &Asm) { // Set the symbol indices. Local symbols must come before all other // symbols with non-local bindings. - Index = 0; + unsigned Index = 1; for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) LocalSymbolData[i].SymbolData->setIndex(Index++); + + Index += NumRegularSections; + for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) ExternalSymbolData[i].SymbolData->setIndex(Index++); for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) UndefinedSymbolData[i].SymbolData->setIndex(Index++); } -void ELFObjectWriterImpl::WriteRelocation(MCAssembler &Asm, MCAsmLayout &Layout, - const MCSectionData &SD) { +void ELFObjectWriter::WriteRelocation(MCAssembler &Asm, MCAsmLayout &Layout, + const MCSectionData &SD) { if (!Relocations[&SD].empty()) { MCContext &Ctx = Asm.getContext(); - const MCSection *RelaSection; + const MCSectionELF *RelaSection; const MCSectionELF &Section = static_cast(SD.getSection()); const StringRef SectionName = Section.getSectionName(); - std::string RelaSectionName = HasRelocationAddend ? ".rela" : ".rel"; + std::string RelaSectionName = hasRelocationAddend() ? ".rela" : ".rel"; RelaSectionName += SectionName; unsigned EntrySize; - if (HasRelocationAddend) - EntrySize = Is64Bit ? sizeof(ELF::Elf64_Rela) : sizeof(ELF::Elf32_Rela); + if (hasRelocationAddend()) + EntrySize = is64Bit() ? sizeof(ELF::Elf64_Rela) : sizeof(ELF::Elf32_Rela); else - EntrySize = Is64Bit ? sizeof(ELF::Elf64_Rel) : sizeof(ELF::Elf32_Rel); + EntrySize = is64Bit() ? sizeof(ELF::Elf64_Rel) : sizeof(ELF::Elf32_Rel); - RelaSection = Ctx.getELFSection(RelaSectionName, HasRelocationAddend ? + RelaSection = Ctx.getELFSection(RelaSectionName, hasRelocationAddend() ? ELF::SHT_RELA : ELF::SHT_REL, 0, SectionKind::getReadOnly(), - false, EntrySize); + EntrySize, ""); MCSectionData &RelaSD = Asm.getOrCreateSectionData(*RelaSection); - RelaSD.setAlignment(1); + RelaSD.setAlignment(is64Bit() ? 8 : 4); MCDataFragment *F = new MCDataFragment(&RelaSD); WriteRelocationsFragment(Asm, F, &SD); - - Asm.AddSectionToTheEnd(RelaSD, Layout); } } -void ELFObjectWriterImpl::WriteSecHdrEntry(uint32_t Name, uint32_t Type, - uint64_t Flags, uint64_t Address, - uint64_t Offset, uint64_t Size, - uint32_t Link, uint32_t Info, - uint64_t Alignment, - uint64_t EntrySize) { +void ELFObjectWriter::WriteSecHdrEntry(uint32_t Name, uint32_t Type, + uint64_t Flags, uint64_t Address, + uint64_t Offset, uint64_t Size, + uint32_t Link, uint32_t Info, + uint64_t Alignment, + uint64_t EntrySize) { Write32(Name); // sh_name: index into string table Write32(Type); // sh_type WriteWord(Flags); // sh_flags @@ -730,9 +1050,9 @@ void ELFObjectWriterImpl::WriteSecHdrEntry(uint32_t Name, uint32_t Type, WriteWord(EntrySize); // sh_entsize } -void ELFObjectWriterImpl::WriteRelocationsFragment(const MCAssembler &Asm, - MCDataFragment *F, - const MCSectionData *SD) { +void ELFObjectWriter::WriteRelocationsFragment(const MCAssembler &Asm, + MCDataFragment *F, + const MCSectionData *SD) { std::vector &Relocs = Relocations[SD]; // sort by the r_offset just like gnu as does array_pod_sort(Relocs.begin(), Relocs.end()); @@ -740,67 +1060,90 @@ void ELFObjectWriterImpl::WriteRelocationsFragment(const MCAssembler &Asm, for (unsigned i = 0, e = Relocs.size(); i != e; ++i) { ELFRelocationEntry entry = Relocs[e - i - 1]; - unsigned WordSize = Is64Bit ? 8 : 4; - F->getContents() += StringRef((const char *)&entry.r_offset, WordSize); - F->getContents() += StringRef((const char *)&entry.r_info, WordSize); + if (!entry.Index) + ; + else if (entry.Index < 0) + entry.Index = getSymbolIndexInSymbolTable(Asm, entry.Symbol); + else + entry.Index += LocalSymbolData.size(); + if (is64Bit()) { + String64(*F, entry.r_offset); + + struct ELF::Elf64_Rela ERE64; + ERE64.setSymbolAndType(entry.Index, entry.Type); + String64(*F, ERE64.r_info); - if (HasRelocationAddend) - F->getContents() += StringRef((const char *)&entry.r_addend, WordSize); + if (hasRelocationAddend()) + String64(*F, entry.r_addend); + } else { + String32(*F, entry.r_offset); + + struct ELF::Elf32_Rela ERE32; + ERE32.setSymbolAndType(entry.Index, entry.Type); + String32(*F, ERE32.r_info); + + if (hasRelocationAddend()) + String32(*F, entry.r_addend); + } } } -void ELFObjectWriterImpl::CreateMetadataSections(MCAssembler &Asm, - MCAsmLayout &Layout) { +void ELFObjectWriter::CreateMetadataSections(MCAssembler &Asm, + MCAsmLayout &Layout, + const SectionIndexMapTy &SectionIndexMap) { MCContext &Ctx = Asm.getContext(); MCDataFragment *F; - WriteRelocations(Asm, Layout); - - const MCSection *SymtabSection; - unsigned EntrySize = Is64Bit ? ELF::SYMENTRY_SIZE64 : ELF::SYMENTRY_SIZE32; + unsigned EntrySize = is64Bit() ? ELF::SYMENTRY_SIZE64 : ELF::SYMENTRY_SIZE32; - SymtabSection = Ctx.getELFSection(".symtab", ELF::SHT_SYMTAB, 0, - SectionKind::getReadOnly(), - false, EntrySize); + // We construct .shstrtab, .symtab and .strtab in this order to match gnu as. + const MCSectionELF *ShstrtabSection = + Ctx.getELFSection(".shstrtab", ELF::SHT_STRTAB, 0, + SectionKind::getReadOnly()); + MCSectionData &ShstrtabSD = Asm.getOrCreateSectionData(*ShstrtabSection); + ShstrtabSD.setAlignment(1); + ShstrtabIndex = Asm.size(); + const MCSectionELF *SymtabSection = + Ctx.getELFSection(".symtab", ELF::SHT_SYMTAB, 0, + SectionKind::getReadOnly(), + EntrySize, ""); MCSectionData &SymtabSD = Asm.getOrCreateSectionData(*SymtabSection); + SymtabSD.setAlignment(is64Bit() ? 8 : 4); + SymbolTableIndex = Asm.size(); - SymtabSD.setAlignment(Is64Bit ? 8 : 4); + MCSectionData *SymtabShndxSD = NULL; - F = new MCDataFragment(&SymtabSD); - - // Symbol table - WriteSymbolTable(F, Asm, Layout); - Asm.AddSectionToTheEnd(SymtabSD, Layout); + if (NeedsSymtabShndx) { + const MCSectionELF *SymtabShndxSection = + Ctx.getELFSection(".symtab_shndx", ELF::SHT_SYMTAB_SHNDX, 0, + SectionKind::getReadOnly(), 4, ""); + SymtabShndxSD = &Asm.getOrCreateSectionData(*SymtabShndxSection); + SymtabShndxSD->setAlignment(4); + } const MCSection *StrtabSection; StrtabSection = Ctx.getELFSection(".strtab", ELF::SHT_STRTAB, 0, - SectionKind::getReadOnly(), false); - + SectionKind::getReadOnly()); MCSectionData &StrtabSD = Asm.getOrCreateSectionData(*StrtabSection); StrtabSD.setAlignment(1); - - // FIXME: This isn't right. If the sections get rearranged this will - // be wrong. We need a proper lookup. StringTableIndex = Asm.size(); - F = new MCDataFragment(&StrtabSD); - F->getContents().append(StringTable.begin(), StringTable.end()); - Asm.AddSectionToTheEnd(StrtabSD, Layout); + WriteRelocations(Asm, Layout); - const MCSection *ShstrtabSection; - ShstrtabSection = Ctx.getELFSection(".shstrtab", ELF::SHT_STRTAB, 0, - SectionKind::getReadOnly(), false); + // Symbol table + F = new MCDataFragment(&SymtabSD); + MCDataFragment *ShndxF = NULL; + if (NeedsSymtabShndx) { + ShndxF = new MCDataFragment(SymtabShndxSD); + } + WriteSymbolTable(F, ShndxF, Asm, Layout, SectionIndexMap); - MCSectionData &ShstrtabSD = Asm.getOrCreateSectionData(*ShstrtabSection); - ShstrtabSD.setAlignment(1); + F = new MCDataFragment(&StrtabSD); + F->getContents().append(StringTable.begin(), StringTable.end()); F = new MCDataFragment(&ShstrtabSD); - // FIXME: This isn't right. If the sections get rearranged this will - // be wrong. We need a proper lookup. - ShstrtabIndex = Asm.size(); - // Section header string table. // // The first entry of a string table holds a null character so skip @@ -808,166 +1151,691 @@ void ELFObjectWriterImpl::CreateMetadataSections(MCAssembler &Asm, uint64_t Index = 1; F->getContents() += '\x00'; + StringMap SecStringMap; for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { const MCSectionELF &Section = static_cast(it->getSection()); + // FIXME: We could merge suffixes like in .text and .rela.text. + StringRef Name = Section.getSectionName(); + if (SecStringMap.count(Name)) { + SectionStringTableIndex[&Section] = SecStringMap[Name]; + continue; + } // Remember the index into the string table so we can write it // into the sh_name field of the section header table. - SectionStringTableIndex[&it->getSection()] = Index; + SectionStringTableIndex[&Section] = Index; + SecStringMap[Name] = Index; - Index += Section.getSectionName().size() + 1; - F->getContents() += Section.getSectionName(); + Index += Name.size() + 1; + F->getContents() += Name; F->getContents() += '\x00'; } +} + +void ELFObjectWriter::CreateIndexedSections(MCAssembler &Asm, + MCAsmLayout &Layout, + GroupMapTy &GroupMap, + RevGroupMapTy &RevGroupMap) { + // Create the .note.GNU-stack section if needed. + MCContext &Ctx = Asm.getContext(); + if (Asm.getNoExecStack()) { + const MCSectionELF *GnuStackSection = + Ctx.getELFSection(".note.GNU-stack", ELF::SHT_PROGBITS, 0, + SectionKind::getReadOnly()); + Asm.getOrCreateSectionData(*GnuStackSection); + } + + // Build the groups + for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); + it != ie; ++it) { + const MCSectionELF &Section = + static_cast(it->getSection()); + if (!(Section.getFlags() & ELF::SHF_GROUP)) + continue; + + const MCSymbol *SignatureSymbol = Section.getGroup(); + Asm.getOrCreateSymbolData(*SignatureSymbol); + const MCSectionELF *&Group = RevGroupMap[SignatureSymbol]; + if (!Group) { + Group = Ctx.CreateELFGroupSection(); + MCSectionData &Data = Asm.getOrCreateSectionData(*Group); + Data.setAlignment(4); + MCDataFragment *F = new MCDataFragment(&Data); + String32(*F, ELF::GRP_COMDAT); + } + GroupMap[Group] = SignatureSymbol; + } + + // Add sections to the groups + unsigned Index = 1; + unsigned NumGroups = RevGroupMap.size(); + for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); + it != ie; ++it, ++Index) { + const MCSectionELF &Section = + static_cast(it->getSection()); + if (!(Section.getFlags() & ELF::SHF_GROUP)) + continue; + const MCSectionELF *Group = RevGroupMap[Section.getGroup()]; + MCSectionData &Data = Asm.getOrCreateSectionData(*Group); + // FIXME: we could use the previous fragment + MCDataFragment *F = new MCDataFragment(&Data); + String32(*F, NumGroups + Index); + } +} + +void ELFObjectWriter::WriteSection(MCAssembler &Asm, + const SectionIndexMapTy &SectionIndexMap, + uint32_t GroupSymbolIndex, + uint64_t Offset, uint64_t Size, + uint64_t Alignment, + const MCSectionELF &Section) { + uint64_t sh_link = 0; + uint64_t sh_info = 0; + + switch(Section.getType()) { + case ELF::SHT_DYNAMIC: + sh_link = SectionStringTableIndex[&Section]; + sh_info = 0; + break; + + case ELF::SHT_REL: + case ELF::SHT_RELA: { + const MCSectionELF *SymtabSection; + const MCSectionELF *InfoSection; + SymtabSection = Asm.getContext().getELFSection(".symtab", ELF::SHT_SYMTAB, + 0, + SectionKind::getReadOnly()); + sh_link = SectionIndexMap.lookup(SymtabSection); + assert(sh_link && ".symtab not found"); + + // Remove ".rel" and ".rela" prefixes. + unsigned SecNameLen = (Section.getType() == ELF::SHT_REL) ? 4 : 5; + StringRef SectionName = Section.getSectionName().substr(SecNameLen); + + InfoSection = Asm.getContext().getELFSection(SectionName, + ELF::SHT_PROGBITS, 0, + SectionKind::getReadOnly()); + sh_info = SectionIndexMap.lookup(InfoSection); + break; + } + + case ELF::SHT_SYMTAB: + case ELF::SHT_DYNSYM: + sh_link = StringTableIndex; + sh_info = LastLocalSymbolIndex; + break; + + case ELF::SHT_SYMTAB_SHNDX: + sh_link = SymbolTableIndex; + break; + + case ELF::SHT_PROGBITS: + case ELF::SHT_STRTAB: + case ELF::SHT_NOBITS: + case ELF::SHT_NOTE: + case ELF::SHT_NULL: + case ELF::SHT_ARM_ATTRIBUTES: + case ELF::SHT_INIT_ARRAY: + case ELF::SHT_FINI_ARRAY: + case ELF::SHT_PREINIT_ARRAY: + case ELF::SHT_X86_64_UNWIND: + // Nothing to do. + break; + + case ELF::SHT_GROUP: { + sh_link = SymbolTableIndex; + sh_info = GroupSymbolIndex; + break; + } + + default: + assert(0 && "FIXME: sh_type value not supported!"); + break; + } - Asm.AddSectionToTheEnd(ShstrtabSD, Layout); + WriteSecHdrEntry(SectionStringTableIndex[&Section], Section.getType(), + Section.getFlags(), 0, Offset, Size, sh_link, sh_info, + Alignment, Section.getEntrySize()); } -void ELFObjectWriterImpl::WriteObject(const MCAssembler &Asm, - const MCAsmLayout &Layout) { +static bool IsELFMetaDataSection(const MCSectionData &SD) { + return SD.getOrdinal() == ~UINT32_C(0) && + !SD.getSection().isVirtualSection(); +} + +static uint64_t DataSectionSize(const MCSectionData &SD) { + uint64_t Ret = 0; + for (MCSectionData::const_iterator i = SD.begin(), e = SD.end(); i != e; + ++i) { + const MCFragment &F = *i; + assert(F.getKind() == MCFragment::FT_Data); + Ret += cast(F).getContents().size(); + } + return Ret; +} + +static uint64_t GetSectionFileSize(const MCAsmLayout &Layout, + const MCSectionData &SD) { + if (IsELFMetaDataSection(SD)) + return DataSectionSize(SD); + return Layout.getSectionFileSize(&SD); +} + +static uint64_t GetSectionAddressSize(const MCAsmLayout &Layout, + const MCSectionData &SD) { + if (IsELFMetaDataSection(SD)) + return DataSectionSize(SD); + return Layout.getSectionAddressSize(&SD); +} + +static void WriteDataSectionData(ELFObjectWriter *W, const MCSectionData &SD) { + for (MCSectionData::const_iterator i = SD.begin(), e = SD.end(); i != e; + ++i) { + const MCFragment &F = *i; + assert(F.getKind() == MCFragment::FT_Data); + W->WriteBytes(cast(F).getContents().str()); + } +} + +void ELFObjectWriter::WriteObject(MCAssembler &Asm, + const MCAsmLayout &Layout) { + GroupMapTy GroupMap; + RevGroupMapTy RevGroupMap; + CreateIndexedSections(Asm, const_cast(Layout), GroupMap, + RevGroupMap); + + SectionIndexMapTy SectionIndexMap; + + ComputeIndexMap(Asm, SectionIndexMap); + + // Compute symbol table information. + ComputeSymbolTable(Asm, SectionIndexMap, RevGroupMap); + CreateMetadataSections(const_cast(Asm), - const_cast(Layout)); + const_cast(Layout), + SectionIndexMap); + + // Update to include the metadata sections. + ComputeIndexMap(Asm, SectionIndexMap); // Add 1 for the null section. unsigned NumSections = Asm.size() + 1; + uint64_t NaturalAlignment = is64Bit() ? 8 : 4; + uint64_t HeaderSize = is64Bit() ? sizeof(ELF::Elf64_Ehdr) : + sizeof(ELF::Elf32_Ehdr); + uint64_t FileOff = HeaderSize; + + std::vector Sections; + Sections.resize(NumSections); + + for (SectionIndexMapTy::const_iterator i= + SectionIndexMap.begin(), e = SectionIndexMap.end(); i != e; ++i) { + const std::pair &p = *i; + Sections[p.second] = p.first; + } - uint64_t SectionDataSize = 0; + for (unsigned i = 1; i < NumSections; ++i) { + const MCSectionELF &Section = *Sections[i]; + const MCSectionData &SD = Asm.getOrCreateSectionData(Section); - for (MCAssembler::const_iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it) { - const MCSectionData &SD = *it; + FileOff = RoundUpToAlignment(FileOff, SD.getAlignment()); // Get the size of the section in the output file (including padding). - uint64_t Size = Layout.getSectionFileSize(&SD); - SectionDataSize += Size; + FileOff += GetSectionFileSize(Layout, SD); } + FileOff = RoundUpToAlignment(FileOff, NaturalAlignment); + // Write out the ELF header ... - WriteHeader(SectionDataSize, NumSections); - FileOff = Is64Bit ? sizeof(ELF::Elf64_Ehdr) : sizeof(ELF::Elf32_Ehdr); + WriteHeader(FileOff - HeaderSize, NumSections); + + FileOff = HeaderSize; // ... then all of the sections ... DenseMap SectionOffsetMap; - DenseMap SectionIndexMap; + for (unsigned i = 1; i < NumSections; ++i) { + const MCSectionELF &Section = *Sections[i]; + const MCSectionData &SD = Asm.getOrCreateSectionData(Section); - unsigned Index = 1; - for (MCAssembler::const_iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it) { - // Remember the offset into the file for this section. - SectionOffsetMap[&it->getSection()] = FileOff; + uint64_t Padding = OffsetToAlignment(FileOff, SD.getAlignment()); + WriteZeros(Padding); + FileOff += Padding; - SectionIndexMap[&it->getSection()] = Index++; + // Remember the offset into the file for this section. + SectionOffsetMap[&Section] = FileOff; - const MCSectionData &SD = *it; - FileOff += Layout.getSectionFileSize(&SD); + FileOff += GetSectionFileSize(Layout, SD); - Asm.WriteSectionData(it, Layout, Writer); + if (IsELFMetaDataSection(SD)) + WriteDataSectionData(this, SD); + else + Asm.WriteSectionData(&SD, Layout); } + uint64_t Padding = OffsetToAlignment(FileOff, NaturalAlignment); + WriteZeros(Padding); + FileOff += Padding; + // ... and then the section header table. // Should we align the section header table? // // Null section first. - WriteSecHdrEntry(0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + uint64_t FirstSectionSize = + NumSections >= ELF::SHN_LORESERVE ? NumSections : 0; + uint32_t FirstSectionLink = + ShstrtabIndex >= ELF::SHN_LORESERVE ? ShstrtabIndex : 0; + WriteSecHdrEntry(0, 0, 0, 0, 0, FirstSectionSize, FirstSectionLink, 0, 0, 0); + + for (unsigned i = 1; i < NumSections; ++i) { + const MCSectionELF &Section = *Sections[i]; + const MCSectionData &SD = Asm.getOrCreateSectionData(Section); + uint32_t GroupSymbolIndex; + if (Section.getType() != ELF::SHT_GROUP) + GroupSymbolIndex = 0; + else + GroupSymbolIndex = getSymbolIndexInSymbolTable(Asm, GroupMap[&Section]); - for (MCAssembler::const_iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it) { - const MCSectionData &SD = *it; - const MCSectionELF &Section = - static_cast(SD.getSection()); + uint64_t Size = GetSectionAddressSize(Layout, SD); - uint64_t sh_link = 0; - uint64_t sh_info = 0; + WriteSection(Asm, SectionIndexMap, GroupSymbolIndex, + SectionOffsetMap[&Section], Size, + SD.getAlignment(), Section); + } +} - switch(Section.getType()) { - case ELF::SHT_DYNAMIC: - sh_link = SectionStringTableIndex[&it->getSection()]; - sh_info = 0; - break; +MCObjectWriter *llvm::createELFObjectWriter(MCELFObjectTargetWriter *MOTW, + raw_ostream &OS, + bool IsLittleEndian) { + switch (MOTW->getEMachine()) { + case ELF::EM_386: + case ELF::EM_X86_64: + return new X86ELFObjectWriter(MOTW, OS, IsLittleEndian); break; + case ELF::EM_ARM: + return new ARMELFObjectWriter(MOTW, OS, IsLittleEndian); break; + case ELF::EM_MBLAZE: + return new MBlazeELFObjectWriter(MOTW, OS, IsLittleEndian); break; + default: llvm_unreachable("Unsupported architecture"); break; + } +} + + +/// START OF SUBCLASSES for ELFObjectWriter +//===- ARMELFObjectWriter -------------------------------------------===// + +ARMELFObjectWriter::ARMELFObjectWriter(MCELFObjectTargetWriter *MOTW, + raw_ostream &_OS, + bool IsLittleEndian) + : ELFObjectWriter(MOTW, _OS, IsLittleEndian) +{} + +ARMELFObjectWriter::~ARMELFObjectWriter() +{} - case ELF::SHT_REL: - case ELF::SHT_RELA: { - const MCSection *SymtabSection; - const MCSection *InfoSection; - - SymtabSection = Asm.getContext().getELFSection(".symtab", ELF::SHT_SYMTAB, 0, - SectionKind::getReadOnly(), - false); - sh_link = SectionIndexMap[SymtabSection]; - - // Remove ".rel" and ".rela" prefixes. - unsigned SecNameLen = (Section.getType() == ELF::SHT_REL) ? 4 : 5; - StringRef SectionName = Section.getSectionName().substr(SecNameLen); - - InfoSection = Asm.getContext().getELFSection(SectionName, - ELF::SHT_PROGBITS, 0, - SectionKind::getReadOnly(), - false); - sh_info = SectionIndexMap[InfoSection]; +// FIXME: get the real EABI Version from the Triple. +void ARMELFObjectWriter::WriteEFlags() { + Write32(ELF::EF_ARM_EABIMASK & DefaultEABIVersion); +} + +// In ARM, _MergedGlobals and other most symbols get emitted directly. +// I.e. not as an offset to a section symbol. +// This code is a first-cut approximation of what ARM/gcc does. + +const MCSymbol *ARMELFObjectWriter::ExplicitRelSym(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F, + bool IsBSS) const { + const MCSymbol &Symbol = Target.getSymA()->getSymbol(); + bool EmitThisSym = false; + + if (IsBSS) { + EmitThisSym = StringSwitch(Symbol.getName()) + .Case("_MergedGlobals", true) + .Default(false); + } else { + EmitThisSym = StringSwitch(Symbol.getName()) + .Case("_MergedGlobals", true) + .StartsWith(".L.str", true) + .Default(false); + } + if (EmitThisSym) + return &Symbol; + if (! Symbol.isTemporary()) + return &Symbol; + return NULL; +} + +unsigned ARMELFObjectWriter::GetRelocType(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel, + bool IsRelocWithSymbol, + int64_t Addend) { + MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ? + MCSymbolRefExpr::VK_None : Target.getSymA()->getKind(); + + unsigned Type = 0; + if (IsPCRel) { + switch ((unsigned)Fixup.getKind()) { + default: assert(0 && "Unimplemented"); + case FK_Data_4: + switch (Modifier) { + default: llvm_unreachable("Unsupported Modifier"); + case MCSymbolRefExpr::VK_None: + Type = ELF::R_ARM_BASE_PREL; + break; + case MCSymbolRefExpr::VK_ARM_TLSGD: + assert(0 && "unimplemented"); + break; + case MCSymbolRefExpr::VK_ARM_GOTTPOFF: + Type = ELF::R_ARM_TLS_IE32; + break; + } + break; + case ARM::fixup_arm_uncondbranch: + switch (Modifier) { + case MCSymbolRefExpr::VK_ARM_PLT: + Type = ELF::R_ARM_PLT32; + break; + default: + Type = ELF::R_ARM_CALL; + break; + } + break; + case ARM::fixup_arm_condbranch: + Type = ELF::R_ARM_JUMP24; + break; + case ARM::fixup_arm_movt_hi16: + case ARM::fixup_arm_movt_hi16_pcrel: + Type = ELF::R_ARM_MOVT_PREL; + break; + case ARM::fixup_arm_movw_lo16: + case ARM::fixup_arm_movw_lo16_pcrel: + Type = ELF::R_ARM_MOVW_PREL_NC; + break; + case ARM::fixup_t2_movt_hi16: + case ARM::fixup_t2_movt_hi16_pcrel: + Type = ELF::R_ARM_THM_MOVT_PREL; + break; + case ARM::fixup_t2_movw_lo16: + case ARM::fixup_t2_movw_lo16_pcrel: + Type = ELF::R_ARM_THM_MOVW_PREL_NC; break; } - - case ELF::SHT_SYMTAB: - case ELF::SHT_DYNSYM: - sh_link = StringTableIndex; - sh_info = LastLocalSymbolIndex; + } else { + switch ((unsigned)Fixup.getKind()) { + default: llvm_unreachable("invalid fixup kind!"); + case FK_Data_4: + switch (Modifier) { + default: llvm_unreachable("Unsupported Modifier"); break; + case MCSymbolRefExpr::VK_ARM_GOT: + Type = ELF::R_ARM_GOT_BREL; + break; + case MCSymbolRefExpr::VK_ARM_TLSGD: + Type = ELF::R_ARM_TLS_GD32; + break; + case MCSymbolRefExpr::VK_ARM_TPOFF: + Type = ELF::R_ARM_TLS_LE32; + break; + case MCSymbolRefExpr::VK_ARM_GOTTPOFF: + Type = ELF::R_ARM_TLS_IE32; + break; + case MCSymbolRefExpr::VK_None: + Type = ELF::R_ARM_ABS32; + break; + case MCSymbolRefExpr::VK_ARM_GOTOFF: + Type = ELF::R_ARM_GOTOFF32; + break; + } break; - - case ELF::SHT_PROGBITS: - case ELF::SHT_STRTAB: - case ELF::SHT_NOBITS: - case ELF::SHT_NULL: - // Nothing to do. + case ARM::fixup_arm_ldst_pcrel_12: + case ARM::fixup_arm_pcrel_10: + case ARM::fixup_arm_adr_pcrel_12: + case ARM::fixup_arm_thumb_bl: + case ARM::fixup_arm_thumb_cb: + case ARM::fixup_arm_thumb_cp: + case ARM::fixup_arm_thumb_br: + assert(0 && "Unimplemented"); break; - - case ELF::SHT_HASH: - case ELF::SHT_GROUP: - case ELF::SHT_SYMTAB_SHNDX: - default: - assert(0 && "FIXME: sh_type value not supported!"); + case ARM::fixup_arm_uncondbranch: + Type = ELF::R_ARM_CALL; + break; + case ARM::fixup_arm_condbranch: + Type = ELF::R_ARM_JUMP24; + break; + case ARM::fixup_arm_movt_hi16: + Type = ELF::R_ARM_MOVT_ABS; + break; + case ARM::fixup_arm_movw_lo16: + Type = ELF::R_ARM_MOVW_ABS_NC; + break; + case ARM::fixup_t2_movt_hi16: + Type = ELF::R_ARM_THM_MOVT_ABS; + break; + case ARM::fixup_t2_movw_lo16: + Type = ELF::R_ARM_THM_MOVW_ABS_NC; break; } - - WriteSecHdrEntry(SectionStringTableIndex[&it->getSection()], - Section.getType(), Section.getFlags(), - Layout.getSectionAddress(&SD), - SectionOffsetMap.lookup(&SD.getSection()), - Layout.getSectionSize(&SD), sh_link, - sh_info, SD.getAlignment(), - Section.getEntrySize()); } -} -ELFObjectWriter::ELFObjectWriter(raw_ostream &OS, - bool Is64Bit, - bool IsLittleEndian, - bool HasRelocationAddend) - : MCObjectWriter(OS, IsLittleEndian) -{ - Impl = new ELFObjectWriterImpl(this, Is64Bit, HasRelocationAddend); + if (RelocNeedsGOT(Modifier)) + NeedsGOT = true; + + return Type; } -ELFObjectWriter::~ELFObjectWriter() { - delete (ELFObjectWriterImpl*) Impl; +//===- MBlazeELFObjectWriter -------------------------------------------===// + +MBlazeELFObjectWriter::MBlazeELFObjectWriter(MCELFObjectTargetWriter *MOTW, + raw_ostream &_OS, + bool IsLittleEndian) + : ELFObjectWriter(MOTW, _OS, IsLittleEndian) { } -void ELFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm) { - ((ELFObjectWriterImpl*) Impl)->ExecutePostLayoutBinding(Asm); +MBlazeELFObjectWriter::~MBlazeELFObjectWriter() { } -void ELFObjectWriter::RecordRelocation(const MCAssembler &Asm, - const MCAsmLayout &Layout, - const MCFragment *Fragment, - const MCFixup &Fixup, MCValue Target, - uint64_t &FixedValue) { - ((ELFObjectWriterImpl*) Impl)->RecordRelocation(Asm, Layout, Fragment, Fixup, - Target, FixedValue); +unsigned MBlazeELFObjectWriter::GetRelocType(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel, + bool IsRelocWithSymbol, + int64_t Addend) { + // determine the type of the relocation + unsigned Type; + if (IsPCRel) { + switch ((unsigned)Fixup.getKind()) { + default: + llvm_unreachable("Unimplemented"); + case FK_PCRel_4: + Type = ELF::R_MICROBLAZE_64_PCREL; + break; + case FK_PCRel_2: + Type = ELF::R_MICROBLAZE_32_PCREL; + break; + } + } else { + switch ((unsigned)Fixup.getKind()) { + default: llvm_unreachable("invalid fixup kind!"); + case FK_Data_4: + Type = ((IsRelocWithSymbol || Addend !=0) + ? ELF::R_MICROBLAZE_32 + : ELF::R_MICROBLAZE_64); + break; + case FK_Data_2: + Type = ELF::R_MICROBLAZE_32; + break; + } + } + return Type; } -void ELFObjectWriter::WriteObject(const MCAssembler &Asm, - const MCAsmLayout &Layout) { - ((ELFObjectWriterImpl*) Impl)->WriteObject(Asm, Layout); +//===- X86ELFObjectWriter -------------------------------------------===// + + +X86ELFObjectWriter::X86ELFObjectWriter(MCELFObjectTargetWriter *MOTW, + raw_ostream &_OS, + bool IsLittleEndian) + : ELFObjectWriter(MOTW, _OS, IsLittleEndian) +{} + +X86ELFObjectWriter::~X86ELFObjectWriter() +{} + +unsigned X86ELFObjectWriter::GetRelocType(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel, + bool IsRelocWithSymbol, + int64_t Addend) { + // determine the type of the relocation + + MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ? + MCSymbolRefExpr::VK_None : Target.getSymA()->getKind(); + unsigned Type; + if (is64Bit()) { + if (IsPCRel) { + switch ((unsigned)Fixup.getKind()) { + default: llvm_unreachable("invalid fixup kind!"); + case FK_PCRel_8: + assert(Modifier == MCSymbolRefExpr::VK_None); + Type = ELF::R_X86_64_PC64; + break; + case X86::reloc_signed_4byte: + case X86::reloc_riprel_4byte_movq_load: + case FK_Data_4: // FIXME? + case X86::reloc_riprel_4byte: + case FK_PCRel_4: + switch (Modifier) { + default: + llvm_unreachable("Unimplemented"); + case MCSymbolRefExpr::VK_None: + Type = ELF::R_X86_64_PC32; + break; + case MCSymbolRefExpr::VK_PLT: + Type = ELF::R_X86_64_PLT32; + break; + case MCSymbolRefExpr::VK_GOTPCREL: + Type = ELF::R_X86_64_GOTPCREL; + break; + case MCSymbolRefExpr::VK_GOTTPOFF: + Type = ELF::R_X86_64_GOTTPOFF; + break; + case MCSymbolRefExpr::VK_TLSGD: + Type = ELF::R_X86_64_TLSGD; + break; + case MCSymbolRefExpr::VK_TLSLD: + Type = ELF::R_X86_64_TLSLD; + break; + } + break; + case FK_PCRel_2: + assert(Modifier == MCSymbolRefExpr::VK_None); + Type = ELF::R_X86_64_PC16; + break; + } + } else { + switch ((unsigned)Fixup.getKind()) { + default: llvm_unreachable("invalid fixup kind!"); + case FK_Data_8: Type = ELF::R_X86_64_64; break; + case X86::reloc_signed_4byte: + assert(isInt<32>(Target.getConstant())); + switch (Modifier) { + default: + llvm_unreachable("Unimplemented"); + case MCSymbolRefExpr::VK_None: + Type = ELF::R_X86_64_32S; + break; + case MCSymbolRefExpr::VK_GOT: + Type = ELF::R_X86_64_GOT32; + break; + case MCSymbolRefExpr::VK_GOTPCREL: + Type = ELF::R_X86_64_GOTPCREL; + break; + case MCSymbolRefExpr::VK_TPOFF: + Type = ELF::R_X86_64_TPOFF32; + break; + case MCSymbolRefExpr::VK_DTPOFF: + Type = ELF::R_X86_64_DTPOFF32; + break; + } + break; + case FK_Data_4: + Type = ELF::R_X86_64_32; + break; + case FK_Data_2: Type = ELF::R_X86_64_16; break; + case FK_PCRel_1: + case FK_Data_1: Type = ELF::R_X86_64_8; break; + } + } + } else { + if (IsPCRel) { + switch (Modifier) { + default: + llvm_unreachable("Unimplemented"); + case MCSymbolRefExpr::VK_None: + Type = ELF::R_386_PC32; + break; + case MCSymbolRefExpr::VK_PLT: + Type = ELF::R_386_PLT32; + break; + } + } else { + switch ((unsigned)Fixup.getKind()) { + default: llvm_unreachable("invalid fixup kind!"); + + case X86::reloc_global_offset_table: + Type = ELF::R_386_GOTPC; + break; + + // FIXME: Should we avoid selecting reloc_signed_4byte in 32 bit mode + // instead? + case X86::reloc_signed_4byte: + case FK_PCRel_4: + case FK_Data_4: + switch (Modifier) { + default: + llvm_unreachable("Unimplemented"); + case MCSymbolRefExpr::VK_None: + Type = ELF::R_386_32; + break; + case MCSymbolRefExpr::VK_GOT: + Type = ELF::R_386_GOT32; + break; + case MCSymbolRefExpr::VK_GOTOFF: + Type = ELF::R_386_GOTOFF; + break; + case MCSymbolRefExpr::VK_TLSGD: + Type = ELF::R_386_TLS_GD; + break; + case MCSymbolRefExpr::VK_TPOFF: + Type = ELF::R_386_TLS_LE_32; + break; + case MCSymbolRefExpr::VK_INDNTPOFF: + Type = ELF::R_386_TLS_IE; + break; + case MCSymbolRefExpr::VK_NTPOFF: + Type = ELF::R_386_TLS_LE; + break; + case MCSymbolRefExpr::VK_GOTNTPOFF: + Type = ELF::R_386_TLS_GOTIE; + break; + case MCSymbolRefExpr::VK_TLSLDM: + Type = ELF::R_386_TLS_LDM; + break; + case MCSymbolRefExpr::VK_DTPOFF: + Type = ELF::R_386_TLS_LDO_32; + break; + } + break; + case FK_Data_2: Type = ELF::R_386_16; break; + case FK_PCRel_1: + case FK_Data_1: Type = ELF::R_386_8; break; + } + } + } + + if (RelocNeedsGOT(Modifier)) + NeedsGOT = true; + + return Type; } diff --git a/lib/MC/MCAsmInfo.cpp b/lib/MC/MCAsmInfo.cpp index 670b2e9b292a..cc1afbd08926 100644 --- a/lib/MC/MCAsmInfo.cpp +++ b/lib/MC/MCAsmInfo.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCAsmInfo.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include #include using namespace llvm; @@ -23,11 +23,13 @@ MCAsmInfo::MCAsmInfo() { HasMachoZeroFillDirective = false; HasMachoTBSSDirective = false; HasStaticCtorDtorReferenceInStaticMode = false; + LinkerRequiresNonEmptyDwarfLines = false; MaxInstLength = 4; PCSymbol = "$"; SeparatorChar = ';'; CommentColumn = 40; CommentString = "#"; + LabelSuffix = ":"; GlobalPrefix = ""; PrivateGlobalPrefix = "."; LinkerPrivateGlobalPrefix = ""; @@ -52,18 +54,19 @@ MCAsmInfo::MCAsmInfo() { GPRel32Directive = 0; GlobalDirective = "\t.globl\t"; HasSetDirective = true; + HasAggressiveSymbolFolding = true; HasLCOMMDirective = false; COMMDirectiveAlignmentIsInBytes = true; HasDotTypeDotSizeDirective = true; HasSingleParameterDotFile = true; HasNoDeadStrip = false; + HasSymbolResolver = false; WeakRefDirective = 0; WeakDefDirective = 0; LinkOnceDirective = 0; HiddenVisibilityAttr = MCSA_Hidden; ProtectedVisibilityAttr = MCSA_Protected; HasLEB128 = false; - HasDotLocAndDotFile = false; SupportsDebugInformation = false; ExceptionsType = ExceptionHandling::None; DwarfRequiresFrameSection = true; diff --git a/lib/MC/MCAsmInfoDarwin.cpp b/lib/MC/MCAsmInfoDarwin.cpp index e0e261a63c70..13776f04437d 100644 --- a/lib/MC/MCAsmInfoDarwin.cpp +++ b/lib/MC/MCAsmInfoDarwin.cpp @@ -37,13 +37,20 @@ MCAsmInfoDarwin::MCAsmInfoDarwin() { HasMachoZeroFillDirective = true; // Uses .zerofill HasMachoTBSSDirective = true; // Uses .tbss HasStaticCtorDtorReferenceInStaticMode = true; - + + // FIXME: Darwin 10 and newer don't need this. + LinkerRequiresNonEmptyDwarfLines = true; + + // FIXME: Change this once MC is the system assembler. + HasAggressiveSymbolFolding = false; + HiddenVisibilityAttr = MCSA_PrivateExtern; // Doesn't support protected visibility. ProtectedVisibilityAttr = MCSA_Global; HasDotTypeDotSizeDirective = false; HasNoDeadStrip = true; + HasSymbolResolver = true; DwarfUsesAbsoluteLabelForStmtList = false; DwarfUsesLabelOffsetForRanges = false; diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index 1cc8fb0b5486..8d0698216f60 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -12,6 +12,7 @@ #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCSectionMachO.h" @@ -23,6 +24,10 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/Format.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Target/TargetAsmBackend.h" +#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/Target/TargetLoweringObjectFile.h" +#include using namespace llvm; namespace { @@ -32,29 +37,33 @@ class MCAsmStreamer : public MCStreamer { const MCAsmInfo &MAI; OwningPtr InstPrinter; OwningPtr Emitter; - + OwningPtr AsmBackend; + SmallString<128> CommentToEmit; raw_svector_ostream CommentStream; - unsigned IsLittleEndian : 1; unsigned IsVerboseAsm : 1; unsigned ShowInst : 1; + unsigned UseLoc : 1; + + bool needsSet(const MCExpr *Value); public: MCAsmStreamer(MCContext &Context, formatted_raw_ostream &os, - bool isLittleEndian, bool isVerboseAsm, MCInstPrinter *printer, - MCCodeEmitter *emitter, bool showInst) + bool isVerboseAsm, + bool useLoc, + MCInstPrinter *printer, MCCodeEmitter *emitter, + TargetAsmBackend *asmbackend, + bool showInst) : MCStreamer(Context), OS(os), MAI(Context.getAsmInfo()), - InstPrinter(printer), Emitter(emitter), CommentStream(CommentToEmit), - IsLittleEndian(isLittleEndian), IsVerboseAsm(isVerboseAsm), - ShowInst(showInst) { + InstPrinter(printer), Emitter(emitter), AsmBackend(asmbackend), + CommentStream(CommentToEmit), IsVerboseAsm(isVerboseAsm), + ShowInst(showInst), UseLoc(useLoc) { if (InstPrinter && IsVerboseAsm) InstPrinter->setCommentStream(CommentStream); } ~MCAsmStreamer() {} - bool isLittleEndian() const { return IsLittleEndian; } - inline void EmitEOL() { // If we don't have any comments, just emit a \n. if (!IsVerboseAsm) { @@ -68,7 +77,7 @@ public: /// isVerboseAsm - Return true if this streamer supports verbose assembly at /// all. virtual bool isVerboseAsm() const { return IsVerboseAsm; } - + /// hasRawTextSupport - We support EmitRawText. virtual bool hasRawTextSupport() const { return true; } @@ -98,13 +107,26 @@ public: /// @name MCStreamer Interface /// @{ - virtual void SwitchSection(const MCSection *Section); + virtual void ChangeSection(const MCSection *Section); + + virtual void InitSections() { + // FIXME, this is MachO specific, but the testsuite + // expects this. + SwitchSection(getContext().getMachOSection("__TEXT", "__text", + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + 0, SectionKind::getText())); + } virtual void EmitLabel(MCSymbol *Symbol); virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); + virtual void EmitThumbFunc(MCSymbol *Func); virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); + virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol); + virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label); virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); @@ -122,19 +144,26 @@ public: /// @param Symbol - The common symbol to emit. /// @param Size - The size of the common symbol. virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size); - + virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, unsigned Size = 0, unsigned ByteAlignment = 0); virtual void EmitTBSSSymbol (const MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment = 0); - + virtual void EmitBytes(StringRef Data, unsigned AddrSpace); - virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace); - virtual void EmitIntValue(uint64_t Value, unsigned Size, unsigned AddrSpace); + virtual void EmitValueImpl(const MCExpr *Value, unsigned Size, + bool isPCRel, unsigned AddrSpace); + virtual void EmitIntValue(uint64_t Value, unsigned Size, + unsigned AddrSpace = 0); + + virtual void EmitULEB128Value(const MCExpr *Value, unsigned AddrSpace = 0); + + virtual void EmitSLEB128Value(const MCExpr *Value, unsigned AddrSpace = 0); + virtual void EmitGPRel32Value(const MCExpr *Value); - + virtual void EmitFill(uint64_t NumBytes, uint8_t FillValue, unsigned AddrSpace); @@ -150,17 +179,28 @@ public: unsigned char Value = 0); virtual void EmitFileDirective(StringRef Filename); - virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename); + virtual bool EmitDwarfFileDirective(unsigned FileNo, StringRef Filename); + virtual void EmitDwarfLocDirective(unsigned FileNo, unsigned Line, + unsigned Column, unsigned Flags, + unsigned Isa, unsigned Discriminator); + + virtual bool EmitCFIStartProc(); + virtual bool EmitCFIEndProc(); + virtual bool EmitCFIDefCfaOffset(int64_t Offset); + virtual bool EmitCFIDefCfaRegister(int64_t Register); + virtual bool EmitCFIOffset(int64_t Register, int64_t Offset); + virtual bool EmitCFIPersonality(const MCSymbol *Sym, unsigned Encoding); + virtual bool EmitCFILsda(const MCSymbol *Sym, unsigned Encoding); virtual void EmitInstruction(const MCInst &Inst); - - /// EmitRawText - If this file is backed by a assembly streamer, this dumps + + /// EmitRawText - If this file is backed by an assembly streamer, this dumps /// the specified string in the output .s file. This capability is /// indicated by the hasRawTextSupport() predicate. virtual void EmitRawText(StringRef String); - + virtual void Finish(); - + /// @} }; @@ -172,14 +212,14 @@ public: /// verbose assembly output is enabled. void MCAsmStreamer::AddComment(const Twine &T) { if (!IsVerboseAsm) return; - + // Make sure that CommentStream is flushed. CommentStream.flush(); - + T.toVector(CommentToEmit); // Each comment goes on its own line. CommentToEmit.push_back('\n'); - + // Tell the comment stream that the vector changed underneath it. CommentStream.resync(); } @@ -189,10 +229,10 @@ void MCAsmStreamer::EmitCommentsAndEOL() { OS << '\n'; return; } - + CommentStream.flush(); StringRef Comments = CommentToEmit.str(); - + assert(Comments.back() == '\n' && "Comment array not newline terminated"); do { @@ -200,10 +240,10 @@ void MCAsmStreamer::EmitCommentsAndEOL() { OS.PadToColumn(MAI.getCommentColumn()); size_t Position = Comments.find('\n'); OS << MAI.getCommentString() << ' ' << Comments.substr(0, Position) << '\n'; - + Comments = Comments.substr(Position+1); } while (!Comments.empty()); - + CommentToEmit.clear(); // Tell the comment stream that the vector changed underneath it. CommentStream.resync(); @@ -214,33 +254,41 @@ static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) { return Value & ((uint64_t) (int64_t) -1 >> (64 - Bytes * 8)); } -void MCAsmStreamer::SwitchSection(const MCSection *Section) { +void MCAsmStreamer::ChangeSection(const MCSection *Section) { assert(Section && "Cannot switch to a null section!"); - if (Section != CurSection) { - PrevSection = CurSection; - CurSection = Section; - Section->PrintSwitchToSection(MAI, OS); - } + Section->PrintSwitchToSection(MAI, OS); } void MCAsmStreamer::EmitLabel(MCSymbol *Symbol) { assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); assert(!Symbol->isVariable() && "Cannot emit a variable symbol!"); - assert(CurSection && "Cannot emit before setting section!"); + assert(getCurrentSection() && "Cannot emit before setting section!"); - OS << *Symbol << ":"; + OS << *Symbol << MAI.getLabelSuffix(); EmitEOL(); - Symbol->setSection(*CurSection); + Symbol->setSection(*getCurrentSection()); } void MCAsmStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { switch (Flag) { default: assert(0 && "Invalid flag!"); + case MCAF_SyntaxUnified: OS << "\t.syntax unified"; break; case MCAF_SubsectionsViaSymbols: OS << ".subsections_via_symbols"; break; + case MCAF_Code16: OS << "\t.code\t16"; break; + case MCAF_Code32: OS << "\t.code\t32"; break; } EmitEOL(); } +void MCAsmStreamer::EmitThumbFunc(MCSymbol *Func) { + // This needs to emit to a temporary string to get properly quoted + // MCSymbols when they have spaces in them. + OS << "\t.thumb_func"; + if (Func) + OS << '\t' << *Func; + EmitEOL(); +} + void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { OS << *Symbol << " = " << *Value; EmitEOL(); @@ -249,6 +297,18 @@ void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { Symbol->setVariableValue(Value); } +void MCAsmStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { + OS << ".weakref " << *Alias << ", " << *Symbol; + EmitEOL(); +} + +void MCAsmStreamer::EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label) { + EmitDwarfSetLineAddr(LineDelta, Label, + getContext().getTargetAsmInfo().getPointerSize()); +} + void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { switch (Attribute) { @@ -259,6 +319,7 @@ void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, case MCSA_ELF_TypeTLS: /// .type _foo, STT_TLS # aka @tls_object case MCSA_ELF_TypeCommon: /// .type _foo, STT_COMMON # aka @common case MCSA_ELF_TypeNoType: /// .type _foo, STT_NOTYPE # aka @notype + case MCSA_ELF_TypeGnuUniqueObject: /// .type _foo, @gnu_unique_object assert(MAI.hasDotTypeDotSizeDirective() && "Symbol Attr not supported"); OS << "\t.type\t" << *Symbol << ',' << ((MAI.getCommentString()[0] != '@') ? '@' : '%'); @@ -270,6 +331,7 @@ void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, case MCSA_ELF_TypeTLS: OS << "tls_object"; break; case MCSA_ELF_TypeCommon: OS << "common"; break; case MCSA_ELF_TypeNoType: OS << "no_type"; break; + case MCSA_ELF_TypeGnuUniqueObject: OS << "gnu_unique_object"; break; } EmitEOL(); return; @@ -282,6 +344,7 @@ void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, case MCSA_LazyReference: OS << "\t.lazy_reference\t"; break; case MCSA_Local: OS << "\t.local\t"; break; case MCSA_NoDeadStrip: OS << "\t.no_dead_strip\t"; break; + case MCSA_SymbolResolver: OS << "\t.symbol_resolver\t"; break; case MCSA_PrivateExtern: OS << "\t.private_extern\t"; break; case MCSA_Protected: OS << "\t.protected\t"; break; case MCSA_Reference: OS << "\t.reference\t"; break; @@ -352,11 +415,11 @@ void MCAsmStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, unsigned Size, unsigned ByteAlignment) { // Note: a .zerofill directive does not switch sections. OS << ".zerofill "; - + // This is a mach-o specific directive. const MCSectionMachO *MOSection = ((const MCSectionMachO*)Section); OS << MOSection->getSegmentName() << "," << MOSection->getSectionName(); - + if (Symbol != NULL) { OS << ',' << *Symbol << ',' << Size; if (ByteAlignment != 0) @@ -374,11 +437,11 @@ void MCAsmStreamer::EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, // Instead of using the Section we'll just use the shortcut. // This is a mach-o specific directive and section. OS << ".tbss " << *Symbol << ", " << Size; - + // Output align if we have it. We default to 1 so don't bother printing // that. if (ByteAlignment > 1) OS << ", " << Log2_32(ByteAlignment); - + EmitEOL(); } @@ -386,19 +449,19 @@ static inline char toOctal(int X) { return (X&7)+'0'; } static void PrintQuotedString(StringRef Data, raw_ostream &OS) { OS << '"'; - + for (unsigned i = 0, e = Data.size(); i != e; ++i) { unsigned char C = Data[i]; if (C == '"' || C == '\\') { OS << '\\' << (char)C; continue; } - + if (isprint((unsigned char)C)) { OS << (char)C; continue; } - + switch (C) { case '\b': OS << "\\b"; break; case '\f': OS << "\\f"; break; @@ -413,15 +476,15 @@ static void PrintQuotedString(StringRef Data, raw_ostream &OS) { break; } } - + OS << '"'; } void MCAsmStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { - assert(CurSection && "Cannot emit contents before setting section!"); + assert(getCurrentSection() && "Cannot emit contents before setting section!"); if (Data.empty()) return; - + if (Data.size() == 1) { OS << MAI.getData8bitsDirective(AddrSpace); OS << (unsigned)(unsigned char)Data[0]; @@ -443,11 +506,15 @@ void MCAsmStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { EmitEOL(); } -/// EmitIntValue - Special case of EmitValue that avoids the client having -/// to pass in a MCExpr for constant integers. void MCAsmStreamer::EmitIntValue(uint64_t Value, unsigned Size, unsigned AddrSpace) { - assert(CurSection && "Cannot emit contents before setting section!"); + EmitValue(MCConstantExpr::Create(Value, getContext()), Size, AddrSpace); +} + +void MCAsmStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, + bool isPCRel, unsigned AddrSpace) { + assert(getCurrentSection() && "Cannot emit contents before setting section!"); + assert(!isPCRel && "Cannot emit pc relative relocations!"); const char *Directive = 0; switch (Size) { default: break; @@ -458,35 +525,43 @@ void MCAsmStreamer::EmitIntValue(uint64_t Value, unsigned Size, Directive = MAI.getData64bitsDirective(AddrSpace); // If the target doesn't support 64-bit data, emit as two 32-bit halves. if (Directive) break; - if (isLittleEndian()) { - EmitIntValue((uint32_t)(Value >> 0 ), 4, AddrSpace); - EmitIntValue((uint32_t)(Value >> 32), 4, AddrSpace); + int64_t IntValue; + if (!Value->EvaluateAsAbsolute(IntValue)) + report_fatal_error("Don't know how to emit this value."); + if (getContext().getTargetAsmInfo().isLittleEndian()) { + EmitIntValue((uint32_t)(IntValue >> 0 ), 4, AddrSpace); + EmitIntValue((uint32_t)(IntValue >> 32), 4, AddrSpace); } else { - EmitIntValue((uint32_t)(Value >> 32), 4, AddrSpace); - EmitIntValue((uint32_t)(Value >> 0 ), 4, AddrSpace); + EmitIntValue((uint32_t)(IntValue >> 32), 4, AddrSpace); + EmitIntValue((uint32_t)(IntValue >> 0 ), 4, AddrSpace); } return; } - + assert(Directive && "Invalid size for machine code value!"); - OS << Directive << truncateToSize(Value, Size); + OS << Directive << *Value; EmitEOL(); } -void MCAsmStreamer::EmitValue(const MCExpr *Value, unsigned Size, - unsigned AddrSpace) { - assert(CurSection && "Cannot emit contents before setting section!"); - const char *Directive = 0; - switch (Size) { - default: break; - case 1: Directive = MAI.getData8bitsDirective(AddrSpace); break; - case 2: Directive = MAI.getData16bitsDirective(AddrSpace); break; - case 4: Directive = MAI.getData32bitsDirective(AddrSpace); break; - case 8: Directive = MAI.getData64bitsDirective(AddrSpace); break; +void MCAsmStreamer::EmitULEB128Value(const MCExpr *Value, unsigned AddrSpace) { + int64_t IntValue; + if (Value->EvaluateAsAbsolute(IntValue)) { + EmitULEB128IntValue(IntValue, AddrSpace); + return; } - - assert(Directive && "Invalid size for machine code value!"); - OS << Directive << *Value; + assert(MAI.hasLEB128() && "Cannot print a .uleb"); + OS << ".uleb128 " << *Value; + EmitEOL(); +} + +void MCAsmStreamer::EmitSLEB128Value(const MCExpr *Value, unsigned AddrSpace) { + int64_t IntValue; + if (Value->EvaluateAsAbsolute(IntValue)) { + EmitSLEB128IntValue(IntValue, AddrSpace); + return; + } + assert(MAI.hasLEB128() && "Cannot print a .sleb"); + OS << ".sleb128 " << *Value; EmitEOL(); } @@ -502,7 +577,7 @@ void MCAsmStreamer::EmitGPRel32Value(const MCExpr *Value) { void MCAsmStreamer::EmitFill(uint64_t NumBytes, uint8_t FillValue, unsigned AddrSpace) { if (NumBytes == 0) return; - + if (AddrSpace == 0) if (const char *ZeroDirective = MAI.getZeroDirective()) { OS << ZeroDirective << NumBytes; @@ -530,7 +605,7 @@ void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, case 4: OS << ".p2alignl "; break; case 8: llvm_unreachable("Unsupported alignment size!"); } - + if (MAI.getAlignmentIsInBytes()) OS << ByteAlignment; else @@ -540,13 +615,13 @@ void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, OS << ", 0x"; OS.write_hex(truncateToSize(Value, ValueSize)); - if (MaxBytesToEmit) + if (MaxBytesToEmit) OS << ", " << MaxBytesToEmit; } EmitEOL(); return; } - + // Non-power of two alignment. This is not widely supported by assemblers. // FIXME: Parameterize this based on MAI. switch (ValueSize) { @@ -559,7 +634,7 @@ void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, OS << ' ' << ByteAlignment; OS << ", " << truncateToSize(Value, ValueSize); - if (MaxBytesToEmit) + if (MaxBytesToEmit) OS << ", " << MaxBytesToEmit; EmitEOL(); } @@ -586,10 +661,118 @@ void MCAsmStreamer::EmitFileDirective(StringRef Filename) { EmitEOL(); } -void MCAsmStreamer::EmitDwarfFileDirective(unsigned FileNo, StringRef Filename){ - OS << "\t.file\t" << FileNo << ' '; - PrintQuotedString(Filename, OS); +bool MCAsmStreamer::EmitDwarfFileDirective(unsigned FileNo, StringRef Filename){ + if (UseLoc) { + OS << "\t.file\t" << FileNo << ' '; + PrintQuotedString(Filename, OS); + EmitEOL(); + } + return this->MCStreamer::EmitDwarfFileDirective(FileNo, Filename); +} + +void MCAsmStreamer::EmitDwarfLocDirective(unsigned FileNo, unsigned Line, + unsigned Column, unsigned Flags, + unsigned Isa, + unsigned Discriminator) { + this->MCStreamer::EmitDwarfLocDirective(FileNo, Line, Column, Flags, + Isa, Discriminator); + if (!UseLoc) + return; + + OS << "\t.loc\t" << FileNo << " " << Line << " " << Column; + if (Flags & DWARF2_FLAG_BASIC_BLOCK) + OS << " basic_block"; + if (Flags & DWARF2_FLAG_PROLOGUE_END) + OS << " prologue_end"; + if (Flags & DWARF2_FLAG_EPILOGUE_BEGIN) + OS << " epilogue_begin"; + + unsigned OldFlags = getContext().getCurrentDwarfLoc().getFlags(); + if ((Flags & DWARF2_FLAG_IS_STMT) != (OldFlags & DWARF2_FLAG_IS_STMT)) { + OS << " is_stmt "; + + if (Flags & DWARF2_FLAG_IS_STMT) + OS << "1"; + else + OS << "0"; + } + + if (Isa) + OS << "isa " << Isa; + if (Discriminator) + OS << "discriminator " << Discriminator; + EmitEOL(); +} + +bool MCAsmStreamer::EmitCFIStartProc() { + if (this->MCStreamer::EmitCFIStartProc()) + return true; + + OS << "\t.cfi_startproc"; EmitEOL(); + + return false; +} + +bool MCAsmStreamer::EmitCFIEndProc() { + if (this->MCStreamer::EmitCFIEndProc()) + return true; + + OS << "\t.cfi_endproc"; + EmitEOL(); + + return false; +} + +bool MCAsmStreamer::EmitCFIDefCfaOffset(int64_t Offset) { + if (this->MCStreamer::EmitCFIDefCfaOffset(Offset)) + return true; + + OS << "\t.cfi_def_cfa_offset " << Offset; + EmitEOL(); + + return false; +} + +bool MCAsmStreamer::EmitCFIDefCfaRegister(int64_t Register) { + if (this->MCStreamer::EmitCFIDefCfaRegister(Register)) + return true; + + OS << "\t.cfi_def_cfa_register " << Register; + EmitEOL(); + + return false; +} + +bool MCAsmStreamer::EmitCFIOffset(int64_t Register, int64_t Offset) { + if (this->MCStreamer::EmitCFIOffset(Register, Offset)) + return true; + + OS << "\t.cfi_offset " << Register << ", " << Offset; + EmitEOL(); + + return false; +} + +bool MCAsmStreamer::EmitCFIPersonality(const MCSymbol *Sym, + unsigned Encoding) { + if (this->MCStreamer::EmitCFIPersonality(Sym, Encoding)) + return true; + + OS << "\t.cfi_personality " << Encoding << ", " << *Sym; + EmitEOL(); + + return false; +} + +bool MCAsmStreamer::EmitCFILsda(const MCSymbol *Sym, unsigned Encoding) { + if (this->MCStreamer::EmitCFILsda(Sym, Encoding)) + return true; + + OS << "\t.cfi_lsda " << Encoding << ", " << *Sym; + EmitEOL(); + + return false; } void MCAsmStreamer::AddEncodingComment(const MCInst &Inst) { @@ -610,7 +793,7 @@ void MCAsmStreamer::AddEncodingComment(const MCInst &Inst) { for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { MCFixup &F = Fixups[i]; - const MCFixupKindInfo &Info = Emitter->getFixupKindInfo(F.getKind()); + const MCFixupKindInfo &Info = AsmBackend->getFixupKindInfo(F.getKind()); for (unsigned j = 0; j != Info.TargetSize; ++j) { unsigned Index = F.getOffset() * 8 + Info.TargetOffset + j; assert(Index < Code.size() * 8 && "Invalid offset in fixup!"); @@ -618,6 +801,8 @@ void MCAsmStreamer::AddEncodingComment(const MCInst &Inst) { } } + // FIXME: Node the fixup comments for Thumb2 are completely bogus since the + // high order halfword of a 32-bit Thumb2 instruction is emitted first. OS << "encoding: ["; for (unsigned i = 0, e = Code.size(); i != e; ++i) { if (i) @@ -637,15 +822,26 @@ void MCAsmStreamer::AddEncodingComment(const MCInst &Inst) { if (MapEntry == 0) { OS << format("0x%02x", uint8_t(Code[i])); } else { - assert(Code[i] == 0 && "Encoder wrote into fixed up bit!"); - OS << char('A' + MapEntry - 1); + if (Code[i]) { + // FIXME: Some of the 8 bits require fix up. + OS << format("0x%02x", uint8_t(Code[i])) << '\'' + << char('A' + MapEntry - 1) << '\''; + } else + OS << char('A' + MapEntry - 1); } } else { // Otherwise, write out in binary. OS << "0b"; for (unsigned j = 8; j--;) { unsigned Bit = (Code[i] >> j) & 1; - if (uint8_t MapEntry = FixupMap[i * 8 + j]) { + + unsigned FixupBit; + if (getContext().getTargetAsmInfo().isLittleEndian()) + FixupBit = i * 8 + j; + else + FixupBit = i * 8 + (7-j); + + if (uint8_t MapEntry = FixupMap[FixupBit]) { assert(Bit == 0 && "Encoder wrote into fixed up bit!"); OS << char('A' + MapEntry - 1); } else @@ -657,14 +853,17 @@ void MCAsmStreamer::AddEncodingComment(const MCInst &Inst) { for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { MCFixup &F = Fixups[i]; - const MCFixupKindInfo &Info = Emitter->getFixupKindInfo(F.getKind()); + const MCFixupKindInfo &Info = AsmBackend->getFixupKindInfo(F.getKind()); OS << " fixup " << char('A' + i) << " - " << "offset: " << F.getOffset() << ", value: " << *F.getValue() << ", kind: " << Info.Name << "\n"; } } void MCAsmStreamer::EmitInstruction(const MCInst &Inst) { - assert(CurSection && "Cannot emit contents before setting section!"); + assert(getCurrentSection() && "Cannot emit contents before setting section!"); + + if (!UseLoc) + MCLineEntry::Make(this, getCurrentSection()); // Show the encoding in a comment if we have a code emitter. if (Emitter) @@ -684,7 +883,7 @@ void MCAsmStreamer::EmitInstruction(const MCInst &Inst) { EmitEOL(); } -/// EmitRawText - If this file is backed by a assembly streamer, this dumps +/// EmitRawText - If this file is backed by an assembly streamer, this dumps /// the specified string in the output .s file. This capability is /// indicated by the hasRawTextSupport() predicate. void MCAsmStreamer::EmitRawText(StringRef String) { @@ -695,13 +894,16 @@ void MCAsmStreamer::EmitRawText(StringRef String) { } void MCAsmStreamer::Finish() { + // Dump out the dwarf file & directory tables and line tables. + if (getContext().hasDwarfFiles() && !UseLoc) + MCDwarfFileTable::Emit(this); } MCStreamer *llvm::createAsmStreamer(MCContext &Context, formatted_raw_ostream &OS, - bool isLittleEndian, - bool isVerboseAsm, MCInstPrinter *IP, - MCCodeEmitter *CE, bool ShowInst) { - return new MCAsmStreamer(Context, OS, isLittleEndian, isVerboseAsm, - IP, CE, ShowInst); + bool isVerboseAsm, bool useLoc, + MCInstPrinter *IP, MCCodeEmitter *CE, + TargetAsmBackend *TAB, bool ShowInst) { + return new MCAsmStreamer(Context, OS, isVerboseAsm, useLoc, + IP, CE, TAB, ShowInst); } diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index f0e1d7fbc21c..999264604224 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -11,10 +11,13 @@ #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSection.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCValue.h" +#include "llvm/MC/MCDwarf.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" @@ -36,7 +39,6 @@ STATISTIC(FragmentLayouts, "Number of fragment layouts"); STATISTIC(ObjectBytes, "Number of emitted object file bytes"); STATISTIC(RelaxationSteps, "Number of assembler layout and relaxation steps"); STATISTIC(RelaxedInstructions, "Number of relaxed instructions"); -STATISTIC(SectionLayouts, "Number of section layouts"); } } @@ -48,131 +50,78 @@ STATISTIC(SectionLayouts, "Number of section layouts"); /* *** */ MCAsmLayout::MCAsmLayout(MCAssembler &Asm) - : Assembler(Asm), LastValidFragment(0) + : Assembler(Asm), LastValidFragment() { // Compute the section layout order. Virtual sections must go last. for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) - if (!Asm.getBackend().isVirtualSection(it->getSection())) + if (!it->getSection().isVirtualSection()) SectionOrder.push_back(&*it); for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) - if (Asm.getBackend().isVirtualSection(it->getSection())) + if (it->getSection().isVirtualSection()) SectionOrder.push_back(&*it); } -bool MCAsmLayout::isSectionUpToDate(const MCSectionData *SD) const { - // The first section is always up-to-date. - unsigned Index = SD->getLayoutOrder(); - if (!Index) - return true; - - // Otherwise, sections are always implicitly computed when the preceeding - // fragment is layed out. - const MCSectionData *Prev = getSectionOrder()[Index - 1]; - return isFragmentUpToDate(&(Prev->getFragmentList().back())); -} - bool MCAsmLayout::isFragmentUpToDate(const MCFragment *F) const { - return (LastValidFragment && - F->getLayoutOrder() <= LastValidFragment->getLayoutOrder()); + const MCSectionData &SD = *F->getParent(); + const MCFragment *LastValid = LastValidFragment.lookup(&SD); + if (!LastValid) + return false; + assert(LastValid->getParent() == F->getParent()); + return F->getLayoutOrder() <= LastValid->getLayoutOrder(); } -void MCAsmLayout::UpdateForSlide(MCFragment *F, int SlideAmount) { +void MCAsmLayout::Invalidate(MCFragment *F) { // If this fragment wasn't already up-to-date, we don't need to do anything. if (!isFragmentUpToDate(F)) return; - // Otherwise, reset the last valid fragment to the predecessor of the - // invalidated fragment. - LastValidFragment = F->getPrevNode(); - if (!LastValidFragment) { - unsigned Index = F->getParent()->getLayoutOrder(); - if (Index != 0) { - MCSectionData *Prev = getSectionOrder()[Index - 1]; - LastValidFragment = &(Prev->getFragmentList().back()); - } - } + // Otherwise, reset the last valid fragment to this fragment. + const MCSectionData &SD = *F->getParent(); + LastValidFragment[&SD] = F; } void MCAsmLayout::EnsureValid(const MCFragment *F) const { + MCSectionData &SD = *F->getParent(); + + MCFragment *Cur = LastValidFragment[&SD]; + if (!Cur) + Cur = &*SD.begin(); + else + Cur = Cur->getNextNode(); + // Advance the layout position until the fragment is up-to-date. while (!isFragmentUpToDate(F)) { - // Advance to the next fragment. - MCFragment *Cur = LastValidFragment; - if (Cur) - Cur = Cur->getNextNode(); - if (!Cur) { - unsigned NextIndex = 0; - if (LastValidFragment) - NextIndex = LastValidFragment->getParent()->getLayoutOrder() + 1; - Cur = SectionOrder[NextIndex]->begin(); - } - const_cast(this)->LayoutFragment(Cur); + Cur = Cur->getNextNode(); } } -void MCAsmLayout::FragmentReplaced(MCFragment *Src, MCFragment *Dst) { - if (LastValidFragment == Src) - LastValidFragment = Dst; - - Dst->Offset = Src->Offset; - Dst->EffectiveSize = Src->EffectiveSize; -} - -uint64_t MCAsmLayout::getFragmentAddress(const MCFragment *F) const { - assert(F->getParent() && "Missing section()!"); - return getSectionAddress(F->getParent()) + getFragmentOffset(F); -} - -uint64_t MCAsmLayout::getFragmentEffectiveSize(const MCFragment *F) const { - EnsureValid(F); - assert(F->EffectiveSize != ~UINT64_C(0) && "Address not set!"); - return F->EffectiveSize; -} - uint64_t MCAsmLayout::getFragmentOffset(const MCFragment *F) const { EnsureValid(F); assert(F->Offset != ~UINT64_C(0) && "Address not set!"); return F->Offset; } -uint64_t MCAsmLayout::getSymbolAddress(const MCSymbolData *SD) const { - assert(SD->getFragment() && "Invalid getAddress() on undefined symbol!"); - return getFragmentAddress(SD->getFragment()) + SD->getOffset(); -} - -uint64_t MCAsmLayout::getSectionAddress(const MCSectionData *SD) const { - EnsureValid(SD->begin()); - assert(SD->Address != ~UINT64_C(0) && "Address not set!"); - return SD->Address; +uint64_t MCAsmLayout::getSymbolOffset(const MCSymbolData *SD) const { + assert(SD->getFragment() && "Invalid getOffset() on undefined symbol!"); + return getFragmentOffset(SD->getFragment()) + SD->getOffset(); } uint64_t MCAsmLayout::getSectionAddressSize(const MCSectionData *SD) const { // The size is the last fragment's end offset. const MCFragment &F = SD->getFragmentList().back(); - return getFragmentOffset(&F) + getFragmentEffectiveSize(&F); + return getFragmentOffset(&F) + getAssembler().ComputeFragmentSize(*this, F); } uint64_t MCAsmLayout::getSectionFileSize(const MCSectionData *SD) const { // Virtual sections have no file size. - if (getAssembler().getBackend().isVirtualSection(SD->getSection())) + if (SD->getSection().isVirtualSection()) return 0; // Otherwise, the file size is the same as the address space size. return getSectionAddressSize(SD); } -uint64_t MCAsmLayout::getSectionSize(const MCSectionData *SD) const { - // The logical size is the address space size minus any tail padding. - uint64_t Size = getSectionAddressSize(SD); - const MCAlignFragment *AF = - dyn_cast(&(SD->getFragmentList().back())); - if (AF && AF->hasOnlyAlignAddress()) - Size -= getFragmentEffectiveSize(AF); - - return Size; -} - /* *** */ MCFragment::MCFragment() : Kind(FragmentType(~0)) { @@ -182,8 +131,7 @@ MCFragment::~MCFragment() { } MCFragment::MCFragment(FragmentType _Kind, MCSectionData *_Parent) - : Kind(_Kind), Parent(_Parent), Atom(0), Offset(~UINT64_C(0)), - EffectiveSize(~UINT64_C(0)) + : Kind(_Kind), Parent(_Parent), Atom(0), Offset(~UINT64_C(0)) { if (Parent) Parent->getFragmentList().push_back(this); @@ -195,8 +143,8 @@ MCSectionData::MCSectionData() : Section(0) {} MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A) : Section(&_Section), + Ordinal(~UINT32_C(0)), Alignment(1), - Address(~UINT64_C(0)), HasInstructions(false) { if (A) @@ -220,99 +168,17 @@ MCSymbolData::MCSymbolData(const MCSymbol &_Symbol, MCFragment *_Fragment, /* *** */ -MCAssembler::MCAssembler(MCContext &_Context, TargetAsmBackend &_Backend, - MCCodeEmitter &_Emitter, raw_ostream &_OS) - : Context(_Context), Backend(_Backend), Emitter(_Emitter), - OS(_OS), RelaxAll(false), SubsectionsViaSymbols(false) +MCAssembler::MCAssembler(MCContext &Context_, TargetAsmBackend &Backend_, + MCCodeEmitter &Emitter_, MCObjectWriter &Writer_, + raw_ostream &OS_) + : Context(Context_), Backend(Backend_), Emitter(Emitter_), Writer(Writer_), + OS(OS_), RelaxAll(false), NoExecStack(false), SubsectionsViaSymbols(false) { } MCAssembler::~MCAssembler() { } -static bool isScatteredFixupFullyResolvedSimple(const MCAssembler &Asm, - const MCFixup &Fixup, - const MCValue Target, - const MCSection *BaseSection) { - // The effective fixup address is - // addr(atom(A)) + offset(A) - // - addr(atom(B)) - offset(B) - // - addr() + - // and the offsets are not relocatable, so the fixup is fully resolved when - // addr(atom(A)) - addr(atom(B)) - addr()) == 0. - // - // The simple (Darwin, except on x86_64) way of dealing with this was to - // assume that any reference to a temporary symbol *must* be a temporary - // symbol in the same atom, unless the sections differ. Therefore, any PCrel - // relocation to a temporary symbol (in the same section) is fully - // resolved. This also works in conjunction with absolutized .set, which - // requires the compiler to use .set to absolutize the differences between - // symbols which the compiler knows to be assembly time constants, so we don't - // need to worry about considering symbol differences fully resolved. - - // Non-relative fixups are only resolved if constant. - if (!BaseSection) - return Target.isAbsolute(); - - // Otherwise, relative fixups are only resolved if not a difference and the - // target is a temporary in the same section. - if (Target.isAbsolute() || Target.getSymB()) - return false; - - const MCSymbol *A = &Target.getSymA()->getSymbol(); - if (!A->isTemporary() || !A->isInSection() || - &A->getSection() != BaseSection) - return false; - - return true; -} - -static bool isScatteredFixupFullyResolved(const MCAssembler &Asm, - const MCAsmLayout &Layout, - const MCFixup &Fixup, - const MCValue Target, - const MCSymbolData *BaseSymbol) { - // The effective fixup address is - // addr(atom(A)) + offset(A) - // - addr(atom(B)) - offset(B) - // - addr(BaseSymbol) + - // and the offsets are not relocatable, so the fixup is fully resolved when - // addr(atom(A)) - addr(atom(B)) - addr(BaseSymbol) == 0. - // - // Note that "false" is almost always conservatively correct (it means we emit - // a relocation which is unnecessary), except when it would force us to emit a - // relocation which the target cannot encode. - - const MCSymbolData *A_Base = 0, *B_Base = 0; - if (const MCSymbolRefExpr *A = Target.getSymA()) { - // Modified symbol references cannot be resolved. - if (A->getKind() != MCSymbolRefExpr::VK_None) - return false; - - A_Base = Asm.getAtom(Layout, &Asm.getSymbolData(A->getSymbol())); - if (!A_Base) - return false; - } - - if (const MCSymbolRefExpr *B = Target.getSymB()) { - // Modified symbol references cannot be resolved. - if (B->getKind() != MCSymbolRefExpr::VK_None) - return false; - - B_Base = Asm.getAtom(Layout, &Asm.getSymbolData(B->getSymbol())); - if (!B_Base) - return false; - } - - // If there is no base, A and B have to be the same atom for this fixup to be - // fully resolved. - if (!BaseSymbol) - return A_Base == B_Base; - - // Otherwise, B must be missing and A must be the base. - return !B_Base && BaseSymbol == A_Base; -} - bool MCAssembler::isSymbolLinkerVisible(const MCSymbol &Symbol) const { // Non-temporary labels should always be visible to the linker. if (!Symbol.isTemporary()) @@ -326,8 +192,7 @@ bool MCAssembler::isSymbolLinkerVisible(const MCSymbol &Symbol) const { return getBackend().doesSectionRequireSymbols(Symbol.getSection()); } -const MCSymbolData *MCAssembler::getAtom(const MCAsmLayout &Layout, - const MCSymbolData *SD) const { +const MCSymbolData *MCAssembler::getAtom(const MCSymbolData *SD) const { // Linker visible symbols define atoms. if (isSymbolLinkerVisible(SD->getSymbol())) return SD; @@ -351,67 +216,78 @@ bool MCAssembler::EvaluateFixup(const MCAsmLayout &Layout, MCValue &Target, uint64_t &Value) const { ++stats::EvaluateFixup; - if (!Fixup.getValue()->EvaluateAsRelocatable(Target, &Layout)) + if (!Fixup.getValue()->EvaluateAsRelocatable(Target, Layout)) report_fatal_error("expected relocatable expression"); - // FIXME: How do non-scattered symbols work in ELF? I presume the linker - // doesn't support small relocations, but then under what criteria does the - // assembler allow symbol differences? + bool IsPCRel = Backend.getFixupKindInfo( + Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel; + + bool IsResolved; + if (IsPCRel) { + if (Target.getSymB()) { + IsResolved = false; + } else if (!Target.getSymA()) { + IsResolved = false; + } else { + const MCSymbolRefExpr *A = Target.getSymA(); + const MCSymbol &SA = A->getSymbol(); + if (A->getKind() != MCSymbolRefExpr::VK_None || + SA.AliasedSymbol().isUndefined()) { + IsResolved = false; + } else { + const MCSymbolData &DataA = getSymbolData(SA); + IsResolved = + getWriter().IsSymbolRefDifferenceFullyResolvedImpl(*this, DataA, + *DF, false, true); + } + } + } else { + IsResolved = Target.isAbsolute(); + } Value = Target.getConstant(); - bool IsPCRel = Emitter.getFixupKindInfo( - Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel; - bool IsResolved = true; + bool IsThumb = false; if (const MCSymbolRefExpr *A = Target.getSymA()) { - if (A->getSymbol().isDefined()) - Value += Layout.getSymbolAddress(&getSymbolData(A->getSymbol())); - else - IsResolved = false; + const MCSymbol &Sym = A->getSymbol().AliasedSymbol(); + if (Sym.isDefined()) + Value += Layout.getSymbolOffset(&getSymbolData(Sym)); + if (isThumbFunc(&Sym)) + IsThumb = true; } if (const MCSymbolRefExpr *B = Target.getSymB()) { - if (B->getSymbol().isDefined()) - Value -= Layout.getSymbolAddress(&getSymbolData(B->getSymbol())); - else - IsResolved = false; + const MCSymbol &Sym = B->getSymbol().AliasedSymbol(); + if (Sym.isDefined()) + Value -= Layout.getSymbolOffset(&getSymbolData(Sym)); } - // If we are using scattered symbols, determine whether this value is actually - // resolved; scattering may cause atoms to move. - if (IsResolved && getBackend().hasScatteredSymbols()) { - if (getBackend().hasReliableSymbolDifference()) { - // If this is a PCrel relocation, find the base atom (identified by its - // symbol) that the fixup value is relative to. - const MCSymbolData *BaseSymbol = 0; - if (IsPCRel) { - BaseSymbol = DF->getAtom(); - if (!BaseSymbol) - IsResolved = false; - } - if (IsResolved) - IsResolved = isScatteredFixupFullyResolved(*this, Layout, Fixup, Target, - BaseSymbol); - } else { - const MCSection *BaseSection = 0; - if (IsPCRel) - BaseSection = &DF->getParent()->getSection(); + bool ShouldAlignPC = Backend.getFixupKindInfo(Fixup.getKind()).Flags & + MCFixupKindInfo::FKF_IsAlignedDownTo32Bits; + assert((ShouldAlignPC ? IsPCRel : true) && + "FKF_IsAlignedDownTo32Bits is only allowed on PC-relative fixups!"); - IsResolved = isScatteredFixupFullyResolvedSimple(*this, Fixup, Target, - BaseSection); - } + if (IsPCRel) { + uint32_t Offset = Layout.getFragmentOffset(DF) + Fixup.getOffset(); + + // A number of ARM fixups in Thumb mode require that the effective PC + // address be determined as the 32-bit aligned version of the actual offset. + if (ShouldAlignPC) Offset &= ~0x3; + Value -= Offset; } - if (IsPCRel) - Value -= Layout.getFragmentAddress(DF) + Fixup.getOffset(); + // ARM fixups based from a thumb function address need to have the low + // bit set. The actual value is always at least 16-bit aligned, so the + // low bit is normally clear and available for use as an ISA flag for + // interworking. + if (IsThumb) + Value |= 1; return IsResolved; } -uint64_t MCAssembler::ComputeFragmentSize(MCAsmLayout &Layout, - const MCFragment &F, - uint64_t SectionAddress, - uint64_t FragmentOffset) const { +uint64_t MCAssembler::ComputeFragmentSize(const MCAsmLayout &Layout, + const MCFragment &F) const { switch (F.getKind()) { case MCFragment::FT_Data: return cast(F).getContents().size(); @@ -420,62 +296,48 @@ uint64_t MCAssembler::ComputeFragmentSize(MCAsmLayout &Layout, case MCFragment::FT_Inst: return cast(F).getInstSize(); + case MCFragment::FT_LEB: + return cast(F).getContents().size(); + case MCFragment::FT_Align: { const MCAlignFragment &AF = cast(F); - - assert((!AF.hasOnlyAlignAddress() || !AF.getNextNode()) && - "Invalid OnlyAlignAddress bit, not the last fragment!"); - - uint64_t Size = OffsetToAlignment(SectionAddress + FragmentOffset, - AF.getAlignment()); - - // Honor MaxBytesToEmit. + unsigned Offset = Layout.getFragmentOffset(&AF); + unsigned Size = OffsetToAlignment(Offset, AF.getAlignment()); if (Size > AF.getMaxBytesToEmit()) return 0; - return Size; } case MCFragment::FT_Org: { - const MCOrgFragment &OF = cast(F); - - // FIXME: We should compute this sooner, we don't want to recurse here, and - // we would like to be more functional. + MCOrgFragment &OF = cast(F); int64_t TargetLocation; - if (!OF.getOffset().EvaluateAsAbsolute(TargetLocation, &Layout)) + if (!OF.getOffset().EvaluateAsAbsolute(TargetLocation, Layout)) report_fatal_error("expected assembly-time absolute expression"); // FIXME: We need a way to communicate this error. - int64_t Offset = TargetLocation - FragmentOffset; - if (Offset < 0) + uint64_t FragmentOffset = Layout.getFragmentOffset(&OF); + int64_t Size = TargetLocation - FragmentOffset; + if (Size < 0 || Size >= 0x40000000) report_fatal_error("invalid .org offset '" + Twine(TargetLocation) + - "' (at offset '" + Twine(FragmentOffset) + "'"); - - return Offset; + "' (at offset '" + Twine(FragmentOffset) + "')"); + return Size; } + + case MCFragment::FT_Dwarf: + return cast(F).getContents().size(); + case MCFragment::FT_DwarfFrame: + return cast(F).getContents().size(); } assert(0 && "invalid fragment kind"); return 0; } -void MCAsmLayout::LayoutFile() { - // Initialize the first section and set the valid fragment layout point. All - // actual layout computations are done lazily. - LastValidFragment = 0; - if (!getSectionOrder().empty()) - getSectionOrder().front()->Address = 0; -} - void MCAsmLayout::LayoutFragment(MCFragment *F) { MCFragment *Prev = F->getPrevNode(); // We should never try to recompute something which is up-to-date. assert(!isFragmentUpToDate(F) && "Attempt to recompute up-to-date fragment!"); - // We should never try to compute the fragment layout if the section isn't - // up-to-date. - assert(isSectionUpToDate(F->getParent()) && - "Attempt to compute fragment before it's section!"); // We should never try to compute the fragment layout if it's predecessor // isn't up-to-date. assert((!Prev || isFragmentUpToDate(Prev)) && @@ -483,55 +345,26 @@ void MCAsmLayout::LayoutFragment(MCFragment *F) { ++stats::FragmentLayouts; - // Compute the fragment start address. - uint64_t StartAddress = F->getParent()->Address; - uint64_t Address = StartAddress; - if (Prev) - Address += Prev->Offset + Prev->EffectiveSize; - // Compute fragment offset and size. - F->Offset = Address - StartAddress; - F->EffectiveSize = getAssembler().ComputeFragmentSize(*this, *F, StartAddress, - F->Offset); - LastValidFragment = F; - - // If this is the last fragment in a section, update the next section address. - if (!F->getNextNode()) { - unsigned NextIndex = F->getParent()->getLayoutOrder() + 1; - if (NextIndex != getSectionOrder().size()) - LayoutSection(getSectionOrder()[NextIndex]); - } -} - -void MCAsmLayout::LayoutSection(MCSectionData *SD) { - unsigned SectionOrderIndex = SD->getLayoutOrder(); - - ++stats::SectionLayouts; - - // Compute the section start address. - uint64_t StartAddress = 0; - if (SectionOrderIndex) { - MCSectionData *Prev = getSectionOrder()[SectionOrderIndex - 1]; - StartAddress = getSectionAddress(Prev) + getSectionAddressSize(Prev); - } - - // Honor the section alignment requirements. - StartAddress = RoundUpToAlignment(StartAddress, SD->getAlignment()); + uint64_t Offset = 0; + if (Prev) + Offset += Prev->Offset + getAssembler().ComputeFragmentSize(*this, *Prev); - // Set the section address. - SD->Address = StartAddress; + F->Offset = Offset; + LastValidFragment[F->getParent()] = F; } /// WriteFragmentData - Write the \arg F data to the output file. static void WriteFragmentData(const MCAssembler &Asm, const MCAsmLayout &Layout, - const MCFragment &F, MCObjectWriter *OW) { + const MCFragment &F) { + MCObjectWriter *OW = &Asm.getWriter(); uint64_t Start = OW->getStream().tell(); (void) Start; ++stats::EmittedFragments; // FIXME: Embed in fragments instead? - uint64_t FragmentSize = Layout.getFragmentEffectiveSize(&F); + uint64_t FragmentSize = Asm.ComputeFragmentSize(Layout, F); switch (F.getKind()) { case MCFragment::FT_Align: { MCAlignFragment &AF = cast(F); @@ -598,9 +431,17 @@ static void WriteFragmentData(const MCAssembler &Asm, const MCAsmLayout &Layout, break; } - case MCFragment::FT_Inst: - llvm_unreachable("unexpected inst fragment after lowering"); + case MCFragment::FT_Inst: { + MCInstFragment &IF = cast(F); + OW->WriteBytes(StringRef(IF.getCode().begin(), IF.getCode().size())); + break; + } + + case MCFragment::FT_LEB: { + MCLEBFragment &LF = cast(F); + OW->WriteBytes(LF.getContents().str()); break; + } case MCFragment::FT_Org: { MCOrgFragment &OF = cast(F); @@ -610,16 +451,26 @@ static void WriteFragmentData(const MCAssembler &Asm, const MCAsmLayout &Layout, break; } + + case MCFragment::FT_Dwarf: { + const MCDwarfLineAddrFragment &OF = cast(F); + OW->WriteBytes(OF.getContents().str()); + break; + } + case MCFragment::FT_DwarfFrame: { + const MCDwarfCallFrameFragment &CF = cast(F); + OW->WriteBytes(CF.getContents().str()); + break; + } } assert(OW->getStream().tell() - Start == FragmentSize); } void MCAssembler::WriteSectionData(const MCSectionData *SD, - const MCAsmLayout &Layout, - MCObjectWriter *OW) const { + const MCAsmLayout &Layout) const { // Ignore virtual sections. - if (getBackend().isVirtualSection(SD->getSection())) { + if (SD->getSection().isVirtualSection()) { assert(Layout.getSectionFileSize(SD) == 0 && "Invalid size for section!"); // Check that contents are only things legal inside a virtual section. @@ -657,51 +508,34 @@ void MCAssembler::WriteSectionData(const MCSectionData *SD, return; } - uint64_t Start = OW->getStream().tell(); + uint64_t Start = getWriter().getStream().tell(); (void) Start; for (MCSectionData::const_iterator it = SD->begin(), ie = SD->end(); it != ie; ++it) - WriteFragmentData(*this, Layout, *it, OW); + WriteFragmentData(*this, Layout, *it); - assert(OW->getStream().tell() - Start == Layout.getSectionFileSize(SD)); + assert(getWriter().getStream().tell() - Start == + Layout.getSectionAddressSize(SD)); } -void MCAssembler::AddSectionToTheEnd(MCSectionData &SD, MCAsmLayout &Layout) { - // Create dummy fragments and assign section ordinals. - unsigned SectionIndex = 0; - for (MCAssembler::iterator it = begin(), ie = end(); it != ie; ++it) - SectionIndex++; - - SD.setOrdinal(SectionIndex); - - // Assign layout order indices to sections and fragments. - unsigned FragmentIndex = 0; - unsigned i = 0; - for (unsigned e = Layout.getSectionOrder().size(); i != e; ++i) { - MCSectionData *SD = Layout.getSectionOrder()[i]; - for (MCSectionData::iterator it2 = SD->begin(), - ie2 = SD->end(); it2 != ie2; ++it2) - FragmentIndex++; - } +uint64_t MCAssembler::HandleFixup(const MCAsmLayout &Layout, + MCFragment &F, + const MCFixup &Fixup) { + // Evaluate the fixup. + MCValue Target; + uint64_t FixedValue; + if (!EvaluateFixup(Layout, Fixup, &F, Target, FixedValue)) { + // The fixup was unresolved, we need a relocation. Inform the object + // writer of the relocation, and give it an opportunity to adjust the + // fixup value if need be. + getWriter().RecordRelocation(*this, Layout, &F, Fixup, Target, FixedValue); + } + return FixedValue; + } - SD.setLayoutOrder(i); - for (MCSectionData::iterator it2 = SD.begin(), - ie2 = SD.end(); it2 != ie2; ++it2) { - it2->setLayoutOrder(FragmentIndex++); - } - Layout.getSectionOrder().push_back(&SD); - - Layout.LayoutSection(&SD); - - // Layout until everything fits. - while (LayoutOnce(Layout)) - continue; - -} - -void MCAssembler::Finish(MCObjectWriter *Writer) { +void MCAssembler::Finish() { DEBUG_WITH_TYPE("mc-dump", { llvm::errs() << "assembler backend - pre-layout\n--\n"; dump(); }); @@ -709,47 +543,23 @@ void MCAssembler::Finish(MCObjectWriter *Writer) { // Create the layout object. MCAsmLayout Layout(*this); - // Insert additional align fragments for concrete sections to explicitly pad - // the previous section to match their alignment requirements. This is for - // 'gas' compatibility, it shouldn't strictly be necessary. - // - // FIXME: This may be Mach-O specific. - for (unsigned i = 1, e = Layout.getSectionOrder().size(); i < e; ++i) { - MCSectionData *SD = Layout.getSectionOrder()[i]; - - // Ignore sections without alignment requirements. - unsigned Align = SD->getAlignment(); - if (Align <= 1) - continue; - - // Ignore virtual sections, they don't cause file size modifications. - if (getBackend().isVirtualSection(SD->getSection())) - continue; - - // Otherwise, create a new align fragment at the end of the previous - // section. - MCAlignFragment *AF = new MCAlignFragment(Align, 0, 1, Align, - Layout.getSectionOrder()[i - 1]); - AF->setOnlyAlignAddress(true); - } - // Create dummy fragments and assign section ordinals. unsigned SectionIndex = 0; for (MCAssembler::iterator it = begin(), ie = end(); it != ie; ++it) { // Create dummy fragments to eliminate any empty sections, this simplifies // layout. if (it->getFragmentList().empty()) - new MCFillFragment(0, 1, 0, it); + new MCDataFragment(it); it->setOrdinal(SectionIndex++); } // Assign layout order indices to sections and fragments. - unsigned FragmentIndex = 0; for (unsigned i = 0, e = Layout.getSectionOrder().size(); i != e; ++i) { MCSectionData *SD = Layout.getSectionOrder()[i]; SD->setLayoutOrder(i); + unsigned FragmentIndex = 0; for (MCSectionData::iterator it2 = SD->begin(), ie2 = SD->end(); it2 != ie2; ++it2) it2->setLayoutOrder(FragmentIndex++); @@ -772,48 +582,39 @@ void MCAssembler::Finish(MCObjectWriter *Writer) { uint64_t StartOffset = OS.tell(); - llvm::OwningPtr OwnWriter(0); - if (Writer == 0) { - //no custom Writer_ : create the default one life-managed by OwningPtr - OwnWriter.reset(getBackend().createObjectWriter(OS)); - Writer = OwnWriter.get(); - if (!Writer) - report_fatal_error("unable to create object writer!"); - } - // Allow the object writer a chance to perform post-layout binding (for // example, to set the index fields in the symbol data). - Writer->ExecutePostLayoutBinding(*this); + getWriter().ExecutePostLayoutBinding(*this, Layout); // Evaluate and apply the fixups, generating relocation entries as necessary. for (MCAssembler::iterator it = begin(), ie = end(); it != ie; ++it) { for (MCSectionData::iterator it2 = it->begin(), ie2 = it->end(); it2 != ie2; ++it2) { MCDataFragment *DF = dyn_cast(it2); - if (!DF) - continue; - - for (MCDataFragment::fixup_iterator it3 = DF->fixup_begin(), - ie3 = DF->fixup_end(); it3 != ie3; ++it3) { - MCFixup &Fixup = *it3; - - // Evaluate the fixup. - MCValue Target; - uint64_t FixedValue; - if (!EvaluateFixup(Layout, Fixup, DF, Target, FixedValue)) { - // The fixup was unresolved, we need a relocation. Inform the object - // writer of the relocation, and give it an opportunity to adjust the - // fixup value if need be. - Writer->RecordRelocation(*this, Layout, DF, Fixup, Target,FixedValue); + if (DF) { + for (MCDataFragment::fixup_iterator it3 = DF->fixup_begin(), + ie3 = DF->fixup_end(); it3 != ie3; ++it3) { + MCFixup &Fixup = *it3; + uint64_t FixedValue = HandleFixup(Layout, *DF, Fixup); + getBackend().ApplyFixup(Fixup, DF->getContents().data(), + DF->getContents().size(), FixedValue); + } + } + MCInstFragment *IF = dyn_cast(it2); + if (IF) { + for (MCInstFragment::fixup_iterator it3 = IF->fixup_begin(), + ie3 = IF->fixup_end(); it3 != ie3; ++it3) { + MCFixup &Fixup = *it3; + uint64_t FixedValue = HandleFixup(Layout, *IF, Fixup); + getBackend().ApplyFixup(Fixup, IF->getCode().data(), + IF->getCode().size(), FixedValue); } - - getBackend().ApplyFixup(Fixup, *DF, FixedValue); } } } // Write the object file. - Writer->WriteObject(*this, Layout); + getWriter().WriteObject(*this, Layout); stats::ObjectBytes += OS.tell() - StartOffset; } @@ -852,100 +653,144 @@ bool MCAssembler::FragmentNeedsRelaxation(const MCInstFragment *IF, return false; } -bool MCAssembler::LayoutOnce(MCAsmLayout &Layout) { - ++stats::RelaxationSteps; +bool MCAssembler::RelaxInstruction(MCAsmLayout &Layout, + MCInstFragment &IF) { + if (!FragmentNeedsRelaxation(&IF, Layout)) + return false; - // Layout the sections in order. - Layout.LayoutFile(); + ++stats::RelaxedInstructions; + // FIXME-PERF: We could immediately lower out instructions if we can tell + // they are fully resolved, to avoid retesting on later passes. + + // Relax the fragment. + + MCInst Relaxed; + getBackend().RelaxInstruction(IF.getInst(), Relaxed); + + // Encode the new instruction. + // + // FIXME-PERF: If it matters, we could let the target do this. It can + // probably do so more efficiently in many cases. + SmallVector Fixups; + SmallString<256> Code; + raw_svector_ostream VecOS(Code); + getEmitter().EncodeInstruction(Relaxed, VecOS, Fixups); + VecOS.flush(); + + // Update the instruction fragment. + IF.setInst(Relaxed); + IF.getCode() = Code; + IF.getFixups().clear(); + // FIXME: Eliminate copy. + for (unsigned i = 0, e = Fixups.size(); i != e; ++i) + IF.getFixups().push_back(Fixups[i]); + + return true; +} + +bool MCAssembler::RelaxLEB(MCAsmLayout &Layout, MCLEBFragment &LF) { + int64_t Value = 0; + uint64_t OldSize = LF.getContents().size(); + LF.getValue().EvaluateAsAbsolute(Value, Layout); + SmallString<8> &Data = LF.getContents(); + Data.clear(); + raw_svector_ostream OSE(Data); + if (LF.isSigned()) + MCObjectWriter::EncodeSLEB128(Value, OSE); + else + MCObjectWriter::EncodeULEB128(Value, OSE); + OSE.flush(); + return OldSize != LF.getContents().size(); +} + +bool MCAssembler::RelaxDwarfLineAddr(MCAsmLayout &Layout, + MCDwarfLineAddrFragment &DF) { + int64_t AddrDelta = 0; + uint64_t OldSize = DF.getContents().size(); + bool IsAbs = DF.getAddrDelta().EvaluateAsAbsolute(AddrDelta, Layout); + (void)IsAbs; + assert(IsAbs); + int64_t LineDelta; + LineDelta = DF.getLineDelta(); + SmallString<8> &Data = DF.getContents(); + Data.clear(); + raw_svector_ostream OSE(Data); + MCDwarfLineAddr::Encode(LineDelta, AddrDelta, OSE); + OSE.flush(); + return OldSize != Data.size(); +} + +bool MCAssembler::RelaxDwarfCallFrameFragment(MCAsmLayout &Layout, + MCDwarfCallFrameFragment &DF) { + int64_t AddrDelta = 0; + uint64_t OldSize = DF.getContents().size(); + bool IsAbs = DF.getAddrDelta().EvaluateAsAbsolute(AddrDelta, Layout); + (void)IsAbs; + assert(IsAbs); + SmallString<8> &Data = DF.getContents(); + Data.clear(); + raw_svector_ostream OSE(Data); + MCDwarfFrameEmitter::EncodeAdvanceLoc(AddrDelta, OSE); + OSE.flush(); + return OldSize != Data.size(); +} + +bool MCAssembler::LayoutSectionOnce(MCAsmLayout &Layout, + MCSectionData &SD) { + MCFragment *FirstInvalidFragment = NULL; // Scan for fragments that need relaxation. + for (MCSectionData::iterator it2 = SD.begin(), + ie2 = SD.end(); it2 != ie2; ++it2) { + // Check if this is an fragment that needs relaxation. + bool relaxedFrag = false; + switch(it2->getKind()) { + default: + break; + case MCFragment::FT_Inst: + relaxedFrag = RelaxInstruction(Layout, *cast(it2)); + break; + case MCFragment::FT_Dwarf: + relaxedFrag = RelaxDwarfLineAddr(Layout, + *cast(it2)); + break; + case MCFragment::FT_DwarfFrame: + relaxedFrag = + RelaxDwarfCallFrameFragment(Layout, + *cast(it2)); + break; + case MCFragment::FT_LEB: + relaxedFrag = RelaxLEB(Layout, *cast(it2)); + break; + } + // Update the layout, and remember that we relaxed. + if (relaxedFrag && !FirstInvalidFragment) + FirstInvalidFragment = it2; + } + if (FirstInvalidFragment) { + Layout.Invalidate(FirstInvalidFragment); + return true; + } + return false; +} + +bool MCAssembler::LayoutOnce(MCAsmLayout &Layout) { + ++stats::RelaxationSteps; + bool WasRelaxed = false; for (iterator it = begin(), ie = end(); it != ie; ++it) { MCSectionData &SD = *it; - - for (MCSectionData::iterator it2 = SD.begin(), - ie2 = SD.end(); it2 != ie2; ++it2) { - // Check if this is an instruction fragment that needs relaxation. - MCInstFragment *IF = dyn_cast(it2); - if (!IF || !FragmentNeedsRelaxation(IF, Layout)) - continue; - - ++stats::RelaxedInstructions; - - // FIXME-PERF: We could immediately lower out instructions if we can tell - // they are fully resolved, to avoid retesting on later passes. - - // Relax the fragment. - - MCInst Relaxed; - getBackend().RelaxInstruction(IF->getInst(), Relaxed); - - // Encode the new instruction. - // - // FIXME-PERF: If it matters, we could let the target do this. It can - // probably do so more efficiently in many cases. - SmallVector Fixups; - SmallString<256> Code; - raw_svector_ostream VecOS(Code); - getEmitter().EncodeInstruction(Relaxed, VecOS, Fixups); - VecOS.flush(); - - // Update the instruction fragment. - int SlideAmount = Code.size() - IF->getInstSize(); - IF->setInst(Relaxed); - IF->getCode() = Code; - IF->getFixups().clear(); - // FIXME: Eliminate copy. - for (unsigned i = 0, e = Fixups.size(); i != e; ++i) - IF->getFixups().push_back(Fixups[i]); - - // Update the layout, and remember that we relaxed. - Layout.UpdateForSlide(IF, SlideAmount); + while(LayoutSectionOnce(Layout, SD)) WasRelaxed = true; - } } return WasRelaxed; } void MCAssembler::FinishLayout(MCAsmLayout &Layout) { - // Lower out any instruction fragments, to simplify the fixup application and - // output. - // - // FIXME-PERF: We don't have to do this, but the assumption is that it is - // cheap (we will mostly end up eliminating fragments and appending on to data - // fragments), so the extra complexity downstream isn't worth it. Evaluate - // this assumption. - for (iterator it = begin(), ie = end(); it != ie; ++it) { - MCSectionData &SD = *it; - - for (MCSectionData::iterator it2 = SD.begin(), - ie2 = SD.end(); it2 != ie2; ++it2) { - MCInstFragment *IF = dyn_cast(it2); - if (!IF) - continue; - - // Create a new data fragment for the instruction. - // - // FIXME-PERF: Reuse previous data fragment if possible. - MCDataFragment *DF = new MCDataFragment(); - SD.getFragmentList().insert(it2, DF); - - // Update the data fragments layout data. - DF->setParent(IF->getParent()); - DF->setAtom(IF->getAtom()); - DF->setLayoutOrder(IF->getLayoutOrder()); - Layout.FragmentReplaced(IF, DF); - - // Copy in the data and the fixups. - DF->getContents().append(IF->getCode().begin(), IF->getCode().end()); - for (unsigned i = 0, e = IF->getFixups().size(); i != e; ++i) - DF->getFixups().push_back(IF->getFixups()[i]); - - // Delete the instruction fragment and update the iterator. - SD.getFragmentList().erase(IF); - it2 = DF; - } + // The layout is done. Mark every fragment as valid. + for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) { + Layout.getFragmentOffset(&*Layout.getSectionOrder()[i]->rbegin()); } } @@ -972,18 +817,19 @@ void MCFragment::dump() { case MCFragment::FT_Fill: OS << "MCFillFragment"; break; case MCFragment::FT_Inst: OS << "MCInstFragment"; break; case MCFragment::FT_Org: OS << "MCOrgFragment"; break; + case MCFragment::FT_Dwarf: OS << "MCDwarfFragment"; break; + case MCFragment::FT_DwarfFrame: OS << "MCDwarfCallFrameFragment"; break; + case MCFragment::FT_LEB: OS << "MCLEBFragment"; break; } OS << ""; + << " Offset:" << Offset << ">"; switch (getKind()) { case MCFragment::FT_Align: { const MCAlignFragment *AF = cast(this); if (AF->hasEmitNops()) OS << " (emit nops)"; - if (AF->hasOnlyAlignAddress()) - OS << " (only align section)"; OS << "\n "; OS << " Alignment:" << AF->getAlignment() << " Value:" << AF->getValue() << " ValueSize:" << AF->getValueSize() @@ -1032,6 +878,25 @@ void MCFragment::dump() { OS << " Offset:" << OF->getOffset() << " Value:" << OF->getValue(); break; } + case MCFragment::FT_Dwarf: { + const MCDwarfLineAddrFragment *OF = cast(this); + OS << "\n "; + OS << " AddrDelta:" << OF->getAddrDelta() + << " LineDelta:" << OF->getLineDelta(); + break; + } + case MCFragment::FT_DwarfFrame: { + const MCDwarfCallFrameFragment *CF = cast(this); + OS << "\n "; + OS << " AddrDelta:" << CF->getAddrDelta(); + break; + } + case MCFragment::FT_LEB: { + const MCLEBFragment *LF = cast(this); + OS << "\n "; + OS << " Value:" << LF->getValue() << " Signed:" << LF->isSigned(); + break; + } } OS << ">"; } @@ -1040,8 +905,7 @@ void MCSectionData::dump() { raw_ostream &OS = llvm::errs(); OS << "dump(); diff --git a/lib/MC/MCCodeEmitter.cpp b/lib/MC/MCCodeEmitter.cpp index d51323785541..c122763b2fe5 100644 --- a/lib/MC/MCCodeEmitter.cpp +++ b/lib/MC/MCCodeEmitter.cpp @@ -16,15 +16,3 @@ MCCodeEmitter::MCCodeEmitter() { MCCodeEmitter::~MCCodeEmitter() { } - -const MCFixupKindInfo &MCCodeEmitter::getFixupKindInfo(MCFixupKind Kind) const { - static const MCFixupKindInfo Builtins[] = { - { "FK_Data_1", 0, 8, 0 }, - { "FK_Data_2", 0, 16, 0 }, - { "FK_Data_4", 0, 32, 0 }, - { "FK_Data_8", 0, 64, 0 } - }; - - assert(Kind <= 3 && "Unknown fixup kind"); - return Builtins[Kind]; -} diff --git a/lib/MC/MCContext.cpp b/lib/MC/MCContext.cpp index e5586a0d7c31..018f00c08f6f 100644 --- a/lib/MC/MCContext.cpp +++ b/lib/MC/MCContext.cpp @@ -15,8 +15,10 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCLabel.h" #include "llvm/MC/MCDwarf.h" +#include "llvm/Target/TargetAsmInfo.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/ELF.h" using namespace llvm; typedef StringMap MachOUniqueMapTy; @@ -24,8 +26,9 @@ typedef StringMap ELFUniqueMapTy; typedef StringMap COFFUniqueMapTy; -MCContext::MCContext(const MCAsmInfo &mai) : MAI(mai), NextUniqueID(0), - CurrentDwarfLoc(0,0,0,0,0) { +MCContext::MCContext(const MCAsmInfo &mai, const TargetAsmInfo *tai) : + MAI(mai), TAI(tai), NextUniqueID(0), + CurrentDwarfLoc(0,0,0,DWARF2_FLAG_IS_STMT,0,0) { MachOUniquingMap = 0; ELFUniquingMap = 0; COFFUniquingMap = 0; @@ -40,7 +43,7 @@ MCContext::MCContext(const MCAsmInfo &mai) : MAI(mai), NextUniqueID(0), MCContext::~MCContext() { // NOTE: The symbols are all allocated out of a bump pointer allocator, // we don't need to free them here. - + // If we have the MachO uniquing map, free it. delete (MachOUniqueMapTy*)MachOUniquingMap; delete (ELFUniqueMapTy*)ELFUniquingMap; @@ -48,6 +51,8 @@ MCContext::~MCContext() { // If the stream for the .secure_log_unique directive was created free it. delete (raw_ostream*)SecureLog; + + delete TAI; } //===----------------------------------------------------------------------===// @@ -56,20 +61,42 @@ MCContext::~MCContext() { MCSymbol *MCContext::GetOrCreateSymbol(StringRef Name) { assert(!Name.empty() && "Normal symbols cannot be unnamed!"); - - // Determine whether this is an assembler temporary or normal label. - bool isTemporary = Name.startswith(MAI.getPrivateGlobalPrefix()); - + // Do the lookup and get the entire StringMapEntry. We want access to the // key if we are creating the entry. StringMapEntry &Entry = Symbols.GetOrCreateValue(Name); - if (Entry.getValue()) return Entry.getValue(); + MCSymbol *Sym = Entry.getValue(); + + if (Sym) + return Sym; + + Sym = CreateSymbol(Name); + Entry.setValue(Sym); + return Sym; +} + +MCSymbol *MCContext::CreateSymbol(StringRef Name) { + // Determine whether this is an assembler temporary or normal label. + bool isTemporary = Name.startswith(MAI.getPrivateGlobalPrefix()); + + StringMapEntry *NameEntry = &UsedNames.GetOrCreateValue(Name); + if (NameEntry->getValue()) { + assert(isTemporary && "Cannot rename non temporary symbols"); + SmallString<128> NewName; + do { + Twine T = Name + Twine(NextUniqueID++); + T.toVector(NewName); + StringRef foo = NewName; + NameEntry = &UsedNames.GetOrCreateValue(foo); + } while (NameEntry->getValue()); + } + NameEntry->setValue(true); // Ok, the entry doesn't already exist. Have the MCSymbol object itself refer - // to the copy of the string that is embedded in the StringMapEntry. - MCSymbol *Result = new (*this) MCSymbol(Entry.getKey(), isTemporary); - Entry.setValue(Result); - return Result; + // to the copy of the string that is embedded in the UsedNames entry. + MCSymbol *Result = new (*this) MCSymbol(NameEntry->getKey(), isTemporary); + + return Result; } MCSymbol *MCContext::GetOrCreateSymbol(const Twine &Name) { @@ -79,8 +106,11 @@ MCSymbol *MCContext::GetOrCreateSymbol(const Twine &Name) { } MCSymbol *MCContext::CreateTempSymbol() { - return GetOrCreateSymbol(Twine(MAI.getPrivateGlobalPrefix()) + - "tmp" + Twine(NextUniqueID++)); + SmallString<128> NameSV; + Twine Name = Twine(MAI.getPrivateGlobalPrefix()) + "tmp" + + Twine(NextUniqueID++); + Name.toVector(NameSV); + return CreateSymbol(NameSV); } unsigned MCContext::NextInstance(int64_t LocalLabelVal) { @@ -123,49 +153,70 @@ const MCSectionMachO *MCContext:: getMachOSection(StringRef Segment, StringRef Section, unsigned TypeAndAttributes, unsigned Reserved2, SectionKind Kind) { - + // We unique sections by their segment/section pair. The returned section // may not have the same flags as the requested section, if so this should be // diagnosed by the client as an error. - + // Create the map if it doesn't already exist. if (MachOUniquingMap == 0) MachOUniquingMap = new MachOUniqueMapTy(); MachOUniqueMapTy &Map = *(MachOUniqueMapTy*)MachOUniquingMap; - + // Form the name to look up. SmallString<64> Name; Name += Segment; Name.push_back(','); Name += Section; - + // Do the lookup, if we have a hit, return it. const MCSectionMachO *&Entry = Map[Name.str()]; if (Entry) return Entry; - + // Otherwise, return a new section. return Entry = new (*this) MCSectionMachO(Segment, Section, TypeAndAttributes, Reserved2, Kind); } +const MCSectionELF *MCContext:: +getELFSection(StringRef Section, unsigned Type, unsigned Flags, + SectionKind Kind) { + return getELFSection(Section, Type, Flags, Kind, 0, ""); +} -const MCSection *MCContext:: +const MCSectionELF *MCContext:: getELFSection(StringRef Section, unsigned Type, unsigned Flags, - SectionKind Kind, bool IsExplicit, unsigned EntrySize) { + SectionKind Kind, unsigned EntrySize, StringRef Group) { if (ELFUniquingMap == 0) ELFUniquingMap = new ELFUniqueMapTy(); ELFUniqueMapTy &Map = *(ELFUniqueMapTy*)ELFUniquingMap; - + // Do the lookup, if we have a hit, return it. StringMapEntry &Entry = Map.GetOrCreateValue(Section); if (Entry.getValue()) return Entry.getValue(); - + + // Possibly refine the entry size first. + if (!EntrySize) { + EntrySize = MCSectionELF::DetermineEntrySize(Kind); + } + + MCSymbol *GroupSym = NULL; + if (!Group.empty()) + GroupSym = GetOrCreateSymbol(Group); + MCSectionELF *Result = new (*this) MCSectionELF(Entry.getKey(), Type, Flags, - Kind, IsExplicit, EntrySize); + Kind, EntrySize, GroupSym); Entry.setValue(Result); return Result; } +const MCSectionELF *MCContext::CreateELFGroupSection() { + MCSectionELF *Result = + new (*this) MCSectionELF(".group", ELF::SHT_GROUP, 0, + SectionKind::getReadOnly(), 4, NULL); + return Result; +} + const MCSection *MCContext::getCOFFSection(StringRef Section, unsigned Characteristics, int Selection, @@ -173,15 +224,15 @@ const MCSection *MCContext::getCOFFSection(StringRef Section, if (COFFUniquingMap == 0) COFFUniquingMap = new COFFUniqueMapTy(); COFFUniqueMapTy &Map = *(COFFUniqueMapTy*)COFFUniquingMap; - + // Do the lookup, if we have a hit, return it. StringMapEntry &Entry = Map.GetOrCreateValue(Section); if (Entry.getValue()) return Entry.getValue(); - + MCSectionCOFF *Result = new (*this) MCSectionCOFF(Entry.getKey(), Characteristics, Selection, Kind); - + Entry.setValue(Result); return Result; } @@ -240,7 +291,7 @@ unsigned MCContext::GetDwarfFile(StringRef FileName, unsigned FileNumber) { // stored at MCDwarfFiles[FileNumber].Name . DirIndex++; } - + // Now make the MCDwarfFile entry and place it in the slot in the MCDwarfFiles // vector. char *Buf = static_cast(Allocate(Name.size())); @@ -251,15 +302,11 @@ unsigned MCContext::GetDwarfFile(StringRef FileName, unsigned FileNumber) { return FileNumber; } -/// ValidateDwarfFileNumber - takes a dwarf file number and returns true if it +/// isValidDwarfFileNumber - takes a dwarf file number and returns true if it /// currently is assigned and false otherwise. -bool MCContext::ValidateDwarfFileNumber(unsigned FileNumber) { +bool MCContext::isValidDwarfFileNumber(unsigned FileNumber) { if(FileNumber == 0 || FileNumber >= MCDwarfFiles.size()) return false; - MCDwarfFile *&ExistingFile = MCDwarfFiles[FileNumber]; - if (ExistingFile) - return true; - else - return false; + return MCDwarfFiles[FileNumber] != 0; } diff --git a/lib/MC/MCDisassembler/EDDisassembler.cpp b/lib/MC/MCDisassembler/EDDisassembler.cpp index 697b3d9c0515..2fd14db2a45d 100644 --- a/lib/MC/MCDisassembler/EDDisassembler.cpp +++ b/lib/MC/MCDisassembler/EDDisassembler.cpp @@ -354,7 +354,7 @@ int EDDisassembler::parseInst(SmallVectorImpl &operands, SourceMgr sourceMgr; sourceMgr.AddNewSourceBuffer(buf, SMLoc()); // ownership of buf handed over - MCContext context(*AsmInfo); + MCContext context(*AsmInfo, NULL); OwningPtr streamer(createNullStreamer(context)); OwningPtr genericParser(createMCAsmParser(*Tgt, sourceMgr, context, *streamer, diff --git a/lib/MC/MCDisassembler/EDDisassembler.h b/lib/MC/MCDisassembler/EDDisassembler.h index e2f850bcdba9..71e45f0b042f 100644 --- a/lib/MC/MCDisassembler/EDDisassembler.h +++ b/lib/MC/MCDisassembler/EDDisassembler.h @@ -21,7 +21,7 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Mutex.h" +#include "llvm/Support/Mutex.h" #include #include @@ -89,8 +89,10 @@ struct EDDisassembler { bool operator<(const CPUKey &key) const { if(Arch > key.Arch) return false; - if(Syntax >= key.Syntax) - return false; + else if (Arch == key.Arch) { + if(Syntax > key.Syntax) + return false; + } return true; } }; diff --git a/lib/MC/MCDisassembler/EDInst.cpp b/lib/MC/MCDisassembler/EDInst.cpp index e22408f060b1..63b049fe40fd 100644 --- a/lib/MC/MCDisassembler/EDInst.cpp +++ b/lib/MC/MCDisassembler/EDInst.cpp @@ -62,6 +62,8 @@ int EDInst::stringify() { if (Disassembler.printInst(String, *Inst)) return StringifyResult.setResult(-1); + + String.push_back('\n'); return StringifyResult.setResult(0); } diff --git a/lib/MC/MCDisassembler/EDInst.h b/lib/MC/MCDisassembler/EDInst.h index 39d264fb7aad..ceb9505028de 100644 --- a/lib/MC/MCDisassembler/EDInst.h +++ b/lib/MC/MCDisassembler/EDInst.h @@ -16,7 +16,7 @@ #ifndef LLVM_EDINST_H #define LLVM_EDINST_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/ADT/SmallVector.h" #include #include diff --git a/lib/MC/MCDisassembler/EDOperand.cpp b/lib/MC/MCDisassembler/EDOperand.cpp index 2aed123368da..cfeb56fa3dfd 100644 --- a/lib/MC/MCDisassembler/EDOperand.cpp +++ b/lib/MC/MCDisassembler/EDOperand.cpp @@ -260,23 +260,20 @@ int EDOperand::isMemory() { } #ifdef __BLOCKS__ -struct RegisterReaderWrapper { - EDOperand::EDRegisterBlock_t regBlock; -}; +namespace { + struct RegisterReaderWrapper { + EDOperand::EDRegisterBlock_t regBlock; + }; +} -int readerWrapperCallback(uint64_t *value, - unsigned regID, - void *arg) { - struct RegisterReaderWrapper *wrapper = (struct RegisterReaderWrapper *)arg; +static int readerWrapperCallback(uint64_t *value, unsigned regID, void *arg) { + RegisterReaderWrapper *wrapper = (RegisterReaderWrapper *)arg; return wrapper->regBlock(value, regID); } -int EDOperand::evaluate(uint64_t &result, - EDRegisterBlock_t regBlock) { - struct RegisterReaderWrapper wrapper; +int EDOperand::evaluate(uint64_t &result, EDRegisterBlock_t regBlock) { + RegisterReaderWrapper wrapper; wrapper.regBlock = regBlock; - return evaluate(result, - readerWrapperCallback, - (void*)&wrapper); + return evaluate(result, readerWrapperCallback, (void*)&wrapper); } #endif diff --git a/lib/MC/MCDisassembler/EDOperand.h b/lib/MC/MCDisassembler/EDOperand.h index 6e695224318c..50260ec965a6 100644 --- a/lib/MC/MCDisassembler/EDOperand.h +++ b/lib/MC/MCDisassembler/EDOperand.h @@ -16,7 +16,7 @@ #ifndef LLVM_EDOPERAND_H #define LLVM_EDOPERAND_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { diff --git a/lib/MC/MCDisassembler/EDToken.h b/lib/MC/MCDisassembler/EDToken.h index 6b2aeac60ba5..ba467078686a 100644 --- a/lib/MC/MCDisassembler/EDToken.h +++ b/lib/MC/MCDisassembler/EDToken.h @@ -17,7 +17,7 @@ #define LLVM_EDTOKEN_H #include "llvm/ADT/StringRef.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include #include diff --git a/lib/MC/MCDwarf.cpp b/lib/MC/MCDwarf.cpp index 2da71f96c676..112d7d887a2d 100644 --- a/lib/MC/MCDwarf.cpp +++ b/lib/MC/MCDwarf.cpp @@ -7,11 +7,420 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/FoldingSet.h" +#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCDwarf.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/ADT/SmallString.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetAsmBackend.h" +#include "llvm/Target/TargetAsmInfo.h" using namespace llvm; +// Given a special op, return the address skip amount (in units of +// DWARF2_LINE_MIN_INSN_LENGTH. +#define SPECIAL_ADDR(op) (((op) - DWARF2_LINE_OPCODE_BASE)/DWARF2_LINE_RANGE) + +// The maximum address skip amount that can be encoded with a special op. +#define MAX_SPECIAL_ADDR_DELTA SPECIAL_ADDR(255) + +// First special line opcode - leave room for the standard opcodes. +// Note: If you want to change this, you'll have to update the +// "standard_opcode_lengths" table that is emitted in DwarfFileTable::Emit(). +#define DWARF2_LINE_OPCODE_BASE 13 + +// Minimum line offset in a special line info. opcode. This value +// was chosen to give a reasonable range of values. +#define DWARF2_LINE_BASE -5 + +// Range of line offsets in a special line info. opcode. +# define DWARF2_LINE_RANGE 14 + +// Define the architecture-dependent minimum instruction length (in bytes). +// This value should be rather too small than too big. +# define DWARF2_LINE_MIN_INSN_LENGTH 1 + +// Note: when DWARF2_LINE_MIN_INSN_LENGTH == 1 which is the current setting, +// this routine is a nop and will be optimized away. +static inline uint64_t ScaleAddrDelta(uint64_t AddrDelta) +{ + if (DWARF2_LINE_MIN_INSN_LENGTH == 1) + return AddrDelta; + if (AddrDelta % DWARF2_LINE_MIN_INSN_LENGTH != 0) { + // TODO: report this error, but really only once. + ; + } + return AddrDelta / DWARF2_LINE_MIN_INSN_LENGTH; +} + +// +// This is called when an instruction is assembled into the specified section +// and if there is information from the last .loc directive that has yet to have +// a line entry made for it is made. +// +void MCLineEntry::Make(MCStreamer *MCOS, const MCSection *Section) { + if (!MCOS->getContext().getDwarfLocSeen()) + return; + + // Create a symbol at in the current section for use in the line entry. + MCSymbol *LineSym = MCOS->getContext().CreateTempSymbol(); + // Set the value of the symbol to use for the MCLineEntry. + MCOS->EmitLabel(LineSym); + + // Get the current .loc info saved in the context. + const MCDwarfLoc &DwarfLoc = MCOS->getContext().getCurrentDwarfLoc(); + + // Create a (local) line entry with the symbol and the current .loc info. + MCLineEntry LineEntry(LineSym, DwarfLoc); + + // clear DwarfLocSeen saying the current .loc info is now used. + MCOS->getContext().ClearDwarfLocSeen(); + + // Get the MCLineSection for this section, if one does not exist for this + // section create it. + const DenseMap &MCLineSections = + MCOS->getContext().getMCLineSections(); + MCLineSection *LineSection = MCLineSections.lookup(Section); + if (!LineSection) { + // Create a new MCLineSection. This will be deleted after the dwarf line + // table is created using it by iterating through the MCLineSections + // DenseMap. + LineSection = new MCLineSection; + // Save a pointer to the new LineSection into the MCLineSections DenseMap. + MCOS->getContext().addMCLineSection(Section, LineSection); + } + + // Add the line entry to this section's entries. + LineSection->addLineEntry(LineEntry); +} + +// +// This helper routine returns an expression of End - Start + IntVal . +// +static inline const MCExpr *MakeStartMinusEndExpr(const MCStreamer &MCOS, + const MCSymbol &Start, + const MCSymbol &End, + int IntVal) { + MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; + const MCExpr *Res = + MCSymbolRefExpr::Create(&End, Variant, MCOS.getContext()); + const MCExpr *RHS = + MCSymbolRefExpr::Create(&Start, Variant, MCOS.getContext()); + const MCExpr *Res1 = + MCBinaryExpr::Create(MCBinaryExpr::Sub, Res, RHS, MCOS.getContext()); + const MCExpr *Res2 = + MCConstantExpr::Create(IntVal, MCOS.getContext()); + const MCExpr *Res3 = + MCBinaryExpr::Create(MCBinaryExpr::Sub, Res1, Res2, MCOS.getContext()); + return Res3; +} + +// +// This emits the Dwarf line table for the specified section from the entries +// in the LineSection. +// +static inline void EmitDwarfLineTable(MCStreamer *MCOS, + const MCSection *Section, + const MCLineSection *LineSection) { + unsigned FileNum = 1; + unsigned LastLine = 1; + unsigned Column = 0; + unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0; + unsigned Isa = 0; + MCSymbol *LastLabel = NULL; + + // Loop through each MCLineEntry and encode the dwarf line number table. + for (MCLineSection::const_iterator + it = LineSection->getMCLineEntries()->begin(), + ie = LineSection->getMCLineEntries()->end(); it != ie; ++it) { + + if (FileNum != it->getFileNum()) { + FileNum = it->getFileNum(); + MCOS->EmitIntValue(dwarf::DW_LNS_set_file, 1); + MCOS->EmitULEB128IntValue(FileNum); + } + if (Column != it->getColumn()) { + Column = it->getColumn(); + MCOS->EmitIntValue(dwarf::DW_LNS_set_column, 1); + MCOS->EmitULEB128IntValue(Column); + } + if (Isa != it->getIsa()) { + Isa = it->getIsa(); + MCOS->EmitIntValue(dwarf::DW_LNS_set_isa, 1); + MCOS->EmitULEB128IntValue(Isa); + } + if ((it->getFlags() ^ Flags) & DWARF2_FLAG_IS_STMT) { + Flags = it->getFlags(); + MCOS->EmitIntValue(dwarf::DW_LNS_negate_stmt, 1); + } + if (it->getFlags() & DWARF2_FLAG_BASIC_BLOCK) + MCOS->EmitIntValue(dwarf::DW_LNS_set_basic_block, 1); + if (it->getFlags() & DWARF2_FLAG_PROLOGUE_END) + MCOS->EmitIntValue(dwarf::DW_LNS_set_prologue_end, 1); + if (it->getFlags() & DWARF2_FLAG_EPILOGUE_BEGIN) + MCOS->EmitIntValue(dwarf::DW_LNS_set_epilogue_begin, 1); + + int64_t LineDelta = static_cast(it->getLine()) - LastLine; + MCSymbol *Label = it->getLabel(); + + // At this point we want to emit/create the sequence to encode the delta in + // line numbers and the increment of the address from the previous Label + // and the current Label. + MCOS->EmitDwarfAdvanceLineAddr(LineDelta, LastLabel, Label); + + LastLine = it->getLine(); + LastLabel = Label; + } + + // Emit a DW_LNE_end_sequence for the end of the section. + // Using the pointer Section create a temporary label at the end of the + // section and use that and the LastLabel to compute the address delta + // and use INT64_MAX as the line delta which is the signal that this is + // actually a DW_LNE_end_sequence. + + // Switch to the section to be able to create a symbol at its end. + MCOS->SwitchSection(Section); + + MCContext &context = MCOS->getContext(); + // Create a symbol at the end of the section. + MCSymbol *SectionEnd = context.CreateTempSymbol(); + // Set the value of the symbol, as we are at the end of the section. + MCOS->EmitLabel(SectionEnd); + + // Switch back the the dwarf line section. + MCOS->SwitchSection(context.getTargetAsmInfo().getDwarfLineSection()); + + MCOS->EmitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, SectionEnd); +} + +// +// This emits the Dwarf file and the line tables. +// +void MCDwarfFileTable::Emit(MCStreamer *MCOS) { + MCContext &context = MCOS->getContext(); + // Switch to the section where the table will be emitted into. + MCOS->SwitchSection(context.getTargetAsmInfo().getDwarfLineSection()); + + // Create a symbol at the beginning of this section. + MCSymbol *LineStartSym = context.CreateTempSymbol(); + // Set the value of the symbol, as we are at the start of the section. + MCOS->EmitLabel(LineStartSym); + + // Create a symbol for the end of the section (to be set when we get there). + MCSymbol *LineEndSym = context.CreateTempSymbol(); + + // The first 4 bytes is the total length of the information for this + // compilation unit (not including these 4 bytes for the length). + MCOS->EmitAbsValue(MakeStartMinusEndExpr(*MCOS, *LineStartSym, *LineEndSym,4), + 4); + + // Next 2 bytes is the Version, which is Dwarf 2. + MCOS->EmitIntValue(2, 2); + + // Create a symbol for the end of the prologue (to be set when we get there). + MCSymbol *ProEndSym = context.CreateTempSymbol(); // Lprologue_end + + // Length of the prologue, is the next 4 bytes. Which is the start of the + // section to the end of the prologue. Not including the 4 bytes for the + // total length, the 2 bytes for the version, and these 4 bytes for the + // length of the prologue. + MCOS->EmitAbsValue(MakeStartMinusEndExpr(*MCOS, *LineStartSym, *ProEndSym, + (4 + 2 + 4)), + 4, 0); + + // Parameters of the state machine, are next. + MCOS->EmitIntValue(DWARF2_LINE_MIN_INSN_LENGTH, 1); + MCOS->EmitIntValue(DWARF2_LINE_DEFAULT_IS_STMT, 1); + MCOS->EmitIntValue(DWARF2_LINE_BASE, 1); + MCOS->EmitIntValue(DWARF2_LINE_RANGE, 1); + MCOS->EmitIntValue(DWARF2_LINE_OPCODE_BASE, 1); + + // Standard opcode lengths + MCOS->EmitIntValue(0, 1); // length of DW_LNS_copy + MCOS->EmitIntValue(1, 1); // length of DW_LNS_advance_pc + MCOS->EmitIntValue(1, 1); // length of DW_LNS_advance_line + MCOS->EmitIntValue(1, 1); // length of DW_LNS_set_file + MCOS->EmitIntValue(1, 1); // length of DW_LNS_set_column + MCOS->EmitIntValue(0, 1); // length of DW_LNS_negate_stmt + MCOS->EmitIntValue(0, 1); // length of DW_LNS_set_basic_block + MCOS->EmitIntValue(0, 1); // length of DW_LNS_const_add_pc + MCOS->EmitIntValue(1, 1); // length of DW_LNS_fixed_advance_pc + MCOS->EmitIntValue(0, 1); // length of DW_LNS_set_prologue_end + MCOS->EmitIntValue(0, 1); // length of DW_LNS_set_epilogue_begin + MCOS->EmitIntValue(1, 1); // DW_LNS_set_isa + + // Put out the directory and file tables. + + // First the directory table. + const std::vector &MCDwarfDirs = + context.getMCDwarfDirs(); + for (unsigned i = 0; i < MCDwarfDirs.size(); i++) { + MCOS->EmitBytes(MCDwarfDirs[i], 0); // the DirectoryName + MCOS->EmitBytes(StringRef("\0", 1), 0); // the null term. of the string + } + MCOS->EmitIntValue(0, 1); // Terminate the directory list + + // Second the file table. + const std::vector &MCDwarfFiles = + MCOS->getContext().getMCDwarfFiles(); + for (unsigned i = 1; i < MCDwarfFiles.size(); i++) { + MCOS->EmitBytes(MCDwarfFiles[i]->getName(), 0); // FileName + MCOS->EmitBytes(StringRef("\0", 1), 0); // the null term. of the string + // the Directory num + MCOS->EmitULEB128IntValue(MCDwarfFiles[i]->getDirIndex()); + MCOS->EmitIntValue(0, 1); // last modification timestamp (always 0) + MCOS->EmitIntValue(0, 1); // filesize (always 0) + } + MCOS->EmitIntValue(0, 1); // Terminate the file list + + // This is the end of the prologue, so set the value of the symbol at the + // end of the prologue (that was used in a previous expression). + MCOS->EmitLabel(ProEndSym); + + // Put out the line tables. + const DenseMap &MCLineSections = + MCOS->getContext().getMCLineSections(); + const std::vector &MCLineSectionOrder = + MCOS->getContext().getMCLineSectionOrder(); + for (std::vector::const_iterator it = + MCLineSectionOrder.begin(), ie = MCLineSectionOrder.end(); it != ie; + ++it) { + const MCSection *Sec = *it; + const MCLineSection *Line = MCLineSections.lookup(Sec); + EmitDwarfLineTable(MCOS, Sec, Line); + + // Now delete the MCLineSections that were created in MCLineEntry::Make() + // and used to emit the line table. + delete Line; + } + + if (MCOS->getContext().getAsmInfo().getLinkerRequiresNonEmptyDwarfLines() + && MCLineSectionOrder.begin() == MCLineSectionOrder.end()) { + // The darwin9 linker has a bug (see PR8715). For for 32-bit architectures + // it requires: + // total_length >= prologue_length + 10 + // We are 4 bytes short, since we have total_length = 51 and + // prologue_length = 45 + + // The regular end_sequence should be sufficient. + MCDwarfLineAddr::Emit(MCOS, INT64_MAX, 0); + } + + // This is the end of the section, so set the value of the symbol at the end + // of this section (that was used in a previous expression). + MCOS->EmitLabel(LineEndSym); +} + +/// Utility function to write the encoding to an object writer. +void MCDwarfLineAddr::Write(MCObjectWriter *OW, int64_t LineDelta, + uint64_t AddrDelta) { + SmallString<256> Tmp; + raw_svector_ostream OS(Tmp); + MCDwarfLineAddr::Encode(LineDelta, AddrDelta, OS); + OW->WriteBytes(OS.str()); +} + +/// Utility function to emit the encoding to a streamer. +void MCDwarfLineAddr::Emit(MCStreamer *MCOS, int64_t LineDelta, + uint64_t AddrDelta) { + SmallString<256> Tmp; + raw_svector_ostream OS(Tmp); + MCDwarfLineAddr::Encode(LineDelta, AddrDelta, OS); + MCOS->EmitBytes(OS.str(), /*AddrSpace=*/0); +} + +/// Utility function to encode a Dwarf pair of LineDelta and AddrDeltas. +void MCDwarfLineAddr::Encode(int64_t LineDelta, uint64_t AddrDelta, + raw_ostream &OS) { + uint64_t Temp, Opcode; + bool NeedCopy = false; + + // Scale the address delta by the minimum instruction length. + AddrDelta = ScaleAddrDelta(AddrDelta); + + // A LineDelta of INT64_MAX is a signal that this is actually a + // DW_LNE_end_sequence. We cannot use special opcodes here, since we want the + // end_sequence to emit the matrix entry. + if (LineDelta == INT64_MAX) { + if (AddrDelta == MAX_SPECIAL_ADDR_DELTA) + OS << char(dwarf::DW_LNS_const_add_pc); + else { + OS << char(dwarf::DW_LNS_advance_pc); + SmallString<32> Tmp; + raw_svector_ostream OSE(Tmp); + MCObjectWriter::EncodeULEB128(AddrDelta, OSE); + OS << OSE.str(); + } + OS << char(dwarf::DW_LNS_extended_op); + OS << char(1); + OS << char(dwarf::DW_LNE_end_sequence); + return; + } + + // Bias the line delta by the base. + Temp = LineDelta - DWARF2_LINE_BASE; + + // If the line increment is out of range of a special opcode, we must encode + // it with DW_LNS_advance_line. + if (Temp >= DWARF2_LINE_RANGE) { + OS << char(dwarf::DW_LNS_advance_line); + SmallString<32> Tmp; + raw_svector_ostream OSE(Tmp); + MCObjectWriter::EncodeSLEB128(LineDelta, OSE); + OS << OSE.str(); + + LineDelta = 0; + Temp = 0 - DWARF2_LINE_BASE; + NeedCopy = true; + } + + // Use DW_LNS_copy instead of a "line +0, addr +0" special opcode. + if (LineDelta == 0 && AddrDelta == 0) { + OS << char(dwarf::DW_LNS_copy); + return; + } + + // Bias the opcode by the special opcode base. + Temp += DWARF2_LINE_OPCODE_BASE; + + // Avoid overflow when addr_delta is large. + if (AddrDelta < 256 + MAX_SPECIAL_ADDR_DELTA) { + // Try using a special opcode. + Opcode = Temp + AddrDelta * DWARF2_LINE_RANGE; + if (Opcode <= 255) { + OS << char(Opcode); + return; + } + + // Try using DW_LNS_const_add_pc followed by special op. + Opcode = Temp + (AddrDelta - MAX_SPECIAL_ADDR_DELTA) * DWARF2_LINE_RANGE; + if (Opcode <= 255) { + OS << char(dwarf::DW_LNS_const_add_pc); + OS << char(Opcode); + return; + } + } + + // Otherwise use DW_LNS_advance_pc. + OS << char(dwarf::DW_LNS_advance_pc); + SmallString<32> Tmp; + raw_svector_ostream OSE(Tmp); + MCObjectWriter::EncodeULEB128(AddrDelta, OSE); + OS << OSE.str(); + + if (NeedCopy) + OS << char(dwarf::DW_LNS_copy); + else + OS << char(Temp); +} + void MCDwarfFile::print(raw_ostream &OS) const { OS << '"' << getName() << '"'; } @@ -19,3 +428,387 @@ void MCDwarfFile::print(raw_ostream &OS) const { void MCDwarfFile::dump() const { print(dbgs()); } + +static int getDataAlignmentFactor(MCStreamer &streamer) { + MCContext &context = streamer.getContext(); + const TargetAsmInfo &asmInfo = context.getTargetAsmInfo(); + int size = asmInfo.getPointerSize(); + if (asmInfo.getStackGrowthDirection() == TargetFrameLowering::StackGrowsUp) + return size; + else + return -size; +} + +static void EmitCFIInstruction(MCStreamer &Streamer, + const MCCFIInstruction &Instr) { + int dataAlignmentFactor = getDataAlignmentFactor(Streamer); + + switch (Instr.getOperation()) { + case MCCFIInstruction::Move: { + const MachineLocation &Dst = Instr.getDestination(); + const MachineLocation &Src = Instr.getSource(); + + // If advancing cfa. + if (Dst.isReg() && Dst.getReg() == MachineLocation::VirtualFP) { + assert(!Src.isReg() && "Machine move not supported yet."); + + if (Src.getReg() == MachineLocation::VirtualFP) { + Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa_offset, 1); + } else { + Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa, 1); + Streamer.EmitULEB128IntValue(Src.getReg()); + } + + Streamer.EmitULEB128IntValue(-Src.getOffset(), 1); + return; + } + + if (Src.isReg() && Src.getReg() == MachineLocation::VirtualFP) { + assert(Dst.isReg() && "Machine move not supported yet."); + Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa_register, 1); + Streamer.EmitULEB128IntValue(Dst.getReg()); + return; + } + + unsigned Reg = Src.getReg(); + int Offset = Dst.getOffset() / dataAlignmentFactor; + + if (Offset < 0) { + Streamer.EmitIntValue(dwarf::DW_CFA_offset_extended_sf, 1); + Streamer.EmitULEB128IntValue(Reg); + Streamer.EmitSLEB128IntValue(Offset); + } else if (Reg < 64) { + Streamer.EmitIntValue(dwarf::DW_CFA_offset + Reg, 1); + Streamer.EmitULEB128IntValue(Offset, 1); + } else { + Streamer.EmitIntValue(dwarf::DW_CFA_offset_extended, 1); + Streamer.EmitULEB128IntValue(Reg, 1); + Streamer.EmitULEB128IntValue(Offset, 1); + } + return; + } + case MCCFIInstruction::Remember: + Streamer.EmitIntValue(dwarf::DW_CFA_remember_state, 1); + return; + case MCCFIInstruction::Restore: + Streamer.EmitIntValue(dwarf::DW_CFA_restore_state, 1); + return; + } + llvm_unreachable("Unhandled case in switch"); +} + +/// EmitFrameMoves - Emit frame instructions to describe the layout of the +/// frame. +static void EmitCFIInstructions(MCStreamer &streamer, + const std::vector &Instrs, + MCSymbol *BaseLabel) { + for (unsigned i = 0, N = Instrs.size(); i < N; ++i) { + const MCCFIInstruction &Instr = Instrs[i]; + MCSymbol *Label = Instr.getLabel(); + // Throw out move if the label is invalid. + if (Label && !Label->isDefined()) continue; // Not emitted, in dead code. + + // Advance row if new location. + if (BaseLabel && Label) { + MCSymbol *ThisSym = Label; + if (ThisSym != BaseLabel) { + streamer.EmitDwarfAdvanceFrameAddr(BaseLabel, ThisSym); + BaseLabel = ThisSym; + } + } + + EmitCFIInstruction(streamer, Instr); + } +} + +static void EmitSymbol(MCStreamer &streamer, const MCSymbol &symbol, + unsigned symbolEncoding) { + MCContext &context = streamer.getContext(); + const TargetAsmInfo &asmInfo = context.getTargetAsmInfo(); + unsigned format = symbolEncoding & 0x0f; + unsigned application = symbolEncoding & 0x70; + unsigned size; + switch (format) { + default: + assert(0 && "Unknown Encoding"); + case dwarf::DW_EH_PE_absptr: + case dwarf::DW_EH_PE_signed: + size = asmInfo.getPointerSize(); + break; + case dwarf::DW_EH_PE_udata2: + case dwarf::DW_EH_PE_sdata2: + size = 2; + break; + case dwarf::DW_EH_PE_udata4: + case dwarf::DW_EH_PE_sdata4: + size = 4; + break; + case dwarf::DW_EH_PE_udata8: + case dwarf::DW_EH_PE_sdata8: + size = 8; + break; + } + switch (application) { + default: + assert(0 && "Unknown Encoding"); + break; + case 0: + streamer.EmitSymbolValue(&symbol, size); + break; + case dwarf::DW_EH_PE_pcrel: + streamer.EmitPCRelSymbolValue(&symbol, size); + break; + } +} + +static const MachineLocation TranslateMachineLocation( + const TargetAsmInfo &AsmInfo, + const MachineLocation &Loc) { + unsigned Reg = Loc.getReg() == MachineLocation::VirtualFP ? + MachineLocation::VirtualFP : + unsigned(AsmInfo.getDwarfRegNum(Loc.getReg(), true)); + const MachineLocation &NewLoc = Loc.isReg() ? + MachineLocation(Reg) : MachineLocation(Reg, Loc.getOffset()); + return NewLoc; +} + +static const MCSymbol &EmitCIE(MCStreamer &streamer, + const MCSymbol *personality, + unsigned personalityEncoding, + const MCSymbol *lsda, + unsigned lsdaEncoding) { + MCContext &context = streamer.getContext(); + const TargetAsmInfo &asmInfo = context.getTargetAsmInfo(); + const MCSection §ion = *asmInfo.getEHFrameSection(); + streamer.SwitchSection(§ion); + MCSymbol *sectionStart = streamer.getContext().CreateTempSymbol(); + MCSymbol *sectionEnd = streamer.getContext().CreateTempSymbol(); + + // Length + const MCExpr *Length = MakeStartMinusEndExpr(streamer, *sectionStart, + *sectionEnd, 4); + streamer.EmitLabel(sectionStart); + streamer.EmitValue(Length, 4); + + // CIE ID + streamer.EmitIntValue(0, 4); + + // Version + streamer.EmitIntValue(dwarf::DW_CIE_VERSION, 1); + + // Augmentation String + SmallString<8> Augmentation; + Augmentation += "z"; + if (personality) + Augmentation += "P"; + if (lsda) + Augmentation += "L"; + Augmentation += "R"; + streamer.EmitBytes(Augmentation.str(), 0); + streamer.EmitIntValue(0, 1); + + // Code Alignment Factor + streamer.EmitULEB128IntValue(1); + + // Data Alignment Factor + streamer.EmitSLEB128IntValue(getDataAlignmentFactor(streamer)); + + // Return Address Register + streamer.EmitULEB128IntValue(asmInfo.getDwarfRARegNum(true)); + + // Augmentation Data Length (optional) + MCSymbol *augmentationStart = streamer.getContext().CreateTempSymbol(); + MCSymbol *augmentationEnd = streamer.getContext().CreateTempSymbol(); + const MCExpr *augmentationLength = MakeStartMinusEndExpr(streamer, + *augmentationStart, + *augmentationEnd, 0); + streamer.EmitULEB128Value(augmentationLength); + + // Augmentation Data (optional) + streamer.EmitLabel(augmentationStart); + if (personality) { + // Personality Encoding + streamer.EmitIntValue(personalityEncoding, 1); + // Personality + EmitSymbol(streamer, *personality, personalityEncoding); + } + if (lsda) { + // LSDA Encoding + streamer.EmitIntValue(lsdaEncoding, 1); + } + // Encoding of the FDE pointers + streamer.EmitIntValue(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4, 1); + streamer.EmitLabel(augmentationEnd); + + // Initial Instructions + + const std::vector Moves = asmInfo.getInitialFrameState(); + std::vector Instructions; + + for (int i = 0, n = Moves.size(); i != n; ++i) { + MCSymbol *Label = Moves[i].getLabel(); + const MachineLocation &Dst = + TranslateMachineLocation(asmInfo, Moves[i].getDestination()); + const MachineLocation &Src = + TranslateMachineLocation(asmInfo, Moves[i].getSource()); + MCCFIInstruction Inst(Label, Dst, Src); + Instructions.push_back(Inst); + } + + EmitCFIInstructions(streamer, Instructions, NULL); + + // Padding + streamer.EmitValueToAlignment(4); + + streamer.EmitLabel(sectionEnd); + return *sectionStart; +} + +static MCSymbol *EmitFDE(MCStreamer &streamer, + const MCSymbol &cieStart, + const MCDwarfFrameInfo &frame) { + MCContext &context = streamer.getContext(); + MCSymbol *fdeStart = context.CreateTempSymbol(); + MCSymbol *fdeEnd = context.CreateTempSymbol(); + + // Length + const MCExpr *Length = MakeStartMinusEndExpr(streamer, *fdeStart, *fdeEnd, 0); + streamer.EmitValue(Length, 4); + + streamer.EmitLabel(fdeStart); + // CIE Pointer + const MCExpr *offset = MakeStartMinusEndExpr(streamer, cieStart, *fdeStart, + 0); + streamer.EmitValue(offset, 4); + + // PC Begin + streamer.EmitPCRelSymbolValue(frame.Begin, 4); + + // PC Range + const MCExpr *Range = MakeStartMinusEndExpr(streamer, *frame.Begin, + *frame.End, 0); + streamer.EmitValue(Range, 4); + + // Augmentation Data Length + MCSymbol *augmentationStart = streamer.getContext().CreateTempSymbol(); + MCSymbol *augmentationEnd = streamer.getContext().CreateTempSymbol(); + const MCExpr *augmentationLength = MakeStartMinusEndExpr(streamer, + *augmentationStart, + *augmentationEnd, 0); + streamer.EmitULEB128Value(augmentationLength); + + // Augmentation Data + streamer.EmitLabel(augmentationStart); + if (frame.Lsda) + EmitSymbol(streamer, *frame.Lsda, frame.LsdaEncoding); + streamer.EmitLabel(augmentationEnd); + // Call Frame Instructions + + EmitCFIInstructions(streamer, frame.Instructions, frame.Begin); + + // Padding + streamer.EmitValueToAlignment(4); + + return fdeEnd; +} + +namespace { + struct CIEKey { + static const CIEKey getEmptyKey() { return CIEKey(0, 0, -1); } + static const CIEKey getTombstoneKey() { return CIEKey(0, -1, 0); } + + CIEKey(const MCSymbol* Personality_, unsigned PersonalityEncoding_, + unsigned LsdaEncoding_) : Personality(Personality_), + PersonalityEncoding(PersonalityEncoding_), + LsdaEncoding(LsdaEncoding_) { + } + const MCSymbol* Personality; + unsigned PersonalityEncoding; + unsigned LsdaEncoding; + }; +} + +namespace llvm { + template <> + struct DenseMapInfo { + static CIEKey getEmptyKey() { + return CIEKey::getEmptyKey(); + } + static CIEKey getTombstoneKey() { + return CIEKey::getTombstoneKey(); + } + static unsigned getHashValue(const CIEKey &Key) { + FoldingSetNodeID ID; + ID.AddPointer(Key.Personality); + ID.AddInteger(Key.PersonalityEncoding); + ID.AddInteger(Key.LsdaEncoding); + return ID.ComputeHash(); + } + static bool isEqual(const CIEKey &LHS, + const CIEKey &RHS) { + return LHS.Personality == RHS.Personality && + LHS.PersonalityEncoding == RHS.PersonalityEncoding && + LHS.LsdaEncoding == RHS.LsdaEncoding; + } + }; +} + +void MCDwarfFrameEmitter::Emit(MCStreamer &streamer) { + const MCContext &context = streamer.getContext(); + const TargetAsmInfo &asmInfo = context.getTargetAsmInfo(); + MCSymbol *fdeEnd = NULL; + DenseMap CIEStarts; + + for (unsigned i = 0, n = streamer.getNumFrameInfos(); i < n; ++i) { + const MCDwarfFrameInfo &frame = streamer.getFrameInfo(i); + CIEKey key(frame.Personality, frame.PersonalityEncoding, + frame.LsdaEncoding); + const MCSymbol *&cieStart = CIEStarts[key]; + if (!cieStart) + cieStart = &EmitCIE(streamer, frame.Personality, + frame.PersonalityEncoding, frame.Lsda, + frame.LsdaEncoding); + fdeEnd = EmitFDE(streamer, *cieStart, frame); + if (i != n - 1) + streamer.EmitLabel(fdeEnd); + } + + streamer.EmitValueToAlignment(asmInfo.getPointerSize()); + if (fdeEnd) + streamer.EmitLabel(fdeEnd); +} + +void MCDwarfFrameEmitter::EmitAdvanceLoc(MCStreamer &Streamer, + uint64_t AddrDelta) { + SmallString<256> Tmp; + raw_svector_ostream OS(Tmp); + MCDwarfFrameEmitter::EncodeAdvanceLoc(AddrDelta, OS); + Streamer.EmitBytes(OS.str(), /*AddrSpace=*/0); +} + +void MCDwarfFrameEmitter::EncodeAdvanceLoc(uint64_t AddrDelta, + raw_ostream &OS) { + // FIXME: Assumes the code alignment factor is 1. + if (AddrDelta == 0) { + } else if (isUIntN(6, AddrDelta)) { + uint8_t Opcode = dwarf::DW_CFA_advance_loc | AddrDelta; + OS << Opcode; + } else if (isUInt<8>(AddrDelta)) { + OS << uint8_t(dwarf::DW_CFA_advance_loc1); + OS << uint8_t(AddrDelta); + } else if (isUInt<16>(AddrDelta)) { + // FIXME: check what is the correct behavior on a big endian machine. + OS << uint8_t(dwarf::DW_CFA_advance_loc2); + OS << uint8_t( AddrDelta & 0xff); + OS << uint8_t((AddrDelta >> 8) & 0xff); + } else { + // FIXME: check what is the correct behavior on a big endian machine. + assert(isUInt<32>(AddrDelta)); + OS << uint8_t(dwarf::DW_CFA_advance_loc4); + OS << uint8_t( AddrDelta & 0xff); + OS << uint8_t((AddrDelta >> 8) & 0xff); + OS << uint8_t((AddrDelta >> 16) & 0xff); + OS << uint8_t((AddrDelta >> 24) & 0xff); + + } +} diff --git a/lib/MC/MCELFObjectTargetWriter.cpp b/lib/MC/MCELFObjectTargetWriter.cpp new file mode 100644 index 000000000000..12a02a9e9740 --- /dev/null +++ b/lib/MC/MCELFObjectTargetWriter.cpp @@ -0,0 +1,23 @@ +//===-- MCELFObjectTargetWriter.cpp - ELF Target Writer Subclass ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCELFObjectWriter.h" + +using namespace llvm; + +MCELFObjectTargetWriter::MCELFObjectTargetWriter(bool Is64Bit_, + Triple::OSType OSType_, + uint16_t EMachine_, + bool HasRelocationAddend_) + : OSType(OSType_), EMachine(EMachine_), + HasRelocationAddend(HasRelocationAddend_), Is64Bit(Is64Bit_) { +} + +MCELFObjectTargetWriter::~MCELFObjectTargetWriter() { +} diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp index 570c3917ab46..e49074da3994 100644 --- a/lib/MC/MCELFStreamer.cpp +++ b/lib/MC/MCELFStreamer.cpp @@ -13,6 +13,7 @@ #include "llvm/MC/MCStreamer.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCCodeEmitter.h" @@ -23,19 +24,51 @@ #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCValue.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ELF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetAsmBackend.h" +#include "llvm/Target/TargetAsmInfo.h" using namespace llvm; namespace { +static void SetBinding(MCSymbolData &SD, unsigned Binding) { + assert(Binding == ELF::STB_LOCAL || Binding == ELF::STB_GLOBAL || + Binding == ELF::STB_WEAK); + uint32_t OtherFlags = SD.getFlags() & ~(0xf << ELF_STB_Shift); + SD.setFlags(OtherFlags | (Binding << ELF_STB_Shift)); +} + +static unsigned GetBinding(const MCSymbolData &SD) { + uint32_t Binding = (SD.getFlags() & (0xf << ELF_STB_Shift)) >> ELF_STB_Shift; + assert(Binding == ELF::STB_LOCAL || Binding == ELF::STB_GLOBAL || + Binding == ELF::STB_WEAK); + return Binding; +} + +static void SetType(MCSymbolData &SD, unsigned Type) { + assert(Type == ELF::STT_NOTYPE || Type == ELF::STT_OBJECT || + Type == ELF::STT_FUNC || Type == ELF::STT_SECTION || + Type == ELF::STT_FILE || Type == ELF::STT_COMMON || + Type == ELF::STT_TLS); + + uint32_t OtherFlags = SD.getFlags() & ~(0xf << ELF_STT_Shift); + SD.setFlags(OtherFlags | (Type << ELF_STT_Shift)); +} + +static void SetVisibility(MCSymbolData &SD, unsigned Visibility) { + assert(Visibility == ELF::STV_DEFAULT || Visibility == ELF::STV_INTERNAL || + Visibility == ELF::STV_HIDDEN || Visibility == ELF::STV_PROTECTED); + + uint32_t OtherFlags = SD.getFlags() & ~(0xf << ELF_STV_Shift); + SD.setFlags(OtherFlags | (Visibility << ELF_STV_Shift)); +} + class MCELFStreamer : public MCObjectStreamer { - void EmitInstToFragment(const MCInst &Inst); - void EmitInstToData(const MCInst &Inst); public: MCELFStreamer(MCContext &Context, TargetAsmBackend &TAB, raw_ostream &OS, MCCodeEmitter *Emitter) @@ -46,9 +79,13 @@ public: /// @name MCStreamer Interface /// @{ + virtual void InitSections(); + virtual void ChangeSection(const MCSection *Section); virtual void EmitLabel(MCSymbol *Symbol); virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); + virtual void EmitThumbFunc(MCSymbol *Func); virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); + virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol); virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { assert(0 && "ELF doesn't support this directive"); @@ -76,9 +113,8 @@ public: SD.setSize(Value); } - virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { - assert(0 && "ELF doesn't support this directive"); - } + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size); + virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, unsigned Size = 0, unsigned ByteAlignment = 0) { assert(0 && "ELF doesn't support this directive"); @@ -88,49 +124,84 @@ public: assert(0 && "ELF doesn't support this directive"); } virtual void EmitBytes(StringRef Data, unsigned AddrSpace); - virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace); - virtual void EmitGPRel32Value(const MCExpr *Value) { - assert(0 && "ELF doesn't support this directive"); - } virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, unsigned ValueSize = 1, unsigned MaxBytesToEmit = 0); virtual void EmitCodeAlignment(unsigned ByteAlignment, unsigned MaxBytesToEmit = 0); - virtual void EmitValueToOffset(const MCExpr *Offset, - unsigned char Value = 0); virtual void EmitFileDirective(StringRef Filename); - virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) { - DEBUG(dbgs() << "FIXME: MCELFStreamer:EmitDwarfFileDirective not implemented\n"); - } - virtual void EmitInstruction(const MCInst &Inst); virtual void Finish(); +private: + virtual void EmitInstToFragment(const MCInst &Inst); + virtual void EmitInstToData(const MCInst &Inst); + + void fixSymbolsInTLSFixups(const MCExpr *expr); + + struct LocalCommon { + MCSymbolData *SD; + uint64_t Size; + unsigned ByteAlignment; + }; + std::vector LocalCommons; + + SmallPtrSet BindingExplicitlySet; /// @} + void SetSection(StringRef Section, unsigned Type, unsigned Flags, + SectionKind Kind) { + SwitchSection(getContext().getELFSection(Section, Type, Flags, Kind)); + } + + void SetSectionData() { + SetSection(".data", ELF::SHT_PROGBITS, + ELF::SHF_WRITE |ELF::SHF_ALLOC, + SectionKind::getDataRel()); + EmitCodeAlignment(4, 0); + } + void SetSectionText() { + SetSection(".text", ELF::SHT_PROGBITS, + ELF::SHF_EXECINSTR | + ELF::SHF_ALLOC, SectionKind::getText()); + EmitCodeAlignment(4, 0); + } + void SetSectionBss() { + SetSection(".bss", ELF::SHT_NOBITS, + ELF::SHF_WRITE | + ELF::SHF_ALLOC, SectionKind::getBSS()); + EmitCodeAlignment(4, 0); + } }; } // end anonymous namespace. +void MCELFStreamer::InitSections() { + // This emulates the same behavior of GNU as. This makes it easier + // to compare the output as the major sections are in the same order. + SetSectionText(); + SetSectionData(); + SetSectionBss(); + SetSectionText(); +} + void MCELFStreamer::EmitLabel(MCSymbol *Symbol) { assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); - // FIXME: This is wasteful, we don't necessarily need to create a data - // fragment. Instead, we should mark the symbol as pointing into the data - // fragment if it exists, otherwise we should just queue the label and set its - // fragment pointer when we emit the next fragment. - MCDataFragment *F = getOrCreateDataFragment(); - MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); - assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); - SD.setFragment(F); - SD.setOffset(F->getContents().size()); + MCObjectStreamer::EmitLabel(Symbol); - Symbol->setSection(*CurSection); + const MCSectionELF &Section = + static_cast(Symbol->getSection()); + MCSymbolData &SD = getAssembler().getSymbolData(*Symbol); + if (Section.getFlags() & ELF::SHF_TLS) + SetType(SD, ELF::STT_TLS); } void MCELFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { switch (Flag) { + case MCAF_SyntaxUnified: return; // no-op here. + case MCAF_Code16: return; // no-op here. + case MCAF_Code32: return; // no-op here. case MCAF_SubsectionsViaSymbols: getAssembler().setSubsectionsViaSymbols(true); return; @@ -139,6 +210,10 @@ void MCELFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { assert(0 && "invalid assembler flag!"); } +void MCELFStreamer::EmitThumbFunc(MCSymbol *Func) { + // FIXME: Anything needed here to flag the function as thumb? +} + void MCELFStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into // MCObjectStreamer. @@ -147,6 +222,21 @@ void MCELFStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { Symbol->setVariableValue(AddValueSymbols(Value)); } +void MCELFStreamer::ChangeSection(const MCSection *Section) { + const MCSymbol *Grp = static_cast(Section)->getGroup(); + if (Grp) + getAssembler().getOrCreateSymbolData(*Grp); + this->MCObjectStreamer::ChangeSection(Section); +} + +void MCELFStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { + getAssembler().getOrCreateSymbolData(*Symbol); + MCSymbolData &AliasSD = getAssembler().getOrCreateSymbolData(*Alias); + AliasSD.setFlags(AliasSD.getFlags() | ELF_Other_Weakref); + const MCExpr *Value = MCSymbolRefExpr::Create(Symbol, getContext()); + Alias->setVariableValue(Value); +} + void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { // Indirect symbols are handled differently, to match how 'as' handles @@ -176,6 +266,7 @@ void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, case MCSA_LazyReference: case MCSA_Reference: case MCSA_NoDeadStrip: + case MCSA_SymbolResolver: case MCSA_PrivateExtern: case MCSA_WeakDefinition: case MCSA_WeakDefAutoPrivate: @@ -185,50 +276,59 @@ void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, assert(0 && "Invalid symbol attribute for ELF!"); break; + case MCSA_ELF_TypeGnuUniqueObject: + // Ignore for now. + break; + case MCSA_Global: - SD.setFlags(SD.getFlags() | ELF_STB_Global); + SetBinding(SD, ELF::STB_GLOBAL); SD.setExternal(true); + BindingExplicitlySet.insert(Symbol); break; case MCSA_WeakReference: case MCSA_Weak: - SD.setFlags(SD.getFlags() | ELF_STB_Weak); + SetBinding(SD, ELF::STB_WEAK); + SD.setExternal(true); + BindingExplicitlySet.insert(Symbol); break; case MCSA_Local: - SD.setFlags(SD.getFlags() | ELF_STB_Local); + SetBinding(SD, ELF::STB_LOCAL); + SD.setExternal(false); + BindingExplicitlySet.insert(Symbol); break; case MCSA_ELF_TypeFunction: - SD.setFlags(SD.getFlags() | ELF_STT_Func); + SetType(SD, ELF::STT_FUNC); break; case MCSA_ELF_TypeObject: - SD.setFlags(SD.getFlags() | ELF_STT_Object); + SetType(SD, ELF::STT_OBJECT); break; case MCSA_ELF_TypeTLS: - SD.setFlags(SD.getFlags() | ELF_STT_Tls); + SetType(SD, ELF::STT_TLS); break; case MCSA_ELF_TypeCommon: - SD.setFlags(SD.getFlags() | ELF_STT_Common); + SetType(SD, ELF::STT_COMMON); break; case MCSA_ELF_TypeNoType: - SD.setFlags(SD.getFlags() | ELF_STT_Notype); + SetType(SD, ELF::STT_NOTYPE); break; case MCSA_Protected: - SD.setFlags(SD.getFlags() | ELF_STV_Protected); + SetVisibility(SD, ELF::STV_PROTECTED); break; case MCSA_Hidden: - SD.setFlags(SD.getFlags() | ELF_STV_Hidden); + SetVisibility(SD, ELF::STV_HIDDEN); break; case MCSA_Internal: - SD.setFlags(SD.getFlags() | ELF_STV_Internal); + SetVisibility(SD, ELF::STV_INTERNAL); break; } } @@ -237,24 +337,38 @@ void MCELFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); - if ((SD.getFlags() & (0xf << ELF_STB_Shift)) == ELF_STB_Local) { + if (!BindingExplicitlySet.count(Symbol)) { + SetBinding(SD, ELF::STB_GLOBAL); + SD.setExternal(true); + } + + SetType(SD, ELF::STT_OBJECT); + + if (GetBinding(SD) == ELF_STB_Local) { const MCSection *Section = getAssembler().getContext().getELFSection(".bss", - MCSectionELF::SHT_NOBITS, - MCSectionELF::SHF_WRITE | - MCSectionELF::SHF_ALLOC, + ELF::SHT_NOBITS, + ELF::SHF_WRITE | + ELF::SHF_ALLOC, SectionKind::getBSS()); - - MCSectionData &SectData = getAssembler().getOrCreateSectionData(*Section); - MCFragment *F = new MCFillFragment(0, 0, Size, &SectData); - SD.setFragment(F); Symbol->setSection(*Section); - SD.setSize(MCConstantExpr::Create(Size, getContext())); + + struct LocalCommon L = {&SD, Size, ByteAlignment}; + LocalCommons.push_back(L); + } else { + SD.setCommon(Size, ByteAlignment); } - SD.setFlags(SD.getFlags() | ELF_STB_Global); - SD.setExternal(true); + SD.setSize(MCConstantExpr::Create(Size, getContext())); +} - SD.setCommon(Size, ByteAlignment); +void MCELFStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { + // FIXME: Should this be caught and done earlier? + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + SetBinding(SD, ELF::STB_LOCAL); + SD.setExternal(false); + BindingExplicitlySet.insert(Symbol); + // FIXME: ByteAlignment is not needed here, but is required. + EmitCommonSymbol(Symbol, Size, 1); } void MCELFStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { @@ -263,25 +377,6 @@ void MCELFStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end()); } -void MCELFStreamer::EmitValue(const MCExpr *Value, unsigned Size, - unsigned AddrSpace) { - // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into - // MCObjectStreamer. - MCDataFragment *DF = getOrCreateDataFragment(); - - // Avoid fixups when possible. - int64_t AbsValue; - if (AddValueSymbols(Value)->EvaluateAsAbsolute(AbsValue)) { - // FIXME: Endianness assumption. - for (unsigned i = 0; i != Size; ++i) - DF->getContents().push_back(uint8_t(AbsValue >> (i * 8))); - } else { - DF->addFixup(MCFixup::Create(DF->getContents().size(), AddValueSymbols(Value), - MCFixup::getKindForSize(Size))); - DF->getContents().resize(DF->getContents().size() + Size, 0); - } -} - void MCELFStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, unsigned ValueSize, unsigned MaxBytesToEmit) { @@ -312,18 +407,11 @@ void MCELFStreamer::EmitCodeAlignment(unsigned ByteAlignment, getCurrentSectionData()->setAlignment(ByteAlignment); } -void MCELFStreamer::EmitValueToOffset(const MCExpr *Offset, - unsigned char Value) { - // TODO: This is exactly the same as MCMachOStreamer. Consider merging into - // MCObjectStreamer. - new MCOrgFragment(*Offset, Value, getCurrentSectionData()); -} - // Add a symbol for the file name of this module. This is the second // entry in the module's symbol table (the first being the null symbol). void MCELFStreamer::EmitFileDirective(StringRef Filename) { MCSymbol *Symbol = getAssembler().getContext().GetOrCreateSymbol(Filename); - Symbol->setSection(*CurSection); + Symbol->setSection(*getCurrentSection()); Symbol->setAbsolute(); MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); @@ -331,21 +419,52 @@ void MCELFStreamer::EmitFileDirective(StringRef Filename) { SD.setFlags(ELF_STT_File | ELF_STB_Local | ELF_STV_Default); } -void MCELFStreamer::EmitInstToFragment(const MCInst &Inst) { - MCInstFragment *IF = new MCInstFragment(Inst, getCurrentSectionData()); +void MCELFStreamer::fixSymbolsInTLSFixups(const MCExpr *expr) { + switch (expr->getKind()) { + case MCExpr::Target: llvm_unreachable("Can't handle target exprs yet!"); + case MCExpr::Constant: + break; - // Add the fixups and data. - // - // FIXME: Revisit this design decision when relaxation is done, we may be - // able to get away with not storing any extra data in the MCInst. - SmallVector Fixups; - SmallString<256> Code; - raw_svector_ostream VecOS(Code); - getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups); - VecOS.flush(); + case MCExpr::Binary: { + const MCBinaryExpr *be = cast(expr); + fixSymbolsInTLSFixups(be->getLHS()); + fixSymbolsInTLSFixups(be->getRHS()); + break; + } + + case MCExpr::SymbolRef: { + const MCSymbolRefExpr &symRef = *cast(expr); + switch (symRef.getKind()) { + default: + return; + case MCSymbolRefExpr::VK_NTPOFF: + case MCSymbolRefExpr::VK_GOTNTPOFF: + case MCSymbolRefExpr::VK_TLSGD: + case MCSymbolRefExpr::VK_TLSLDM: + case MCSymbolRefExpr::VK_TPOFF: + case MCSymbolRefExpr::VK_DTPOFF: + case MCSymbolRefExpr::VK_GOTTPOFF: + case MCSymbolRefExpr::VK_TLSLD: + case MCSymbolRefExpr::VK_ARM_TLSGD: + break; + } + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(symRef.getSymbol()); + SetType(SD, ELF::STT_TLS); + break; + } + + case MCExpr::Unary: + fixSymbolsInTLSFixups(cast(expr)->getSubExpr()); + break; + } +} + +void MCELFStreamer::EmitInstToFragment(const MCInst &Inst) { + this->MCObjectStreamer::EmitInstToFragment(Inst); + MCInstFragment &F = *cast(getCurrentFragment()); - IF->getCode() = Code; - IF->getFixups() = Fixups; + for (unsigned i = 0, e = F.getFixups().size(); i != e; ++i) + fixSymbolsInTLSFixups(F.getFixups()[i].getValue()); } void MCELFStreamer::EmitInstToData(const MCInst &Inst) { @@ -357,6 +476,9 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst) { getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups); VecOS.flush(); + for (unsigned i = 0, e = Fixups.size(); i != e; ++i) + fixSymbolsInTLSFixups(Fixups[i].getValue()); + // Add the fixups and data. for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size()); @@ -365,44 +487,40 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst) { DF->getContents().append(Code.begin(), Code.end()); } -void MCELFStreamer::EmitInstruction(const MCInst &Inst) { - // Scan for values. - for (unsigned i = 0; i != Inst.getNumOperands(); ++i) - if (Inst.getOperand(i).isExpr()) - AddValueSymbols(Inst.getOperand(i).getExpr()); +void MCELFStreamer::Finish() { + if (getNumFrameInfos()) + MCDwarfFrameEmitter::Emit(*this); - getCurrentSectionData()->setHasInstructions(true); + for (std::vector::const_iterator i = LocalCommons.begin(), + e = LocalCommons.end(); + i != e; ++i) { + MCSymbolData *SD = i->SD; + uint64_t Size = i->Size; + unsigned ByteAlignment = i->ByteAlignment; + const MCSymbol &Symbol = SD->getSymbol(); + const MCSection &Section = Symbol.getSection(); - // If this instruction doesn't need relaxation, just emit it as data. - if (!getAssembler().getBackend().MayNeedRelaxation(Inst)) { - EmitInstToData(Inst); - return; - } + MCSectionData &SectData = getAssembler().getOrCreateSectionData(Section); + new MCAlignFragment(ByteAlignment, 0, 1, ByteAlignment, &SectData); - // Otherwise, if we are relaxing everything, relax the instruction as much as - // possible and emit it as data. - if (getAssembler().getRelaxAll()) { - MCInst Relaxed; - getAssembler().getBackend().RelaxInstruction(Inst, Relaxed); - while (getAssembler().getBackend().MayNeedRelaxation(Relaxed)) - getAssembler().getBackend().RelaxInstruction(Relaxed, Relaxed); - EmitInstToData(Relaxed); - return; - } + MCFragment *F = new MCFillFragment(0, 0, Size, &SectData); + SD->setFragment(F); - // Otherwise emit to a separate fragment. - EmitInstToFragment(Inst); -} + // Update the maximum alignment of the section if necessary. + if (ByteAlignment > SectData.getAlignment()) + SectData.setAlignment(ByteAlignment); + } -void MCELFStreamer::Finish() { - getAssembler().Finish(); + this->MCObjectStreamer::Finish(); } MCStreamer *llvm::createELFStreamer(MCContext &Context, TargetAsmBackend &TAB, - raw_ostream &OS, MCCodeEmitter *CE, - bool RelaxAll) { + raw_ostream &OS, MCCodeEmitter *CE, + bool RelaxAll, bool NoExecStack) { MCELFStreamer *S = new MCELFStreamer(Context, TAB, OS, CE); if (RelaxAll) S->getAssembler().setRelaxAll(true); + if (NoExecStack) + S->getAssembler().setNoExecStack(true); return S; } diff --git a/lib/MC/MCExpr.cpp b/lib/MC/MCExpr.cpp index 343f33475235..54d3743e68e4 100644 --- a/lib/MC/MCExpr.cpp +++ b/lib/MC/MCExpr.cpp @@ -38,21 +38,31 @@ void MCExpr::print(raw_ostream &OS) const { case MCExpr::SymbolRef: { const MCSymbolRefExpr &SRE = cast(*this); const MCSymbol &Sym = SRE.getSymbol(); + // Parenthesize names that start with $ so that they don't look like + // absolute names. + bool UseParens = Sym.getName()[0] == '$'; - if (SRE.getKind() == MCSymbolRefExpr::VK_ARM_HI16 || - SRE.getKind() == MCSymbolRefExpr::VK_ARM_LO16) + if (SRE.getKind() == MCSymbolRefExpr::VK_PPC_HA16 || + SRE.getKind() == MCSymbolRefExpr::VK_PPC_LO16) { OS << MCSymbolRefExpr::getVariantKindName(SRE.getKind()); + UseParens = true; + } - // Parenthesize names that start with $ so that they don't look like - // absolute names. - if (Sym.getName()[0] == '$') + if (UseParens) OS << '(' << Sym << ')'; else OS << Sym; - if (SRE.getKind() != MCSymbolRefExpr::VK_None && - SRE.getKind() != MCSymbolRefExpr::VK_ARM_HI16 && - SRE.getKind() != MCSymbolRefExpr::VK_ARM_LO16) + if (SRE.getKind() == MCSymbolRefExpr::VK_ARM_PLT || + SRE.getKind() == MCSymbolRefExpr::VK_ARM_TLSGD || + SRE.getKind() == MCSymbolRefExpr::VK_ARM_GOT || + SRE.getKind() == MCSymbolRefExpr::VK_ARM_GOTOFF || + SRE.getKind() == MCSymbolRefExpr::VK_ARM_TPOFF || + SRE.getKind() == MCSymbolRefExpr::VK_ARM_GOTTPOFF) + OS << MCSymbolRefExpr::getVariantKindName(SRE.getKind()); + else if (SRE.getKind() != MCSymbolRefExpr::VK_None && + SRE.getKind() != MCSymbolRefExpr::VK_PPC_HA16 && + SRE.getKind() != MCSymbolRefExpr::VK_PPC_LO16) OS << '@' << MCSymbolRefExpr::getVariantKindName(SRE.getKind()); return; @@ -172,12 +182,23 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) { case VK_GOTTPOFF: return "GOTTPOFF"; case VK_INDNTPOFF: return "INDNTPOFF"; case VK_NTPOFF: return "NTPOFF"; + case VK_GOTNTPOFF: return "GOTNTPOFF"; case VK_PLT: return "PLT"; case VK_TLSGD: return "TLSGD"; + case VK_TLSLD: return "TLSLD"; + case VK_TLSLDM: return "TLSLDM"; case VK_TPOFF: return "TPOFF"; - case VK_ARM_HI16: return ":upper16:"; - case VK_ARM_LO16: return ":lower16:"; + case VK_DTPOFF: return "DTPOFF"; case VK_TLVP: return "TLVP"; + case VK_ARM_PLT: return "(PLT)"; + case VK_ARM_GOT: return "(GOT)"; + case VK_ARM_GOTOFF: return "(GOTOFF)"; + case VK_ARM_TPOFF: return "(tpoff)"; + case VK_ARM_GOTTPOFF: return "(gottpoff)"; + case VK_ARM_TLSGD: return "(tlsgd)"; + case VK_PPC_TOC: return "toc"; + case VK_PPC_HA16: return "ha16"; + case VK_PPC_LO16: return "lo16"; } } @@ -185,15 +206,33 @@ MCSymbolRefExpr::VariantKind MCSymbolRefExpr::getVariantKindForName(StringRef Name) { return StringSwitch(Name) .Case("GOT", VK_GOT) + .Case("got", VK_GOT) .Case("GOTOFF", VK_GOTOFF) + .Case("gotoff", VK_GOTOFF) .Case("GOTPCREL", VK_GOTPCREL) + .Case("gotpcrel", VK_GOTPCREL) .Case("GOTTPOFF", VK_GOTTPOFF) + .Case("gottpoff", VK_GOTTPOFF) .Case("INDNTPOFF", VK_INDNTPOFF) + .Case("indntpoff", VK_INDNTPOFF) .Case("NTPOFF", VK_NTPOFF) + .Case("ntpoff", VK_NTPOFF) + .Case("GOTNTPOFF", VK_GOTNTPOFF) + .Case("gotntpoff", VK_GOTNTPOFF) .Case("PLT", VK_PLT) + .Case("plt", VK_PLT) .Case("TLSGD", VK_TLSGD) + .Case("tlsgd", VK_TLSGD) + .Case("TLSLD", VK_TLSLD) + .Case("tlsld", VK_TLSLD) + .Case("TLSLDM", VK_TLSLDM) + .Case("tlsldm", VK_TLSLDM) .Case("TPOFF", VK_TPOFF) + .Case("tpoff", VK_TPOFF) + .Case("DTPOFF", VK_DTPOFF) + .Case("dtpoff", VK_DTPOFF) .Case("TLVP", VK_TLVP) + .Case("tlvp", VK_TLVP) .Default(VK_Invalid); } @@ -203,7 +242,28 @@ void MCTargetExpr::Anchor() {} /* *** */ -bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAsmLayout *Layout) const { +bool MCExpr::EvaluateAsAbsolute(int64_t &Res) const { + return EvaluateAsAbsolute(Res, 0, 0, 0); +} + +bool MCExpr::EvaluateAsAbsolute(int64_t &Res, + const MCAsmLayout &Layout) const { + return EvaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, 0); +} + +bool MCExpr::EvaluateAsAbsolute(int64_t &Res, + const MCAsmLayout &Layout, + const SectionAddrMap &Addrs) const { + return EvaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, &Addrs); +} + +bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAssembler &Asm) const { + return EvaluateAsAbsolute(Res, &Asm, 0, 0); +} + +bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm, + const MCAsmLayout *Layout, + const SectionAddrMap *Addrs) const { MCValue Value; // Fast path constants. @@ -212,37 +272,159 @@ bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAsmLayout *Layout) const { return true; } - if (!EvaluateAsRelocatable(Value, Layout) || !Value.isAbsolute()) - return false; + // FIXME: The use if InSet = Addrs is a hack. Setting InSet causes us + // absolutize differences across sections and that is what the MachO writer + // uses Addrs for. + bool IsRelocatable = + EvaluateAsRelocatableImpl(Value, Asm, Layout, Addrs, /*InSet*/ Addrs); + // Record the current value. Res = Value.getConstant(); - return true; + + return IsRelocatable && Value.isAbsolute(); +} + +/// \brief Helper method for \see EvaluateSymbolAdd(). +static void AttemptToFoldSymbolOffsetDifference(const MCAssembler *Asm, + const MCAsmLayout *Layout, + const SectionAddrMap *Addrs, + bool InSet, + const MCSymbolRefExpr *&A, + const MCSymbolRefExpr *&B, + int64_t &Addend) { + if (!A || !B) + return; + + const MCSymbol &SA = A->getSymbol(); + const MCSymbol &SB = B->getSymbol(); + + if (SA.isUndefined() || SB.isUndefined()) + return; + + if (!Asm->getWriter().IsSymbolRefDifferenceFullyResolved(*Asm, A, B, InSet)) + return; + + MCSymbolData &AD = Asm->getSymbolData(SA); + MCSymbolData &BD = Asm->getSymbolData(SB); + + if (AD.getFragment() == BD.getFragment()) { + Addend += (AD.getOffset() - BD.getOffset()); + + // Clear the symbol expr pointers to indicate we have folded these + // operands. + A = B = 0; + return; + } + + if (!Layout) + return; + + const MCSectionData &SecA = *AD.getFragment()->getParent(); + const MCSectionData &SecB = *BD.getFragment()->getParent(); + + if ((&SecA != &SecB) && !Addrs) + return; + + // Eagerly evaluate. + Addend += (Layout->getSymbolOffset(&Asm->getSymbolData(A->getSymbol())) - + Layout->getSymbolOffset(&Asm->getSymbolData(B->getSymbol()))); + if (Addrs && (&SecA != &SecB)) + Addend += (Addrs->lookup(&SecA) - Addrs->lookup(&SecB)); + + // Clear the symbol expr pointers to indicate we have folded these + // operands. + A = B = 0; } -static bool EvaluateSymbolicAdd(const MCValue &LHS,const MCSymbolRefExpr *RHS_A, +/// \brief Evaluate the result of an add between (conceptually) two MCValues. +/// +/// This routine conceptually attempts to construct an MCValue: +/// Result = (Result_A - Result_B + Result_Cst) +/// from two MCValue's LHS and RHS where +/// Result = LHS + RHS +/// and +/// Result = (LHS_A - LHS_B + LHS_Cst) + (RHS_A - RHS_B + RHS_Cst). +/// +/// This routine attempts to aggresively fold the operands such that the result +/// is representable in an MCValue, but may not always succeed. +/// +/// \returns True on success, false if the result is not representable in an +/// MCValue. + +/// NOTE: It is really important to have both the Asm and Layout arguments. +/// They might look redundant, but this function can be used before layout +/// is done (see the object streamer for example) and having the Asm argument +/// lets us avoid relaxations early. +static bool EvaluateSymbolicAdd(const MCAssembler *Asm, + const MCAsmLayout *Layout, + const SectionAddrMap *Addrs, + bool InSet, + const MCValue &LHS,const MCSymbolRefExpr *RHS_A, const MCSymbolRefExpr *RHS_B, int64_t RHS_Cst, MCValue &Res) { - // We can't add or subtract two symbols. - if ((LHS.getSymA() && RHS_A) || - (LHS.getSymB() && RHS_B)) + // FIXME: This routine (and other evaluation parts) are *incredibly* sloppy + // about dealing with modifiers. This will ultimately bite us, one day. + const MCSymbolRefExpr *LHS_A = LHS.getSymA(); + const MCSymbolRefExpr *LHS_B = LHS.getSymB(); + int64_t LHS_Cst = LHS.getConstant(); + + // Fold the result constant immediately. + int64_t Result_Cst = LHS_Cst + RHS_Cst; + + assert((!Layout || Asm) && + "Must have an assembler object if layout is given!"); + + // If we have a layout, we can fold resolved differences. + if (Asm) { + // First, fold out any differences which are fully resolved. By + // reassociating terms in + // Result = (LHS_A - LHS_B + LHS_Cst) + (RHS_A - RHS_B + RHS_Cst). + // we have the four possible differences: + // (LHS_A - LHS_B), + // (LHS_A - RHS_B), + // (RHS_A - LHS_B), + // (RHS_A - RHS_B). + // Since we are attempting to be as aggresive as possible about folding, we + // attempt to evaluate each possible alternative. + AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, LHS_A, LHS_B, + Result_Cst); + AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, LHS_A, RHS_B, + Result_Cst); + AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, RHS_A, LHS_B, + Result_Cst); + AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, RHS_A, RHS_B, + Result_Cst); + } + + // We can't represent the addition or subtraction of two symbols. + if ((LHS_A && RHS_A) || (LHS_B && RHS_B)) return false; - const MCSymbolRefExpr *A = LHS.getSymA() ? LHS.getSymA() : RHS_A; - const MCSymbolRefExpr *B = LHS.getSymB() ? LHS.getSymB() : RHS_B; - if (B) { - // If we have a negated symbol, then we must have also have a non-negated - // symbol in order to encode the expression. We can do this check later to - // permit expressions which eventually fold to a representable form -- such - // as (a + (0 - b)) -- if necessary. - if (!A) - return false; - } - Res = MCValue::get(A, B, LHS.getConstant() + RHS_Cst); + // At this point, we have at most one additive symbol and one subtractive + // symbol -- find them. + const MCSymbolRefExpr *A = LHS_A ? LHS_A : RHS_A; + const MCSymbolRefExpr *B = LHS_B ? LHS_B : RHS_B; + + // If we have a negated symbol, then we must have also have a non-negated + // symbol in order to encode the expression. + if (B && !A) + return false; + + Res = MCValue::get(A, B, Result_Cst); return true; } bool MCExpr::EvaluateAsRelocatable(MCValue &Res, - const MCAsmLayout *Layout) const { + const MCAsmLayout &Layout) const { + return EvaluateAsRelocatableImpl(Res, &Layout.getAssembler(), &Layout, + 0, false); +} + +bool MCExpr::EvaluateAsRelocatableImpl(MCValue &Res, + const MCAssembler *Asm, + const MCAsmLayout *Layout, + const SectionAddrMap *Addrs, + bool InSet) const { ++stats::MCExprEvaluate; switch (getKind()) { @@ -258,26 +440,15 @@ bool MCExpr::EvaluateAsRelocatable(MCValue &Res, const MCSymbol &Sym = SRE->getSymbol(); // Evaluate recursively if this is a variable. - if (Sym.isVariable()) { - if (!Sym.getVariableValue()->EvaluateAsRelocatable(Res, Layout)) - return false; - - // Absolutize symbol differences between defined symbols when we have a - // layout object and the target requests it. - if (Layout && Res.getSymB() && - Layout->getAssembler().getBackend().hasAbsolutizedSet() && - Res.getSymA()->getSymbol().isDefined() && - Res.getSymB()->getSymbol().isDefined()) { - MCSymbolData &A = - Layout->getAssembler().getSymbolData(Res.getSymA()->getSymbol()); - MCSymbolData &B = - Layout->getAssembler().getSymbolData(Res.getSymB()->getSymbol()); - Res = MCValue::get(+ Layout->getSymbolAddress(&A) - - Layout->getSymbolAddress(&B) - + Res.getConstant()); - } - - return true; + if (Sym.isVariable() && SRE->getKind() == MCSymbolRefExpr::VK_None) { + bool Ret = Sym.getVariableValue()->EvaluateAsRelocatableImpl(Res, Asm, + Layout, + Addrs, + true); + // If we failed to simplify this to a constant, let the target + // handle it. + if (Ret && !Res.getSymA() && !Res.getSymB()) + return true; } Res = MCValue::get(SRE, 0, 0); @@ -288,7 +459,8 @@ bool MCExpr::EvaluateAsRelocatable(MCValue &Res, const MCUnaryExpr *AUE = cast(this); MCValue Value; - if (!AUE->getSubExpr()->EvaluateAsRelocatable(Value, Layout)) + if (!AUE->getSubExpr()->EvaluateAsRelocatableImpl(Value, Asm, Layout, + Addrs, InSet)) return false; switch (AUE->getOpcode()) { @@ -321,8 +493,10 @@ bool MCExpr::EvaluateAsRelocatable(MCValue &Res, const MCBinaryExpr *ABE = cast(this); MCValue LHSValue, RHSValue; - if (!ABE->getLHS()->EvaluateAsRelocatable(LHSValue, Layout) || - !ABE->getRHS()->EvaluateAsRelocatable(RHSValue, Layout)) + if (!ABE->getLHS()->EvaluateAsRelocatableImpl(LHSValue, Asm, Layout, + Addrs, InSet) || + !ABE->getRHS()->EvaluateAsRelocatableImpl(RHSValue, Asm, Layout, + Addrs, InSet)) return false; // We only support a few operations on non-constant expressions, handle @@ -333,13 +507,13 @@ bool MCExpr::EvaluateAsRelocatable(MCValue &Res, return false; case MCBinaryExpr::Sub: // Negate RHS and add. - return EvaluateSymbolicAdd(LHSValue, + return EvaluateSymbolicAdd(Asm, Layout, Addrs, InSet, LHSValue, RHSValue.getSymB(), RHSValue.getSymA(), -RHSValue.getConstant(), Res); case MCBinaryExpr::Add: - return EvaluateSymbolicAdd(LHSValue, + return EvaluateSymbolicAdd(Asm, Layout, Addrs, InSet, LHSValue, RHSValue.getSymA(), RHSValue.getSymB(), RHSValue.getConstant(), Res); diff --git a/lib/MC/MCLoggingStreamer.cpp b/lib/MC/MCLoggingStreamer.cpp index b96040abd0c1..012c7f62f8af 100644 --- a/lib/MC/MCLoggingStreamer.cpp +++ b/lib/MC/MCLoggingStreamer.cpp @@ -48,10 +48,14 @@ public: return Child->AddBlankLine(); } - virtual void SwitchSection(const MCSection *Section) { - CurSection = Section; - LogCall("SwitchSection"); - return Child->SwitchSection(Section); + virtual void ChangeSection(const MCSection *Section) { + LogCall("ChangeSection"); + return Child->ChangeSection(Section); + } + + virtual void InitSections() { + LogCall("InitSections"); + return Child->InitSections(); } virtual void EmitLabel(MCSymbol *Symbol) { @@ -64,11 +68,28 @@ public: return Child->EmitAssemblerFlag(Flag); } + virtual void EmitThumbFunc(MCSymbol *Func) { + LogCall("EmitThumbFunc"); + return Child->EmitThumbFunc(Func); + } + virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { LogCall("EmitAssignment"); return Child->EmitAssignment(Symbol, Value); } + virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { + LogCall("EmitWeakReference"); + return Child->EmitWeakReference(Alias, Symbol); + } + + virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label) { + LogCall("EmitDwarfAdvanceLineAddr"); + return Child->EmitDwarfAdvanceLineAddr(LineDelta, LastLabel, Label); + } + virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { LogCall("EmitSymbolAttribute"); return Child->EmitSymbolAttribute(Symbol, Attribute); @@ -132,14 +153,22 @@ public: return Child->EmitBytes(Data, AddrSpace); } - virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace){ + virtual void EmitValueImpl(const MCExpr *Value, unsigned Size, + bool isPCRel, unsigned AddrSpace){ LogCall("EmitValue"); - return Child->EmitValue(Value, Size, AddrSpace); + return Child->EmitValueImpl(Value, Size, isPCRel, AddrSpace); + } + + virtual void EmitULEB128Value(const MCExpr *Value, + unsigned AddrSpace = 0) { + LogCall("EmitULEB128Value"); + return Child->EmitULEB128Value(Value, AddrSpace); } - virtual void EmitIntValue(uint64_t Value, unsigned Size, unsigned AddrSpace) { - LogCall("EmitIntValue"); - return Child->EmitIntValue(Value, Size, AddrSpace); + virtual void EmitSLEB128Value(const MCExpr *Value, + unsigned AddrSpace = 0) { + LogCall("EmitSLEB128Value"); + return Child->EmitSLEB128Value(Value, AddrSpace); } virtual void EmitGPRel32Value(const MCExpr *Value) { @@ -178,12 +207,23 @@ public: return Child->EmitFileDirective(Filename); } - virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) { + virtual bool EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) { LogCall("EmitDwarfFileDirective", "FileNo:" + Twine(FileNo) + " Filename:" + Filename); return Child->EmitDwarfFileDirective(FileNo, Filename); } + virtual void EmitDwarfLocDirective(unsigned FileNo, unsigned Line, + unsigned Column, unsigned Flags, + unsigned Isa, unsigned Discriminator) { + LogCall("EmitDwarfLocDirective", + "FileNo:" + Twine(FileNo) + " Line:" + Twine(Line) + + " Column:" + Twine(Column) + " Flags:" + Twine(Flags) + + " Isa:" + Twine(Isa) + " Discriminator:" + Twine(Discriminator)); + return Child->EmitDwarfLocDirective(FileNo, Line, Column, Flags, + Isa, Discriminator); + } + virtual void EmitInstruction(const MCInst &Inst) { LogCall("EmitInstruction"); return Child->EmitInstruction(Inst); diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp index 671874df2c69..d1f9f5cd568e 100644 --- a/lib/MC/MCMachOStreamer.cpp +++ b/lib/MC/MCMachOStreamer.cpp @@ -20,9 +20,11 @@ #include "llvm/MC/MCMachOSymbolFlags.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCDwarf.h" +#include "llvm/Support/Dwarf.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetAsmBackend.h" +#include "llvm/Target/TargetAsmInfo.h" using namespace llvm; @@ -30,13 +32,7 @@ namespace { class MCMachOStreamer : public MCObjectStreamer { private: - void EmitInstToFragment(const MCInst &Inst); - void EmitInstToData(const MCInst &Inst); - // FIXME: These will likely moved to a better place. - void MakeLineEntryForSection(const MCSection *Section); - const MCExpr * MakeStartMinusEndExpr(MCSymbol *Start, MCSymbol *End, - int IntVal); - void EmitDwarfFileTable(void); + virtual void EmitInstToData(const MCInst &Inst); public: MCMachOStreamer(MCContext &Context, TargetAsmBackend &TAB, @@ -46,8 +42,10 @@ public: /// @name MCStreamer Interface /// @{ + virtual void InitSections(); virtual void EmitLabel(MCSymbol *Symbol); virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); + virtual void EmitThumbFunc(MCSymbol *Func); virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue); @@ -76,17 +74,11 @@ public: virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment = 0); virtual void EmitBytes(StringRef Data, unsigned AddrSpace); - virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace); - virtual void EmitGPRel32Value(const MCExpr *Value) { - assert(0 && "macho doesn't support this directive"); - } virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, unsigned ValueSize = 1, unsigned MaxBytesToEmit = 0); virtual void EmitCodeAlignment(unsigned ByteAlignment, unsigned MaxBytesToEmit = 0); - virtual void EmitValueToOffset(const MCExpr *Offset, - unsigned char Value = 0); virtual void EmitFileDirective(StringRef Filename) { // FIXME: Just ignore the .file; it isn't important enough to fail the @@ -94,14 +86,6 @@ public: //report_fatal_error("unsupported directive: '.file'"); } - virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) { - // FIXME: Just ignore the .file; it isn't important enough to fail the - // entire assembly. - - //report_fatal_error("unsupported directive: '.file'"); - } - - virtual void EmitInstruction(const MCInst &Inst); virtual void Finish(); @@ -110,31 +94,26 @@ public: } // end anonymous namespace. -void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) { - // TODO: This is almost exactly the same as WinCOFFStreamer. Consider merging - // into MCObjectStreamer. - assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); - assert(!Symbol->isVariable() && "Cannot emit a variable symbol!"); - assert(CurSection && "Cannot emit before setting section!"); +void MCMachOStreamer::InitSections() { + SwitchSection(getContext().getMachOSection("__TEXT", "__text", + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + 0, SectionKind::getText())); - Symbol->setSection(*CurSection); +} - MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); +void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) { + assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); + // isSymbolLinkerVisible uses the section. + Symbol->setSection(*getCurrentSection()); // We have to create a new fragment if this is an atom defining symbol, // fragments cannot span atoms. - if (getAssembler().isSymbolLinkerVisible(SD.getSymbol())) + if (getAssembler().isSymbolLinkerVisible(*Symbol)) new MCDataFragment(getCurrentSectionData()); - // FIXME: This is wasteful, we don't necessarily need to create a data - // fragment. Instead, we should mark the symbol as pointing into the data - // fragment if it exists, otherwise we should just queue the label and set its - // fragment pointer when we emit the next fragment. - MCDataFragment *F = getOrCreateDataFragment(); - assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); - SD.setFragment(F); - SD.setOffset(F->getContents().size()); + MCObjectStreamer::EmitLabel(Symbol); + MCSymbolData &SD = getAssembler().getSymbolData(*Symbol); // This causes the reference type flag to be cleared. Darwin 'as' was "trying" // to clear the weak reference and weak definition bits too, but the // implementation was buggy. For now we just try to match 'as', for @@ -146,13 +125,31 @@ void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) { } void MCMachOStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { + // Let the target do whatever target specific stuff it needs to do. + getAssembler().getBackend().HandleAssemblerFlag(Flag); + // Do any generic stuff we need to do. switch (Flag) { + case MCAF_SyntaxUnified: return; // no-op here. + case MCAF_Code16: return; // no-op here. + case MCAF_Code32: return; // no-op here. case MCAF_SubsectionsViaSymbols: getAssembler().setSubsectionsViaSymbols(true); return; + default: + llvm_unreachable("invalid assembler flag!"); } +} + +void MCMachOStreamer::EmitThumbFunc(MCSymbol *Symbol) { + // FIXME: Flag the function ISA as thumb with DW_AT_APPLE_isa. - assert(0 && "invalid assembler flag!"); + // Remember that the function is a thumb function. Fixup and relocation + // values will need adjusted. + getAssembler().setIsThumbFunc(Symbol); + + // Mark the thumb bit on the symbol. + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + SD.setFlags(SD.getFlags() | SF_ThumbFunc); } void MCMachOStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { @@ -196,6 +193,7 @@ void MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol, case MCSA_ELF_TypeTLS: case MCSA_ELF_TypeCommon: case MCSA_ELF_TypeNoType: + case MCSA_ELF_TypeGnuUniqueObject: case MCSA_IndirectSymbol: case MCSA_Hidden: case MCSA_Internal: @@ -230,6 +228,10 @@ void MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol, SD.setFlags(SD.getFlags() | SF_NoDeadStrip); break; + case MCSA_SymbolResolver: + SD.setFlags(SD.getFlags() | SF_SymbolResolver); + break; + case MCSA_PrivateExtern: SD.setExternal(true); SD.setPrivateExtern(true); @@ -313,26 +315,6 @@ void MCMachOStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end()); } -void MCMachOStreamer::EmitValue(const MCExpr *Value, unsigned Size, - unsigned AddrSpace) { - // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into - // MCObjectStreamer. - MCDataFragment *DF = getOrCreateDataFragment(); - - // Avoid fixups when possible. - int64_t AbsValue; - if (AddValueSymbols(Value)->EvaluateAsAbsolute(AbsValue)) { - // FIXME: Endianness assumption. - for (unsigned i = 0; i != Size; ++i) - DF->getContents().push_back(uint8_t(AbsValue >> (i * 8))); - } else { - DF->addFixup(MCFixup::Create(DF->getContents().size(), - AddValueSymbols(Value), - MCFixup::getKindForSize(Size))); - DF->getContents().resize(DF->getContents().size() + Size, 0); - } -} - void MCMachOStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, unsigned ValueSize, unsigned MaxBytesToEmit) { @@ -363,28 +345,6 @@ void MCMachOStreamer::EmitCodeAlignment(unsigned ByteAlignment, getCurrentSectionData()->setAlignment(ByteAlignment); } -void MCMachOStreamer::EmitValueToOffset(const MCExpr *Offset, - unsigned char Value) { - new MCOrgFragment(*Offset, Value, getCurrentSectionData()); -} - -void MCMachOStreamer::EmitInstToFragment(const MCInst &Inst) { - MCInstFragment *IF = new MCInstFragment(Inst, getCurrentSectionData()); - - // Add the fixups and data. - // - // FIXME: Revisit this design decision when relaxation is done, we may be - // able to get away with not storing any extra data in the MCInst. - SmallVector Fixups; - SmallString<256> Code; - raw_svector_ostream VecOS(Code); - getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups); - VecOS.flush(); - - IF->getCode() = Code; - IF->getFixups() = Fixups; -} - void MCMachOStreamer::EmitInstToData(const MCInst &Inst) { MCDataFragment *DF = getOrCreateDataFragment(); @@ -402,240 +362,7 @@ void MCMachOStreamer::EmitInstToData(const MCInst &Inst) { DF->getContents().append(Code.begin(), Code.end()); } -void MCMachOStreamer::EmitInstruction(const MCInst &Inst) { - // Scan for values. - for (unsigned i = Inst.getNumOperands(); i--; ) - if (Inst.getOperand(i).isExpr()) - AddValueSymbols(Inst.getOperand(i).getExpr()); - - getCurrentSectionData()->setHasInstructions(true); - - // Now that a machine instruction has been assembled into this section, make - // a line entry for any .loc directive that has been seen. - MakeLineEntryForSection(getCurrentSection()); - - // If this instruction doesn't need relaxation, just emit it as data. - if (!getAssembler().getBackend().MayNeedRelaxation(Inst)) { - EmitInstToData(Inst); - return; - } - - // Otherwise, if we are relaxing everything, relax the instruction as much as - // possible and emit it as data. - if (getAssembler().getRelaxAll()) { - MCInst Relaxed; - getAssembler().getBackend().RelaxInstruction(Inst, Relaxed); - while (getAssembler().getBackend().MayNeedRelaxation(Relaxed)) - getAssembler().getBackend().RelaxInstruction(Relaxed, Relaxed); - EmitInstToData(Relaxed); - return; - } - - // Otherwise emit to a separate fragment. - EmitInstToFragment(Inst); -} - -// -// This is called when an instruction is assembled into the specified section -// and if there is information from the last .loc directive that has yet to have -// a line entry made for it is made. -// -void MCMachOStreamer::MakeLineEntryForSection(const MCSection *Section) { - if (!getContext().getDwarfLocSeen()) - return; - - // Create a symbol at in the current section for use in the line entry. - MCSymbol *LineSym = getContext().CreateTempSymbol(); - // Set the value of the symbol to use for the MCLineEntry. - EmitLabel(LineSym); - - // Get the current .loc info saved in the context. - const MCDwarfLoc &DwarfLoc = getContext().getCurrentDwarfLoc(); - - // Create a (local) line entry with the symbol and the current .loc info. - MCLineEntry LineEntry(LineSym, DwarfLoc); - - // clear DwarfLocSeen saying the current .loc info is now used. - getContext().clearDwarfLocSeen(); - - // Get the MCLineSection for this section, if one does not exist for this - // section create it. - DenseMap &MCLineSections = - getContext().getMCLineSections(); - MCLineSection *LineSection = MCLineSections[Section]; - if (!LineSection) { - // Create a new MCLineSection. This will be deleted after the dwarf line - // table is created using it by iterating through the MCLineSections - // DenseMap. - LineSection = new MCLineSection; - // Save a pointer to the new LineSection into the MCLineSections DenseMap. - MCLineSections[Section] = LineSection; - } - - // Add the line entry to this section's entries. - LineSection->addLineEntry(LineEntry); -} - -// -// This helper routine returns an expression of End - Start + IntVal for use -// by EmitDwarfFileTable() below. -// -const MCExpr * MCMachOStreamer::MakeStartMinusEndExpr(MCSymbol *Start, - MCSymbol *End, - int IntVal) { - MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; - const MCExpr *Res = - MCSymbolRefExpr::Create(End, Variant, getContext()); - const MCExpr *RHS = - MCSymbolRefExpr::Create(Start, Variant, getContext()); - const MCExpr *Res1 = - MCBinaryExpr::Create(MCBinaryExpr::Sub, Res, RHS,getContext()); - const MCExpr *Res2 = - MCConstantExpr::Create(IntVal, getContext()); - const MCExpr *Res3 = - MCBinaryExpr::Create(MCBinaryExpr::Sub, Res1, Res2, getContext()); - return Res3; -} - -// -// This emits the Dwarf file (and eventually the line) table. -// -void MCMachOStreamer::EmitDwarfFileTable(void) { - // For now make sure we don't put out the Dwarf file table if no .file - // directives were seen. - const std::vector &MCDwarfFiles = - getContext().getMCDwarfFiles(); - if (MCDwarfFiles.size() == 0) - return; - - // This is the Mach-O section, for ELF it is the .debug_line section. - SwitchSection(getContext().getMachOSection("__DWARF", "__debug_line", - MCSectionMachO::S_ATTR_DEBUG, - 0, SectionKind::getDataRelLocal())); - - // Create a symbol at the beginning of this section. - MCSymbol *LineStartSym = getContext().CreateTempSymbol(); - // Set the value of the symbol, as we are at the start of the section. - EmitLabel(LineStartSym); - - // Create a symbol for the end of the section (to be set when we get there). - MCSymbol *LineEndSym = getContext().CreateTempSymbol(); - - // The first 4 bytes is the total length of the information for this - // compilation unit (not including these 4 bytes for the length). - EmitValue(MakeStartMinusEndExpr(LineStartSym, LineEndSym, 4), 4, 0); - - // Next 2 bytes is the Version, which is Dwarf 2. - EmitIntValue(2, 2); - - // Create a symbol for the end of the prologue (to be set when we get there). - MCSymbol *ProEndSym = getContext().CreateTempSymbol(); // Lprologue_end - - // Length of the prologue, is the next 4 bytes. Which is the start of the - // section to the end of the prologue. Not including the 4 bytes for the - // total length, the 2 bytes for the version, and these 4 bytes for the - // length of the prologue. - EmitValue(MakeStartMinusEndExpr(LineStartSym, ProEndSym, (4 + 2 + 4)), 4, 0); - - // Parameters of the state machine, are next. - // Define the architecture-dependent minimum instruction length (in - // bytes). This value should be rather too small than too big. */ - // DWARF2_LINE_MIN_INSN_LENGTH - EmitIntValue(1, 1); - // Flag that indicates the initial value of the is_stmt_start flag. - // DWARF2_LINE_DEFAULT_IS_STMT - EmitIntValue(1, 1); - // Minimum line offset in a special line info. opcode. This value - // was chosen to give a reasonable range of values. */ - // DWARF2_LINE_BASE - EmitIntValue(uint64_t(-5), 1); - // Range of line offsets in a special line info. opcode. - // DWARF2_LINE_RANGE - EmitIntValue(14, 1); - // First special line opcode - leave room for the standard opcodes. - // DWARF2_LINE_OPCODE_BASE - EmitIntValue(13, 1); - - // Standard opcode lengths - EmitIntValue(0, 1); // length of DW_LNS_copy - EmitIntValue(1, 1); // length of DW_LNS_advance_pc - EmitIntValue(1, 1); // length of DW_LNS_advance_line - EmitIntValue(1, 1); // length of DW_LNS_set_file - EmitIntValue(1, 1); // length of DW_LNS_set_column - EmitIntValue(0, 1); // length of DW_LNS_negate_stmt - EmitIntValue(0, 1); // length of DW_LNS_set_basic_block - EmitIntValue(0, 1); // length of DW_LNS_const_add_pc - EmitIntValue(1, 1); // length of DW_LNS_fixed_advance_pc - EmitIntValue(0, 1); // length of DW_LNS_set_prologue_end - EmitIntValue(0, 1); // length of DW_LNS_set_epilogue_begin - EmitIntValue(1, 1); // DW_LNS_set_isa - - // Put out the directory and file tables. - - // First the directory table. - const std::vector &MCDwarfDirs = - getContext().getMCDwarfDirs(); - for (unsigned i = 0; i < MCDwarfDirs.size(); i++) { - EmitBytes(MCDwarfDirs[i], 0); // the DirectoryName - EmitBytes(StringRef("\0", 1), 0); // the null termination of the string - } - EmitIntValue(0, 1); // Terminate the directory list - - // Second the file table. - for (unsigned i = 1; i < MCDwarfFiles.size(); i++) { - EmitBytes(MCDwarfFiles[i]->getName(), 0); // FileName - EmitBytes(StringRef("\0", 1), 0); // the null termination of the string - // FIXME the Directory number should be a .uleb128 not a .byte - EmitIntValue(MCDwarfFiles[i]->getDirIndex(), 1); - EmitIntValue(0, 1); // last modification timestamp (always 0) - EmitIntValue(0, 1); // filesize (always 0) - } - EmitIntValue(0, 1); // Terminate the file list - - // This is the end of the prologue, so set the value of the symbol at the - // end of the prologue (that was used in a previous expression). - EmitLabel(ProEndSym); - - // TODO: This is the point where the line tables would be emitted. - - // Delete the MCLineSections that were created in - // MCMachOStreamer::MakeLineEntryForSection() and used to emit the line - // tables. - DenseMap &MCLineSections = - getContext().getMCLineSections(); - for (DenseMap::iterator it = - MCLineSections.begin(), ie = MCLineSections.end(); it != ie; ++it) { - delete it->second; - } - - // If there are no line tables emited then we emit: - // The following DW_LNE_set_address sequence to set the address to zero - // TODO test for 32-bit or 64-bit output - // This is the sequence for 32-bit code - EmitIntValue(0, 1); - EmitIntValue(5, 1); - EmitIntValue(2, 1); - EmitIntValue(0, 1); - EmitIntValue(0, 1); - EmitIntValue(0, 1); - EmitIntValue(0, 1); - - // Lastly emit the DW_LNE_end_sequence which consists of 3 bytes '00 01 01' - // (00 is the code for extended opcodes, followed by a ULEB128 length of the - // extended opcode (01), and the DW_LNE_end_sequence (01). - EmitIntValue(0, 1); // DW_LNS_extended_op - EmitIntValue(1, 1); // ULEB128 length of the extended opcode - EmitIntValue(1, 1); // DW_LNE_end_sequence - - // This is the end of the section, so set the value of the symbol at the end - // of this section (that was used in a previous expression). - EmitLabel(LineEndSym); -} - void MCMachOStreamer::Finish() { - // Dump out the dwarf file and directory tables (soon to include line table) - EmitDwarfFileTable(); - // We have to set the fragment atom associations so we can relax properly for // Mach-O. diff --git a/lib/MC/MCMachObjectTargetWriter.cpp b/lib/MC/MCMachObjectTargetWriter.cpp new file mode 100644 index 000000000000..146cebf01a3a --- /dev/null +++ b/lib/MC/MCMachObjectTargetWriter.cpp @@ -0,0 +1,22 @@ +//===-- MCMachObjectTargetWriter.cpp - Mach-O Target Writer Subclass ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCMachObjectWriter.h" + +using namespace llvm; + +MCMachObjectTargetWriter::MCMachObjectTargetWriter( + bool Is64Bit_, uint32_t CPUType_, uint32_t CPUSubtype_, + bool UseAggressiveSymbolFolding_) + : Is64Bit(Is64Bit_), CPUType(CPUType_), CPUSubtype(CPUSubtype_), + UseAggressiveSymbolFolding(UseAggressiveSymbolFolding_) { +} + +MCMachObjectTargetWriter::~MCMachObjectTargetWriter() { +} diff --git a/lib/MC/MCNullStreamer.cpp b/lib/MC/MCNullStreamer.cpp index f7a2f20ca4bc..08ddf01d1a36 100644 --- a/lib/MC/MCNullStreamer.cpp +++ b/lib/MC/MCNullStreamer.cpp @@ -25,20 +25,26 @@ namespace { /// @name MCStreamer Interface /// @{ - virtual void SwitchSection(const MCSection *Section) { - PrevSection = CurSection; - CurSection = Section; + virtual void InitSections() { + } + + virtual void ChangeSection(const MCSection *Section) { } virtual void EmitLabel(MCSymbol *Symbol) { assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); - assert(CurSection && "Cannot emit before setting section!"); - Symbol->setSection(*CurSection); + assert(getCurrentSection() && "Cannot emit before setting section!"); + Symbol->setSection(*getCurrentSection()); } virtual void EmitAssemblerFlag(MCAssemblerFlag Flag) {} + virtual void EmitThumbFunc(MCSymbol *Func) {} virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {} + virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol){} + virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label) {} virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute){} @@ -60,8 +66,12 @@ namespace { uint64_t Size, unsigned ByteAlignment) {} virtual void EmitBytes(StringRef Data, unsigned AddrSpace) {} - virtual void EmitValue(const MCExpr *Value, unsigned Size, - unsigned AddrSpace) {} + virtual void EmitValueImpl(const MCExpr *Value, unsigned Size, + bool isPCRel, unsigned AddrSpace) {} + virtual void EmitULEB128Value(const MCExpr *Value, + unsigned AddrSpace = 0) {} + virtual void EmitSLEB128Value(const MCExpr *Value, + unsigned AddrSpace = 0) {} virtual void EmitGPRel32Value(const MCExpr *Value) {} virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, unsigned ValueSize = 1, @@ -74,7 +84,12 @@ namespace { unsigned char Value = 0) {} virtual void EmitFileDirective(StringRef Filename) {} - virtual void EmitDwarfFileDirective(unsigned FileNo,StringRef Filename) {} + virtual bool EmitDwarfFileDirective(unsigned FileNo,StringRef Filename) { + return false; + } + virtual void EmitDwarfLocDirective(unsigned FileNo, unsigned Line, + unsigned Column, unsigned Flags, + unsigned Isa, unsigned Discriminator) {} virtual void EmitInstruction(const MCInst &Inst) {} virtual void Finish() {} diff --git a/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp index 2b2385ef9156..035826690cdf 100644 --- a/lib/MC/MCObjectStreamer.cpp +++ b/lib/MC/MCObjectStreamer.cpp @@ -7,19 +7,26 @@ // //===----------------------------------------------------------------------===// +#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCObjectStreamer.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCSymbol.h" #include "llvm/Target/TargetAsmBackend.h" +#include "llvm/Target/TargetAsmInfo.h" using namespace llvm; MCObjectStreamer::MCObjectStreamer(MCContext &Context, TargetAsmBackend &TAB, - raw_ostream &_OS, MCCodeEmitter *_Emitter) - : MCStreamer(Context), Assembler(new MCAssembler(Context, TAB, - *_Emitter, _OS)), + raw_ostream &OS, MCCodeEmitter *Emitter_) + : MCStreamer(Context), + Assembler(new MCAssembler(Context, TAB, + *Emitter_, *TAB.createObjectWriter(OS), + OS)), CurSectionData(0) { } @@ -27,6 +34,7 @@ MCObjectStreamer::MCObjectStreamer(MCContext &Context, TargetAsmBackend &TAB, MCObjectStreamer::~MCObjectStreamer() { delete &Assembler->getBackend(); delete &Assembler->getEmitter(); + delete &Assembler->getWriter(); delete Assembler; } @@ -48,7 +56,10 @@ MCDataFragment *MCObjectStreamer::getOrCreateDataFragment() const { const MCExpr *MCObjectStreamer::AddValueSymbols(const MCExpr *Value) { switch (Value->getKind()) { - case MCExpr::Target: llvm_unreachable("Can't handle target exprs yet!"); + case MCExpr::Target: + cast(Value)->AddValueSymbols(Assembler); + break; + case MCExpr::Constant: break; @@ -71,17 +82,173 @@ const MCExpr *MCObjectStreamer::AddValueSymbols(const MCExpr *Value) { return Value; } -void MCObjectStreamer::SwitchSection(const MCSection *Section) { - assert(Section && "Cannot switch to a null section!"); +void MCObjectStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, + bool isPCRel, unsigned AddrSpace) { + assert(AddrSpace == 0 && "Address space must be 0!"); + MCDataFragment *DF = getOrCreateDataFragment(); + + // Avoid fixups when possible. + int64_t AbsValue; + if (AddValueSymbols(Value)->EvaluateAsAbsolute(AbsValue, getAssembler())) { + EmitIntValue(AbsValue, Size, AddrSpace); + return; + } + DF->addFixup(MCFixup::Create(DF->getContents().size(), + Value, + MCFixup::getKindForSize(Size, isPCRel))); + DF->getContents().resize(DF->getContents().size() + Size, 0); +} + +void MCObjectStreamer::EmitLabel(MCSymbol *Symbol) { + assert(!Symbol->isVariable() && "Cannot emit a variable symbol!"); + assert(getCurrentSection() && "Cannot emit before setting section!"); + + Symbol->setSection(*getCurrentSection()); + + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + + // FIXME: This is wasteful, we don't necessarily need to create a data + // fragment. Instead, we should mark the symbol as pointing into the data + // fragment if it exists, otherwise we should just queue the label and set its + // fragment pointer when we emit the next fragment. + MCDataFragment *F = getOrCreateDataFragment(); + assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); + SD.setFragment(F); + SD.setOffset(F->getContents().size()); +} + +void MCObjectStreamer::EmitULEB128Value(const MCExpr *Value, + unsigned AddrSpace) { + int64_t IntValue; + if (Value->EvaluateAsAbsolute(IntValue, getAssembler())) { + EmitULEB128IntValue(IntValue, AddrSpace); + return; + } + new MCLEBFragment(*Value, false, getCurrentSectionData()); +} + +void MCObjectStreamer::EmitSLEB128Value(const MCExpr *Value, + unsigned AddrSpace) { + int64_t IntValue; + if (Value->EvaluateAsAbsolute(IntValue, getAssembler())) { + EmitSLEB128IntValue(IntValue, AddrSpace); + return; + } + new MCLEBFragment(*Value, true, getCurrentSectionData()); +} + +void MCObjectStreamer::EmitWeakReference(MCSymbol *Alias, + const MCSymbol *Symbol) { + report_fatal_error("This file format doesn't support weak aliases."); +} - // If already in this section, then this is a noop. - if (Section == CurSection) return; +void MCObjectStreamer::ChangeSection(const MCSection *Section) { + assert(Section && "Cannot switch to a null section!"); - PrevSection = CurSection; - CurSection = Section; CurSectionData = &getAssembler().getOrCreateSectionData(*Section); } +void MCObjectStreamer::EmitInstruction(const MCInst &Inst) { + // Scan for values. + for (unsigned i = Inst.getNumOperands(); i--; ) + if (Inst.getOperand(i).isExpr()) + AddValueSymbols(Inst.getOperand(i).getExpr()); + + getCurrentSectionData()->setHasInstructions(true); + + // Now that a machine instruction has been assembled into this section, make + // a line entry for any .loc directive that has been seen. + MCLineEntry::Make(this, getCurrentSection()); + + // If this instruction doesn't need relaxation, just emit it as data. + if (!getAssembler().getBackend().MayNeedRelaxation(Inst)) { + EmitInstToData(Inst); + return; + } + + // Otherwise, if we are relaxing everything, relax the instruction as much as + // possible and emit it as data. + if (getAssembler().getRelaxAll()) { + MCInst Relaxed; + getAssembler().getBackend().RelaxInstruction(Inst, Relaxed); + while (getAssembler().getBackend().MayNeedRelaxation(Relaxed)) + getAssembler().getBackend().RelaxInstruction(Relaxed, Relaxed); + EmitInstToData(Relaxed); + return; + } + + // Otherwise emit to a separate fragment. + EmitInstToFragment(Inst); +} + +void MCObjectStreamer::EmitInstToFragment(const MCInst &Inst) { + MCInstFragment *IF = new MCInstFragment(Inst, getCurrentSectionData()); + + raw_svector_ostream VecOS(IF->getCode()); + getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, IF->getFixups()); +} + +static const MCExpr *BuildSymbolDiff(MCContext &Context, + const MCSymbol *A, const MCSymbol *B) { + MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; + const MCExpr *ARef = + MCSymbolRefExpr::Create(A, Variant, Context); + const MCExpr *BRef = + MCSymbolRefExpr::Create(B, Variant, Context); + const MCExpr *AddrDelta = + MCBinaryExpr::Create(MCBinaryExpr::Sub, ARef, BRef, Context); + return AddrDelta; +} + +static const MCExpr *ForceExpAbs(MCObjectStreamer *Streamer, + MCContext &Context, const MCExpr* Expr) { + if (Context.getAsmInfo().hasAggressiveSymbolFolding()) + return Expr; + + MCSymbol *ABS = Context.CreateTempSymbol(); + Streamer->EmitAssignment(ABS, Expr); + return MCSymbolRefExpr::Create(ABS, Context); +} + +void MCObjectStreamer::EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label) { + if (!LastLabel) { + int PointerSize = getContext().getTargetAsmInfo().getPointerSize(); + EmitDwarfSetLineAddr(LineDelta, Label, PointerSize); + return; + } + const MCExpr *AddrDelta = BuildSymbolDiff(getContext(), Label, LastLabel); + int64_t Res; + if (AddrDelta->EvaluateAsAbsolute(Res, getAssembler())) { + MCDwarfLineAddr::Emit(this, LineDelta, Res); + return; + } + AddrDelta = ForceExpAbs(this, getContext(), AddrDelta); + new MCDwarfLineAddrFragment(LineDelta, *AddrDelta, getCurrentSectionData()); +} + +void MCObjectStreamer::EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel, + const MCSymbol *Label) { + const MCExpr *AddrDelta = BuildSymbolDiff(getContext(), Label, LastLabel); + int64_t Res; + if (AddrDelta->EvaluateAsAbsolute(Res, getAssembler())) { + MCDwarfFrameEmitter::EmitAdvanceLoc(*this, Res); + return; + } + AddrDelta = ForceExpAbs(this, getContext(), AddrDelta); + new MCDwarfCallFrameFragment(*AddrDelta, getCurrentSectionData()); +} + +void MCObjectStreamer::EmitValueToOffset(const MCExpr *Offset, + unsigned char Value) { + new MCOrgFragment(*Offset, Value, getCurrentSectionData()); +} + void MCObjectStreamer::Finish() { + // Dump out the dwarf file & directory tables and line tables. + if (getContext().hasDwarfFiles()) + MCDwarfFileTable::Emit(this); + getAssembler().Finish(); } diff --git a/lib/MC/MCObjectWriter.cpp b/lib/MC/MCObjectWriter.cpp index d117e82b8a1f..efe9f68ee22b 100644 --- a/lib/MC/MCObjectWriter.cpp +++ b/lib/MC/MCObjectWriter.cpp @@ -7,9 +7,74 @@ // //===----------------------------------------------------------------------===// +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSymbol.h" using namespace llvm; MCObjectWriter::~MCObjectWriter() { } + +/// Utility function to encode a SLEB128 value. +void MCObjectWriter::EncodeSLEB128(int64_t Value, raw_ostream &OS) { + bool More; + do { + uint8_t Byte = Value & 0x7f; + // NOTE: this assumes that this signed shift is an arithmetic right shift. + Value >>= 7; + More = !((((Value == 0 ) && ((Byte & 0x40) == 0)) || + ((Value == -1) && ((Byte & 0x40) != 0)))); + if (More) + Byte |= 0x80; // Mark this byte that that more bytes will follow. + OS << char(Byte); + } while (More); +} + +/// Utility function to encode a ULEB128 value. +void MCObjectWriter::EncodeULEB128(uint64_t Value, raw_ostream &OS) { + do { + uint8_t Byte = Value & 0x7f; + Value >>= 7; + if (Value != 0) + Byte |= 0x80; // Mark this byte that that more bytes will follow. + OS << char(Byte); + } while (Value != 0); +} + +bool +MCObjectWriter::IsSymbolRefDifferenceFullyResolved(const MCAssembler &Asm, + const MCSymbolRefExpr *A, + const MCSymbolRefExpr *B, + bool InSet) const { + // Modified symbol references cannot be resolved. + if (A->getKind() != MCSymbolRefExpr::VK_None || + B->getKind() != MCSymbolRefExpr::VK_None) + return false; + + const MCSymbol &SA = A->getSymbol(); + const MCSymbol &SB = B->getSymbol(); + if (SA.AliasedSymbol().isUndefined() || SB.AliasedSymbol().isUndefined()) + return false; + + const MCSymbolData &DataA = Asm.getSymbolData(SA); + const MCSymbolData &DataB = Asm.getSymbolData(SB); + + return IsSymbolRefDifferenceFullyResolvedImpl(Asm, DataA, + *DataB.getFragment(), + InSet, + false); +} + +bool +MCObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, + const MCSymbolData &DataA, + const MCFragment &FB, + bool InSet, + bool IsPCRel) const { + const MCSection &SecA = DataA.getSymbol().AliasedSymbol().getSection(); + const MCSection &SecB = FB.getParent()->getSection(); + // On ELF and COFF A - B is absolute if A and B are in the same section. + return &SecA == &SecB; +} diff --git a/lib/MC/MCParser/AsmLexer.cpp b/lib/MC/MCParser/AsmLexer.cpp index 086df081a938..89374d0c3fb9 100644 --- a/lib/MC/MCParser/AsmLexer.cpp +++ b/lib/MC/MCParser/AsmLexer.cpp @@ -15,6 +15,7 @@ #include "llvm/Support/SMLoc.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/MC/MCAsmInfo.h" +#include #include #include #include @@ -30,12 +31,12 @@ AsmLexer::~AsmLexer() { void AsmLexer::setBuffer(const MemoryBuffer *buf, const char *ptr) { CurBuf = buf; - + if (ptr) CurPtr = ptr; else CurPtr = CurBuf->getBufferStart(); - + TokStart = 0; } @@ -43,7 +44,7 @@ void AsmLexer::setBuffer(const MemoryBuffer *buf, const char *ptr) { /// location. This is defined to always return AsmToken::Error. AsmToken AsmLexer::ReturnError(const char *Loc, const std::string &Msg) { SetError(SMLoc::getFromPointer(Loc), Msg); - + return AsmToken(AsmToken::Error, StringRef(Loc, 0)); } @@ -57,23 +58,59 @@ int AsmLexer::getNextChar() { // a random nul in the file. Disambiguate that here. if (CurPtr-1 != CurBuf->getBufferEnd()) return 0; // Just whitespace. - + // Otherwise, return end of file. - --CurPtr; // Another call to lex will return EOF again. + --CurPtr; // Another call to lex will return EOF again. return EOF; } } +/// LexFloatLiteral: [0-9]*[.][0-9]*([eE][+-]?[0-9]*)? +/// +/// The leading integral digit sequence and dot should have already been +/// consumed, some or all of the fractional digit sequence *can* have been +/// consumed. +AsmToken AsmLexer::LexFloatLiteral() { + // Skip the fractional digit sequence. + while (isdigit(*CurPtr)) + ++CurPtr; + + // Check for exponent; we intentionally accept a slighlty wider set of + // literals here and rely on the upstream client to reject invalid ones (e.g., + // "1e+"). + if (*CurPtr == 'e' || *CurPtr == 'E') { + ++CurPtr; + if (*CurPtr == '-' || *CurPtr == '+') + ++CurPtr; + while (isdigit(*CurPtr)) + ++CurPtr; + } + + return AsmToken(AsmToken::Real, + StringRef(TokStart, CurPtr - TokStart)); +} + /// LexIdentifier: [a-zA-Z_.][a-zA-Z0-9_$.@]* +static bool IsIdentifierChar(char c) { + return isalnum(c) || c == '_' || c == '$' || c == '.' || c == '@'; +} AsmToken AsmLexer::LexIdentifier() { - while (isalnum(*CurPtr) || *CurPtr == '_' || *CurPtr == '$' || - *CurPtr == '.' || *CurPtr == '@') + // Check for floating point literals. + if (CurPtr[-1] == '.' && isdigit(*CurPtr)) { + // Disambiguate a .1243foo identifier from a floating literal. + while (isdigit(*CurPtr)) + ++CurPtr; + if (*CurPtr == 'e' || *CurPtr == 'E' || !IsIdentifierChar(*CurPtr)) + return LexFloatLiteral(); + } + + while (IsIdentifierChar(*CurPtr)) ++CurPtr; - + // Handle . as a special case. if (CurPtr == TokStart+1 && TokStart[0] == '.') return AsmToken(AsmToken::Dot, StringRef(TokStart, 1)); - + return AsmToken(AsmToken::Identifier, StringRef(TokStart, CurPtr - TokStart)); } @@ -83,7 +120,7 @@ AsmToken AsmLexer::LexSlash() { switch (*CurPtr) { case '*': break; // C style comment. case '/': return ++CurPtr, LexLineComment(); - default: return AsmToken(AsmToken::Slash, StringRef(CurPtr, 1)); + default: return AsmToken(AsmToken::Slash, StringRef(CurPtr-1, 1)); } // C Style comment. @@ -96,7 +133,7 @@ AsmToken AsmLexer::LexSlash() { case '*': // End of the comment? if (CurPtr[0] != '/') break; - + ++CurPtr; // End the */. return LexToken(); } @@ -111,7 +148,7 @@ AsmToken AsmLexer::LexLineComment() { int CurChar = getNextChar(); while (CurChar != '\n' && CurChar != '\n' && CurChar != EOF) CurChar = getNextChar(); - + if (CurChar == EOF) return AsmToken(AsmToken::Eof, StringRef(CurPtr, 0)); return AsmToken(AsmToken::EndOfStatement, StringRef(CurPtr, 0)); @@ -124,7 +161,6 @@ static void SkipIgnoredIntegerSuffix(const char *&CurPtr) { CurPtr += 3; } - /// LexDigit: First character is [0-9]. /// Local Label: [0-9][:] /// Forward/Backward Label: [0-9][fb] @@ -132,32 +168,37 @@ static void SkipIgnoredIntegerSuffix(const char *&CurPtr) { /// Octal integer: 0[0-7]+ /// Hex integer: 0x[0-9a-fA-F]+ /// Decimal integer: [1-9][0-9]* -/// TODO: FP literal. AsmToken AsmLexer::LexDigit() { // Decimal integer: [1-9][0-9]* - if (CurPtr[-1] != '0') { + if (CurPtr[-1] != '0' || CurPtr[0] == '.') { while (isdigit(*CurPtr)) ++CurPtr; - + + // Check for floating point literals. + if (*CurPtr == '.' || *CurPtr == 'e') { + ++CurPtr; + return LexFloatLiteral(); + } + StringRef Result(TokStart, CurPtr - TokStart); long long Value; if (Result.getAsInteger(10, Value)) { - // We have to handle minint_as_a_positive_value specially, because - // - minint_as_a_positive_value = minint and it is valid. - if (Result == "9223372036854775808") - Value = -9223372036854775808ULL; - else - return ReturnError(TokStart, "Invalid decimal number"); + // Allow positive values that are too large to fit into a signed 64-bit + // integer, but that do fit in an unsigned one, we just convert them over. + unsigned long long UValue; + if (Result.getAsInteger(10, UValue)) + return ReturnError(TokStart, "invalid decimal number"); + Value = (long long)UValue; } - + // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL // suffixes on integer literals. SkipIgnoredIntegerSuffix(CurPtr); - + return AsmToken(AsmToken::Integer, Result, Value); } - + if (*CurPtr == 'b') { ++CurPtr; // See if we actually have "0b" as part of something like "jmp 0b\n" @@ -169,30 +210,30 @@ AsmToken AsmLexer::LexDigit() { const char *NumStart = CurPtr; while (CurPtr[0] == '0' || CurPtr[0] == '1') ++CurPtr; - + // Requires at least one binary digit. if (CurPtr == NumStart) return ReturnError(TokStart, "Invalid binary number"); - + StringRef Result(TokStart, CurPtr - TokStart); - + long long Value; if (Result.substr(2).getAsInteger(2, Value)) return ReturnError(TokStart, "Invalid binary number"); - + // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL // suffixes on integer literals. SkipIgnoredIntegerSuffix(CurPtr); - + return AsmToken(AsmToken::Integer, Result, Value); } - + if (*CurPtr == 'x') { ++CurPtr; const char *NumStart = CurPtr; while (isxdigit(CurPtr[0])) ++CurPtr; - + // Requires at least one hex digit. if (CurPtr == NumStart) return ReturnError(CurPtr-2, "Invalid hexadecimal number"); @@ -200,31 +241,67 @@ AsmToken AsmLexer::LexDigit() { unsigned long long Result; if (StringRef(TokStart, CurPtr - TokStart).getAsInteger(0, Result)) return ReturnError(TokStart, "Invalid hexadecimal number"); - + // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL // suffixes on integer literals. SkipIgnoredIntegerSuffix(CurPtr); - + return AsmToken(AsmToken::Integer, StringRef(TokStart, CurPtr - TokStart), (int64_t)Result); } - + // Must be an octal number, it starts with 0. while (*CurPtr >= '0' && *CurPtr <= '7') ++CurPtr; - + StringRef Result(TokStart, CurPtr - TokStart); long long Value; if (Result.getAsInteger(8, Value)) return ReturnError(TokStart, "Invalid octal number"); - + // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL // suffixes on integer literals. SkipIgnoredIntegerSuffix(CurPtr); - + return AsmToken(AsmToken::Integer, Result, Value); } +/// LexSingleQuote: Integer: 'b' +AsmToken AsmLexer::LexSingleQuote() { + int CurChar = getNextChar(); + + if (CurChar == '\\') + CurChar = getNextChar(); + + if (CurChar == EOF) + return ReturnError(TokStart, "unterminated single quote"); + + CurChar = getNextChar(); + + if (CurChar != '\'') + return ReturnError(TokStart, "single quote way too long"); + + // The idea here being that 'c' is basically just an integral + // constant. + StringRef Res = StringRef(TokStart,CurPtr - TokStart); + long long Value; + + if (Res.startswith("\'\\")) { + char theChar = Res[2]; + switch (theChar) { + default: Value = theChar; break; + case '\'': Value = '\''; break; + case 't': Value = '\t'; break; + case 'n': Value = '\n'; break; + case 'b': Value = '\b'; break; + } + } else + Value = TokStart[1]; + + return AsmToken(AsmToken::Integer, Res, Value); +} + + /// LexQuote: String: "..." AsmToken AsmLexer::LexQuote() { int CurChar = getNextChar(); @@ -234,13 +311,13 @@ AsmToken AsmLexer::LexQuote() { // Allow \", etc. CurChar = getNextChar(); } - + if (CurChar == EOF) return ReturnError(TokStart, "unterminated string constant"); CurChar = getNextChar(); } - + return AsmToken(AsmToken::String, StringRef(TokStart, CurPtr - TokStart)); } @@ -266,7 +343,7 @@ AsmToken AsmLexer::LexToken() { TokStart = CurPtr; // This always consumes at least one character. int CurChar = getNextChar(); - + if (isAtStartOfComment(CurChar)) return LexLineComment(); @@ -275,7 +352,7 @@ AsmToken AsmLexer::LexToken() { // Handle identifier: [a-zA-Z_.][a-zA-Z0-9_$.@]* if (isalpha(CurChar) || CurChar == '_' || CurChar == '.') return LexIdentifier(); - + // Unknown character, emit an error. return ReturnError(TokStart, "invalid character in input"); case EOF: return AsmToken(AsmToken::Eof, StringRef(TokStart, 0)); @@ -301,49 +378,50 @@ AsmToken AsmLexer::LexToken() { case ',': return AsmToken(AsmToken::Comma, StringRef(TokStart, 1)); case '$': return AsmToken(AsmToken::Dollar, StringRef(TokStart, 1)); case '@': return AsmToken(AsmToken::At, StringRef(TokStart, 1)); - case '=': + case '=': if (*CurPtr == '=') return ++CurPtr, AsmToken(AsmToken::EqualEqual, StringRef(TokStart, 2)); return AsmToken(AsmToken::Equal, StringRef(TokStart, 1)); - case '|': + case '|': if (*CurPtr == '|') return ++CurPtr, AsmToken(AsmToken::PipePipe, StringRef(TokStart, 2)); return AsmToken(AsmToken::Pipe, StringRef(TokStart, 1)); case '^': return AsmToken(AsmToken::Caret, StringRef(TokStart, 1)); - case '&': + case '&': if (*CurPtr == '&') return ++CurPtr, AsmToken(AsmToken::AmpAmp, StringRef(TokStart, 2)); return AsmToken(AsmToken::Amp, StringRef(TokStart, 1)); - case '!': + case '!': if (*CurPtr == '=') return ++CurPtr, AsmToken(AsmToken::ExclaimEqual, StringRef(TokStart, 2)); return AsmToken(AsmToken::Exclaim, StringRef(TokStart, 1)); case '%': return AsmToken(AsmToken::Percent, StringRef(TokStart, 1)); case '/': return LexSlash(); case '#': return AsmToken(AsmToken::Hash, StringRef(TokStart, 1)); + case '\'': return LexSingleQuote(); case '"': return LexQuote(); case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return LexDigit(); case '<': switch (*CurPtr) { - case '<': return ++CurPtr, AsmToken(AsmToken::LessLess, + case '<': return ++CurPtr, AsmToken(AsmToken::LessLess, StringRef(TokStart, 2)); - case '=': return ++CurPtr, AsmToken(AsmToken::LessEqual, + case '=': return ++CurPtr, AsmToken(AsmToken::LessEqual, StringRef(TokStart, 2)); - case '>': return ++CurPtr, AsmToken(AsmToken::LessGreater, + case '>': return ++CurPtr, AsmToken(AsmToken::LessGreater, StringRef(TokStart, 2)); default: return AsmToken(AsmToken::Less, StringRef(TokStart, 1)); } case '>': switch (*CurPtr) { - case '>': return ++CurPtr, AsmToken(AsmToken::GreaterGreater, + case '>': return ++CurPtr, AsmToken(AsmToken::GreaterGreater, StringRef(TokStart, 2)); - case '=': return ++CurPtr, AsmToken(AsmToken::GreaterEqual, + case '=': return ++CurPtr, AsmToken(AsmToken::GreaterEqual, StringRef(TokStart, 2)); default: return AsmToken(AsmToken::Greater, StringRef(TokStart, 1)); } - + // TODO: Quoted identifiers (objc methods etc) // local labels: [0-9][:] // Forward/backward labels: [0-9][fb] diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index f83cd5eb2a16..c6d0da609b3b 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/APFloat.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" @@ -18,7 +19,6 @@ #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" -#include "llvm/MC/MCInst.h" #include "llvm/MC/MCParser/AsmCond.h" #include "llvm/MC/MCParser/AsmLexer.h" #include "llvm/MC/MCParser/MCAsmParser.h" @@ -27,11 +27,12 @@ #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCDwarf.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetAsmInfo.h" #include "llvm/Target/TargetAsmParser.h" +#include #include using namespace llvm; @@ -102,6 +103,9 @@ private: /// Boolean tracking whether macro substitution is enabled. unsigned MacrosEnabled : 1; + /// Flag tracking whether any errors have been encountered. + unsigned HadError : 1; + public: AsmParser(const Target &T, SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, const MCAsmInfo &MAI); @@ -137,14 +141,18 @@ public: /// } private: + void CheckForValidSection(); + bool ParseStatement(); bool HandleMacroEntry(StringRef Name, SMLoc NameLoc, const Macro *M); void HandleMacroExit(); void PrintMacroInstantiations(); - void PrintMessage(SMLoc Loc, const std::string &Msg, const char *Type) const; - + void PrintMessage(SMLoc Loc, const Twine &Msg, const char *Type) const { + SrcMgr.PrintMessage(Loc, Msg, Type); + } + /// EnterIncludeFile - Enter the specified file. This returns true on failure. bool EnterIncludeFile(const std::string &Filename); @@ -160,22 +168,27 @@ private: /// will be either the EndOfStatement or EOF. StringRef ParseStringToEndOfStatement(); - bool ParseAssignment(StringRef Name); + bool ParseAssignment(StringRef Name, bool allow_redef); bool ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc); bool ParseBinOpRHS(unsigned Precedence, const MCExpr *&Res, SMLoc &EndLoc); bool ParseParenExpr(const MCExpr *&Res, SMLoc &EndLoc); + bool ParseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc); /// ParseIdentifier - Parse an identifier or string (as a quoted identifier) /// and set \arg Res to the identifier contents. bool ParseIdentifier(StringRef &Res); - + // Directive Parsing. - bool ParseDirectiveAscii(bool ZeroTerminated); // ".ascii", ".asciiz" + + // ".ascii", ".asciiz", ".string" + bool ParseDirectiveAscii(StringRef IDVal, bool ZeroTerminated); bool ParseDirectiveValue(unsigned Size); // ".byte", ".long", ... + bool ParseDirectiveRealValue(const fltSemantics &); // ".single", ... bool ParseDirectiveFill(); // ".fill" bool ParseDirectiveSpace(); // ".space" - bool ParseDirectiveSet(); // ".set" + bool ParseDirectiveZero(); // ".zero" + bool ParseDirectiveSet(StringRef IDVal, bool allow_redef); // ".set", ".equ", ".equiv" bool ParseDirectiveOrg(); // ".org" // ".align{,32}", ".p2align{,w,l}" bool ParseDirectiveAlign(bool IsPow2, unsigned ValueSize); @@ -183,7 +196,6 @@ private: /// ParseDirectiveSymbolAttribute - Parse a directive like ".globl" which /// accepts a single symbol (which should be a label or an external). bool ParseDirectiveSymbolAttribute(MCSymbolAttr Attr); - bool ParseDirectiveELFType(); // ELF specific ".type" bool ParseDirectiveComm(bool IsLocal); // ".comm" and ".lcomm" @@ -191,6 +203,8 @@ private: bool ParseDirectiveInclude(); // ".include" bool ParseDirectiveIf(SMLoc DirectiveLoc); // ".if" + // ".ifdef" or ".ifndef", depending on expect_defined + bool ParseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined); bool ParseDirectiveElseIf(SMLoc DirectiveLoc); // ".elseif" bool ParseDirectiveElse(SMLoc DirectiveLoc); // ".else" bool ParseDirectiveEndIf(SMLoc DirectiveLoc); // .endif @@ -198,6 +212,9 @@ private: /// ParseEscapedString - Parse the current token as a string which may include /// escaped characters and return the string contents. bool ParseEscapedString(std::string &Data); + + const MCExpr *ApplyModifierToExpr(const MCExpr *E, + MCSymbolRefExpr::VariantKind Variant); }; /// \brief Generic implementations of directive handling, etc. which is shared @@ -208,7 +225,6 @@ class GenericAsmParser : public MCAsmParserExtension { getParser().AddDirectiveHandler(this, Directive, HandleDirective); } - public: GenericAsmParser() {} @@ -224,6 +240,29 @@ public: AddDirectiveHandler<&GenericAsmParser::ParseDirectiveFile>(".file"); AddDirectiveHandler<&GenericAsmParser::ParseDirectiveLine>(".line"); AddDirectiveHandler<&GenericAsmParser::ParseDirectiveLoc>(".loc"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveStabs>(".stabs"); + + // CFI directives. + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveCFIStartProc>( + ".cfi_startproc"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveCFIEndProc>( + ".cfi_endproc"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveCFIDefCfa>( + ".cfi_def_cfa"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveCFIDefCfaOffset>( + ".cfi_def_cfa_offset"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveCFIDefCfaRegister>( + ".cfi_def_cfa_register"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveCFIOffset>( + ".cfi_offset"); + AddDirectiveHandler< + &GenericAsmParser::ParseDirectiveCFIPersonalityOrLsda>(".cfi_personality"); + AddDirectiveHandler< + &GenericAsmParser::ParseDirectiveCFIPersonalityOrLsda>(".cfi_lsda"); + AddDirectiveHandler< + &GenericAsmParser::ParseDirectiveCFIRememberState>(".cfi_remember_state"); + AddDirectiveHandler< + &GenericAsmParser::ParseDirectiveCFIRestoreState>(".cfi_restore_state"); // Macro directives. AddDirectiveHandler<&GenericAsmParser::ParseDirectiveMacrosOnOff>( @@ -233,15 +272,32 @@ public: AddDirectiveHandler<&GenericAsmParser::ParseDirectiveMacro>(".macro"); AddDirectiveHandler<&GenericAsmParser::ParseDirectiveEndMacro>(".endm"); AddDirectiveHandler<&GenericAsmParser::ParseDirectiveEndMacro>(".endmacro"); + + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveLEB128>(".sleb128"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveLEB128>(".uleb128"); } + bool ParseRegisterOrRegisterNumber(int64_t &Register, SMLoc DirectiveLoc); + bool ParseDirectiveFile(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveLine(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveStabs(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveCFIStartProc(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveCFIEndProc(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveCFIDefCfa(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveCFIDefCfaOffset(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveCFIDefCfaRegister(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveCFIOffset(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveCFIPersonalityOrLsda(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveCFIRememberState(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveCFIRestoreState(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveMacrosOnOff(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveMacro(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveEndMacro(StringRef, SMLoc DirectiveLoc); + + bool ParseDirectiveLEB128(StringRef, SMLoc); }; } @@ -250,6 +306,7 @@ namespace llvm { extern MCAsmParserExtension *createDarwinAsmParser(); extern MCAsmParserExtension *createELFAsmParser(); +extern MCAsmParserExtension *createCOFFAsmParser(); } @@ -269,7 +326,10 @@ AsmParser::AsmParser(const Target &T, SourceMgr &_SM, MCContext &_Ctx, // // FIXME: This is a hack, we need to (majorly) cleanup how these objects are // created. - if (_MAI.hasSubsectionsViaSymbols()) { + if (_MAI.hasMicrosoftFastStdCallMangling()) { + PlatformParser = createCOFFAsmParser(); + PlatformParser->Initialize(*this); + } else if (_MAI.hasSubsectionsViaSymbols()) { PlatformParser = createDarwinAsmParser(); PlatformParser->Initialize(*this); } else { @@ -299,30 +359,26 @@ void AsmParser::PrintMacroInstantiations() { } void AsmParser::Warning(SMLoc L, const Twine &Msg) { - PrintMessage(L, Msg.str(), "warning"); + PrintMessage(L, Msg, "warning"); PrintMacroInstantiations(); } bool AsmParser::Error(SMLoc L, const Twine &Msg) { - PrintMessage(L, Msg.str(), "error"); + HadError = true; + PrintMessage(L, Msg, "error"); PrintMacroInstantiations(); return true; } -void AsmParser::PrintMessage(SMLoc Loc, const std::string &Msg, - const char *Type) const { - SrcMgr.PrintMessage(Loc, Msg, Type); -} - bool AsmParser::EnterIncludeFile(const std::string &Filename) { int NewBuf = SrcMgr.AddIncludeFile(Filename, Lexer.getLoc()); if (NewBuf == -1) return true; - + CurBuffer = NewBuf; - + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)); - + return false; } @@ -333,7 +389,7 @@ void AsmParser::JumpToLoc(SMLoc Loc) { const AsmToken &AsmParser::Lex() { const AsmToken *tok = &Lexer.Lex(); - + if (tok->is(AsmToken::Eof)) { // If this is the end of an included file, pop the parent file off the // include stack. @@ -343,35 +399,31 @@ const AsmToken &AsmParser::Lex() { tok = &Lexer.Lex(); } } - + if (tok->is(AsmToken::Error)) Error(Lexer.getErrLoc(), Lexer.getErr()); - + return *tok; } bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { // Create the initial section, if requested. - // - // FIXME: Target hook & command line option for initial section. if (!NoInitialTextSection) - Out.SwitchSection(Ctx.getMachOSection("__TEXT", "__text", - MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, - 0, SectionKind::getText())); + Out.InitSections(); // Prime the lexer. Lex(); - - bool HadError = false; - + + HadError = false; AsmCond StartingCondState = TheCondState; // While we have input, parse each statement. while (Lexer.isNot(AsmToken::Eof)) { if (!ParseStatement()) continue; - - // We had an error, remember it and recover by skipping to the next line. - HadError = true; + + // We had an error, validate that one was emitted and recover by skipping to + // the next line. + assert(HadError && "Parse statement returned an error, but none emitted!"); EatToEndOfStatement(); } @@ -383,26 +435,34 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { const std::vector &MCDwarfFiles = getContext().getMCDwarfFiles(); for (unsigned i = 1; i < MCDwarfFiles.size(); i++) { - if (!MCDwarfFiles[i]){ + if (!MCDwarfFiles[i]) TokError("unassigned file number: " + Twine(i) + " for .file directives"); - HadError = true; - } } - + // Finalize the output stream if there are no errors and if the client wants // us to. - if (!HadError && !NoFinalize) + if (!HadError && !NoFinalize) Out.Finish(); return HadError; } +void AsmParser::CheckForValidSection() { + if (!getStreamer().getCurrentSection()) { + TokError("expected section directive before assembly directive"); + Out.SwitchSection(Ctx.getMachOSection( + "__TEXT", "__text", + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + 0, SectionKind::getText())); + } +} + /// EatToEndOfStatement - Throw away the rest of the line for testing purposes. void AsmParser::EatToEndOfStatement() { while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.isNot(AsmToken::Eof)) Lex(); - + // Eat EOL. if (Lexer.is(AsmToken::EndOfStatement)) Lex(); @@ -433,6 +493,20 @@ bool AsmParser::ParseParenExpr(const MCExpr *&Res, SMLoc &EndLoc) { return false; } +/// ParseBracketExpr - Parse a bracket expression and return it. +/// NOTE: This assumes the leading '[' has already been consumed. +/// +/// bracketexpr ::= expr] +/// +bool AsmParser::ParseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc) { + if (ParseExpression(Res)) return true; + if (Lexer.isNot(AsmToken::RBrac)) + return TokError("expected ']' in brackets expression"); + EndLoc = Lexer.getLoc(); + Lex(); + return false; +} + /// ParsePrimaryExpr - Parse a primary expression and return it. /// primaryexpr ::= (parenexpr /// primaryexpr ::= symbol @@ -462,19 +536,21 @@ bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { std::pair Split = Identifier.split('@'); MCSymbol *Sym = getContext().GetOrCreateSymbol(Split.first); - // Mark the symbol as used in an expression. - Sym->setUsedInExpr(true); - // Lookup the symbol variant if used. MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; - if (Split.first.size() != Identifier.size()) + if (Split.first.size() != Identifier.size()) { Variant = MCSymbolRefExpr::getVariantKindForName(Split.second); + if (Variant == MCSymbolRefExpr::VK_Invalid) { + Variant = MCSymbolRefExpr::VK_None; + return TokError("invalid variant '" + Split.second + "'"); + } + } // If this is an absolute variable reference, substitute it now to preserve // semantics in the face of reassignment. if (Sym->isVariable() && isa(Sym->getVariableValue())) { if (Variant) - return Error(EndLoc, "unexpected modified on variable reference"); + return Error(EndLoc, "unexpected modifier on variable reference"); Res = Sym->getVariableValue(); return false; @@ -506,6 +582,13 @@ bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { } return false; } + case AsmToken::Real: { + APFloat RealVal(APFloat::IEEEdouble, getTok().getString()); + uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue(); + Res = MCConstantExpr::Create(IntVal, getContext()); + Lex(); // Eat token. + return false; + } case AsmToken::Dot: { // This is a '.' reference, which references the current PC. Emit a // temporary label to the streamer and refer to it. @@ -516,10 +599,12 @@ bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { Lex(); // Eat identifier. return false; } - case AsmToken::LParen: Lex(); // Eat the '('. return ParseParenExpr(Res, EndLoc); + case AsmToken::LBrac: + Lex(); // Eat the '['. + return ParseBracketExpr(Res, EndLoc); case AsmToken::Minus: Lex(); // Eat the operator. if (ParsePrimaryExpr(Res, EndLoc)) @@ -546,8 +631,57 @@ bool AsmParser::ParseExpression(const MCExpr *&Res) { return ParseExpression(Res, EndLoc); } +const MCExpr * +AsmParser::ApplyModifierToExpr(const MCExpr *E, + MCSymbolRefExpr::VariantKind Variant) { + // Recurse over the given expression, rebuilding it to apply the given variant + // if there is exactly one symbol. + switch (E->getKind()) { + case MCExpr::Target: + case MCExpr::Constant: + return 0; + + case MCExpr::SymbolRef: { + const MCSymbolRefExpr *SRE = cast(E); + + if (SRE->getKind() != MCSymbolRefExpr::VK_None) { + TokError("invalid variant on expression '" + + getTok().getIdentifier() + "' (already modified)"); + return E; + } + + return MCSymbolRefExpr::Create(&SRE->getSymbol(), Variant, getContext()); + } + + case MCExpr::Unary: { + const MCUnaryExpr *UE = cast(E); + const MCExpr *Sub = ApplyModifierToExpr(UE->getSubExpr(), Variant); + if (!Sub) + return 0; + return MCUnaryExpr::Create(UE->getOpcode(), Sub, getContext()); + } + + case MCExpr::Binary: { + const MCBinaryExpr *BE = cast(E); + const MCExpr *LHS = ApplyModifierToExpr(BE->getLHS(), Variant); + const MCExpr *RHS = ApplyModifierToExpr(BE->getRHS(), Variant); + + if (!LHS && !RHS) + return 0; + + if (!LHS) LHS = BE->getLHS(); + if (!RHS) RHS = BE->getRHS(); + + return MCBinaryExpr::Create(BE->getOpcode(), LHS, RHS, getContext()); + } + } + + assert(0 && "Invalid expression kind!"); + return 0; +} + /// ParseExpression - Parse an expression and return it. -/// +/// /// expr ::= expr +,- expr -> lowest. /// expr ::= expr |,^,&,! expr -> middle. /// expr ::= expr *,/,%,<<,>> expr -> highest. @@ -559,6 +693,31 @@ bool AsmParser::ParseExpression(const MCExpr *&Res, SMLoc &EndLoc) { if (ParsePrimaryExpr(Res, EndLoc) || ParseBinOpRHS(1, Res, EndLoc)) return true; + // As a special case, we support 'a op b @ modifier' by rewriting the + // expression to include the modifier. This is inefficient, but in general we + // expect users to use 'a@modifier op b'. + if (Lexer.getKind() == AsmToken::At) { + Lex(); + + if (Lexer.isNot(AsmToken::Identifier)) + return TokError("unexpected symbol modifier following '@'"); + + MCSymbolRefExpr::VariantKind Variant = + MCSymbolRefExpr::getVariantKindForName(getTok().getIdentifier()); + if (Variant == MCSymbolRefExpr::VK_Invalid) + return TokError("invalid variant '" + getTok().getIdentifier() + "'"); + + const MCExpr *ModifiedRes = ApplyModifierToExpr(Res, Variant); + if (!ModifiedRes) { + return TokError("invalid modifier '" + getTok().getIdentifier() + + "' (no symbols present)"); + return true; + } + + Res = ModifiedRes; + Lex(); + } + // Try to constant fold it up front, if possible. int64_t Value; if (Res->EvaluateAsAbsolute(Value)) @@ -575,7 +734,7 @@ bool AsmParser::ParseParenExpression(const MCExpr *&Res, SMLoc &EndLoc) { bool AsmParser::ParseAbsoluteExpression(int64_t &Res) { const MCExpr *Expr; - + SMLoc StartLoc = Lexer.getLoc(); if (ParseExpression(Expr)) return true; @@ -586,13 +745,13 @@ bool AsmParser::ParseAbsoluteExpression(int64_t &Res) { return false; } -static unsigned getBinOpPrecedence(AsmToken::TokenKind K, +static unsigned getBinOpPrecedence(AsmToken::TokenKind K, MCBinaryExpr::Opcode &Kind) { switch (K) { default: return 0; // not a binop. - // Lowest Precedence: &&, || + // Lowest Precedence: &&, ||, @ case AsmToken::AmpAmp: Kind = MCBinaryExpr::LAnd; return 1; @@ -600,62 +759,65 @@ static unsigned getBinOpPrecedence(AsmToken::TokenKind K, Kind = MCBinaryExpr::LOr; return 1; - // Low Precedence: +, -, ==, !=, <>, <, <=, >, >= - case AsmToken::Plus: - Kind = MCBinaryExpr::Add; + + // Low Precedence: |, &, ^ + // + // FIXME: gas seems to support '!' as an infix operator? + case AsmToken::Pipe: + Kind = MCBinaryExpr::Or; return 2; - case AsmToken::Minus: - Kind = MCBinaryExpr::Sub; + case AsmToken::Caret: + Kind = MCBinaryExpr::Xor; + return 2; + case AsmToken::Amp: + Kind = MCBinaryExpr::And; return 2; + + // Low Intermediate Precedence: ==, !=, <>, <, <=, >, >= case AsmToken::EqualEqual: Kind = MCBinaryExpr::EQ; - return 2; + return 3; case AsmToken::ExclaimEqual: case AsmToken::LessGreater: Kind = MCBinaryExpr::NE; - return 2; + return 3; case AsmToken::Less: Kind = MCBinaryExpr::LT; - return 2; + return 3; case AsmToken::LessEqual: Kind = MCBinaryExpr::LTE; - return 2; + return 3; case AsmToken::Greater: Kind = MCBinaryExpr::GT; - return 2; + return 3; case AsmToken::GreaterEqual: Kind = MCBinaryExpr::GTE; - return 2; - - // Intermediate Precedence: |, &, ^ - // - // FIXME: gas seems to support '!' as an infix operator? - case AsmToken::Pipe: - Kind = MCBinaryExpr::Or; - return 3; - case AsmToken::Caret: - Kind = MCBinaryExpr::Xor; - return 3; - case AsmToken::Amp: - Kind = MCBinaryExpr::And; return 3; + // High Intermediate Precedence: +, - + case AsmToken::Plus: + Kind = MCBinaryExpr::Add; + return 4; + case AsmToken::Minus: + Kind = MCBinaryExpr::Sub; + return 4; + // Highest Precedence: *, /, %, <<, >> case AsmToken::Star: Kind = MCBinaryExpr::Mul; - return 4; + return 5; case AsmToken::Slash: Kind = MCBinaryExpr::Div; - return 4; + return 5; case AsmToken::Percent: Kind = MCBinaryExpr::Mod; - return 4; + return 5; case AsmToken::LessLess: Kind = MCBinaryExpr::Shl; - return 4; + return 5; case AsmToken::GreaterGreater: Kind = MCBinaryExpr::Shr; - return 4; + return 5; } } @@ -667,18 +829,18 @@ bool AsmParser::ParseBinOpRHS(unsigned Precedence, const MCExpr *&Res, while (1) { MCBinaryExpr::Opcode Kind = MCBinaryExpr::Add; unsigned TokPrec = getBinOpPrecedence(Lexer.getKind(), Kind); - + // If the next token is lower precedence than we are allowed to eat, return // successfully with what we ate already. if (TokPrec < Precedence) return false; - + Lex(); - + // Eat the next primary expression. const MCExpr *RHS; if (ParsePrimaryExpr(RHS, EndLoc)) return true; - + // If BinOp binds less tightly with RHS than the operator after RHS, let // the pending operator take RHS as its LHS. MCBinaryExpr::Opcode Dummy; @@ -692,9 +854,9 @@ bool AsmParser::ParseBinOpRHS(unsigned Precedence, const MCExpr *&Res, } } - - - + + + /// ParseStatement: /// ::= EndOfStatement /// ::= Label* Directive ...Operands... EndOfStatement @@ -706,12 +868,17 @@ bool AsmParser::ParseStatement() { return false; } - // Statements always start with an identifier. + // Statements always start with an identifier or are a full line comment. AsmToken ID = getTok(); SMLoc IDLoc = ID.getLoc(); StringRef IDVal; int64_t LocalLabelVal = -1; - // GUESS allow an integer followed by a ':' as a directional local label + // A full line comment is a '#' as the first token. + if (Lexer.is(AsmToken::Hash)) { + EatToEndOfStatement(); + return false; + } + // Allow an integer followed by a ':' as a directional local label. if (Lexer.is(AsmToken::Integer)) { LocalLabelVal = getTok().getIntVal(); if (LocalLabelVal < 0) { @@ -739,24 +906,30 @@ bool AsmParser::ParseStatement() { // example. if (IDVal == ".if") return ParseDirectiveIf(IDLoc); + if (IDVal == ".ifdef") + return ParseDirectiveIfdef(IDLoc, true); + if (IDVal == ".ifndef" || IDVal == ".ifnotdef") + return ParseDirectiveIfdef(IDLoc, false); if (IDVal == ".elseif") return ParseDirectiveElseIf(IDLoc); if (IDVal == ".else") return ParseDirectiveElse(IDLoc); if (IDVal == ".endif") return ParseDirectiveEndIf(IDLoc); - + // If we are in a ".if 0" block, ignore this statement. if (TheCondState.Ignore) { EatToEndOfStatement(); return false; } - + // FIXME: Recurse on local labels? // See what kind of statement we have. switch (Lexer.getKind()) { case AsmToken::Colon: { + CheckForValidSection(); + // identifier ':' -> Label. Lex(); @@ -772,10 +945,10 @@ bool AsmParser::ParseStatement() { Sym = Ctx.CreateDirectionalLocalSymbol(LocalLabelVal); if (!Sym->isUndefined() || Sym->isVariable()) return Error(IDLoc, "invalid symbol redefinition"); - + // Emit the label. Out.EmitLabel(Sym); - + // Consume any end of statement token, if present, to avoid spurious // AddBlankLine calls(). if (Lexer.is(AsmToken::EndOfStatement)) { @@ -791,7 +964,7 @@ bool AsmParser::ParseStatement() { // identifier '=' ... -> assignment statement Lex(); - return ParseAssignment(IDVal); + return ParseAssignment(IDVal, true); default: // Normal instruction or directive. break; @@ -802,27 +975,43 @@ bool AsmParser::ParseStatement() { if (const Macro *M = MacroMap.lookup(IDVal)) return HandleMacroEntry(IDVal, IDLoc, M); - // Otherwise, we have a normal instruction or directive. + // Otherwise, we have a normal instruction or directive. if (IDVal[0] == '.') { // Assembler features - if (IDVal == ".set") - return ParseDirectiveSet(); + if (IDVal == ".set" || IDVal == ".equ") + return ParseDirectiveSet(IDVal, true); + if (IDVal == ".equiv") + return ParseDirectiveSet(IDVal, false); // Data directives if (IDVal == ".ascii") - return ParseDirectiveAscii(false); - if (IDVal == ".asciz") - return ParseDirectiveAscii(true); + return ParseDirectiveAscii(IDVal, false); + if (IDVal == ".asciz" || IDVal == ".string") + return ParseDirectiveAscii(IDVal, true); if (IDVal == ".byte") return ParseDirectiveValue(1); if (IDVal == ".short") return ParseDirectiveValue(2); + if (IDVal == ".value") + return ParseDirectiveValue(2); + if (IDVal == ".2byte") + return ParseDirectiveValue(2); if (IDVal == ".long") return ParseDirectiveValue(4); + if (IDVal == ".int") + return ParseDirectiveValue(4); + if (IDVal == ".4byte") + return ParseDirectiveValue(4); if (IDVal == ".quad") return ParseDirectiveValue(8); + if (IDVal == ".8byte") + return ParseDirectiveValue(8); + if (IDVal == ".single" || IDVal == ".float") + return ParseDirectiveRealValue(APFloat::IEEEsingle); + if (IDVal == ".double") + return ParseDirectiveRealValue(APFloat::IEEEdouble); if (IDVal == ".align") { bool IsPow2 = !getContext().getAsmInfo().getAlignmentIsInBytes(); @@ -852,11 +1041,16 @@ bool AsmParser::ParseStatement() { return ParseDirectiveFill(); if (IDVal == ".space") return ParseDirectiveSpace(); + if (IDVal == ".zero") + return ParseDirectiveZero(); // Symbol attribute directives if (IDVal == ".globl" || IDVal == ".global") return ParseDirectiveSymbolAttribute(MCSA_Global); + // ELF only? Should it be here? + if (IDVal == ".local") + return ParseDirectiveSymbolAttribute(MCSA_Local); if (IDVal == ".hidden") return ParseDirectiveSymbolAttribute(MCSA_Hidden); if (IDVal == ".indirect_symbol") @@ -867,14 +1061,14 @@ bool AsmParser::ParseStatement() { return ParseDirectiveSymbolAttribute(MCSA_LazyReference); if (IDVal == ".no_dead_strip") return ParseDirectiveSymbolAttribute(MCSA_NoDeadStrip); + if (IDVal == ".symbol_resolver") + return ParseDirectiveSymbolAttribute(MCSA_SymbolResolver); if (IDVal == ".private_extern") return ParseDirectiveSymbolAttribute(MCSA_PrivateExtern); if (IDVal == ".protected") return ParseDirectiveSymbolAttribute(MCSA_Protected); if (IDVal == ".reference") return ParseDirectiveSymbolAttribute(MCSA_Reference); - if (IDVal == ".type") - return ParseDirectiveELFType(); if (IDVal == ".weak") return ParseDirectiveSymbolAttribute(MCSA_Weak); if (IDVal == ".weak_definition") @@ -894,6 +1088,9 @@ bool AsmParser::ParseStatement() { if (IDVal == ".include") return ParseDirectiveInclude(); + if (IDVal == ".code16" || IDVal == ".code32" || IDVal == ".code64") + return TokError(Twine(IDVal) + " not supported yet"); + // Look up the handler in the handler table. std::pair Handler = DirectiveMap.lookup(IDVal); @@ -909,16 +1106,16 @@ bool AsmParser::ParseStatement() { return false; } + CheckForValidSection(); + // Canonicalize the opcode to lower case. SmallString<128> Opcode; for (unsigned i = 0, e = IDVal.size(); i != e; ++i) Opcode.push_back(tolower(IDVal[i])); - + SmallVector ParsedOperands; bool HadError = getTargetParser().ParseInstruction(Opcode.str(), IDLoc, ParsedOperands); - if (!HadError && Lexer.isNot(AsmToken::EndOfStatement)) - HadError = TokError("unexpected token in argument list"); // Dump the parsed representation, if requested. if (getShowParsedOperands()) { @@ -936,25 +1133,17 @@ bool AsmParser::ParseStatement() { } // If parsing succeeded, match the instruction. - if (!HadError) { - MCInst Inst; - if (!getTargetParser().MatchInstruction(IDLoc, ParsedOperands, Inst)) { - // Emit the instruction on success. - Out.EmitInstruction(Inst); - } else - HadError = true; - } - - // If there was no error, consume the end-of-statement token. Otherwise this - // will be done by our caller. if (!HadError) - Lex(); + HadError = getTargetParser().MatchAndEmitInstruction(IDLoc, ParsedOperands, + Out); // Free any parsed operands. for (unsigned i = 0, e = ParsedOperands.size(); i != e; ++i) delete ParsedOperands[i]; - return HadError; + // Don't skip the rest of the line, the instruction parser is responsible for + // that. + return false; } MacroInstantiation::MacroInstantiation(const Macro *M, SMLoc IL, SMLoc EL, @@ -1083,14 +1272,35 @@ void AsmParser::HandleMacroExit() { ActiveMacros.pop_back(); } -bool AsmParser::ParseAssignment(StringRef Name) { +static void MarkUsed(const MCExpr *Value) { + switch (Value->getKind()) { + case MCExpr::Binary: + MarkUsed(static_cast(Value)->getLHS()); + MarkUsed(static_cast(Value)->getRHS()); + break; + case MCExpr::Target: + case MCExpr::Constant: + break; + case MCExpr::SymbolRef: { + static_cast(Value)->getSymbol().setUsed(true); + break; + } + case MCExpr::Unary: + MarkUsed(static_cast(Value)->getSubExpr()); + break; + } +} + +bool AsmParser::ParseAssignment(StringRef Name, bool allow_redef) { // FIXME: Use better location, we should use proper tokens. SMLoc EqualLoc = Lexer.getLoc(); const MCExpr *Value; if (ParseExpression(Value)) return true; - + + MarkUsed(Value); + if (Lexer.isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in assignment"); @@ -1105,22 +1315,23 @@ bool AsmParser::ParseAssignment(StringRef Name) { // // FIXME: Diagnostics. Note the location of the definition as a label. // FIXME: Diagnose assignment to protected identifier (e.g., register name). - if (Sym->isUndefined() && !Sym->isUsedInExpr()) + if (Sym->isUndefined() && !Sym->isUsed() && !Sym->isVariable()) ; // Allow redefinitions of undefined symbols only used in directives. - else if (!Sym->isUndefined() && !Sym->isAbsolute()) + else if (!Sym->isUndefined() && (!Sym->isAbsolute() || !allow_redef)) return Error(EqualLoc, "redefinition of '" + Name + "'"); else if (!Sym->isVariable()) return Error(EqualLoc, "invalid assignment to '" + Name + "'"); else if (!isa(Sym->getVariableValue())) return Error(EqualLoc, "invalid reassignment of non-absolute variable '" + Name + "'"); + + // Don't count these checks as uses. + Sym->setUsed(false); } else Sym = getContext().GetOrCreateSymbol(Name); // FIXME: Handle '.'. - Sym->setUsedInExpr(true); - // Do the assignment. Out.EmitAssignment(Sym, Value); @@ -1167,18 +1378,20 @@ bool AsmParser::ParseIdentifier(StringRef &Res) { } /// ParseDirectiveSet: +/// ::= .equ identifier ',' expression +/// ::= .equiv identifier ',' expression /// ::= .set identifier ',' expression -bool AsmParser::ParseDirectiveSet() { +bool AsmParser::ParseDirectiveSet(StringRef IDVal, bool allow_redef) { StringRef Name; if (ParseIdentifier(Name)) - return TokError("expected identifier after '.set' directive"); - + return TokError("expected identifier after '" + Twine(IDVal) + "'"); + if (getLexer().isNot(AsmToken::Comma)) - return TokError("unexpected token in '.set'"); + return TokError("unexpected token in '" + Twine(IDVal) + "'"); Lex(); - return ParseAssignment(Name); + return ParseAssignment(Name, allow_redef); } bool AsmParser::ParseEscapedString(std::string &Data) { @@ -1240,12 +1453,14 @@ bool AsmParser::ParseEscapedString(std::string &Data) { } /// ParseDirectiveAscii: -/// ::= ( .ascii | .asciz ) [ "string" ( , "string" )* ] -bool AsmParser::ParseDirectiveAscii(bool ZeroTerminated) { +/// ::= ( .ascii | .asciz | .string ) [ "string" ( , "string" )* ] +bool AsmParser::ParseDirectiveAscii(StringRef IDVal, bool ZeroTerminated) { if (getLexer().isNot(AsmToken::EndOfStatement)) { + CheckForValidSection(); + for (;;) { if (getLexer().isNot(AsmToken::String)) - return TokError("expected string in '.ascii' or '.asciz' directive"); + return TokError("expected string in '" + Twine(IDVal) + "' directive"); std::string Data; if (ParseEscapedString(Data)) @@ -1261,7 +1476,7 @@ bool AsmParser::ParseDirectiveAscii(bool ZeroTerminated) { break; if (getLexer().isNot(AsmToken::Comma)) - return TokError("unexpected token in '.ascii' or '.asciz' directive"); + return TokError("unexpected token in '" + Twine(IDVal) + "' directive"); Lex(); } } @@ -1274,9 +1489,10 @@ bool AsmParser::ParseDirectiveAscii(bool ZeroTerminated) { /// ::= (.byte | .short | ... ) [ expression (, expression)* ] bool AsmParser::ParseDirectiveValue(unsigned Size) { if (getLexer().isNot(AsmToken::EndOfStatement)) { + CheckForValidSection(); + for (;;) { const MCExpr *Value; - SMLoc ATTRIBUTE_UNUSED StartLoc = getLexer().getLoc(); if (ParseExpression(Value)) return true; @@ -1288,7 +1504,7 @@ bool AsmParser::ParseDirectiveValue(unsigned Size) { if (getLexer().is(AsmToken::EndOfStatement)) break; - + // FIXME: Improve diagnostic. if (getLexer().isNot(AsmToken::Comma)) return TokError("unexpected token in directive"); @@ -1300,9 +1516,61 @@ bool AsmParser::ParseDirectiveValue(unsigned Size) { return false; } +/// ParseDirectiveRealValue +/// ::= (.single | .double) [ expression (, expression)* ] +bool AsmParser::ParseDirectiveRealValue(const fltSemantics &Semantics) { + if (getLexer().isNot(AsmToken::EndOfStatement)) { + CheckForValidSection(); + + for (;;) { + // We don't truly support arithmetic on floating point expressions, so we + // have to manually parse unary prefixes. + bool IsNeg = false; + if (getLexer().is(AsmToken::Minus)) { + Lex(); + IsNeg = true; + } else if (getLexer().is(AsmToken::Plus)) + Lex(); + + if (getLexer().isNot(AsmToken::Integer) && + getLexer().isNot(AsmToken::Real)) + return TokError("unexpected token in directive"); + + // Convert to an APFloat. + APFloat Value(Semantics); + if (Value.convertFromString(getTok().getString(), + APFloat::rmNearestTiesToEven) == + APFloat::opInvalidOp) + return TokError("invalid floating point literal"); + if (IsNeg) + Value.changeSign(); + + // Consume the numeric token. + Lex(); + + // Emit the value as an integer. + APInt AsInt = Value.bitcastToAPInt(); + getStreamer().EmitIntValue(AsInt.getLimitedValue(), + AsInt.getBitWidth() / 8, DEFAULT_ADDRSPACE); + + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + } + } + + Lex(); + return false; +} + /// ParseDirectiveSpace /// ::= .space expression [ , expression ] bool AsmParser::ParseDirectiveSpace() { + CheckForValidSection(); + int64_t NumBytes; if (ParseAbsoluteExpression(NumBytes)) return true; @@ -1312,7 +1580,7 @@ bool AsmParser::ParseDirectiveSpace() { if (getLexer().isNot(AsmToken::Comma)) return TokError("unexpected token in '.space' directive"); Lex(); - + if (ParseAbsoluteExpression(FillExpr)) return true; @@ -1331,9 +1599,37 @@ bool AsmParser::ParseDirectiveSpace() { return false; } +/// ParseDirectiveZero +/// ::= .zero expression +bool AsmParser::ParseDirectiveZero() { + CheckForValidSection(); + + int64_t NumBytes; + if (ParseAbsoluteExpression(NumBytes)) + return true; + + int64_t Val = 0; + if (getLexer().is(AsmToken::Comma)) { + Lex(); + if (ParseAbsoluteExpression(Val)) + return true; + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.zero' directive"); + + Lex(); + + getStreamer().EmitFill(NumBytes, Val, DEFAULT_ADDRSPACE); + + return false; +} + /// ParseDirectiveFill /// ::= .fill expression , expression , expression bool AsmParser::ParseDirectiveFill() { + CheckForValidSection(); + int64_t NumValues; if (ParseAbsoluteExpression(NumValues)) return true; @@ -1341,7 +1637,7 @@ bool AsmParser::ParseDirectiveFill() { if (getLexer().isNot(AsmToken::Comma)) return TokError("unexpected token in '.fill' directive"); Lex(); - + int64_t FillSize; if (ParseAbsoluteExpression(FillSize)) return true; @@ -1349,14 +1645,14 @@ bool AsmParser::ParseDirectiveFill() { if (getLexer().isNot(AsmToken::Comma)) return TokError("unexpected token in '.fill' directive"); Lex(); - + int64_t FillExpr; if (ParseAbsoluteExpression(FillExpr)) return true; if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.fill' directive"); - + Lex(); if (FillSize != 1 && FillSize != 2 && FillSize != 4 && FillSize != 8) @@ -1371,6 +1667,8 @@ bool AsmParser::ParseDirectiveFill() { /// ParseDirectiveOrg /// ::= .org expression [ , expression ] bool AsmParser::ParseDirectiveOrg() { + CheckForValidSection(); + const MCExpr *Offset; if (ParseExpression(Offset)) return true; @@ -1381,7 +1679,7 @@ bool AsmParser::ParseDirectiveOrg() { if (getLexer().isNot(AsmToken::Comma)) return TokError("unexpected token in '.org' directive"); Lex(); - + if (ParseAbsoluteExpression(FillExpr)) return true; @@ -1401,6 +1699,8 @@ bool AsmParser::ParseDirectiveOrg() { /// ParseDirectiveAlign /// ::= {.align, ...} expression [ , expression [ , expression ]] bool AsmParser::ParseDirectiveAlign(bool IsPow2, unsigned ValueSize) { + CheckForValidSection(); + SMLoc AlignmentLoc = getLexer().getLoc(); int64_t Alignment; if (ParseAbsoluteExpression(Alignment)) @@ -1432,7 +1732,7 @@ bool AsmParser::ParseDirectiveAlign(bool IsPow2, unsigned ValueSize) { MaxBytesLoc = getLexer().getLoc(); if (ParseAbsoluteExpression(MaxBytesToFill)) return true; - + if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in directive"); } @@ -1471,12 +1771,7 @@ bool AsmParser::ParseDirectiveAlign(bool IsPow2, unsigned ValueSize) { // Check whether we should use optimal code alignment for this .align // directive. - // - // FIXME: This should be using a target hook. - bool UseCodeAlign = false; - if (const MCSectionMachO *S = dyn_cast( - getStreamer().getCurrentSection())) - UseCodeAlign = S->hasAttribute(MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS); + bool UseCodeAlign = getStreamer().getCurrentSection()->UseCodeAlign(); if ((!HasFillExpr || Lexer.getMAI().getTextAlignFillValue() == FillExpr) && ValueSize == 1 && UseCodeAlign) { getStreamer().EmitCodeAlignment(Alignment, MaxBytesToFill); @@ -1498,7 +1793,7 @@ bool AsmParser::ParseDirectiveSymbolAttribute(MCSymbolAttr Attr) { if (ParseIdentifier(Name)) return TokError("expected identifier in directive"); - + MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); getStreamer().EmitSymbolAttribute(Sym, Attr); @@ -1513,63 +1808,19 @@ bool AsmParser::ParseDirectiveSymbolAttribute(MCSymbolAttr Attr) { } Lex(); - return false; -} - -/// ParseDirectiveELFType -/// ::= .type identifier , @attribute -bool AsmParser::ParseDirectiveELFType() { - StringRef Name; - if (ParseIdentifier(Name)) - return TokError("expected identifier in directive"); - - // Handle the identifier as the key symbol. - MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); - - if (getLexer().isNot(AsmToken::Comma)) - return TokError("unexpected token in '.type' directive"); - Lex(); - - if (getLexer().isNot(AsmToken::At)) - return TokError("expected '@' before type"); - Lex(); - - StringRef Type; - SMLoc TypeLoc; - - TypeLoc = getLexer().getLoc(); - if (ParseIdentifier(Type)) - return TokError("expected symbol type in directive"); - - MCSymbolAttr Attr = StringSwitch(Type) - .Case("function", MCSA_ELF_TypeFunction) - .Case("object", MCSA_ELF_TypeObject) - .Case("tls_object", MCSA_ELF_TypeTLS) - .Case("common", MCSA_ELF_TypeCommon) - .Case("notype", MCSA_ELF_TypeNoType) - .Default(MCSA_Invalid); - - if (Attr == MCSA_Invalid) - return Error(TypeLoc, "unsupported attribute in '.type' directive"); - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in '.type' directive"); - - Lex(); - - getStreamer().EmitSymbolAttribute(Sym, Attr); - return false; } /// ParseDirectiveComm /// ::= ( .comm | .lcomm ) identifier , size_expression [ , align_expression ] bool AsmParser::ParseDirectiveComm(bool IsLocal) { + CheckForValidSection(); + SMLoc IDLoc = getLexer().getLoc(); StringRef Name; if (ParseIdentifier(Name)) return TokError("expected identifier in directive"); - + // Handle the identifier as the key symbol. MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); @@ -1589,7 +1840,7 @@ bool AsmParser::ParseDirectiveComm(bool IsLocal) { Pow2AlignmentLoc = getLexer().getLoc(); if (ParseAbsoluteExpression(Pow2Alignment)) return true; - + // If this target takes alignments in bytes (not log) validate and convert. if (Lexer.getMAI().getAlignmentIsInBytes()) { if (!isPowerOf2_64(Pow2Alignment)) @@ -1597,10 +1848,10 @@ bool AsmParser::ParseDirectiveComm(bool IsLocal) { Pow2Alignment = Log2_64(Pow2Alignment); } } - + if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.comm' or '.lcomm' directive"); - + Lex(); // NOTE: a size of zero for a .comm should create a undefined symbol @@ -1659,17 +1910,17 @@ bool AsmParser::ParseDirectiveAbort() { bool AsmParser::ParseDirectiveInclude() { if (getLexer().isNot(AsmToken::String)) return TokError("expected string in '.include' directive"); - + std::string Filename = getTok().getString(); SMLoc IncludeLoc = getLexer().getLoc(); Lex(); if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.include' directive"); - + // Strip the quotes. Filename = Filename.substr(1, Filename.size()-2); - + // Attempt to switch the lexer to the included file before consuming the end // of statement to avoid losing it when we switch. if (EnterIncludeFile(Filename)) { @@ -1695,7 +1946,7 @@ bool AsmParser::ParseDirectiveIf(SMLoc DirectiveLoc) { if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.if' directive"); - + Lex(); TheCondState.CondMet = ExprValue; @@ -1705,6 +1956,31 @@ bool AsmParser::ParseDirectiveIf(SMLoc DirectiveLoc) { return false; } +bool AsmParser::ParseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined) { + StringRef Name; + TheCondStack.push_back(TheCondState); + TheCondState.TheCond = AsmCond::IfCond; + + if (TheCondState.Ignore) { + EatToEndOfStatement(); + } else { + if (ParseIdentifier(Name)) + return TokError("expected identifier after '.ifdef'"); + + Lex(); + + MCSymbol *Sym = getContext().LookupSymbol(Name); + + if (expect_defined) + TheCondState.CondMet = (Sym != NULL && !Sym->isUndefined()); + else + TheCondState.CondMet = (Sym == NULL || Sym->isUndefined()); + TheCondState.Ignore = !TheCondState.CondMet; + } + + return false; +} + /// ParseDirectiveElseIf /// ::= .elseif expression bool AsmParser::ParseDirectiveElseIf(SMLoc DirectiveLoc) { @@ -1728,7 +2004,7 @@ bool AsmParser::ParseDirectiveElseIf(SMLoc DirectiveLoc) { if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.elseif' directive"); - + Lex(); TheCondState.CondMet = ExprValue; TheCondState.Ignore = !TheCondState.CondMet; @@ -1742,7 +2018,7 @@ bool AsmParser::ParseDirectiveElseIf(SMLoc DirectiveLoc) { bool AsmParser::ParseDirectiveElse(SMLoc DirectiveLoc) { if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.else' directive"); - + Lex(); if (TheCondState.TheCond != AsmCond::IfCond && @@ -1766,7 +2042,7 @@ bool AsmParser::ParseDirectiveElse(SMLoc DirectiveLoc) { bool AsmParser::ParseDirectiveEndIf(SMLoc DirectiveLoc) { if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.endif' directive"); - + Lex(); if ((TheCondState.TheCond == AsmCond::NoCond) || @@ -1808,9 +2084,8 @@ bool GenericAsmParser::ParseDirectiveFile(StringRef, SMLoc DirectiveLoc) { if (FileNumber == -1) getStreamer().EmitFileDirective(Filename); else { - if (getContext().GetDwarfFile(Filename, FileNumber) == 0) - Error(FileNumberLoc, "file number already allocated"); - getStreamer().EmitDwarfFileDirective(FileNumber, Filename); + if (getStreamer().EmitDwarfFileDirective(FileNumber, Filename)) + Error(FileNumberLoc, "file number already allocated"); } return false; @@ -1851,7 +2126,7 @@ bool GenericAsmParser::ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc) { int64_t FileNumber = getTok().getIntVal(); if (FileNumber < 1) return TokError("file number less than one in '.loc' directive"); - if (!getContext().ValidateDwarfFileNumber(FileNumber)) + if (!getContext().isValidDwarfFileNumber(FileNumber)) return TokError("unassigned file number in '.loc' directive"); Lex(); @@ -1871,8 +2146,9 @@ bool GenericAsmParser::ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc) { Lex(); } - unsigned Flags = 0; + unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0; unsigned Isa = 0; + int64_t Discriminator = 0; if (getLexer().isNot(AsmToken::EndOfStatement)) { for (;;) { if (getLexer().is(AsmToken::EndOfStatement)) @@ -1903,7 +2179,7 @@ bool GenericAsmParser::ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc) { Flags |= DWARF2_FLAG_IS_STMT; else return Error(Loc, "is_stmt value not 0 or 1"); - } + } else { return Error(Loc, "is_stmt value not the constant value of 0 or 1"); } @@ -1919,11 +2195,15 @@ bool GenericAsmParser::ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc) { if (Value < 0) return Error(Loc, "isa number less than zero"); Isa = Value; - } + } else { return Error(Loc, "isa number not a constant value"); } } + else if (Name == "discriminator") { + if (getParser().ParseAbsoluteExpression(Discriminator)) + return true; + } else { return Error(Loc, "unknown sub-directive in '.loc' directive"); } @@ -1933,11 +2213,176 @@ bool GenericAsmParser::ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc) { } } - getContext().setCurrentDwarfLoc(FileNumber, LineNumber, ColumnPos, Flags,Isa); + getStreamer().EmitDwarfLocDirective(FileNumber, LineNumber, ColumnPos, Flags, + Isa, Discriminator); return false; } +/// ParseDirectiveStabs +/// ::= .stabs string, number, number, number +bool GenericAsmParser::ParseDirectiveStabs(StringRef Directive, + SMLoc DirectiveLoc) { + return TokError("unsupported directive '" + Directive + "'"); +} + +/// ParseDirectiveCFIStartProc +/// ::= .cfi_startproc +bool GenericAsmParser::ParseDirectiveCFIStartProc(StringRef, + SMLoc DirectiveLoc) { + return getStreamer().EmitCFIStartProc(); +} + +/// ParseDirectiveCFIEndProc +/// ::= .cfi_endproc +bool GenericAsmParser::ParseDirectiveCFIEndProc(StringRef, SMLoc DirectiveLoc) { + return getStreamer().EmitCFIEndProc(); +} + +/// ParseRegisterOrRegisterNumber - parse register name or number. +bool GenericAsmParser::ParseRegisterOrRegisterNumber(int64_t &Register, + SMLoc DirectiveLoc) { + unsigned RegNo; + + if (getLexer().is(AsmToken::Percent)) { + if (getParser().getTargetParser().ParseRegister(RegNo, DirectiveLoc, + DirectiveLoc)) + return true; + Register = getContext().getTargetAsmInfo().getDwarfRegNum(RegNo, true); + } else + return getParser().ParseAbsoluteExpression(Register); + + return false; +} + +/// ParseDirectiveCFIDefCfa +/// ::= .cfi_def_cfa register, offset +bool GenericAsmParser::ParseDirectiveCFIDefCfa(StringRef, + SMLoc DirectiveLoc) { + int64_t Register = 0; + if (ParseRegisterOrRegisterNumber(Register, DirectiveLoc)) + return true; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + int64_t Offset = 0; + if (getParser().ParseAbsoluteExpression(Offset)) + return true; + + return getStreamer().EmitCFIDefCfa(Register, Offset); +} + +/// ParseDirectiveCFIDefCfaOffset +/// ::= .cfi_def_cfa_offset offset +bool GenericAsmParser::ParseDirectiveCFIDefCfaOffset(StringRef, + SMLoc DirectiveLoc) { + int64_t Offset = 0; + if (getParser().ParseAbsoluteExpression(Offset)) + return true; + + return getStreamer().EmitCFIDefCfaOffset(Offset); +} + +/// ParseDirectiveCFIDefCfaRegister +/// ::= .cfi_def_cfa_register register +bool GenericAsmParser::ParseDirectiveCFIDefCfaRegister(StringRef, + SMLoc DirectiveLoc) { + int64_t Register = 0; + if (ParseRegisterOrRegisterNumber(Register, DirectiveLoc)) + return true; + + return getStreamer().EmitCFIDefCfaRegister(Register); +} + +/// ParseDirectiveCFIOffset +/// ::= .cfi_off register, offset +bool GenericAsmParser::ParseDirectiveCFIOffset(StringRef, SMLoc DirectiveLoc) { + int64_t Register = 0; + int64_t Offset = 0; + + if (ParseRegisterOrRegisterNumber(Register, DirectiveLoc)) + return true; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + if (getParser().ParseAbsoluteExpression(Offset)) + return true; + + return getStreamer().EmitCFIOffset(Register, Offset); +} + +static bool isValidEncoding(int64_t Encoding) { + if (Encoding & ~0xff) + return false; + + if (Encoding == dwarf::DW_EH_PE_omit) + return true; + + const unsigned Format = Encoding & 0xf; + if (Format != dwarf::DW_EH_PE_absptr && Format != dwarf::DW_EH_PE_udata2 && + Format != dwarf::DW_EH_PE_udata4 && Format != dwarf::DW_EH_PE_udata8 && + Format != dwarf::DW_EH_PE_sdata2 && Format != dwarf::DW_EH_PE_sdata4 && + Format != dwarf::DW_EH_PE_sdata8 && Format != dwarf::DW_EH_PE_signed) + return false; + + const unsigned Application = Encoding & 0x70; + if (Application != dwarf::DW_EH_PE_absptr && + Application != dwarf::DW_EH_PE_pcrel) + return false; + + return true; +} + +/// ParseDirectiveCFIPersonalityOrLsda +/// ::= .cfi_personality encoding, [symbol_name] +/// ::= .cfi_lsda encoding, [symbol_name] +bool GenericAsmParser::ParseDirectiveCFIPersonalityOrLsda(StringRef IDVal, + SMLoc DirectiveLoc) { + int64_t Encoding = 0; + if (getParser().ParseAbsoluteExpression(Encoding)) + return true; + if (Encoding == dwarf::DW_EH_PE_omit) + return false; + + if (!isValidEncoding(Encoding)) + return TokError("unsupported encoding."); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + StringRef Name; + if (getParser().ParseIdentifier(Name)) + return TokError("expected identifier in directive"); + + MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); + + if (IDVal == ".cfi_personality") + return getStreamer().EmitCFIPersonality(Sym, Encoding); + else { + assert(IDVal == ".cfi_lsda"); + return getStreamer().EmitCFILsda(Sym, Encoding); + } +} + +/// ParseDirectiveCFIRememberState +/// ::= .cfi_remember_state +bool GenericAsmParser::ParseDirectiveCFIRememberState(StringRef IDVal, + SMLoc DirectiveLoc) { + return getStreamer().EmitCFIRememberState(); +} + +/// ParseDirectiveCFIRestoreState +/// ::= .cfi_remember_state +bool GenericAsmParser::ParseDirectiveCFIRestoreState(StringRef IDVal, + SMLoc DirectiveLoc) { + return getStreamer().EmitCFIRestoreState(); +} + /// ParseDirectiveMacrosOnOff /// ::= .macros_on /// ::= .macros_off @@ -2022,6 +2467,26 @@ bool GenericAsmParser::ParseDirectiveEndMacro(StringRef Directive, "no current macro definition"); } +bool GenericAsmParser::ParseDirectiveLEB128(StringRef DirName, SMLoc) { + getParser().CheckForValidSection(); + + const MCExpr *Value; + + if (getParser().ParseExpression(Value)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + if (DirName[1] == 's') + getStreamer().EmitSLEB128Value(Value); + else + getStreamer().EmitULEB128Value(Value); + + return false; +} + + /// \brief Create an MCAsmParser instance. MCAsmParser *llvm::createMCAsmParser(const Target &T, SourceMgr &SM, MCContext &C, MCStreamer &Out, diff --git a/lib/MC/MCParser/CMakeLists.txt b/lib/MC/MCParser/CMakeLists.txt index 25a7bf484212..eaea9f6cd3c5 100644 --- a/lib/MC/MCParser/CMakeLists.txt +++ b/lib/MC/MCParser/CMakeLists.txt @@ -1,6 +1,7 @@ add_llvm_library(LLVMMCParser AsmLexer.cpp AsmParser.cpp + COFFAsmParser.cpp DarwinAsmParser.cpp ELFAsmParser.cpp MCAsmLexer.cpp diff --git a/lib/MC/MCParser/COFFAsmParser.cpp b/lib/MC/MCParser/COFFAsmParser.cpp new file mode 100644 index 000000000000..5ecab03b00f0 --- /dev/null +++ b/lib/MC/MCParser/COFFAsmParser.cpp @@ -0,0 +1,144 @@ +//===- COFFAsmParser.cpp - COFF Assembly Parser ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCParser/MCAsmParserExtension.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCSectionCOFF.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Support/COFF.h" +using namespace llvm; + +namespace { + +class COFFAsmParser : public MCAsmParserExtension { + template + void AddDirectiveHandler(StringRef Directive) { + getParser().AddDirectiveHandler(this, Directive, + HandleDirective); + } + + bool ParseSectionSwitch(StringRef Section, + unsigned Characteristics, + SectionKind Kind); + + virtual void Initialize(MCAsmParser &Parser) { + // Call the base implementation. + MCAsmParserExtension::Initialize(Parser); + + AddDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text"); + AddDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data"); + AddDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss"); + AddDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def"); + AddDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl"); + AddDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type"); + AddDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef"); + } + + bool ParseSectionDirectiveText(StringRef, SMLoc) { + return ParseSectionSwitch(".text", + COFF::IMAGE_SCN_CNT_CODE + | COFF::IMAGE_SCN_MEM_EXECUTE + | COFF::IMAGE_SCN_MEM_READ, + SectionKind::getText()); + } + bool ParseSectionDirectiveData(StringRef, SMLoc) { + return ParseSectionSwitch(".data", + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA + | COFF::IMAGE_SCN_MEM_READ + | COFF::IMAGE_SCN_MEM_WRITE, + SectionKind::getDataRel()); + } + bool ParseSectionDirectiveBSS(StringRef, SMLoc) { + return ParseSectionSwitch(".bss", + COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA + | COFF::IMAGE_SCN_MEM_READ + | COFF::IMAGE_SCN_MEM_WRITE, + SectionKind::getBSS()); + } + + bool ParseDirectiveDef(StringRef, SMLoc); + bool ParseDirectiveScl(StringRef, SMLoc); + bool ParseDirectiveType(StringRef, SMLoc); + bool ParseDirectiveEndef(StringRef, SMLoc); + +public: + COFFAsmParser() {} +}; + +} // end annonomous namespace. + +bool COFFAsmParser::ParseSectionSwitch(StringRef Section, + unsigned Characteristics, + SectionKind Kind) { + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in section switching directive"); + Lex(); + + getStreamer().SwitchSection(getContext().getCOFFSection( + Section, Characteristics, Kind)); + + return false; +} + +bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) { + StringRef SymbolName; + + if (getParser().ParseIdentifier(SymbolName)) + return TokError("expected identifier in directive"); + + MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName); + + getStreamer().BeginCOFFSymbolDef(Sym); + + Lex(); + return false; +} + +bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) { + int64_t SymbolStorageClass; + if (getParser().ParseAbsoluteExpression(SymbolStorageClass)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass); + return false; +} + +bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) { + int64_t Type; + if (getParser().ParseAbsoluteExpression(Type)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + getStreamer().EmitCOFFSymbolType(Type); + return false; +} + +bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) { + Lex(); + getStreamer().EndCOFFSymbolDef(); + return false; +} + +namespace llvm { + +MCAsmParserExtension *createCOFFAsmParser() { + return new COFFAsmParser; +} + +} diff --git a/lib/MC/MCParser/DarwinAsmParser.cpp b/lib/MC/MCParser/DarwinAsmParser.cpp index 54ddb449b285..44f234566afd 100644 --- a/lib/MC/MCParser/DarwinAsmParser.cpp +++ b/lib/MC/MCParser/DarwinAsmParser.cpp @@ -305,7 +305,7 @@ bool DarwinAsmParser::ParseSectionSwitch(const char *Segment, // // FIXME: This isn't really what 'as' does; I think it just uses the implicit // alignment on the section (e.g., if one manually inserts bytes into the - // section, then just issueing the section switch directive will not realign + // section, then just issuing the section switch directive will not realign // the section. However, this is arguably more reasonable behavior, and there // is no good reason for someone to intentionally emit incorrectly sized // values into the implicitly aligned sections. diff --git a/lib/MC/MCParser/ELFAsmParser.cpp b/lib/MC/MCParser/ELFAsmParser.cpp index f982fdaecb12..bfaf36a451b3 100644 --- a/lib/MC/MCParser/ELFAsmParser.cpp +++ b/lib/MC/MCParser/ELFAsmParser.cpp @@ -8,13 +8,15 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCParser/MCAsmParserExtension.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCStreamer.h" -#include "llvm/ADT/Twine.h" +#include "llvm/Support/ELF.h" using namespace llvm; namespace { @@ -47,72 +49,86 @@ public: AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveDataRelRoLocal>(".data.rel.ro.local"); AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveEhFrame>(".eh_frame"); AddDirectiveHandler<&ELFAsmParser::ParseDirectiveSection>(".section"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectivePushSection>(".pushsection"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectivePopSection>(".popsection"); AddDirectiveHandler<&ELFAsmParser::ParseDirectiveSize>(".size"); - AddDirectiveHandler<&ELFAsmParser::ParseDirectiveLEB128>(".sleb128"); - AddDirectiveHandler<&ELFAsmParser::ParseDirectiveLEB128>(".uleb128"); AddDirectiveHandler<&ELFAsmParser::ParseDirectivePrevious>(".previous"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectiveType>(".type"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectiveIdent>(".ident"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectiveSymver>(".symver"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectiveWeakref>(".weakref"); } + // FIXME: Part of this logic is duplicated in the MCELFStreamer. What is + // the best way for us to get access to it? bool ParseSectionDirectiveData(StringRef, SMLoc) { - return ParseSectionSwitch(".data", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_WRITE |MCSectionELF::SHF_ALLOC, + return ParseSectionSwitch(".data", ELF::SHT_PROGBITS, + ELF::SHF_WRITE |ELF::SHF_ALLOC, SectionKind::getDataRel()); } bool ParseSectionDirectiveText(StringRef, SMLoc) { - return ParseSectionSwitch(".text", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_EXECINSTR | - MCSectionELF::SHF_ALLOC, SectionKind::getText()); + return ParseSectionSwitch(".text", ELF::SHT_PROGBITS, + ELF::SHF_EXECINSTR | + ELF::SHF_ALLOC, SectionKind::getText()); } bool ParseSectionDirectiveBSS(StringRef, SMLoc) { - return ParseSectionSwitch(".bss", MCSectionELF::SHT_NOBITS, - MCSectionELF::SHF_WRITE | - MCSectionELF::SHF_ALLOC, SectionKind::getBSS()); + return ParseSectionSwitch(".bss", ELF::SHT_NOBITS, + ELF::SHF_WRITE | + ELF::SHF_ALLOC, SectionKind::getBSS()); } bool ParseSectionDirectiveRoData(StringRef, SMLoc) { - return ParseSectionSwitch(".rodata", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC, + return ParseSectionSwitch(".rodata", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC, SectionKind::getReadOnly()); } bool ParseSectionDirectiveTData(StringRef, SMLoc) { - return ParseSectionSwitch(".tdata", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC | - MCSectionELF::SHF_TLS | MCSectionELF::SHF_WRITE, + return ParseSectionSwitch(".tdata", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | + ELF::SHF_TLS | ELF::SHF_WRITE, SectionKind::getThreadData()); } bool ParseSectionDirectiveTBSS(StringRef, SMLoc) { - return ParseSectionSwitch(".tbss", MCSectionELF::SHT_NOBITS, - MCSectionELF::SHF_ALLOC | - MCSectionELF::SHF_TLS | MCSectionELF::SHF_WRITE, + return ParseSectionSwitch(".tbss", ELF::SHT_NOBITS, + ELF::SHF_ALLOC | + ELF::SHF_TLS | ELF::SHF_WRITE, SectionKind::getThreadBSS()); } bool ParseSectionDirectiveDataRel(StringRef, SMLoc) { - return ParseSectionSwitch(".data.rel", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC | - MCSectionELF::SHF_WRITE, + return ParseSectionSwitch(".data.rel", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | + ELF::SHF_WRITE, SectionKind::getDataRel()); } bool ParseSectionDirectiveDataRelRo(StringRef, SMLoc) { - return ParseSectionSwitch(".data.rel.ro", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC | - MCSectionELF::SHF_WRITE, + return ParseSectionSwitch(".data.rel.ro", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | + ELF::SHF_WRITE, SectionKind::getReadOnlyWithRel()); } bool ParseSectionDirectiveDataRelRoLocal(StringRef, SMLoc) { - return ParseSectionSwitch(".data.rel.ro.local", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC | - MCSectionELF::SHF_WRITE, + return ParseSectionSwitch(".data.rel.ro.local", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | + ELF::SHF_WRITE, SectionKind::getReadOnlyWithRelLocal()); } bool ParseSectionDirectiveEhFrame(StringRef, SMLoc) { - return ParseSectionSwitch(".eh_frame", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC | - MCSectionELF::SHF_WRITE, + return ParseSectionSwitch(".eh_frame", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | + ELF::SHF_WRITE, SectionKind::getDataRel()); } - bool ParseDirectiveLEB128(StringRef, SMLoc); + bool ParseDirectivePushSection(StringRef, SMLoc); + bool ParseDirectivePopSection(StringRef, SMLoc); bool ParseDirectiveSection(StringRef, SMLoc); bool ParseDirectiveSize(StringRef, SMLoc); bool ParseDirectivePrevious(StringRef, SMLoc); + bool ParseDirectiveType(StringRef, SMLoc); + bool ParseDirectiveIdent(StringRef, SMLoc); + bool ParseDirectiveSymver(StringRef, SMLoc); + bool ParseDirectiveWeakref(StringRef, SMLoc); + +private: + bool ParseSectionName(StringRef &SectionName); }; } @@ -150,135 +166,359 @@ bool ELFAsmParser::ParseDirectiveSize(StringRef, SMLoc) { return false; } -// FIXME: This is a work in progress. -bool ELFAsmParser::ParseDirectiveSection(StringRef, SMLoc) { - StringRef SectionName; - // FIXME: This doesn't parse section names like ".note.GNU-stack" correctly. - if (getParser().ParseIdentifier(SectionName)) - return TokError("expected identifier in directive"); - - std::string FlagsStr; - StringRef TypeName; - int64_t Size = 0; - if (getLexer().is(AsmToken::Comma)) { - Lex(); - - if (getLexer().isNot(AsmToken::String)) - return TokError("expected string in directive"); +bool ELFAsmParser::ParseSectionName(StringRef &SectionName) { + // A section name can contain -, so we cannot just use + // ParseIdentifier. + SMLoc FirstLoc = getLexer().getLoc(); + unsigned Size = 0; - FlagsStr = getTok().getStringContents(); + if (getLexer().is(AsmToken::String)) { + SectionName = getTok().getIdentifier(); Lex(); + return false; + } - AsmToken::TokenKind TypeStartToken; - if (getContext().getAsmInfo().getCommentString()[0] == '@') - TypeStartToken = AsmToken::Percent; - else - TypeStartToken = AsmToken::At; + for (;;) { + StringRef Tmp; + unsigned CurSize; - if (getLexer().is(AsmToken::Comma)) { + SMLoc PrevLoc = getLexer().getLoc(); + if (getLexer().is(AsmToken::Minus)) { + CurSize = 1; + Lex(); // Consume the "-". + } else if (getLexer().is(AsmToken::String)) { + CurSize = getTok().getIdentifier().size() + 2; Lex(); - if (getLexer().is(TypeStartToken)) { - Lex(); - if (getParser().ParseIdentifier(TypeName)) - return TokError("expected identifier in directive"); - - if (getLexer().is(AsmToken::Comma)) { - Lex(); + } else if (getLexer().is(AsmToken::Identifier)) { + CurSize = getTok().getIdentifier().size(); + Lex(); + } else { + break; + } - if (getParser().ParseAbsoluteExpression(Size)) - return true; + Size += CurSize; + SectionName = StringRef(FirstLoc.getPointer(), Size); - if (Size <= 0) - return TokError("section size must be positive"); - } - } - } + // Make sure the following token is adjacent. + if (PrevLoc.getPointer() + CurSize != getTok().getLoc().getPointer()) + break; } + if (Size == 0) + return true; - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); + return false; +} - unsigned Flags = 0; - for (unsigned i = 0; i < FlagsStr.size(); i++) { - switch (FlagsStr[i]) { +static SectionKind computeSectionKind(unsigned Flags) { + if (Flags & ELF::SHF_EXECINSTR) + return SectionKind::getText(); + if (Flags & ELF::SHF_TLS) + return SectionKind::getThreadData(); + return SectionKind::getDataRel(); +} + +static int parseSectionFlags(StringRef flagsStr) { + int flags = 0; + + for (unsigned i = 0; i < flagsStr.size(); i++) { + switch (flagsStr[i]) { case 'a': - Flags |= MCSectionELF::SHF_ALLOC; + flags |= ELF::SHF_ALLOC; break; case 'x': - Flags |= MCSectionELF::SHF_EXECINSTR; + flags |= ELF::SHF_EXECINSTR; break; case 'w': - Flags |= MCSectionELF::SHF_WRITE; + flags |= ELF::SHF_WRITE; break; case 'M': - Flags |= MCSectionELF::SHF_MERGE; + flags |= ELF::SHF_MERGE; break; case 'S': - Flags |= MCSectionELF::SHF_STRINGS; + flags |= ELF::SHF_STRINGS; break; case 'T': - Flags |= MCSectionELF::SHF_TLS; + flags |= ELF::SHF_TLS; break; case 'c': - Flags |= MCSectionELF::XCORE_SHF_CP_SECTION; + flags |= ELF::XCORE_SHF_CP_SECTION; break; case 'd': - Flags |= MCSectionELF::XCORE_SHF_DP_SECTION; + flags |= ELF::XCORE_SHF_DP_SECTION; + break; + case 'G': + flags |= ELF::SHF_GROUP; break; default: + return -1; + } + } + + return flags; +} + +bool ELFAsmParser::ParseDirectivePushSection(StringRef s, SMLoc loc) { + getStreamer().PushSection(); + + if (ParseDirectiveSection(s, loc)) { + getStreamer().PopSection(); + return true; + } + + return false; +} + +bool ELFAsmParser::ParseDirectivePopSection(StringRef, SMLoc) { + if (!getStreamer().PopSection()) + return TokError(".popsection without corresponding .pushsection"); + return false; +} + +// FIXME: This is a work in progress. +bool ELFAsmParser::ParseDirectiveSection(StringRef, SMLoc) { + StringRef SectionName; + + if (ParseSectionName(SectionName)) + return TokError("expected identifier in directive"); + + StringRef TypeName; + int64_t Size = 0; + StringRef GroupName; + unsigned Flags = 0; + + // Set the defaults first. + if (SectionName == ".fini" || SectionName == ".init" || + SectionName == ".rodata") + Flags |= ELF::SHF_ALLOC; + if (SectionName == ".fini" || SectionName == ".init") + Flags |= ELF::SHF_EXECINSTR; + + if (getLexer().is(AsmToken::Comma)) { + Lex(); + + if (getLexer().isNot(AsmToken::String)) + return TokError("expected string in directive"); + + StringRef FlagsStr = getTok().getStringContents(); + Lex(); + + int extraFlags = parseSectionFlags(FlagsStr); + if (extraFlags < 0) return TokError("unknown flag"); + Flags |= extraFlags; + + bool Mergeable = Flags & ELF::SHF_MERGE; + bool Group = Flags & ELF::SHF_GROUP; + + if (getLexer().isNot(AsmToken::Comma)) { + if (Mergeable) + return TokError("Mergeable section must specify the type"); + if (Group) + return TokError("Group section must specify the type"); + } else { + Lex(); + if (getLexer().isNot(AsmToken::Percent) && getLexer().isNot(AsmToken::At)) + return TokError("expected '@' or '%' before type"); + + Lex(); + if (getParser().ParseIdentifier(TypeName)) + return TokError("expected identifier in directive"); + + if (Mergeable) { + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected the entry size"); + Lex(); + if (getParser().ParseAbsoluteExpression(Size)) + return true; + if (Size <= 0) + return TokError("entry size must be positive"); + } + + if (Group) { + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected group name"); + Lex(); + if (getParser().ParseIdentifier(GroupName)) + return true; + if (getLexer().is(AsmToken::Comma)) { + Lex(); + StringRef Linkage; + if (getParser().ParseIdentifier(Linkage)) + return true; + if (Linkage != "comdat") + return TokError("Linkage must be 'comdat'"); + } + } } } - unsigned Type = MCSectionELF::SHT_NULL; + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + unsigned Type = ELF::SHT_PROGBITS; + if (!TypeName.empty()) { if (TypeName == "init_array") - Type = MCSectionELF::SHT_INIT_ARRAY; + Type = ELF::SHT_INIT_ARRAY; else if (TypeName == "fini_array") - Type = MCSectionELF::SHT_FINI_ARRAY; + Type = ELF::SHT_FINI_ARRAY; else if (TypeName == "preinit_array") - Type = MCSectionELF::SHT_PREINIT_ARRAY; + Type = ELF::SHT_PREINIT_ARRAY; else if (TypeName == "nobits") - Type = MCSectionELF::SHT_NOBITS; + Type = ELF::SHT_NOBITS; else if (TypeName == "progbits") - Type = MCSectionELF::SHT_PROGBITS; + Type = ELF::SHT_PROGBITS; + else if (TypeName == "note") + Type = ELF::SHT_NOTE; + else if (TypeName == "unwind") + Type = ELF::SHT_X86_64_UNWIND; else return TokError("unknown section type"); } - SectionKind Kind = (Flags & MCSectionELF::SHF_EXECINSTR) - ? SectionKind::getText() - : SectionKind::getDataRel(); + SectionKind Kind = computeSectionKind(Flags); getStreamer().SwitchSection(getContext().getELFSection(SectionName, Type, - Flags, Kind, false)); + Flags, Kind, Size, + GroupName)); return false; } -bool ELFAsmParser::ParseDirectiveLEB128(StringRef DirName, SMLoc) { - int64_t Value; - if (getParser().ParseAbsoluteExpression(Value)) - return true; +bool ELFAsmParser::ParseDirectivePrevious(StringRef DirName, SMLoc) { + const MCSection *PreviousSection = getStreamer().getPreviousSection(); + if (PreviousSection == NULL) + return TokError(".previous without corresponding .section"); + getStreamer().SwitchSection(PreviousSection); + + return false; +} + +/// ParseDirectiveELFType +/// ::= .type identifier , @attribute +bool ELFAsmParser::ParseDirectiveType(StringRef, SMLoc) { + StringRef Name; + if (getParser().ParseIdentifier(Name)) + return TokError("expected identifier in directive"); + + // Handle the identifier as the key symbol. + MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in '.type' directive"); + Lex(); + + if (getLexer().isNot(AsmToken::Percent) && getLexer().isNot(AsmToken::At)) + return TokError("expected '@' or '%' before type"); + Lex(); + + StringRef Type; + SMLoc TypeLoc; + + TypeLoc = getLexer().getLoc(); + if (getParser().ParseIdentifier(Type)) + return TokError("expected symbol type in directive"); + + MCSymbolAttr Attr = StringSwitch(Type) + .Case("function", MCSA_ELF_TypeFunction) + .Case("object", MCSA_ELF_TypeObject) + .Case("tls_object", MCSA_ELF_TypeTLS) + .Case("common", MCSA_ELF_TypeCommon) + .Case("notype", MCSA_ELF_TypeNoType) + .Case("gnu_unique_object", MCSA_ELF_TypeGnuUniqueObject) + .Default(MCSA_Invalid); + + if (Attr == MCSA_Invalid) + return Error(TypeLoc, "unsupported attribute in '.type' directive"); if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); + return TokError("unexpected token in '.type' directive"); - // FIXME: Add proper MC support. - if (getContext().getAsmInfo().hasLEB128()) { - if (DirName[1] == 's') - getStreamer().EmitRawText("\t.sleb128\t" + Twine(Value)); - else - getStreamer().EmitRawText("\t.uleb128\t" + Twine(Value)); - return false; - } - // FIXME: This shouldn't be an error! - return TokError("LEB128 not supported yet"); + Lex(); + + getStreamer().EmitSymbolAttribute(Sym, Attr); + + return false; } -bool ELFAsmParser::ParseDirectivePrevious(StringRef DirName, SMLoc) { - const MCSection *PreviousSection = getStreamer().getPreviousSection(); - if (PreviousSection != NULL) - getStreamer().SwitchSection(PreviousSection); +/// ParseDirectiveIdent +/// ::= .ident string +bool ELFAsmParser::ParseDirectiveIdent(StringRef, SMLoc) { + if (getLexer().isNot(AsmToken::String)) + return TokError("unexpected token in '.ident' directive"); + + StringRef Data = getTok().getIdentifier(); + + Lex(); + + const MCSection *Comment = + getContext().getELFSection(".comment", ELF::SHT_PROGBITS, + ELF::SHF_MERGE | + ELF::SHF_STRINGS, + SectionKind::getReadOnly(), + 1, ""); + + static bool First = true; + + getStreamer().PushSection(); + getStreamer().SwitchSection(Comment); + if (First) + getStreamer().EmitIntValue(0, 1); + First = false; + getStreamer().EmitBytes(Data, 0); + getStreamer().EmitIntValue(0, 1); + getStreamer().PopSection(); + return false; +} + +/// ParseDirectiveSymver +/// ::= .symver foo, bar2@zed +bool ELFAsmParser::ParseDirectiveSymver(StringRef, SMLoc) { + StringRef Name; + if (getParser().ParseIdentifier(Name)) + return TokError("expected identifier in directive"); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected a comma"); + + Lex(); + + StringRef AliasName; + if (getParser().ParseIdentifier(AliasName)) + return TokError("expected identifier in directive"); + + if (AliasName.find('@') == StringRef::npos) + return TokError("expected a '@' in the name"); + + MCSymbol *Alias = getContext().GetOrCreateSymbol(AliasName); + MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); + const MCExpr *Value = MCSymbolRefExpr::Create(Sym, getContext()); + + getStreamer().EmitAssignment(Alias, Value); + return false; +} + +/// ParseDirectiveWeakref +/// ::= .weakref foo, bar +bool ELFAsmParser::ParseDirectiveWeakref(StringRef, SMLoc) { + // FIXME: Share code with the other alias building directives. + + StringRef AliasName; + if (getParser().ParseIdentifier(AliasName)) + return TokError("expected identifier in directive"); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected a comma"); + + Lex(); + + StringRef Name; + if (getParser().ParseIdentifier(Name)) + return TokError("expected identifier in directive"); + + MCSymbol *Alias = getContext().GetOrCreateSymbol(AliasName); + + MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); + getStreamer().EmitWeakReference(Alias, Sym); return false; } diff --git a/lib/MC/MCPureStreamer.cpp b/lib/MC/MCPureStreamer.cpp new file mode 100644 index 000000000000..6098e6b8f38b --- /dev/null +++ b/lib/MC/MCPureStreamer.cpp @@ -0,0 +1,234 @@ +//===- lib/MC/MCPureStreamer.cpp - MC "Pure" Object Output ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCObjectStreamer.h" +// FIXME: Remove this. +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +namespace { + +class MCPureStreamer : public MCObjectStreamer { +private: + virtual void EmitInstToFragment(const MCInst &Inst); + virtual void EmitInstToData(const MCInst &Inst); + +public: + MCPureStreamer(MCContext &Context, TargetAsmBackend &TAB, + raw_ostream &OS, MCCodeEmitter *Emitter) + : MCObjectStreamer(Context, TAB, OS, Emitter) {} + + /// @name MCStreamer Interface + /// @{ + + virtual void InitSections(); + virtual void EmitLabel(MCSymbol *Symbol); + virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); + virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, + unsigned Size = 0, unsigned ByteAlignment = 0); + virtual void EmitBytes(StringRef Data, unsigned AddrSpace); + virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, + unsigned ValueSize = 1, + unsigned MaxBytesToEmit = 0); + virtual void EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit = 0); + virtual void EmitValueToOffset(const MCExpr *Offset, + unsigned char Value = 0); + virtual void Finish(); + + + virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitAssemblerFlag(MCAssemblerFlag Flag) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment = 0) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitThumbFunc(MCSymbol *Func) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitCOFFSymbolStorageClass(int StorageClass) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitCOFFSymbolType(int Type) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EndCOFFSymbolDef() { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitFileDirective(StringRef Filename) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual bool EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) { + report_fatal_error("unsupported directive in pure streamer"); + return false; + } + + /// @} +}; + +} // end anonymous namespace. + +void MCPureStreamer::InitSections() { + // FIMXE: To what!? + SwitchSection(getContext().getMachOSection("__TEXT", "__text", + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + 0, SectionKind::getText())); + +} + +void MCPureStreamer::EmitLabel(MCSymbol *Symbol) { + assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); + assert(!Symbol->isVariable() && "Cannot emit a variable symbol!"); + assert(getCurrentSection() && "Cannot emit before setting section!"); + + Symbol->setSection(*getCurrentSection()); + + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + + // We have to create a new fragment if this is an atom defining symbol, + // fragments cannot span atoms. + if (getAssembler().isSymbolLinkerVisible(SD.getSymbol())) + new MCDataFragment(getCurrentSectionData()); + + // FIXME: This is wasteful, we don't necessarily need to create a data + // fragment. Instead, we should mark the symbol as pointing into the data + // fragment if it exists, otherwise we should just queue the label and set its + // fragment pointer when we emit the next fragment. + MCDataFragment *F = getOrCreateDataFragment(); + assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); + SD.setFragment(F); + SD.setOffset(F->getContents().size()); +} + +void MCPureStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. + // FIXME: Lift context changes into super class. + getAssembler().getOrCreateSymbolData(*Symbol); + Symbol->setVariableValue(AddValueSymbols(Value)); +} + +void MCPureStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, + unsigned Size, unsigned ByteAlignment) { + report_fatal_error("not yet implemented in pure streamer"); +} + +void MCPureStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. + getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end()); +} + +void MCPureStreamer::EmitValueToAlignment(unsigned ByteAlignment, + int64_t Value, unsigned ValueSize, + unsigned MaxBytesToEmit) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. + if (MaxBytesToEmit == 0) + MaxBytesToEmit = ByteAlignment; + new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit, + getCurrentSectionData()); + + // Update the maximum alignment on the current section if necessary. + if (ByteAlignment > getCurrentSectionData()->getAlignment()) + getCurrentSectionData()->setAlignment(ByteAlignment); +} + +void MCPureStreamer::EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. + if (MaxBytesToEmit == 0) + MaxBytesToEmit = ByteAlignment; + MCAlignFragment *F = new MCAlignFragment(ByteAlignment, 0, 1, MaxBytesToEmit, + getCurrentSectionData()); + F->setEmitNops(true); + + // Update the maximum alignment on the current section if necessary. + if (ByteAlignment > getCurrentSectionData()->getAlignment()) + getCurrentSectionData()->setAlignment(ByteAlignment); +} + +void MCPureStreamer::EmitValueToOffset(const MCExpr *Offset, + unsigned char Value) { + new MCOrgFragment(*Offset, Value, getCurrentSectionData()); +} + +void MCPureStreamer::EmitInstToFragment(const MCInst &Inst) { + MCInstFragment *IF = new MCInstFragment(Inst, getCurrentSectionData()); + + // Add the fixups and data. + // + // FIXME: Revisit this design decision when relaxation is done, we may be + // able to get away with not storing any extra data in the MCInst. + SmallVector Fixups; + SmallString<256> Code; + raw_svector_ostream VecOS(Code); + getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups); + VecOS.flush(); + + IF->getCode() = Code; + IF->getFixups() = Fixups; +} + +void MCPureStreamer::EmitInstToData(const MCInst &Inst) { + MCDataFragment *DF = getOrCreateDataFragment(); + + SmallVector Fixups; + SmallString<256> Code; + raw_svector_ostream VecOS(Code); + getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups); + VecOS.flush(); + + // Add the fixups and data. + for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { + Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size()); + DF->addFixup(Fixups[i]); + } + DF->getContents().append(Code.begin(), Code.end()); +} + +void MCPureStreamer::Finish() { + // FIXME: Handle DWARF tables? + + this->MCObjectStreamer::Finish(); +} + +MCStreamer *llvm::createPureStreamer(MCContext &Context, TargetAsmBackend &TAB, + raw_ostream &OS, MCCodeEmitter *CE) { + return new MCPureStreamer(Context, TAB, OS, CE); +} diff --git a/lib/MC/MCSectionCOFF.cpp b/lib/MC/MCSectionCOFF.cpp index eb531600f727..90091f06e9ac 100644 --- a/lib/MC/MCSectionCOFF.cpp +++ b/lib/MC/MCSectionCOFF.cpp @@ -74,3 +74,11 @@ void MCSectionCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, } } } + +bool MCSectionCOFF::UseCodeAlign() const { + return getKind().isText(); +} + +bool MCSectionCOFF::isVirtualSection() const { + return getCharacteristics() & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA; +} diff --git a/lib/MC/MCSectionELF.cpp b/lib/MC/MCSectionELF.cpp index a7599de1b7b4..d32aea144e6e 100644 --- a/lib/MC/MCSectionELF.cpp +++ b/lib/MC/MCSectionELF.cpp @@ -11,7 +11,9 @@ #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/Support/ELF.h" #include "llvm/Support/raw_ostream.h" + using namespace llvm; MCSectionELF::~MCSectionELF() {} // anchor. @@ -29,14 +31,6 @@ bool MCSectionELF::ShouldOmitSectionDirective(StringRef Name, return false; } -// ShouldPrintSectionType - Only prints the section type if supported -bool MCSectionELF::ShouldPrintSectionType(unsigned Ty) const { - if (IsExplicit && !(Ty == SHT_NOBITS || Ty == SHT_PROGBITS)) - return false; - - return true; -} - void MCSectionELF::PrintSwitchToSection(const MCAsmInfo &MAI, raw_ostream &OS) const { @@ -49,87 +43,88 @@ void MCSectionELF::PrintSwitchToSection(const MCAsmInfo &MAI, // Handle the weird solaris syntax if desired. if (MAI.usesSunStyleELFSectionSwitchSyntax() && - !(Flags & MCSectionELF::SHF_MERGE)) { - if (Flags & MCSectionELF::SHF_ALLOC) + !(Flags & ELF::SHF_MERGE)) { + if (Flags & ELF::SHF_ALLOC) OS << ",#alloc"; - if (Flags & MCSectionELF::SHF_EXECINSTR) + if (Flags & ELF::SHF_EXECINSTR) OS << ",#execinstr"; - if (Flags & MCSectionELF::SHF_WRITE) + if (Flags & ELF::SHF_WRITE) OS << ",#write"; - if (Flags & MCSectionELF::SHF_TLS) + if (Flags & ELF::SHF_TLS) OS << ",#tls"; OS << '\n'; return; } OS << ",\""; - if (Flags & MCSectionELF::SHF_ALLOC) + if (Flags & ELF::SHF_ALLOC) OS << 'a'; - if (Flags & MCSectionELF::SHF_EXECINSTR) + if (Flags & ELF::SHF_EXECINSTR) OS << 'x'; - if (Flags & MCSectionELF::SHF_WRITE) + if (Flags & ELF::SHF_GROUP) + OS << 'G'; + if (Flags & ELF::SHF_WRITE) OS << 'w'; - if (Flags & MCSectionELF::SHF_MERGE) + if (Flags & ELF::SHF_MERGE) OS << 'M'; - if (Flags & MCSectionELF::SHF_STRINGS) + if (Flags & ELF::SHF_STRINGS) OS << 'S'; - if (Flags & MCSectionELF::SHF_TLS) + if (Flags & ELF::SHF_TLS) OS << 'T'; // If there are target-specific flags, print them. - if (Flags & MCSectionELF::XCORE_SHF_CP_SECTION) + if (Flags & ELF::XCORE_SHF_CP_SECTION) OS << 'c'; - if (Flags & MCSectionELF::XCORE_SHF_DP_SECTION) + if (Flags & ELF::XCORE_SHF_DP_SECTION) OS << 'd'; OS << '"'; - if (ShouldPrintSectionType(Type)) { - OS << ','; - - // If comment string is '@', e.g. as on ARM - use '%' instead - if (MAI.getCommentString()[0] == '@') - OS << '%'; - else - OS << '@'; - - if (Type == MCSectionELF::SHT_INIT_ARRAY) - OS << "init_array"; - else if (Type == MCSectionELF::SHT_FINI_ARRAY) - OS << "fini_array"; - else if (Type == MCSectionELF::SHT_PREINIT_ARRAY) - OS << "preinit_array"; - else if (Type == MCSectionELF::SHT_NOBITS) - OS << "nobits"; - else if (Type == MCSectionELF::SHT_PROGBITS) - OS << "progbits"; - - if (getKind().isMergeable1ByteCString()) { - OS << ",1"; - } else if (getKind().isMergeable2ByteCString()) { - OS << ",2"; - } else if (getKind().isMergeable4ByteCString() || - getKind().isMergeableConst4()) { - OS << ",4"; - } else if (getKind().isMergeableConst8()) { - OS << ",8"; - } else if (getKind().isMergeableConst16()) { - OS << ",16"; - } + OS << ','; + + // If comment string is '@', e.g. as on ARM - use '%' instead + if (MAI.getCommentString()[0] == '@') + OS << '%'; + else + OS << '@'; + + if (Type == ELF::SHT_INIT_ARRAY) + OS << "init_array"; + else if (Type == ELF::SHT_FINI_ARRAY) + OS << "fini_array"; + else if (Type == ELF::SHT_PREINIT_ARRAY) + OS << "preinit_array"; + else if (Type == ELF::SHT_NOBITS) + OS << "nobits"; + else if (Type == ELF::SHT_NOTE) + OS << "note"; + else if (Type == ELF::SHT_PROGBITS) + OS << "progbits"; + + if (EntrySize) { + assert(Flags & ELF::SHF_MERGE); + OS << "," << EntrySize; } - + + if (Flags & ELF::SHF_GROUP) + OS << "," << Group->getName() << ",comdat"; OS << '\n'; } -// HasCommonSymbols - True if this section holds common symbols, this is -// indicated on the ELF object file by a symbol with SHN_COMMON section -// header index. -bool MCSectionELF::HasCommonSymbols() const { - - if (StringRef(SectionName).startswith(".gnu.linkonce.")) - return true; - - return false; +bool MCSectionELF::UseCodeAlign() const { + return getFlags() & ELF::SHF_EXECINSTR; } +bool MCSectionELF::isVirtualSection() const { + return getType() == ELF::SHT_NOBITS; +} +unsigned MCSectionELF::DetermineEntrySize(SectionKind Kind) { + if (Kind.isMergeable1ByteCString()) return 1; + if (Kind.isMergeable2ByteCString()) return 2; + if (Kind.isMergeable4ByteCString()) return 4; + if (Kind.isMergeableConst4()) return 4; + if (Kind.isMergeableConst8()) return 8; + if (Kind.isMergeableConst16()) return 16; + return 0; +} diff --git a/lib/MC/MCSectionMachO.cpp b/lib/MC/MCSectionMachO.cpp index ded3b20eaf53..b897c0bd6855 100644 --- a/lib/MC/MCSectionMachO.cpp +++ b/lib/MC/MCSectionMachO.cpp @@ -10,6 +10,7 @@ #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCContext.h" #include "llvm/Support/raw_ostream.h" +#include using namespace llvm; /// SectionTypeDescriptors - These are strings that describe the various section @@ -81,18 +82,18 @@ MCSectionMachO::MCSectionMachO(StringRef Segment, StringRef Section, SegmentName[i] = Segment[i]; else SegmentName[i] = 0; - + if (i < Section.size()) SectionName[i] = Section[i]; else SectionName[i] = 0; - } + } } void MCSectionMachO::PrintSwitchToSection(const MCAsmInfo &MAI, raw_ostream &OS) const { OS << "\t.section\t" << getSegmentName() << ',' << getSectionName(); - + // Get the section type and attributes. unsigned TAA = getTypeAndAttributes(); if (TAA == 0) { @@ -101,7 +102,7 @@ void MCSectionMachO::PrintSwitchToSection(const MCAsmInfo &MAI, } OS << ','; - + unsigned SectionType = TAA & MCSectionMachO::SECTION_TYPE; assert(SectionType <= MCSectionMachO::LAST_KNOWN_SECTION_TYPE && "Invalid SectionType specified!"); @@ -110,7 +111,7 @@ void MCSectionMachO::PrintSwitchToSection(const MCAsmInfo &MAI, OS << SectionTypeDescriptors[SectionType].AssemblerName; else OS << "<<" << SectionTypeDescriptors[SectionType].EnumName << ">>"; - + // If we don't have any attributes, we're done. unsigned SectionAttrs = TAA & MCSectionMachO::SECTION_ATTRIBUTES; if (SectionAttrs == 0) { @@ -128,10 +129,10 @@ void MCSectionMachO::PrintSwitchToSection(const MCAsmInfo &MAI, // Check to see if we have this attribute. if ((SectionAttrDescriptors[i].AttrFlag & SectionAttrs) == 0) continue; - + // Yep, clear it and print it. SectionAttrs &= ~SectionAttrDescriptors[i].AttrFlag; - + OS << Separator; if (SectionAttrDescriptors[i].AssemblerName) OS << SectionAttrDescriptors[i].AssemblerName; @@ -139,15 +140,25 @@ void MCSectionMachO::PrintSwitchToSection(const MCAsmInfo &MAI, OS << "<<" << SectionAttrDescriptors[i].EnumName << ">>"; Separator = '+'; } - + assert(SectionAttrs == 0 && "Unknown section attributes!"); - + // If we have a S_SYMBOL_STUBS size specified, print it. if (Reserved2 != 0) OS << ',' << Reserved2; OS << '\n'; } +bool MCSectionMachO::UseCodeAlign() const { + return hasAttribute(MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS); +} + +bool MCSectionMachO::isVirtualSection() const { + return (getType() == MCSectionMachO::S_ZEROFILL || + getType() == MCSectionMachO::S_GB_ZEROFILL || + getType() == MCSectionMachO::S_THREAD_LOCAL_ZEROFILL); +} + /// StripSpaces - This removes leading and trailing spaces from the StringRef. static void StripSpaces(StringRef &Str) { while (!Str.empty() && isspace(Str[0])) @@ -168,12 +179,12 @@ std::string MCSectionMachO::ParseSectionSpecifier(StringRef Spec, // In. unsigned &StubSize) { // Out. // Find the first comma. std::pair Comma = Spec.split(','); - + // If there is no comma, we fail. if (Comma.second.empty()) return "mach-o section specifier requires a segment and section " "separated by a comma"; - + // Capture segment, remove leading and trailing whitespace. Segment = Comma.first; StripSpaces(Segment); @@ -182,14 +193,14 @@ std::string MCSectionMachO::ParseSectionSpecifier(StringRef Spec, // In. if (Segment.empty() || Segment.size() > 16) return "mach-o section specifier requires a segment whose length is " "between 1 and 16 characters"; - + // Split the section name off from any attributes if present. Comma = Comma.second.split(','); // Capture section, remove leading and trailing whitespace. Section = Comma.first; StripSpaces(Section); - + // Verify that the section is present and not too long. if (Section.empty() || Section.size() > 16) return "mach-o section specifier requires a section whose length is " @@ -200,25 +211,25 @@ std::string MCSectionMachO::ParseSectionSpecifier(StringRef Spec, // In. StubSize = 0; if (Comma.second.empty()) return ""; - + // Otherwise, we need to parse the section type and attributes. Comma = Comma.second.split(','); - + // Get the section type. StringRef SectionType = Comma.first; StripSpaces(SectionType); - + // Figure out which section type it is. unsigned TypeID; for (TypeID = 0; TypeID !=MCSectionMachO::LAST_KNOWN_SECTION_TYPE+1; ++TypeID) if (SectionTypeDescriptors[TypeID].AssemblerName && SectionType == SectionTypeDescriptors[TypeID].AssemblerName) break; - + // If we didn't find the section type, reject it. if (TypeID > MCSectionMachO::LAST_KNOWN_SECTION_TYPE) return "mach-o section specifier uses an unknown section type"; - + // Remember the TypeID. TAA = TypeID; @@ -235,10 +246,10 @@ std::string MCSectionMachO::ParseSectionSpecifier(StringRef Spec, // In. // present. Comma = Comma.second.split(','); StringRef Attrs = Comma.first; - + // The attribute list is a '+' separated list of attributes. std::pair Plus = Attrs.split('+'); - + while (1) { StringRef Attr = Plus.first; StripSpaces(Attr); @@ -247,14 +258,14 @@ std::string MCSectionMachO::ParseSectionSpecifier(StringRef Spec, // In. for (unsigned i = 0; ; ++i) { if (SectionAttrDescriptors[i].AttrFlag == AttrFlagEnd) return "mach-o section specifier has invalid attribute"; - + if (SectionAttrDescriptors[i].AssemblerName && Attr == SectionAttrDescriptors[i].AssemblerName) { TAA |= SectionAttrDescriptors[i].AttrFlag; break; } } - + if (Plus.second.empty()) break; Plus = Plus.second.split('+'); }; @@ -272,15 +283,14 @@ std::string MCSectionMachO::ParseSectionSpecifier(StringRef Spec, // In. if ((TAA & MCSectionMachO::SECTION_TYPE) != MCSectionMachO::S_SYMBOL_STUBS) return "mach-o section specifier cannot have a stub size specified because " "it does not have type 'symbol_stubs'"; - + // Okay, if we do, it must be a number. StringRef StubSizeStr = Comma.second; StripSpaces(StubSizeStr); - + // Convert the stub size from a string to an integer. if (StubSizeStr.getAsInteger(0, StubSize)) return "mach-o section specifier has a malformed stub size"; - + return ""; } - diff --git a/lib/MC/MCStreamer.cpp b/lib/MC/MCStreamer.cpp index 3e9d02ea5ae7..3dcdba13135f 100644 --- a/lib/MC/MCStreamer.cpp +++ b/lib/MC/MCStreamer.cpp @@ -7,16 +7,21 @@ // //===----------------------------------------------------------------------===// +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" #include using namespace llvm; -MCStreamer::MCStreamer(MCContext &Ctx) : Context(Ctx), CurSection(0), - PrevSection(0) { +MCStreamer::MCStreamer(MCContext &Ctx) : Context(Ctx) { + PrevSectionStack.push_back(NULL); + CurSectionStack.push_back(NULL); } MCStreamer::~MCStreamer() { @@ -27,17 +32,90 @@ raw_ostream &MCStreamer::GetCommentOS() { return nulls(); } +void MCStreamer::EmitDwarfSetLineAddr(int64_t LineDelta, + const MCSymbol *Label, int PointerSize) { + // emit the sequence to set the address + EmitIntValue(dwarf::DW_LNS_extended_op, 1); + EmitULEB128IntValue(PointerSize + 1); + EmitIntValue(dwarf::DW_LNE_set_address, 1); + EmitSymbolValue(Label, PointerSize); + + // emit the sequence for the LineDelta (from 1) and a zero address delta. + MCDwarfLineAddr::Emit(this, LineDelta, 0); +} /// EmitIntValue - Special case of EmitValue that avoids the client having to /// pass in a MCExpr for constant integers. void MCStreamer::EmitIntValue(uint64_t Value, unsigned Size, unsigned AddrSpace) { - EmitValue(MCConstantExpr::Create(Value, getContext()), Size, AddrSpace); + assert(Size <= 8 && "Invalid size"); + assert((isUIntN(8 * Size, Value) || isIntN(8 * Size, Value)) && + "Invalid size"); + char buf[8]; + // FIXME: Endianness assumption. + for (unsigned i = 0; i != Size; ++i) + buf[i] = uint8_t(Value >> (i * 8)); + EmitBytes(StringRef(buf, Size), AddrSpace); +} + +/// EmitULEB128Value - Special case of EmitULEB128Value that avoids the +/// client having to pass in a MCExpr for constant integers. +void MCStreamer::EmitULEB128IntValue(uint64_t Value, unsigned AddrSpace) { + SmallString<32> Tmp; + raw_svector_ostream OSE(Tmp); + MCObjectWriter::EncodeULEB128(Value, OSE); + EmitBytes(OSE.str(), AddrSpace); +} + +/// EmitSLEB128Value - Special case of EmitSLEB128Value that avoids the +/// client having to pass in a MCExpr for constant integers. +void MCStreamer::EmitSLEB128IntValue(int64_t Value, unsigned AddrSpace) { + SmallString<32> Tmp; + raw_svector_ostream OSE(Tmp); + MCObjectWriter::EncodeSLEB128(Value, OSE); + EmitBytes(OSE.str(), AddrSpace); +} + +void MCStreamer::EmitAbsValue(const MCExpr *Value, unsigned Size, + unsigned AddrSpace) { + if (getContext().getAsmInfo().hasAggressiveSymbolFolding()) { + EmitValue(Value, Size, AddrSpace); + return; + } + MCSymbol *ABS = getContext().CreateTempSymbol(); + EmitAssignment(ABS, Value); + EmitSymbolValue(ABS, Size, AddrSpace); +} + + +void MCStreamer::EmitValue(const MCExpr *Value, unsigned Size, + unsigned AddrSpace) { + EmitValueImpl(Value, Size, false, AddrSpace); +} + +void MCStreamer::EmitPCRelValue(const MCExpr *Value, unsigned Size, + unsigned AddrSpace) { + EmitValueImpl(Value, Size, true, AddrSpace); +} + +void MCStreamer::EmitSymbolValue(const MCSymbol *Sym, unsigned Size, + bool isPCRel, unsigned AddrSpace) { + EmitValueImpl(MCSymbolRefExpr::Create(Sym, getContext()), Size, isPCRel, + AddrSpace); } void MCStreamer::EmitSymbolValue(const MCSymbol *Sym, unsigned Size, unsigned AddrSpace) { - EmitValue(MCSymbolRefExpr::Create(Sym, getContext()), Size, AddrSpace); + EmitSymbolValue(Sym, Size, false, AddrSpace); +} + +void MCStreamer::EmitPCRelSymbolValue(const MCSymbol *Sym, unsigned Size, + unsigned AddrSpace) { + EmitSymbolValue(Sym, Size, true, AddrSpace); +} + +void MCStreamer::EmitGPRel32Value(const MCExpr *Value) { + report_fatal_error("unsupported directive in streamer"); } /// EmitFill - Emit NumBytes bytes worth of the value specified by @@ -49,6 +127,138 @@ void MCStreamer::EmitFill(uint64_t NumBytes, uint8_t FillValue, EmitValue(E, 1, AddrSpace); } +bool MCStreamer::EmitDwarfFileDirective(unsigned FileNo, + StringRef Filename) { + return getContext().GetDwarfFile(Filename, FileNo) == 0; +} + +void MCStreamer::EmitDwarfLocDirective(unsigned FileNo, unsigned Line, + unsigned Column, unsigned Flags, + unsigned Isa, + unsigned Discriminator) { + getContext().setCurrentDwarfLoc(FileNo, Line, Column, Flags, Isa, + Discriminator); +} + +MCDwarfFrameInfo *MCStreamer::getCurrentFrameInfo() { + if (FrameInfos.empty()) + return NULL; + return &FrameInfos.back(); +} + +void MCStreamer::EnsureValidFrame() { + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + if (!CurFrame || CurFrame->End) + report_fatal_error("No open frame"); +} + +bool MCStreamer::EmitCFIStartProc() { + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + if (CurFrame && !CurFrame->End) { + report_fatal_error("Starting a frame before finishing the previous one!"); + return true; + } + MCDwarfFrameInfo Frame; + Frame.Begin = getContext().CreateTempSymbol(); + EmitLabel(Frame.Begin); + FrameInfos.push_back(Frame); + return false; +} + +bool MCStreamer::EmitCFIEndProc() { + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->End = getContext().CreateTempSymbol(); + EmitLabel(CurFrame->End); + return false; +} + +bool MCStreamer::EmitCFIDefCfa(int64_t Register, int64_t Offset) { + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + MCSymbol *Label = getContext().CreateTempSymbol(); + EmitLabel(Label); + MachineLocation Dest(MachineLocation::VirtualFP); + MachineLocation Source(Register, -Offset); + MCCFIInstruction Instruction(Label, Dest, Source); + CurFrame->Instructions.push_back(Instruction); + return false; +} + +bool MCStreamer::EmitCFIDefCfaOffset(int64_t Offset) { + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + MCSymbol *Label = getContext().CreateTempSymbol(); + EmitLabel(Label); + MachineLocation Dest(MachineLocation::VirtualFP); + MachineLocation Source(MachineLocation::VirtualFP, -Offset); + MCCFIInstruction Instruction(Label, Dest, Source); + CurFrame->Instructions.push_back(Instruction); + return false; +} + +bool MCStreamer::EmitCFIDefCfaRegister(int64_t Register) { + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + MCSymbol *Label = getContext().CreateTempSymbol(); + EmitLabel(Label); + MachineLocation Dest(Register); + MachineLocation Source(MachineLocation::VirtualFP); + MCCFIInstruction Instruction(Label, Dest, Source); + CurFrame->Instructions.push_back(Instruction); + return false; +} + +bool MCStreamer::EmitCFIOffset(int64_t Register, int64_t Offset) { + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + MCSymbol *Label = getContext().CreateTempSymbol(); + EmitLabel(Label); + MachineLocation Dest(Register, Offset); + MachineLocation Source(Register, Offset); + MCCFIInstruction Instruction(Label, Dest, Source); + CurFrame->Instructions.push_back(Instruction); + return false; +} + +bool MCStreamer::EmitCFIPersonality(const MCSymbol *Sym, + unsigned Encoding) { + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->Personality = Sym; + CurFrame->PersonalityEncoding = Encoding; + return false; +} + +bool MCStreamer::EmitCFILsda(const MCSymbol *Sym, unsigned Encoding) { + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->Lsda = Sym; + CurFrame->LsdaEncoding = Encoding; + return false; +} + +bool MCStreamer::EmitCFIRememberState() { + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + MCSymbol *Label = getContext().CreateTempSymbol(); + EmitLabel(Label); + MCCFIInstruction Instruction(MCCFIInstruction::Remember, Label); + CurFrame->Instructions.push_back(Instruction); + return false; +} + +bool MCStreamer::EmitCFIRestoreState() { + // FIXME: Error if there is no matching cfi_remember_state. + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + MCSymbol *Label = getContext().CreateTempSymbol(); + EmitLabel(Label); + MCCFIInstruction Instruction(MCCFIInstruction::Restore, Label); + CurFrame->Instructions.push_back(Instruction); + return false; +} + /// EmitRawText - If this file is backed by an assembly streamer, this dumps /// the specified string in the output .s file. This capability is /// indicated by the hasRawTextSupport() predicate. diff --git a/lib/MC/MCSymbol.cpp b/lib/MC/MCSymbol.cpp index 07751f729844..1c71f267a4b5 100644 --- a/lib/MC/MCSymbol.cpp +++ b/lib/MC/MCSymbol.cpp @@ -39,7 +39,20 @@ static bool NameNeedsQuoting(StringRef Str) { return false; } +const MCSymbol &MCSymbol::AliasedSymbol() const { + const MCSymbol *S = this; + while (S->isVariable()) { + const MCExpr *Value = S->getVariableValue(); + if (Value->getKind() != MCExpr::SymbolRef) + return *S; + const MCSymbolRefExpr *Ref = static_cast(Value); + S = &Ref->getSymbol(); + } + return *S; +} + void MCSymbol::setVariableValue(const MCExpr *Value) { + assert(!IsUsed && "Cannot set a variable that has already been used."); assert(Value && "Invalid variable value!"); assert((isUndefined() || (isAbsolute() && isa(Value))) && "Invalid redefinition!"); diff --git a/lib/MC/MachObjectWriter.cpp b/lib/MC/MachObjectWriter.cpp index cffabfadb316..8af07c74fdfe 100644 --- a/lib/MC/MachObjectWriter.cpp +++ b/lib/MC/MachObjectWriter.cpp @@ -7,7 +7,8 @@ // //===----------------------------------------------------------------------===// -#include "llvm/MC/MachObjectWriter.h" +#include "llvm/MC/MCMachObjectWriter.h" +#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/Twine.h" #include "llvm/MC/MCAssembler.h" @@ -18,49 +19,37 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCMachOSymbolFlags.h" #include "llvm/MC/MCValue.h" +#include "llvm/Object/MachOFormat.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/MachO.h" #include "llvm/Target/TargetAsmBackend.h" // FIXME: Gross. +#include "../Target/ARM/ARMFixupKinds.h" #include "../Target/X86/X86FixupKinds.h" #include using namespace llvm; +using namespace llvm::object; +// FIXME: this has been copied from (or to) X86AsmBackend.cpp static unsigned getFixupKindLog2Size(unsigned Kind) { switch (Kind) { - default: llvm_unreachable("invalid fixup kind!"); - case X86::reloc_pcrel_1byte: + default: + llvm_unreachable("invalid fixup kind!"); + case FK_PCRel_1: case FK_Data_1: return 0; - case X86::reloc_pcrel_2byte: + case FK_PCRel_2: case FK_Data_2: return 1; - case X86::reloc_pcrel_4byte: + case FK_PCRel_4: + // FIXME: Remove these!!! case X86::reloc_riprel_4byte: case X86::reloc_riprel_4byte_movq_load: + case X86::reloc_signed_4byte: case FK_Data_4: return 2; case FK_Data_8: return 3; } } -static bool isFixupKindPCRel(unsigned Kind) { - switch (Kind) { - default: - return false; - case X86::reloc_pcrel_1byte: - case X86::reloc_pcrel_2byte: - case X86::reloc_pcrel_4byte: - case X86::reloc_riprel_4byte: - case X86::reloc_riprel_4byte_movq_load: - return true; - } -} - -static bool isFixupKindRIPRel(unsigned Kind) { - return Kind == X86::reloc_riprel_4byte || - Kind == X86::reloc_riprel_4byte_movq_load; -} - static bool doesSymbolRequireExternRelocation(MCSymbolData *SD) { // Undefined symbols are always extern. if (SD->Symbol->isUndefined()) @@ -77,94 +66,7 @@ static bool doesSymbolRequireExternRelocation(MCSymbolData *SD) { namespace { -class MachObjectWriterImpl { - // See . - enum { - Header_Magic32 = 0xFEEDFACE, - Header_Magic64 = 0xFEEDFACF - }; - - enum { - Header32Size = 28, - Header64Size = 32, - SegmentLoadCommand32Size = 56, - SegmentLoadCommand64Size = 72, - Section32Size = 68, - Section64Size = 80, - SymtabLoadCommandSize = 24, - DysymtabLoadCommandSize = 80, - Nlist32Size = 12, - Nlist64Size = 16, - RelocationInfoSize = 8 - }; - - enum HeaderFileType { - HFT_Object = 0x1 - }; - - enum HeaderFlags { - HF_SubsectionsViaSymbols = 0x2000 - }; - - enum LoadCommandType { - LCT_Segment = 0x1, - LCT_Symtab = 0x2, - LCT_Dysymtab = 0xb, - LCT_Segment64 = 0x19 - }; - - // See . - enum SymbolTypeType { - STT_Undefined = 0x00, - STT_Absolute = 0x02, - STT_Section = 0x0e - }; - - enum SymbolTypeFlags { - // If any of these bits are set, then the entry is a stab entry number (see - // . Otherwise the other masks apply. - STF_StabsEntryMask = 0xe0, - - STF_TypeMask = 0x0e, - STF_External = 0x01, - STF_PrivateExtern = 0x10 - }; - - /// IndirectSymbolFlags - Flags for encoding special values in the indirect - /// symbol entry. - enum IndirectSymbolFlags { - ISF_Local = 0x80000000, - ISF_Absolute = 0x40000000 - }; - - /// RelocationFlags - Special flags for addresses. - enum RelocationFlags { - RF_Scattered = 0x80000000 - }; - - enum RelocationInfoType { - RIT_Vanilla = 0, - RIT_Pair = 1, - RIT_Difference = 2, - RIT_PreboundLazyPointer = 3, - RIT_LocalDifference = 4, - RIT_TLV = 5 - }; - - /// X86_64 uses its own relocation types. - enum RelocationInfoTypeX86_64 { - RIT_X86_64_Unsigned = 0, - RIT_X86_64_Signed = 1, - RIT_X86_64_Branch = 2, - RIT_X86_64_GOTLoad = 3, - RIT_X86_64_GOT = 4, - RIT_X86_64_Subtractor = 5, - RIT_X86_64_Signed1 = 6, - RIT_X86_64_Signed2 = 7, - RIT_X86_64_Signed4 = 8, - RIT_X86_64_TLV = 9 - }; - +class MachObjectWriter : public MCObjectWriter { /// MachSymbolData - Helper struct for containing some precomputed information /// on symbols. struct MachSymbolData { @@ -179,16 +81,14 @@ class MachObjectWriterImpl { } }; + /// The target specific Mach-O writer instance. + llvm::OwningPtr TargetObjectWriter; + /// @name Relocation Data /// @{ - struct MachRelocationEntry { - uint32_t Word0; - uint32_t Word1; - }; - llvm::DenseMap > Relocations; + std::vector > Relocations; llvm::DenseMap IndirectSymBase; /// @} @@ -202,32 +102,70 @@ class MachObjectWriterImpl { /// @} - MachObjectWriter *Writer; +private: + /// @name Utility Methods + /// @{ - raw_ostream &OS; + bool isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind) { + const MCFixupKindInfo &FKI = Asm.getBackend().getFixupKindInfo( + (MCFixupKind) Kind); - unsigned Is64Bit : 1; + return FKI.Flags & MCFixupKindInfo::FKF_IsPCRel; + } + + /// @} + + SectionAddrMap SectionAddress; + uint64_t getSectionAddress(const MCSectionData* SD) const { + return SectionAddress.lookup(SD); + } + uint64_t getSymbolAddress(const MCSymbolData* SD, + const MCAsmLayout &Layout) const { + return getSectionAddress(SD->getFragment()->getParent()) + + Layout.getSymbolOffset(SD); + } + uint64_t getFragmentAddress(const MCFragment *Fragment, + const MCAsmLayout &Layout) const { + return getSectionAddress(Fragment->getParent()) + + Layout.getFragmentOffset(Fragment); + } + + uint64_t getPaddingSize(const MCSectionData *SD, + const MCAsmLayout &Layout) const { + uint64_t EndAddr = getSectionAddress(SD) + Layout.getSectionAddressSize(SD); + unsigned Next = SD->getLayoutOrder() + 1; + if (Next >= Layout.getSectionOrder().size()) + return 0; + + const MCSectionData &NextSD = *Layout.getSectionOrder()[Next]; + if (NextSD.getSection().isVirtualSection()) + return 0; + return OffsetToAlignment(EndAddr, NextSD.getAlignment()); + } public: - MachObjectWriterImpl(MachObjectWriter *_Writer, bool _Is64Bit) - : Writer(_Writer), OS(Writer->getStream()), Is64Bit(_Is64Bit) { + MachObjectWriter(MCMachObjectTargetWriter *MOTW, raw_ostream &_OS, + bool _IsLittleEndian) + : MCObjectWriter(_OS, _IsLittleEndian), TargetObjectWriter(MOTW) { } - void Write8(uint8_t Value) { Writer->Write8(Value); } - void Write16(uint16_t Value) { Writer->Write16(Value); } - void Write32(uint32_t Value) { Writer->Write32(Value); } - void Write64(uint64_t Value) { Writer->Write64(Value); } - void WriteZeros(unsigned N) { Writer->WriteZeros(N); } - void WriteBytes(StringRef Str, unsigned ZeroFillSize = 0) { - Writer->WriteBytes(Str, ZeroFillSize); + /// @name Target Writer Proxy Accessors + /// @{ + + bool is64Bit() const { return TargetObjectWriter->is64Bit(); } + bool isARM() const { + uint32_t CPUType = TargetObjectWriter->getCPUType() & ~mach::CTFM_ArchMask; + return CPUType == mach::CTM_ARM; } + /// @} + void WriteHeader(unsigned NumLoadCommands, unsigned LoadCommandsSize, bool SubsectionsViaSymbols) { uint32_t Flags = 0; if (SubsectionsViaSymbols) - Flags |= HF_SubsectionsViaSymbols; + Flags |= macho::HF_SubsectionsViaSymbols; // struct mach_header (28 bytes) or // struct mach_header_64 (32 bytes) @@ -235,21 +173,20 @@ public: uint64_t Start = OS.tell(); (void) Start; - Write32(Is64Bit ? Header_Magic64 : Header_Magic32); + Write32(is64Bit() ? macho::HM_Object64 : macho::HM_Object32); + + Write32(TargetObjectWriter->getCPUType()); + Write32(TargetObjectWriter->getCPUSubtype()); - // FIXME: Support cputype. - Write32(Is64Bit ? MachO::CPUTypeX86_64 : MachO::CPUTypeI386); - // FIXME: Support cpusubtype. - Write32(MachO::CPUSubType_I386_ALL); - Write32(HFT_Object); - Write32(NumLoadCommands); // Object files have a single load command, the - // segment. + Write32(macho::HFT_Object); + Write32(NumLoadCommands); Write32(LoadCommandsSize); Write32(Flags); - if (Is64Bit) + if (is64Bit()) Write32(0); // reserved - assert(OS.tell() - Start == Is64Bit ? Header64Size : Header32Size); + assert(OS.tell() - Start == + (is64Bit() ? macho::Header64Size : macho::Header32Size)); } /// WriteSegmentLoadCommand - Write a segment load command. @@ -266,14 +203,16 @@ public: uint64_t Start = OS.tell(); (void) Start; - unsigned SegmentLoadCommandSize = Is64Bit ? SegmentLoadCommand64Size : - SegmentLoadCommand32Size; - Write32(Is64Bit ? LCT_Segment64 : LCT_Segment); + unsigned SegmentLoadCommandSize = + is64Bit() ? macho::SegmentLoadCommand64Size: + macho::SegmentLoadCommand32Size; + Write32(is64Bit() ? macho::LCT_Segment64 : macho::LCT_Segment); Write32(SegmentLoadCommandSize + - NumSections * (Is64Bit ? Section64Size : Section32Size)); + NumSections * (is64Bit() ? macho::Section64Size : + macho::Section32Size)); WriteBytes("", 16); - if (Is64Bit) { + if (is64Bit()) { Write64(0); // vmaddr Write64(VMSize); // vmsize Write64(SectionDataStartOffset); // file offset @@ -295,10 +234,10 @@ public: void WriteSection(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCSectionData &SD, uint64_t FileOffset, uint64_t RelocationsStart, unsigned NumRelocations) { - uint64_t SectionSize = Layout.getSectionSize(&SD); + uint64_t SectionSize = Layout.getSectionAddressSize(&SD); // The offset is unused for virtual sections. - if (Asm.getBackend().isVirtualSection(SD.getSection())) { + if (SD.getSection().isVirtualSection()) { assert(Layout.getSectionFileSize(&SD) == 0 && "Invalid file size!"); FileOffset = 0; } @@ -312,11 +251,11 @@ public: const MCSectionMachO &Section = cast(SD.getSection()); WriteBytes(Section.getSectionName(), 16); WriteBytes(Section.getSegmentName(), 16); - if (Is64Bit) { - Write64(Layout.getSectionAddress(&SD)); // address + if (is64Bit()) { + Write64(getSectionAddress(&SD)); // address Write64(SectionSize); // size } else { - Write32(Layout.getSectionAddress(&SD)); // address + Write32(getSectionAddress(&SD)); // address Write32(SectionSize); // size } Write32(FileOffset); @@ -332,10 +271,11 @@ public: Write32(Flags); Write32(IndirectSymBase.lookup(&SD)); // reserved1 Write32(Section.getStubSize()); // reserved2 - if (Is64Bit) + if (is64Bit()) Write32(0); // reserved3 - assert(OS.tell() - Start == Is64Bit ? Section64Size : Section32Size); + assert(OS.tell() - Start == is64Bit() ? macho::Section64Size : + macho::Section32Size); } void WriteSymtabLoadCommand(uint32_t SymbolOffset, uint32_t NumSymbols, @@ -346,14 +286,14 @@ public: uint64_t Start = OS.tell(); (void) Start; - Write32(LCT_Symtab); - Write32(SymtabLoadCommandSize); + Write32(macho::LCT_Symtab); + Write32(macho::SymtabLoadCommandSize); Write32(SymbolOffset); Write32(NumSymbols); Write32(StringTableOffset); Write32(StringTableSize); - assert(OS.tell() - Start == SymtabLoadCommandSize); + assert(OS.tell() - Start == macho::SymtabLoadCommandSize); } void WriteDysymtabLoadCommand(uint32_t FirstLocalSymbol, @@ -369,8 +309,8 @@ public: uint64_t Start = OS.tell(); (void) Start; - Write32(LCT_Dysymtab); - Write32(DysymtabLoadCommandSize); + Write32(macho::LCT_Dysymtab); + Write32(macho::DysymtabLoadCommandSize); Write32(FirstLocalSymbol); Write32(NumLocalSymbols); Write32(FirstExternalSymbol); @@ -390,7 +330,7 @@ public: Write32(0); // locreloff Write32(0); // nlocrel - assert(OS.tell() - Start == DysymtabLoadCommandSize); + assert(OS.tell() - Start == macho::DysymtabLoadCommandSize); } void WriteNlist(MachSymbolData &MSD, const MCAsmLayout &Layout) { @@ -404,27 +344,27 @@ public: // // FIXME: Are the prebound or indirect fields possible here? if (Symbol.isUndefined()) - Type = STT_Undefined; + Type = macho::STT_Undefined; else if (Symbol.isAbsolute()) - Type = STT_Absolute; + Type = macho::STT_Absolute; else - Type = STT_Section; + Type = macho::STT_Section; // FIXME: Set STAB bits. if (Data.isPrivateExtern()) - Type |= STF_PrivateExtern; + Type |= macho::STF_PrivateExtern; // Set external bit. if (Data.isExternal() || Symbol.isUndefined()) - Type |= STF_External; + Type |= macho::STF_External; // Compute the symbol address. if (Symbol.isDefined()) { if (Symbol.isAbsolute()) { Address = cast(Symbol.getVariableValue())->getValue(); } else { - Address = Layout.getSymbolAddress(&Data); + Address = getSymbolAddress(&Data, Layout); } } else if (Data.isCommon()) { // Common symbols are encoded with the size in the address @@ -452,7 +392,7 @@ public: // The Mach-O streamer uses the lowest 16-bits of the flags for the 'desc' // value. Write16(Flags); - if (Is64Bit) + if (is64Bit()) Write64(Address); else Write32(Address); @@ -472,11 +412,15 @@ public: // - Input errors, where something cannot be correctly encoded. 'as' allows // these through in many cases. + static bool isFixupKindRIPRel(unsigned Kind) { + return Kind == X86::reloc_riprel_4byte || + Kind == X86::reloc_riprel_4byte_movq_load; + } void RecordX86_64Relocation(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { - unsigned IsPCRel = isFixupKindPCRel(Fixup.getKind()); + unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); unsigned IsRIPRel = isFixupKindRIPRel(Fixup.getKind()); unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); @@ -484,7 +428,7 @@ public: uint32_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); uint32_t FixupAddress = - Layout.getFragmentAddress(Fragment) + Fixup.getOffset(); + getFragmentAddress(Fragment, Layout) + Fixup.getOffset(); int64_t Value = 0; unsigned Index = 0; unsigned IsExtern = 0; @@ -503,7 +447,7 @@ public: if (Target.isAbsolute()) { // constant // SymbolNum of 0 indicates the absolute section. - Type = RIT_X86_64_Unsigned; + Type = macho::RIT_X86_64_Unsigned; Index = 0; // FIXME: I believe this is broken, I don't think the linker can @@ -513,16 +457,16 @@ public: // yet). if (IsPCRel) { IsExtern = 1; - Type = RIT_X86_64_Branch; + Type = macho::RIT_X86_64_Branch; } } else if (Target.getSymB()) { // A - B + constant const MCSymbol *A = &Target.getSymA()->getSymbol(); MCSymbolData &A_SD = Asm.getSymbolData(*A); - const MCSymbolData *A_Base = Asm.getAtom(Layout, &A_SD); + const MCSymbolData *A_Base = Asm.getAtom(&A_SD); const MCSymbol *B = &Target.getSymB()->getSymbol(); MCSymbolData &B_SD = Asm.getSymbolData(*B); - const MCSymbolData *B_Base = Asm.getAtom(Layout, &B_SD); + const MCSymbolData *B_Base = Asm.getAtom(&B_SD); // Neither symbol can be modified. if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None || @@ -534,25 +478,35 @@ public: if (IsPCRel) report_fatal_error("unsupported pc-relative relocation of difference"); - // We don't currently support any situation where one or both of the - // symbols would require a local relocation. This is almost certainly - // unused and may not be possible to encode correctly. - if (!A_Base || !B_Base) - report_fatal_error("unsupported local relocations in difference"); + // The support for the situation where one or both of the symbols would + // require a local relocation is handled just like if the symbols were + // external. This is certainly used in the case of debug sections where + // the section has only temporary symbols and thus the symbols don't have + // base symbols. This is encoded using the section ordinal and + // non-extern relocation entries. // Darwin 'as' doesn't emit correct relocations for this (it ends up with - // a single SIGNED relocation); reject it for now. - if (A_Base == B_Base) + // a single SIGNED relocation); reject it for now. Except the case where + // both symbols don't have a base, equal but both NULL. + if (A_Base == B_Base && A_Base) report_fatal_error("unsupported relocation with identical base"); - Value += Layout.getSymbolAddress(&A_SD) - Layout.getSymbolAddress(A_Base); - Value -= Layout.getSymbolAddress(&B_SD) - Layout.getSymbolAddress(B_Base); + Value += getSymbolAddress(&A_SD, Layout) - + (A_Base == NULL ? 0 : getSymbolAddress(A_Base, Layout)); + Value -= getSymbolAddress(&B_SD, Layout) - + (B_Base == NULL ? 0 : getSymbolAddress(B_Base, Layout)); - Index = A_Base->getIndex(); - IsExtern = 1; - Type = RIT_X86_64_Unsigned; + if (A_Base) { + Index = A_Base->getIndex(); + IsExtern = 1; + } + else { + Index = A_SD.getFragment()->getParent()->getOrdinal() + 1; + IsExtern = 0; + } + Type = macho::RIT_X86_64_Unsigned; - MachRelocationEntry MRE; + macho::RelocationEntry MRE; MRE.Word0 = FixupOffset; MRE.Word1 = ((Index << 0) | (IsPCRel << 24) | @@ -561,13 +515,19 @@ public: (Type << 28)); Relocations[Fragment->getParent()].push_back(MRE); - Index = B_Base->getIndex(); - IsExtern = 1; - Type = RIT_X86_64_Subtractor; + if (B_Base) { + Index = B_Base->getIndex(); + IsExtern = 1; + } + else { + Index = B_SD.getFragment()->getParent()->getOrdinal() + 1; + IsExtern = 0; + } + Type = macho::RIT_X86_64_Subtractor; } else { const MCSymbol *Symbol = &Target.getSymA()->getSymbol(); MCSymbolData &SD = Asm.getSymbolData(*Symbol); - const MCSymbolData *Base = Asm.getAtom(Layout, &SD); + const MCSymbolData *Base = Asm.getAtom(&SD); // Relocations inside debug sections always use local relocations when // possible. This seems to be done because the debugger doesn't fully @@ -589,15 +549,26 @@ public: // Add the local offset, if needed. if (Base != &SD) - Value += Layout.getSymbolAddress(&SD) - Layout.getSymbolAddress(Base); + Value += Layout.getSymbolOffset(&SD) - Layout.getSymbolOffset(Base); } else if (Symbol->isInSection()) { // The index is the section ordinal (1-based). Index = SD.getFragment()->getParent()->getOrdinal() + 1; IsExtern = 0; - Value += Layout.getSymbolAddress(&SD); + Value += getSymbolAddress(&SD, Layout); if (IsPCRel) Value -= FixupAddress + (1 << Log2Size); + } else if (Symbol->isVariable()) { + const MCExpr *Value = Symbol->getVariableValue(); + int64_t Res; + bool isAbs = Value->EvaluateAsAbsolute(Res, Layout, SectionAddress); + if (isAbs) { + FixedValue = Res; + return; + } else { + report_fatal_error("unsupported relocation of variable '" + + Symbol->getName() + "'"); + } } else { report_fatal_error("unsupported relocation of undefined symbol '" + Symbol->getName() + "'"); @@ -611,15 +582,15 @@ public: // rewrite the movq to an leaq at link time if the symbol ends up in // the same linkage unit. if (unsigned(Fixup.getKind()) == X86::reloc_riprel_4byte_movq_load) - Type = RIT_X86_64_GOTLoad; + Type = macho::RIT_X86_64_GOTLoad; else - Type = RIT_X86_64_GOT; + Type = macho::RIT_X86_64_GOT; } else if (Modifier == MCSymbolRefExpr::VK_TLVP) { - Type = RIT_X86_64_TLV; + Type = macho::RIT_X86_64_TLV; } else if (Modifier != MCSymbolRefExpr::VK_None) { report_fatal_error("unsupported symbol modifier in relocation"); } else { - Type = RIT_X86_64_Signed; + Type = macho::RIT_X86_64_Signed; // The Darwin x86_64 relocation format has a problem where it cannot // encode an address (L + ) which is outside the atom @@ -636,9 +607,9 @@ public: // (the additional bias), but instead appear to just look at the // final offset. switch (-(Target.getConstant() + (1LL << Log2Size))) { - case 1: Type = RIT_X86_64_Signed1; break; - case 2: Type = RIT_X86_64_Signed2; break; - case 4: Type = RIT_X86_64_Signed4; break; + case 1: Type = macho::RIT_X86_64_Signed1; break; + case 2: Type = macho::RIT_X86_64_Signed2; break; + case 4: Type = macho::RIT_X86_64_Signed4; break; } } } else { @@ -646,24 +617,24 @@ public: report_fatal_error("unsupported symbol modifier in branch " "relocation"); - Type = RIT_X86_64_Branch; + Type = macho::RIT_X86_64_Branch; } } else { if (Modifier == MCSymbolRefExpr::VK_GOT) { - Type = RIT_X86_64_GOT; + Type = macho::RIT_X86_64_GOT; } else if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) { // GOTPCREL is allowed as a modifier on non-PCrel instructions, in // which case all we do is set the PCrel bit in the relocation entry; // this is used with exception handling, for example. The source is // required to include any necessary offset directly. - Type = RIT_X86_64_GOT; + Type = macho::RIT_X86_64_GOT; IsPCRel = 1; } else if (Modifier == MCSymbolRefExpr::VK_TLVP) { report_fatal_error("TLVP symbol modifier should have been rip-rel"); } else if (Modifier != MCSymbolRefExpr::VK_None) report_fatal_error("unsupported symbol modifier in relocation"); else - Type = RIT_X86_64_Unsigned; + Type = macho::RIT_X86_64_Unsigned; } } @@ -671,7 +642,7 @@ public: FixedValue = Value; // struct relocation_info (8 bytes) - MachRelocationEntry MRE; + macho::RelocationEntry MRE; MRE.Word0 = FixupOffset; MRE.Word1 = ((Index << 0) | (IsPCRel << 24) | @@ -685,11 +656,11 @@ public: const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, + unsigned Log2Size, uint64_t &FixedValue) { uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); - unsigned IsPCRel = isFixupKindPCRel(Fixup.getKind()); - unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); - unsigned Type = RIT_Vanilla; + unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); + unsigned Type = macho::RIT_Vanilla; // See . const MCSymbol *A = &Target.getSymA()->getSymbol(); @@ -699,7 +670,9 @@ public: report_fatal_error("symbol '" + A->getName() + "' can not be undefined in a subtraction expression"); - uint32_t Value = Layout.getSymbolAddress(A_SD); + uint32_t Value = getSymbolAddress(A_SD, Layout); + uint64_t SecAddr = getSectionAddress(A_SD->getFragment()->getParent()); + FixedValue += SecAddr; uint32_t Value2 = 0; if (const MCSymbolRefExpr *B = Target.getSymB()) { @@ -714,28 +687,184 @@ public: // Note that there is no longer any semantic difference between these two // relocation types from the linkers point of view, this is done solely // for pedantic compatibility with 'as'. - Type = A_SD->isExternal() ? RIT_Difference : RIT_LocalDifference; - Value2 = Layout.getSymbolAddress(B_SD); + Type = A_SD->isExternal() ? (unsigned)macho::RIT_Difference : + (unsigned)macho::RIT_Generic_LocalDifference; + Value2 = getSymbolAddress(B_SD, Layout); + FixedValue -= getSectionAddress(B_SD->getFragment()->getParent()); + } + + // Relocations are written out in reverse order, so the PAIR comes first. + if (Type == macho::RIT_Difference || + Type == macho::RIT_Generic_LocalDifference) { + macho::RelocationEntry MRE; + MRE.Word0 = ((0 << 0) | + (macho::RIT_Pair << 24) | + (Log2Size << 28) | + (IsPCRel << 30) | + macho::RF_Scattered); + MRE.Word1 = Value2; + Relocations[Fragment->getParent()].push_back(MRE); + } + + macho::RelocationEntry MRE; + MRE.Word0 = ((FixupOffset << 0) | + (Type << 24) | + (Log2Size << 28) | + (IsPCRel << 30) | + macho::RF_Scattered); + MRE.Word1 = Value; + Relocations[Fragment->getParent()].push_back(MRE); + } + + void RecordARMScatteredRelocation(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, MCValue Target, + unsigned Log2Size, + uint64_t &FixedValue) { + uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); + unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); + unsigned Type = macho::RIT_Vanilla; + + // See . + const MCSymbol *A = &Target.getSymA()->getSymbol(); + MCSymbolData *A_SD = &Asm.getSymbolData(*A); + + if (!A_SD->getFragment()) + report_fatal_error("symbol '" + A->getName() + + "' can not be undefined in a subtraction expression"); + + uint32_t Value = getSymbolAddress(A_SD, Layout); + uint64_t SecAddr = getSectionAddress(A_SD->getFragment()->getParent()); + FixedValue += SecAddr; + uint32_t Value2 = 0; + + if (const MCSymbolRefExpr *B = Target.getSymB()) { + MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol()); + + if (!B_SD->getFragment()) + report_fatal_error("symbol '" + B->getSymbol().getName() + + "' can not be undefined in a subtraction expression"); + + // Select the appropriate difference relocation type. + Type = macho::RIT_Difference; + Value2 = getSymbolAddress(B_SD, Layout); + FixedValue -= getSectionAddress(B_SD->getFragment()->getParent()); } // Relocations are written out in reverse order, so the PAIR comes first. - if (Type == RIT_Difference || Type == RIT_LocalDifference) { - MachRelocationEntry MRE; + if (Type == macho::RIT_Difference || + Type == macho::RIT_Generic_LocalDifference) { + macho::RelocationEntry MRE; MRE.Word0 = ((0 << 0) | - (RIT_Pair << 24) | + (macho::RIT_Pair << 24) | (Log2Size << 28) | (IsPCRel << 30) | - RF_Scattered); + macho::RF_Scattered); MRE.Word1 = Value2; Relocations[Fragment->getParent()].push_back(MRE); } - MachRelocationEntry MRE; + macho::RelocationEntry MRE; MRE.Word0 = ((FixupOffset << 0) | (Type << 24) | (Log2Size << 28) | (IsPCRel << 30) | - RF_Scattered); + macho::RF_Scattered); + MRE.Word1 = Value; + Relocations[Fragment->getParent()].push_back(MRE); + } + + void RecordARMMovwMovtRelocation(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, MCValue Target, + uint64_t &FixedValue) { + uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); + unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); + unsigned Type = macho::RIT_ARM_Half; + + // See . + const MCSymbol *A = &Target.getSymA()->getSymbol(); + MCSymbolData *A_SD = &Asm.getSymbolData(*A); + + if (!A_SD->getFragment()) + report_fatal_error("symbol '" + A->getName() + + "' can not be undefined in a subtraction expression"); + + uint32_t Value = getSymbolAddress(A_SD, Layout); + uint32_t Value2 = 0; + uint64_t SecAddr = getSectionAddress(A_SD->getFragment()->getParent()); + FixedValue += SecAddr; + + if (const MCSymbolRefExpr *B = Target.getSymB()) { + MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol()); + + if (!B_SD->getFragment()) + report_fatal_error("symbol '" + B->getSymbol().getName() + + "' can not be undefined in a subtraction expression"); + + // Select the appropriate difference relocation type. + Type = macho::RIT_ARM_HalfDifference; + Value2 = getSymbolAddress(B_SD, Layout); + FixedValue -= getSectionAddress(B_SD->getFragment()->getParent()); + } + + // Relocations are written out in reverse order, so the PAIR comes first. + // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field: + // + // For these two r_type relocations they always have a pair following them + // and the r_length bits are used differently. The encoding of the + // r_length is as follows: + // low bit of r_length: + // 0 - :lower16: for movw instructions + // 1 - :upper16: for movt instructions + // high bit of r_length: + // 0 - arm instructions + // 1 - thumb instructions + // the other half of the relocated expression is in the following pair + // relocation entry in the the low 16 bits of r_address field. + unsigned ThumbBit = 0; + unsigned MovtBit = 0; + switch (Fixup.getKind()) { + default: break; + case ARM::fixup_arm_movt_hi16: + case ARM::fixup_arm_movt_hi16_pcrel: + MovtBit = 1; + break; + case ARM::fixup_t2_movt_hi16: + case ARM::fixup_t2_movt_hi16_pcrel: + MovtBit = 1; + // Fallthrough + case ARM::fixup_t2_movw_lo16: + case ARM::fixup_t2_movw_lo16_pcrel: + ThumbBit = 1; + break; + } + + + if (Type == macho::RIT_ARM_HalfDifference) { + uint32_t OtherHalf = MovtBit + ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16); + + macho::RelocationEntry MRE; + MRE.Word0 = ((OtherHalf << 0) | + (macho::RIT_Pair << 24) | + (MovtBit << 28) | + (ThumbBit << 29) | + (IsPCRel << 30) | + macho::RF_Scattered); + MRE.Word1 = Value2; + Relocations[Fragment->getParent()].push_back(MRE); + } + + macho::RelocationEntry MRE; + MRE.Word0 = ((FixupOffset << 0) | + (Type << 24) | + (MovtBit << 28) | + (ThumbBit << 29) | + (IsPCRel << 30) | + macho::RF_Scattered); MRE.Word1 = Value; Relocations[Fragment->getParent()].push_back(MRE); } @@ -746,7 +875,7 @@ public: const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { assert(Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP && - !Is64Bit && + !is64Bit() && "Should only be called with a 32-bit TLVP relocation!"); unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); @@ -764,50 +893,218 @@ public: if (Target.getSymB()) { // If this is a subtraction then we're pcrel. uint32_t FixupAddress = - Layout.getFragmentAddress(Fragment) + Fixup.getOffset(); + getFragmentAddress(Fragment, Layout) + Fixup.getOffset(); MCSymbolData *SD_B = &Asm.getSymbolData(Target.getSymB()->getSymbol()); IsPCRel = 1; - FixedValue = (FixupAddress - Layout.getSymbolAddress(SD_B) + + FixedValue = (FixupAddress - getSymbolAddress(SD_B, Layout) + Target.getConstant()); FixedValue += 1ULL << Log2Size; } else { FixedValue = 0; } - + // struct relocation_info (8 bytes) - MachRelocationEntry MRE; + macho::RelocationEntry MRE; MRE.Word0 = Value; + MRE.Word1 = ((Index << 0) | + (IsPCRel << 24) | + (Log2Size << 25) | + (1 << 27) | // Extern + (macho::RIT_Generic_TLV << 28)); // Type + Relocations[Fragment->getParent()].push_back(MRE); + } + + static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType, + unsigned &Log2Size) { + RelocType = unsigned(macho::RIT_Vanilla); + Log2Size = ~0U; + + switch (Kind) { + default: + return false; + + case FK_Data_1: + Log2Size = llvm::Log2_32(1); + return true; + case FK_Data_2: + Log2Size = llvm::Log2_32(2); + return true; + case FK_Data_4: + Log2Size = llvm::Log2_32(4); + return true; + case FK_Data_8: + Log2Size = llvm::Log2_32(8); + return true; + + // Handle 24-bit branch kinds. + case ARM::fixup_arm_ldst_pcrel_12: + case ARM::fixup_arm_pcrel_10: + case ARM::fixup_arm_adr_pcrel_12: + case ARM::fixup_arm_condbranch: + case ARM::fixup_arm_uncondbranch: + RelocType = unsigned(macho::RIT_ARM_Branch24Bit); + // Report as 'long', even though that is not quite accurate. + Log2Size = llvm::Log2_32(4); + return true; + + // Handle Thumb branches. + case ARM::fixup_arm_thumb_br: + RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit); + Log2Size = llvm::Log2_32(2); + return true; + + case ARM::fixup_arm_thumb_bl: + RelocType = unsigned(macho::RIT_ARM_ThumbBranch32Bit); + Log2Size = llvm::Log2_32(4); + return true; + + case ARM::fixup_arm_thumb_blx: + RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit); + // Report as 'long', even though that is not quite accurate. + Log2Size = llvm::Log2_32(4); + return true; + + case ARM::fixup_arm_movt_hi16: + case ARM::fixup_arm_movt_hi16_pcrel: + case ARM::fixup_t2_movt_hi16: + case ARM::fixup_t2_movt_hi16_pcrel: + RelocType = unsigned(macho::RIT_ARM_HalfDifference); + // Report as 'long', even though that is not quite accurate. + Log2Size = llvm::Log2_32(4); + return true; + + case ARM::fixup_arm_movw_lo16: + case ARM::fixup_arm_movw_lo16_pcrel: + case ARM::fixup_t2_movw_lo16: + case ARM::fixup_t2_movw_lo16_pcrel: + RelocType = unsigned(macho::RIT_ARM_Half); + // Report as 'long', even though that is not quite accurate. + Log2Size = llvm::Log2_32(4); + return true; + } + } + void RecordARMRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, + const MCFragment *Fragment, const MCFixup &Fixup, + MCValue Target, uint64_t &FixedValue) { + unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); + unsigned Log2Size; + unsigned RelocType = macho::RIT_Vanilla; + if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size)) { + report_fatal_error("unknown ARM fixup kind!"); + return; + } + + // If this is a difference or a defined symbol plus an offset, then we need + // a scattered relocation entry. Differences always require scattered + // relocations. + if (Target.getSymB()) { + if (RelocType == macho::RIT_ARM_Half || + RelocType == macho::RIT_ARM_HalfDifference) + return RecordARMMovwMovtRelocation(Asm, Layout, Fragment, Fixup, + Target, FixedValue); + return RecordARMScatteredRelocation(Asm, Layout, Fragment, Fixup, + Target, Log2Size, FixedValue); + } + + // Get the symbol data, if any. + MCSymbolData *SD = 0; + if (Target.getSymA()) + SD = &Asm.getSymbolData(Target.getSymA()->getSymbol()); + + // FIXME: For other platforms, we need to use scattered relocations for + // internal relocations with offsets. If this is an internal relocation + // with an offset, it also needs a scattered relocation entry. + // + // Is this right for ARM? + uint32_t Offset = Target.getConstant(); + if (IsPCRel && RelocType == macho::RIT_Vanilla) + Offset += 1 << Log2Size; + if (Offset && SD && !doesSymbolRequireExternRelocation(SD)) + return RecordARMScatteredRelocation(Asm, Layout, Fragment, Fixup, Target, + Log2Size, FixedValue); + + // See . + uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); + unsigned Index = 0; + unsigned IsExtern = 0; + unsigned Type = 0; + + if (Target.isAbsolute()) { // constant + // FIXME! + report_fatal_error("FIXME: relocations to absolute targets " + "not yet implemented"); + } else if (SD->getSymbol().isVariable()) { + int64_t Res; + if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute( + Res, Layout, SectionAddress)) { + FixedValue = Res; + return; + } + + report_fatal_error("unsupported relocation of variable '" + + SD->getSymbol().getName() + "'"); + } else { + // Check whether we need an external or internal relocation. + if (doesSymbolRequireExternRelocation(SD)) { + IsExtern = 1; + Index = SD->getIndex(); + // For external relocations, make sure to offset the fixup value to + // compensate for the addend of the symbol address, if it was + // undefined. This occurs with weak definitions, for example. + if (!SD->Symbol->isUndefined()) + FixedValue -= Layout.getSymbolOffset(SD); + } else { + // The index is the section ordinal (1-based). + Index = SD->getFragment()->getParent()->getOrdinal() + 1; + FixedValue += getSectionAddress(SD->getFragment()->getParent()); + } + if (IsPCRel) + FixedValue -= getSectionAddress(Fragment->getParent()); + + // The type is determined by the fixup kind. + Type = RelocType; + } + + // struct relocation_info (8 bytes) + macho::RelocationEntry MRE; + MRE.Word0 = FixupOffset; MRE.Word1 = ((Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | - (1 << 27) | // Extern - (RIT_TLV << 28)); // Type + (IsExtern << 27) | + (Type << 28)); Relocations[Fragment->getParent()].push_back(MRE); } - + void RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { - if (Is64Bit) { + // FIXME: These needs to be factored into the target Mach-O writer. + if (isARM()) { + RecordARMRelocation(Asm, Layout, Fragment, Fixup, Target, FixedValue); + return; + } + if (is64Bit()) { RecordX86_64Relocation(Asm, Layout, Fragment, Fixup, Target, FixedValue); return; } - unsigned IsPCRel = isFixupKindPCRel(Fixup.getKind()); + unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); // If this is a 32-bit TLVP reloc it's handled a bit differently. - if (Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP) { + if (Target.getSymA() && + Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP) { RecordTLVPRelocation(Asm, Layout, Fragment, Fixup, Target, FixedValue); return; } - + // If this is a difference or a defined symbol plus an offset, then we need // a scattered relocation entry. // Differences always require scattered relocations. if (Target.getSymB()) return RecordScatteredRelocation(Asm, Layout, Fragment, Fixup, - Target, FixedValue); + Target, Log2Size, FixedValue); // Get the symbol data, if any. MCSymbolData *SD = 0; @@ -821,7 +1118,7 @@ public: Offset += 1 << Log2Size; if (Offset && SD && !doesSymbolRequireExternRelocation(SD)) return RecordScatteredRelocation(Asm, Layout, Fragment, Fixup, - Target, FixedValue); + Target, Log2Size, FixedValue); // See . uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); @@ -834,7 +1131,17 @@ public: // // FIXME: Currently, these are never generated (see code below). I cannot // find a case where they are actually emitted. - Type = RIT_Vanilla; + Type = macho::RIT_Vanilla; + } else if (SD->getSymbol().isVariable()) { + int64_t Res; + if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute( + Res, Layout, SectionAddress)) { + FixedValue = Res; + return; + } + + report_fatal_error("unsupported relocation of variable '" + + SD->getSymbol().getName() + "'"); } else { // Check whether we need an external or internal relocation. if (doesSymbolRequireExternRelocation(SD)) { @@ -844,17 +1151,20 @@ public: // compensate for the addend of the symbol address, if it was // undefined. This occurs with weak definitions, for example. if (!SD->Symbol->isUndefined()) - FixedValue -= Layout.getSymbolAddress(SD); + FixedValue -= Layout.getSymbolOffset(SD); } else { // The index is the section ordinal (1-based). Index = SD->getFragment()->getParent()->getOrdinal() + 1; + FixedValue += getSectionAddress(SD->getFragment()->getParent()); } + if (IsPCRel) + FixedValue -= getSectionAddress(Fragment->getParent()); - Type = RIT_Vanilla; + Type = macho::RIT_Vanilla; } // struct relocation_info (8 bytes) - MachRelocationEntry MRE; + macho::RelocationEntry MRE; MRE.Word0 = FixupOffset; MRE.Word1 = ((Index << 0) | (IsPCRel << 24) | @@ -885,7 +1195,7 @@ public: // Initialize the section indirect symbol base, if necessary. if (!IndirectSymBase.count(it->SectionData)) IndirectSymBase[it->SectionData] = IndirectIndex; - + Asm.getOrCreateSymbolData(*it->Symbol); } @@ -1028,7 +1338,25 @@ public: StringTable += '\x00'; } - void ExecutePostLayoutBinding(MCAssembler &Asm) { + void computeSectionAddresses(const MCAssembler &Asm, + const MCAsmLayout &Layout) { + uint64_t StartAddress = 0; + const SmallVectorImpl &Order = Layout.getSectionOrder(); + for (int i = 0, n = Order.size(); i != n ; ++i) { + const MCSectionData *SD = Order[i]; + StartAddress = RoundUpToAlignment(StartAddress, SD->getAlignment()); + SectionAddress[SD] = StartAddress; + StartAddress += Layout.getSectionAddressSize(SD); + // Explicitly pad the section to match the alignment requirements of the + // following one. This is for 'gas' compatibility, it shouldn't + /// strictly be necessary. + StartAddress += getPaddingSize(SD, Layout); + } + } + + void ExecutePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) { + computeSectionAddresses(Asm, Layout); + // Create symbol data for any indirect symbols. BindIndirectSymbols(Asm); @@ -1037,41 +1365,101 @@ public: UndefinedSymbolData); } - void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout) { + virtual bool IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, + const MCSymbolData &DataA, + const MCFragment &FB, + bool InSet, + bool IsPCRel) const { + if (InSet) + return true; + + // The effective address is + // addr(atom(A)) + offset(A) + // - addr(atom(B)) - offset(B) + // and the offsets are not relocatable, so the fixup is fully resolved when + // addr(atom(A)) - addr(atom(B)) == 0. + const MCSymbolData *A_Base = 0, *B_Base = 0; + + const MCSymbol &SA = DataA.getSymbol().AliasedSymbol(); + const MCSection &SecA = SA.getSection(); + const MCSection &SecB = FB.getParent()->getSection(); + + if (IsPCRel) { + // The simple (Darwin, except on x86_64) way of dealing with this was to + // assume that any reference to a temporary symbol *must* be a temporary + // symbol in the same atom, unless the sections differ. Therefore, any + // PCrel relocation to a temporary symbol (in the same section) is fully + // resolved. This also works in conjunction with absolutized .set, which + // requires the compiler to use .set to absolutize the differences between + // symbols which the compiler knows to be assembly time constants, so we + // don't need to worry about considering symbol differences fully + // resolved. + + if (!Asm.getBackend().hasReliableSymbolDifference()) { + if (!SA.isTemporary() || !SA.isInSection() || &SecA != &SecB) + return false; + return true; + } + } else { + if (!TargetObjectWriter->useAggressiveSymbolFolding()) + return false; + } + + const MCFragment &FA = *Asm.getSymbolData(SA).getFragment(); + + A_Base = FA.getAtom(); + if (!A_Base) + return false; + + B_Base = FB.getAtom(); + if (!B_Base) + return false; + + // If the atoms are the same, they are guaranteed to have the same address. + if (A_Base == B_Base) + return true; + + // Otherwise, we can't prove this is fully resolved. + return false; + } + + void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout) { unsigned NumSections = Asm.size(); // The section data starts after the header, the segment load command (and // section headers) and the symbol table. unsigned NumLoadCommands = 1; - uint64_t LoadCommandsSize = Is64Bit ? - SegmentLoadCommand64Size + NumSections * Section64Size : - SegmentLoadCommand32Size + NumSections * Section32Size; + uint64_t LoadCommandsSize = is64Bit() ? + macho::SegmentLoadCommand64Size + NumSections * macho::Section64Size : + macho::SegmentLoadCommand32Size + NumSections * macho::Section32Size; // Add the symbol table load command sizes, if used. unsigned NumSymbols = LocalSymbolData.size() + ExternalSymbolData.size() + UndefinedSymbolData.size(); if (NumSymbols) { NumLoadCommands += 2; - LoadCommandsSize += SymtabLoadCommandSize + DysymtabLoadCommandSize; + LoadCommandsSize += (macho::SymtabLoadCommandSize + + macho::DysymtabLoadCommandSize); } // Compute the total size of the section data, as well as its file size and // vm size. - uint64_t SectionDataStart = (Is64Bit ? Header64Size : Header32Size) - + LoadCommandsSize; + uint64_t SectionDataStart = (is64Bit() ? macho::Header64Size : + macho::Header32Size) + LoadCommandsSize; uint64_t SectionDataSize = 0; uint64_t SectionDataFileSize = 0; uint64_t VMSize = 0; for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { const MCSectionData &SD = *it; - uint64_t Address = Layout.getSectionAddress(&SD); - uint64_t Size = Layout.getSectionSize(&SD); + uint64_t Address = getSectionAddress(&SD); + uint64_t Size = Layout.getSectionAddressSize(&SD); uint64_t FileSize = Layout.getSectionFileSize(&SD); + FileSize += getPaddingSize(&SD, Layout); VMSize = std::max(VMSize, Address + Size); - if (Asm.getBackend().isVirtualSection(SD.getSection())) + if (SD.getSection().isVirtualSection()) continue; SectionDataSize = std::max(SectionDataSize, Address + Size); @@ -1094,11 +1482,11 @@ public: uint64_t RelocTableEnd = SectionDataStart + SectionDataFileSize; for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { - std::vector &Relocs = Relocations[it]; + std::vector &Relocs = Relocations[it]; unsigned NumRelocs = Relocs.size(); - uint64_t SectionStart = SectionDataStart + Layout.getSectionAddress(it); + uint64_t SectionStart = SectionDataStart + getSectionAddress(it); WriteSection(Asm, Layout, *it, SectionStart, RelocTableEnd, NumRelocs); - RelocTableEnd += NumRelocs * RelocationInfoSize; + RelocTableEnd += NumRelocs * macho::RelocationInfoSize; } // Write the symbol table load command, if used. @@ -1124,8 +1512,8 @@ public: // The string table is written after symbol table. uint64_t StringTableOffset = - SymbolTableOffset + NumSymTabSymbols * (Is64Bit ? Nlist64Size : - Nlist32Size); + SymbolTableOffset + NumSymTabSymbols * (is64Bit() ? macho::Nlist64Size : + macho::Nlist32Size); WriteSymtabLoadCommand(SymbolTableOffset, NumSymTabSymbols, StringTableOffset, StringTable.size()); @@ -1137,8 +1525,13 @@ public: // Write the actual section data. for (MCAssembler::const_iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it) - Asm.WriteSectionData(it, Layout, Writer); + ie = Asm.end(); it != ie; ++it) { + Asm.WriteSectionData(it, Layout); + + uint64_t Pad = getPaddingSize(it, Layout); + for (unsigned int i = 0; i < Pad; ++i) + Write8(0); + } // Write the extra padding. WriteZeros(SectionDataPadding); @@ -1148,7 +1541,7 @@ public: ie = Asm.end(); it != ie; ++it) { // Write the section relocation entries, in reverse order to match 'as' // (approximately, the exact algorithm is more complicated than this). - std::vector &Relocs = Relocations[it]; + std::vector &Relocs = Relocations[it]; for (unsigned i = 0, e = Relocs.size(); i != e; ++i) { Write32(Relocs[e - i - 1].Word0); Write32(Relocs[e - i - 1].Word1); @@ -1169,9 +1562,9 @@ public: // If this symbol is defined and internal, mark it as such. if (it->Symbol->isDefined() && !Asm.getSymbolData(*it->Symbol).isExternal()) { - uint32_t Flags = ISF_Local; + uint32_t Flags = macho::ISF_Local; if (it->Symbol->isAbsolute()) - Flags |= ISF_Absolute; + Flags |= macho::ISF_Absolute; Write32(Flags); continue; } @@ -1198,32 +1591,8 @@ public: } -MachObjectWriter::MachObjectWriter(raw_ostream &OS, - bool Is64Bit, - bool IsLittleEndian) - : MCObjectWriter(OS, IsLittleEndian) -{ - Impl = new MachObjectWriterImpl(this, Is64Bit); -} - -MachObjectWriter::~MachObjectWriter() { - delete (MachObjectWriterImpl*) Impl; -} - -void MachObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm) { - ((MachObjectWriterImpl*) Impl)->ExecutePostLayoutBinding(Asm); -} - -void MachObjectWriter::RecordRelocation(const MCAssembler &Asm, - const MCAsmLayout &Layout, - const MCFragment *Fragment, - const MCFixup &Fixup, MCValue Target, - uint64_t &FixedValue) { - ((MachObjectWriterImpl*) Impl)->RecordRelocation(Asm, Layout, Fragment, Fixup, - Target, FixedValue); -} - -void MachObjectWriter::WriteObject(const MCAssembler &Asm, - const MCAsmLayout &Layout) { - ((MachObjectWriterImpl*) Impl)->WriteObject(Asm, Layout); +MCObjectWriter *llvm::createMachObjectWriter(MCMachObjectTargetWriter *MOTW, + raw_ostream &OS, + bool IsLittleEndian) { + return new MachObjectWriter(MOTW, OS, IsLittleEndian); } diff --git a/lib/MC/TargetAsmBackend.cpp b/lib/MC/TargetAsmBackend.cpp index bbfddbe9e71f..192755742535 100644 --- a/lib/MC/TargetAsmBackend.cpp +++ b/lib/MC/TargetAsmBackend.cpp @@ -10,13 +10,28 @@ #include "llvm/Target/TargetAsmBackend.h" using namespace llvm; -TargetAsmBackend::TargetAsmBackend(const Target &T) - : TheTarget(T), - HasAbsolutizedSet(false), - HasReliableSymbolDifference(false), - HasScatteredSymbols(false) +TargetAsmBackend::TargetAsmBackend() + : HasReliableSymbolDifference(false) { } TargetAsmBackend::~TargetAsmBackend() { } + +const MCFixupKindInfo & +TargetAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { + static const MCFixupKindInfo Builtins[] = { + { "FK_Data_1", 0, 8, 0 }, + { "FK_Data_2", 0, 16, 0 }, + { "FK_Data_4", 0, 32, 0 }, + { "FK_Data_8", 0, 64, 0 }, + { "FK_PCRel_1", 0, 8, MCFixupKindInfo::FKF_IsPCRel }, + { "FK_PCRel_2", 0, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "FK_PCRel_4", 0, 32, MCFixupKindInfo::FKF_IsPCRel }, + { "FK_PCRel_8", 0, 64, MCFixupKindInfo::FKF_IsPCRel } + }; + + assert((size_t)Kind <= sizeof(Builtins) / sizeof(Builtins[0]) && + "Unknown fixup kind"); + return Builtins[Kind]; +} diff --git a/lib/MC/WinCOFFObjectWriter.cpp b/lib/MC/WinCOFFObjectWriter.cpp index eeb2b9675f4b..6ca5d37fc32e 100644 --- a/lib/MC/WinCOFFObjectWriter.cpp +++ b/lib/MC/WinCOFFObjectWriter.cpp @@ -31,7 +31,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/System/TimeValue.h" +#include "llvm/Support/TimeValue.h" #include "../Target/X86/X86FixupKinds.h" @@ -55,6 +55,9 @@ struct AuxSymbol { COFF::Auxiliary Aux; }; +class COFFSymbol; +class COFFSection; + class COFFSymbol { public: COFF::symbol Data; @@ -62,15 +65,19 @@ public: typedef llvm::SmallVector AuxiliarySymbols; name Name; - size_t Index; + int Index; AuxiliarySymbols Aux; COFFSymbol *Other; + COFFSection *Section; + int Relocations; MCSymbolData const *MCData; - COFFSymbol(llvm::StringRef name, size_t index); + COFFSymbol(llvm::StringRef name); size_t size() const; void set_name_offset(uint32_t Offset); + + bool should_keep() const; }; // This class contains staging data for a COFF relocation entry. @@ -89,12 +96,12 @@ public: COFF::section Header; std::string Name; - size_t Number; + int Number; MCSectionData const *MCData; - COFFSymbol *Symb; + COFFSymbol *Symbol; relocations Relocations; - COFFSection(llvm::StringRef name, size_t Index); + COFFSection(llvm::StringRef name); static size_t size(); }; @@ -118,11 +125,8 @@ public: typedef std::vector symbols; typedef std::vector sections; - typedef StringMap name_symbol_map; - typedef StringMap name_section_map; - - typedef DenseMap symbol_map; - typedef DenseMap section_map; + typedef DenseMap symbol_map; + typedef DenseMap section_map; // Root level file contents. bool Is64Bit; @@ -138,11 +142,9 @@ public: WinCOFFObjectWriter(raw_ostream &OS, bool is64Bit); ~WinCOFFObjectWriter(); - COFFSymbol *createSymbol(llvm::StringRef Name); - COFFSection *createSection(llvm::StringRef Name); - - void InitCOFFEntity(COFFSymbol &Symbol); - void InitCOFFEntity(COFFSection &Section); + COFFSymbol *createSymbol(StringRef Name); + COFFSymbol *GetOrCreateCOFFSymbol(const MCSymbol * Symbol); + COFFSection *createSection(StringRef Name); template object_t *createCOFFEntity(llvm::StringRef Name, list_t &List); @@ -150,9 +152,14 @@ public: void DefineSection(MCSectionData const &SectionData); void DefineSymbol(MCSymbolData const &SymbolData, MCAssembler &Assembler); - bool ExportSection(COFFSection *S); + void MakeSymbolReal(COFFSymbol &S, size_t Index); + void MakeSectionReal(COFFSection &S, size_t Number); + + bool ExportSection(COFFSection const *S); bool ExportSymbol(MCSymbolData const &SymbolData, MCAssembler &Asm); + bool IsPhysicalSection(COFFSection *S); + // Entity writing methods. void WriteFileHeader(const COFF::header &Header); @@ -163,7 +170,7 @@ public: // MCObjectWriter interface implementation. - void ExecutePostLayoutBinding(MCAssembler &Asm); + void ExecutePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout); void RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, @@ -172,7 +179,7 @@ public: MCValue Target, uint64_t &FixedValue); - void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout); + void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout); }; } @@ -198,9 +205,12 @@ static inline void write_uint8_le(void *Data, uint8_t const &Value) { //------------------------------------------------------------------------------ // Symbol class implementation -COFFSymbol::COFFSymbol(llvm::StringRef name, size_t index) - : Name(name.begin(), name.end()), Index(-1) - , Other(NULL), MCData(NULL) { +COFFSymbol::COFFSymbol(llvm::StringRef name) + : Name(name.begin(), name.end()) + , Other(NULL) + , Section(NULL) + , Relocations(0) + , MCData(NULL) { memset(&Data, 0, sizeof(Data)); } @@ -216,12 +226,41 @@ void COFFSymbol::set_name_offset(uint32_t Offset) { write_uint32_le(Data.Name + 4, Offset); } +/// logic to decide if the symbol should be reported in the symbol table +bool COFFSymbol::should_keep() const { + // no section means its external, keep it + if (Section == NULL) + return true; + + // if it has relocations pointing at it, keep it + if (Relocations > 0) { + assert(Section->Number != -1 && "Sections with relocations must be real!"); + return true; + } + + // if the section its in is being droped, drop it + if (Section->Number == -1) + return false; + + // if it is the section symbol, keep it + if (Section->Symbol == this) + return true; + + // if its temporary, drop it + if (MCData && MCData->getSymbol().isTemporary()) + return false; + + // otherwise, keep it + return true; +} + //------------------------------------------------------------------------------ // Section class implementation -COFFSection::COFFSection(llvm::StringRef name, size_t Index) - : Name(name), Number(Index + 1) - , MCData(NULL), Symb(NULL) { +COFFSection::COFFSection(llvm::StringRef name) + : Name(name) + , MCData(NULL) + , Symbol(NULL) { memset(&Header, 0, sizeof(Header)); } @@ -290,43 +329,22 @@ WinCOFFObjectWriter::~WinCOFFObjectWriter() { delete *I; } -COFFSymbol *WinCOFFObjectWriter::createSymbol(llvm::StringRef Name) { +COFFSymbol *WinCOFFObjectWriter::createSymbol(StringRef Name) { return createCOFFEntity(Name, Symbols); } -COFFSection *WinCOFFObjectWriter::createSection(llvm::StringRef Name) { - return createCOFFEntity(Name, Sections); -} - -/// This function initializes a symbol by entering its name into the string -/// table if it is too long to fit in the symbol table header. -void WinCOFFObjectWriter::InitCOFFEntity(COFFSymbol &S) { - if (S.Name.size() > COFF::NameSize) { - size_t StringTableEntry = Strings.insert(S.Name.c_str()); - - S.set_name_offset(StringTableEntry); - } else - memcpy(S.Data.Name, S.Name.c_str(), S.Name.size()); +COFFSymbol *WinCOFFObjectWriter::GetOrCreateCOFFSymbol(const MCSymbol * Symbol){ + symbol_map::iterator i = SymbolMap.find(Symbol); + if (i != SymbolMap.end()) + return i->second; + COFFSymbol *RetSymbol + = createCOFFEntity(Symbol->getName(), Symbols); + SymbolMap[Symbol] = RetSymbol; + return RetSymbol; } -/// This function initializes a section by entering its name into the string -/// table if it is too long to fit in the section table header. -void WinCOFFObjectWriter::InitCOFFEntity(COFFSection &S) { - if (S.Name.size() > COFF::NameSize) { - size_t StringTableEntry = Strings.insert(S.Name.c_str()); - - // FIXME: Why is this number 999999? This number is never mentioned in the - // spec. I'm assuming this is due to the printed value needing to fit into - // the S.Header.Name field. In which case why not 9999999 (7 9's instead of - // 6)? The spec does not state if this entry should be null terminated in - // this case, and thus this seems to be the best way to do it. I think I - // just solved my own FIXME... - if (StringTableEntry > 999999) - report_fatal_error("COFF string table is greater than 999999 bytes."); - - sprintf(S.Header.Name, "/%d", (unsigned)StringTableEntry); - } else - memcpy(S.Header.Name, S.Name.c_str(), S.Name.size()); +COFFSection *WinCOFFObjectWriter::createSection(llvm::StringRef Name) { + return createCOFFEntity(Name, Sections); } /// A template used to lookup or create a symbol/section, and initialize it if @@ -334,9 +352,7 @@ void WinCOFFObjectWriter::InitCOFFEntity(COFFSection &S) { template object_t *WinCOFFObjectWriter::createCOFFEntity(llvm::StringRef Name, list_t &List) { - object_t *Object = new object_t(Name, List.size()); - - InitCOFFEntity(*Object); + object_t *Object = new object_t(Name); List.push_back(Object); @@ -346,6 +362,8 @@ object_t *WinCOFFObjectWriter::createCOFFEntity(llvm::StringRef Name, /// This function takes a section data object from the assembler /// and creates the associated COFF section staging object. void WinCOFFObjectWriter::DefineSection(MCSectionData const &SectionData) { + assert(SectionData.getSection().getVariant() == MCSection::SV_COFF + && "Got non COFF section in the COFF backend!"); // FIXME: Not sure how to verify this (at least in a debug build). MCSectionCOFF const &Sec = static_cast(SectionData.getSection()); @@ -353,15 +371,14 @@ void WinCOFFObjectWriter::DefineSection(MCSectionData const &SectionData) { COFFSection *coff_section = createSection(Sec.getSectionName()); COFFSymbol *coff_symbol = createSymbol(Sec.getSectionName()); - coff_section->Symb = coff_symbol; + coff_section->Symbol = coff_symbol; + coff_symbol->Section = coff_section; coff_symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; - coff_symbol->Data.SectionNumber = coff_section->Number; // In this case the auxiliary symbol is a Section Definition. coff_symbol->Aux.resize(1); memset(&coff_symbol->Aux[0], 0, sizeof(coff_symbol->Aux[0])); coff_symbol->Aux[0].AuxType = ATSectionDefinition; - coff_symbol->Aux[0].Aux.SectionDefinition.Number = coff_section->Number; coff_symbol->Aux[0].Aux.SectionDefinition.Selection = Sec.getSelection(); coff_section->Header.Characteristics = Sec.getCharacteristics(); @@ -388,18 +405,53 @@ void WinCOFFObjectWriter::DefineSection(MCSectionData const &SectionData) { // Bind internal COFF section to MC section. coff_section->MCData = &SectionData; - SectionMap[&SectionData] = coff_section; + SectionMap[&SectionData.getSection()] = coff_section; } /// This function takes a section data object from the assembler /// and creates the associated COFF symbol staging object. void WinCOFFObjectWriter::DefineSymbol(MCSymbolData const &SymbolData, - MCAssembler &Assembler) { - COFFSymbol *coff_symbol = createSymbol(SymbolData.getSymbol().getName()); + MCAssembler &Assembler) { + COFFSymbol *coff_symbol = GetOrCreateCOFFSymbol(&SymbolData.getSymbol()); coff_symbol->Data.Type = (SymbolData.getFlags() & 0x0000FFFF) >> 0; coff_symbol->Data.StorageClass = (SymbolData.getFlags() & 0x00FF0000) >> 16; + if (SymbolData.getFlags() & COFF::SF_WeakExternal) { + coff_symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL; + + if (SymbolData.getSymbol().isVariable()) { + coff_symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL; + const MCExpr *Value = SymbolData.getSymbol().getVariableValue(); + + // FIXME: This assert message isn't very good. + assert(Value->getKind() == MCExpr::SymbolRef && + "Value must be a SymbolRef!"); + + const MCSymbolRefExpr *SymbolRef = + static_cast(Value); + coff_symbol->Other = GetOrCreateCOFFSymbol(&SymbolRef->getSymbol()); + } else { + std::string WeakName = std::string(".weak.") + + SymbolData.getSymbol().getName().str() + + ".default"; + COFFSymbol *WeakDefault = createSymbol(WeakName); + WeakDefault->Data.SectionNumber = COFF::IMAGE_SYM_ABSOLUTE; + WeakDefault->Data.StorageClass = COFF::IMAGE_SYM_CLASS_EXTERNAL; + WeakDefault->Data.Type = 0; + WeakDefault->Data.Value = 0; + coff_symbol->Other = WeakDefault; + } + + // Setup the Weak External auxiliary symbol. + coff_symbol->Aux.resize(1); + memset(&coff_symbol->Aux[0], 0, sizeof(coff_symbol->Aux[0])); + coff_symbol->Aux[0].AuxType = ATWeakExternal; + coff_symbol->Aux[0].Aux.WeakExternal.TagIndex = 0; + coff_symbol->Aux[0].Aux.WeakExternal.Characteristics = + COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY; + } + // If no storage class was specified in the streamer, define it here. if (coff_symbol->Data.StorageClass == 0) { bool external = SymbolData.isExternal() || (SymbolData.Fragment == NULL); @@ -408,44 +460,51 @@ void WinCOFFObjectWriter::DefineSymbol(MCSymbolData const &SymbolData, external ? COFF::IMAGE_SYM_CLASS_EXTERNAL : COFF::IMAGE_SYM_CLASS_STATIC; } - if (SymbolData.getFlags() & COFF::SF_WeakReference) { - coff_symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL; - - const MCExpr *Value = SymbolData.getSymbol().getVariableValue(); + if (SymbolData.Fragment != NULL) + coff_symbol->Section = + SectionMap[&SymbolData.Fragment->getParent()->getSection()]; - // FIXME: This assert message isn't very good. - assert(Value->getKind() == MCExpr::SymbolRef && - "Value must be a SymbolRef!"); + // Bind internal COFF symbol to MC symbol. + coff_symbol->MCData = &SymbolData; + SymbolMap[&SymbolData.getSymbol()] = coff_symbol; +} - const MCSymbolRefExpr *SymbolRef = - static_cast(Value); +/// making a section real involves assigned it a number and putting +/// name into the string table if needed +void WinCOFFObjectWriter::MakeSectionReal(COFFSection &S, size_t Number) { + if (S.Name.size() > COFF::NameSize) { + size_t StringTableEntry = Strings.insert(S.Name.c_str()); - const MCSymbolData &OtherSymbolData = - Assembler.getSymbolData(SymbolRef->getSymbol()); + // FIXME: Why is this number 999999? This number is never mentioned in the + // spec. I'm assuming this is due to the printed value needing to fit into + // the S.Header.Name field. In which case why not 9999999 (7 9's instead of + // 6)? The spec does not state if this entry should be null terminated in + // this case, and thus this seems to be the best way to do it. I think I + // just solved my own FIXME... + if (StringTableEntry > 999999) + report_fatal_error("COFF string table is greater than 999999 bytes."); - // FIXME: This assert message isn't very good. - assert(SymbolMap.find(&OtherSymbolData) != SymbolMap.end() && - "OtherSymbolData must be in the symbol map!"); + std::sprintf(S.Header.Name, "/%d", unsigned(StringTableEntry)); + } else + std::memcpy(S.Header.Name, S.Name.c_str(), S.Name.size()); - coff_symbol->Other = SymbolMap[&OtherSymbolData]; + S.Number = Number; + S.Symbol->Data.SectionNumber = S.Number; + S.Symbol->Aux[0].Aux.SectionDefinition.Number = S.Number; +} - // Setup the Weak External auxiliary symbol. - coff_symbol->Aux.resize(1); - memset(&coff_symbol->Aux[0], 0, sizeof(coff_symbol->Aux[0])); - coff_symbol->Aux[0].AuxType = ATWeakExternal; - coff_symbol->Aux[0].Aux.WeakExternal.TagIndex = 0; - coff_symbol->Aux[0].Aux.WeakExternal.Characteristics = - COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY; - } +void WinCOFFObjectWriter::MakeSymbolReal(COFFSymbol &S, size_t Index) { + if (S.Name.size() > COFF::NameSize) { + size_t StringTableEntry = Strings.insert(S.Name.c_str()); - // Bind internal COFF symbol to MC symbol. - coff_symbol->MCData = &SymbolData; - SymbolMap[&SymbolData] = coff_symbol; + S.set_name_offset(StringTableEntry); + } else + std::memcpy(S.Data.Name, S.Name.c_str(), S.Name.size()); + S.Index = Index; } -bool WinCOFFObjectWriter::ExportSection(COFFSection *S) { - return (S->Header.Characteristics - & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0; +bool WinCOFFObjectWriter::ExportSection(COFFSection const *S) { + return !S->MCData->getFragmentList().empty(); } bool WinCOFFObjectWriter::ExportSymbol(MCSymbolData const &SymbolData, @@ -455,8 +514,14 @@ bool WinCOFFObjectWriter::ExportSymbol(MCSymbolData const &SymbolData, // return Asm.isSymbolLinkerVisible (&SymbolData); - // For now, all symbols are exported, the linker will sort it out for us. - return true; + // For now, all non-variable symbols are exported, + // the linker will sort the rest out for us. + return SymbolData.isExternal() || !SymbolData.getSymbol().isVariable(); +} + +bool WinCOFFObjectWriter::IsPhysicalSection(COFFSection *S) { + return (S->Header.Characteristics + & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0; } //------------------------------------------------------------------------------ @@ -546,9 +611,10 @@ void WinCOFFObjectWriter::WriteRelocation(const COFF::relocation &R) { //////////////////////////////////////////////////////////////////////////////// // MCObjectWriter interface implementations -void WinCOFFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm) { +void WinCOFFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout) { // "Define" each section & symbol. This creates section & symbol - // entries in the staging area and gives them their final indexes. + // entries in the staging area. for (MCAssembler::const_iterator i = Asm.begin(), e = Asm.end(); i != e; i++) DefineSection(*i); @@ -574,19 +640,24 @@ void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, MCSectionData const *SectionData = Fragment->getParent(); // Mark this symbol as requiring an entry in the symbol table. - assert(SectionMap.find(SectionData) != SectionMap.end() && + assert(SectionMap.find(&SectionData->getSection()) != SectionMap.end() && "Section must already have been defined in ExecutePostLayoutBinding!"); - assert(SymbolMap.find(&A_SD) != SymbolMap.end() && + assert(SymbolMap.find(&A_SD.getSymbol()) != SymbolMap.end() && "Symbol must already have been defined in ExecutePostLayoutBinding!"); - COFFSection *coff_section = SectionMap[SectionData]; - COFFSymbol *coff_symbol = SymbolMap[&A_SD]; + COFFSection *coff_section = SectionMap[&SectionData->getSection()]; + COFFSymbol *coff_symbol = SymbolMap[&A_SD.getSymbol()]; if (Target.getSymB()) { + if (&Target.getSymA()->getSymbol().getSection() + != &Target.getSymB()->getSymbol().getSection()) { + llvm_unreachable("Symbol relative relocations are only allowed between " + "symbols in the same section"); + } const MCSymbol *B = &Target.getSymB()->getSymbol(); MCSymbolData &B_SD = Asm.getSymbolData(*B); - FixedValue = Layout.getSymbolAddress(&A_SD) - Layout.getSymbolAddress(&B_SD); + FixedValue = Layout.getSymbolOffset(&A_SD) - Layout.getSymbolOffset(&B_SD); // In the case where we have SymbA and SymB, we just need to store the delta // between the two symbols. Update FixedValue to account for the delta, and @@ -600,12 +671,21 @@ void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, Reloc.Data.SymbolTableIndex = 0; Reloc.Data.VirtualAddress = Layout.getFragmentOffset(Fragment); - Reloc.Symb = coff_symbol; + + // Turn relocations for temporary symbols into section relocations. + if (coff_symbol->MCData->getSymbol().isTemporary()) { + Reloc.Symb = coff_symbol->Section->Symbol; + FixedValue += Layout.getFragmentOffset(coff_symbol->MCData->Fragment) + + coff_symbol->MCData->getOffset(); + } else + Reloc.Symb = coff_symbol; + + ++Reloc.Symb->Relocations; Reloc.Data.VirtualAddress += Fixup.getOffset(); - switch (Fixup.getKind()) { - case X86::reloc_pcrel_4byte: + switch ((unsigned)Fixup.getKind()) { + case FK_PCRel_4: case X86::reloc_riprel_4byte: case X86::reloc_riprel_4byte_movq_load: Reloc.Data.Type = Is64Bit ? COFF::IMAGE_REL_AMD64_REL32 @@ -615,6 +695,7 @@ void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, FixedValue += 4; break; case FK_Data_4: + case X86::reloc_signed_4byte: Reloc.Data.Type = Is64Bit ? COFF::IMAGE_REL_AMD64_ADDR32 : COFF::IMAGE_REL_I386_DIR32; break; @@ -631,9 +712,19 @@ void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, coff_section->Relocations.push_back(Reloc); } -void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm, +void WinCOFFObjectWriter::WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout) { // Assign symbol and section indexes and offsets. + Header.NumberOfSections = 0; + + for (sections::iterator i = Sections.begin(), + e = Sections.end(); i != e; i++) { + if (Layout.getSectionAddressSize((*i)->MCData) > 0) { + MakeSectionReal(**i, ++Header.NumberOfSections); + } else { + (*i)->Number = -1; + } + } Header.NumberOfSymbols = 0; @@ -641,32 +732,35 @@ void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm, COFFSymbol *coff_symbol = *i; MCSymbolData const *SymbolData = coff_symbol->MCData; - coff_symbol->Index = Header.NumberOfSymbols++; - // Update section number & offset for symbols that have them. if ((SymbolData != NULL) && (SymbolData->Fragment != NULL)) { - COFFSection *coff_section = SectionMap[SymbolData->Fragment->getParent()]; + assert(coff_symbol->Section != NULL); - coff_symbol->Data.SectionNumber = coff_section->Number; + coff_symbol->Data.SectionNumber = coff_symbol->Section->Number; coff_symbol->Data.Value = Layout.getFragmentOffset(SymbolData->Fragment) + SymbolData->Offset; } - // Update auxiliary symbol info. - coff_symbol->Data.NumberOfAuxSymbols = coff_symbol->Aux.size(); - Header.NumberOfSymbols += coff_symbol->Data.NumberOfAuxSymbols; + if (coff_symbol->should_keep()) { + MakeSymbolReal(*coff_symbol, Header.NumberOfSymbols++); + + // Update auxiliary symbol info. + coff_symbol->Data.NumberOfAuxSymbols = coff_symbol->Aux.size(); + Header.NumberOfSymbols += coff_symbol->Data.NumberOfAuxSymbols; + } else + coff_symbol->Index = -1; } // Fixup weak external references. for (symbols::iterator i = Symbols.begin(), e = Symbols.end(); i != e; i++) { - COFFSymbol *symb = *i; - - if (symb->Other != NULL) { - assert(symb->Aux.size() == 1 && + COFFSymbol *coff_symbol = *i; + if (coff_symbol->Other != NULL) { + assert(coff_symbol->Index != -1); + assert(coff_symbol->Aux.size() == 1 && "Symbol must contain one aux symbol!"); - assert(symb->Aux[0].AuxType == ATWeakExternal && + assert(coff_symbol->Aux[0].AuxType == ATWeakExternal && "Symbol's aux symbol must be a Weak External!"); - symb->Aux[0].Aux.WeakExternal.TagIndex = symb->Other->Index; + coff_symbol->Aux[0].Aux.WeakExternal.TagIndex = coff_symbol->Other->Index; } } @@ -675,18 +769,19 @@ void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm, unsigned offset = 0; offset += COFF::HeaderSize; - offset += COFF::SectionSize * Asm.size(); - - Header.NumberOfSections = Sections.size(); + offset += COFF::SectionSize * Header.NumberOfSections; for (MCAssembler::const_iterator i = Asm.begin(), e = Asm.end(); i != e; i++) { - COFFSection *Sec = SectionMap[i]; + COFFSection *Sec = SectionMap[&i->getSection()]; - Sec->Header.SizeOfRawData = Layout.getSectionFileSize(i); + if (Sec->Number == -1) + continue; - if (ExportSection(Sec)) { + Sec->Header.SizeOfRawData = Layout.getSectionAddressSize(i); + + if (IsPhysicalSection(Sec)) { Sec->Header.PointerToRawData = offset; offset += Sec->Header.SizeOfRawData; @@ -700,13 +795,15 @@ void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm, for (relocations::iterator cr = Sec->Relocations.begin(), er = Sec->Relocations.end(); - cr != er; cr++) { + cr != er; ++cr) { + assert((*cr).Symb->Index != -1); (*cr).Data.SymbolTableIndex = (*cr).Symb->Index; } } - assert(Sec->Symb->Aux.size() == 1 && "Section's symbol must have one aux!"); - AuxSymbol &Aux = Sec->Symb->Aux[0]; + assert(Sec->Symbol->Aux.size() == 1 + && "Section's symbol must have one aux!"); + AuxSymbol &Aux = Sec->Symbol->Aux[0]; assert(Aux.AuxType == ATSectionDefinition && "Section's symbol's aux symbol must be a Section Definition!"); Aux.Aux.SectionDefinition.Length = Sec->Header.SizeOfRawData; @@ -728,16 +825,21 @@ void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm, MCAssembler::const_iterator j, je; for (i = Sections.begin(), ie = Sections.end(); i != ie; i++) - WriteSectionHeader((*i)->Header); + if ((*i)->Number != -1) + WriteSectionHeader((*i)->Header); for (i = Sections.begin(), ie = Sections.end(), j = Asm.begin(), je = Asm.end(); - (i != ie) && (j != je); i++, j++) { + (i != ie) && (j != je); ++i, ++j) { + + if ((*i)->Number == -1) + continue; + if ((*i)->Header.PointerToRawData != 0) { assert(OS.tell() == (*i)->Header.PointerToRawData && "Section::PointerToRawData is insane!"); - Asm.WriteSectionData(j, Layout, this); + Asm.WriteSectionData(j, Layout); } if ((*i)->Relocations.size() > 0) { @@ -759,7 +861,8 @@ void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm, "Header::PointerToSymbolTable is insane!"); for (symbols::iterator i = Symbols.begin(), e = Symbols.end(); i != e; i++) - WriteSymbol(*i); + if ((*i)->Index != -1) + WriteSymbol(*i); OS.write((char const *)&Strings.Data.front(), Strings.Data.size()); } diff --git a/lib/MC/WinCOFFStreamer.cpp b/lib/MC/WinCOFFStreamer.cpp index 8a194bff2151..46968e601be7 100644 --- a/lib/MC/WinCOFFStreamer.cpp +++ b/lib/MC/WinCOFFStreamer.cpp @@ -48,8 +48,10 @@ public: // MCStreamer interface + virtual void InitSections(); virtual void EmitLabel(MCSymbol *Symbol); virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); + virtual void EmitThumbFunc(MCSymbol *Func); virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue); @@ -66,18 +68,55 @@ public: virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment); virtual void EmitBytes(StringRef Data, unsigned AddrSpace); - virtual void EmitValue(const MCExpr *Value, unsigned Size, - unsigned AddrSpace); - virtual void EmitGPRel32Value(const MCExpr *Value); virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, unsigned ValueSize, unsigned MaxBytesToEmit); virtual void EmitCodeAlignment(unsigned ByteAlignment, unsigned MaxBytesToEmit); - virtual void EmitValueToOffset(const MCExpr *Offset, unsigned char Value); virtual void EmitFileDirective(StringRef Filename); - virtual void EmitDwarfFileDirective(unsigned FileNo,StringRef Filename); virtual void EmitInstruction(const MCInst &Instruction); virtual void Finish(); + +private: + virtual void EmitInstToFragment(const MCInst &Inst) { + llvm_unreachable("Not used by WinCOFF."); + } + virtual void EmitInstToData(const MCInst &Inst) { + llvm_unreachable("Not used by WinCOFF."); + } + + void SetSection(StringRef Section, + unsigned Characteristics, + SectionKind Kind) { + SwitchSection(getContext().getCOFFSection(Section, Characteristics, Kind)); + } + + void SetSectionText() { + SetSection(".text", + COFF::IMAGE_SCN_CNT_CODE + | COFF::IMAGE_SCN_MEM_EXECUTE + | COFF::IMAGE_SCN_MEM_READ, + SectionKind::getText()); + EmitCodeAlignment(4, 0); + } + + void SetSectionData() { + SetSection(".data", + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA + | COFF::IMAGE_SCN_MEM_READ + | COFF::IMAGE_SCN_MEM_WRITE, + SectionKind::getDataRel()); + EmitCodeAlignment(4, 0); + } + + void SetSectionBSS() { + SetSection(".bss", + COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA + | COFF::IMAGE_SCN_MEM_READ + | COFF::IMAGE_SCN_MEM_WRITE, + SectionKind::getBSS()); + EmitCodeAlignment(4, 0); + } + }; } // end anonymous namespace. @@ -126,47 +165,81 @@ void WinCOFFStreamer::AddCommonSymbol(MCSymbol *Symbol, uint64_t Size, // MCStreamer interface +void WinCOFFStreamer::InitSections() { + SetSectionText(); + SetSectionData(); + SetSectionBSS(); + SetSectionText(); +} + void WinCOFFStreamer::EmitLabel(MCSymbol *Symbol) { - // TODO: This is copied almost exactly from the MachOStreamer. Consider - // merging into MCObjectStreamer? assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); - assert(!Symbol->isVariable() && "Cannot emit a variable symbol!"); - assert(CurSection && "Cannot emit before setting section!"); - - Symbol->setSection(*CurSection); - - MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); - - // FIXME: This is wasteful, we don't necessarily need to create a data - // fragment. Instead, we should mark the symbol as pointing into the data - // fragment if it exists, otherwise we should just queue the label and set its - // fragment pointer when we emit the next fragment. - MCDataFragment *DF = getOrCreateDataFragment(); - - assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); - SD.setFragment(DF); - SD.setOffset(DF->getContents().size()); + MCObjectStreamer::EmitLabel(Symbol); } void WinCOFFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { llvm_unreachable("not implemented"); } +void WinCOFFStreamer::EmitThumbFunc(MCSymbol *Func) { + llvm_unreachable("not implemented"); +} + void WinCOFFStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { - // TODO: This is exactly the same as MachOStreamer. Consider merging into - // MCObjectStreamer. - getAssembler().getOrCreateSymbolData(*Symbol); - AddValueSymbols(Value); - Symbol->setVariableValue(Value); + assert((Symbol->isInSection() + ? Symbol->getSection().getVariant() == MCSection::SV_COFF + : true) && "Got non COFF section in the COFF backend!"); + // FIXME: This is all very ugly and depressing. What needs to happen here + // depends on quite a few things that are all part of relaxation, which we + // don't really even do. + + if (Value->getKind() != MCExpr::SymbolRef) { + // TODO: This is exactly the same as MachOStreamer. Consider merging into + // MCObjectStreamer. + getAssembler().getOrCreateSymbolData(*Symbol); + AddValueSymbols(Value); + Symbol->setVariableValue(Value); + } else { + // FIXME: This is a horrible way to do this :(. This should really be + // handled after we are done with the MC* objects and immediately before + // writing out the object file when we know exactly what the symbol should + // look like in the coff symbol table. I'm not doing that now because the + // COFF object writer doesn't have a clearly defined separation between MC + // data structures, the object writers data structures, and the raw, POD, + // data structures that get written to disk. + + // Copy over the aliased data. + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + const MCSymbolData &RealSD = getAssembler().getOrCreateSymbolData( + dyn_cast(Value)->getSymbol()); + + // FIXME: This is particularly nasty because it breaks as soon as any data + // members of MCSymbolData change. + SD.CommonAlign = RealSD.CommonAlign; + SD.CommonSize = RealSD.CommonSize; + SD.Flags = RealSD.Flags; + SD.Fragment = RealSD.Fragment; + SD.Index = RealSD.Index; + SD.IsExternal = RealSD.IsExternal; + SD.IsPrivateExtern = RealSD.IsPrivateExtern; + SD.Offset = RealSD.Offset; + SD.SymbolSize = RealSD.SymbolSize; + } } void WinCOFFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { + assert(Symbol && "Symbol must be non-null!"); + assert((Symbol->isInSection() + ? Symbol->getSection().getVariant() == MCSection::SV_COFF + : true) && "Got non COFF section in the COFF backend!"); switch (Attribute) { case MCSA_WeakReference: - getAssembler().getOrCreateSymbolData(*Symbol).modifyFlags( - COFF::SF_WeakReference, - COFF::SF_WeakReference); + case MCSA_Weak: { + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + SD.modifyFlags(COFF::SF_WeakExternal, COFF::SF_WeakExternal); + SD.setExternal(true); + } break; case MCSA_Global: @@ -184,6 +257,9 @@ void WinCOFFStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { } void WinCOFFStreamer::BeginCOFFSymbolDef(MCSymbol const *Symbol) { + assert((Symbol->isInSection() + ? Symbol->getSection().getVariant() == MCSection::SV_COFF + : true) && "Got non COFF section in the COFF backend!"); assert(CurSymbol == NULL && "EndCOFFSymbolDef must be called between calls " "to BeginCOFFSymbolDef!"); CurSymbol = Symbol; @@ -220,10 +296,16 @@ void WinCOFFStreamer::EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { void WinCOFFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { + assert((Symbol->isInSection() + ? Symbol->getSection().getVariant() == MCSection::SV_COFF + : true) && "Got non COFF section in the COFF backend!"); AddCommonSymbol(Symbol, Size, ByteAlignment, true); } void WinCOFFStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { + assert((Symbol->isInSection() + ? Symbol->getSection().getVariant() == MCSection::SV_COFF + : true) && "Got non COFF section in the COFF backend!"); AddCommonSymbol(Symbol, Size, 1, false); } @@ -243,32 +325,6 @@ void WinCOFFStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end()); } -void WinCOFFStreamer::EmitValue(const MCExpr *Value, unsigned Size, - unsigned AddrSpace) { - assert(AddrSpace == 0 && "Address space must be 0!"); - - // TODO: This is copied exactly from the MachOStreamer. Consider merging into - // MCObjectStreamer? - MCDataFragment *DF = getOrCreateDataFragment(); - - // Avoid fixups when possible. - int64_t AbsValue; - if (AddValueSymbols(Value)->EvaluateAsAbsolute(AbsValue)) { - // FIXME: Endianness assumption. - for (unsigned i = 0; i != Size; ++i) - DF->getContents().push_back(uint8_t(AbsValue >> (i * 8))); - } else { - DF->addFixup(MCFixup::Create(DF->getContents().size(), - AddValueSymbols(Value), - MCFixup::getKindForSize(Size))); - DF->getContents().resize(DF->getContents().size() + Size, 0); - } -} - -void WinCOFFStreamer::EmitGPRel32Value(const MCExpr *Value) { - llvm_unreachable("not implemented"); -} - void WinCOFFStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, unsigned ValueSize, @@ -300,21 +356,11 @@ void WinCOFFStreamer::EmitCodeAlignment(unsigned ByteAlignment, getCurrentSectionData()->setAlignment(ByteAlignment); } -void WinCOFFStreamer::EmitValueToOffset(const MCExpr *Offset, - unsigned char Value) { - llvm_unreachable("not implemented"); -} - void WinCOFFStreamer::EmitFileDirective(StringRef Filename) { // Ignore for now, linkers don't care, and proper debug // info will be a much large effort. } -void WinCOFFStreamer::EmitDwarfFileDirective(unsigned FileNo, - StringRef Filename) { - llvm_unreachable("not implemented"); -} - void WinCOFFStreamer::EmitInstruction(const MCInst &Instruction) { for (unsigned i = 0, e = Instruction.getNumOperands(); i != e; ++i) if (Instruction.getOperand(i).isExpr()) diff --git a/lib/Makefile b/lib/Makefile index 3807f31c7037..ed27854f22c7 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -11,7 +11,7 @@ LEVEL = .. include $(LEVEL)/Makefile.config PARALLEL_DIRS := VMCore AsmParser Bitcode Archive Analysis Transforms CodeGen \ - Target ExecutionEngine Linker MC CompilerDriver + Target ExecutionEngine Linker MC CompilerDriver Object include $(LEVEL)/Makefile.common diff --git a/lib/Object/CMakeLists.txt b/lib/Object/CMakeLists.txt new file mode 100644 index 000000000000..6a6814fd37d9 --- /dev/null +++ b/lib/Object/CMakeLists.txt @@ -0,0 +1,6 @@ +add_llvm_library(LLVMObject + MachOObject.cpp + ObjectFile.cpp + COFFObjectFile.cpp + ELFObjectFile.cpp + ) diff --git a/lib/Object/COFFObjectFile.cpp b/lib/Object/COFFObjectFile.cpp new file mode 100644 index 000000000000..cfee82a0b217 --- /dev/null +++ b/lib/Object/COFFObjectFile.cpp @@ -0,0 +1,375 @@ +//===- COFFObjectFile.cpp - COFF object file implementation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the COFFObjectFile class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/COFF.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace object; + +namespace { +using support::ulittle8_t; +using support::ulittle16_t; +using support::ulittle32_t; +using support::little16_t; +} + +namespace { +struct coff_file_header { + ulittle16_t Machine; + ulittle16_t NumberOfSections; + ulittle32_t TimeDateStamp; + ulittle32_t PointerToSymbolTable; + ulittle32_t NumberOfSymbols; + ulittle16_t SizeOfOptionalHeader; + ulittle16_t Characteristics; +}; +} + +extern char coff_file_header_layout_static_assert + [sizeof(coff_file_header) == 20 ? 1 : -1]; + +namespace { +struct coff_symbol { + struct StringTableOffset { + ulittle32_t Zeroes; + ulittle32_t Offset; + }; + + union { + char ShortName[8]; + StringTableOffset Offset; + } Name; + + ulittle32_t Value; + little16_t SectionNumber; + + struct { + ulittle8_t BaseType; + ulittle8_t ComplexType; + } Type; + + ulittle8_t StorageClass; + ulittle8_t NumberOfAuxSymbols; +}; +} + +extern char coff_coff_symbol_layout_static_assert + [sizeof(coff_symbol) == 18 ? 1 : -1]; + +namespace { +struct coff_section { + char Name[8]; + ulittle32_t VirtualSize; + ulittle32_t VirtualAddress; + ulittle32_t SizeOfRawData; + ulittle32_t PointerToRawData; + ulittle32_t PointerToRelocations; + ulittle32_t PointerToLinenumbers; + ulittle16_t NumberOfRelocations; + ulittle16_t NumberOfLinenumbers; + ulittle32_t Characteristics; +}; +} + +extern char coff_coff_section_layout_static_assert + [sizeof(coff_section) == 40 ? 1 : -1]; + +namespace { +class COFFObjectFile : public ObjectFile { +private: + const coff_file_header *Header; + const coff_section *SectionTable; + const coff_symbol *SymbolTable; + const char *StringTable; + + const coff_section *getSection(std::size_t index) const; + const char *getString(std::size_t offset) const; + +protected: + virtual SymbolRef getSymbolNext(DataRefImpl Symb) const; + virtual StringRef getSymbolName(DataRefImpl Symb) const; + virtual uint64_t getSymbolAddress(DataRefImpl Symb) const; + virtual uint64_t getSymbolSize(DataRefImpl Symb) const; + virtual char getSymbolNMTypeChar(DataRefImpl Symb) const; + virtual bool isSymbolInternal(DataRefImpl Symb) const; + + virtual SectionRef getSectionNext(DataRefImpl Sec) const; + virtual StringRef getSectionName(DataRefImpl Sec) const; + virtual uint64_t getSectionAddress(DataRefImpl Sec) const; + virtual uint64_t getSectionSize(DataRefImpl Sec) const; + virtual StringRef getSectionContents(DataRefImpl Sec) const; + virtual bool isSectionText(DataRefImpl Sec) const; + +public: + COFFObjectFile(MemoryBuffer *Object); + virtual symbol_iterator begin_symbols() const; + virtual symbol_iterator end_symbols() const; + virtual section_iterator begin_sections() const; + virtual section_iterator end_sections() const; + + virtual uint8_t getBytesInAddress() const; + virtual StringRef getFileFormatName() const; + virtual unsigned getArch() const; +}; +} // end namespace + +SymbolRef COFFObjectFile::getSymbolNext(DataRefImpl Symb) const { + const coff_symbol *symb = reinterpret_cast(Symb.p); + symb += 1 + symb->NumberOfAuxSymbols; + Symb.p = reinterpret_cast(symb); + return SymbolRef(Symb, this); +} + +StringRef COFFObjectFile::getSymbolName(DataRefImpl Symb) const { + const coff_symbol *symb = reinterpret_cast(Symb.p); + // Check for string table entry. First 4 bytes are 0. + if (symb->Name.Offset.Zeroes == 0) { + uint32_t Offset = symb->Name.Offset.Offset; + return StringRef(getString(Offset)); + } + + if (symb->Name.ShortName[7] == 0) + // Null terminated, let ::strlen figure out the length. + return StringRef(symb->Name.ShortName); + // Not null terminated, use all 8 bytes. + return StringRef(symb->Name.ShortName, 8); +} + +uint64_t COFFObjectFile::getSymbolAddress(DataRefImpl Symb) const { + const coff_symbol *symb = reinterpret_cast(Symb.p); + const coff_section *Section = getSection(symb->SectionNumber); + char Type = getSymbolNMTypeChar(Symb); + if (Type == 'U' || Type == 'w') + return UnknownAddressOrSize; + if (Section) + return Section->VirtualAddress + symb->Value; + return symb->Value; +} + +uint64_t COFFObjectFile::getSymbolSize(DataRefImpl Symb) const { + // FIXME: Return the correct size. This requires looking at all the symbols + // in the same section as this symbol, and looking for either the next + // symbol, or the end of the section. + const coff_symbol *symb = reinterpret_cast(Symb.p); + const coff_section *Section = getSection(symb->SectionNumber); + char Type = getSymbolNMTypeChar(Symb); + if (Type == 'U' || Type == 'w') + return UnknownAddressOrSize; + if (Section) + return Section->SizeOfRawData - symb->Value; + return 0; +} + +char COFFObjectFile::getSymbolNMTypeChar(DataRefImpl Symb) const { + const coff_symbol *symb = reinterpret_cast(Symb.p); + char ret = StringSwitch(getSymbolName(Symb)) + .StartsWith(".debug", 'N') + .StartsWith(".sxdata", 'N') + .Default('?'); + + if (ret != '?') + return ret; + + uint32_t Characteristics = 0; + uint32_t PointerToRawData = 0; + const coff_section *Section = getSection(symb->SectionNumber); + if (Section) { + Characteristics = Section->Characteristics; + PointerToRawData = Section->PointerToRawData; + } + + switch (symb->SectionNumber) { + case COFF::IMAGE_SYM_UNDEFINED: + // Check storage classes. + if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL) + return 'w'; // Don't do ::toupper. + else + ret = 'u'; + break; + case COFF::IMAGE_SYM_ABSOLUTE: + ret = 'a'; + break; + case COFF::IMAGE_SYM_DEBUG: + ret = 'n'; + break; + default: + // Check section type. + if (Characteristics & COFF::IMAGE_SCN_CNT_CODE) + ret = 't'; + else if ( Characteristics & COFF::IMAGE_SCN_MEM_READ + && ~Characteristics & COFF::IMAGE_SCN_MEM_WRITE) // Read only. + ret = 'r'; + else if (Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA) + ret = 'd'; + else if (Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) + ret = 'b'; + else if (Characteristics & COFF::IMAGE_SCN_LNK_INFO) + ret = 'i'; + + // Check for section symbol. + else if ( symb->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC + && symb->Value == 0) + ret = 's'; + } + + if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL) + ret = ::toupper(ret); + + return ret; +} + +bool COFFObjectFile::isSymbolInternal(DataRefImpl Symb) const { + return false; +} + +SectionRef COFFObjectFile::getSectionNext(DataRefImpl Sec) const { + const coff_section *sec = reinterpret_cast(Sec.p); + sec += 1; + Sec.p = reinterpret_cast(sec); + return SectionRef(Sec, this); +} + +StringRef COFFObjectFile::getSectionName(DataRefImpl Sec) const { + const coff_section *sec = reinterpret_cast(Sec.p); + StringRef name; + if (sec->Name[7] == 0) + // Null terminated, let ::strlen figure out the length. + name = sec->Name; + else + // Not null terminated, use all 8 bytes. + name = StringRef(sec->Name, 8); + + // Check for string table entry. First byte is '/'. + if (name[0] == '/') { + uint32_t Offset; + name.getAsInteger(10, Offset); + return StringRef(getString(Offset)); + } + + // It's just a normal name. + return name; +} + +uint64_t COFFObjectFile::getSectionAddress(DataRefImpl Sec) const { + const coff_section *sec = reinterpret_cast(Sec.p); + return sec->VirtualAddress; +} + +uint64_t COFFObjectFile::getSectionSize(DataRefImpl Sec) const { + const coff_section *sec = reinterpret_cast(Sec.p); + return sec->SizeOfRawData; +} + +StringRef COFFObjectFile::getSectionContents(DataRefImpl Sec) const { + const coff_section *sec = reinterpret_cast(Sec.p); + return StringRef(reinterpret_cast(base + sec->PointerToRawData), + sec->SizeOfRawData); +} + +bool COFFObjectFile::isSectionText(DataRefImpl Sec) const { + const coff_section *sec = reinterpret_cast(Sec.p); + return sec->Characteristics & COFF::IMAGE_SCN_CNT_CODE; +} + +COFFObjectFile::COFFObjectFile(MemoryBuffer *Object) + : ObjectFile(Object) { + Header = reinterpret_cast(base); + SectionTable = + reinterpret_cast( base + + sizeof(coff_file_header) + + Header->SizeOfOptionalHeader); + SymbolTable = + reinterpret_cast(base + Header->PointerToSymbolTable); + + // Find string table. + StringTable = reinterpret_cast(base) + + Header->PointerToSymbolTable + + Header->NumberOfSymbols * 18; +} + +ObjectFile::symbol_iterator COFFObjectFile::begin_symbols() const { + DataRefImpl ret; + ret.p = reinterpret_cast(SymbolTable); + return symbol_iterator(SymbolRef(ret, this)); +} + +ObjectFile::symbol_iterator COFFObjectFile::end_symbols() const { + // The symbol table ends where the string table begins. + DataRefImpl ret; + ret.p = reinterpret_cast(StringTable); + return symbol_iterator(SymbolRef(ret, this)); +} + +ObjectFile::section_iterator COFFObjectFile::begin_sections() const { + DataRefImpl ret; + ret.p = reinterpret_cast(SectionTable); + return section_iterator(SectionRef(ret, this)); +} + +ObjectFile::section_iterator COFFObjectFile::end_sections() const { + DataRefImpl ret; + ret.p = reinterpret_cast(SectionTable + Header->NumberOfSections); + return section_iterator(SectionRef(ret, this)); +} + +uint8_t COFFObjectFile::getBytesInAddress() const { + return getArch() == Triple::x86_64 ? 8 : 4; +} + +StringRef COFFObjectFile::getFileFormatName() const { + switch(Header->Machine) { + case COFF::IMAGE_FILE_MACHINE_I386: + return "COFF-i386"; + case COFF::IMAGE_FILE_MACHINE_AMD64: + return "COFF-x86-64"; + default: + return "COFF-"; + } +} + +unsigned COFFObjectFile::getArch() const { + switch(Header->Machine) { + case COFF::IMAGE_FILE_MACHINE_I386: + return Triple::x86; + case COFF::IMAGE_FILE_MACHINE_AMD64: + return Triple::x86_64; + default: + return Triple::UnknownArch; + } +} + +const coff_section *COFFObjectFile::getSection(std::size_t index) const { + if (index > 0 && index <= Header->NumberOfSections) + return SectionTable + (index - 1); + return 0; +} + +const char *COFFObjectFile::getString(std::size_t offset) const { + const ulittle32_t *StringTableSize = + reinterpret_cast(StringTable); + if (offset < *StringTableSize) + return StringTable + offset; + return 0; +} + +namespace llvm { + + ObjectFile *ObjectFile::createCOFFObjectFile(MemoryBuffer *Object) { + return new COFFObjectFile(Object); + } + +} // end namespace llvm diff --git a/lib/Object/ELFObjectFile.cpp b/lib/Object/ELFObjectFile.cpp new file mode 100644 index 000000000000..682be770f48f --- /dev/null +++ b/lib/Object/ELFObjectFile.cpp @@ -0,0 +1,686 @@ +//===- ELFObjectFile.cpp - ELF object file implementation -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ELFObjectFile class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/ELF.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MemoryBuffer.h" +#include +#include + +using namespace llvm; +using namespace object; + +// Templates to choose Elf_Addr and Elf_Off depending on is64Bits. +namespace { +template +struct ELFDataTypeTypedefHelperCommon { + typedef support::detail::packed_endian_specific_integral + Elf_Half; + typedef support::detail::packed_endian_specific_integral + Elf_Word; + typedef support::detail::packed_endian_specific_integral + Elf_Sword; + typedef support::detail::packed_endian_specific_integral + Elf_Xword; + typedef support::detail::packed_endian_specific_integral + Elf_Sxword; +}; +} + +namespace { +template +struct ELFDataTypeTypedefHelper; + +/// ELF 32bit types. +template +struct ELFDataTypeTypedefHelper + : ELFDataTypeTypedefHelperCommon { + typedef support::detail::packed_endian_specific_integral + Elf_Addr; + typedef support::detail::packed_endian_specific_integral + Elf_Off; +}; + +/// ELF 64bit types. +template +struct ELFDataTypeTypedefHelper + : ELFDataTypeTypedefHelperCommon{ + typedef support::detail::packed_endian_specific_integral + Elf_Addr; + typedef support::detail::packed_endian_specific_integral + Elf_Off; +}; +} + +// I really don't like doing this, but the alternative is copypasta. +#define LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits) \ +typedef typename \ + ELFDataTypeTypedefHelper::Elf_Addr Elf_Addr; \ +typedef typename \ + ELFDataTypeTypedefHelper::Elf_Off Elf_Off; \ +typedef typename \ + ELFDataTypeTypedefHelper::Elf_Half Elf_Half; \ +typedef typename \ + ELFDataTypeTypedefHelper::Elf_Word Elf_Word; \ +typedef typename \ + ELFDataTypeTypedefHelper::Elf_Sword Elf_Sword; \ +typedef typename \ + ELFDataTypeTypedefHelper::Elf_Xword Elf_Xword; \ +typedef typename \ + ELFDataTypeTypedefHelper::Elf_Sxword Elf_Sxword; + + // Section header. +namespace { +template +struct Elf_Shdr_Base; + +template +struct Elf_Shdr_Base { + LLVM_ELF_IMPORT_TYPES(target_endianness, false) + Elf_Word sh_name; // Section name (index into string table) + Elf_Word sh_type; // Section type (SHT_*) + Elf_Word sh_flags; // Section flags (SHF_*) + Elf_Addr sh_addr; // Address where section is to be loaded + Elf_Off sh_offset; // File offset of section data, in bytes + Elf_Word sh_size; // Size of section, in bytes + Elf_Word sh_link; // Section type-specific header table index link + Elf_Word sh_info; // Section type-specific extra information + Elf_Word sh_addralign;// Section address alignment + Elf_Word sh_entsize; // Size of records contained within the section +}; + +template +struct Elf_Shdr_Base { + LLVM_ELF_IMPORT_TYPES(target_endianness, true) + Elf_Word sh_name; // Section name (index into string table) + Elf_Word sh_type; // Section type (SHT_*) + Elf_Xword sh_flags; // Section flags (SHF_*) + Elf_Addr sh_addr; // Address where section is to be loaded + Elf_Off sh_offset; // File offset of section data, in bytes + Elf_Xword sh_size; // Size of section, in bytes + Elf_Word sh_link; // Section type-specific header table index link + Elf_Word sh_info; // Section type-specific extra information + Elf_Xword sh_addralign;// Section address alignment + Elf_Xword sh_entsize; // Size of records contained within the section +}; + +template +struct Elf_Shdr_Impl : Elf_Shdr_Base { + using Elf_Shdr_Base::sh_entsize; + using Elf_Shdr_Base::sh_size; + + /// @brief Get the number of entities this section contains if it has any. + unsigned getEntityCount() const { + if (sh_entsize == 0) + return 0; + return sh_size / sh_entsize; + } +}; +} + +namespace { +template +struct Elf_Sym_Base; + +template +struct Elf_Sym_Base { + LLVM_ELF_IMPORT_TYPES(target_endianness, false) + Elf_Word st_name; // Symbol name (index into string table) + Elf_Addr st_value; // Value or address associated with the symbol + Elf_Word st_size; // Size of the symbol + unsigned char st_info; // Symbol's type and binding attributes + unsigned char st_other; // Must be zero; reserved + Elf_Half st_shndx; // Which section (header table index) it's defined in +}; + +template +struct Elf_Sym_Base { + LLVM_ELF_IMPORT_TYPES(target_endianness, true) + Elf_Word st_name; // Symbol name (index into string table) + unsigned char st_info; // Symbol's type and binding attributes + unsigned char st_other; // Must be zero; reserved + Elf_Half st_shndx; // Which section (header table index) it's defined in + Elf_Addr st_value; // Value or address associated with the symbol + Elf_Xword st_size; // Size of the symbol +}; + +template +struct Elf_Sym_Impl : Elf_Sym_Base { + using Elf_Sym_Base::st_info; + + // These accessors and mutators correspond to the ELF32_ST_BIND, + // ELF32_ST_TYPE, and ELF32_ST_INFO macros defined in the ELF specification: + unsigned char getBinding() const { return st_info >> 4; } + unsigned char getType() const { return st_info & 0x0f; } + void setBinding(unsigned char b) { setBindingAndType(b, getType()); } + void setType(unsigned char t) { setBindingAndType(getBinding(), t); } + void setBindingAndType(unsigned char b, unsigned char t) { + st_info = (b << 4) + (t & 0x0f); + } +}; +} + +namespace { +template +class ELFObjectFile : public ObjectFile { + LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits) + + typedef Elf_Shdr_Impl Elf_Shdr; + typedef Elf_Sym_Impl Elf_Sym; + + struct Elf_Ehdr { + unsigned char e_ident[ELF::EI_NIDENT]; // ELF Identification bytes + Elf_Half e_type; // Type of file (see ET_*) + Elf_Half e_machine; // Required architecture for this file (see EM_*) + Elf_Word e_version; // Must be equal to 1 + Elf_Addr e_entry; // Address to jump to in order to start program + Elf_Off e_phoff; // Program header table's file offset, in bytes + Elf_Off e_shoff; // Section header table's file offset, in bytes + Elf_Word e_flags; // Processor-specific flags + Elf_Half e_ehsize; // Size of ELF header, in bytes + Elf_Half e_phentsize;// Size of an entry in the program header table + Elf_Half e_phnum; // Number of entries in the program header table + Elf_Half e_shentsize;// Size of an entry in the section header table + Elf_Half e_shnum; // Number of entries in the section header table + Elf_Half e_shstrndx; // Section header table index of section name + // string table + bool checkMagic() const { + return (memcmp(e_ident, ELF::ElfMagic, strlen(ELF::ElfMagic))) == 0; + } + unsigned char getFileClass() const { return e_ident[ELF::EI_CLASS]; } + unsigned char getDataEncoding() const { return e_ident[ELF::EI_DATA]; } + }; + + typedef SmallVector SymbolTableSections_t; + + const Elf_Ehdr *Header; + const Elf_Shdr *SectionHeaderTable; + const Elf_Shdr *dot_shstrtab_sec; // Section header string table. + const Elf_Shdr *dot_strtab_sec; // Symbol header string table. + SymbolTableSections_t SymbolTableSections; + + void validateSymbol(DataRefImpl Symb) const; + const Elf_Sym *getSymbol(DataRefImpl Symb) const; + const Elf_Shdr *getSection(DataRefImpl index) const; + const Elf_Shdr *getSection(uint16_t index) const; + const char *getString(uint16_t section, uint32_t offset) const; + const char *getString(const Elf_Shdr *section, uint32_t offset) const; + +protected: + virtual SymbolRef getSymbolNext(DataRefImpl Symb) const; + virtual StringRef getSymbolName(DataRefImpl Symb) const; + virtual uint64_t getSymbolAddress(DataRefImpl Symb) const; + virtual uint64_t getSymbolSize(DataRefImpl Symb) const; + virtual char getSymbolNMTypeChar(DataRefImpl Symb) const; + virtual bool isSymbolInternal(DataRefImpl Symb) const; + + virtual SectionRef getSectionNext(DataRefImpl Sec) const; + virtual StringRef getSectionName(DataRefImpl Sec) const; + virtual uint64_t getSectionAddress(DataRefImpl Sec) const; + virtual uint64_t getSectionSize(DataRefImpl Sec) const; + virtual StringRef getSectionContents(DataRefImpl Sec) const; + virtual bool isSectionText(DataRefImpl Sec) const; + +public: + ELFObjectFile(MemoryBuffer *Object); + virtual symbol_iterator begin_symbols() const; + virtual symbol_iterator end_symbols() const; + virtual section_iterator begin_sections() const; + virtual section_iterator end_sections() const; + + virtual uint8_t getBytesInAddress() const; + virtual StringRef getFileFormatName() const; + virtual unsigned getArch() const; +}; +} // end namespace + +template +void ELFObjectFile + ::validateSymbol(DataRefImpl Symb) const { + const Elf_Sym *symb = getSymbol(Symb); + const Elf_Shdr *SymbolTableSection = SymbolTableSections[Symb.d.b]; + // FIXME: We really need to do proper error handling in the case of an invalid + // input file. Because we don't use exceptions, I think we'll just pass + // an error object around. + if (!( symb + && SymbolTableSection + && symb >= (const Elf_Sym*)(base + + SymbolTableSection->sh_offset) + && symb < (const Elf_Sym*)(base + + SymbolTableSection->sh_offset + + SymbolTableSection->sh_size))) + // FIXME: Proper error handling. + report_fatal_error("Symb must point to a valid symbol!"); +} + +template +SymbolRef ELFObjectFile + ::getSymbolNext(DataRefImpl Symb) const { + validateSymbol(Symb); + const Elf_Shdr *SymbolTableSection = SymbolTableSections[Symb.d.b]; + + ++Symb.d.a; + // Check to see if we are at the end of this symbol table. + if (Symb.d.a >= SymbolTableSection->getEntityCount()) { + // We are at the end. If there are other symbol tables, jump to them. + ++Symb.d.b; + Symb.d.a = 1; // The 0th symbol in ELF is fake. + // Otherwise return the terminator. + if (Symb.d.b >= SymbolTableSections.size()) { + Symb.d.a = std::numeric_limits::max(); + Symb.d.b = std::numeric_limits::max(); + } + } + + return SymbolRef(Symb, this); +} + +template +StringRef ELFObjectFile + ::getSymbolName(DataRefImpl Symb) const { + validateSymbol(Symb); + const Elf_Sym *symb = getSymbol(Symb); + if (symb->st_name == 0) { + const Elf_Shdr *section = getSection(symb->st_shndx); + if (!section) + return ""; + return getString(dot_shstrtab_sec, section->sh_name); + } + + // Use the default symbol table name section. + return getString(dot_strtab_sec, symb->st_name); +} + +template +uint64_t ELFObjectFile + ::getSymbolAddress(DataRefImpl Symb) const { + validateSymbol(Symb); + const Elf_Sym *symb = getSymbol(Symb); + const Elf_Shdr *Section; + switch (symb->st_shndx) { + case ELF::SHN_COMMON: + // Undefined symbols have no address yet. + case ELF::SHN_UNDEF: return UnknownAddressOrSize; + case ELF::SHN_ABS: return symb->st_value; + default: Section = getSection(symb->st_shndx); + } + + switch (symb->getType()) { + case ELF::STT_SECTION: return Section ? Section->sh_addr + : UnknownAddressOrSize; + case ELF::STT_FUNC: + case ELF::STT_OBJECT: + case ELF::STT_NOTYPE: + return symb->st_value; + default: return UnknownAddressOrSize; + } +} + +template +uint64_t ELFObjectFile + ::getSymbolSize(DataRefImpl Symb) const { + validateSymbol(Symb); + const Elf_Sym *symb = getSymbol(Symb); + if (symb->st_size == 0) + return UnknownAddressOrSize; + return symb->st_size; +} + +template +char ELFObjectFile + ::getSymbolNMTypeChar(DataRefImpl Symb) const { + validateSymbol(Symb); + const Elf_Sym *symb = getSymbol(Symb); + const Elf_Shdr *Section = getSection(symb->st_shndx); + + char ret = '?'; + + if (Section) { + switch (Section->sh_type) { + case ELF::SHT_PROGBITS: + case ELF::SHT_DYNAMIC: + switch (Section->sh_flags) { + case (ELF::SHF_ALLOC | ELF::SHF_EXECINSTR): + ret = 't'; break; + case (ELF::SHF_ALLOC | ELF::SHF_WRITE): + ret = 'd'; break; + case ELF::SHF_ALLOC: + case (ELF::SHF_ALLOC | ELF::SHF_MERGE): + case (ELF::SHF_ALLOC | ELF::SHF_MERGE | ELF::SHF_STRINGS): + ret = 'r'; break; + } + break; + case ELF::SHT_NOBITS: ret = 'b'; + } + } + + switch (symb->st_shndx) { + case ELF::SHN_UNDEF: + if (ret == '?') + ret = 'U'; + break; + case ELF::SHN_ABS: ret = 'a'; break; + case ELF::SHN_COMMON: ret = 'c'; break; + } + + switch (symb->getBinding()) { + case ELF::STB_GLOBAL: ret = ::toupper(ret); break; + case ELF::STB_WEAK: + if (symb->st_shndx == ELF::SHN_UNDEF) + ret = 'w'; + else + if (symb->getType() == ELF::STT_OBJECT) + ret = 'V'; + else + ret = 'W'; + } + + if (ret == '?' && symb->getType() == ELF::STT_SECTION) + return StringSwitch(getSymbolName(Symb)) + .StartsWith(".debug", 'N') + .StartsWith(".note", 'n'); + + return ret; +} + +template +bool ELFObjectFile + ::isSymbolInternal(DataRefImpl Symb) const { + validateSymbol(Symb); + const Elf_Sym *symb = getSymbol(Symb); + + if ( symb->getType() == ELF::STT_FILE + || symb->getType() == ELF::STT_SECTION) + return true; + return false; +} + +template +SectionRef ELFObjectFile + ::getSectionNext(DataRefImpl Sec) const { + const uint8_t *sec = reinterpret_cast(Sec.p); + sec += Header->e_shentsize; + Sec.p = reinterpret_cast(sec); + return SectionRef(Sec, this); +} + +template +StringRef ELFObjectFile + ::getSectionName(DataRefImpl Sec) const { + const Elf_Shdr *sec = reinterpret_cast(Sec.p); + return StringRef(getString(dot_shstrtab_sec, sec->sh_name)); +} + +template +uint64_t ELFObjectFile + ::getSectionAddress(DataRefImpl Sec) const { + const Elf_Shdr *sec = reinterpret_cast(Sec.p); + return sec->sh_addr; +} + +template +uint64_t ELFObjectFile + ::getSectionSize(DataRefImpl Sec) const { + const Elf_Shdr *sec = reinterpret_cast(Sec.p); + return sec->sh_size; +} + +template +StringRef ELFObjectFile + ::getSectionContents(DataRefImpl Sec) const { + const Elf_Shdr *sec = reinterpret_cast(Sec.p); + const char *start = (char*)base + sec->sh_offset; + return StringRef(start, sec->sh_size); +} + +template +bool ELFObjectFile + ::isSectionText(DataRefImpl Sec) const { + const Elf_Shdr *sec = reinterpret_cast(Sec.p); + if (sec->sh_flags & ELF::SHF_EXECINSTR) + return true; + return false; +} + +template +ELFObjectFile::ELFObjectFile(MemoryBuffer *Object) + : ObjectFile(Object) + , SectionHeaderTable(0) + , dot_shstrtab_sec(0) + , dot_strtab_sec(0) { + Header = reinterpret_cast(base); + + if (Header->e_shoff == 0) + return; + + SectionHeaderTable = + reinterpret_cast(base + Header->e_shoff); + uint32_t SectionTableSize = Header->e_shnum * Header->e_shentsize; + if (!( (const uint8_t *)SectionHeaderTable + SectionTableSize + <= base + MapFile->getBufferSize())) + // FIXME: Proper error handling. + report_fatal_error("Section table goes past end of file!"); + + + // To find the symbol tables we walk the section table to find SHT_STMTAB. + for (const char *i = reinterpret_cast(SectionHeaderTable), + *e = i + Header->e_shnum * Header->e_shentsize; + i != e; i += Header->e_shentsize) { + const Elf_Shdr *sh = reinterpret_cast(i); + if (sh->sh_type == ELF::SHT_SYMTAB) { + SymbolTableSections.push_back(sh); + } + } + + // Get string table sections. + dot_shstrtab_sec = getSection(Header->e_shstrndx); + if (dot_shstrtab_sec) { + // Verify that the last byte in the string table in a null. + if (((const char*)base + dot_shstrtab_sec->sh_offset) + [dot_shstrtab_sec->sh_size - 1] != 0) + // FIXME: Proper error handling. + report_fatal_error("String table must end with a null terminator!"); + } + + // Merge this into the above loop. + for (const char *i = reinterpret_cast(SectionHeaderTable), + *e = i + Header->e_shnum * Header->e_shentsize; + i != e; i += Header->e_shentsize) { + const Elf_Shdr *sh = reinterpret_cast(i); + if (sh->sh_type == ELF::SHT_STRTAB) { + StringRef SectionName(getString(dot_shstrtab_sec, sh->sh_name)); + if (SectionName == ".strtab") { + if (dot_strtab_sec != 0) + // FIXME: Proper error handling. + report_fatal_error("Already found section named .strtab!"); + dot_strtab_sec = sh; + const char *dot_strtab = (const char*)base + sh->sh_offset; + if (dot_strtab[sh->sh_size - 1] != 0) + // FIXME: Proper error handling. + report_fatal_error("String table must end with a null terminator!"); + } + } + } +} + +template +ObjectFile::symbol_iterator ELFObjectFile + ::begin_symbols() const { + DataRefImpl SymbolData; + memset(&SymbolData, 0, sizeof(SymbolData)); + if (SymbolTableSections.size() == 0) { + SymbolData.d.a = std::numeric_limits::max(); + SymbolData.d.b = std::numeric_limits::max(); + } else { + SymbolData.d.a = 1; // The 0th symbol in ELF is fake. + SymbolData.d.b = 0; + } + return symbol_iterator(SymbolRef(SymbolData, this)); +} + +template +ObjectFile::symbol_iterator ELFObjectFile + ::end_symbols() const { + DataRefImpl SymbolData; + memset(&SymbolData, 0, sizeof(SymbolData)); + SymbolData.d.a = std::numeric_limits::max(); + SymbolData.d.b = std::numeric_limits::max(); + return symbol_iterator(SymbolRef(SymbolData, this)); +} + +template +ObjectFile::section_iterator ELFObjectFile + ::begin_sections() const { + DataRefImpl ret; + ret.p = reinterpret_cast(base + Header->e_shoff); + return section_iterator(SectionRef(ret, this)); +} + +template +ObjectFile::section_iterator ELFObjectFile + ::end_sections() const { + DataRefImpl ret; + ret.p = reinterpret_cast(base + + Header->e_shoff + + (Header->e_shentsize * Header->e_shnum)); + return section_iterator(SectionRef(ret, this)); +} + +template +uint8_t ELFObjectFile::getBytesInAddress() const { + return is64Bits ? 8 : 4; +} + +template +StringRef ELFObjectFile + ::getFileFormatName() const { + switch(Header->e_ident[ELF::EI_CLASS]) { + case ELF::ELFCLASS32: + switch(Header->e_machine) { + case ELF::EM_386: + return "ELF32-i386"; + case ELF::EM_X86_64: + return "ELF32-x86-64"; + default: + return "ELF32-unknown"; + } + case ELF::ELFCLASS64: + switch(Header->e_machine) { + case ELF::EM_386: + return "ELF64-i386"; + case ELF::EM_X86_64: + return "ELF64-x86-64"; + default: + return "ELF64-unknown"; + } + default: + // FIXME: Proper error handling. + report_fatal_error("Invalid ELFCLASS!"); + } +} + +template +unsigned ELFObjectFile::getArch() const { + switch(Header->e_machine) { + case ELF::EM_386: + return Triple::x86; + case ELF::EM_X86_64: + return Triple::x86_64; + default: + return Triple::UnknownArch; + } +} + +template +const typename ELFObjectFile::Elf_Sym * +ELFObjectFile::getSymbol(DataRefImpl Symb) const { + const Elf_Shdr *sec = SymbolTableSections[Symb.d.b]; + return reinterpret_cast( + base + + sec->sh_offset + + (Symb.d.a * sec->sh_entsize)); +} + +template +const typename ELFObjectFile::Elf_Shdr * +ELFObjectFile::getSection(DataRefImpl Symb) const { + const Elf_Shdr *sec = getSection(Symb.d.b); + if (sec->sh_type != ELF::SHT_SYMTAB) + // FIXME: Proper error handling. + report_fatal_error("Invalid symbol table section!"); + return sec; +} + +template +const typename ELFObjectFile::Elf_Shdr * +ELFObjectFile::getSection(uint16_t index) const { + if (index == 0 || index >= ELF::SHN_LORESERVE) + return 0; + if (!SectionHeaderTable || index >= Header->e_shnum) + // FIXME: Proper error handling. + report_fatal_error("Invalid section index!"); + + return reinterpret_cast( + reinterpret_cast(SectionHeaderTable) + + (index * Header->e_shentsize)); +} + +template +const char *ELFObjectFile + ::getString(uint16_t section, + ELF::Elf32_Word offset) const { + return getString(getSection(section), offset); +} + +template +const char *ELFObjectFile + ::getString(const Elf_Shdr *section, + ELF::Elf32_Word offset) const { + assert(section && section->sh_type == ELF::SHT_STRTAB && "Invalid section!"); + if (offset >= section->sh_size) + // FIXME: Proper error handling. + report_fatal_error("Sybol name offset outside of string table!"); + return (const char *)base + section->sh_offset + offset; +} + +// EI_CLASS, EI_DATA. +static std::pair +getElfArchType(MemoryBuffer *Object) { + if (Object->getBufferSize() < ELF::EI_NIDENT) + return std::make_pair((uint8_t)ELF::ELFCLASSNONE,(uint8_t)ELF::ELFDATANONE); + return std::make_pair( (uint8_t)Object->getBufferStart()[ELF::EI_CLASS] + , (uint8_t)Object->getBufferStart()[ELF::EI_DATA]); +} + +namespace llvm { + + ObjectFile *ObjectFile::createELFObjectFile(MemoryBuffer *Object) { + std::pair Ident = getElfArchType(Object); + if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2LSB) + return new ELFObjectFile(Object); + else if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2MSB) + return new ELFObjectFile(Object); + else if (Ident.first == ELF::ELFCLASS64 && Ident.second == ELF::ELFDATA2LSB) + return new ELFObjectFile(Object); + else if (Ident.first == ELF::ELFCLASS64 && Ident.second == ELF::ELFDATA2MSB) + return new ELFObjectFile(Object); + // FIXME: Proper error handling. + report_fatal_error("Not an ELF object file!"); + } + +} // end namespace llvm diff --git a/lib/Object/MachOObject.cpp b/lib/Object/MachOObject.cpp new file mode 100644 index 000000000000..5e64d6323288 --- /dev/null +++ b/lib/Object/MachOObject.cpp @@ -0,0 +1,342 @@ +//===- MachOObject.cpp - Mach-O Object File Wrapper -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/MachOObject.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/SwapByteOrder.h" + +using namespace llvm; +using namespace llvm::object; + +/* Translation Utilities */ + +template +static void SwapValue(T &Value) { + Value = sys::SwapByteOrder(Value); +} + +template +static void SwapStruct(T &Value); + +template +static void ReadInMemoryStruct(const MachOObject &MOO, + StringRef Buffer, uint64_t Base, + InMemoryStruct &Res) { + typedef T struct_type; + uint64_t Size = sizeof(struct_type); + + // Check that the buffer contains the expected data. + if (Base + Size > Buffer.size()) { + Res = 0; + return; + } + + // Check whether we can return a direct pointer. + struct_type *Ptr = (struct_type *) (Buffer.data() + Base); + if (!MOO.isSwappedEndian()) { + Res = Ptr; + return; + } + + // Otherwise, copy the struct and translate the values. + Res = *Ptr; + SwapStruct(*Res); +} + +/* *** */ + +MachOObject::MachOObject(MemoryBuffer *Buffer_, bool IsLittleEndian_, + bool Is64Bit_) + : Buffer(Buffer_), IsLittleEndian(IsLittleEndian_), Is64Bit(Is64Bit_), + IsSwappedEndian(IsLittleEndian != sys::isLittleEndianHost()), + HasStringTable(false), LoadCommands(0), NumLoadedCommands(0) { + // Load the common header. + memcpy(&Header, Buffer->getBuffer().data(), sizeof(Header)); + if (IsSwappedEndian) { + SwapValue(Header.Magic); + SwapValue(Header.CPUType); + SwapValue(Header.CPUSubtype); + SwapValue(Header.FileType); + SwapValue(Header.NumLoadCommands); + SwapValue(Header.SizeOfLoadCommands); + SwapValue(Header.Flags); + } + + if (is64Bit()) { + memcpy(&Header64Ext, Buffer->getBuffer().data() + sizeof(Header), + sizeof(Header64Ext)); + if (IsSwappedEndian) { + SwapValue(Header64Ext.Reserved); + } + } + + // Create the load command array if sane. + if (getHeader().NumLoadCommands < (1 << 20)) + LoadCommands = new LoadCommandInfo[getHeader().NumLoadCommands]; +} + +MachOObject::~MachOObject() { + delete [] LoadCommands; +} + +MachOObject *MachOObject::LoadFromBuffer(MemoryBuffer *Buffer, + std::string *ErrorStr) { + // First, check the magic value and initialize the basic object info. + bool IsLittleEndian = false, Is64Bit = false; + StringRef Magic = Buffer->getBuffer().slice(0, 4); + if (Magic == "\xFE\xED\xFA\xCE") { + } else if (Magic == "\xCE\xFA\xED\xFE") { + IsLittleEndian = true; + } else if (Magic == "\xFE\xED\xFA\xCF") { + Is64Bit = true; + } else if (Magic == "\xCF\xFA\xED\xFE") { + IsLittleEndian = true; + Is64Bit = true; + } else { + if (ErrorStr) *ErrorStr = "not a Mach object file (invalid magic)"; + return 0; + } + + // Ensure that the at least the full header is present. + unsigned HeaderSize = Is64Bit ? macho::Header64Size : macho::Header32Size; + if (Buffer->getBufferSize() < HeaderSize) { + if (ErrorStr) *ErrorStr = "not a Mach object file (invalid header)"; + return 0; + } + + OwningPtr Object(new MachOObject(Buffer, IsLittleEndian, + Is64Bit)); + + // Check for bogus number of load commands. + if (Object->getHeader().NumLoadCommands >= (1 << 20)) { + if (ErrorStr) *ErrorStr = "not a Mach object file (unreasonable header)"; + return 0; + } + + if (ErrorStr) *ErrorStr = ""; + return Object.take(); +} + +StringRef MachOObject::getData(size_t Offset, size_t Size) const { + return Buffer->getBuffer().substr(Offset,Size); +} + +void MachOObject::RegisterStringTable(macho::SymtabLoadCommand &SLC) { + HasStringTable = true; + StringTable = Buffer->getBuffer().substr(SLC.StringTableOffset, + SLC.StringTableSize); +} + +const MachOObject::LoadCommandInfo & +MachOObject::getLoadCommandInfo(unsigned Index) const { + assert(Index < getHeader().NumLoadCommands && "Invalid index!"); + + // Load the command, if necessary. + if (Index >= NumLoadedCommands) { + uint64_t Offset; + if (Index == 0) { + Offset = getHeaderSize(); + } else { + const LoadCommandInfo &Prev = getLoadCommandInfo(Index - 1); + Offset = Prev.Offset + Prev.Command.Size; + } + + LoadCommandInfo &Info = LoadCommands[Index]; + memcpy(&Info.Command, Buffer->getBuffer().data() + Offset, + sizeof(macho::LoadCommand)); + if (IsSwappedEndian) { + SwapValue(Info.Command.Type); + SwapValue(Info.Command.Size); + } + Info.Offset = Offset; + NumLoadedCommands = Index + 1; + } + + return LoadCommands[Index]; +} + +template<> +void SwapStruct(macho::SegmentLoadCommand &Value) { + SwapValue(Value.Type); + SwapValue(Value.Size); + SwapValue(Value.VMAddress); + SwapValue(Value.VMSize); + SwapValue(Value.FileOffset); + SwapValue(Value.FileSize); + SwapValue(Value.MaxVMProtection); + SwapValue(Value.InitialVMProtection); + SwapValue(Value.NumSections); + SwapValue(Value.Flags); +} +void MachOObject::ReadSegmentLoadCommand(const LoadCommandInfo &LCI, + InMemoryStruct &Res) const { + ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res); +} + +template<> +void SwapStruct(macho::Segment64LoadCommand &Value) { + SwapValue(Value.Type); + SwapValue(Value.Size); + SwapValue(Value.VMAddress); + SwapValue(Value.VMSize); + SwapValue(Value.FileOffset); + SwapValue(Value.FileSize); + SwapValue(Value.MaxVMProtection); + SwapValue(Value.InitialVMProtection); + SwapValue(Value.NumSections); + SwapValue(Value.Flags); +} +void MachOObject::ReadSegment64LoadCommand(const LoadCommandInfo &LCI, + InMemoryStruct &Res) const { + ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res); +} + +template<> +void SwapStruct(macho::SymtabLoadCommand &Value) { + SwapValue(Value.Type); + SwapValue(Value.Size); + SwapValue(Value.SymbolTableOffset); + SwapValue(Value.NumSymbolTableEntries); + SwapValue(Value.StringTableOffset); + SwapValue(Value.StringTableSize); +} +void MachOObject::ReadSymtabLoadCommand(const LoadCommandInfo &LCI, + InMemoryStruct &Res) const { + ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res); +} + +template<> +void SwapStruct(macho::DysymtabLoadCommand &Value) { + SwapValue(Value.Type); + SwapValue(Value.Size); + SwapValue(Value.LocalSymbolsIndex); + SwapValue(Value.NumLocalSymbols); + SwapValue(Value.ExternalSymbolsIndex); + SwapValue(Value.NumExternalSymbols); + SwapValue(Value.UndefinedSymbolsIndex); + SwapValue(Value.NumUndefinedSymbols); + SwapValue(Value.TOCOffset); + SwapValue(Value.NumTOCEntries); + SwapValue(Value.ModuleTableOffset); + SwapValue(Value.NumModuleTableEntries); + SwapValue(Value.ReferenceSymbolTableOffset); + SwapValue(Value.NumReferencedSymbolTableEntries); + SwapValue(Value.IndirectSymbolTableOffset); + SwapValue(Value.NumIndirectSymbolTableEntries); + SwapValue(Value.ExternalRelocationTableOffset); + SwapValue(Value.NumExternalRelocationTableEntries); + SwapValue(Value.LocalRelocationTableOffset); + SwapValue(Value.NumLocalRelocationTableEntries); +} +void MachOObject::ReadDysymtabLoadCommand(const LoadCommandInfo &LCI, + InMemoryStruct &Res) const { + ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res); +} + +template<> +void SwapStruct(macho::IndirectSymbolTableEntry &Value) { + SwapValue(Value.Index); +} +void +MachOObject::ReadIndirectSymbolTableEntry(const macho::DysymtabLoadCommand &DLC, + unsigned Index, + InMemoryStruct &Res) const { + uint64_t Offset = (DLC.IndirectSymbolTableOffset + + Index * sizeof(macho::IndirectSymbolTableEntry)); + ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res); +} + + +template<> +void SwapStruct(macho::Section &Value) { + SwapValue(Value.Address); + SwapValue(Value.Size); + SwapValue(Value.Offset); + SwapValue(Value.Align); + SwapValue(Value.RelocationTableOffset); + SwapValue(Value.NumRelocationTableEntries); + SwapValue(Value.Flags); + SwapValue(Value.Reserved1); + SwapValue(Value.Reserved2); +} +void MachOObject::ReadSection(const LoadCommandInfo &LCI, + unsigned Index, + InMemoryStruct &Res) const { + assert(LCI.Command.Type == macho::LCT_Segment && + "Unexpected load command info!"); + uint64_t Offset = (LCI.Offset + sizeof(macho::SegmentLoadCommand) + + Index * sizeof(macho::Section)); + ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res); +} + +template<> +void SwapStruct(macho::Section64 &Value) { + SwapValue(Value.Address); + SwapValue(Value.Size); + SwapValue(Value.Offset); + SwapValue(Value.Align); + SwapValue(Value.RelocationTableOffset); + SwapValue(Value.NumRelocationTableEntries); + SwapValue(Value.Flags); + SwapValue(Value.Reserved1); + SwapValue(Value.Reserved2); + SwapValue(Value.Reserved3); +} +void MachOObject::ReadSection64(const LoadCommandInfo &LCI, + unsigned Index, + InMemoryStruct &Res) const { + assert(LCI.Command.Type == macho::LCT_Segment64 && + "Unexpected load command info!"); + uint64_t Offset = (LCI.Offset + sizeof(macho::Segment64LoadCommand) + + Index * sizeof(macho::Section64)); + ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res); +} + +template<> +void SwapStruct(macho::RelocationEntry &Value) { + SwapValue(Value.Word0); + SwapValue(Value.Word1); +} +void MachOObject::ReadRelocationEntry(uint64_t RelocationTableOffset, + unsigned Index, + InMemoryStruct &Res) const { + uint64_t Offset = (RelocationTableOffset + + Index * sizeof(macho::RelocationEntry)); + ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res); +} + +template<> +void SwapStruct(macho::SymbolTableEntry &Value) { + SwapValue(Value.StringIndex); + SwapValue(Value.Flags); + SwapValue(Value.Value); +} +void MachOObject::ReadSymbolTableEntry(uint64_t SymbolTableOffset, + unsigned Index, + InMemoryStruct &Res) const { + uint64_t Offset = (SymbolTableOffset + + Index * sizeof(macho::SymbolTableEntry)); + ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res); +} + +template<> +void SwapStruct(macho::Symbol64TableEntry &Value) { + SwapValue(Value.StringIndex); + SwapValue(Value.Flags); + SwapValue(Value.Value); +} +void MachOObject::ReadSymbol64TableEntry(uint64_t SymbolTableOffset, + unsigned Index, + InMemoryStruct &Res) const { + uint64_t Offset = (SymbolTableOffset + + Index * sizeof(macho::Symbol64TableEntry)); + ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res); +} diff --git a/lib/Object/Makefile b/lib/Object/Makefile new file mode 100644 index 000000000000..79388dc97f1a --- /dev/null +++ b/lib/Object/Makefile @@ -0,0 +1,14 @@ +##===- lib/Object/Makefile ---------------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../.. +LIBRARYNAME = LLVMObject +BUILD_ARCHIVE := 1 + +include $(LEVEL)/Makefile.common diff --git a/lib/Object/ObjectFile.cpp b/lib/Object/ObjectFile.cpp new file mode 100644 index 000000000000..161ae3a083f1 --- /dev/null +++ b/lib/Object/ObjectFile.cpp @@ -0,0 +1,71 @@ +//===- ObjectFile.cpp - File format independent object file -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a file format independent ObjectFile class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/ObjectFile.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/system_error.h" + +using namespace llvm; +using namespace object; + +ObjectFile::ObjectFile(MemoryBuffer *Object) + : MapFile(Object) { + assert(MapFile && "Must be a valid MemoryBuffer!"); + base = reinterpret_cast(MapFile->getBufferStart()); +} + +ObjectFile::~ObjectFile() { + delete MapFile; +} + +StringRef ObjectFile::getFilename() const { + return MapFile->getBufferIdentifier(); +} + +ObjectFile *ObjectFile::createObjectFile(MemoryBuffer *Object) { + if (!Object || Object->getBufferSize() < 64) + return 0; + sys::LLVMFileType type = sys::IdentifyFileType(Object->getBufferStart(), + static_cast(Object->getBufferSize())); + switch (type) { + case sys::ELF_Relocatable_FileType: + case sys::ELF_Executable_FileType: + case sys::ELF_SharedObject_FileType: + case sys::ELF_Core_FileType: + return createELFObjectFile(Object); + case sys::Mach_O_Object_FileType: + case sys::Mach_O_Executable_FileType: + case sys::Mach_O_FixedVirtualMemorySharedLib_FileType: + case sys::Mach_O_Core_FileType: + case sys::Mach_O_PreloadExecutable_FileType: + case sys::Mach_O_DynamicallyLinkedSharedLib_FileType: + case sys::Mach_O_DynamicLinker_FileType: + case sys::Mach_O_Bundle_FileType: + case sys::Mach_O_DynamicallyLinkedSharedLibStub_FileType: + return 0; + case sys::COFF_FileType: + return createCOFFObjectFile(Object); + default: + llvm_unreachable("Unknown Object File Type"); + } +} + +ObjectFile *ObjectFile::createObjectFile(StringRef ObjectPath) { + OwningPtr File; + if (error_code ec = MemoryBuffer::getFile(ObjectPath, File)) + return NULL; + return createObjectFile(File.take()); +} diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp index b87ddf9c95b5..e765ba0a27bb 100644 --- a/lib/Support/APFloat.cpp +++ b/lib/Support/APFloat.cpp @@ -175,7 +175,7 @@ totalExponent(StringRef::iterator p, StringRef::iterator end, { int unsignedExponent; bool negative, overflow; - int exponent; + int exponent = 0; assert(p != end && "Exponent has no digits"); @@ -194,11 +194,11 @@ totalExponent(StringRef::iterator p, StringRef::iterator end, assert(value < 10U && "Invalid character in exponent"); unsignedExponent = unsignedExponent * 10 + value; - if (unsignedExponent > 65535) + if (unsignedExponent > 32767) overflow = true; } - if (exponentAdjustment > 65535 || exponentAdjustment < -65536) + if (exponentAdjustment > 32767 || exponentAdjustment < -32768) overflow = true; if (!overflow) { @@ -206,12 +206,12 @@ totalExponent(StringRef::iterator p, StringRef::iterator end, if (negative) exponent = -exponent; exponent += exponentAdjustment; - if (exponent > 65535 || exponent < -65536) + if (exponent > 32767 || exponent < -32768) overflow = true; } if (overflow) - exponent = negative ? -65536: 65535; + exponent = negative ? -32768: 32767; return exponent; } @@ -3197,6 +3197,12 @@ APFloat::initFromAPInt(const APInt& api, bool isIEEE) llvm_unreachable(0); } +APFloat +APFloat::getAllOnesValue(unsigned BitWidth, bool isIEEE) +{ + return APFloat(APInt::getAllOnesValue(BitWidth), isIEEE); +} + APFloat APFloat::getLargest(const fltSemantics &Sem, bool Negative) { APFloat Val(Sem, fcNormal, Negative); @@ -3258,14 +3264,12 @@ APFloat::APFloat(const APInt& api, bool isIEEE) APFloat::APFloat(float f) { - APInt api = APInt(32, 0); - initFromAPInt(api.floatToBits(f)); + initFromAPInt(APInt::floatToBits(f)); } APFloat::APFloat(double d) { - APInt api = APInt(64, 0); - initFromAPInt(api.doubleToBits(d)); + initFromAPInt(APInt::doubleToBits(d)); } namespace { @@ -3312,7 +3316,7 @@ namespace { // Truncate the significand down to its active bit count, but // don't try to drop below 32. unsigned newPrecision = std::max(32U, significand.getActiveBits()); - significand.trunc(newPrecision); + significand = significand.trunc(newPrecision); } @@ -3417,7 +3421,7 @@ void APFloat::toString(SmallVectorImpl &Str, // Nothing to do. } else if (exp > 0) { // Just shift left. - significand.zext(semantics->precision + exp); + significand = significand.zext(semantics->precision + exp); significand <<= exp; exp = 0; } else { /* exp < 0 */ @@ -3436,7 +3440,7 @@ void APFloat::toString(SmallVectorImpl &Str, // Multiply significand by 5^e. // N * 5^0101 == N * 5^(1*1) * 5^(0*2) * 5^(1*4) * 5^(0*8) - significand.zext(precision); + significand = significand.zext(precision); APInt five_to_the_i(precision, 5); while (true) { if (texp & 1) significand *= five_to_the_i; diff --git a/lib/Support/APInt.cpp b/lib/Support/APInt.cpp index 8a212a291f24..77033428b577 100644 --- a/lib/Support/APInt.cpp +++ b/lib/Support/APInt.cpp @@ -361,7 +361,7 @@ APInt& APInt::operator*=(const APInt& RHS) { unsigned rhsWords = !rhsBits ? 0 : whichWord(rhsBits - 1) + 1; if (!rhsWords) { // X * 0 ===> 0 - clear(); + clearAllBits(); return *this; } @@ -373,7 +373,7 @@ APInt& APInt::operator*=(const APInt& RHS) { mul(dest, pVal, lhsWords, RHS.pVal, rhsWords); // Copy result back into *this - clear(); + clearAllBits(); unsigned wordsToCopy = destWords >= getNumWords() ? getNumWords() : destWords; memcpy(pVal, dest, wordsToCopy * APINT_WORD_SIZE); @@ -483,6 +483,7 @@ APInt APInt::operator-(const APInt& RHS) const { } bool APInt::operator[](unsigned bitPosition) const { + assert(bitPosition < getBitWidth() && "Bit position out of bounds!"); return (maskBit(bitPosition) & (isSingleWord() ? VAL : pVal[whichWord(bitPosition)])) != 0; } @@ -561,12 +562,12 @@ bool APInt::slt(const APInt& RHS) const { bool rhsNeg = rhs.isNegative(); if (lhsNeg) { // Sign bit is set so perform two's complement to make it positive - lhs.flip(); + lhs.flipAllBits(); lhs++; } if (rhsNeg) { // Sign bit is set so perform two's complement to make it positive - rhs.flip(); + rhs.flipAllBits(); rhs++; } @@ -583,22 +584,20 @@ bool APInt::slt(const APInt& RHS) const { return lhs.ult(rhs); } -APInt& APInt::set(unsigned bitPosition) { +void APInt::setBit(unsigned bitPosition) { if (isSingleWord()) VAL |= maskBit(bitPosition); else pVal[whichWord(bitPosition)] |= maskBit(bitPosition); - return *this; } /// Set the given bit to 0 whose position is given as "bitPosition". /// @brief Set a given bit to 0. -APInt& APInt::clear(unsigned bitPosition) { +void APInt::clearBit(unsigned bitPosition) { if (isSingleWord()) VAL &= ~maskBit(bitPosition); else pVal[whichWord(bitPosition)] &= ~maskBit(bitPosition); - return *this; } /// @brief Toggle every bit to its opposite value. @@ -606,11 +605,10 @@ APInt& APInt::clear(unsigned bitPosition) { /// Toggle a given bit to its opposite value whose position is given /// as "bitPosition". /// @brief Toggles a given bit to its opposite value. -APInt& APInt::flip(unsigned bitPosition) { +void APInt::flipBit(unsigned bitPosition) { assert(bitPosition < BitWidth && "Out of the bit-width range!"); - if ((*this)[bitPosition]) clear(bitPosition); - else set(bitPosition); - return *this; + if ((*this)[bitPosition]) clearBit(bitPosition); + else setBit(bitPosition); } unsigned APInt::getBitsNeeded(StringRef str, uint8_t radix) { @@ -761,10 +759,6 @@ APInt APInt::getLoBits(unsigned numBits) const { BitWidth - numBits); } -bool APInt::isPowerOf2() const { - return (!!*this) && !(*this & (*this - APInt(BitWidth,1))); -} - unsigned APInt::countLeadingZerosSlowCase() const { // Treat the most significand word differently because it might have // meaningless bits set beyond the precision. @@ -1001,96 +995,90 @@ double APInt::roundToDouble(bool isSigned) const { } // Truncate to new width. -APInt &APInt::trunc(unsigned width) { +APInt APInt::trunc(unsigned width) const { assert(width < BitWidth && "Invalid APInt Truncate request"); assert(width && "Can't truncate to 0 bits"); - unsigned wordsBefore = getNumWords(); - BitWidth = width; - unsigned wordsAfter = getNumWords(); - if (wordsBefore != wordsAfter) { - if (wordsAfter == 1) { - uint64_t *tmp = pVal; - VAL = pVal[0]; - delete [] tmp; - } else { - uint64_t *newVal = getClearedMemory(wordsAfter); - for (unsigned i = 0; i < wordsAfter; ++i) - newVal[i] = pVal[i]; - delete [] pVal; - pVal = newVal; - } - } - return clearUnusedBits(); + + if (width <= APINT_BITS_PER_WORD) + return APInt(width, getRawData()[0]); + + APInt Result(getMemory(getNumWords(width)), width); + + // Copy full words. + unsigned i; + for (i = 0; i != width / APINT_BITS_PER_WORD; i++) + Result.pVal[i] = pVal[i]; + + // Truncate and copy any partial word. + unsigned bits = (0 - width) % APINT_BITS_PER_WORD; + if (bits != 0) + Result.pVal[i] = pVal[i] << bits >> bits; + + return Result; } // Sign extend to a new width. -APInt &APInt::sext(unsigned width) { +APInt APInt::sext(unsigned width) const { assert(width > BitWidth && "Invalid APInt SignExtend request"); - // If the sign bit isn't set, this is the same as zext. - if (!isNegative()) { - zext(width); - return *this; + + if (width <= APINT_BITS_PER_WORD) { + uint64_t val = VAL << (APINT_BITS_PER_WORD - BitWidth); + val = (int64_t)val >> (width - BitWidth); + return APInt(width, val >> (APINT_BITS_PER_WORD - width)); } - // The sign bit is set. First, get some facts - unsigned wordsBefore = getNumWords(); - unsigned wordBits = BitWidth % APINT_BITS_PER_WORD; - BitWidth = width; - unsigned wordsAfter = getNumWords(); - - // Mask the high order word appropriately - if (wordsBefore == wordsAfter) { - unsigned newWordBits = width % APINT_BITS_PER_WORD; - // The extension is contained to the wordsBefore-1th word. - uint64_t mask = ~0ULL; - if (newWordBits) - mask >>= APINT_BITS_PER_WORD - newWordBits; - mask <<= wordBits; - if (wordsBefore == 1) - VAL |= mask; - else - pVal[wordsBefore-1] |= mask; - return clearUnusedBits(); + APInt Result(getMemory(getNumWords(width)), width); + + // Copy full words. + unsigned i; + uint64_t word = 0; + for (i = 0; i != BitWidth / APINT_BITS_PER_WORD; i++) { + word = getRawData()[i]; + Result.pVal[i] = word; } - uint64_t mask = wordBits == 0 ? 0 : ~0ULL << wordBits; - uint64_t *newVal = getMemory(wordsAfter); - if (wordsBefore == 1) - newVal[0] = VAL | mask; - else { - for (unsigned i = 0; i < wordsBefore; ++i) - newVal[i] = pVal[i]; - newVal[wordsBefore-1] |= mask; + // Read and sign-extend any partial word. + unsigned bits = (0 - BitWidth) % APINT_BITS_PER_WORD; + if (bits != 0) + word = (int64_t)getRawData()[i] << bits >> bits; + else + word = (int64_t)word >> (APINT_BITS_PER_WORD - 1); + + // Write remaining full words. + for (; i != width / APINT_BITS_PER_WORD; i++) { + Result.pVal[i] = word; + word = (int64_t)word >> (APINT_BITS_PER_WORD - 1); } - for (unsigned i = wordsBefore; i < wordsAfter; i++) - newVal[i] = -1ULL; - if (wordsBefore != 1) - delete [] pVal; - pVal = newVal; - return clearUnusedBits(); + + // Write any partial word. + bits = (0 - width) % APINT_BITS_PER_WORD; + if (bits != 0) + Result.pVal[i] = word << bits >> bits; + + return Result; } // Zero extend to a new width. -APInt &APInt::zext(unsigned width) { +APInt APInt::zext(unsigned width) const { assert(width > BitWidth && "Invalid APInt ZeroExtend request"); - unsigned wordsBefore = getNumWords(); - BitWidth = width; - unsigned wordsAfter = getNumWords(); - if (wordsBefore != wordsAfter) { - uint64_t *newVal = getClearedMemory(wordsAfter); - if (wordsBefore == 1) - newVal[0] = VAL; - else - for (unsigned i = 0; i < wordsBefore; ++i) - newVal[i] = pVal[i]; - if (wordsBefore != 1) - delete [] pVal; - pVal = newVal; - } - return *this; + + if (width <= APINT_BITS_PER_WORD) + return APInt(width, VAL); + + APInt Result(getMemory(getNumWords(width)), width); + + // Copy words. + unsigned i; + for (i = 0; i != getNumWords(); i++) + Result.pVal[i] = getRawData()[i]; + + // Zero remaining words. + memset(&Result.pVal[i], 0, (Result.getNumWords() - i) * APINT_WORD_SIZE); + + return Result; } -APInt &APInt::zextOrTrunc(unsigned width) { +APInt APInt::zextOrTrunc(unsigned width) const { if (BitWidth < width) return zext(width); if (BitWidth > width) @@ -1098,7 +1086,7 @@ APInt &APInt::zextOrTrunc(unsigned width) { return *this; } -APInt &APInt::sextOrTrunc(unsigned width) { +APInt APInt::sextOrTrunc(unsigned width) const { if (BitWidth < width) return sext(width); if (BitWidth > width) @@ -1873,7 +1861,7 @@ void APInt::divide(const APInt LHS, unsigned lhsWords, if (!Quotient->isSingleWord()) Quotient->pVal = getClearedMemory(Quotient->getNumWords()); } else - Quotient->clear(); + Quotient->clearAllBits(); // The quotient is in Q. Reconstitute the quotient into Quotient's low // order words. @@ -1904,7 +1892,7 @@ void APInt::divide(const APInt LHS, unsigned lhsWords, if (!Remainder->isSingleWord()) Remainder->pVal = getClearedMemory(Remainder->getNumWords()); } else - Remainder->clear(); + Remainder->clearAllBits(); // The remainder is in R. Reconstitute the remainder into Remainder's low // order words. @@ -2046,6 +2034,64 @@ void APInt::udivrem(const APInt &LHS, const APInt &RHS, divide(LHS, lhsWords, RHS, rhsWords, &Quotient, &Remainder); } +APInt APInt::sadd_ov(const APInt &RHS, bool &Overflow) const { + APInt Res = *this+RHS; + Overflow = isNonNegative() == RHS.isNonNegative() && + Res.isNonNegative() != isNonNegative(); + return Res; +} + +APInt APInt::uadd_ov(const APInt &RHS, bool &Overflow) const { + APInt Res = *this+RHS; + Overflow = Res.ult(RHS); + return Res; +} + +APInt APInt::ssub_ov(const APInt &RHS, bool &Overflow) const { + APInt Res = *this - RHS; + Overflow = isNonNegative() != RHS.isNonNegative() && + Res.isNonNegative() != isNonNegative(); + return Res; +} + +APInt APInt::usub_ov(const APInt &RHS, bool &Overflow) const { + APInt Res = *this-RHS; + Overflow = Res.ugt(*this); + return Res; +} + +APInt APInt::sdiv_ov(const APInt &RHS, bool &Overflow) const { + // MININT/-1 --> overflow. + Overflow = isMinSignedValue() && RHS.isAllOnesValue(); + return sdiv(RHS); +} + +APInt APInt::smul_ov(const APInt &RHS, bool &Overflow) const { + APInt Res = *this * RHS; + + if (*this != 0 && RHS != 0) + Overflow = Res.sdiv(RHS) != *this || Res.sdiv(*this) != RHS; + else + Overflow = false; + return Res; +} + +APInt APInt::sshl_ov(unsigned ShAmt, bool &Overflow) const { + Overflow = ShAmt >= getBitWidth(); + if (Overflow) + ShAmt = getBitWidth()-1; + + if (isNonNegative()) // Don't allow sign change. + Overflow = ShAmt >= countLeadingZeros(); + else + Overflow = ShAmt >= countLeadingOnes(); + + return *this << ShAmt; +} + + + + void APInt::fromString(unsigned numbits, StringRef str, uint8_t radix) { // Check our assumptions here assert(!str.empty() && "Invalid string length"); @@ -2101,7 +2147,7 @@ void APInt::fromString(unsigned numbits, StringRef str, uint8_t radix) { // If its negative, put it in two's complement form if (isNeg) { (*this)--; - this->flip(); + this->flipAllBits(); } } @@ -2149,7 +2195,7 @@ void APInt::toString(SmallVectorImpl &Str, unsigned Radix, // They want to print the signed version and it is a negative value // Flip the bits and add one to turn it into the equivalent positive // value and put a '-' in the result. - Tmp.flip(); + Tmp.flipAllBits(); Tmp++; Str.push_back('-'); } diff --git a/lib/Support/Allocator.cpp b/lib/Support/Allocator.cpp index 90df262336c5..5e27df6628eb 100644 --- a/lib/Support/Allocator.cpp +++ b/lib/Support/Allocator.cpp @@ -12,10 +12,10 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Allocator.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/Support/Recycler.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Memory.h" +#include "llvm/Support/Memory.h" #include namespace llvm { @@ -44,6 +44,12 @@ char *BumpPtrAllocator::AlignPtr(char *Ptr, size_t Alignment) { /// StartNewSlab - Allocate a new slab and move the bump pointers over into /// the new slab. Modifies CurPtr and End. void BumpPtrAllocator::StartNewSlab() { + // If we allocated a big number of slabs already it's likely that we're going + // to allocate more. Increase slab size to reduce mallocs and possibly memory + // overhead. The factors are chosen conservatively to avoid overallocation. + if (BytesAllocated >= SlabSize * 128) + SlabSize *= 2; + MemSlab *NewSlab = Allocator.Allocate(SlabSize); NewSlab->NextPtr = CurSlab; CurSlab = NewSlab; diff --git a/lib/Support/Atomic.cpp b/lib/Support/Atomic.cpp new file mode 100644 index 000000000000..c7b4bff27948 --- /dev/null +++ b/lib/Support/Atomic.cpp @@ -0,0 +1,112 @@ +//===-- Atomic.cpp - Atomic Operations --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header file implements atomic operations. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Atomic.h" +#include "llvm/Config/config.h" + +using namespace llvm; + +#if defined(_MSC_VER) +#include +#undef MemoryFence +#endif + +void sys::MemoryFence() { +#if LLVM_MULTITHREADED==0 + return; +#else +# if defined(__GNUC__) + __sync_synchronize(); +# elif defined(_MSC_VER) + MemoryBarrier(); +# else +# error No memory fence implementation for your platform! +# endif +#endif +} + +sys::cas_flag sys::CompareAndSwap(volatile sys::cas_flag* ptr, + sys::cas_flag new_value, + sys::cas_flag old_value) { +#if LLVM_MULTITHREADED==0 + sys::cas_flag result = *ptr; + if (result == old_value) + *ptr = new_value; + return result; +#elif defined(__GNUC__) + return __sync_val_compare_and_swap(ptr, old_value, new_value); +#elif defined(_MSC_VER) + return InterlockedCompareExchange(ptr, new_value, old_value); +#else +# error No compare-and-swap implementation for your platform! +#endif +} + +sys::cas_flag sys::AtomicIncrement(volatile sys::cas_flag* ptr) { +#if LLVM_MULTITHREADED==0 + ++(*ptr); + return *ptr; +#elif defined(__GNUC__) + return __sync_add_and_fetch(ptr, 1); +#elif defined(_MSC_VER) + return InterlockedIncrement(ptr); +#else +# error No atomic increment implementation for your platform! +#endif +} + +sys::cas_flag sys::AtomicDecrement(volatile sys::cas_flag* ptr) { +#if LLVM_MULTITHREADED==0 + --(*ptr); + return *ptr; +#elif defined(__GNUC__) + return __sync_sub_and_fetch(ptr, 1); +#elif defined(_MSC_VER) + return InterlockedDecrement(ptr); +#else +# error No atomic decrement implementation for your platform! +#endif +} + +sys::cas_flag sys::AtomicAdd(volatile sys::cas_flag* ptr, sys::cas_flag val) { +#if LLVM_MULTITHREADED==0 + *ptr += val; + return *ptr; +#elif defined(__GNUC__) + return __sync_add_and_fetch(ptr, val); +#elif defined(_MSC_VER) + return InterlockedExchangeAdd(ptr, val) + val; +#else +# error No atomic add implementation for your platform! +#endif +} + +sys::cas_flag sys::AtomicMul(volatile sys::cas_flag* ptr, sys::cas_flag val) { + sys::cas_flag original, result; + do { + original = *ptr; + result = original * val; + } while (sys::CompareAndSwap(ptr, result, original) != original); + + return result; +} + +sys::cas_flag sys::AtomicDiv(volatile sys::cas_flag* ptr, sys::cas_flag val) { + sys::cas_flag original, result; + do { + original = *ptr; + result = original / val; + } while (sys::CompareAndSwap(ptr, result, original) != original); + + return result; +} diff --git a/lib/Support/CMakeLists.txt b/lib/Support/CMakeLists.txt index 0c70a402654e..a0e997d349f9 100644 --- a/lib/Support/CMakeLists.txt +++ b/lib/Support/CMakeLists.txt @@ -1,3 +1,9 @@ +## FIXME: This only requires RTTI because tblgen uses it. Fix that. +set(LLVM_REQUIRES_RTTI 1) +if( MINGW ) + set(LLVM_REQUIRES_EH 1) +endif() + add_llvm_library(LLVMSupport APFloat.cpp APInt.cpp @@ -16,6 +22,8 @@ add_llvm_library(LLVMSupport FoldingSet.cpp FormattedStream.cpp GraphWriter.cpp + IntEqClasses.cpp + IntervalMap.cpp IsInf.cpp IsNAN.cpp ManagedStatic.cpp @@ -35,6 +43,7 @@ add_llvm_library(LLVMSupport SystemUtils.cpp TargetRegistry.cpp Timer.cpp + ToolOutputFile.cpp Triple.cpp Twine.cpp raw_os_ostream.cpp @@ -44,6 +53,51 @@ add_llvm_library(LLVMSupport regexec.c regfree.c regstrlcpy.c - ) -target_link_libraries (LLVMSupport LLVMSystem) +# System + Atomic.cpp + Disassembler.cpp + DynamicLibrary.cpp + Errno.cpp + Host.cpp + IncludeFile.cpp + Memory.cpp + Mutex.cpp + Path.cpp + PathV2.cpp + Process.cpp + Program.cpp + RWMutex.cpp + SearchForAddressOfSpecialSymbol.cpp + Signals.cpp + system_error.cpp + ThreadLocal.cpp + Threading.cpp + TimeValue.cpp + Valgrind.cpp + Unix/Host.inc + Unix/Memory.inc + Unix/Mutex.inc + Unix/Path.inc + Unix/PathV2.inc + Unix/Process.inc + Unix/Program.inc + Unix/RWMutex.inc + Unix/Signals.inc + Unix/system_error.inc + Unix/ThreadLocal.inc + Unix/TimeValue.inc + Windows/DynamicLibrary.inc + Windows/Host.inc + Windows/Memory.inc + Windows/Mutex.inc + Windows/Path.inc + Windows/PathV2.inc + Windows/Process.inc + Windows/Program.inc + Windows/RWMutex.inc + Windows/Signals.inc + Windows/system_error.inc + Windows/ThreadLocal.inc + Windows/TimeValue.inc + ) diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp index ae66110ded61..7e744993a7cb 100644 --- a/lib/Support/CommandLine.cpp +++ b/lib/Support/CommandLine.cpp @@ -22,9 +22,10 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" #include "llvm/Target/TargetRegistry.h" -#include "llvm/System/Host.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/Path.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" @@ -179,6 +180,45 @@ static Option *LookupOption(StringRef &Arg, StringRef &Value, return I->second; } +/// LookupNearestOption - Lookup the closest match to the option specified by +/// the specified option on the command line. If there is a value specified +/// (after an equal sign) return that as well. This assumes that leading dashes +/// have already been stripped. +static Option *LookupNearestOption(StringRef Arg, + const StringMap &OptionsMap, + const char *&NearestString) { + // Reject all dashes. + if (Arg.empty()) return 0; + + // Split on any equal sign. + StringRef LHS = Arg.split('=').first; + + // Find the closest match. + Option *Best = 0; + unsigned BestDistance = 0; + for (StringMap::const_iterator it = OptionsMap.begin(), + ie = OptionsMap.end(); it != ie; ++it) { + Option *O = it->second; + SmallVector OptionNames; + O->getExtraOptionNames(OptionNames); + if (O->ArgStr[0]) + OptionNames.push_back(O->ArgStr); + + for (size_t i = 0, e = OptionNames.size(); i != e; ++i) { + StringRef Name = OptionNames[i]; + unsigned Distance = StringRef(Name).edit_distance( + Arg, /*AllowReplacements=*/true, /*MaxEditDistance=*/BestDistance); + if (!Best || Distance < BestDistance) { + Best = O; + NearestString = OptionNames[i]; + BestDistance = Distance; + } + } + } + + return Best; +} + /// CommaSeparateAndAddOccurence - A wrapper around Handler->addOccurence() that /// does special handling of cl::CommaSeparated options. static bool CommaSeparateAndAddOccurence(Option *Handler, unsigned pos, @@ -463,10 +503,6 @@ static void ExpandResponseFiles(unsigned argc, char** argv, const sys::FileStatus *FileStat = respFile.getFileStatus(); if (FileStat && FileStat->getSize() != 0) { - // Mmap the response file into memory. - OwningPtr - respFilePtr(MemoryBuffer::getFile(respFile.c_str())); - // If we could open the file, parse its contents, otherwise // pass the @file option verbatim. @@ -475,7 +511,9 @@ static void ExpandResponseFiles(unsigned argc, char** argv, // itself contain additional @file options; any such options will be // processed recursively.") - if (respFilePtr != 0) { + // Mmap the response file into memory. + OwningPtr respFilePtr; + if (!MemoryBuffer::getFile(respFile.c_str(), respFilePtr)) { ParseCStringVector(newArgv, respFilePtr->getBufferStart()); continue; } @@ -506,7 +544,7 @@ void cl::ParseCommandLineOptions(int argc, char **argv, } // Copy the program name into ProgName, making sure not to overflow it. - std::string ProgName = sys::Path(argv[0]).getLast(); + std::string ProgName = sys::path::filename(argv[0]); size_t Len = std::min(ProgName.size(), size_t(79)); memcpy(ProgramName, ProgName.data(), Len); ProgramName[Len] = '\0'; @@ -572,6 +610,8 @@ void cl::ParseCommandLineOptions(int argc, char **argv, bool DashDashFound = false; // Have we read '--'? for (int i = 1; i < argc; ++i) { Option *Handler = 0; + Option *NearestHandler = 0; + const char *NearestHandlerString = 0; StringRef Value; StringRef ArgName = ""; @@ -645,12 +685,25 @@ void cl::ParseCommandLineOptions(int argc, char **argv, if (Handler == 0) Handler = HandlePrefixedOrGroupedOption(ArgName, Value, ErrorParsing, Opts); + + // Otherwise, look for the closest available option to report to the user + // in the upcoming error. + if (Handler == 0 && SinkOpts.empty()) + NearestHandler = LookupNearestOption(ArgName, Opts, + NearestHandlerString); } if (Handler == 0) { if (SinkOpts.empty()) { errs() << ProgramName << ": Unknown command line argument '" << argv[i] << "'. Try: '" << argv[0] << " -help'\n"; + + if (NearestHandler) { + // If we know a near match, report it as well. + errs() << ProgramName << ": Did you mean '-" + << NearestHandlerString << "'?\n"; + } + ErrorParsing = true; } else { for (SmallVectorImpl::iterator I = SinkOpts.begin(), @@ -765,6 +818,15 @@ void cl::ParseCommandLineOptions(int argc, char **argv, } } + // Now that we know if -debug is specified, we can use it. + // Note that if ReadResponseFiles == true, this must be done before the + // memory allocated for the expanded command line is free()d below. + DEBUG(dbgs() << "Args: "; + for (int i = 0; i < argc; ++i) + dbgs() << argv[i] << ' '; + dbgs() << '\n'; + ); + // Free all of the memory allocated to the map. Command line options may only // be processed once! Opts.clear(); @@ -779,12 +841,6 @@ void cl::ParseCommandLineOptions(int argc, char **argv, free(*i); } - DEBUG(dbgs() << "Args: "; - for (int i = 0; i < argc; ++i) - dbgs() << argv[i] << ' '; - dbgs() << '\n'; - ); - // If we had an error processing our arguments, don't let the program execute if (ErrorParsing) exit(1); } diff --git a/lib/Support/ConstantRange.cpp b/lib/Support/ConstantRange.cpp index 8ef3785f5331..493f7083dbb3 100644 --- a/lib/Support/ConstantRange.cpp +++ b/lib/Support/ConstantRange.cpp @@ -51,6 +51,9 @@ ConstantRange::ConstantRange(const APInt &L, const APInt &U) : ConstantRange ConstantRange::makeICmpRegion(unsigned Pred, const ConstantRange &CR) { + if (CR.isEmptySet()) + return CR; + uint32_t W = CR.getBitWidth(); switch (Pred) { default: assert(!"Invalid ICmp predicate to makeICmpRegion()"); @@ -60,10 +63,18 @@ ConstantRange ConstantRange::makeICmpRegion(unsigned Pred, if (CR.isSingleElement()) return ConstantRange(CR.getUpper(), CR.getLower()); return ConstantRange(W); - case ICmpInst::ICMP_ULT: - return ConstantRange(APInt::getMinValue(W), CR.getUnsignedMax()); - case ICmpInst::ICMP_SLT: - return ConstantRange(APInt::getSignedMinValue(W), CR.getSignedMax()); + case ICmpInst::ICMP_ULT: { + APInt UMax(CR.getUnsignedMax()); + if (UMax.isMinValue()) + return ConstantRange(W, /* empty */ false); + return ConstantRange(APInt::getMinValue(W), UMax); + } + case ICmpInst::ICMP_SLT: { + APInt SMax(CR.getSignedMax()); + if (SMax.isMinSignedValue()) + return ConstantRange(W, /* empty */ false); + return ConstantRange(APInt::getSignedMinValue(W), SMax); + } case ICmpInst::ICMP_ULE: { APInt UMax(CR.getUnsignedMax()); if (UMax.isMaxValue()) @@ -72,15 +83,22 @@ ConstantRange ConstantRange::makeICmpRegion(unsigned Pred, } case ICmpInst::ICMP_SLE: { APInt SMax(CR.getSignedMax()); - if (SMax.isMaxSignedValue() || (SMax+1).isMaxSignedValue()) + if (SMax.isMaxSignedValue()) return ConstantRange(W); return ConstantRange(APInt::getSignedMinValue(W), SMax + 1); } - case ICmpInst::ICMP_UGT: - return ConstantRange(CR.getUnsignedMin() + 1, APInt::getNullValue(W)); - case ICmpInst::ICMP_SGT: - return ConstantRange(CR.getSignedMin() + 1, - APInt::getSignedMinValue(W)); + case ICmpInst::ICMP_UGT: { + APInt UMin(CR.getUnsignedMin()); + if (UMin.isMaxValue()) + return ConstantRange(W, /* empty */ false); + return ConstantRange(UMin + 1, APInt::getNullValue(W)); + } + case ICmpInst::ICMP_SGT: { + APInt SMin(CR.getSignedMin()); + if (SMin.isMaxSignedValue()) + return ConstantRange(W, /* empty */ false); + return ConstantRange(SMin + 1, APInt::getSignedMinValue(W)); + } case ICmpInst::ICMP_UGE: { APInt UMin(CR.getUnsignedMin()); if (UMin.isMinValue()) @@ -115,6 +133,14 @@ bool ConstantRange::isWrappedSet() const { return Lower.ugt(Upper); } +/// isSignWrappedSet - Return true if this set wraps around the INT_MIN of +/// its bitwidth, for example: i8 [120, 140). +/// +bool ConstantRange::isSignWrappedSet() const { + return contains(APInt::getSignedMaxValue(getBitWidth())) && + contains(APInt::getSignedMinValue(getBitWidth())); +} + /// getSetSize - Return the number of elements in this set. /// APInt ConstantRange::getSetSize() const { @@ -408,15 +434,15 @@ ConstantRange ConstantRange::unionWith(const ConstantRange &CR) const { /// correspond to the possible range of values as if the source range had been /// zero extended. ConstantRange ConstantRange::zeroExtend(uint32_t DstTySize) const { + if (isEmptySet()) return ConstantRange(DstTySize, /*isFullSet=*/false); + unsigned SrcTySize = getBitWidth(); assert(SrcTySize < DstTySize && "Not a value extension"); - if (isFullSet()) - // Change a source full set into [0, 1 << 8*numbytes) + if (isFullSet() || isWrappedSet()) + // Change into [0, 1 << src bit width) return ConstantRange(APInt(DstTySize,0), APInt(DstTySize,1).shl(SrcTySize)); - APInt L = Lower; L.zext(DstTySize); - APInt U = Upper; U.zext(DstTySize); - return ConstantRange(L, U); + return ConstantRange(Lower.zext(DstTySize), Upper.zext(DstTySize)); } /// signExtend - Return a new range in the specified integer type, which must @@ -424,16 +450,16 @@ ConstantRange ConstantRange::zeroExtend(uint32_t DstTySize) const { /// correspond to the possible range of values as if the source range had been /// sign extended. ConstantRange ConstantRange::signExtend(uint32_t DstTySize) const { + if (isEmptySet()) return ConstantRange(DstTySize, /*isFullSet=*/false); + unsigned SrcTySize = getBitWidth(); assert(SrcTySize < DstTySize && "Not a value extension"); - if (isFullSet()) { + if (isFullSet() || isSignWrappedSet()) { return ConstantRange(APInt::getHighBitsSet(DstTySize,DstTySize-SrcTySize+1), APInt::getLowBitsSet(DstTySize, SrcTySize-1) + 1); } - APInt L = Lower; L.sext(DstTySize); - APInt U = Upper; U.sext(DstTySize); - return ConstantRange(L, U); + return ConstantRange(Lower.sext(DstTySize), Upper.sext(DstTySize)); } /// truncate - Return a new range in the specified integer type, which must be @@ -447,9 +473,7 @@ ConstantRange ConstantRange::truncate(uint32_t DstTySize) const { if (isFullSet() || getSetSize().ugt(Size)) return ConstantRange(DstTySize, /*isFullSet=*/true); - APInt L = Lower; L.trunc(DstTySize); - APInt U = Upper; U.trunc(DstTySize); - return ConstantRange(L, U); + return ConstantRange(Lower.trunc(DstTySize), Upper.trunc(DstTySize)); } /// zextOrTrunc - make this range have the bit width given by \p DstTySize. The @@ -595,6 +619,32 @@ ConstantRange::udiv(const ConstantRange &RHS) const { return ConstantRange(Lower, Upper); } +ConstantRange +ConstantRange::binaryAnd(const ConstantRange &Other) const { + if (isEmptySet() || Other.isEmptySet()) + return ConstantRange(getBitWidth(), /*isFullSet=*/false); + + // TODO: replace this with something less conservative + + APInt umin = APIntOps::umin(Other.getUnsignedMax(), getUnsignedMax()); + if (umin.isAllOnesValue()) + return ConstantRange(getBitWidth(), /*isFullSet=*/true); + return ConstantRange(APInt::getNullValue(getBitWidth()), umin + 1); +} + +ConstantRange +ConstantRange::binaryOr(const ConstantRange &Other) const { + if (isEmptySet() || Other.isEmptySet()) + return ConstantRange(getBitWidth(), /*isFullSet=*/false); + + // TODO: replace this with something less conservative + + APInt umax = APIntOps::umax(getUnsignedMin(), Other.getUnsignedMin()); + if (umax.isMinValue()) + return ConstantRange(getBitWidth(), /*isFullSet=*/true); + return ConstantRange(umax, APInt::getNullValue(getBitWidth())); +} + ConstantRange ConstantRange::shl(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) diff --git a/lib/Support/CrashRecoveryContext.cpp b/lib/Support/CrashRecoveryContext.cpp index 49258ede83c1..bf8ca3f844b4 100644 --- a/lib/Support/CrashRecoveryContext.cpp +++ b/lib/Support/CrashRecoveryContext.cpp @@ -10,8 +10,8 @@ #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/ADT/SmallString.h" #include "llvm/Config/config.h" -#include "llvm/System/Mutex.h" -#include "llvm/System/ThreadLocal.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Support/ThreadLocal.h" #include #include using namespace llvm; @@ -128,6 +128,9 @@ static void CrashRecoverySignalHandler(int Signal) { // This call of Disable isn't thread safe, but it doesn't actually matter. CrashRecoveryContext::Disable(); raise(Signal); + + // The signal will be thrown once the signal mask is restored. + return; } // Unblock the signal we received. @@ -202,3 +205,26 @@ const std::string &CrashRecoveryContext::getBacktrace() const { assert(CRC->Failed && "No crash was detected!"); return CRC->Backtrace; } + +// + +namespace { +struct RunSafelyOnThreadInfo { + void (*UserFn)(void*); + void *UserData; + CrashRecoveryContext *CRC; + bool Result; +}; +} + +static void RunSafelyOnThread_Dispatch(void *UserData) { + RunSafelyOnThreadInfo *Info = + reinterpret_cast(UserData); + Info->Result = Info->CRC->RunSafely(Info->UserFn, Info->UserData); +} +bool CrashRecoveryContext::RunSafelyOnThread(void (*Fn)(void*), void *UserData, + unsigned RequestedStackSize) { + RunSafelyOnThreadInfo Info = { Fn, UserData, this, false }; + llvm_execute_on_thread(RunSafelyOnThread_Dispatch, &Info, RequestedStackSize); + return Info.Result; +} diff --git a/lib/Support/Debug.cpp b/lib/Support/Debug.cpp index 7f48f8aae717..9fdb12ecfdcb 100644 --- a/lib/Support/Debug.cpp +++ b/lib/Support/Debug.cpp @@ -26,7 +26,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/circular_raw_ostream.h" -#include "llvm/System/Signals.h" +#include "llvm/Support/Signals.h" using namespace llvm; diff --git a/lib/Support/Disassembler.cpp b/lib/Support/Disassembler.cpp new file mode 100644 index 000000000000..6362aff43a9d --- /dev/null +++ b/lib/Support/Disassembler.cpp @@ -0,0 +1,75 @@ +//===- lib/System/Disassembler.cpp ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the necessary glue to call external disassembler +// libraries. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" +#include "llvm/Support/Disassembler.h" + +#include +#include +#include +#include + +#if USE_UDIS86 +#include +#endif + +using namespace llvm; + +bool llvm::sys::hasDisassembler() +{ +#if defined (__i386__) || defined (__amd64__) || defined (__x86_64__) + // We have option to enable udis86 library. +# if USE_UDIS86 + return true; +#else + return false; +#endif +#else + return false; +#endif +} + +std::string llvm::sys::disassembleBuffer(uint8_t* start, size_t length, + uint64_t pc) { + std::stringstream res; + +#if (defined (__i386__) || defined (__amd64__) || defined (__x86_64__)) \ + && USE_UDIS86 + unsigned bits; +# if defined(__i386__) + bits = 32; +# else + bits = 64; +# endif + + ud_t ud_obj; + + ud_init(&ud_obj); + ud_set_input_buffer(&ud_obj, start, length); + ud_set_mode(&ud_obj, bits); + ud_set_pc(&ud_obj, pc); + ud_set_syntax(&ud_obj, UD_SYN_ATT); + + res << std::setbase(16) + << std::setw(bits/4); + + while (ud_disassemble(&ud_obj)) { + res << ud_insn_off(&ud_obj) << ":\t" << ud_insn_asm(&ud_obj) << "\n"; + } +#else + res << "No disassembler available. See configure help for options.\n"; +#endif + + return res.str(); +} diff --git a/lib/Support/Dwarf.cpp b/lib/Support/Dwarf.cpp index 96ce9d395b38..9799ef54792b 100644 --- a/lib/Support/Dwarf.cpp +++ b/lib/Support/Dwarf.cpp @@ -78,6 +78,10 @@ const char *llvm::dwarf::TagString(unsigned Tag) { case DW_TAG_shared_type: return "DW_TAG_shared_type"; case DW_TAG_lo_user: return "DW_TAG_lo_user"; case DW_TAG_hi_user: return "DW_TAG_hi_user"; + case DW_TAG_auto_variable: return "DW_TAG_auto_variable"; + case DW_TAG_arg_variable: return "DW_TAG_arg_variable"; + case DW_TAG_return_variable: return "DW_TAG_return_variable"; + case DW_TAG_vector_type: return "DW_TAG_vector_type"; } return 0; } diff --git a/lib/Support/DynamicLibrary.cpp b/lib/Support/DynamicLibrary.cpp new file mode 100644 index 000000000000..455c3801cc68 --- /dev/null +++ b/lib/Support/DynamicLibrary.cpp @@ -0,0 +1,170 @@ +//===-- DynamicLibrary.cpp - Runtime link/load libraries --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header file implements the operating system DynamicLibrary concept. +// +// FIXME: This file leaks the ExplicitSymbols and OpenedHandles vector, and is +// not thread safe! +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Config/config.h" +#include +#include +#include +#include + +// Collection of symbol name/value pairs to be searched prior to any libraries. +static std::map *ExplicitSymbols = 0; + +namespace { + +struct ExplicitSymbolsDeleter { + ~ExplicitSymbolsDeleter() { + if (ExplicitSymbols) + delete ExplicitSymbols; + } +}; + +} + +static ExplicitSymbolsDeleter Dummy; + +void llvm::sys::DynamicLibrary::AddSymbol(const char* symbolName, + void *symbolValue) { + if (ExplicitSymbols == 0) + ExplicitSymbols = new std::map(); + (*ExplicitSymbols)[symbolName] = symbolValue; +} + +#ifdef LLVM_ON_WIN32 + +#include "Windows/DynamicLibrary.inc" + +#else + +#if HAVE_DLFCN_H +#include +using namespace llvm; +using namespace llvm::sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +static std::vector *OpenedHandles = 0; + + +static SmartMutex& getMutex() { + static SmartMutex HandlesMutex; + return HandlesMutex; +} + + +bool DynamicLibrary::LoadLibraryPermanently(const char *Filename, + std::string *ErrMsg) { + void *H = dlopen(Filename, RTLD_LAZY|RTLD_GLOBAL); + if (H == 0) { + if (ErrMsg) *ErrMsg = dlerror(); + return true; + } +#ifdef __CYGWIN__ + // Cygwin searches symbols only in the main + // with the handle of dlopen(NULL, RTLD_GLOBAL). + if (Filename == NULL) + H = RTLD_DEFAULT; +#endif + SmartScopedLock Lock(getMutex()); + if (OpenedHandles == 0) + OpenedHandles = new std::vector(); + OpenedHandles->push_back(H); + return false; +} +#else + +using namespace llvm; +using namespace llvm::sys; + +bool DynamicLibrary::LoadLibraryPermanently(const char *Filename, + std::string *ErrMsg) { + if (ErrMsg) *ErrMsg = "dlopen() not supported on this platform"; + return true; +} +#endif + +namespace llvm { +void *SearchForAddressOfSpecialSymbol(const char* symbolName); +} + +void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) { + // First check symbols added via AddSymbol(). + if (ExplicitSymbols) { + std::map::iterator I = + ExplicitSymbols->find(symbolName); + std::map::iterator E = ExplicitSymbols->end(); + + if (I != E) + return I->second; + } + +#if HAVE_DLFCN_H + // Now search the libraries. + SmartScopedLock Lock(getMutex()); + if (OpenedHandles) { + for (std::vector::iterator I = OpenedHandles->begin(), + E = OpenedHandles->end(); I != E; ++I) { + //lt_ptr ptr = lt_dlsym(*I, symbolName); + void *ptr = dlsym(*I, symbolName); + if (ptr) { + return ptr; + } + } + } +#endif + + if (void *Result = llvm::SearchForAddressOfSpecialSymbol(symbolName)) + return Result; + +// This macro returns the address of a well-known, explicit symbol +#define EXPLICIT_SYMBOL(SYM) \ + if (!strcmp(symbolName, #SYM)) return &SYM + +// On linux we have a weird situation. The stderr/out/in symbols are both +// macros and global variables because of standards requirements. So, we +// boldly use the EXPLICIT_SYMBOL macro without checking for a #define first. +#if defined(__linux__) + { + EXPLICIT_SYMBOL(stderr); + EXPLICIT_SYMBOL(stdout); + EXPLICIT_SYMBOL(stdin); + } +#else + // For everything else, we want to check to make sure the symbol isn't defined + // as a macro before using EXPLICIT_SYMBOL. + { +#ifndef stdin + EXPLICIT_SYMBOL(stdin); +#endif +#ifndef stdout + EXPLICIT_SYMBOL(stdout); +#endif +#ifndef stderr + EXPLICIT_SYMBOL(stderr); +#endif + } +#endif +#undef EXPLICIT_SYMBOL + + return 0; +} + +#endif // LLVM_ON_WIN32 diff --git a/lib/Support/Errno.cpp b/lib/Support/Errno.cpp new file mode 100644 index 000000000000..18c658173a7a --- /dev/null +++ b/lib/Support/Errno.cpp @@ -0,0 +1,74 @@ +//===- Errno.cpp - errno support --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the errno wrappers. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Errno.h" +#include "llvm/Config/config.h" // Get autoconf configuration settings + +#if HAVE_STRING_H +#include + +#if HAVE_ERRNO_H +#include +#endif + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +namespace llvm { +namespace sys { + +#if HAVE_ERRNO_H +std::string StrError() { + return StrError(errno); +} +#endif // HAVE_ERRNO_H + +std::string StrError(int errnum) { + const int MaxErrStrLen = 2000; + char buffer[MaxErrStrLen]; + buffer[0] = '\0'; + char* str = buffer; +#ifdef HAVE_STRERROR_R + // strerror_r is thread-safe. + if (errnum) +# if defined(__GLIBC__) && defined(_GNU_SOURCE) + // glibc defines its own incompatible version of strerror_r + // which may not use the buffer supplied. + str = strerror_r(errnum,buffer,MaxErrStrLen-1); +# else + strerror_r(errnum,buffer,MaxErrStrLen-1); +# endif +#elif HAVE_DECL_STRERROR_S // "Windows Secure API" + if (errnum) + strerror_s(buffer, errnum); +#elif defined(HAVE_STRERROR) + // Copy the thread un-safe result of strerror into + // the buffer as fast as possible to minimize impact + // of collision of strerror in multiple threads. + if (errnum) + strncpy(buffer,strerror(errnum),MaxErrStrLen-1); + buffer[MaxErrStrLen-1] = '\0'; +#else + // Strange that this system doesn't even have strerror + // but, oh well, just use a generic message + sprintf(buffer, "Error #%d", errnum); +#endif + return str; +} + +} // namespace sys +} // namespace llvm + +#endif // HAVE_STRING_H diff --git a/lib/Support/ErrorHandling.cpp b/lib/Support/ErrorHandling.cpp index 0b7af3e5905b..3579546d757d 100644 --- a/lib/Support/ErrorHandling.cpp +++ b/lib/Support/ErrorHandling.cpp @@ -16,8 +16,8 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Signals.h" -#include "llvm/System/Threading.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/Threading.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Config/config.h" #include @@ -58,6 +58,10 @@ void llvm::report_fatal_error(const std::string &Reason) { report_fatal_error(Twine(Reason)); } +void llvm::report_fatal_error(StringRef Reason) { + report_fatal_error(Twine(Reason)); +} + void llvm::report_fatal_error(const Twine &Reason) { if (ErrorHandler) { ErrorHandler(ErrorHandlerUserData, Reason.str()); @@ -69,7 +73,8 @@ void llvm::report_fatal_error(const Twine &Reason) { raw_svector_ostream OS(Buffer); OS << "LLVM ERROR: " << Reason << "\n"; StringRef MessageStr = OS.str(); - (void)::write(2, MessageStr.data(), MessageStr.size()); + ssize_t written = ::write(2, MessageStr.data(), MessageStr.size()); + (void)written; // If something went wrong, we deliberately just give up. } // If we reached here, we are failing ungracefully. Run the interrupt handlers diff --git a/lib/Support/FileUtilities.cpp b/lib/Support/FileUtilities.cpp index 1bde2fe8a871..5dbabee7a7ed 100644 --- a/lib/Support/FileUtilities.cpp +++ b/lib/Support/FileUtilities.cpp @@ -15,7 +15,8 @@ #include "llvm/Support/FileUtilities.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/system_error.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallString.h" #include @@ -108,17 +109,17 @@ static bool CompareNumbers(const char *&F1P, const char *&F2P, SmallString<200> StrTmp(F1P, EndOfNumber(F1NumEnd)+1); // Strange exponential notation! StrTmp[static_cast(F1NumEnd-F1P)] = 'e'; - + V1 = strtod(&StrTmp[0], const_cast(&F1NumEnd)); F1NumEnd = F1P + (F1NumEnd-&StrTmp[0]); } - + if (*F2NumEnd == 'D' || *F2NumEnd == 'd') { // Copy string into tmp buffer to replace the 'D' with an 'e'. SmallString<200> StrTmp(F2P, EndOfNumber(F2NumEnd)+1); // Strange exponential notation! StrTmp[static_cast(F2NumEnd-F2P)] = 'e'; - + V2 = strtod(&StrTmp[0], const_cast(&F2NumEnd)); F2NumEnd = F2P + (F2NumEnd-&StrTmp[0]); } @@ -199,11 +200,20 @@ int llvm::DiffFilesWithTolerance(const sys::PathWithStatus &FileA, // Now its safe to mmap the files into memory becasue both files // have a non-zero size. - OwningPtr F1(MemoryBuffer::getFile(FileA.c_str(), Error)); - OwningPtr F2(MemoryBuffer::getFile(FileB.c_str(), Error)); - if (F1 == 0 || F2 == 0) + error_code ec; + OwningPtr F1; + if (error_code ec = MemoryBuffer::getFile(FileA.c_str(), F1)) { + if (Error) + *Error = ec.message(); return 2; - + } + OwningPtr F2; + if (error_code ec = MemoryBuffer::getFile(FileB.c_str(), F2)) { + if (Error) + *Error = ec.message(); + return 2; + } + // Okay, now that we opened the files, scan them for the first difference. const char *File1Start = F1->getBufferStart(); const char *File2Start = F2->getBufferStart(); diff --git a/lib/Support/FoldingSet.cpp b/lib/Support/FoldingSet.cpp index 29b595220887..a4f80a90d6d0 100644 --- a/lib/Support/FoldingSet.cpp +++ b/lib/Support/FoldingSet.cpp @@ -18,6 +18,7 @@ #include "llvm/Support/Allocator.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/Host.h" #include #include using namespace llvm; @@ -110,18 +111,32 @@ void FoldingSetNodeID::AddString(StringRef String) { Pos = (Units + 1) * 4; } else { // Otherwise do it the hard way. - for (Pos += 4; Pos <= Size; Pos += 4) { - unsigned V = ((unsigned char)String[Pos - 4] << 24) | - ((unsigned char)String[Pos - 3] << 16) | - ((unsigned char)String[Pos - 2] << 8) | - (unsigned char)String[Pos - 1]; - Bits.push_back(V); + // To be compatible with above bulk transfer, we need to take endianness + // into account. + if (sys::isBigEndianHost()) { + for (Pos += 4; Pos <= Size; Pos += 4) { + unsigned V = ((unsigned char)String[Pos - 4] << 24) | + ((unsigned char)String[Pos - 3] << 16) | + ((unsigned char)String[Pos - 2] << 8) | + (unsigned char)String[Pos - 1]; + Bits.push_back(V); + } + } else { + assert(sys::isLittleEndianHost() && "Unexpected host endianness"); + for (Pos += 4; Pos <= Size; Pos += 4) { + unsigned V = ((unsigned char)String[Pos - 1] << 24) | + ((unsigned char)String[Pos - 2] << 16) | + ((unsigned char)String[Pos - 3] << 8) | + (unsigned char)String[Pos - 4]; + Bits.push_back(V); + } } } // With the leftover bits. unsigned V = 0; - // Pos will have overshot size by 4 - #bytes left over. + // Pos will have overshot size by 4 - #bytes left over. + // No need to take endianness into account here - this is always executed. switch (Pos - Size) { case 1: V = (V << 8) | (unsigned char)String[Size - 3]; // Fall thru. case 2: V = (V << 8) | (unsigned char)String[Size - 2]; // Fall thru. diff --git a/lib/Support/FormattedStream.cpp b/lib/Support/FormattedStream.cpp index c72b5a1751b4..231ae48759e2 100644 --- a/lib/Support/FormattedStream.cpp +++ b/lib/Support/FormattedStream.cpp @@ -13,6 +13,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/FormattedStream.h" +#include using namespace llvm; diff --git a/lib/Support/GraphWriter.cpp b/lib/Support/GraphWriter.cpp index fdd6285a8c5e..0dba28a2530c 100644 --- a/lib/Support/GraphWriter.cpp +++ b/lib/Support/GraphWriter.cpp @@ -12,8 +12,8 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/GraphWriter.h" -#include "llvm/System/Path.h" -#include "llvm/System/Program.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" #include "llvm/Config/config.h" using namespace llvm; @@ -63,11 +63,37 @@ void llvm::DisplayGraph(const sys::Path &Filename, bool wait, args.push_back(0); errs() << "Running 'Graphviz' program... "; - if (sys::Program::ExecuteAndWait(Graphviz, &args[0],0,0,0,0,&ErrMsg)) - errs() << "Error viewing graph " << Filename.str() << ": " << ErrMsg - << "\n"; - else - Filename.eraseFromDisk(); + if (sys::Program::ExecuteAndWait(Graphviz, &args[0],0,0,0,0,&ErrMsg)) { + errs() << "Error: " << ErrMsg << "\n"; + return; + } + Filename.eraseFromDisk(); + errs() << " done. \n"; + +#elif HAVE_XDOT_PY + std::vector args; + args.push_back(LLVM_PATH_XDOT_PY); + args.push_back(Filename.c_str()); + + switch (program) { + case GraphProgram::DOT: args.push_back("-f"); args.push_back("dot"); break; + case GraphProgram::FDP: args.push_back("-f"); args.push_back("fdp"); break; + case GraphProgram::NEATO: args.push_back("-f"); args.push_back("neato");break; + case GraphProgram::TWOPI: args.push_back("-f"); args.push_back("twopi");break; + case GraphProgram::CIRCO: args.push_back("-f"); args.push_back("circo");break; + default: errs() << "Unknown graph layout name; using default.\n"; + } + + args.push_back(0); + + errs() << "Running 'xdot.py' program... "; + if (sys::Program::ExecuteAndWait(sys::Path(LLVM_PATH_XDOT_PY), + &args[0],0,0,0,0,&ErrMsg)) { + errs() << "Error: " << ErrMsg << "\n"; + return; + } + Filename.eraseFromDisk(); + errs() << " done. \n"; #elif (HAVE_GV && (HAVE_DOT || HAVE_FDP || HAVE_NEATO || \ HAVE_TWOPI || HAVE_CIRCO)) @@ -128,8 +154,7 @@ void llvm::DisplayGraph(const sys::Path &Filename, bool wait, errs() << "Running '" << prog.str() << "' program... "; if (sys::Program::ExecuteAndWait(prog, &args[0], 0, 0, 0, 0, &ErrMsg)) { - errs() << "Error viewing graph " << Filename.str() << ": '" - << ErrMsg << "\n"; + errs() << "Error: " << ErrMsg << "\n"; return; } errs() << " done. \n"; @@ -144,7 +169,7 @@ void llvm::DisplayGraph(const sys::Path &Filename, bool wait, ErrMsg.clear(); if (wait) { if (sys::Program::ExecuteAndWait(gv, &args[0],0,0,0,0,&ErrMsg)) - errs() << "Error viewing graph: " << ErrMsg << "\n"; + errs() << "Error: " << ErrMsg << "\n"; Filename.eraseFromDisk(); PSFilename.eraseFromDisk(); } @@ -163,8 +188,7 @@ void llvm::DisplayGraph(const sys::Path &Filename, bool wait, errs() << "Running 'dotty' program... "; if (sys::Program::ExecuteAndWait(dotty, &args[0],0,0,0,0,&ErrMsg)) { - errs() << "Error viewing graph " << Filename.str() << ": " - << ErrMsg << "\n"; + errs() << "Error: " << ErrMsg << "\n"; } else { // Dotty spawns another app and doesn't wait until it returns #if defined (__MINGW32__) || defined (_WINDOWS) diff --git a/lib/Support/Host.cpp b/lib/Support/Host.cpp new file mode 100644 index 000000000000..4dacf9691d6e --- /dev/null +++ b/lib/Support/Host.cpp @@ -0,0 +1,307 @@ +//===-- Host.cpp - Implement OS Host Concept --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header file implements the operating system Host concept. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Host.h" +#include "llvm/Config/config.h" +#include + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/Host.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/Host.inc" +#endif +#ifdef _MSC_VER +#include +#endif + +//===----------------------------------------------------------------------===// +// +// Implementations of the CPU detection routines +// +//===----------------------------------------------------------------------===// + +using namespace llvm; + +#if defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86)\ + || defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64) + +/// GetX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in the +/// specified arguments. If we can't run cpuid on the host, return true. +static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX, + unsigned *rEBX, unsigned *rECX, unsigned *rEDX) { +#if defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64) + #if defined(__GNUC__) + // gcc doesn't know cpuid would clobber ebx/rbx. Preseve it manually. + asm ("movq\t%%rbx, %%rsi\n\t" + "cpuid\n\t" + "xchgq\t%%rbx, %%rsi\n\t" + : "=a" (*rEAX), + "=S" (*rEBX), + "=c" (*rECX), + "=d" (*rEDX) + : "a" (value)); + return false; + #elif defined(_MSC_VER) + int registers[4]; + __cpuid(registers, value); + *rEAX = registers[0]; + *rEBX = registers[1]; + *rECX = registers[2]; + *rEDX = registers[3]; + return false; + #endif +#elif defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86) + #if defined(__GNUC__) + asm ("movl\t%%ebx, %%esi\n\t" + "cpuid\n\t" + "xchgl\t%%ebx, %%esi\n\t" + : "=a" (*rEAX), + "=S" (*rEBX), + "=c" (*rECX), + "=d" (*rEDX) + : "a" (value)); + return false; + #elif defined(_MSC_VER) + __asm { + mov eax,value + cpuid + mov esi,rEAX + mov dword ptr [esi],eax + mov esi,rEBX + mov dword ptr [esi],ebx + mov esi,rECX + mov dword ptr [esi],ecx + mov esi,rEDX + mov dword ptr [esi],edx + } + return false; + #endif +#endif + return true; +} + +static void DetectX86FamilyModel(unsigned EAX, unsigned &Family, + unsigned &Model) { + Family = (EAX >> 8) & 0xf; // Bits 8 - 11 + Model = (EAX >> 4) & 0xf; // Bits 4 - 7 + if (Family == 6 || Family == 0xf) { + if (Family == 0xf) + // Examine extended family ID if family ID is F. + Family += (EAX >> 20) & 0xff; // Bits 20 - 27 + // Examine extended model ID if family ID is 6 or F. + Model += ((EAX >> 16) & 0xf) << 4; // Bits 16 - 19 + } +} + +std::string sys::getHostCPUName() { + unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0; + if (GetX86CpuIDAndInfo(0x1, &EAX, &EBX, &ECX, &EDX)) + return "generic"; + unsigned Family = 0; + unsigned Model = 0; + DetectX86FamilyModel(EAX, Family, Model); + + bool HasSSE3 = (ECX & 0x1); + GetX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); + bool Em64T = (EDX >> 29) & 0x1; + + union { + unsigned u[3]; + char c[12]; + } text; + + GetX86CpuIDAndInfo(0, &EAX, text.u+0, text.u+2, text.u+1); + if (memcmp(text.c, "GenuineIntel", 12) == 0) { + switch (Family) { + case 3: + return "i386"; + case 4: + switch (Model) { + case 0: // Intel486 DX processors + case 1: // Intel486 DX processors + case 2: // Intel486 SX processors + case 3: // Intel487 processors, IntelDX2 OverDrive processors, + // IntelDX2 processors + case 4: // Intel486 SL processor + case 5: // IntelSX2 processors + case 7: // Write-Back Enhanced IntelDX2 processors + case 8: // IntelDX4 OverDrive processors, IntelDX4 processors + default: return "i486"; + } + case 5: + switch (Model) { + case 1: // Pentium OverDrive processor for Pentium processor (60, 66), + // Pentium processors (60, 66) + case 2: // Pentium OverDrive processor for Pentium processor (75, 90, + // 100, 120, 133), Pentium processors (75, 90, 100, 120, 133, + // 150, 166, 200) + case 3: // Pentium OverDrive processors for Intel486 processor-based + // systems + return "pentium"; + + case 4: // Pentium OverDrive processor with MMX technology for Pentium + // processor (75, 90, 100, 120, 133), Pentium processor with + // MMX technology (166, 200) + return "pentium-mmx"; + + default: return "pentium"; + } + case 6: + switch (Model) { + case 1: // Pentium Pro processor + return "pentiumpro"; + + case 3: // Intel Pentium II OverDrive processor, Pentium II processor, + // model 03 + case 5: // Pentium II processor, model 05, Pentium II Xeon processor, + // model 05, and Intel Celeron processor, model 05 + case 6: // Celeron processor, model 06 + return "pentium2"; + + case 7: // Pentium III processor, model 07, and Pentium III Xeon + // processor, model 07 + case 8: // Pentium III processor, model 08, Pentium III Xeon processor, + // model 08, and Celeron processor, model 08 + case 10: // Pentium III Xeon processor, model 0Ah + case 11: // Pentium III processor, model 0Bh + return "pentium3"; + + case 9: // Intel Pentium M processor, Intel Celeron M processor model 09. + case 13: // Intel Pentium M processor, Intel Celeron M processor, model + // 0Dh. All processors are manufactured using the 90 nm process. + return "pentium-m"; + + case 14: // Intel Core Duo processor, Intel Core Solo processor, model + // 0Eh. All processors are manufactured using the 65 nm process. + return "yonah"; + + case 15: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile + // processor, Intel Core 2 Quad processor, Intel Core 2 Quad + // mobile processor, Intel Core 2 Extreme processor, Intel + // Pentium Dual-Core processor, Intel Xeon processor, model + // 0Fh. All processors are manufactured using the 65 nm process. + case 22: // Intel Celeron processor model 16h. All processors are + // manufactured using the 65 nm process + return "core2"; + + case 21: // Intel EP80579 Integrated Processor and Intel EP80579 + // Integrated Processor with Intel QuickAssist Technology + return "i686"; // FIXME: ??? + + case 23: // Intel Core 2 Extreme processor, Intel Xeon processor, model + // 17h. All processors are manufactured using the 45 nm process. + // + // 45nm: Penryn , Wolfdale, Yorkfield (XE) + return "penryn"; + + case 26: // Intel Core i7 processor and Intel Xeon processor. All + // processors are manufactured using the 45 nm process. + case 29: // Intel Xeon processor MP. All processors are manufactured using + // the 45 nm process. + case 30: // Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz. + // As found in a Summer 2010 model iMac. + case 37: // Intel Core i7, laptop version. + return "corei7"; + + case 28: // Intel Atom processor. All processors are manufactured using + // the 45 nm process + return "atom"; + + default: return "i686"; + } + case 15: { + switch (Model) { + case 0: // Pentium 4 processor, Intel Xeon processor. All processors are + // model 00h and manufactured using the 0.18 micron process. + case 1: // Pentium 4 processor, Intel Xeon processor, Intel Xeon + // processor MP, and Intel Celeron processor. All processors are + // model 01h and manufactured using the 0.18 micron process. + case 2: // Pentium 4 processor, Mobile Intel Pentium 4 processor - M, + // Intel Xeon processor, Intel Xeon processor MP, Intel Celeron + // processor, and Mobile Intel Celeron processor. All processors + // are model 02h and manufactured using the 0.13 micron process. + return (Em64T) ? "x86-64" : "pentium4"; + + case 3: // Pentium 4 processor, Intel Xeon processor, Intel Celeron D + // processor. All processors are model 03h and manufactured using + // the 90 nm process. + case 4: // Pentium 4 processor, Pentium 4 processor Extreme Edition, + // Pentium D processor, Intel Xeon processor, Intel Xeon + // processor MP, Intel Celeron D processor. All processors are + // model 04h and manufactured using the 90 nm process. + case 6: // Pentium 4 processor, Pentium D processor, Pentium processor + // Extreme Edition, Intel Xeon processor, Intel Xeon processor + // MP, Intel Celeron D processor. All processors are model 06h + // and manufactured using the 65 nm process. + return (Em64T) ? "nocona" : "prescott"; + + default: + return (Em64T) ? "x86-64" : "pentium4"; + } + } + + default: + return "generic"; + } + } else if (memcmp(text.c, "AuthenticAMD", 12) == 0) { + // FIXME: this poorly matches the generated SubtargetFeatureKV table. There + // appears to be no way to generate the wide variety of AMD-specific targets + // from the information returned from CPUID. + switch (Family) { + case 4: + return "i486"; + case 5: + switch (Model) { + case 6: + case 7: return "k6"; + case 8: return "k6-2"; + case 9: + case 13: return "k6-3"; + default: return "pentium"; + } + case 6: + switch (Model) { + case 4: return "athlon-tbird"; + case 6: + case 7: + case 8: return "athlon-mp"; + case 10: return "athlon-xp"; + default: return "athlon"; + } + case 15: + if (HasSSE3) + return "k8-sse3"; + switch (Model) { + case 1: return "opteron"; + case 5: return "athlon-fx"; // also opteron + default: return "athlon64"; + } + case 16: + return "amdfam10"; + default: + return "generic"; + } + } + return "generic"; +} +#else +std::string sys::getHostCPUName() { + return "generic"; +} +#endif + +bool sys::getHostCPUFeatures(StringMap &Features){ + return false; +} diff --git a/lib/Support/IncludeFile.cpp b/lib/Support/IncludeFile.cpp new file mode 100644 index 000000000000..5da88261ce53 --- /dev/null +++ b/lib/Support/IncludeFile.cpp @@ -0,0 +1,20 @@ +//===- lib/System/IncludeFile.cpp - Ensure Linking Of Implementation -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the IncludeFile constructor. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/IncludeFile.h" + +using namespace llvm; + +// This constructor is used to ensure linking of other modules. See the +// llvm/Support/IncludeFile.h header for details. +IncludeFile::IncludeFile(const void*) {} diff --git a/lib/Support/IntEqClasses.cpp b/lib/Support/IntEqClasses.cpp new file mode 100644 index 000000000000..11344956e4c9 --- /dev/null +++ b/lib/Support/IntEqClasses.cpp @@ -0,0 +1,70 @@ +//===-- llvm/ADT/IntEqClasses.cpp - Equivalence Classes of Integers -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Equivalence classes for small integers. This is a mapping of the integers +// 0 .. N-1 into M equivalence classes numbered 0 .. M-1. +// +// Initially each integer has its own equivalence class. Classes are joined by +// passing a representative member of each class to join(). +// +// Once the classes are built, compress() will number them 0 .. M-1 and prevent +// further changes. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/IntEqClasses.h" + +using namespace llvm; + +void IntEqClasses::grow(unsigned N) { + assert(NumClasses == 0 && "grow() called after compress()."); + EC.reserve(N); + while (EC.size() < N) + EC.push_back(EC.size()); +} + +void IntEqClasses::join(unsigned a, unsigned b) { + assert(NumClasses == 0 && "join() called after compress()."); + unsigned eca = EC[a]; + unsigned ecb = EC[b]; + // Update pointers while searching for the leaders, compressing the paths + // incrementally. The larger leader will eventually be updated, joining the + // classes. + while (eca != ecb) + if (eca < ecb) + EC[b] = eca, b = ecb, ecb = EC[b]; + else + EC[a] = ecb, a = eca, eca = EC[a]; +} + +unsigned IntEqClasses::findLeader(unsigned a) const { + assert(NumClasses == 0 && "findLeader() called after compress()."); + while (a != EC[a]) + a = EC[a]; + return a; +} + +void IntEqClasses::compress() { + if (NumClasses) + return; + for (unsigned i = 0, e = EC.size(); i != e; ++i) + EC[i] = (EC[i] == i) ? NumClasses++ : EC[EC[i]]; +} + +void IntEqClasses::uncompress() { + if (!NumClasses) + return; + SmallVector Leader; + for (unsigned i = 0, e = EC.size(); i != e; ++i) + if (EC[i] < Leader.size()) + EC[i] = Leader[EC[i]]; + else + Leader.push_back(EC[i] = i); + NumClasses = 0; +} diff --git a/lib/Support/IntervalMap.cpp b/lib/Support/IntervalMap.cpp new file mode 100644 index 000000000000..4dfcc404ca42 --- /dev/null +++ b/lib/Support/IntervalMap.cpp @@ -0,0 +1,161 @@ +//===- lib/Support/IntervalMap.cpp - A sorted interval map ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the few non-templated functions in IntervalMap. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/IntervalMap.h" + +namespace llvm { +namespace IntervalMapImpl { + +void Path::replaceRoot(void *Root, unsigned Size, IdxPair Offsets) { + assert(!path.empty() && "Can't replace missing root"); + path.front() = Entry(Root, Size, Offsets.first); + path.insert(path.begin() + 1, Entry(subtree(0), Offsets.second)); +} + +NodeRef Path::getLeftSibling(unsigned Level) const { + // The root has no siblings. + if (Level == 0) + return NodeRef(); + + // Go up the tree until we can go left. + unsigned l = Level - 1; + while (l && path[l].offset == 0) + --l; + + // We can't go left. + if (path[l].offset == 0) + return NodeRef(); + + // NR is the subtree containing our left sibling. + NodeRef NR = path[l].subtree(path[l].offset - 1); + + // Keep right all the way down. + for (++l; l != Level; ++l) + NR = NR.subtree(NR.size() - 1); + return NR; +} + +void Path::moveLeft(unsigned Level) { + assert(Level != 0 && "Cannot move the root node"); + + // Go up the tree until we can go left. + unsigned l = 0; + if (valid()) { + l = Level - 1; + while (path[l].offset == 0) { + assert(l != 0 && "Cannot move beyond begin()"); + --l; + } + } else if (height() < Level) + // end() may have created a height=0 path. + path.resize(Level + 1, Entry(0, 0, 0)); + + // NR is the subtree containing our left sibling. + --path[l].offset; + NodeRef NR = subtree(l); + + // Get the rightmost node in the subtree. + for (++l; l != Level; ++l) { + path[l] = Entry(NR, NR.size() - 1); + NR = NR.subtree(NR.size() - 1); + } + path[l] = Entry(NR, NR.size() - 1); +} + +NodeRef Path::getRightSibling(unsigned Level) const { + // The root has no siblings. + if (Level == 0) + return NodeRef(); + + // Go up the tree until we can go right. + unsigned l = Level - 1; + while (l && atLastEntry(l)) + --l; + + // We can't go right. + if (atLastEntry(l)) + return NodeRef(); + + // NR is the subtree containing our right sibling. + NodeRef NR = path[l].subtree(path[l].offset + 1); + + // Keep left all the way down. + for (++l; l != Level; ++l) + NR = NR.subtree(0); + return NR; +} + +void Path::moveRight(unsigned Level) { + assert(Level != 0 && "Cannot move the root node"); + + // Go up the tree until we can go right. + unsigned l = Level - 1; + while (l && atLastEntry(l)) + --l; + + // NR is the subtree containing our right sibling. If we hit end(), we have + // offset(0) == node(0).size(). + if (++path[l].offset == path[l].size) + return; + NodeRef NR = subtree(l); + + for (++l; l != Level; ++l) { + path[l] = Entry(NR, 0); + NR = NR.subtree(0); + } + path[l] = Entry(NR, 0); +} + + +IdxPair distribute(unsigned Nodes, unsigned Elements, unsigned Capacity, + const unsigned *CurSize, unsigned NewSize[], + unsigned Position, bool Grow) { + assert(Elements + Grow <= Nodes * Capacity && "Not enough room for elements"); + assert(Position <= Elements && "Invalid position"); + if (!Nodes) + return IdxPair(); + + // Trivial algorithm: left-leaning even distribution. + const unsigned PerNode = (Elements + Grow) / Nodes; + const unsigned Extra = (Elements + Grow) % Nodes; + IdxPair PosPair = IdxPair(Nodes, 0); + unsigned Sum = 0; + for (unsigned n = 0; n != Nodes; ++n) { + Sum += NewSize[n] = PerNode + (n < Extra); + if (PosPair.first == Nodes && Sum > Position) + PosPair = IdxPair(n, Position - (Sum - NewSize[n])); + } + assert(Sum == Elements + Grow && "Bad distribution sum"); + + // Subtract the Grow element that was added. + if (Grow) { + assert(PosPair.first < Nodes && "Bad algebra"); + assert(NewSize[PosPair.first] && "Too few elements to need Grow"); + --NewSize[PosPair.first]; + } + +#ifndef NDEBUG + Sum = 0; + for (unsigned n = 0; n != Nodes; ++n) { + assert(NewSize[n] <= Capacity && "Overallocated node"); + Sum += NewSize[n]; + } + assert(Sum == Elements && "Bad distribution sum"); +#endif + + return PosPair; +} + +} // namespace IntervalMapImpl +} // namespace llvm + diff --git a/lib/Support/Makefile b/lib/Support/Makefile index 48c21f4fd9e0..d68e500ca5f4 100644 --- a/lib/Support/Makefile +++ b/lib/Support/Makefile @@ -14,4 +14,9 @@ BUILD_ARCHIVE = 1 ## FIXME: This only requires RTTI because tblgen uses it. Fix that. REQUIRES_RTTI = 1 +EXTRA_DIST = Unix Win32 README.txt + include $(LEVEL)/Makefile.common + +CompileCommonOpts := $(filter-out -pedantic,$(CompileCommonOpts)) +CompileCommonOpts := $(filter-out -Wno-long-long,$(CompileCommonOpts)) diff --git a/lib/Support/ManagedStatic.cpp b/lib/Support/ManagedStatic.cpp index 4e655a0f9eec..c767c15e71c9 100644 --- a/lib/Support/ManagedStatic.cpp +++ b/lib/Support/ManagedStatic.cpp @@ -13,7 +13,7 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Config/config.h" -#include "llvm/System/Atomic.h" +#include "llvm/Support/Atomic.h" #include using namespace llvm; diff --git a/lib/Support/Memory.cpp b/lib/Support/Memory.cpp new file mode 100644 index 000000000000..a9689b2c39f2 --- /dev/null +++ b/lib/Support/Memory.cpp @@ -0,0 +1,74 @@ +//===- Memory.cpp - Memory Handling Support ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines some helpful functions for allocating memory and dealing +// with memory mapped files +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Memory.h" +#include "llvm/Support/Valgrind.h" +#include "llvm/Config/config.h" + +namespace llvm { +using namespace sys; +} + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/Memory.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/Memory.inc" +#endif + +extern "C" void sys_icache_invalidate(const void *Addr, size_t len); + +/// InvalidateInstructionCache - Before the JIT can run a block of code +/// that has been emitted it must invalidate the instruction cache on some +/// platforms. +void llvm::sys::Memory::InvalidateInstructionCache(const void *Addr, + size_t Len) { + +// icache invalidation for PPC and ARM. +#if defined(__APPLE__) + +# if (defined(__POWERPC__) || defined (__ppc__) || \ + defined(_POWER) || defined(_ARCH_PPC)) || defined(__arm__) + sys_icache_invalidate(Addr, Len); +# endif + +#else + +# if (defined(__POWERPC__) || defined (__ppc__) || \ + defined(_POWER) || defined(_ARCH_PPC)) && defined(__GNUC__) + const size_t LineSize = 32; + + const intptr_t Mask = ~(LineSize - 1); + const intptr_t StartLine = ((intptr_t) Addr) & Mask; + const intptr_t EndLine = ((intptr_t) Addr + Len + LineSize - 1) & Mask; + + for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) + asm volatile("dcbf 0, %0" : : "r"(Line)); + asm volatile("sync"); + + for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) + asm volatile("icbi 0, %0" : : "r"(Line)); + asm volatile("isync"); +# elif defined(__arm__) && defined(__GNUC__) + // FIXME: Can we safely always call this for __GNUC__ everywhere? + char *Start = (char*) Addr; + char *End = Start + Len; + __clear_cache(Start, End); +# endif + +#endif // end apple + + ValgrindDiscardTranslations(Addr, Len); +} diff --git a/lib/Support/MemoryBuffer.cpp b/lib/Support/MemoryBuffer.cpp index 542162d513b9..a0c650d6820b 100644 --- a/lib/Support/MemoryBuffer.cpp +++ b/lib/Support/MemoryBuffer.cpp @@ -15,14 +15,16 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/MathExtras.h" -#include "llvm/System/Errno.h" -#include "llvm/System/Path.h" -#include "llvm/System/Process.h" -#include "llvm/System/Program.h" +#include "llvm/Support/Errno.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/system_error.h" #include #include #include #include +#include #include #include #if !defined(_MSC_VER) && !defined(__MINGW32__) @@ -34,6 +36,8 @@ #include using namespace llvm; +namespace { const llvm::error_code success; } + //===----------------------------------------------------------------------===// // MemoryBuffer implementation itself. //===----------------------------------------------------------------------===// @@ -142,22 +146,20 @@ MemoryBuffer *MemoryBuffer::getNewMemBuffer(size_t Size, StringRef BufferName) { /// if the Filename is "-". If an error occurs, this returns null and fills /// in *ErrStr with a reason. If stdin is empty, this API (unlike getSTDIN) /// returns an empty buffer. -MemoryBuffer *MemoryBuffer::getFileOrSTDIN(StringRef Filename, - std::string *ErrStr, - int64_t FileSize, - struct stat *FileInfo) { +error_code MemoryBuffer::getFileOrSTDIN(StringRef Filename, + OwningPtr &result, + int64_t FileSize) { if (Filename == "-") - return getSTDIN(ErrStr); - return getFile(Filename, ErrStr, FileSize, FileInfo); + return getSTDIN(result); + return getFile(Filename, result, FileSize); } -MemoryBuffer *MemoryBuffer::getFileOrSTDIN(const char *Filename, - std::string *ErrStr, - int64_t FileSize, - struct stat *FileInfo) { +error_code MemoryBuffer::getFileOrSTDIN(const char *Filename, + OwningPtr &result, + int64_t FileSize) { if (strcmp(Filename, "-") == 0) - return getSTDIN(ErrStr); - return getFile(Filename, ErrStr, FileSize, FileInfo); + return getSTDIN(result); + return getFile(Filename, result, FileSize); } //===----------------------------------------------------------------------===// @@ -177,50 +179,47 @@ public: sys::Path::UnMapFilePages(getBufferStart(), getBufferSize()); } }; - -/// FileCloser - RAII object to make sure an FD gets closed properly. -class FileCloser { - int FD; -public: - explicit FileCloser(int FD) : FD(FD) {} - ~FileCloser() { ::close(FD); } -}; } -MemoryBuffer *MemoryBuffer::getFile(StringRef Filename, std::string *ErrStr, - int64_t FileSize, struct stat *FileInfo) { +error_code MemoryBuffer::getFile(StringRef Filename, + OwningPtr &result, + int64_t FileSize) { + // Ensure the path is null terminated. SmallString<256> PathBuf(Filename.begin(), Filename.end()); - return MemoryBuffer::getFile(PathBuf.c_str(), ErrStr, FileSize, FileInfo); + return MemoryBuffer::getFile(PathBuf.c_str(), result, FileSize); } -MemoryBuffer *MemoryBuffer::getFile(const char *Filename, std::string *ErrStr, - int64_t FileSize, struct stat *FileInfo) { +error_code MemoryBuffer::getFile(const char *Filename, + OwningPtr &result, + int64_t FileSize) { int OpenFlags = O_RDONLY; #ifdef O_BINARY OpenFlags |= O_BINARY; // Open input file in binary mode on win32. #endif int FD = ::open(Filename, OpenFlags); if (FD == -1) { - if (ErrStr) *ErrStr = sys::StrError(); - return 0; + return error_code(errno, posix_category()); } - FileCloser FC(FD); // Close FD on return. - + error_code ret = getOpenFile(FD, Filename, result, FileSize); + close(FD); + return ret; +} + +error_code MemoryBuffer::getOpenFile(int FD, const char *Filename, + OwningPtr &result, + int64_t FileSize) { // If we don't know the file size, use fstat to find out. fstat on an open // file descriptor is cheaper than stat on a random path. - if (FileSize == -1 || FileInfo) { - struct stat MyFileInfo; - struct stat *FileInfoPtr = FileInfo? FileInfo : &MyFileInfo; - + if (FileSize == -1) { + struct stat FileInfo; // TODO: This should use fstat64 when available. - if (fstat(FD, FileInfoPtr) == -1) { - if (ErrStr) *ErrStr = sys::StrError(); - return 0; + if (fstat(FD, &FileInfo) == -1) { + return error_code(errno, posix_category()); } - FileSize = FileInfoPtr->st_size; + FileSize = FileInfo.st_size; } - - + + // If the file is large, try to use mmap to read it in. We don't use mmap // for small files, because this can severely fragment our address space. Also // don't try to map files that are exactly a multiple of the system page size, @@ -230,16 +229,17 @@ MemoryBuffer *MemoryBuffer::getFile(const char *Filename, std::string *ErrStr, if (FileSize >= 4096*4 && (FileSize & (sys::Process::GetPageSize()-1)) != 0) { if (const char *Pages = sys::Path::MapInFilePages(FD, FileSize)) { - return GetNamedBuffer(StringRef(Pages, FileSize), - Filename); + result.reset(GetNamedBuffer( + StringRef(Pages, FileSize), Filename)); + return success; } } MemoryBuffer *Buf = MemoryBuffer::getNewUninitMemBuffer(FileSize, Filename); if (!Buf) { - // Failed to create a buffer. - if (ErrStr) *ErrStr = "could not allocate buffer"; - return 0; + // Failed to create a buffer. The only way it can fail is if + // new(std::nothrow) returns 0. + return make_error_code(errc::not_enough_memory); } OwningPtr SB(Buf); @@ -252,26 +252,27 @@ MemoryBuffer *MemoryBuffer::getFile(const char *Filename, std::string *ErrStr, if (errno == EINTR) continue; // Error while reading. - if (ErrStr) *ErrStr = sys::StrError(); - return 0; + return error_code(errno, posix_category()); } else if (NumRead == 0) { // We hit EOF early, truncate and terminate buffer. Buf->BufferEnd = BufPtr; *BufPtr = 0; - return SB.take(); + result.swap(SB); + return success; } BytesLeft -= NumRead; BufPtr += NumRead; } - return SB.take(); + result.swap(SB); + return success; } //===----------------------------------------------------------------------===// // MemoryBuffer::getSTDIN implementation. //===----------------------------------------------------------------------===// -MemoryBuffer *MemoryBuffer::getSTDIN(std::string *ErrStr) { +error_code MemoryBuffer::getSTDIN(OwningPtr &result) { // Read in all of the data from stdin, we cannot mmap stdin. // // FIXME: That isn't necessarily true, we should try to mmap stdin and @@ -287,11 +288,11 @@ MemoryBuffer *MemoryBuffer::getSTDIN(std::string *ErrStr) { ReadBytes = read(0, Buffer.end(), ChunkSize); if (ReadBytes == -1) { if (errno == EINTR) continue; - if (ErrStr) *ErrStr = sys::StrError(); - return 0; + return error_code(errno, posix_category()); } Buffer.set_size(Buffer.size() + ReadBytes); } while (ReadBytes != 0); - return getMemBufferCopy(Buffer, ""); + result.reset(getMemBufferCopy(Buffer, "")); + return success; } diff --git a/lib/Support/Mutex.cpp b/lib/Support/Mutex.cpp new file mode 100644 index 000000000000..b408973bbad1 --- /dev/null +++ b/lib/Support/Mutex.cpp @@ -0,0 +1,157 @@ +//===- Mutex.cpp - Mutual Exclusion Lock ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the llvm::sys::Mutex class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" +#include "llvm/Support/Mutex.h" + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +#if !defined(ENABLE_THREADS) || ENABLE_THREADS == 0 +// Define all methods as no-ops if threading is explicitly disabled +namespace llvm { +using namespace sys; +MutexImpl::MutexImpl( bool recursive) { } +MutexImpl::~MutexImpl() { } +bool MutexImpl::acquire() { return true; } +bool MutexImpl::release() { return true; } +bool MutexImpl::tryacquire() { return true; } +} +#else + +#if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_MUTEX_LOCK) + +#include +#include +#include + +namespace llvm { +using namespace sys; + + +// This variable is useful for situations where the pthread library has been +// compiled with weak linkage for its interface symbols. This allows the +// threading support to be turned off by simply not linking against -lpthread. +// In that situation, the value of pthread_mutex_init will be 0 and +// consequently pthread_enabled will be false. In such situations, all the +// pthread operations become no-ops and the functions all return false. If +// pthread_mutex_init does have an address, then mutex support is enabled. +// Note: all LLVM tools will link against -lpthread if its available since it +// is configured into the LIBS variable. +// Note: this line of code generates a warning if pthread_mutex_init is not +// declared with weak linkage. It's safe to ignore the warning. +static const bool pthread_enabled = true; + +// Construct a Mutex using pthread calls +MutexImpl::MutexImpl( bool recursive) + : data_(0) +{ + if (pthread_enabled) + { + // Declare the pthread_mutex data structures + pthread_mutex_t* mutex = + static_cast(malloc(sizeof(pthread_mutex_t))); + pthread_mutexattr_t attr; + + // Initialize the mutex attributes + int errorcode = pthread_mutexattr_init(&attr); + assert(errorcode == 0); + + // Initialize the mutex as a recursive mutex, if requested, or normal + // otherwise. + int kind = ( recursive ? PTHREAD_MUTEX_RECURSIVE : PTHREAD_MUTEX_NORMAL ); + errorcode = pthread_mutexattr_settype(&attr, kind); + assert(errorcode == 0); + +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__DragonFly__) + // Make it a process local mutex + errorcode = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE); + assert(errorcode == 0); +#endif + + // Initialize the mutex + errorcode = pthread_mutex_init(mutex, &attr); + assert(errorcode == 0); + + // Destroy the attributes + errorcode = pthread_mutexattr_destroy(&attr); + assert(errorcode == 0); + + // Assign the data member + data_ = mutex; + } +} + +// Destruct a Mutex +MutexImpl::~MutexImpl() +{ + if (pthread_enabled) + { + pthread_mutex_t* mutex = static_cast(data_); + assert(mutex != 0); + pthread_mutex_destroy(mutex); + free(mutex); + } +} + +bool +MutexImpl::acquire() +{ + if (pthread_enabled) + { + pthread_mutex_t* mutex = static_cast(data_); + assert(mutex != 0); + + int errorcode = pthread_mutex_lock(mutex); + return errorcode == 0; + } else return false; +} + +bool +MutexImpl::release() +{ + if (pthread_enabled) + { + pthread_mutex_t* mutex = static_cast(data_); + assert(mutex != 0); + + int errorcode = pthread_mutex_unlock(mutex); + return errorcode == 0; + } else return false; +} + +bool +MutexImpl::tryacquire() +{ + if (pthread_enabled) + { + pthread_mutex_t* mutex = static_cast(data_); + assert(mutex != 0); + + int errorcode = pthread_mutex_trylock(mutex); + return errorcode == 0; + } else return false; +} + +} + +#elif defined(LLVM_ON_UNIX) +#include "Unix/Mutex.inc" +#elif defined( LLVM_ON_WIN32) +#include "Windows/Mutex.inc" +#else +#warning Neither LLVM_ON_UNIX nor LLVM_ON_WIN32 was set in System/Mutex.cpp +#endif +#endif diff --git a/lib/Support/Path.cpp b/lib/Support/Path.cpp new file mode 100644 index 000000000000..e5e875bc54d7 --- /dev/null +++ b/lib/Support/Path.cpp @@ -0,0 +1,283 @@ +//===-- Path.cpp - Implement OS Path Concept --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header file implements the operating system Path concept. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Path.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Config/config.h" +#include "llvm/Support/FileSystem.h" +#include +#include +#include +using namespace llvm; +using namespace sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +bool Path::operator==(const Path &that) const { + return path == that.path; +} + +bool Path::operator<(const Path& that) const { + return path < that.path; +} + +Path +Path::GetLLVMConfigDir() { + Path result; +#ifdef LLVM_ETCDIR + if (result.set(LLVM_ETCDIR)) + return result; +#endif + return GetLLVMDefaultConfigDir(); +} + +LLVMFileType +sys::IdentifyFileType(const char *magic, unsigned length) { + assert(magic && "Invalid magic number string"); + assert(length >=4 && "Invalid magic number length"); + switch ((unsigned char)magic[0]) { + case 0xDE: // 0x0B17C0DE = BC wraper + if (magic[1] == (char)0xC0 && magic[2] == (char)0x17 && + magic[3] == (char)0x0B) + return Bitcode_FileType; + break; + case 'B': + if (magic[1] == 'C' && magic[2] == (char)0xC0 && magic[3] == (char)0xDE) + return Bitcode_FileType; + break; + case '!': + if (length >= 8) + if (memcmp(magic,"!\n",8) == 0) + return Archive_FileType; + break; + + case '\177': + if (magic[1] == 'E' && magic[2] == 'L' && magic[3] == 'F') { + if (length >= 18 && magic[17] == 0) + switch (magic[16]) { + default: break; + case 1: return ELF_Relocatable_FileType; + case 2: return ELF_Executable_FileType; + case 3: return ELF_SharedObject_FileType; + case 4: return ELF_Core_FileType; + } + } + break; + + case 0xCA: + if (magic[1] == char(0xFE) && magic[2] == char(0xBA) && + magic[3] == char(0xBE)) { + // This is complicated by an overlap with Java class files. + // See the Mach-O section in /usr/share/file/magic for details. + if (length >= 8 && magic[7] < 43) + // FIXME: Universal Binary of any type. + return Mach_O_DynamicallyLinkedSharedLib_FileType; + } + break; + + case 0xFE: + case 0xCE: { + uint16_t type = 0; + if (magic[0] == char(0xFE) && magic[1] == char(0xED) && + magic[2] == char(0xFA) && magic[3] == char(0xCE)) { + /* Native endian */ + if (length >= 16) type = magic[14] << 8 | magic[15]; + } else if (magic[0] == char(0xCE) && magic[1] == char(0xFA) && + magic[2] == char(0xED) && magic[3] == char(0xFE)) { + /* Reverse endian */ + if (length >= 14) type = magic[13] << 8 | magic[12]; + } + switch (type) { + default: break; + case 1: return Mach_O_Object_FileType; + case 2: return Mach_O_Executable_FileType; + case 3: return Mach_O_FixedVirtualMemorySharedLib_FileType; + case 4: return Mach_O_Core_FileType; + case 5: return Mach_O_PreloadExecutable_FileType; + case 6: return Mach_O_DynamicallyLinkedSharedLib_FileType; + case 7: return Mach_O_DynamicLinker_FileType; + case 8: return Mach_O_Bundle_FileType; + case 9: return Mach_O_DynamicallyLinkedSharedLibStub_FileType; + case 10: break; // FIXME: MH_DSYM companion file with only debug. + } + break; + } + case 0xF0: // PowerPC Windows + case 0x83: // Alpha 32-bit + case 0x84: // Alpha 64-bit + case 0x66: // MPS R4000 Windows + case 0x50: // mc68K + case 0x4c: // 80386 Windows + if (magic[1] == 0x01) + return COFF_FileType; + + case 0x90: // PA-RISC Windows + case 0x68: // mc68K Windows + if (magic[1] == 0x02) + return COFF_FileType; + break; + case 0x64: // x86-64 Windows. + if (magic[1] == char(0x86)) + return COFF_FileType; + break; + + default: + break; + } + return Unknown_FileType; +} + +bool +Path::isArchive() const { + LLVMFileType type; + if (fs::identify_magic(str(), type)) + return false; + return type == Archive_FileType; +} + +bool +Path::isDynamicLibrary() const { + LLVMFileType type; + if (fs::identify_magic(str(), type)) + return false; + switch (type) { + default: return false; + case Mach_O_FixedVirtualMemorySharedLib_FileType: + case Mach_O_DynamicallyLinkedSharedLib_FileType: + case Mach_O_DynamicallyLinkedSharedLibStub_FileType: + case ELF_SharedObject_FileType: + case COFF_FileType: return true; + } +} + +bool +Path::isObjectFile() const { + LLVMFileType type; + if (fs::identify_magic(str(), type) || type == Unknown_FileType) + return false; + return true; +} + +Path +Path::FindLibrary(std::string& name) { + std::vector LibPaths; + GetSystemLibraryPaths(LibPaths); + for (unsigned i = 0; i < LibPaths.size(); ++i) { + sys::Path FullPath(LibPaths[i]); + FullPath.appendComponent("lib" + name + LTDL_SHLIB_EXT); + if (FullPath.isDynamicLibrary()) + return FullPath; + FullPath.eraseSuffix(); + FullPath.appendSuffix("a"); + if (FullPath.isArchive()) + return FullPath; + } + return sys::Path(); +} + +StringRef Path::GetDLLSuffix() { + return &(LTDL_SHLIB_EXT[1]); +} + +void +Path::appendSuffix(StringRef suffix) { + if (!suffix.empty()) { + path.append("."); + path.append(suffix); + } +} + +bool +Path::isBitcodeFile() const { + LLVMFileType type; + if (fs::identify_magic(str(), type)) + return false; + return type == Bitcode_FileType; +} + +bool Path::hasMagicNumber(StringRef Magic) const { + std::string actualMagic; + if (getMagicNumber(actualMagic, static_cast(Magic.size()))) + return Magic == actualMagic; + return false; +} + +static void getPathList(const char*path, std::vector& Paths) { + const char* at = path; + const char* delim = strchr(at, PathSeparator); + Path tmpPath; + while (delim != 0) { + std::string tmp(at, size_t(delim-at)); + if (tmpPath.set(tmp)) + if (tmpPath.canRead()) + Paths.push_back(tmpPath); + at = delim + 1; + delim = strchr(at, PathSeparator); + } + + if (*at != 0) + if (tmpPath.set(std::string(at))) + if (tmpPath.canRead()) + Paths.push_back(tmpPath); +} + +static StringRef getDirnameCharSep(StringRef path, const char *Sep) { + assert(Sep[0] != '\0' && Sep[1] == '\0' && + "Sep must be a 1-character string literal."); + if (path.empty()) + return "."; + + // If the path is all slashes, return a single slash. + // Otherwise, remove all trailing slashes. + + signed pos = static_cast(path.size()) - 1; + + while (pos >= 0 && path[pos] == Sep[0]) + --pos; + + if (pos < 0) + return path[0] == Sep[0] ? Sep : "."; + + // Any slashes left? + signed i = 0; + + while (i < pos && path[i] != Sep[0]) + ++i; + + if (i == pos) // No slashes? Return "." + return "."; + + // There is at least one slash left. Remove all trailing non-slashes. + while (pos >= 0 && path[pos] != Sep[0]) + --pos; + + // Remove any trailing slashes. + while (pos >= 0 && path[pos] == Sep[0]) + --pos; + + if (pos < 0) + return path[0] == Sep[0] ? Sep : "."; + + return path.substr(0, pos+1); +} + +// Include the truly platform-specific parts of this class. +#if defined(LLVM_ON_UNIX) +#include "Unix/Path.inc" +#endif +#if defined(LLVM_ON_WIN32) +#include "Windows/Path.inc" +#endif diff --git a/lib/Support/PathV2.cpp b/lib/Support/PathV2.cpp new file mode 100644 index 000000000000..896c94c071bc --- /dev/null +++ b/lib/Support/PathV2.cpp @@ -0,0 +1,774 @@ +//===-- PathV2.cpp - Implement OS Path Concept ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the operating system PathV2 API. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/PathV2.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/ErrorHandling.h" +#include +#include +#include + +namespace { + using llvm::StringRef; + using llvm::sys::path::is_separator; + +#ifdef LLVM_ON_WIN32 + const StringRef separators = "\\/"; + const char prefered_separator = '\\'; +#else + const StringRef separators = "/"; + const char prefered_separator = '/'; +#endif + + const llvm::error_code success; + + StringRef find_first_component(StringRef path) { + // Look for this first component in the following order. + // * empty (in this case we return an empty string) + // * either C: or {//,\\}net. + // * {/,\} + // * {.,..} + // * {file,directory}name + + if (path.empty()) + return path; + +#ifdef LLVM_ON_WIN32 + // C: + if (path.size() >= 2 && std::isalpha(path[0]) && path[1] == ':') + return path.substr(0, 2); +#endif + + // //net + if ((path.size() > 2) && + is_separator(path[0]) && + path[0] == path[1] && + !is_separator(path[2])) { + // Find the next directory separator. + size_t end = path.find_first_of(separators, 2); + return path.substr(0, end); + } + + // {/,\} + if (is_separator(path[0])) + return path.substr(0, 1); + + if (path.startswith("..")) + return path.substr(0, 2); + + if (path[0] == '.') + return path.substr(0, 1); + + // * {file,directory}name + size_t end = path.find_first_of(separators, 2); + return path.substr(0, end); + } + + size_t filename_pos(StringRef str) { + if (str.size() == 2 && + is_separator(str[0]) && + str[0] == str[1]) + return 0; + + if (str.size() > 0 && is_separator(str[str.size() - 1])) + return str.size() - 1; + + size_t pos = str.find_last_of(separators, str.size() - 1); + +#ifdef LLVM_ON_WIN32 + if (pos == StringRef::npos) + pos = str.find_last_of(':', str.size() - 2); +#endif + + if (pos == StringRef::npos || + (pos == 1 && is_separator(str[0]))) + return 0; + + return pos + 1; + } + + size_t root_dir_start(StringRef str) { + // case "c:/" +#ifdef LLVM_ON_WIN32 + if (str.size() > 2 && + str[1] == ':' && + is_separator(str[2])) + return 2; +#endif + + // case "//" + if (str.size() == 2 && + is_separator(str[0]) && + str[0] == str[1]) + return StringRef::npos; + + // case "//net" + if (str.size() > 3 && + is_separator(str[0]) && + str[0] == str[1] && + !is_separator(str[2])) { + return str.find_first_of(separators, 2); + } + + // case "/" + if (str.size() > 0 && is_separator(str[0])) + return 0; + + return StringRef::npos; + } + + size_t parent_path_end(StringRef path) { + size_t end_pos = filename_pos(path); + + bool filename_was_sep = path.size() > 0 && is_separator(path[end_pos]); + + // Skip separators except for root dir. + size_t root_dir_pos = root_dir_start(path.substr(0, end_pos)); + + while(end_pos > 0 && + (end_pos - 1) != root_dir_pos && + is_separator(path[end_pos - 1])) + --end_pos; + + if (end_pos == 1 && root_dir_pos == 0 && filename_was_sep) + return StringRef::npos; + + return end_pos; + } +} // end unnamed namespace + +namespace llvm { +namespace sys { +namespace path { + +const_iterator begin(StringRef path) { + const_iterator i; + i.Path = path; + i.Component = find_first_component(path); + i.Position = 0; + return i; +} + +const_iterator end(StringRef path) { + const_iterator i; + i.Path = path; + i.Position = path.size(); + return i; +} + +const_iterator &const_iterator::operator++() { + assert(Position < Path.size() && "Tried to increment past end!"); + + // Increment Position to past the current component + Position += Component.size(); + + // Check for end. + if (Position == Path.size()) { + Component = StringRef(); + return *this; + } + + // Both POSIX and Windows treat paths that begin with exactly two separators + // specially. + bool was_net = Component.size() > 2 && + is_separator(Component[0]) && + Component[1] == Component[0] && + !is_separator(Component[2]); + + // Handle separators. + if (is_separator(Path[Position])) { + // Root dir. + if (was_net +#ifdef LLVM_ON_WIN32 + // c:/ + || Component.endswith(":") +#endif + ) { + Component = Path.substr(Position, 1); + return *this; + } + + // Skip extra separators. + while (Position != Path.size() && + is_separator(Path[Position])) { + ++Position; + } + + // Treat trailing '/' as a '.'. + if (Position == Path.size()) { + --Position; + Component = "."; + return *this; + } + } + + // Find next component. + size_t end_pos = Path.find_first_of(separators, Position); + Component = Path.slice(Position, end_pos); + + return *this; +} + +const_iterator &const_iterator::operator--() { + // If we're at the end and the previous char was a '/', return '.'. + if (Position == Path.size() && + Path.size() > 1 && + is_separator(Path[Position - 1]) +#ifdef LLVM_ON_WIN32 + && Path[Position - 2] != ':' +#endif + ) { + --Position; + Component = "."; + return *this; + } + + // Skip separators unless it's the root directory. + size_t root_dir_pos = root_dir_start(Path); + size_t end_pos = Position; + + while(end_pos > 0 && + (end_pos - 1) != root_dir_pos && + is_separator(Path[end_pos - 1])) + --end_pos; + + // Find next separator. + size_t start_pos = filename_pos(Path.substr(0, end_pos)); + Component = Path.slice(start_pos, end_pos); + Position = start_pos; + return *this; +} + +bool const_iterator::operator==(const const_iterator &RHS) const { + return Path.begin() == RHS.Path.begin() && + Position == RHS.Position; +} + +bool const_iterator::operator!=(const const_iterator &RHS) const { + return !(*this == RHS); +} + +ptrdiff_t const_iterator::operator-(const const_iterator &RHS) const { + return Position - RHS.Position; +} + +const StringRef root_path(StringRef path) { + const_iterator b = begin(path), + pos = b, + e = end(path); + if (b != e) { + bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; + bool has_drive = +#ifdef LLVM_ON_WIN32 + b->endswith(":"); +#else + false; +#endif + + if (has_net || has_drive) { + if ((++pos != e) && is_separator((*pos)[0])) { + // {C:/,//net/}, so get the first two components. + return path.substr(0, b->size() + pos->size()); + } else { + // just {C:,//net}, return the first component. + return *b; + } + } + + // POSIX style root directory. + if (is_separator((*b)[0])) { + return *b; + } + } + + return StringRef(); +} + +const StringRef root_name(StringRef path) { + const_iterator b = begin(path), + e = end(path); + if (b != e) { + bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; + bool has_drive = +#ifdef LLVM_ON_WIN32 + b->endswith(":"); +#else + false; +#endif + + if (has_net || has_drive) { + // just {C:,//net}, return the first component. + return *b; + } + } + + // No path or no name. + return StringRef(); +} + +const StringRef root_directory(StringRef path) { + const_iterator b = begin(path), + pos = b, + e = end(path); + if (b != e) { + bool has_net = b->size() > 2 && is_separator((*b)[0]) && (*b)[1] == (*b)[0]; + bool has_drive = +#ifdef LLVM_ON_WIN32 + b->endswith(":"); +#else + false; +#endif + + if ((has_net || has_drive) && + // {C:,//net}, skip to the next component. + (++pos != e) && is_separator((*pos)[0])) { + return *pos; + } + + // POSIX style root directory. + if (!has_net && is_separator((*b)[0])) { + return *b; + } + } + + // No path or no root. + return StringRef(); +} + +const StringRef relative_path(StringRef path) { + StringRef root = root_path(path); + return root.substr(root.size()); +} + +void append(SmallVectorImpl &path, const Twine &a, + const Twine &b, + const Twine &c, + const Twine &d) { + SmallString<32> a_storage; + SmallString<32> b_storage; + SmallString<32> c_storage; + SmallString<32> d_storage; + + SmallVector components; + if (!a.isTriviallyEmpty()) components.push_back(a.toStringRef(a_storage)); + if (!b.isTriviallyEmpty()) components.push_back(b.toStringRef(b_storage)); + if (!c.isTriviallyEmpty()) components.push_back(c.toStringRef(c_storage)); + if (!d.isTriviallyEmpty()) components.push_back(d.toStringRef(d_storage)); + + for (SmallVectorImpl::const_iterator i = components.begin(), + e = components.end(); + i != e; ++i) { + bool path_has_sep = !path.empty() && is_separator(path[path.size() - 1]); + bool component_has_sep = !i->empty() && is_separator((*i)[0]); + bool is_root_name = has_root_name(*i); + + if (path_has_sep) { + // Strip separators from beginning of component. + size_t loc = i->find_first_not_of(separators); + StringRef c = i->substr(loc); + + // Append it. + path.append(c.begin(), c.end()); + continue; + } + + if (!component_has_sep && !(path.empty() || is_root_name)) { + // Add a separator. + path.push_back(prefered_separator); + } + + path.append(i->begin(), i->end()); + } +} + +void append(SmallVectorImpl &path, + const_iterator begin, const_iterator end) { + for (; begin != end; ++begin) + path::append(path, *begin); +} + +const StringRef parent_path(StringRef path) { + size_t end_pos = parent_path_end(path); + if (end_pos == StringRef::npos) + return StringRef(); + else + return path.substr(0, end_pos); +} + +void remove_filename(SmallVectorImpl &path) { + size_t end_pos = parent_path_end(StringRef(path.begin(), path.size())); + if (end_pos != StringRef::npos) + path.set_size(end_pos); +} + +void replace_extension(SmallVectorImpl &path, const Twine &extension) { + StringRef p(path.begin(), path.size()); + SmallString<32> ext_storage; + StringRef ext = extension.toStringRef(ext_storage); + + // Erase existing extension. + size_t pos = p.find_last_of('.'); + if (pos != StringRef::npos && pos >= filename_pos(p)) + path.set_size(pos); + + // Append '.' if needed. + if (ext.size() > 0 && ext[0] != '.') + path.push_back('.'); + + // Append extension. + path.append(ext.begin(), ext.end()); +} + +void native(const Twine &path, SmallVectorImpl &result) { + // Clear result. + result.clear(); +#ifdef LLVM_ON_WIN32 + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + result.reserve(p.size()); + for (StringRef::const_iterator i = p.begin(), + e = p.end(); + i != e; + ++i) { + if (*i == '/') + result.push_back('\\'); + else + result.push_back(*i); + } +#else + path.toVector(result); +#endif +} + +const StringRef filename(StringRef path) { + return *(--end(path)); +} + +const StringRef stem(StringRef path) { + StringRef fname = filename(path); + size_t pos = fname.find_last_of('.'); + if (pos == StringRef::npos) + return fname; + else + if ((fname.size() == 1 && fname == ".") || + (fname.size() == 2 && fname == "..")) + return fname; + else + return fname.substr(0, pos); +} + +const StringRef extension(StringRef path) { + StringRef fname = filename(path); + size_t pos = fname.find_last_of('.'); + if (pos == StringRef::npos) + return StringRef(); + else + if ((fname.size() == 1 && fname == ".") || + (fname.size() == 2 && fname == "..")) + return StringRef(); + else + return fname.substr(pos); +} + +bool is_separator(char value) { + switch(value) { +#ifdef LLVM_ON_WIN32 + case '\\': // fall through +#endif + case '/': return true; + default: return false; + } +} + +bool has_root_name(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !root_name(p).empty(); +} + +bool has_root_directory(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !root_directory(p).empty(); +} + +bool has_root_path(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !root_path(p).empty(); +} + +bool has_relative_path(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !relative_path(p).empty(); +} + +bool has_filename(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !filename(p).empty(); +} + +bool has_parent_path(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !parent_path(p).empty(); +} + +bool has_stem(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !stem(p).empty(); +} + +bool has_extension(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + return !extension(p).empty(); +} + +bool is_absolute(const Twine &path) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + bool rootDir = has_root_directory(p), +#ifdef LLVM_ON_WIN32 + rootName = has_root_name(p); +#else + rootName = true; +#endif + + return rootDir && rootName; +} + +bool is_relative(const Twine &path) { + return !is_absolute(path); +} + +} // end namespace path + +namespace fs { + +error_code make_absolute(SmallVectorImpl &path) { + StringRef p(path.data(), path.size()); + + bool rootName = path::has_root_name(p), + rootDirectory = path::has_root_directory(p); + + // Already absolute. + if (rootName && rootDirectory) + return success; + + // All of the following conditions will need the current directory. + SmallString<128> current_dir; + if (error_code ec = current_path(current_dir)) return ec; + + // Relative path. Prepend the current directory. + if (!rootName && !rootDirectory) { + // Append path to the current directory. + path::append(current_dir, p); + // Set path to the result. + path.swap(current_dir); + return success; + } + + if (!rootName && rootDirectory) { + StringRef cdrn = path::root_name(current_dir); + SmallString<128> curDirRootName(cdrn.begin(), cdrn.end()); + path::append(curDirRootName, p); + // Set path to the result. + path.swap(curDirRootName); + return success; + } + + if (rootName && !rootDirectory) { + StringRef pRootName = path::root_name(p); + StringRef bRootDirectory = path::root_directory(current_dir); + StringRef bRelativePath = path::relative_path(current_dir); + StringRef pRelativePath = path::relative_path(p); + + SmallString<128> res; + path::append(res, pRootName, bRootDirectory, bRelativePath, pRelativePath); + path.swap(res); + return success; + } + + llvm_unreachable("All rootName and rootDirectory combinations should have " + "occurred above!"); +} + +error_code create_directories(const Twine &path, bool &existed) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + StringRef parent = path::parent_path(p); + bool parent_exists; + + if (error_code ec = fs::exists(parent, parent_exists)) return ec; + + if (!parent_exists) + return create_directories(parent, existed); + + return create_directory(p, existed); +} + +bool exists(file_status status) { + return status_known(status) && status.type() != file_type::file_not_found; +} + +bool status_known(file_status s) { + return s.type() != file_type::status_error; +} + +bool is_directory(file_status status) { + return status.type() == file_type::directory_file; +} + +error_code is_directory(const Twine &path, bool &result) { + file_status st; + if (error_code ec = status(path, st)) + return ec; + result = is_directory(st); + return success; +} + +bool is_regular_file(file_status status) { + return status.type() == file_type::regular_file; +} + +error_code is_regular_file(const Twine &path, bool &result) { + file_status st; + if (error_code ec = status(path, st)) + return ec; + result = is_regular_file(st); + return success; +} + +bool is_symlink(file_status status) { + return status.type() == file_type::symlink_file; +} + +error_code is_symlink(const Twine &path, bool &result) { + file_status st; + if (error_code ec = status(path, st)) + return ec; + result = is_symlink(st); + return success; +} + +bool is_other(file_status status) { + return exists(status) && + !is_regular_file(status) && + !is_directory(status) && + !is_symlink(status); +} + +void directory_entry::replace_filename(const Twine &filename, file_status st, + file_status symlink_st) { + SmallString<128> path(Path.begin(), Path.end()); + path::remove_filename(path); + path::append(path, filename); + Path = path.str(); + Status = st; + SymlinkStatus = symlink_st; +} + +error_code has_magic(const Twine &path, const Twine &magic, bool &result) { + SmallString<32> MagicStorage; + StringRef Magic = magic.toStringRef(MagicStorage); + SmallString<32> Buffer; + + if (error_code ec = get_magic(path, Magic.size(), Buffer)) { + if (ec == errc::value_too_large) { + // Magic.size() > file_size(Path). + result = false; + return success; + } + return ec; + } + + result = Magic == Buffer; + return success; +} + +error_code identify_magic(const Twine &path, LLVMFileType &result) { + SmallString<32> Magic; + error_code ec = get_magic(path, Magic.capacity(), Magic); + if (ec && ec != errc::value_too_large) + return ec; + + result = IdentifyFileType(Magic.data(), Magic.size()); + return success; +} + +namespace { +error_code remove_all_r(StringRef path, file_type ft, uint32_t &count) { + if (ft == file_type::directory_file) { + // This code would be a lot better with exceptions ;/. + error_code ec; + for (directory_iterator i(path, ec), e; i != e; i.increment(ec)) { + if (ec) return ec; + file_status st; + if (error_code ec = i->status(st)) return ec; + if (error_code ec = remove_all_r(i->path(), st.type(), count)) return ec; + } + bool obviously_this_exists; + if (error_code ec = remove(path, obviously_this_exists)) return ec; + assert(obviously_this_exists); + ++count; // Include the directory itself in the items removed. + } else { + bool obviously_this_exists; + if (error_code ec = remove(path, obviously_this_exists)) return ec; + assert(obviously_this_exists); + ++count; + } + + return success; +} +} // end unnamed namespace + +error_code remove_all(const Twine &path, uint32_t &num_removed) { + SmallString<128> path_storage; + StringRef p = path.toStringRef(path_storage); + + file_status fs; + if (error_code ec = status(path, fs)) + return ec; + num_removed = 0; + return remove_all_r(p, fs.type(), num_removed); +} + +error_code directory_entry::status(file_status &result) const { + return fs::status(Path, result); +} + +} // end namespace fs +} // end namespace sys +} // end namespace llvm + +// Include the truly platform-specific parts. +#if defined(LLVM_ON_UNIX) +#include "Unix/PathV2.inc" +#endif +#if defined(LLVM_ON_WIN32) +#include "Windows/PathV2.inc" +#endif diff --git a/lib/Support/PluginLoader.cpp b/lib/Support/PluginLoader.cpp index 36caecffeede..2924cfa38897 100644 --- a/lib/Support/PluginLoader.cpp +++ b/lib/Support/PluginLoader.cpp @@ -15,8 +15,8 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/DynamicLibrary.h" -#include "llvm/System/Mutex.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/Mutex.h" #include using namespace llvm; diff --git a/lib/Support/PrettyStackTrace.cpp b/lib/Support/PrettyStackTrace.cpp index 3c8a10849d14..a9f4709e4b93 100644 --- a/lib/Support/PrettyStackTrace.cpp +++ b/lib/Support/PrettyStackTrace.cpp @@ -15,8 +15,8 @@ #include "llvm/Config/config.h" // Get autoconf configuration settings #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Signals.h" -#include "llvm/System/ThreadLocal.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/ThreadLocal.h" #include "llvm/ADT/SmallString.h" #ifdef HAVE_CRASHREPORTERCLIENT_H @@ -55,7 +55,7 @@ static void PrintCurStackTrace(raw_ostream &OS) { } // Integrate with crash reporter libraries. -#if defined (__APPLE__) && defined (HAVE_CRASHREPORTERCLIENT_H) +#if defined (__APPLE__) && HAVE_CRASHREPORTERCLIENT_H // If any clients of llvm try to link to libCrashReporterClient.a themselves, // only one crash info struct will be used. extern "C" { @@ -64,7 +64,7 @@ struct crashreporter_annotations_t gCRAnnotations __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION))) = { CRASHREPORTER_ANNOTATIONS_VERSION, 0, 0, 0, 0 }; } -#elif defined (__APPLE__) +#elif defined (__APPLE__) && HAVE_CRASHREPORTER_INFO static const char *__crashreporter_info__ = 0; asm(".desc ___crashreporter_info__, 0x10"); #endif @@ -86,11 +86,11 @@ static void CrashHandler(void *) { } if (!TmpStr.empty()) { -#ifndef HAVE_CRASHREPORTERCLIENT_H - __crashreporter_info__ = strdup(std::string(TmpStr.str()).c_str()); -#else +#ifdef HAVE_CRASHREPORTERCLIENT_H // Cast to void to avoid warning. (void)CRSetCrashLogMessage(std::string(TmpStr.str()).c_str()); +#elif HAVE_CRASHREPORTER_INFO + __crashreporter_info__ = strdup(std::string(TmpStr.str()).c_str()); #endif errs() << TmpStr.str(); } @@ -107,7 +107,7 @@ static bool RegisterCrashPrinter() { PrettyStackTraceEntry::PrettyStackTraceEntry() { // The first time this is called, we register the crash printer. static bool HandlerRegistered = RegisterCrashPrinter(); - HandlerRegistered = HandlerRegistered; + (void)HandlerRegistered; // Link ourselves. NextEntry = PrettyStackTraceHead.get(); @@ -131,4 +131,3 @@ void PrettyStackTraceProgram::print(raw_ostream &OS) const { OS << ArgV[i] << ' '; OS << '\n'; } - diff --git a/lib/Support/Process.cpp b/lib/Support/Process.cpp new file mode 100644 index 000000000000..88ca7c3f220f --- /dev/null +++ b/lib/Support/Process.cpp @@ -0,0 +1,33 @@ +//===-- Process.cpp - Implement OS Process Concept --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header file implements the operating system Process concept. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Process.h" +#include "llvm/Config/config.h" + +namespace llvm { +using namespace sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +} + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/Process.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/Process.inc" +#endif diff --git a/lib/Support/Program.cpp b/lib/Support/Program.cpp new file mode 100644 index 000000000000..01860b082d62 --- /dev/null +++ b/lib/Support/Program.cpp @@ -0,0 +1,56 @@ +//===-- Program.cpp - Implement OS Program Concept --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header file implements the operating system Program concept. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Program.h" +#include "llvm/Config/config.h" +using namespace llvm; +using namespace sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +int +Program::ExecuteAndWait(const Path& path, + const char** args, + const char** envp, + const Path** redirects, + unsigned secondsToWait, + unsigned memoryLimit, + std::string* ErrMsg) { + Program prg; + if (prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg)) + return prg.Wait(path, secondsToWait, ErrMsg); + else + return -1; +} + +void +Program::ExecuteNoWait(const Path& path, + const char** args, + const char** envp, + const Path** redirects, + unsigned memoryLimit, + std::string* ErrMsg) { + Program prg; + prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg); +} + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/Program.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/Program.inc" +#endif diff --git a/lib/Support/README.txt.system b/lib/Support/README.txt.system new file mode 100644 index 000000000000..7a906b8dba4c --- /dev/null +++ b/lib/Support/README.txt.system @@ -0,0 +1,43 @@ +Design Of lib/System +==================== + +The software in this directory is designed to completely shield LLVM from any +and all operating system specific functionality. It is not intended to be a +complete operating system wrapper (such as ACE), but only to provide the +functionality necessary to support LLVM. + +The software located here, of necessity, has very specific and stringent design +rules. Violation of these rules means that cracks in the shield could form and +the primary goal of the library is defeated. By consistently using this library, +LLVM becomes more easily ported to new platforms since the only thing requiring +porting is this library. + +Complete documentation for the library can be found in the file: + llvm/docs/SystemLibrary.html +or at this URL: + http://llvm.org/docs/SystemLibrary.html + +While we recommend that you read the more detailed documentation, for the +impatient, here's a high level summary of the library's requirements. + + 1. No system header files are to be exposed through the interface. + 2. Std C++ and Std C header files are okay to be exposed through the interface. + 3. No exposed system-specific functions. + 4. No exposed system-specific data. + 5. Data in lib/System classes must use only simple C++ intrinsic types. + 6. Errors are handled by returning "true" and setting an optional std::string + 7. Library must not throw any exceptions, period. + 8. Interface functions must not have throw() specifications. + 9. No duplicate function impementations are permitted within an operating + system class. + +To accomplish these requirements, the library has numerous design criteria that +must be satisfied. Here's a high level summary of the library's design criteria: + + 1. No unused functionality (only what LLVM needs) + 2. High-Level Interfaces + 3. Use Opaque Classes + 4. Common Implementations + 5. Multiple Implementations + 6. Minimize Memory Allocation + 7. No Virtual Methods diff --git a/lib/Support/RWMutex.cpp b/lib/Support/RWMutex.cpp new file mode 100644 index 000000000000..fc02f9cf7c11 --- /dev/null +++ b/lib/Support/RWMutex.cpp @@ -0,0 +1,157 @@ +//===- RWMutex.cpp - Reader/Writer Mutual Exclusion Lock --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the llvm::sys::RWMutex class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" +#include "llvm/Support/RWMutex.h" +#include + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +#if !defined(ENABLE_THREADS) || ENABLE_THREADS == 0 +// Define all methods as no-ops if threading is explicitly disabled +namespace llvm { +using namespace sys; +RWMutexImpl::RWMutexImpl() { } +RWMutexImpl::~RWMutexImpl() { } +bool RWMutexImpl::reader_acquire() { return true; } +bool RWMutexImpl::reader_release() { return true; } +bool RWMutexImpl::writer_acquire() { return true; } +bool RWMutexImpl::writer_release() { return true; } +} +#else + +#if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_RWLOCK_INIT) + +#include +#include +#include + +namespace llvm { +using namespace sys; + + +// This variable is useful for situations where the pthread library has been +// compiled with weak linkage for its interface symbols. This allows the +// threading support to be turned off by simply not linking against -lpthread. +// In that situation, the value of pthread_mutex_init will be 0 and +// consequently pthread_enabled will be false. In such situations, all the +// pthread operations become no-ops and the functions all return false. If +// pthread_rwlock_init does have an address, then rwlock support is enabled. +// Note: all LLVM tools will link against -lpthread if its available since it +// is configured into the LIBS variable. +// Note: this line of code generates a warning if pthread_rwlock_init is not +// declared with weak linkage. It's safe to ignore the warning. +static const bool pthread_enabled = true; + +// Construct a RWMutex using pthread calls +RWMutexImpl::RWMutexImpl() + : data_(0) +{ + if (pthread_enabled) + { + // Declare the pthread_rwlock data structures + pthread_rwlock_t* rwlock = + static_cast(malloc(sizeof(pthread_rwlock_t))); + +#ifdef __APPLE__ + // Workaround a bug/mis-feature in Darwin's pthread_rwlock_init. + bzero(rwlock, sizeof(pthread_rwlock_t)); +#endif + + // Initialize the rwlock + int errorcode = pthread_rwlock_init(rwlock, NULL); + (void)errorcode; + assert(errorcode == 0); + + // Assign the data member + data_ = rwlock; + } +} + +// Destruct a RWMutex +RWMutexImpl::~RWMutexImpl() +{ + if (pthread_enabled) + { + pthread_rwlock_t* rwlock = static_cast(data_); + assert(rwlock != 0); + pthread_rwlock_destroy(rwlock); + free(rwlock); + } +} + +bool +RWMutexImpl::reader_acquire() +{ + if (pthread_enabled) + { + pthread_rwlock_t* rwlock = static_cast(data_); + assert(rwlock != 0); + + int errorcode = pthread_rwlock_rdlock(rwlock); + return errorcode == 0; + } else return false; +} + +bool +RWMutexImpl::reader_release() +{ + if (pthread_enabled) + { + pthread_rwlock_t* rwlock = static_cast(data_); + assert(rwlock != 0); + + int errorcode = pthread_rwlock_unlock(rwlock); + return errorcode == 0; + } else return false; +} + +bool +RWMutexImpl::writer_acquire() +{ + if (pthread_enabled) + { + pthread_rwlock_t* rwlock = static_cast(data_); + assert(rwlock != 0); + + int errorcode = pthread_rwlock_wrlock(rwlock); + return errorcode == 0; + } else return false; +} + +bool +RWMutexImpl::writer_release() +{ + if (pthread_enabled) + { + pthread_rwlock_t* rwlock = static_cast(data_); + assert(rwlock != 0); + + int errorcode = pthread_rwlock_unlock(rwlock); + return errorcode == 0; + } else return false; +} + +} + +#elif defined(LLVM_ON_UNIX) +#include "Unix/RWMutex.inc" +#elif defined( LLVM_ON_WIN32) +#include "Windows/RWMutex.inc" +#else +#warning Neither LLVM_ON_UNIX nor LLVM_ON_WIN32 was set in System/Mutex.cpp +#endif +#endif diff --git a/lib/Support/SearchForAddressOfSpecialSymbol.cpp b/lib/Support/SearchForAddressOfSpecialSymbol.cpp new file mode 100644 index 000000000000..d63830185c32 --- /dev/null +++ b/lib/Support/SearchForAddressOfSpecialSymbol.cpp @@ -0,0 +1,73 @@ +//===- SearchForAddressOfSpecialSymbol.cpp - Function addresses -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file pulls the addresses of certain symbols out of the linker. It must +// include as few header files as possible because it declares the symbols as +// void*, which would conflict with the actual symbol type if any header +// declared it. +// +//===----------------------------------------------------------------------===// + +#include + +// Must declare the symbols in the global namespace. +static void *DoSearch(const char* symbolName) { +#define EXPLICIT_SYMBOL(SYM) \ + extern void *SYM; if (!strcmp(symbolName, #SYM)) return &SYM + + // If this is darwin, it has some funky issues, try to solve them here. Some + // important symbols are marked 'private external' which doesn't allow + // SearchForAddressOfSymbol to find them. As such, we special case them here, + // there is only a small handful of them. + +#ifdef __APPLE__ + { + EXPLICIT_SYMBOL(__ashldi3); + EXPLICIT_SYMBOL(__ashrdi3); + EXPLICIT_SYMBOL(__cmpdi2); + EXPLICIT_SYMBOL(__divdi3); + EXPLICIT_SYMBOL(__fixdfdi); + EXPLICIT_SYMBOL(__fixsfdi); + EXPLICIT_SYMBOL(__fixunsdfdi); + EXPLICIT_SYMBOL(__fixunssfdi); + EXPLICIT_SYMBOL(__floatdidf); + EXPLICIT_SYMBOL(__floatdisf); + EXPLICIT_SYMBOL(__lshrdi3); + EXPLICIT_SYMBOL(__moddi3); + EXPLICIT_SYMBOL(__udivdi3); + EXPLICIT_SYMBOL(__umoddi3); + + // __eprintf is sometimes used for assert() handling on x86. + // + // FIXME: Currently disabled when using Clang, as we don't always have our + // runtime support libraries available. +#ifndef __clang__ +#ifdef __i386__ + EXPLICIT_SYMBOL(__eprintf); +#endif +#endif + } +#endif + +#ifdef __CYGWIN__ + { + EXPLICIT_SYMBOL(_alloca); + EXPLICIT_SYMBOL(__main); + } +#endif + +#undef EXPLICIT_SYMBOL + return 0; +} + +namespace llvm { +void *SearchForAddressOfSpecialSymbol(const char* symbolName) { + return DoSearch(symbolName); +} +} // namespace llvm diff --git a/lib/Support/Signals.cpp b/lib/Support/Signals.cpp new file mode 100644 index 000000000000..a3af37d5fe6a --- /dev/null +++ b/lib/Support/Signals.cpp @@ -0,0 +1,34 @@ +//===- Signals.cpp - Signal Handling support --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines some helpful functions for dealing with the possibility of +// Unix signals occuring while your program is running. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Signals.h" +#include "llvm/Config/config.h" + +namespace llvm { +using namespace sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +} + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/Signals.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/Signals.inc" +#endif diff --git a/lib/Support/SourceMgr.cpp b/lib/Support/SourceMgr.cpp index da5681c5bc09..ef099163c221 100644 --- a/lib/Support/SourceMgr.cpp +++ b/lib/Support/SourceMgr.cpp @@ -13,9 +13,12 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/Twine.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/ADT/OwningPtr.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" using namespace llvm; namespace { @@ -47,18 +50,18 @@ SourceMgr::~SourceMgr() { /// ~0, otherwise it returns the buffer ID of the stacked file. unsigned SourceMgr::AddIncludeFile(const std::string &Filename, SMLoc IncludeLoc) { - - MemoryBuffer *NewBuf = MemoryBuffer::getFile(Filename.c_str()); + OwningPtr NewBuf; + MemoryBuffer::getFile(Filename.c_str(), NewBuf); // If the file didn't exist directly, see if it's in an include path. for (unsigned i = 0, e = IncludeDirectories.size(); i != e && !NewBuf; ++i) { std::string IncFile = IncludeDirectories[i] + "/" + Filename; - NewBuf = MemoryBuffer::getFile(IncFile.c_str()); + MemoryBuffer::getFile(IncFile.c_str(), NewBuf); } if (NewBuf == 0) return ~0U; - return AddNewSourceBuffer(NewBuf, IncludeLoc); + return AddNewSourceBuffer(NewBuf.take(), IncludeLoc); } @@ -135,7 +138,7 @@ void SourceMgr::PrintIncludeStack(SMLoc IncludeLoc, raw_ostream &OS) const { /// /// @param Type - If non-null, the kind of message (e.g., "error") which is /// prefixed to the message. -SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, const std::string &Msg, +SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, const Twine &Msg, const char *Type, bool ShowLine) const { // First thing to do: find the current buffer containing the specified @@ -162,27 +165,25 @@ SMDiagnostic SourceMgr::GetMessage(SMLoc Loc, const std::string &Msg, } std::string PrintedMsg; - if (Type) { - PrintedMsg = Type; - PrintedMsg += ": "; - } - PrintedMsg += Msg; + raw_string_ostream OS(PrintedMsg); + if (Type) + OS << Type << ": "; + OS << Msg; return SMDiagnostic(*this, Loc, CurMB->getBufferIdentifier(), FindLineNumber(Loc, CurBuf), - Loc.getPointer()-LineStart, PrintedMsg, + Loc.getPointer()-LineStart, OS.str(), LineStr, ShowLine); } -void SourceMgr::PrintMessage(SMLoc Loc, const std::string &Msg, +void SourceMgr::PrintMessage(SMLoc Loc, const Twine &Msg, const char *Type, bool ShowLine) const { // Report the message with the diagnostic handler if present. if (DiagHandler) { - DiagHandler(GetMessage(Loc, Msg, Type, ShowLine), - DiagContext, DiagLocCookie); + DiagHandler(GetMessage(Loc, Msg, Type, ShowLine), DiagContext); return; } - + raw_ostream &OS = errs(); int CurBuf = FindBufferContainingLoc(Loc); diff --git a/lib/Support/Statistic.cpp b/lib/Support/Statistic.cpp index e32ab74a2d4c..f0ed62690fd3 100644 --- a/lib/Support/Statistic.cpp +++ b/lib/Support/Statistic.cpp @@ -26,7 +26,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Mutex.h" +#include "llvm/Support/Mutex.h" #include "llvm/ADT/StringExtras.h" #include #include diff --git a/lib/Support/StringMap.cpp b/lib/Support/StringMap.cpp index 6f28277890e3..90ec29950262 100644 --- a/lib/Support/StringMap.cpp +++ b/lib/Support/StringMap.cpp @@ -155,7 +155,7 @@ int StringMapImpl::FindKey(StringRef Key) const { void StringMapImpl::RemoveKey(StringMapEntryBase *V) { const char *VStr = (char*)V + ItemSize; StringMapEntryBase *V2 = RemoveKey(StringRef(VStr, V->getKeyLength())); - V2 = V2; + (void)V2; assert(V == V2 && "Didn't find key?"); } diff --git a/lib/Support/StringRef.cpp b/lib/Support/StringRef.cpp index 46f26b242aac..539805196450 100644 --- a/lib/Support/StringRef.cpp +++ b/lib/Support/StringRef.cpp @@ -9,6 +9,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/APInt.h" +#include "llvm/ADT/OwningPtr.h" #include using namespace llvm; @@ -67,8 +68,9 @@ int StringRef::compare_numeric(StringRef RHS) const { } // Compute the edit distance between the two given strings. -unsigned StringRef::edit_distance(llvm::StringRef Other, - bool AllowReplacements) { +unsigned StringRef::edit_distance(llvm::StringRef Other, + bool AllowReplacements, + unsigned MaxEditDistance) { // The algorithm implemented below is the "classic" // dynamic-programming algorithm for computing the Levenshtein // distance, which is described here: @@ -83,17 +85,21 @@ unsigned StringRef::edit_distance(llvm::StringRef Other, const unsigned SmallBufferSize = 64; unsigned SmallBuffer[SmallBufferSize]; - unsigned *Allocated = 0; + llvm::OwningArrayPtr Allocated; unsigned *previous = SmallBuffer; - if (2*(n + 1) > SmallBufferSize) - Allocated = previous = new unsigned [2*(n+1)]; + if (2*(n + 1) > SmallBufferSize) { + previous = new unsigned [2*(n+1)]; + Allocated.reset(previous); + } unsigned *current = previous + (n + 1); - - for (unsigned i = 0; i <= n; ++i) + + for (unsigned i = 0; i <= n; ++i) previous[i] = i; for (size_type y = 1; y <= m; ++y) { current[0] = y; + unsigned BestThisRow = current[0]; + for (size_type x = 1; x <= n; ++x) { if (AllowReplacements) { current[x] = min(previous[x-1] + ((*this)[y-1] == Other[x-1]? 0u:1u), @@ -103,16 +109,18 @@ unsigned StringRef::edit_distance(llvm::StringRef Other, if ((*this)[y-1] == Other[x-1]) current[x] = previous[x-1]; else current[x] = min(current[x-1], previous[x]) + 1; } + BestThisRow = min(BestThisRow, current[x]); } - + + if (MaxEditDistance && BestThisRow > MaxEditDistance) + return MaxEditDistance + 1; + unsigned *tmp = current; current = previous; previous = tmp; } unsigned Result = previous[n]; - delete [] Allocated; - return Result; } @@ -192,6 +200,21 @@ StringRef::size_type StringRef::find_first_not_of(StringRef Chars, return npos; } +/// find_last_of - Find the last character in the string that is in \arg C, +/// or npos if not found. +/// +/// Note: O(size() + Chars.size()) +StringRef::size_type StringRef::find_last_of(StringRef Chars, + size_t From) const { + std::bitset<1 << CHAR_BIT> CharBits; + for (size_type i = 0; i != Chars.size(); ++i) + CharBits.set((unsigned char)Chars[i]); + + for (size_type i = min(From, Length) - 1, e = -1; i != e; --i) + if (CharBits.test((unsigned char)Data[i])) + return i; + return npos; +} //===----------------------------------------------------------------------===// // Helpful Algorithms @@ -232,10 +255,10 @@ static bool GetAsUnsignedInteger(StringRef Str, unsigned Radix, // Autosense radix if not specified. if (Radix == 0) Radix = GetAutoSenseRadix(Str); - + // Empty strings (after the radix autosense) are invalid. if (Str.empty()) return true; - + // Parse all the bytes of the string given this radix. Watch for overflow. Result = 0; while (!Str.empty()) { @@ -248,23 +271,23 @@ static bool GetAsUnsignedInteger(StringRef Str, unsigned Radix, CharVal = Str[0]-'A'+10; else return true; - + // If the parsed value is larger than the integer radix, the string is // invalid. if (CharVal >= Radix) return true; - + // Add in this character. unsigned long long PrevResult = Result; Result = Result*Radix+CharVal; - + // Check for overflow. if (Result < PrevResult) return true; Str = Str.substr(1); } - + return false; } @@ -275,7 +298,7 @@ bool StringRef::getAsInteger(unsigned Radix, unsigned long long &Result) const { bool StringRef::getAsInteger(unsigned Radix, long long &Result) const { unsigned long long ULLVal; - + // Handle positive strings first. if (empty() || front() != '-') { if (GetAsUnsignedInteger(*this, Radix, ULLVal) || @@ -285,7 +308,7 @@ bool StringRef::getAsInteger(unsigned Radix, long long &Result) const { Result = ULLVal; return false; } - + // Get the positive part of the value. if (GetAsUnsignedInteger(substr(1), Radix, ULLVal) || // Reject values so large they'd overflow as negative signed, but allow @@ -293,7 +316,7 @@ bool StringRef::getAsInteger(unsigned Radix, long long &Result) const { // on signed overflow. (long long)-ULLVal > 0) return true; - + Result = -ULLVal; return false; } @@ -314,7 +337,7 @@ bool StringRef::getAsInteger(unsigned Radix, unsigned &Result) const { return true; Result = Val; return false; -} +} bool StringRef::getAsInteger(unsigned Radix, APInt &Result) const { StringRef Str = *this; @@ -324,7 +347,7 @@ bool StringRef::getAsInteger(unsigned Radix, APInt &Result) const { Radix = GetAutoSenseRadix(Str); assert(Radix > 1 && Radix <= 36); - + // Empty strings (after the radix autosense) are invalid. if (Str.empty()) return true; @@ -348,7 +371,7 @@ bool StringRef::getAsInteger(unsigned Radix, APInt &Result) const { if (BitWidth < Result.getBitWidth()) BitWidth = Result.getBitWidth(); // don't shrink the result else - Result.zext(BitWidth); + Result = Result.zext(BitWidth); APInt RadixAP, CharAP; // unused unless !IsPowerOf2Radix if (!IsPowerOf2Radix) { @@ -369,12 +392,12 @@ bool StringRef::getAsInteger(unsigned Radix, APInt &Result) const { CharVal = Str[0]-'A'+10; else return true; - + // If the parsed value is larger than the integer radix, the string is // invalid. if (CharVal >= Radix) return true; - + // Add in this character. if (IsPowerOf2Radix) { Result <<= Log2Radix; @@ -387,6 +410,6 @@ bool StringRef::getAsInteger(unsigned Radix, APInt &Result) const { Str = Str.substr(1); } - + return false; } diff --git a/lib/Support/SystemUtils.cpp b/lib/Support/SystemUtils.cpp index c8b260c2e3dd..54b5e97bfe18 100644 --- a/lib/Support/SystemUtils.cpp +++ b/lib/Support/SystemUtils.cpp @@ -13,8 +13,8 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/SystemUtils.h" -#include "llvm/System/Process.h" -#include "llvm/System/Program.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -23,43 +23,33 @@ bool llvm::CheckBitcodeOutputToConsole(raw_ostream &stream_to_check, if (stream_to_check.is_displayed()) { if (print_warning) { errs() << "WARNING: You're attempting to print out a bitcode file.\n" - << "This is inadvisable as it may cause display problems. If\n" - << "you REALLY want to taste LLVM bitcode first-hand, you\n" - << "can force output with the `-f' option.\n\n"; + "This is inadvisable as it may cause display problems. If\n" + "you REALLY want to taste LLVM bitcode first-hand, you\n" + "can force output with the `-f' option.\n\n"; } return true; } return false; } -/// FindExecutable - Find a named executable, giving the argv[0] of program -/// being executed. This allows us to find another LLVM tool if it is built in -/// the same directory. If the executable cannot be found, return an -/// empty string. +/// PrependMainExecutablePath - Prepend the path to the program being executed +/// to \p ExeName, given the value of argv[0] and the address of main() +/// itself. This allows us to find another LLVM tool if it is built in the same +/// directory. An empty string is returned on error; note that this function +/// just mainpulates the path and doesn't check for executability. /// @brief Find a named executable. -#undef FindExecutable // needed on windows :( -sys::Path llvm::FindExecutable(const std::string &ExeName, - const char *Argv0, void *MainAddr) { +sys::Path llvm::PrependMainExecutablePath(const std::string &ExeName, + const char *Argv0, void *MainAddr) { // Check the directory that the calling program is in. We can do // this if ProgramPath contains at least one / character, indicating that it // is a relative path to the executable itself. sys::Path Result = sys::Path::GetMainExecutable(Argv0, MainAddr); Result.eraseComponent(); + if (!Result.isEmpty()) { Result.appendComponent(ExeName); - if (Result.canExecute()) - return Result; - // If the path is absolute (and it usually is), call FindProgramByName to - // allow it to try platform-specific logic, such as appending a .exe suffix - // on Windows. Don't do this if we somehow have a relative path, because - // we don't want to go searching the PATH and accidentally find an unrelated - // version of the program. - if (Result.isAbsolute()) { - Result = sys::Program::FindProgramByName(Result.str()); - if (!Result.empty()) - return Result; - } + Result.appendSuffix(sys::Path::GetEXESuffix()); } - return sys::Path(); + return Result; } diff --git a/lib/Support/TargetRegistry.cpp b/lib/Support/TargetRegistry.cpp index 5896447f5ea5..293a5d7a0168 100644 --- a/lib/Support/TargetRegistry.cpp +++ b/lib/Support/TargetRegistry.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Target/TargetRegistry.h" -#include "llvm/System/Host.h" +#include "llvm/Support/Host.h" #include using namespace llvm; diff --git a/lib/Support/ThreadLocal.cpp b/lib/Support/ThreadLocal.cpp new file mode 100644 index 000000000000..6b43048da155 --- /dev/null +++ b/lib/Support/ThreadLocal.cpp @@ -0,0 +1,84 @@ +//===- ThreadLocal.cpp - Thread Local Data ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the llvm::sys::ThreadLocal class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" +#include "llvm/Support/ThreadLocal.h" + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +#if !defined(ENABLE_THREADS) || ENABLE_THREADS == 0 +// Define all methods as no-ops if threading is explicitly disabled +namespace llvm { +using namespace sys; +ThreadLocalImpl::ThreadLocalImpl() { } +ThreadLocalImpl::~ThreadLocalImpl() { } +void ThreadLocalImpl::setInstance(const void* d) { data = const_cast(d);} +const void* ThreadLocalImpl::getInstance() { return data; } +void ThreadLocalImpl::removeInstance() { data = 0; } +} +#else + +#if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_GETSPECIFIC) + +#include +#include +#include + +namespace llvm { +using namespace sys; + +ThreadLocalImpl::ThreadLocalImpl() : data(0) { + pthread_key_t* key = new pthread_key_t; + int errorcode = pthread_key_create(key, NULL); + assert(errorcode == 0); + (void) errorcode; + data = (void*)key; +} + +ThreadLocalImpl::~ThreadLocalImpl() { + pthread_key_t* key = static_cast(data); + int errorcode = pthread_key_delete(*key); + assert(errorcode == 0); + (void) errorcode; + delete key; +} + +void ThreadLocalImpl::setInstance(const void* d) { + pthread_key_t* key = static_cast(data); + int errorcode = pthread_setspecific(*key, d); + assert(errorcode == 0); + (void) errorcode; +} + +const void* ThreadLocalImpl::getInstance() { + pthread_key_t* key = static_cast(data); + return pthread_getspecific(*key); +} + +void ThreadLocalImpl::removeInstance() { + setInstance(0); +} + +} + +#elif defined(LLVM_ON_UNIX) +#include "Unix/ThreadLocal.inc" +#elif defined( LLVM_ON_WIN32) +#include "Windows/ThreadLocal.inc" +#else +#warning Neither LLVM_ON_UNIX nor LLVM_ON_WIN32 was set in System/ThreadLocal.cpp +#endif +#endif diff --git a/lib/Support/Threading.cpp b/lib/Support/Threading.cpp new file mode 100644 index 000000000000..29579567ac6c --- /dev/null +++ b/lib/Support/Threading.cpp @@ -0,0 +1,116 @@ +//===-- llvm/Support/Threading.cpp- Control multithreading mode --*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements llvm_start_multithreaded() and friends. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Threading.h" +#include "llvm/Support/Atomic.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Config/config.h" +#include + +using namespace llvm; + +static bool multithreaded_mode = false; + +static sys::Mutex* global_lock = 0; + +bool llvm::llvm_start_multithreaded() { +#ifdef LLVM_MULTITHREADED + assert(!multithreaded_mode && "Already multithreaded!"); + multithreaded_mode = true; + global_lock = new sys::Mutex(true); + + // We fence here to ensure that all initialization is complete BEFORE we + // return from llvm_start_multithreaded(). + sys::MemoryFence(); + return true; +#else + return false; +#endif +} + +void llvm::llvm_stop_multithreaded() { +#ifdef LLVM_MULTITHREADED + assert(multithreaded_mode && "Not currently multithreaded!"); + + // We fence here to insure that all threaded operations are complete BEFORE we + // return from llvm_stop_multithreaded(). + sys::MemoryFence(); + + multithreaded_mode = false; + delete global_lock; +#endif +} + +bool llvm::llvm_is_multithreaded() { + return multithreaded_mode; +} + +void llvm::llvm_acquire_global_lock() { + if (multithreaded_mode) global_lock->acquire(); +} + +void llvm::llvm_release_global_lock() { + if (multithreaded_mode) global_lock->release(); +} + +#if defined(LLVM_MULTITHREADED) && defined(HAVE_PTHREAD_H) +#include + +struct ThreadInfo { + void (*UserFn)(void *); + void *UserData; +}; +static void *ExecuteOnThread_Dispatch(void *Arg) { + ThreadInfo *TI = reinterpret_cast(Arg); + TI->UserFn(TI->UserData); + return 0; +} + +void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData, + unsigned RequestedStackSize) { + ThreadInfo Info = { Fn, UserData }; + pthread_attr_t Attr; + pthread_t Thread; + + // Construct the attributes object. + if (::pthread_attr_init(&Attr) != 0) + return; + + // Set the requested stack size, if given. + if (RequestedStackSize != 0) { + if (::pthread_attr_setstacksize(&Attr, RequestedStackSize) != 0) + goto error; + } + + // Construct and execute the thread. + if (::pthread_create(&Thread, &Attr, ExecuteOnThread_Dispatch, &Info) != 0) + goto error; + + // Wait for the thread and clean up. + ::pthread_join(Thread, 0); + + error: + ::pthread_attr_destroy(&Attr); +} + +#else + +// No non-pthread implementation, currently. + +void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData, + unsigned RequestedStackSize) { + (void) RequestedStackSize; + Fn(UserData); +} + +#endif diff --git a/lib/Support/TimeValue.cpp b/lib/Support/TimeValue.cpp new file mode 100644 index 000000000000..1a0f7bc36394 --- /dev/null +++ b/lib/Support/TimeValue.cpp @@ -0,0 +1,57 @@ +//===-- TimeValue.cpp - Implement OS TimeValue Concept ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the operating system TimeValue concept. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/TimeValue.h" +#include "llvm/Config/config.h" + +namespace llvm { +using namespace sys; + +const TimeValue TimeValue::MinTime = TimeValue ( INT64_MIN,0 ); +const TimeValue TimeValue::MaxTime = TimeValue ( INT64_MAX,0 ); +const TimeValue TimeValue::ZeroTime = TimeValue ( 0,0 ); +const TimeValue TimeValue::PosixZeroTime = TimeValue ( -946684800,0 ); +const TimeValue TimeValue::Win32ZeroTime = TimeValue ( -12591158400ULL,0 ); + +void +TimeValue::normalize( void ) { + if ( nanos_ >= NANOSECONDS_PER_SECOND ) { + do { + seconds_++; + nanos_ -= NANOSECONDS_PER_SECOND; + } while ( nanos_ >= NANOSECONDS_PER_SECOND ); + } else if (nanos_ <= -NANOSECONDS_PER_SECOND ) { + do { + seconds_--; + nanos_ += NANOSECONDS_PER_SECOND; + } while (nanos_ <= -NANOSECONDS_PER_SECOND); + } + + if (seconds_ >= 1 && nanos_ < 0) { + seconds_--; + nanos_ += NANOSECONDS_PER_SECOND; + } else if (seconds_ < 0 && nanos_ > 0) { + seconds_++; + nanos_ -= NANOSECONDS_PER_SECOND; + } +} + +} + +/// Include the platform specific portion of TimeValue class +#ifdef LLVM_ON_UNIX +#include "Unix/TimeValue.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/TimeValue.inc" +#endif diff --git a/lib/Support/Timer.cpp b/lib/Support/Timer.cpp index 44ee1777cb57..a9ed5eecfa7e 100644 --- a/lib/Support/Timer.cpp +++ b/lib/Support/Timer.cpp @@ -17,8 +17,8 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Format.h" -#include "llvm/System/Mutex.h" -#include "llvm/System/Process.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Support/Process.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/StringMap.h" using namespace llvm; diff --git a/lib/Support/ToolOutputFile.cpp b/lib/Support/ToolOutputFile.cpp new file mode 100644 index 000000000000..e7ca927ea537 --- /dev/null +++ b/lib/Support/ToolOutputFile.cpp @@ -0,0 +1,43 @@ +//===--- ToolOutputFile.cpp - Implement the tool_output_file class --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This implements the tool_output_file class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/Signals.h" +using namespace llvm; + +tool_output_file::CleanupInstaller::CleanupInstaller(const char *filename) + : Filename(filename), Keep(false) { + // Arrange for the file to be deleted if the process is killed. + if (Filename != "-") + sys::RemoveFileOnSignal(sys::Path(Filename)); +} + +tool_output_file::CleanupInstaller::~CleanupInstaller() { + // Delete the file if the client hasn't told us not to. + if (!Keep && Filename != "-") + sys::Path(Filename).eraseFromDisk(); + + // Ok, the file is successfully written and closed, or deleted. There's no + // further need to clean it up on signals. + if (Filename != "-") + sys::DontRemoveFileOnSignal(sys::Path(Filename)); +} + +tool_output_file::tool_output_file(const char *filename, std::string &ErrorInfo, + unsigned Flags) + : Installer(filename), + OS(filename, ErrorInfo, Flags) { + // If open fails, no cleanup is needed. + if (!ErrorInfo.empty()) + Installer.Keep = true; +} diff --git a/lib/Support/Triple.cpp b/lib/Support/Triple.cpp index 3a95b65e6900..36edf6eefa70 100644 --- a/lib/Support/Triple.cpp +++ b/lib/Support/Triple.cpp @@ -10,6 +10,7 @@ #include "llvm/ADT/Triple.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Twine.h" #include #include @@ -21,7 +22,7 @@ const char *Triple::getArchTypeName(ArchType Kind) { switch (Kind) { case InvalidArch: return ""; case UnknownArch: return "unknown"; - + case alpha: return "alpha"; case arm: return "arm"; case bfin: return "bfin"; @@ -29,7 +30,6 @@ const char *Triple::getArchTypeName(ArchType Kind) { case mips: return "mips"; case mipsel: return "mipsel"; case msp430: return "msp430"; - case pic16: return "pic16"; case ppc64: return "powerpc64"; case ppc: return "powerpc"; case sparc: return "sparc"; @@ -41,6 +41,7 @@ const char *Triple::getArchTypeName(ArchType Kind) { case x86_64: return "x86_64"; case xcore: return "xcore"; case mblaze: return "mblaze"; + case ptx: return "ptx"; } return ""; @@ -70,7 +71,10 @@ const char *Triple::getArchTypePrefix(ArchType Kind) { case x86: case x86_64: return "x86"; + case xcore: return "xcore"; + + case ptx: return "ptx"; } } @@ -97,7 +101,6 @@ const char *Triple::getOSTypeName(OSType Kind) { case Linux: return "linux"; case Lv2: return "lv2"; case MinGW32: return "mingw32"; - case MinGW64: return "mingw64"; case NetBSD: return "netbsd"; case OpenBSD: return "openbsd"; case Psp: return "psp"; @@ -110,6 +113,18 @@ const char *Triple::getOSTypeName(OSType Kind) { return ""; } +const char *Triple::getEnvironmentTypeName(EnvironmentType Kind) { + switch (Kind) { + case UnknownEnvironment: return "unknown"; + case GNU: return "gnu"; + case GNUEABI: return "gnueabi"; + case EABI: return "eabi"; + case MachO: return "macho"; + } + + return ""; +} + Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { if (Name == "alpha") return alpha; @@ -125,8 +140,6 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { return mipsel; if (Name == "msp430") return msp430; - if (Name == "pic16") - return pic16; if (Name == "ppc64") return ppc64; if (Name == "ppc") @@ -149,6 +162,8 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) { return x86_64; if (Name == "xcore") return xcore; + if (Name == "ptx") + return ptx; return UnknownArch; } @@ -187,6 +202,9 @@ Triple::ArchType Triple::getArchTypeForDarwinArchName(StringRef Str) { Str == "armv6" || Str == "armv7") return Triple::arm; + if (Str == "ptx") + return Triple::ptx; + return Triple::UnknownArch; } @@ -210,28 +228,29 @@ const char *Triple::getArchNameForAssembler() { return "arm"; if (Str == "armv4t" || Str == "thumbv4t") return "armv4t"; - if (Str == "armv5" || Str == "armv5e" || Str == "thumbv5" || Str == "thumbv5e") + if (Str == "armv5" || Str == "armv5e" || Str == "thumbv5" + || Str == "thumbv5e") return "armv5"; if (Str == "armv6" || Str == "thumbv6") return "armv6"; if (Str == "armv7" || Str == "thumbv7") return "armv7"; + if (Str == "ptx") + return "ptx"; return NULL; } // Triple::ArchType Triple::ParseArch(StringRef ArchName) { - if (ArchName.size() == 4 && ArchName[0] == 'i' && - ArchName[2] == '8' && ArchName[3] == '6' && + if (ArchName.size() == 4 && ArchName[0] == 'i' && + ArchName[2] == '8' && ArchName[3] == '6' && ArchName[1] - '3' < 6) // i[3-9]86 return x86; else if (ArchName == "amd64" || ArchName == "x86_64") return x86_64; else if (ArchName == "bfin") return bfin; - else if (ArchName == "pic16") - return pic16; else if (ArchName == "powerpc") return ppc; else if ((ArchName == "powerpc64") || (ArchName == "ppu")) @@ -266,6 +285,8 @@ Triple::ArchType Triple::ParseArch(StringRef ArchName) { return tce; else if (ArchName == "xcore") return xcore; + else if (ArchName == "ptx") + return ptx; else return UnknownArch; } @@ -296,8 +317,6 @@ Triple::OSType Triple::ParseOS(StringRef OSName) { return Lv2; else if (OSName.startswith("mingw32")) return MinGW32; - else if (OSName.startswith("mingw64")) - return MinGW64; else if (OSName.startswith("netbsd")) return NetBSD; else if (OSName.startswith("openbsd")) @@ -316,12 +335,26 @@ Triple::OSType Triple::ParseOS(StringRef OSName) { return UnknownOS; } +Triple::EnvironmentType Triple::ParseEnvironment(StringRef EnvironmentName) { + if (EnvironmentName.startswith("eabi")) + return EABI; + else if (EnvironmentName.startswith("gnueabi")) + return GNUEABI; + else if (EnvironmentName.startswith("gnu")) + return GNU; + else if (EnvironmentName.startswith("macho")) + return MachO; + else + return UnknownEnvironment; +} + void Triple::Parse() const { assert(!isInitialized() && "Invalid parse call."); Arch = ParseArch(getArchName()); Vendor = ParseVendor(getVendorName()); OS = ParseOS(getOSName()); + Environment = ParseEnvironment(getEnvironmentName()); assert(isInitialized() && "Failed to initialize!"); } @@ -348,24 +381,28 @@ std::string Triple::normalize(StringRef Str) { OSType OS = UnknownOS; if (Components.size() > 2) OS = ParseOS(Components[2]); + EnvironmentType Environment = UnknownEnvironment; + if (Components.size() > 3) + Environment = ParseEnvironment(Components[3]); // Note which components are already in their final position. These will not // be moved. - bool Found[3]; + bool Found[4]; Found[0] = Arch != UnknownArch; Found[1] = Vendor != UnknownVendor; Found[2] = OS != UnknownOS; + Found[3] = Environment != UnknownEnvironment; // If they are not there already, permute the components into their canonical // positions by seeing if they parse as a valid architecture, and if so moving // the component to the architecture position etc. - for (unsigned Pos = 0; Pos != 3; ++Pos) { + for (unsigned Pos = 0; Pos != array_lengthof(Found); ++Pos) { if (Found[Pos]) continue; // Already in the canonical position. for (unsigned Idx = 0; Idx != Components.size(); ++Idx) { // Do not reparse any components that already matched. - if (Idx < 3 && Found[Idx]) + if (Idx < array_lengthof(Found) && Found[Idx]) continue; // Does this component parse as valid for the target position? @@ -386,6 +423,10 @@ std::string Triple::normalize(StringRef Str) { OS = ParseOS(Comp); Valid = OS != UnknownOS; break; + case 3: + Environment = ParseEnvironment(Comp); + Valid = Environment != UnknownEnvironment; + break; } if (!Valid) continue; // Nope, try the next component. @@ -404,7 +445,7 @@ std::string Triple::normalize(StringRef Str) { // components to the right. for (unsigned i = Pos; !CurrentComponent.empty(); ++i) { // Skip over any fixed components. - while (i < 3 && Found[i]) ++i; + while (i < array_lengthof(Found) && Found[i]) ++i; // Place the component at the new position, getting the component // that was at this position - it will be moved right. std::swap(CurrentComponent, Components[i]); @@ -416,22 +457,23 @@ std::string Triple::normalize(StringRef Str) { do { // Insert one empty component at Idx. StringRef CurrentComponent(""); // The empty component. - for (unsigned i = Idx; i < Components.size(); ++i) { - // Skip over any fixed components. - while (i < 3 && Found[i]) ++i; + for (unsigned i = Idx; i < Components.size();) { // Place the component at the new position, getting the component // that was at this position - it will be moved right. std::swap(CurrentComponent, Components[i]); // If it was placed on top of an empty component then we are done. if (CurrentComponent.empty()) break; + // Advance to the next component, skipping any fixed components. + while (++i < array_lengthof(Found) && Found[i]) + ; } // The last component was pushed off the end - append it. if (!CurrentComponent.empty()) Components.push_back(CurrentComponent); // Advance Idx to the component's new position. - while (++Idx < 3 && Found[Idx]) {} + while (++Idx < array_lengthof(Found) && Found[Idx]) {} } while (Idx < Pos); // Add more until the final position is reached. } assert(Pos < Components.size() && Components[Pos] == Comp && @@ -482,17 +524,17 @@ StringRef Triple::getOSAndEnvironmentName() const { static unsigned EatNumber(StringRef &Str) { assert(!Str.empty() && Str[0] >= '0' && Str[0] <= '9' && "Not a number"); unsigned Result = Str[0]-'0'; - + // Eat the digit. Str = Str.substr(1); - + // Handle "darwin11". if (Result == 1 && !Str.empty() && Str[0] >= '0' && Str[0] <= '9') { Result = Result*10 + (Str[0] - '0'); // Eat the digit. Str = Str.substr(1); } - + return Result; } @@ -505,10 +547,10 @@ void Triple::getDarwinNumber(unsigned &Maj, unsigned &Min, assert(getOS() == Darwin && "Not a darwin target triple!"); StringRef OSName = getOSName(); assert(OSName.startswith("darwin") && "Unknown darwin target triple!"); - + // Strip off "darwin". OSName = OSName.substr(6); - + Maj = Min = Revision = 0; if (OSName.empty() || OSName[0] < '0' || OSName[0] > '9') @@ -517,27 +559,27 @@ void Triple::getDarwinNumber(unsigned &Maj, unsigned &Min, // The major version is the first digit. Maj = EatNumber(OSName); if (OSName.empty()) return; - + // Handle minor version: 10.4.9 -> darwin8.9. if (OSName[0] != '.') return; - + // Eat the '.'. OSName = OSName.substr(1); if (OSName.empty() || OSName[0] < '0' || OSName[0] > '9') return; - + Min = EatNumber(OSName); if (OSName.empty()) return; // Handle revision darwin8.9.1 if (OSName[0] != '.') return; - + // Eat the '.'. OSName = OSName.substr(1); - + if (OSName.empty() || OSName[0] < '0' || OSName[0] > '9') return; @@ -561,6 +603,10 @@ void Triple::setOS(OSType Kind) { setOSName(getOSTypeName(Kind)); } +void Triple::setEnvironment(EnvironmentType Kind) { + setEnvironmentName(getEnvironmentTypeName(Kind)); +} + void Triple::setArchName(StringRef Str) { // Work around a miscompilation bug for Twines in gcc 4.0.3. SmallString<64> Triple; diff --git a/lib/Support/Twine.cpp b/lib/Support/Twine.cpp index b3ea0132e4ac..75cea2961a9d 100644 --- a/lib/Support/Twine.cpp +++ b/lib/Support/Twine.cpp @@ -30,22 +30,42 @@ StringRef Twine::toStringRef(SmallVectorImpl &Out) const { return StringRef(Out.data(), Out.size()); } -void Twine::printOneChild(raw_ostream &OS, const void *Ptr, +StringRef Twine::toNullTerminatedStringRef(SmallVectorImpl &Out) const { + if (isUnary()) { + switch (getLHSKind()) { + case CStringKind: + // Already null terminated, yay! + return StringRef(static_cast(LHS)); + case StdStringKind: { + const std::string *str = static_cast(LHS); + return StringRef(str->c_str(), str->size()); + } + default: + break; + } + } + toVector(Out); + Out.push_back(0); + Out.pop_back(); + return StringRef(Out.data(), Out.size()); +} + +void Twine::printOneChild(raw_ostream &OS, const void *Ptr, NodeKind Kind) const { switch (Kind) { case Twine::NullKind: break; case Twine::EmptyKind: break; case Twine::TwineKind: - static_cast(Ptr)->print(OS); + static_cast(Ptr)->print(OS); break; - case Twine::CStringKind: - OS << static_cast(Ptr); + case Twine::CStringKind: + OS << static_cast(Ptr); break; case Twine::StdStringKind: - OS << *static_cast(Ptr); + OS << *static_cast(Ptr); break; case Twine::StringRefKind: - OS << *static_cast(Ptr); + OS << *static_cast(Ptr); break; case Twine::DecUIKind: OS << (unsigned)(uintptr_t)Ptr; @@ -71,7 +91,7 @@ void Twine::printOneChild(raw_ostream &OS, const void *Ptr, } } -void Twine::printOneChildRepr(raw_ostream &OS, const void *Ptr, +void Twine::printOneChildRepr(raw_ostream &OS, const void *Ptr, NodeKind Kind) const { switch (Kind) { case Twine::NullKind: diff --git a/lib/Support/Unix/Host.inc b/lib/Support/Unix/Host.inc new file mode 100644 index 000000000000..ed74b6759901 --- /dev/null +++ b/lib/Support/Unix/Host.inc @@ -0,0 +1,97 @@ + //===- llvm/Support/Unix/Host.inc -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the UNIX Host support. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" +#include "llvm/ADT/StringRef.h" +#include "Unix.h" +#include +#include +#include + +using namespace llvm; + +static std::string getOSVersion() { + struct utsname info; + + if (uname(&info)) + return ""; + + return info.release; +} + +std::string sys::getHostTriple() { + // FIXME: Derive directly instead of relying on the autoconf generated + // variable. + + StringRef HostTripleString(LLVM_HOSTTRIPLE); + std::pair ArchSplit = HostTripleString.split('-'); + + // Normalize the arch, since the host triple may not actually match the host. + std::string Arch = ArchSplit.first; + + // It would be nice to do this in terms of llvm::Triple, but that is in + // Support which is layered above us. +#if defined(__x86_64__) + Arch = "x86_64"; +#elif defined(__i386__) + Arch = "i386"; +#elif defined(__ppc64__) + Arch = "powerpc64"; +#elif defined(__ppc__) + Arch = "powerpc"; +#elif defined(__arm__) + + // FIXME: We need to pick the right ARM triple (which involves querying the + // chip). However, for now this is most important for LLVM arch selection, so + // we only need to make sure to distinguish ARM and Thumb. +# if defined(__thumb__) + Arch = "thumb"; +# else + Arch = "arm"; +# endif + +#else + + // FIXME: When enough auto-detection is in place, this should just + // #error. Then at least the arch selection is done, and we only need the OS + // etc selection to kill off the use of LLVM_HOSTTRIPLE. + +#endif + + std::string Triple(Arch); + Triple += '-'; + Triple += ArchSplit.second; + + // Force i86 to i386. + if (Triple[0] == 'i' && isdigit(Triple[1]) && + Triple[2] == '8' && Triple[3] == '6') + Triple[1] = '3'; + + // On darwin, we want to update the version to match that of the + // host. + std::string::size_type DarwinDashIdx = Triple.find("-darwin"); + if (DarwinDashIdx != std::string::npos) { + Triple.resize(DarwinDashIdx + strlen("-darwin")); + + // Only add the major part of the os version. + std::string Version = getOSVersion(); + Triple += Version.substr(0, Version.find('.')); + } + + return Triple; +} diff --git a/lib/Support/Unix/Memory.inc b/lib/Support/Unix/Memory.inc new file mode 100644 index 000000000000..4312d67183c4 --- /dev/null +++ b/lib/Support/Unix/Memory.inc @@ -0,0 +1,151 @@ +//===- Unix/Memory.cpp - Generic UNIX System Configuration ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines some functions for various memory management utilities. +// +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Process.h" + +#ifdef HAVE_SYS_MMAN_H +#include +#endif + +#ifdef __APPLE__ +#include +#endif + +/// AllocateRWX - Allocate a slab of memory with read/write/execute +/// permissions. This is typically used for JIT applications where we want +/// to emit code to the memory then jump to it. Getting this type of memory +/// is very OS specific. +/// +llvm::sys::MemoryBlock +llvm::sys::Memory::AllocateRWX(size_t NumBytes, const MemoryBlock* NearBlock, + std::string *ErrMsg) { + if (NumBytes == 0) return MemoryBlock(); + + size_t pageSize = Process::GetPageSize(); + size_t NumPages = (NumBytes+pageSize-1)/pageSize; + + int fd = -1; +#ifdef NEED_DEV_ZERO_FOR_MMAP + static int zero_fd = open("/dev/zero", O_RDWR); + if (zero_fd == -1) { + MakeErrMsg(ErrMsg, "Can't open /dev/zero device"); + return MemoryBlock(); + } + fd = zero_fd; +#endif + + int flags = MAP_PRIVATE | +#ifdef HAVE_MMAP_ANONYMOUS + MAP_ANONYMOUS +#else + MAP_ANON +#endif + ; + + void* start = NearBlock ? (unsigned char*)NearBlock->base() + + NearBlock->size() : 0; + +#if defined(__APPLE__) && defined(__arm__) + void *pa = ::mmap(start, pageSize*NumPages, PROT_READ|PROT_EXEC, + flags, fd, 0); +#else + void *pa = ::mmap(start, pageSize*NumPages, PROT_READ|PROT_WRITE|PROT_EXEC, + flags, fd, 0); +#endif + if (pa == MAP_FAILED) { + if (NearBlock) //Try again without a near hint + return AllocateRWX(NumBytes, 0); + + MakeErrMsg(ErrMsg, "Can't allocate RWX Memory"); + return MemoryBlock(); + } + +#if defined(__APPLE__) && defined(__arm__) + kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)pa, + (vm_size_t)(pageSize*NumPages), 0, + VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); + if (KERN_SUCCESS != kr) { + MakeErrMsg(ErrMsg, "vm_protect max RX failed"); + return sys::MemoryBlock(); + } + + kr = vm_protect(mach_task_self(), (vm_address_t)pa, + (vm_size_t)(pageSize*NumPages), 0, + VM_PROT_READ | VM_PROT_WRITE); + if (KERN_SUCCESS != kr) { + MakeErrMsg(ErrMsg, "vm_protect RW failed"); + return sys::MemoryBlock(); + } +#endif + + MemoryBlock result; + result.Address = pa; + result.Size = NumPages*pageSize; + + return result; +} + +bool llvm::sys::Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { + if (M.Address == 0 || M.Size == 0) return false; + if (0 != ::munmap(M.Address, M.Size)) + return MakeErrMsg(ErrMsg, "Can't release RWX Memory"); + return false; +} + +bool llvm::sys::Memory::setWritable (MemoryBlock &M, std::string *ErrMsg) { +#if defined(__APPLE__) && defined(__arm__) + if (M.Address == 0 || M.Size == 0) return false; + sys::Memory::InvalidateInstructionCache(M.Address, M.Size); + kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address, + (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_WRITE); + return KERN_SUCCESS == kr; +#else + return true; +#endif +} + +bool llvm::sys::Memory::setExecutable (MemoryBlock &M, std::string *ErrMsg) { +#if defined(__APPLE__) && defined(__arm__) + if (M.Address == 0 || M.Size == 0) return false; + sys::Memory::InvalidateInstructionCache(M.Address, M.Size); + kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address, + (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); + return KERN_SUCCESS == kr; +#else + return false; +#endif +} + +bool llvm::sys::Memory::setRangeWritable(const void *Addr, size_t Size) { +#if defined(__APPLE__) && defined(__arm__) + kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)Addr, + (vm_size_t)Size, 0, + VM_PROT_READ | VM_PROT_WRITE); + return KERN_SUCCESS == kr; +#else + return true; +#endif +} + +bool llvm::sys::Memory::setRangeExecutable(const void *Addr, size_t Size) { +#if defined(__APPLE__) && defined(__arm__) + kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)Addr, + (vm_size_t)Size, 0, + VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); + return KERN_SUCCESS == kr; +#else + return true; +#endif +} diff --git a/lib/Support/Unix/Mutex.inc b/lib/Support/Unix/Mutex.inc new file mode 100644 index 000000000000..fe6b17041457 --- /dev/null +++ b/lib/Support/Unix/Mutex.inc @@ -0,0 +1,43 @@ +//===- llvm/Support/Unix/Mutex.inc - Unix Mutex Implementation ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific (non-pthread) Mutex class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +namespace llvm +{ +using namespace sys; + +MutexImpl::MutexImpl( bool recursive) +{ +} + +MutexImpl::~MutexImpl() +{ +} + +bool +MutexImpl::release() +{ + return true; +} + +bool +MutexImpl::tryacquire( void ) +{ + return true; +} + +} diff --git a/lib/Support/Unix/Path.inc b/lib/Support/Unix/Path.inc new file mode 100644 index 000000000000..0f6e800505e1 --- /dev/null +++ b/lib/Support/Unix/Path.inc @@ -0,0 +1,887 @@ +//===- llvm/Support/Unix/Path.cpp - Unix Path Implementation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific portion of the Path class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_SYS_MMAN_H +#include +#endif +#ifdef HAVE_SYS_STAT_H +#include +#endif +#if HAVE_UTIME_H +#include +#endif +#if HAVE_TIME_H +#include +#endif +#if HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# if HAVE_SYS_NDIR_H +# include +# endif +# if HAVE_SYS_DIR_H +# include +# endif +# if HAVE_NDIR_H +# include +# endif +#endif + +#if HAVE_DLFCN_H +#include +#endif + +#ifdef __APPLE__ +#include +#endif + +// Put in a hack for Cygwin which falsely reports that the mkdtemp function +// is available when it is not. +#ifdef __CYGWIN__ +# undef HAVE_MKDTEMP +#endif + +namespace { +inline bool lastIsSlash(const std::string& path) { + return !path.empty() && path[path.length() - 1] == '/'; +} + +} + +namespace llvm { +using namespace sys; + +const char sys::PathSeparator = ':'; + +StringRef Path::GetEXESuffix() { + return StringRef(); +} + +Path::Path(StringRef p) + : path(p) {} + +Path::Path(const char *StrStart, unsigned StrLen) + : path(StrStart, StrLen) {} + +Path& +Path::operator=(StringRef that) { + path.assign(that.data(), that.size()); + return *this; +} + +bool +Path::isValid() const { + // Empty paths are considered invalid here. + // This code doesn't check MAXPATHLEN because there's no need. Nothing in + // LLVM manipulates Paths with fixed-sizes arrays, and if the OS can't + // handle names longer than some limit, it'll report this on demand using + // ENAMETOLONG. + return !path.empty(); +} + +bool +Path::isAbsolute(const char *NameStart, unsigned NameLen) { + assert(NameStart); + if (NameLen == 0) + return false; + return NameStart[0] == '/'; +} + +bool +Path::isAbsolute() const { + if (path.empty()) + return false; + return path[0] == '/'; +} + +Path +Path::GetRootDirectory() { + Path result; + result.set("/"); + return result; +} + +Path +Path::GetTemporaryDirectory(std::string *ErrMsg) { +#if defined(HAVE_MKDTEMP) + // The best way is with mkdtemp but that's not available on many systems, + // Linux and FreeBSD have it. Others probably won't. + char pathname[] = "/tmp/llvm_XXXXXX"; + if (0 == mkdtemp(pathname)) { + MakeErrMsg(ErrMsg, + std::string(pathname) + ": can't create temporary directory"); + return Path(); + } + return Path(pathname); +#elif defined(HAVE_MKSTEMP) + // If no mkdtemp is available, mkstemp can be used to create a temporary file + // which is then removed and created as a directory. We prefer this over + // mktemp because of mktemp's inherent security and threading risks. We still + // have a slight race condition from the time the temporary file is created to + // the time it is re-created as a directoy. + char pathname[] = "/tmp/llvm_XXXXXX"; + int fd = 0; + if (-1 == (fd = mkstemp(pathname))) { + MakeErrMsg(ErrMsg, + std::string(pathname) + ": can't create temporary directory"); + return Path(); + } + ::close(fd); + ::unlink(pathname); // start race condition, ignore errors + if (-1 == ::mkdir(pathname, S_IRWXU)) { // end race condition + MakeErrMsg(ErrMsg, + std::string(pathname) + ": can't create temporary directory"); + return Path(); + } + return Path(pathname); +#elif defined(HAVE_MKTEMP) + // If a system doesn't have mkdtemp(3) or mkstemp(3) but it does have + // mktemp(3) then we'll assume that system (e.g. AIX) has a reasonable + // implementation of mktemp(3) and doesn't follow BSD 4.3's lead of replacing + // the XXXXXX with the pid of the process and a letter. That leads to only + // twenty six temporary files that can be generated. + char pathname[] = "/tmp/llvm_XXXXXX"; + char *TmpName = ::mktemp(pathname); + if (TmpName == 0) { + MakeErrMsg(ErrMsg, + std::string(TmpName) + ": can't create unique directory name"); + return Path(); + } + if (-1 == ::mkdir(TmpName, S_IRWXU)) { + MakeErrMsg(ErrMsg, + std::string(TmpName) + ": can't create temporary directory"); + return Path(); + } + return Path(TmpName); +#else + // This is the worst case implementation. tempnam(3) leaks memory unless its + // on an SVID2 (or later) system. On BSD 4.3 it leaks. tmpnam(3) has thread + // issues. The mktemp(3) function doesn't have enough variability in the + // temporary name generated. So, we provide our own implementation that + // increments an integer from a random number seeded by the current time. This + // should be sufficiently unique that we don't have many collisions between + // processes. Generally LLVM processes don't run very long and don't use very + // many temporary files so this shouldn't be a big issue for LLVM. + static time_t num = ::time(0); + char pathname[MAXPATHLEN]; + do { + num++; + sprintf(pathname, "/tmp/llvm_%010u", unsigned(num)); + } while ( 0 == access(pathname, F_OK ) ); + if (-1 == ::mkdir(pathname, S_IRWXU)) { + MakeErrMsg(ErrMsg, + std::string(pathname) + ": can't create temporary directory"); + return Path(); + } + return Path(pathname); +#endif +} + +void +Path::GetSystemLibraryPaths(std::vector& Paths) { +#ifdef LTDL_SHLIBPATH_VAR + char* env_var = getenv(LTDL_SHLIBPATH_VAR); + if (env_var != 0) { + getPathList(env_var,Paths); + } +#endif + // FIXME: Should this look at LD_LIBRARY_PATH too? + Paths.push_back(sys::Path("/usr/local/lib/")); + Paths.push_back(sys::Path("/usr/X11R6/lib/")); + Paths.push_back(sys::Path("/usr/lib/")); + Paths.push_back(sys::Path("/lib/")); +} + +void +Path::GetBitcodeLibraryPaths(std::vector& Paths) { + char * env_var = getenv("LLVM_LIB_SEARCH_PATH"); + if (env_var != 0) { + getPathList(env_var,Paths); + } +#ifdef LLVM_LIBDIR + { + Path tmpPath; + if (tmpPath.set(LLVM_LIBDIR)) + if (tmpPath.canRead()) + Paths.push_back(tmpPath); + } +#endif + GetSystemLibraryPaths(Paths); +} + +Path +Path::GetLLVMDefaultConfigDir() { + return Path("/etc/llvm/"); +} + +Path +Path::GetUserHomeDirectory() { + const char* home = getenv("HOME"); + Path result; + if (home && result.set(home)) + return result; + result.set("/"); + return result; +} + +Path +Path::GetCurrentDirectory() { + char pathname[MAXPATHLEN]; + if (!getcwd(pathname,MAXPATHLEN)) { + assert (false && "Could not query current working directory."); + return Path(); + } + + return Path(pathname); +} + +#if defined(__FreeBSD__) || defined (__NetBSD__) || \ + defined(__OpenBSD__) || defined(__minix) +static int +test_dir(char buf[PATH_MAX], char ret[PATH_MAX], + const char *dir, const char *bin) +{ + struct stat sb; + + snprintf(buf, PATH_MAX, "%s/%s", dir, bin); + if (realpath(buf, ret) == NULL) + return (1); + if (stat(buf, &sb) != 0) + return (1); + + return (0); +} + +static char * +getprogpath(char ret[PATH_MAX], const char *bin) +{ + char *pv, *s, *t, buf[PATH_MAX]; + + /* First approach: absolute path. */ + if (bin[0] == '/') { + if (test_dir(buf, ret, "/", bin) == 0) + return (ret); + return (NULL); + } + + /* Second approach: relative path. */ + if (strchr(bin, '/') != NULL) { + if (getcwd(buf, PATH_MAX) == NULL) + return (NULL); + if (test_dir(buf, ret, buf, bin) == 0) + return (ret); + return (NULL); + } + + /* Third approach: $PATH */ + if ((pv = getenv("PATH")) == NULL) + return (NULL); + s = pv = strdup(pv); + if (pv == NULL) + return (NULL); + while ((t = strsep(&s, ":")) != NULL) { + if (test_dir(buf, ret, t, bin) == 0) { + free(pv); + return (ret); + } + } + free(pv); + return (NULL); +} +#endif // __FreeBSD__ || __NetBSD__ + +/// GetMainExecutable - Return the path to the main executable, given the +/// value of argv[0] from program startup. +Path Path::GetMainExecutable(const char *argv0, void *MainAddr) { +#if defined(__APPLE__) + // On OS X the executable path is saved to the stack by dyld. Reading it + // from there is much faster than calling dladdr, especially for large + // binaries with symbols. + char exe_path[MAXPATHLEN]; + uint32_t size = sizeof(exe_path); + if (_NSGetExecutablePath(exe_path, &size) == 0) { + char link_path[MAXPATHLEN]; + if (realpath(exe_path, link_path)) + return Path(link_path); + } +#elif defined(__FreeBSD__) || defined (__NetBSD__) || \ + defined(__OpenBSD__) || defined(__minix) + char exe_path[PATH_MAX]; + + if (getprogpath(exe_path, argv0) != NULL) + return Path(exe_path); +#elif defined(__linux__) || defined(__CYGWIN__) + char exe_path[MAXPATHLEN]; + ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path)); + if (len >= 0) + return Path(StringRef(exe_path, len)); +#elif defined(HAVE_DLFCN_H) + // Use dladdr to get executable path if available. + Dl_info DLInfo; + int err = dladdr(MainAddr, &DLInfo); + if (err == 0) + return Path(); + + // If the filename is a symlink, we need to resolve and return the location of + // the actual executable. + char link_path[MAXPATHLEN]; + if (realpath(DLInfo.dli_fname, link_path)) + return Path(link_path); +#else +#error GetMainExecutable is not implemented on this host yet. +#endif + return Path(); +} + + +StringRef Path::getDirname() const { + return getDirnameCharSep(path, "/"); +} + +StringRef +Path::getBasename() const { + // Find the last slash + std::string::size_type slash = path.rfind('/'); + if (slash == std::string::npos) + slash = 0; + else + slash++; + + std::string::size_type dot = path.rfind('.'); + if (dot == std::string::npos || dot < slash) + return StringRef(path).substr(slash); + else + return StringRef(path).substr(slash, dot - slash); +} + +StringRef +Path::getSuffix() const { + // Find the last slash + std::string::size_type slash = path.rfind('/'); + if (slash == std::string::npos) + slash = 0; + else + slash++; + + std::string::size_type dot = path.rfind('.'); + if (dot == std::string::npos || dot < slash) + return StringRef(); + else + return StringRef(path).substr(dot + 1); +} + +bool Path::getMagicNumber(std::string &Magic, unsigned len) const { + assert(len < 1024 && "Request for magic string too long"); + char Buf[1025]; + int fd = ::open(path.c_str(), O_RDONLY); + if (fd < 0) + return false; + ssize_t bytes_read = ::read(fd, Buf, len); + ::close(fd); + if (ssize_t(len) != bytes_read) + return false; + Magic.assign(Buf, len); + return true; +} + +bool +Path::exists() const { + return 0 == access(path.c_str(), F_OK ); +} + +bool +Path::isDirectory() const { + struct stat buf; + if (0 != stat(path.c_str(), &buf)) + return false; + return ((buf.st_mode & S_IFMT) == S_IFDIR) ? true : false; +} + +bool +Path::isSymLink() const { + struct stat buf; + if (0 != lstat(path.c_str(), &buf)) + return false; + return S_ISLNK(buf.st_mode); +} + + +bool +Path::canRead() const { + return 0 == access(path.c_str(), R_OK); +} + +bool +Path::canWrite() const { + return 0 == access(path.c_str(), W_OK); +} + +bool +Path::isRegularFile() const { + // Get the status so we can determine if it's a file or directory + struct stat buf; + + if (0 != stat(path.c_str(), &buf)) + return false; + + if (S_ISREG(buf.st_mode)) + return true; + + return false; +} + +bool +Path::canExecute() const { + if (0 != access(path.c_str(), R_OK | X_OK )) + return false; + struct stat buf; + if (0 != stat(path.c_str(), &buf)) + return false; + if (!S_ISREG(buf.st_mode)) + return false; + return true; +} + +StringRef +Path::getLast() const { + // Find the last slash + size_t pos = path.rfind('/'); + + // Handle the corner cases + if (pos == std::string::npos) + return path; + + // If the last character is a slash + if (pos == path.length()-1) { + // Find the second to last slash + size_t pos2 = path.rfind('/', pos-1); + if (pos2 == std::string::npos) + return StringRef(path).substr(0,pos); + else + return StringRef(path).substr(pos2+1,pos-pos2-1); + } + // Return everything after the last slash + return StringRef(path).substr(pos+1); +} + +const FileStatus * +PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const { + if (!fsIsValid || update) { + struct stat buf; + if (0 != stat(path.c_str(), &buf)) { + MakeErrMsg(ErrStr, path + ": can't get status of file"); + return 0; + } + status.fileSize = buf.st_size; + status.modTime.fromEpochTime(buf.st_mtime); + status.mode = buf.st_mode; + status.user = buf.st_uid; + status.group = buf.st_gid; + status.uniqueID = uint64_t(buf.st_ino); + status.isDir = S_ISDIR(buf.st_mode); + status.isFile = S_ISREG(buf.st_mode); + fsIsValid = true; + } + return &status; +} + +static bool AddPermissionBits(const Path &File, int bits) { + // Get the umask value from the operating system. We want to use it + // when changing the file's permissions. Since calling umask() sets + // the umask and returns its old value, we must call it a second + // time to reset it to the user's preference. + int mask = umask(0777); // The arg. to umask is arbitrary. + umask(mask); // Restore the umask. + + // Get the file's current mode. + struct stat buf; + if (0 != stat(File.c_str(), &buf)) + return false; + // Change the file to have whichever permissions bits from 'bits' + // that the umask would not disable. + if ((chmod(File.c_str(), (buf.st_mode | (bits & ~mask)))) == -1) + return false; + return true; +} + +bool Path::makeReadableOnDisk(std::string* ErrMsg) { + if (!AddPermissionBits(*this, 0444)) + return MakeErrMsg(ErrMsg, path + ": can't make file readable"); + return false; +} + +bool Path::makeWriteableOnDisk(std::string* ErrMsg) { + if (!AddPermissionBits(*this, 0222)) + return MakeErrMsg(ErrMsg, path + ": can't make file writable"); + return false; +} + +bool Path::makeExecutableOnDisk(std::string* ErrMsg) { + if (!AddPermissionBits(*this, 0111)) + return MakeErrMsg(ErrMsg, path + ": can't make file executable"); + return false; +} + +bool +Path::getDirectoryContents(std::set& result, std::string* ErrMsg) const { + DIR* direntries = ::opendir(path.c_str()); + if (direntries == 0) + return MakeErrMsg(ErrMsg, path + ": can't open directory"); + + std::string dirPath = path; + if (!lastIsSlash(dirPath)) + dirPath += '/'; + + result.clear(); + struct dirent* de = ::readdir(direntries); + for ( ; de != 0; de = ::readdir(direntries)) { + if (de->d_name[0] != '.') { + Path aPath(dirPath + (const char*)de->d_name); + struct stat st; + if (0 != lstat(aPath.path.c_str(), &st)) { + if (S_ISLNK(st.st_mode)) + continue; // dangling symlink -- ignore + return MakeErrMsg(ErrMsg, + aPath.path + ": can't determine file object type"); + } + result.insert(aPath); + } + } + + closedir(direntries); + return false; +} + +bool +Path::set(StringRef a_path) { + if (a_path.empty()) + return false; + path = a_path; + return true; +} + +bool +Path::appendComponent(StringRef name) { + if (name.empty()) + return false; + if (!lastIsSlash(path)) + path += '/'; + path += name; + return true; +} + +bool +Path::eraseComponent() { + size_t slashpos = path.rfind('/',path.size()); + if (slashpos == 0 || slashpos == std::string::npos) { + path.erase(); + return true; + } + if (slashpos == path.size() - 1) + slashpos = path.rfind('/',slashpos-1); + if (slashpos == std::string::npos) { + path.erase(); + return true; + } + path.erase(slashpos); + return true; +} + +bool +Path::eraseSuffix() { + size_t dotpos = path.rfind('.',path.size()); + size_t slashpos = path.rfind('/',path.size()); + if (dotpos != std::string::npos) { + if (slashpos == std::string::npos || dotpos > slashpos+1) { + path.erase(dotpos, path.size()-dotpos); + return true; + } + } + return false; +} + +static bool createDirectoryHelper(char* beg, char* end, bool create_parents) { + + if (access(beg, R_OK | W_OK) == 0) + return false; + + if (create_parents) { + + char* c = end; + + for (; c != beg; --c) + if (*c == '/') { + + // Recurse to handling the parent directory. + *c = '\0'; + bool x = createDirectoryHelper(beg, c, create_parents); + *c = '/'; + + // Return if we encountered an error. + if (x) + return true; + + break; + } + } + + return mkdir(beg, S_IRWXU | S_IRWXG) != 0; +} + +bool +Path::createDirectoryOnDisk( bool create_parents, std::string* ErrMsg ) { + // Get a writeable copy of the path name + std::string pathname(path); + + // Null-terminate the last component + size_t lastchar = path.length() - 1 ; + + if (pathname[lastchar] != '/') + ++lastchar; + + pathname[lastchar] = '\0'; + + if (createDirectoryHelper(&pathname[0], &pathname[lastchar], create_parents)) + return MakeErrMsg(ErrMsg, pathname + ": can't create directory"); + + return false; +} + +bool +Path::createFileOnDisk(std::string* ErrMsg) { + // Create the file + int fd = ::creat(path.c_str(), S_IRUSR | S_IWUSR); + if (fd < 0) + return MakeErrMsg(ErrMsg, path + ": can't create file"); + ::close(fd); + return false; +} + +bool +Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) { + // Make this into a unique file name + if (makeUnique( reuse_current, ErrMsg )) + return true; + + // create the file + int fd = ::open(path.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0666); + if (fd < 0) + return MakeErrMsg(ErrMsg, path + ": can't create temporary file"); + ::close(fd); + return false; +} + +bool +Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const { + // Get the status so we can determine if it's a file or directory. + struct stat buf; + if (0 != stat(path.c_str(), &buf)) { + MakeErrMsg(ErrStr, path + ": can't get status of file"); + return true; + } + + // Note: this check catches strange situations. In all cases, LLVM should + // only be involved in the creation and deletion of regular files. This + // check ensures that what we're trying to erase is a regular file. It + // effectively prevents LLVM from erasing things like /dev/null, any block + // special file, or other things that aren't "regular" files. + if (S_ISREG(buf.st_mode)) { + if (unlink(path.c_str()) != 0) + return MakeErrMsg(ErrStr, path + ": can't destroy file"); + return false; + } + + if (!S_ISDIR(buf.st_mode)) { + if (ErrStr) *ErrStr = "not a file or directory"; + return true; + } + + if (remove_contents) { + // Recursively descend the directory to remove its contents. + std::string cmd = "/bin/rm -rf " + path; + if (system(cmd.c_str()) != 0) { + MakeErrMsg(ErrStr, path + ": failed to recursively remove directory."); + return true; + } + return false; + } + + // Otherwise, try to just remove the one directory. + std::string pathname(path); + size_t lastchar = path.length() - 1; + if (pathname[lastchar] == '/') + pathname[lastchar] = '\0'; + else + pathname[lastchar+1] = '\0'; + + if (rmdir(pathname.c_str()) != 0) + return MakeErrMsg(ErrStr, pathname + ": can't erase directory"); + return false; +} + +bool +Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) { + if (0 != ::rename(path.c_str(), newName.c_str())) + return MakeErrMsg(ErrMsg, std::string("can't rename '") + path + "' as '" + + newName.str() + "'"); + return false; +} + +bool +Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrStr) const { + struct utimbuf utb; + utb.actime = si.modTime.toPosixTime(); + utb.modtime = utb.actime; + if (0 != ::utime(path.c_str(),&utb)) + return MakeErrMsg(ErrStr, path + ": can't set file modification time"); + if (0 != ::chmod(path.c_str(),si.mode)) + return MakeErrMsg(ErrStr, path + ": can't set mode"); + return false; +} + +bool +sys::CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg){ + int inFile = -1; + int outFile = -1; + inFile = ::open(Src.c_str(), O_RDONLY); + if (inFile == -1) + return MakeErrMsg(ErrMsg, Src.str() + + ": can't open source file to copy"); + + outFile = ::open(Dest.c_str(), O_WRONLY|O_CREAT, 0666); + if (outFile == -1) { + ::close(inFile); + return MakeErrMsg(ErrMsg, Dest.str() + + ": can't create destination file for copy"); + } + + char Buffer[16*1024]; + while (ssize_t Amt = ::read(inFile, Buffer, 16*1024)) { + if (Amt == -1) { + if (errno != EINTR && errno != EAGAIN) { + ::close(inFile); + ::close(outFile); + return MakeErrMsg(ErrMsg, Src.str()+": can't read source file"); + } + } else { + char *BufPtr = Buffer; + while (Amt) { + ssize_t AmtWritten = ::write(outFile, BufPtr, Amt); + if (AmtWritten == -1) { + if (errno != EINTR && errno != EAGAIN) { + ::close(inFile); + ::close(outFile); + return MakeErrMsg(ErrMsg, Dest.str() + + ": can't write destination file"); + } + } else { + Amt -= AmtWritten; + BufPtr += AmtWritten; + } + } + } + } + ::close(inFile); + ::close(outFile); + return false; +} + +bool +Path::makeUnique(bool reuse_current, std::string* ErrMsg) { + bool Exists; + if (reuse_current && (fs::exists(path, Exists) || !Exists)) + return false; // File doesn't exist already, just use it! + + // Append an XXXXXX pattern to the end of the file for use with mkstemp, + // mktemp or our own implementation. + // This uses std::vector instead of SmallVector to avoid a dependence on + // libSupport. And performance isn't critical here. + std::vector Buf; + Buf.resize(path.size()+8); + char *FNBuffer = &Buf[0]; + path.copy(FNBuffer,path.size()); + bool isdir; + if (!fs::is_directory(path, isdir) && isdir) + strcpy(FNBuffer+path.size(), "/XXXXXX"); + else + strcpy(FNBuffer+path.size(), "-XXXXXX"); + +#if defined(HAVE_MKSTEMP) + int TempFD; + if ((TempFD = mkstemp(FNBuffer)) == -1) + return MakeErrMsg(ErrMsg, path + ": can't make unique filename"); + + // We don't need to hold the temp file descriptor... we will trust that no one + // will overwrite/delete the file before we can open it again. + close(TempFD); + + // Save the name + path = FNBuffer; +#elif defined(HAVE_MKTEMP) + // If we don't have mkstemp, use the old and obsolete mktemp function. + if (mktemp(FNBuffer) == 0) + return MakeErrMsg(ErrMsg, path + ": can't make unique filename"); + + // Save the name + path = FNBuffer; +#else + // Okay, looks like we have to do it all by our lonesome. + static unsigned FCounter = 0; + // Try to initialize with unique value. + if (FCounter == 0) FCounter = ((unsigned)getpid() & 0xFFFF) << 8; + char* pos = strstr(FNBuffer, "XXXXXX"); + do { + if (++FCounter > 0xFFFFFF) { + return MakeErrMsg(ErrMsg, + path + ": can't make unique filename: too many files"); + } + sprintf(pos, "%06X", FCounter); + path = FNBuffer; + } while (exists()); + // POSSIBLE SECURITY BUG: An attacker can easily guess the name and exploit + // LLVM. +#endif + return false; +} + +const char *Path::MapInFilePages(int FD, uint64_t FileSize) { + int Flags = MAP_PRIVATE; +#ifdef MAP_FILE + Flags |= MAP_FILE; +#endif + void *BasePtr = ::mmap(0, FileSize, PROT_READ, Flags, FD, 0); + if (BasePtr == MAP_FAILED) + return 0; + return (const char*)BasePtr; +} + +void Path::UnMapFilePages(const char *BasePtr, uint64_t FileSize) { + ::munmap((void*)BasePtr, FileSize); +} + +} // end llvm namespace diff --git a/lib/Support/Unix/PathV2.inc b/lib/Support/Unix/PathV2.inc new file mode 100644 index 000000000000..03ff28367e44 --- /dev/null +++ b/lib/Support/Unix/PathV2.inc @@ -0,0 +1,507 @@ +//===- llvm/Support/Unix/PathV2.cpp - Unix Path Implementation --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific implementation of the PathV2 API. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_FCNTL_H +#include +#endif +#if HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# if HAVE_SYS_NDIR_H +# include +# endif +# if HAVE_SYS_DIR_H +# include +# endif +# if HAVE_NDIR_H +# include +# endif +#endif +#if HAVE_STDIO_H +#include +#endif + +using namespace llvm; + +namespace { + /// This class automatically closes the given file descriptor when it goes out + /// of scope. You can take back explicit ownership of the file descriptor by + /// calling take(). The destructor does not verify that close was successful. + /// Therefore, never allow this class to call close on a file descriptor that + /// has been read from or written to. + struct AutoFD { + int FileDescriptor; + + AutoFD(int fd) : FileDescriptor(fd) {} + ~AutoFD() { + if (FileDescriptor >= 0) + ::close(FileDescriptor); + } + + int take() { + int ret = FileDescriptor; + FileDescriptor = -1; + return ret; + } + + operator int() const {return FileDescriptor;} + }; + + error_code TempDir(SmallVectorImpl &result) { + // FIXME: Don't use TMPDIR if program is SUID or SGID enabled. + const char *dir = 0; + (dir = std::getenv("TMPDIR" )) || + (dir = std::getenv("TMP" )) || + (dir = std::getenv("TEMP" )) || + (dir = std::getenv("TEMPDIR")) || +#ifdef P_tmpdir + (dir = P_tmpdir) || +#endif + (dir = "/tmp"); + + result.clear(); + StringRef d(dir); + result.append(d.begin(), d.end()); + return success; + } +} + +namespace llvm { +namespace sys { +namespace fs { + +error_code current_path(SmallVectorImpl &result) { + result.reserve(MAXPATHLEN); + + while (true) { + if (::getcwd(result.data(), result.capacity()) == 0) { + // See if there was a real error. + if (errno != errc::not_enough_memory) + return error_code(errno, system_category()); + // Otherwise there just wasn't enough space. + result.reserve(result.capacity() * 2); + } else + break; + } + + result.set_size(strlen(result.data())); + return success; +} + +error_code copy_file(const Twine &from, const Twine &to, copy_option copt) { + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toNullTerminatedStringRef(from_storage); + StringRef t = to.toNullTerminatedStringRef(to_storage); + + const size_t buf_sz = 32768; + char buffer[buf_sz]; + int from_file = -1, to_file = -1; + + // Open from. + if ((from_file = ::open(f.begin(), O_RDONLY)) < 0) + return error_code(errno, system_category()); + AutoFD from_fd(from_file); + + // Stat from. + struct stat from_stat; + if (::stat(f.begin(), &from_stat) != 0) + return error_code(errno, system_category()); + + // Setup to flags. + int to_flags = O_CREAT | O_WRONLY; + if (copt == copy_option::fail_if_exists) + to_flags |= O_EXCL; + + // Open to. + if ((to_file = ::open(t.begin(), to_flags, from_stat.st_mode)) < 0) + return error_code(errno, system_category()); + AutoFD to_fd(to_file); + + // Copy! + ssize_t sz, sz_read = 1, sz_write; + while (sz_read > 0 && + (sz_read = ::read(from_fd, buffer, buf_sz)) > 0) { + // Allow for partial writes - see Advanced Unix Programming (2nd Ed.), + // Marc Rochkind, Addison-Wesley, 2004, page 94 + sz_write = 0; + do { + if ((sz = ::write(to_fd, buffer + sz_write, sz_read - sz_write)) < 0) { + sz_read = sz; // cause read loop termination. + break; // error. + } + sz_write += sz; + } while (sz_write < sz_read); + } + + // After all the file operations above the return value of close actually + // matters. + if (::close(from_fd.take()) < 0) sz_read = -1; + if (::close(to_fd.take()) < 0) sz_read = -1; + + // Check for errors. + if (sz_read < 0) + return error_code(errno, system_category()); + + return success; +} + +error_code create_directory(const Twine &path, bool &existed) { + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); + + if (::mkdir(p.begin(), S_IRWXU | S_IRWXG) == -1) { + if (errno != errc::file_exists) + return error_code(errno, system_category()); + existed = true; + } else + existed = false; + + return success; +} + +error_code create_hard_link(const Twine &to, const Twine &from) { + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toNullTerminatedStringRef(from_storage); + StringRef t = to.toNullTerminatedStringRef(to_storage); + + if (::link(t.begin(), f.begin()) == -1) + return error_code(errno, system_category()); + + return success; +} + +error_code create_symlink(const Twine &to, const Twine &from) { + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toNullTerminatedStringRef(from_storage); + StringRef t = to.toNullTerminatedStringRef(to_storage); + + if (::symlink(t.begin(), f.begin()) == -1) + return error_code(errno, system_category()); + + return success; +} + +error_code remove(const Twine &path, bool &existed) { + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); + + if (::remove(p.begin()) == -1) { + if (errno != errc::no_such_file_or_directory) + return error_code(errno, system_category()); + existed = false; + } else + existed = true; + + return success; +} + +error_code rename(const Twine &from, const Twine &to) { + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toNullTerminatedStringRef(from_storage); + StringRef t = to.toNullTerminatedStringRef(to_storage); + + if (::rename(f.begin(), t.begin()) == -1) { + // If it's a cross device link, copy then delete, otherwise return the error + if (errno == EXDEV) { + if (error_code ec = copy_file(from, to, copy_option::overwrite_if_exists)) + return ec; + bool Existed; + if (error_code ec = remove(from, Existed)) + return ec; + } else + return error_code(errno, system_category()); + } + + return success; +} + +error_code resize_file(const Twine &path, uint64_t size) { + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); + + if (::truncate(p.begin(), size) == -1) + return error_code(errno, system_category()); + + return success; +} + +error_code exists(const Twine &path, bool &result) { + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); + + struct stat status; + if (::stat(p.begin(), &status) == -1) { + if (errno != errc::no_such_file_or_directory) + return error_code(errno, system_category()); + result = false; + } else + result = true; + + return success; +} + +error_code equivalent(const Twine &A, const Twine &B, bool &result) { + // Get arguments. + SmallString<128> a_storage; + SmallString<128> b_storage; + StringRef a = A.toNullTerminatedStringRef(a_storage); + StringRef b = B.toNullTerminatedStringRef(b_storage); + + struct stat stat_a, stat_b; + int error_b = ::stat(b.begin(), &stat_b); + int error_a = ::stat(a.begin(), &stat_a); + + // If both are invalid, it's an error. If only one is, the result is false. + if (error_a != 0 || error_b != 0) { + if (error_a == error_b) + return error_code(errno, system_category()); + result = false; + } else { + result = + stat_a.st_dev == stat_b.st_dev && + stat_a.st_ino == stat_b.st_ino; + } + + return success; +} + +error_code file_size(const Twine &path, uint64_t &result) { + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); + + struct stat status; + if (::stat(p.begin(), &status) == -1) + return error_code(errno, system_category()); + if (!S_ISREG(status.st_mode)) + return make_error_code(errc::operation_not_permitted); + + result = status.st_size; + return success; +} + +error_code status(const Twine &path, file_status &result) { + SmallString<128> path_storage; + StringRef p = path.toNullTerminatedStringRef(path_storage); + + struct stat status; + if (::stat(p.begin(), &status) != 0) { + error_code ec(errno, system_category()); + if (ec == errc::no_such_file_or_directory) + result = file_status(file_type::file_not_found); + else + result = file_status(file_type::status_error); + return ec; + } + + if (S_ISDIR(status.st_mode)) + result = file_status(file_type::directory_file); + else if (S_ISREG(status.st_mode)) + result = file_status(file_type::regular_file); + else if (S_ISBLK(status.st_mode)) + result = file_status(file_type::block_file); + else if (S_ISCHR(status.st_mode)) + result = file_status(file_type::character_file); + else if (S_ISFIFO(status.st_mode)) + result = file_status(file_type::fifo_file); + else if (S_ISSOCK(status.st_mode)) + result = file_status(file_type::socket_file); + else + result = file_status(file_type::type_unknown); + + return success; +} + +error_code unique_file(const Twine &model, int &result_fd, + SmallVectorImpl &result_path) { + SmallString<128> Model; + model.toVector(Model); + // Null terminate. + Model.c_str(); + + // Make model absolute by prepending a temp directory if it's not already. + bool absolute = path::is_absolute(Twine(Model)); + if (!absolute) { + SmallString<128> TDir; + if (error_code ec = TempDir(TDir)) return ec; + path::append(TDir, Twine(Model)); + Model.swap(TDir); + } + + // Replace '%' with random chars. From here on, DO NOT modify model. It may be + // needed if the randomly chosen path already exists. + SmallString<128> RandomPath; + RandomPath.reserve(Model.size() + 1); + ::srand(::time(NULL)); + +retry_random_path: + // This is opened here instead of above to make it easier to track when to + // close it. Collisions should be rare enough for the possible extra syscalls + // not to matter. + FILE *RandomSource = ::fopen("/dev/urandom", "r"); + RandomPath.set_size(0); + for (SmallVectorImpl::const_iterator i = Model.begin(), + e = Model.end(); i != e; ++i) { + if (*i == '%') { + char val = 0; + if (RandomSource) + val = fgetc(RandomSource); + else + val = ::rand(); + RandomPath.push_back("0123456789abcdef"[val & 15]); + } else + RandomPath.push_back(*i); + } + + if (RandomSource) + ::fclose(RandomSource); + + // Try to open + create the file. +rety_open_create: + int RandomFD = ::open(RandomPath.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); + if (RandomFD == -1) { + // If the file existed, try again, otherwise, error. + if (errno == errc::file_exists) + goto retry_random_path; + // The path prefix doesn't exist. + if (errno == errc::no_such_file_or_directory) { + StringRef p(RandomPath.begin(), RandomPath.size()); + SmallString<64> dir_to_create; + for (path::const_iterator i = path::begin(p), + e = --path::end(p); i != e; ++i) { + path::append(dir_to_create, *i); + bool Exists; + if (error_code ec = exists(Twine(dir_to_create), Exists)) return ec; + if (!Exists) { + // Don't try to create network paths. + if (i->size() > 2 && (*i)[0] == '/' && + (*i)[1] == '/' && + (*i)[2] != '/') + return make_error_code(errc::no_such_file_or_directory); + if (::mkdir(dir_to_create.c_str(), 0700) == -1) + return error_code(errno, system_category()); + } + } + goto rety_open_create; + } + return error_code(errno, system_category()); + } + + // Make the path absolute. + char real_path_buff[PATH_MAX + 1]; + if (realpath(RandomPath.c_str(), real_path_buff) == NULL) { + int error = errno; + ::close(RandomFD); + ::unlink(RandomPath.c_str()); + return error_code(error, system_category()); + } + + result_path.clear(); + StringRef d(real_path_buff); + result_path.append(d.begin(), d.end()); + + result_fd = RandomFD; + return success; +} + +error_code directory_iterator_construct(directory_iterator &it, StringRef path){ + SmallString<128> path_null(path); + DIR *directory = ::opendir(path_null.c_str()); + if (directory == 0) + return error_code(errno, system_category()); + + it.IterationHandle = reinterpret_cast(directory); + // Add something for replace_filename to replace. + path::append(path_null, "."); + it.CurrentEntry = directory_entry(path_null.str()); + return directory_iterator_increment(it); +} + +error_code directory_iterator_destruct(directory_iterator& it) { + if (it.IterationHandle) + ::closedir(reinterpret_cast(it.IterationHandle)); + it.IterationHandle = 0; + it.CurrentEntry = directory_entry(); + return success; +} + +error_code directory_iterator_increment(directory_iterator& it) { + errno = 0; + dirent *cur_dir = ::readdir(reinterpret_cast(it.IterationHandle)); + if (cur_dir == 0 && errno != 0) { + return error_code(errno, system_category()); + } else if (cur_dir != 0) { + StringRef name(cur_dir->d_name, NAMLEN(cur_dir)); + if ((name.size() == 1 && name[0] == '.') || + (name.size() == 2 && name[0] == '.' && name[1] == '.')) + return directory_iterator_increment(it); + it.CurrentEntry.replace_filename(name); + } else + return directory_iterator_destruct(it); + + return success; +} + +error_code get_magic(const Twine &path, uint32_t len, + SmallVectorImpl &result) { + SmallString<128> PathStorage; + StringRef Path = path.toNullTerminatedStringRef(PathStorage); + result.set_size(0); + + // Open path. + std::FILE *file = std::fopen(Path.data(), "rb"); + if (file == 0) + return error_code(errno, system_category()); + + // Reserve storage. + result.reserve(len); + + // Read magic! + size_t size = std::fread(result.data(), 1, len, file); + if (std::ferror(file) != 0) { + std::fclose(file); + return error_code(errno, system_category()); + } else if (size != result.size()) { + if (std::feof(file) != 0) { + std::fclose(file); + result.set_size(size); + return make_error_code(errc::value_too_large); + } + } + std::fclose(file); + result.set_size(len); + return success; +} + +} // end namespace fs +} // end namespace sys +} // end namespace llvm diff --git a/lib/Support/Unix/Process.inc b/lib/Support/Unix/Process.inc new file mode 100644 index 000000000000..5cdb11ccebc4 --- /dev/null +++ b/lib/Support/Unix/Process.inc @@ -0,0 +1,295 @@ +//===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the generic Unix implementation of the Process class. +// +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif +// DragonFly BSD has deprecated for instead, +// Unix.h includes this for us already. +#if defined(HAVE_MALLOC_H) && !defined(__DragonFly__) +#include +#endif +#ifdef HAVE_MALLOC_MALLOC_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +# include +#endif +#ifdef HAVE_TERMIOS_H +# include +#endif + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +using namespace llvm; +using namespace sys; + +unsigned +Process::GetPageSize() +{ +#if defined(__CYGWIN__) + // On Cygwin, getpagesize() returns 64k but the page size for the purposes of + // memory protection and mmap() is 4k. + // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492 + const int page_size = 0x1000; +#elif defined(HAVE_GETPAGESIZE) + const int page_size = ::getpagesize(); +#elif defined(HAVE_SYSCONF) + long page_size = ::sysconf(_SC_PAGE_SIZE); +#else +#warning Cannot get the page size on this machine +#endif + return static_cast(page_size); +} + +size_t Process::GetMallocUsage() { +#if defined(HAVE_MALLINFO) + struct mallinfo mi; + mi = ::mallinfo(); + return mi.uordblks; +#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) + malloc_statistics_t Stats; + malloc_zone_statistics(malloc_default_zone(), &Stats); + return Stats.size_in_use; // darwin +#elif defined(HAVE_SBRK) + // Note this is only an approximation and more closely resembles + // the value returned by mallinfo in the arena field. + static char *StartOfMemory = reinterpret_cast(::sbrk(0)); + char *EndOfMemory = (char*)sbrk(0); + if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1)) + return EndOfMemory - StartOfMemory; + else + return 0; +#else +#warning Cannot get malloc info on this platform + return 0; +#endif +} + +size_t +Process::GetTotalMemoryUsage() +{ +#if defined(HAVE_MALLINFO) + struct mallinfo mi = ::mallinfo(); + return mi.uordblks + mi.hblkhd; +#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) + malloc_statistics_t Stats; + malloc_zone_statistics(malloc_default_zone(), &Stats); + return Stats.size_allocated; // darwin +#elif defined(HAVE_GETRUSAGE) && !defined(__HAIKU__) + struct rusage usage; + ::getrusage(RUSAGE_SELF, &usage); + return usage.ru_maxrss; +#else +#warning Cannot get total memory size on this platform + return 0; +#endif +} + +void +Process::GetTimeUsage(TimeValue& elapsed, TimeValue& user_time, + TimeValue& sys_time) +{ + elapsed = TimeValue::now(); +#if defined(HAVE_GETRUSAGE) + struct rusage usage; + ::getrusage(RUSAGE_SELF, &usage); + user_time = TimeValue( + static_cast( usage.ru_utime.tv_sec ), + static_cast( usage.ru_utime.tv_usec * + TimeValue::NANOSECONDS_PER_MICROSECOND ) ); + sys_time = TimeValue( + static_cast( usage.ru_stime.tv_sec ), + static_cast( usage.ru_stime.tv_usec * + TimeValue::NANOSECONDS_PER_MICROSECOND ) ); +#else +#warning Cannot get usage times on this platform + user_time.seconds(0); + user_time.microseconds(0); + sys_time.seconds(0); + sys_time.microseconds(0); +#endif +} + +int Process::GetCurrentUserId() { + return getuid(); +} + +int Process::GetCurrentGroupId() { + return getgid(); +} + +#ifdef HAVE_MACH_MACH_H +#include +#endif + +// Some LLVM programs such as bugpoint produce core files as a normal part of +// their operation. To prevent the disk from filling up, this function +// does what's necessary to prevent their generation. +void Process::PreventCoreFiles() { +#if HAVE_SETRLIMIT + struct rlimit rlim; + rlim.rlim_cur = rlim.rlim_max = 0; + setrlimit(RLIMIT_CORE, &rlim); +#endif + +#ifdef HAVE_MACH_MACH_H + // Disable crash reporting on Mac OS X 10.0-10.4 + + // get information about the original set of exception ports for the task + mach_msg_type_number_t Count = 0; + exception_mask_t OriginalMasks[EXC_TYPES_COUNT]; + exception_port_t OriginalPorts[EXC_TYPES_COUNT]; + exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT]; + thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT]; + kern_return_t err = + task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks, + &Count, OriginalPorts, OriginalBehaviors, + OriginalFlavors); + if (err == KERN_SUCCESS) { + // replace each with MACH_PORT_NULL. + for (unsigned i = 0; i != Count; ++i) + task_set_exception_ports(mach_task_self(), OriginalMasks[i], + MACH_PORT_NULL, OriginalBehaviors[i], + OriginalFlavors[i]); + } + + // Disable crash reporting on Mac OS X 10.5 + signal(SIGABRT, _exit); + signal(SIGILL, _exit); + signal(SIGFPE, _exit); + signal(SIGSEGV, _exit); + signal(SIGBUS, _exit); +#endif +} + +bool Process::StandardInIsUserInput() { + return FileDescriptorIsDisplayed(STDIN_FILENO); +} + +bool Process::StandardOutIsDisplayed() { + return FileDescriptorIsDisplayed(STDOUT_FILENO); +} + +bool Process::StandardErrIsDisplayed() { + return FileDescriptorIsDisplayed(STDERR_FILENO); +} + +bool Process::FileDescriptorIsDisplayed(int fd) { +#if HAVE_ISATTY + return isatty(fd); +#else + // If we don't have isatty, just return false. + return false; +#endif +} + +static unsigned getColumns(int FileID) { + // If COLUMNS is defined in the environment, wrap to that many columns. + if (const char *ColumnsStr = std::getenv("COLUMNS")) { + int Columns = std::atoi(ColumnsStr); + if (Columns > 0) + return Columns; + } + + unsigned Columns = 0; + +#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H) + // Try to determine the width of the terminal. + struct winsize ws; + if (ioctl(FileID, TIOCGWINSZ, &ws) == 0) + Columns = ws.ws_col; +#endif + + return Columns; +} + +unsigned Process::StandardOutColumns() { + if (!StandardOutIsDisplayed()) + return 0; + + return getColumns(1); +} + +unsigned Process::StandardErrColumns() { + if (!StandardErrIsDisplayed()) + return 0; + + return getColumns(2); +} + +static bool terminalHasColors() { + if (const char *term = std::getenv("TERM")) { + // Most modern terminals support ANSI escape sequences for colors. + // We could check terminfo, or have a list of known terms that support + // colors, but that would be overkill. + // The user can always ask for no colors by setting TERM to dumb, or + // using a commandline flag. + return strcmp(term, "dumb") != 0; + } + return false; +} + +bool Process::StandardOutHasColors() { + if (!StandardOutIsDisplayed()) + return false; + return terminalHasColors(); +} + +bool Process::StandardErrHasColors() { + if (!StandardErrIsDisplayed()) + return false; + return terminalHasColors(); +} + +bool Process::ColorNeedsFlush() { + // No, we use ANSI escape sequences. + return false; +} + +#define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m" + +#define ALLCOLORS(FGBG,BOLD) {\ + COLOR(FGBG, "0", BOLD),\ + COLOR(FGBG, "1", BOLD),\ + COLOR(FGBG, "2", BOLD),\ + COLOR(FGBG, "3", BOLD),\ + COLOR(FGBG, "4", BOLD),\ + COLOR(FGBG, "5", BOLD),\ + COLOR(FGBG, "6", BOLD),\ + COLOR(FGBG, "7", BOLD)\ + } + +static const char colorcodes[2][2][8][10] = { + { ALLCOLORS("3",""), ALLCOLORS("3","1;") }, + { ALLCOLORS("4",""), ALLCOLORS("4","1;") } +}; + +const char *Process::OutputColor(char code, bool bold, bool bg) { + return colorcodes[bg?1:0][bold?1:0][code&7]; +} + +const char *Process::OutputBold(bool bg) { + return "\033[1m"; +} + +const char *Process::ResetColor() { + return "\033[0m"; +} diff --git a/lib/Support/Unix/Program.inc b/lib/Support/Unix/Program.inc new file mode 100644 index 000000000000..1104bc7503e1 --- /dev/null +++ b/lib/Support/Unix/Program.inc @@ -0,0 +1,424 @@ +//===- llvm/Support/Unix/Program.cpp -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific portion of the Program class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include +#include "llvm/Support/FileSystem.h" +#include "Unix.h" +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_RESOURCE_H +#include +#endif +#if HAVE_SIGNAL_H +#include +#endif +#if HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_POSIX_SPAWN +#include +#if !defined(__APPLE__) + extern char **environ; +#else +#include // _NSGetEnviron +#endif +#endif + +namespace llvm { +using namespace sys; + +Program::Program() : Data_(0) {} + +Program::~Program() {} + +unsigned Program::GetPid() const { + uint64_t pid = reinterpret_cast(Data_); + return static_cast(pid); +} + +// This function just uses the PATH environment variable to find the program. +Path +Program::FindProgramByName(const std::string& progName) { + + // Check some degenerate cases + if (progName.length() == 0) // no program + return Path(); + Path temp; + if (!temp.set(progName)) // invalid name + return Path(); + // Use the given path verbatim if it contains any slashes; this matches + // the behavior of sh(1) and friends. + if (progName.find('/') != std::string::npos) + return temp; + + // At this point, the file name is valid and does not contain slashes. Search + // for it through the directories specified in the PATH environment variable. + + // Get the path. If its empty, we can't do anything to find it. + const char *PathStr = getenv("PATH"); + if (PathStr == 0) + return Path(); + + // Now we have a colon separated list of directories to search; try them. + size_t PathLen = strlen(PathStr); + while (PathLen) { + // Find the first colon... + const char *Colon = std::find(PathStr, PathStr+PathLen, ':'); + + // Check to see if this first directory contains the executable... + Path FilePath; + if (FilePath.set(std::string(PathStr,Colon))) { + FilePath.appendComponent(progName); + if (FilePath.canExecute()) + return FilePath; // Found the executable! + } + + // Nope it wasn't in this directory, check the next path in the list! + PathLen -= Colon-PathStr; + PathStr = Colon; + + // Advance past duplicate colons + while (*PathStr == ':') { + PathStr++; + PathLen--; + } + } + return Path(); +} + +static bool RedirectIO(const Path *Path, int FD, std::string* ErrMsg) { + if (Path == 0) // Noop + return false; + const char *File; + if (Path->isEmpty()) + // Redirect empty paths to /dev/null + File = "/dev/null"; + else + File = Path->c_str(); + + // Open the file + int InFD = open(File, FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666); + if (InFD == -1) { + MakeErrMsg(ErrMsg, "Cannot open file '" + std::string(File) + "' for " + + (FD == 0 ? "input" : "output")); + return true; + } + + // Install it as the requested FD + if (dup2(InFD, FD) == -1) { + MakeErrMsg(ErrMsg, "Cannot dup2"); + close(InFD); + return true; + } + close(InFD); // Close the original FD + return false; +} + +#ifdef HAVE_POSIX_SPAWN +static bool RedirectIO_PS(const Path *Path, int FD, std::string *ErrMsg, + posix_spawn_file_actions_t &FileActions) { + if (Path == 0) // Noop + return false; + const char *File; + if (Path->isEmpty()) + // Redirect empty paths to /dev/null + File = "/dev/null"; + else + File = Path->c_str(); + + if (int Err = posix_spawn_file_actions_addopen(&FileActions, FD, + File, FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666)) + return MakeErrMsg(ErrMsg, "Cannot dup2", Err); + return false; +} +#endif + +static void TimeOutHandler(int Sig) { +} + +static void SetMemoryLimits (unsigned size) +{ +#if HAVE_SYS_RESOURCE_H && HAVE_GETRLIMIT && HAVE_SETRLIMIT + struct rlimit r; + __typeof__ (r.rlim_cur) limit = (__typeof__ (r.rlim_cur)) (size) * 1048576; + + // Heap size + getrlimit (RLIMIT_DATA, &r); + r.rlim_cur = limit; + setrlimit (RLIMIT_DATA, &r); +#ifdef RLIMIT_RSS + // Resident set size. + getrlimit (RLIMIT_RSS, &r); + r.rlim_cur = limit; + setrlimit (RLIMIT_RSS, &r); +#endif +#ifdef RLIMIT_AS // e.g. NetBSD doesn't have it. + // Virtual memory. + getrlimit (RLIMIT_AS, &r); + r.rlim_cur = limit; + setrlimit (RLIMIT_AS, &r); +#endif +#endif +} + +bool +Program::Execute(const Path &path, const char **args, const char **envp, + const Path **redirects, unsigned memoryLimit, + std::string *ErrMsg) { + // If this OS has posix_spawn and there is no memory limit being implied, use + // posix_spawn. It is more efficient than fork/exec. +#ifdef HAVE_POSIX_SPAWN + if (memoryLimit == 0) { + posix_spawn_file_actions_t FileActions; + posix_spawn_file_actions_init(&FileActions); + + if (redirects) { + // Redirect stdin/stdout. + if (RedirectIO_PS(redirects[0], 0, ErrMsg, FileActions) || + RedirectIO_PS(redirects[1], 1, ErrMsg, FileActions)) + return false; + if (redirects[1] == 0 || redirects[2] == 0 || + *redirects[1] != *redirects[2]) { + // Just redirect stderr + if (RedirectIO_PS(redirects[2], 2, ErrMsg, FileActions)) return false; + } else { + // If stdout and stderr should go to the same place, redirect stderr + // to the FD already open for stdout. + if (int Err = posix_spawn_file_actions_adddup2(&FileActions, 1, 2)) + return !MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout", Err); + } + } + + if (!envp) +#if !defined(__APPLE__) + envp = const_cast(environ); +#else + // environ is missing in dylibs. + envp = const_cast(*_NSGetEnviron()); +#endif + + // Explicitly initialized to prevent what appears to be a valgrind false + // positive. + pid_t PID = 0; + int Err = posix_spawn(&PID, path.c_str(), &FileActions, /*attrp*/0, + const_cast(args), const_cast(envp)); + + posix_spawn_file_actions_destroy(&FileActions); + + if (Err) + return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err); + + Data_ = reinterpret_cast(PID); + return true; + } +#endif + + // Create a child process. + int child = fork(); + switch (child) { + // An error occured: Return to the caller. + case -1: + MakeErrMsg(ErrMsg, "Couldn't fork"); + return false; + + // Child process: Execute the program. + case 0: { + // Redirect file descriptors... + if (redirects) { + // Redirect stdin + if (RedirectIO(redirects[0], 0, ErrMsg)) { return false; } + // Redirect stdout + if (RedirectIO(redirects[1], 1, ErrMsg)) { return false; } + if (redirects[1] && redirects[2] && + *(redirects[1]) == *(redirects[2])) { + // If stdout and stderr should go to the same place, redirect stderr + // to the FD already open for stdout. + if (-1 == dup2(1,2)) { + MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout"); + return false; + } + } else { + // Just redirect stderr + if (RedirectIO(redirects[2], 2, ErrMsg)) { return false; } + } + } + + // Set memory limits + if (memoryLimit!=0) { + SetMemoryLimits(memoryLimit); + } + + // Execute! + if (envp != 0) + execve(path.c_str(), + const_cast(args), + const_cast(envp)); + else + execv(path.c_str(), + const_cast(args)); + // If the execve() failed, we should exit. Follow Unix protocol and + // return 127 if the executable was not found, and 126 otherwise. + // Use _exit rather than exit so that atexit functions and static + // object destructors cloned from the parent process aren't + // redundantly run, and so that any data buffered in stdio buffers + // cloned from the parent aren't redundantly written out. + _exit(errno == ENOENT ? 127 : 126); + } + + // Parent process: Break out of the switch to do our processing. + default: + break; + } + + Data_ = reinterpret_cast(child); + + return true; +} + +int +Program::Wait(const sys::Path &path, + unsigned secondsToWait, + std::string* ErrMsg) +{ +#ifdef HAVE_SYS_WAIT_H + struct sigaction Act, Old; + + if (Data_ == 0) { + MakeErrMsg(ErrMsg, "Process not started!"); + return -1; + } + + // Install a timeout handler. The handler itself does nothing, but the simple + // fact of having a handler at all causes the wait below to return with EINTR, + // unlike if we used SIG_IGN. + if (secondsToWait) { + memset(&Act, 0, sizeof(Act)); + Act.sa_handler = TimeOutHandler; + sigemptyset(&Act.sa_mask); + sigaction(SIGALRM, &Act, &Old); + alarm(secondsToWait); + } + + // Parent process: Wait for the child process to terminate. + int status; + uint64_t pid = reinterpret_cast(Data_); + pid_t child = static_cast(pid); + while (waitpid(pid, &status, 0) != child) + if (secondsToWait && errno == EINTR) { + // Kill the child. + kill(child, SIGKILL); + + // Turn off the alarm and restore the signal handler + alarm(0); + sigaction(SIGALRM, &Old, 0); + + // Wait for child to die + if (wait(&status) != child) + MakeErrMsg(ErrMsg, "Child timed out but wouldn't die"); + else + MakeErrMsg(ErrMsg, "Child timed out", 0); + + return -1; // Timeout detected + } else if (errno != EINTR) { + MakeErrMsg(ErrMsg, "Error waiting for child process"); + return -1; + } + + // We exited normally without timeout, so turn off the timer. + if (secondsToWait) { + alarm(0); + sigaction(SIGALRM, &Old, 0); + } + + // Return the proper exit status. Detect error conditions + // so we can return -1 for them and set ErrMsg informatively. + int result = 0; + if (WIFEXITED(status)) { + result = WEXITSTATUS(status); +#ifdef HAVE_POSIX_SPAWN + // The posix_spawn child process returns 127 on any kind of error. + // Following the POSIX convention for command-line tools (which posix_spawn + // itself apparently does not), check to see if the failure was due to some + // reason other than the file not existing, and return 126 in this case. + bool Exists; + if (result == 127 && !llvm::sys::fs::exists(path.str(), Exists) && Exists) + result = 126; +#endif + if (result == 127) { + if (ErrMsg) + *ErrMsg = llvm::sys::StrError(ENOENT); + return -1; + } + if (result == 126) { + if (ErrMsg) + *ErrMsg = "Program could not be executed"; + return -1; + } + } else if (WIFSIGNALED(status)) { + if (ErrMsg) { + *ErrMsg = strsignal(WTERMSIG(status)); +#ifdef WCOREDUMP + if (WCOREDUMP(status)) + *ErrMsg += " (core dumped)"; +#endif + } + return -1; + } + return result; +#else + if (ErrMsg) + *ErrMsg = "Program::Wait is not implemented on this platform yet!"; + return -1; +#endif +} + +bool +Program::Kill(std::string* ErrMsg) { + if (Data_ == 0) { + MakeErrMsg(ErrMsg, "Process not started!"); + return true; + } + + uint64_t pid64 = reinterpret_cast(Data_); + pid_t pid = static_cast(pid64); + + if (kill(pid, SIGKILL) != 0) { + MakeErrMsg(ErrMsg, "The process couldn't be killed!"); + return true; + } + + return false; +} + +bool Program::ChangeStdinToBinary(){ + // Do nothing, as Unix doesn't differentiate between text and binary. + return false; +} + +bool Program::ChangeStdoutToBinary(){ + // Do nothing, as Unix doesn't differentiate between text and binary. + return false; +} + +bool Program::ChangeStderrToBinary(){ + // Do nothing, as Unix doesn't differentiate between text and binary. + return false; +} + +} diff --git a/lib/Support/Unix/README.txt b/lib/Support/Unix/README.txt new file mode 100644 index 000000000000..3d547c2990d5 --- /dev/null +++ b/lib/Support/Unix/README.txt @@ -0,0 +1,16 @@ +llvm/lib/Support/Unix README +=========================== + +This directory provides implementations of the lib/System classes that +are common to two or more variants of UNIX. For example, the directory +structure underneath this directory could look like this: + +Unix - only code that is truly generic to all UNIX platforms + Posix - code that is specific to Posix variants of UNIX + SUS - code that is specific to the Single Unix Specification + SysV - code that is specific to System V variants of UNIX + +As a rule, only those directories actually needing to be created should be +created. Also, further subdirectories could be created to reflect versions of +the various standards. For example, under SUS there could be v1, v2, and v3 +subdirectories to reflect the three major versions of SUS. diff --git a/lib/Support/Unix/RWMutex.inc b/lib/Support/Unix/RWMutex.inc new file mode 100644 index 000000000000..40e87ff13111 --- /dev/null +++ b/lib/Support/Unix/RWMutex.inc @@ -0,0 +1,43 @@ +//= llvm/Support/Unix/RWMutex.inc - Unix Reader/Writer Mutual Exclusion Lock =// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific (non-pthread) RWMutex class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +namespace llvm { + +using namespace sys; + +RWMutexImpl::RWMutexImpl() { } + +RWMutexImpl::~RWMutexImpl() { } + +bool RWMutexImpl::reader_acquire() { + return true; +} + +bool RWMutexImpl::reader_release() { + return true; +} + +bool RWMutexImpl::writer_acquire() { + return true; +} + +bool RWMutexImpl::writer_release() { + return true; +} + +} diff --git a/lib/Support/Unix/Signals.inc b/lib/Support/Unix/Signals.inc new file mode 100644 index 000000000000..0a617591551d --- /dev/null +++ b/lib/Support/Unix/Signals.inc @@ -0,0 +1,303 @@ +//===- Signals.cpp - Generic Unix Signals Implementation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines some helpful functions for dealing with the possibility of +// Unix signals occuring while your program is running. +// +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Mutex.h" +#include +#include +#if HAVE_EXECINFO_H +# include // For backtrace(). +#endif +#if HAVE_SIGNAL_H +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_DLFCN_H && __GNUG__ +#include +#include +#endif +using namespace llvm; + +static RETSIGTYPE SignalHandler(int Sig); // defined below. + +static SmartMutex SignalsMutex; + +/// InterruptFunction - The function to call if ctrl-c is pressed. +static void (*InterruptFunction)() = 0; + +static std::vector FilesToRemove; +static std::vector > CallBacksToRun; + +// IntSigs - Signals that may interrupt the program at any time. +static const int IntSigs[] = { + SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2 +}; +static const int *const IntSigsEnd = + IntSigs + sizeof(IntSigs) / sizeof(IntSigs[0]); + +// KillSigs - Signals that are synchronous with the program that will cause it +// to die. +static const int KillSigs[] = { + SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV +#ifdef SIGSYS + , SIGSYS +#endif +#ifdef SIGXCPU + , SIGXCPU +#endif +#ifdef SIGXFSZ + , SIGXFSZ +#endif +#ifdef SIGEMT + , SIGEMT +#endif +}; +static const int *const KillSigsEnd = + KillSigs + sizeof(KillSigs) / sizeof(KillSigs[0]); + +static unsigned NumRegisteredSignals = 0; +static struct { + struct sigaction SA; + int SigNo; +} RegisteredSignalInfo[(sizeof(IntSigs)+sizeof(KillSigs))/sizeof(KillSigs[0])]; + + +static void RegisterHandler(int Signal) { + assert(NumRegisteredSignals < + sizeof(RegisteredSignalInfo)/sizeof(RegisteredSignalInfo[0]) && + "Out of space for signal handlers!"); + + struct sigaction NewHandler; + + NewHandler.sa_handler = SignalHandler; + NewHandler.sa_flags = SA_NODEFER|SA_RESETHAND; + sigemptyset(&NewHandler.sa_mask); + + // Install the new handler, save the old one in RegisteredSignalInfo. + sigaction(Signal, &NewHandler, + &RegisteredSignalInfo[NumRegisteredSignals].SA); + RegisteredSignalInfo[NumRegisteredSignals].SigNo = Signal; + ++NumRegisteredSignals; +} + +static void RegisterHandlers() { + // If the handlers are already registered, we're done. + if (NumRegisteredSignals != 0) return; + + std::for_each(IntSigs, IntSigsEnd, RegisterHandler); + std::for_each(KillSigs, KillSigsEnd, RegisterHandler); +} + +static void UnregisterHandlers() { + // Restore all of the signal handlers to how they were before we showed up. + for (unsigned i = 0, e = NumRegisteredSignals; i != e; ++i) + sigaction(RegisteredSignalInfo[i].SigNo, + &RegisteredSignalInfo[i].SA, 0); + NumRegisteredSignals = 0; +} + + +/// RemoveFilesToRemove - Process the FilesToRemove list. This function +/// should be called with the SignalsMutex lock held. +static void RemoveFilesToRemove() { + while (!FilesToRemove.empty()) { + FilesToRemove.back().eraseFromDisk(true); + FilesToRemove.pop_back(); + } +} + +// SignalHandler - The signal handler that runs. +static RETSIGTYPE SignalHandler(int Sig) { + // Restore the signal behavior to default, so that the program actually + // crashes when we return and the signal reissues. This also ensures that if + // we crash in our signal handler that the program will terminate immediately + // instead of recursing in the signal handler. + UnregisterHandlers(); + + // Unmask all potentially blocked kill signals. + sigset_t SigMask; + sigfillset(&SigMask); + sigprocmask(SIG_UNBLOCK, &SigMask, 0); + + SignalsMutex.acquire(); + RemoveFilesToRemove(); + + if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd) { + if (InterruptFunction) { + void (*IF)() = InterruptFunction; + SignalsMutex.release(); + InterruptFunction = 0; + IF(); // run the interrupt function. + return; + } + + SignalsMutex.release(); + raise(Sig); // Execute the default handler. + return; + } + + SignalsMutex.release(); + + // Otherwise if it is a fault (like SEGV) run any handler. + for (unsigned i = 0, e = CallBacksToRun.size(); i != e; ++i) + CallBacksToRun[i].first(CallBacksToRun[i].second); +} + +void llvm::sys::RunInterruptHandlers() { + SignalsMutex.acquire(); + RemoveFilesToRemove(); + SignalsMutex.release(); +} + +void llvm::sys::SetInterruptFunction(void (*IF)()) { + SignalsMutex.acquire(); + InterruptFunction = IF; + SignalsMutex.release(); + RegisterHandlers(); +} + +// RemoveFileOnSignal - The public API +bool llvm::sys::RemoveFileOnSignal(const sys::Path &Filename, + std::string* ErrMsg) { + SignalsMutex.acquire(); + FilesToRemove.push_back(Filename); + + SignalsMutex.release(); + + RegisterHandlers(); + return false; +} + +// DontRemoveFileOnSignal - The public API +void llvm::sys::DontRemoveFileOnSignal(const sys::Path &Filename) { + SignalsMutex.acquire(); + std::vector::reverse_iterator I = + std::find(FilesToRemove.rbegin(), FilesToRemove.rend(), Filename); + if (I != FilesToRemove.rend()) + FilesToRemove.erase(I.base()-1); + SignalsMutex.release(); +} + +/// AddSignalHandler - Add a function to be called when a signal is delivered +/// to the process. The handler can have a cookie passed to it to identify +/// what instance of the handler it is. +void llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { + CallBacksToRun.push_back(std::make_pair(FnPtr, Cookie)); + RegisterHandlers(); +} + + +// PrintStackTrace - In the case of a program crash or fault, print out a stack +// trace so that the user has an indication of why and where we died. +// +// On glibc systems we have the 'backtrace' function, which works nicely, but +// doesn't demangle symbols. +static void PrintStackTrace(void *) { +#ifdef HAVE_BACKTRACE + static void* StackTrace[256]; + // Use backtrace() to output a backtrace on Linux systems with glibc. + int depth = backtrace(StackTrace, + static_cast(array_lengthof(StackTrace))); +#if HAVE_DLFCN_H && __GNUG__ + int width = 0; + for (int i = 0; i < depth; ++i) { + Dl_info dlinfo; + dladdr(StackTrace[i], &dlinfo); + const char* name = strrchr(dlinfo.dli_fname, '/'); + + int nwidth; + if (name == NULL) nwidth = strlen(dlinfo.dli_fname); + else nwidth = strlen(name) - 1; + + if (nwidth > width) width = nwidth; + } + + for (int i = 0; i < depth; ++i) { + Dl_info dlinfo; + dladdr(StackTrace[i], &dlinfo); + + fprintf(stderr, "%-2d", i); + + const char* name = strrchr(dlinfo.dli_fname, '/'); + if (name == NULL) fprintf(stderr, " %-*s", width, dlinfo.dli_fname); + else fprintf(stderr, " %-*s", width, name+1); + + fprintf(stderr, " %#0*lx", + (int)(sizeof(void*) * 2) + 2, (unsigned long)StackTrace[i]); + + if (dlinfo.dli_sname != NULL) { + int res; + fputc(' ', stderr); + char* d = abi::__cxa_demangle(dlinfo.dli_sname, NULL, NULL, &res); + if (d == NULL) fputs(dlinfo.dli_sname, stderr); + else fputs(d, stderr); + free(d); + + fprintf(stderr, " + %tu",(char*)StackTrace[i]-(char*)dlinfo.dli_saddr); + } + fputc('\n', stderr); + } +#else + backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO); +#endif +#endif +} + +/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or +/// SIGSEGV) is delivered to the process, print a stack trace and then exit. +void llvm::sys::PrintStackTraceOnErrorSignal() { + AddSignalHandler(PrintStackTrace, 0); +} + + +/***/ + +// On Darwin, raise sends a signal to the main thread instead of the current +// thread. This has the unfortunate effect that assert() and abort() will end up +// bypassing our crash recovery attempts. We work around this for anything in +// the same linkage unit by just defining our own versions of the assert handler +// and abort. + +#ifdef __APPLE__ + +int raise(int sig) { + return pthread_kill(pthread_self(), sig); +} + +void __assert_rtn(const char *func, + const char *file, + int line, + const char *expr) { + if (func) + fprintf(stderr, "Assertion failed: (%s), function %s, file %s, line %d.\n", + expr, func, file, line); + else + fprintf(stderr, "Assertion failed: (%s), file %s, line %d.\n", + expr, file, line); + abort(); +} + +#include +#include + +void abort() { + raise(SIGABRT); + usleep(1000); + __builtin_trap(); +} + +#endif diff --git a/lib/Support/Unix/ThreadLocal.inc b/lib/Support/Unix/ThreadLocal.inc new file mode 100644 index 000000000000..2b4c9017cd91 --- /dev/null +++ b/lib/Support/Unix/ThreadLocal.inc @@ -0,0 +1,26 @@ +//=== llvm/Support/Unix/ThreadLocal.inc - Unix Thread Local Data -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific (non-pthread) ThreadLocal class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +namespace llvm { +using namespace sys; +ThreadLocalImpl::ThreadLocalImpl() { } +ThreadLocalImpl::~ThreadLocalImpl() { } +void ThreadLocalImpl::setInstance(const void* d) { data = const_cast(d);} +const void* ThreadLocalImpl::getInstance() { return data; } +void ThreadLocalImpl::removeInstance() { setInstance(0); } +} diff --git a/lib/Support/Unix/TimeValue.inc b/lib/Support/Unix/TimeValue.inc new file mode 100644 index 000000000000..5cf5a9d44ed6 --- /dev/null +++ b/lib/Support/Unix/TimeValue.inc @@ -0,0 +1,56 @@ +//===- Unix/TimeValue.cpp - Unix TimeValue Implementation -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific portion of the TimeValue class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include "Unix.h" + +namespace llvm { + using namespace sys; + +std::string TimeValue::str() const { + char buffer[32]; + + time_t ourTime = time_t(this->toEpochTime()); +#ifdef __hpux +// note that the following line needs -D_REENTRANT on HP-UX to be picked up + asctime_r(localtime(&ourTime), buffer); +#else + ::asctime_r(::localtime(&ourTime), buffer); +#endif + + std::string result(buffer); + return result.substr(0,24); +} + +TimeValue TimeValue::now() { + struct timeval the_time; + timerclear(&the_time); + if (0 != ::gettimeofday(&the_time,0)) { + // This is *really* unlikely to occur because the only gettimeofday + // errors concern the timezone parameter which we're passing in as 0. + // In the unlikely case it does happen, just return MinTime, no error + // message needed. + return MinTime; + } + + return TimeValue( + static_cast( the_time.tv_sec + PosixZeroTime.seconds_ ), + static_cast( the_time.tv_usec * + NANOSECONDS_PER_MICROSECOND ) ); +} + +} diff --git a/lib/Support/Unix/Unix.h b/lib/Support/Unix/Unix.h new file mode 100644 index 000000000000..b7be3111d431 --- /dev/null +++ b/lib/Support/Unix/Unix.h @@ -0,0 +1,87 @@ +//===- llvm/Support/Unix/Unix.h - Common Unix Include File -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines things specific to Unix implementations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_UNIX_UNIX_H +#define LLVM_SYSTEM_UNIX_UNIX_H + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on all UNIX variants. +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" // Get autoconf configuration settings +#include "llvm/Support/Errno.h" +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef HAVE_ASSERT_H +#include +#endif + +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else +# ifdef HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#ifdef HAVE_SYS_WAIT_H +# include +#endif + +#ifndef WEXITSTATUS +# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#endif + +#ifndef WIFEXITED +# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif + +/// This function builds an error message into \p ErrMsg using the \p prefix +/// string and the Unix error number given by \p errnum. If errnum is -1, the +/// default then the value of errno is used. +/// @brief Make an error message +/// +/// If the error number can be converted to a string, it will be +/// separated from prefix by ": ". +static inline bool MakeErrMsg( + std::string* ErrMsg, const std::string& prefix, int errnum = -1) { + if (!ErrMsg) + return true; + if (errnum == -1) + errnum = errno; + *ErrMsg = prefix + ": " + llvm::sys::StrError(errnum); + return true; +} + +#endif diff --git a/lib/Support/Unix/system_error.inc b/lib/Support/Unix/system_error.inc new file mode 100644 index 000000000000..681e919edb4e --- /dev/null +++ b/lib/Support/Unix/system_error.inc @@ -0,0 +1,34 @@ +//===- llvm/Support/Unix/system_error.inc - Unix error_code ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Unix specific implementation of the error_code +// and error_condition classes. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +using namespace llvm; + +std::string +_system_error_category::message(int ev) const { + return _do_message::message(ev); +} + +error_condition +_system_error_category::default_error_condition(int ev) const { +#ifdef ELAST + if (ev > ELAST) + return error_condition(ev, system_category()); +#endif // ELAST + return error_condition(ev, generic_category()); +} diff --git a/lib/Support/Valgrind.cpp b/lib/Support/Valgrind.cpp new file mode 100644 index 000000000000..703448524ed9 --- /dev/null +++ b/lib/Support/Valgrind.cpp @@ -0,0 +1,54 @@ +//===-- Valgrind.cpp - Implement Valgrind communication ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines Valgrind communication methods, if HAVE_VALGRIND_VALGRIND_H is +// defined. If we have valgrind.h but valgrind isn't running, its macros are +// no-ops. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Valgrind.h" +#include "llvm/Config/config.h" + +#if HAVE_VALGRIND_VALGRIND_H +#include + +static bool InitNotUnderValgrind() { + return !RUNNING_ON_VALGRIND; +} + +// This bool is negated from what we'd expect because code may run before it +// gets initialized. If that happens, it will appear to be 0 (false), and we +// want that to cause the rest of the code in this file to run the +// Valgrind-provided macros. +static const bool NotUnderValgrind = InitNotUnderValgrind(); + +bool llvm::sys::RunningOnValgrind() { + if (NotUnderValgrind) + return false; + return RUNNING_ON_VALGRIND; +} + +void llvm::sys::ValgrindDiscardTranslations(const void *Addr, size_t Len) { + if (NotUnderValgrind) + return; + + VALGRIND_DISCARD_TRANSLATIONS(Addr, Len); +} + +#else // !HAVE_VALGRIND_VALGRIND_H + +bool llvm::sys::RunningOnValgrind() { + return false; +} + +void llvm::sys::ValgrindDiscardTranslations(const void *Addr, size_t Len) { +} + +#endif // !HAVE_VALGRIND_VALGRIND_H diff --git a/lib/Support/Windows/DynamicLibrary.inc b/lib/Support/Windows/DynamicLibrary.inc new file mode 100644 index 000000000000..2c14366c0761 --- /dev/null +++ b/lib/Support/Windows/DynamicLibrary.inc @@ -0,0 +1,166 @@ +//===- Win32/DynamicLibrary.cpp - Win32 DL Implementation -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of DynamicLibrary. +// +//===----------------------------------------------------------------------===// + +#include "Windows.h" + +#ifdef __MINGW32__ + #include +#else + #include +#endif + +#ifdef _MSC_VER + #include +#endif + +#ifdef __MINGW32__ + #if (HAVE_LIBIMAGEHLP != 1) + #error "libimagehlp.a should be present" + #endif +#else + #pragma comment(lib, "dbghelp.lib") +#endif + +namespace llvm { +using namespace sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code +//=== and must not be UNIX code. +//===----------------------------------------------------------------------===// + +static std::vector OpenedHandles; + +#ifdef _WIN64 + typedef DWORD64 ModuleBaseType; +#else + typedef ULONG ModuleBaseType; +#endif + +extern "C" { +// Use old callback if: +// - Not using Visual Studio +// - Visual Studio 2005 or earlier but only if we are not using the Windows SDK +// or Windows SDK version is older than 6.0 +// Use new callback if: +// - Newer Visual Studio (comes with newer SDK). +// - Visual Studio 2005 with Windows SDK 6.0+ +#if defined(_MSC_VER) + #if _MSC_VER < 1500 && (!defined(VER_PRODUCTBUILD) || VER_PRODUCTBUILD < 6000) + #define OLD_ELM_CALLBACK_DECL 1 + #endif +#elif defined(__MINGW64__) + // Use new callback. +#elif defined(__MINGW32__) + #define OLD_ELM_CALLBACK_DECL 1 +#endif + +#ifdef OLD_ELM_CALLBACK_DECL + static BOOL CALLBACK ELM_Callback(PSTR ModuleName, + ModuleBaseType ModuleBase, + ULONG ModuleSize, + PVOID UserContext) +#else + static BOOL CALLBACK ELM_Callback(PCSTR ModuleName, + ModuleBaseType ModuleBase, + ULONG ModuleSize, + PVOID UserContext) +#endif + { + // Ignore VC++ runtimes prior to 7.1. Somehow some of them get loaded + // into the process. + if (stricmp(ModuleName, "msvci70") != 0 && + stricmp(ModuleName, "msvcirt") != 0 && + stricmp(ModuleName, "msvcp50") != 0 && + stricmp(ModuleName, "msvcp60") != 0 && + stricmp(ModuleName, "msvcp70") != 0 && + stricmp(ModuleName, "msvcr70") != 0 && +#ifndef __MINGW32__ + // Mingw32 uses msvcrt.dll by default. Don't ignore it. + // Otherwise, user should be aware, what he's doing :) + stricmp(ModuleName, "msvcrt") != 0 && +#endif + stricmp(ModuleName, "msvcrt20") != 0 && + stricmp(ModuleName, "msvcrt40") != 0) { + OpenedHandles.push_back((HMODULE)ModuleBase); + } + return TRUE; + } +} + +bool DynamicLibrary::LoadLibraryPermanently(const char *filename, + std::string *ErrMsg) { + if (filename) { + HMODULE a_handle = LoadLibrary(filename); + + if (a_handle == 0) + return MakeErrMsg(ErrMsg, std::string(filename) + ": Can't open : "); + + OpenedHandles.push_back(a_handle); + } else { + // When no file is specified, enumerate all DLLs and EXEs in the + // process. + EnumerateLoadedModules(GetCurrentProcess(), ELM_Callback, 0); + } + + // Because we don't remember the handle, we will never free it; hence, + // it is loaded permanently. + return false; +} + +// Stack probing routines are in the support library (e.g. libgcc), but we don't +// have dynamic linking on windows. Provide a hook. +#define EXPLICIT_SYMBOL(SYM) \ + extern "C" { extern void *SYM; } +#define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) EXPLICIT_SYMBOL(SYMTO) + +#include "explicit_symbols.inc" + +#undef EXPLICIT_SYMBOL +#undef EXPLICIT_SYMBOL2 + +void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) { + // First check symbols added via AddSymbol(). + if (ExplicitSymbols) { + std::map::iterator I = + ExplicitSymbols->find(symbolName); + std::map::iterator E = ExplicitSymbols->end(); + if (I != E) + return I->second; + } + + // Now search the libraries. + for (std::vector::iterator I = OpenedHandles.begin(), + E = OpenedHandles.end(); I != E; ++I) { + FARPROC ptr = GetProcAddress((HMODULE)*I, symbolName); + if (ptr) { + return (void *) ptr; + } + } + + #define EXPLICIT_SYMBOL(SYM) \ + if (!strcmp(symbolName, #SYM)) return (void*)&SYM; + #define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) \ + if (!strcmp(symbolName, #SYMFROM)) return (void*)&SYMTO; + + { + #include "explicit_symbols.inc" + } + + #undef EXPLICIT_SYMBOL + #undef EXPLICIT_SYMBOL2 + + return 0; +} + +} diff --git a/lib/Support/Windows/Host.inc b/lib/Support/Windows/Host.inc new file mode 100644 index 000000000000..733830e82f08 --- /dev/null +++ b/lib/Support/Windows/Host.inc @@ -0,0 +1,23 @@ +//===- llvm/Support/Win32/Host.inc -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Win32 Host support. +// +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include +#include + +using namespace llvm; + +std::string sys::getHostTriple() { + // FIXME: Adapt to running version. + return LLVM_HOSTTRIPLE; +} diff --git a/lib/Support/Windows/Memory.inc b/lib/Support/Windows/Memory.inc new file mode 100644 index 000000000000..9f69e7367e6f --- /dev/null +++ b/lib/Support/Windows/Memory.inc @@ -0,0 +1,73 @@ +//===- Win32/Memory.cpp - Win32 Memory Implementation -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of various Memory +// management utilities +// +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Process.h" + +namespace llvm { +using namespace sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code +//=== and must not be UNIX code +//===----------------------------------------------------------------------===// + +MemoryBlock Memory::AllocateRWX(size_t NumBytes, + const MemoryBlock *NearBlock, + std::string *ErrMsg) { + if (NumBytes == 0) return MemoryBlock(); + + static const size_t pageSize = Process::GetPageSize(); + size_t NumPages = (NumBytes+pageSize-1)/pageSize; + + //FIXME: support NearBlock if ever needed on Win64. + + void *pa = VirtualAlloc(NULL, NumPages*pageSize, MEM_COMMIT, + PAGE_EXECUTE_READWRITE); + if (pa == NULL) { + MakeErrMsg(ErrMsg, "Can't allocate RWX Memory: "); + return MemoryBlock(); + } + + MemoryBlock result; + result.Address = pa; + result.Size = NumPages*pageSize; + return result; +} + +bool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { + if (M.Address == 0 || M.Size == 0) return false; + if (!VirtualFree(M.Address, 0, MEM_RELEASE)) + return MakeErrMsg(ErrMsg, "Can't release RWX Memory: "); + return false; +} + +bool Memory::setWritable(MemoryBlock &M, std::string *ErrMsg) { + return true; +} + +bool Memory::setExecutable(MemoryBlock &M, std::string *ErrMsg) { + return false; +} + +bool Memory::setRangeWritable(const void *Addr, size_t Size) { + return true; +} + +bool Memory::setRangeExecutable(const void *Addr, size_t Size) { + return false; +} + +} diff --git a/lib/Support/Windows/Mutex.inc b/lib/Support/Windows/Mutex.inc new file mode 100644 index 000000000000..583dc6359a16 --- /dev/null +++ b/lib/Support/Windows/Mutex.inc @@ -0,0 +1,58 @@ +//===- llvm/Support/Win32/Mutex.inc - Win32 Mutex Implementation -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Win32 specific (non-pthread) Mutex class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Win32 code that +//=== is guaranteed to work on *all* Win32 variants. +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include "llvm/Support/Mutex.h" + +namespace llvm { +using namespace sys; + +MutexImpl::MutexImpl(bool /*recursive*/) +{ + data_ = new CRITICAL_SECTION; + InitializeCriticalSection((LPCRITICAL_SECTION)data_); +} + +MutexImpl::~MutexImpl() +{ + DeleteCriticalSection((LPCRITICAL_SECTION)data_); + delete (LPCRITICAL_SECTION)data_; + data_ = 0; +} + +bool +MutexImpl::acquire() +{ + EnterCriticalSection((LPCRITICAL_SECTION)data_); + return true; +} + +bool +MutexImpl::release() +{ + LeaveCriticalSection((LPCRITICAL_SECTION)data_); + return true; +} + +bool +MutexImpl::tryacquire() +{ + return TryEnterCriticalSection((LPCRITICAL_SECTION)data_); +} + +} diff --git a/lib/Support/Windows/Path.inc b/lib/Support/Windows/Path.inc new file mode 100644 index 000000000000..625f67aa912a --- /dev/null +++ b/lib/Support/Windows/Path.inc @@ -0,0 +1,921 @@ +//===- llvm/Support/Win32/Path.cpp - Win32 Path Implementation ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of the Path class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Win32 code that +//=== is guaranteed to work on *all* Win32 variants. +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include +#include + +// We need to undo a macro defined in Windows.h, otherwise we won't compile: +#undef CopyFile +#undef GetCurrentDirectory + +// Windows happily accepts either forward or backward slashes, though any path +// returned by a Win32 API will have backward slashes. As LLVM code basically +// assumes forward slashes are used, backward slashs are converted where they +// can be introduced into a path. +// +// Another invariant is that a path ends with a slash if and only if the path +// is a root directory. Any other use of a trailing slash is stripped. Unlike +// in Unix, Windows has a rather complicated notion of a root path and this +// invariant helps simply the code. + +static void FlipBackSlashes(std::string& s) { + for (size_t i = 0; i < s.size(); i++) + if (s[i] == '\\') + s[i] = '/'; +} + +namespace llvm { +namespace sys { + +const char PathSeparator = ';'; + +StringRef Path::GetEXESuffix() { + return "exe"; +} + +Path::Path(llvm::StringRef p) + : path(p) { + FlipBackSlashes(path); +} + +Path::Path(const char *StrStart, unsigned StrLen) + : path(StrStart, StrLen) { + FlipBackSlashes(path); +} + +Path& +Path::operator=(StringRef that) { + path.assign(that.data(), that.size()); + FlipBackSlashes(path); + return *this; +} + +// push_back 0 on create, and pop_back on delete. +struct ScopedNullTerminator { + std::string &str; + ScopedNullTerminator(std::string &s) : str(s) { str.push_back(0); } + ~ScopedNullTerminator() { + // str.pop_back(); But wait, C++03 doesn't have this... + assert(!str.empty() && str[str.size() - 1] == 0 + && "Null char not present!"); + str.resize(str.size() - 1); + } +}; + +bool +Path::isValid() const { + if (path.empty()) + return false; + + // If there is a colon, it must be the second character, preceded by a letter + // and followed by something. + size_t len = path.size(); + // This code assumes that path is null terminated, so make sure it is. + ScopedNullTerminator snt(path); + size_t pos = path.rfind(':',len); + size_t rootslash = 0; + if (pos != std::string::npos) { + if (pos != 1 || !isalpha(path[0]) || len < 3) + return false; + rootslash = 2; + } + + // Look for a UNC path, and if found adjust our notion of the root slash. + if (len > 3 && path[0] == '/' && path[1] == '/') { + rootslash = path.find('/', 2); + if (rootslash == std::string::npos) + rootslash = 0; + } + + // Check for illegal characters. + if (path.find_first_of("\\<>\"|\001\002\003\004\005\006\007\010\011\012" + "\013\014\015\016\017\020\021\022\023\024\025\026" + "\027\030\031\032\033\034\035\036\037") + != std::string::npos) + return false; + + // Remove trailing slash, unless it's a root slash. + if (len > rootslash+1 && path[len-1] == '/') + path.erase(--len); + + // Check each component for legality. + for (pos = 0; pos < len; ++pos) { + // A component may not end in a space. + if (path[pos] == ' ') { + if (path[pos+1] == '/' || path[pos+1] == '\0') + return false; + } + + // A component may not end in a period. + if (path[pos] == '.') { + if (path[pos+1] == '/' || path[pos+1] == '\0') { + // Unless it is the pseudo-directory "."... + if (pos == 0 || path[pos-1] == '/' || path[pos-1] == ':') + return true; + // or "..". + if (pos > 0 && path[pos-1] == '.') { + if (pos == 1 || path[pos-2] == '/' || path[pos-2] == ':') + return true; + } + return false; + } + } + } + + return true; +} + +void Path::makeAbsolute() { + TCHAR FullPath[MAX_PATH + 1] = {0}; + LPTSTR FilePart = NULL; + + DWORD RetLength = ::GetFullPathNameA(path.c_str(), + sizeof(FullPath)/sizeof(FullPath[0]), + FullPath, &FilePart); + + if (0 == RetLength) { + // FIXME: Report the error GetLastError() + assert(0 && "Unable to make absolute path!"); + } else if (RetLength > MAX_PATH) { + // FIXME: Report too small buffer (needed RetLength bytes). + assert(0 && "Unable to make absolute path!"); + } else { + path = FullPath; + } +} + +bool +Path::isAbsolute(const char *NameStart, unsigned NameLen) { + assert(NameStart); + // FIXME: This does not handle correctly an absolute path starting from + // a drive letter or in UNC format. + switch (NameLen) { + case 0: + return false; + case 1: + case 2: + return NameStart[0] == '/'; + default: + return + (NameStart[0] == '/' || (NameStart[1] == ':' && NameStart[2] == '/')) || + (NameStart[0] == '\\' || (NameStart[1] == ':' && NameStart[2] == '\\')); + } +} + +bool +Path::isAbsolute() const { + // FIXME: This does not handle correctly an absolute path starting from + // a drive letter or in UNC format. + switch (path.length()) { + case 0: + return false; + case 1: + case 2: + return path[0] == '/'; + default: + return path[0] == '/' || (path[1] == ':' && path[2] == '/'); + } +} + +static Path *TempDirectory; + +Path +Path::GetTemporaryDirectory(std::string* ErrMsg) { + if (TempDirectory) + return *TempDirectory; + + char pathname[MAX_PATH]; + if (!GetTempPath(MAX_PATH, pathname)) { + if (ErrMsg) + *ErrMsg = "Can't determine temporary directory"; + return Path(); + } + + Path result; + result.set(pathname); + + // Append a subdirectory passed on our process id so multiple LLVMs don't + // step on each other's toes. +#ifdef __MINGW32__ + // Mingw's Win32 header files are broken. + sprintf(pathname, "LLVM_%u", unsigned(GetCurrentProcessId())); +#else + sprintf(pathname, "LLVM_%u", GetCurrentProcessId()); +#endif + result.appendComponent(pathname); + + // If there's a directory left over from a previous LLVM execution that + // happened to have the same process id, get rid of it. + result.eraseFromDisk(true); + + // And finally (re-)create the empty directory. + result.createDirectoryOnDisk(false); + TempDirectory = new Path(result); + return *TempDirectory; +} + +// FIXME: the following set of functions don't map to Windows very well. +Path +Path::GetRootDirectory() { + // This is the only notion that that Windows has of a root directory. Nothing + // is here except for drives. + return Path("file:///"); +} + +void +Path::GetSystemLibraryPaths(std::vector& Paths) { + char buff[MAX_PATH]; + // Generic form of C:\Windows\System32 + HRESULT res = SHGetFolderPathA(NULL, + CSIDL_FLAG_CREATE | CSIDL_SYSTEM, + NULL, + SHGFP_TYPE_CURRENT, + buff); + if (res != S_OK) { + assert(0 && "Failed to get system directory"); + return; + } + Paths.push_back(sys::Path(buff)); + + // Reset buff. + buff[0] = 0; + // Generic form of C:\Windows + res = SHGetFolderPathA(NULL, + CSIDL_FLAG_CREATE | CSIDL_WINDOWS, + NULL, + SHGFP_TYPE_CURRENT, + buff); + if (res != S_OK) { + assert(0 && "Failed to get windows directory"); + return; + } + Paths.push_back(sys::Path(buff)); +} + +void +Path::GetBitcodeLibraryPaths(std::vector& Paths) { + char * env_var = getenv("LLVM_LIB_SEARCH_PATH"); + if (env_var != 0) { + getPathList(env_var,Paths); + } +#ifdef LLVM_LIBDIR + { + Path tmpPath; + if (tmpPath.set(LLVM_LIBDIR)) + if (tmpPath.canRead()) + Paths.push_back(tmpPath); + } +#endif + GetSystemLibraryPaths(Paths); +} + +Path +Path::GetLLVMDefaultConfigDir() { + Path ret = GetUserHomeDirectory(); + if (!ret.appendComponent(".llvm")) + assert(0 && "Failed to append .llvm"); + return ret; +} + +Path +Path::GetUserHomeDirectory() { + char buff[MAX_PATH]; + HRESULT res = SHGetFolderPathA(NULL, + CSIDL_FLAG_CREATE | CSIDL_APPDATA, + NULL, + SHGFP_TYPE_CURRENT, + buff); + if (res != S_OK) + assert(0 && "Failed to get user home directory"); + return Path(buff); +} + +Path +Path::GetCurrentDirectory() { + char pathname[MAX_PATH]; + ::GetCurrentDirectoryA(MAX_PATH,pathname); + return Path(pathname); +} + +/// GetMainExecutable - Return the path to the main executable, given the +/// value of argv[0] from program startup. +Path Path::GetMainExecutable(const char *argv0, void *MainAddr) { + char pathname[MAX_PATH]; + DWORD ret = ::GetModuleFileNameA(NULL, pathname, MAX_PATH); + return ret != MAX_PATH ? Path(pathname) : Path(); +} + + +// FIXME: the above set of functions don't map to Windows very well. + + +StringRef Path::getDirname() const { + return getDirnameCharSep(path, "/"); +} + +StringRef +Path::getBasename() const { + // Find the last slash + size_t slash = path.rfind('/'); + if (slash == std::string::npos) + slash = 0; + else + slash++; + + size_t dot = path.rfind('.'); + if (dot == std::string::npos || dot < slash) + return StringRef(path).substr(slash); + else + return StringRef(path).substr(slash, dot - slash); +} + +StringRef +Path::getSuffix() const { + // Find the last slash + size_t slash = path.rfind('/'); + if (slash == std::string::npos) + slash = 0; + else + slash++; + + size_t dot = path.rfind('.'); + if (dot == std::string::npos || dot < slash) + return StringRef(""); + else + return StringRef(path).substr(dot + 1); +} + +bool +Path::exists() const { + DWORD attr = GetFileAttributes(path.c_str()); + return attr != INVALID_FILE_ATTRIBUTES; +} + +bool +Path::isDirectory() const { + DWORD attr = GetFileAttributes(path.c_str()); + return (attr != INVALID_FILE_ATTRIBUTES) && + (attr & FILE_ATTRIBUTE_DIRECTORY); +} + +bool +Path::isSymLink() const { + DWORD attributes = GetFileAttributes(path.c_str()); + + if (attributes == INVALID_FILE_ATTRIBUTES) + // There's no sane way to report this :(. + assert(0 && "GetFileAttributes returned INVALID_FILE_ATTRIBUTES"); + + // This isn't exactly what defines a NTFS symlink, but it is only true for + // paths that act like a symlink. + return attributes & FILE_ATTRIBUTE_REPARSE_POINT; +} + +bool +Path::canRead() const { + // FIXME: take security attributes into account. + DWORD attr = GetFileAttributes(path.c_str()); + return attr != INVALID_FILE_ATTRIBUTES; +} + +bool +Path::canWrite() const { + // FIXME: take security attributes into account. + DWORD attr = GetFileAttributes(path.c_str()); + return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_READONLY); +} + +bool +Path::canExecute() const { + // FIXME: take security attributes into account. + DWORD attr = GetFileAttributes(path.c_str()); + return attr != INVALID_FILE_ATTRIBUTES; +} + +bool +Path::isRegularFile() const { + bool res; + if (fs::is_regular_file(path, res)) + return false; + return res; +} + +StringRef +Path::getLast() const { + // Find the last slash + size_t pos = path.rfind('/'); + + // Handle the corner cases + if (pos == std::string::npos) + return path; + + // If the last character is a slash, we have a root directory + if (pos == path.length()-1) + return path; + + // Return everything after the last slash + return StringRef(path).substr(pos+1); +} + +const FileStatus * +PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const { + if (!fsIsValid || update) { + WIN32_FILE_ATTRIBUTE_DATA fi; + if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) { + MakeErrMsg(ErrStr, "getStatusInfo():" + std::string(path) + + ": Can't get status: "); + return 0; + } + + status.fileSize = fi.nFileSizeHigh; + status.fileSize <<= sizeof(fi.nFileSizeHigh)*8; + status.fileSize += fi.nFileSizeLow; + + status.mode = fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? 0555 : 0777; + status.user = 9999; // Not applicable to Windows, so... + status.group = 9999; // Not applicable to Windows, so... + + // FIXME: this is only unique if the file is accessed by the same file path. + // How do we do this for C:\dir\file and ..\dir\file ? Unix has inode + // numbers, but the concept doesn't exist in Windows. + status.uniqueID = 0; + for (unsigned i = 0; i < path.length(); ++i) + status.uniqueID += path[i]; + + ULARGE_INTEGER ui; + ui.LowPart = fi.ftLastWriteTime.dwLowDateTime; + ui.HighPart = fi.ftLastWriteTime.dwHighDateTime; + status.modTime.fromWin32Time(ui.QuadPart); + + status.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; + fsIsValid = true; + } + return &status; +} + +bool Path::makeReadableOnDisk(std::string* ErrMsg) { + // All files are readable on Windows (ignoring security attributes). + return false; +} + +bool Path::makeWriteableOnDisk(std::string* ErrMsg) { + DWORD attr = GetFileAttributes(path.c_str()); + + // If it doesn't exist, we're done. + if (attr == INVALID_FILE_ATTRIBUTES) + return false; + + if (attr & FILE_ATTRIBUTE_READONLY) { + if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY)) { + MakeErrMsg(ErrMsg, std::string(path) + ": Can't make file writable: "); + return true; + } + } + return false; +} + +bool Path::makeExecutableOnDisk(std::string* ErrMsg) { + // All files are executable on Windows (ignoring security attributes). + return false; +} + +bool +Path::getDirectoryContents(std::set& result, std::string* ErrMsg) const { + WIN32_FILE_ATTRIBUTE_DATA fi; + if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) { + MakeErrMsg(ErrMsg, path + ": can't get status of file"); + return true; + } + + if (!(fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + if (ErrMsg) + *ErrMsg = path + ": not a directory"; + return true; + } + + result.clear(); + WIN32_FIND_DATA fd; + std::string searchpath = path; + if (path.size() == 0 || searchpath[path.size()-1] == '/') + searchpath += "*"; + else + searchpath += "/*"; + + HANDLE h = FindFirstFile(searchpath.c_str(), &fd); + if (h == INVALID_HANDLE_VALUE) { + if (GetLastError() == ERROR_FILE_NOT_FOUND) + return true; // not really an error, now is it? + MakeErrMsg(ErrMsg, path + ": Can't read directory: "); + return true; + } + + do { + if (fd.cFileName[0] == '.') + continue; + Path aPath(path); + aPath.appendComponent(&fd.cFileName[0]); + result.insert(aPath); + } while (FindNextFile(h, &fd)); + + DWORD err = GetLastError(); + FindClose(h); + if (err != ERROR_NO_MORE_FILES) { + SetLastError(err); + MakeErrMsg(ErrMsg, path + ": Can't read directory: "); + return true; + } + return false; +} + +bool +Path::set(StringRef a_path) { + if (a_path.empty()) + return false; + std::string save(path); + path = a_path; + FlipBackSlashes(path); + if (!isValid()) { + path = save; + return false; + } + return true; +} + +bool +Path::appendComponent(StringRef name) { + if (name.empty()) + return false; + std::string save(path); + if (!path.empty()) { + size_t last = path.size() - 1; + if (path[last] != '/') + path += '/'; + } + path += name; + if (!isValid()) { + path = save; + return false; + } + return true; +} + +bool +Path::eraseComponent() { + size_t slashpos = path.rfind('/',path.size()); + if (slashpos == path.size() - 1 || slashpos == std::string::npos) + return false; + std::string save(path); + path.erase(slashpos); + if (!isValid()) { + path = save; + return false; + } + return true; +} + +bool +Path::eraseSuffix() { + size_t dotpos = path.rfind('.',path.size()); + size_t slashpos = path.rfind('/',path.size()); + if (dotpos != std::string::npos) { + if (slashpos == std::string::npos || dotpos > slashpos+1) { + std::string save(path); + path.erase(dotpos, path.size()-dotpos); + if (!isValid()) { + path = save; + return false; + } + return true; + } + } + return false; +} + +inline bool PathMsg(std::string* ErrMsg, const char* pathname, const char*msg) { + if (ErrMsg) + *ErrMsg = std::string(pathname) + ": " + std::string(msg); + return true; +} + +bool +Path::createDirectoryOnDisk(bool create_parents, std::string* ErrMsg) { + // Get a writeable copy of the path name + size_t len = path.length(); + char *pathname = reinterpret_cast(_alloca(len+2)); + path.copy(pathname, len); + pathname[len] = 0; + + // Make sure it ends with a slash. + if (len == 0 || pathname[len - 1] != '/') { + pathname[len] = '/'; + pathname[++len] = 0; + } + + // Determine starting point for initial / search. + char *next = pathname; + if (pathname[0] == '/' && pathname[1] == '/') { + // Skip host name. + next = strchr(pathname+2, '/'); + if (next == NULL) + return PathMsg(ErrMsg, pathname, "badly formed remote directory"); + + // Skip share name. + next = strchr(next+1, '/'); + if (next == NULL) + return PathMsg(ErrMsg, pathname,"badly formed remote directory"); + + next++; + if (*next == 0) + return PathMsg(ErrMsg, pathname, "badly formed remote directory"); + + } else { + if (pathname[1] == ':') + next += 2; // skip drive letter + if (*next == '/') + next++; // skip root directory + } + + // If we're supposed to create intermediate directories + if (create_parents) { + // Loop through the directory components until we're done + while (*next) { + next = strchr(next, '/'); + *next = 0; + if (!CreateDirectory(pathname, NULL) && + GetLastError() != ERROR_ALREADY_EXISTS) + return MakeErrMsg(ErrMsg, + std::string(pathname) + ": Can't create directory: "); + *next++ = '/'; + } + } else { + // Drop trailing slash. + pathname[len-1] = 0; + if (!CreateDirectory(pathname, NULL) && + GetLastError() != ERROR_ALREADY_EXISTS) { + return MakeErrMsg(ErrMsg, std::string(pathname) + + ": Can't create directory: "); + } + } + return false; +} + +bool +Path::createFileOnDisk(std::string* ErrMsg) { + // Create the file + HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) + return MakeErrMsg(ErrMsg, path + ": Can't create file: "); + + CloseHandle(h); + return false; +} + +bool +Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const { + WIN32_FILE_ATTRIBUTE_DATA fi; + if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) + return true; + + if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + // If it doesn't exist, we're done. + bool Exists; + if (fs::exists(path, Exists) || !Exists) + return false; + + char *pathname = reinterpret_cast(_alloca(path.length()+3)); + int lastchar = path.length() - 1 ; + path.copy(pathname, lastchar+1); + + // Make path end with '/*'. + if (pathname[lastchar] != '/') + pathname[++lastchar] = '/'; + pathname[lastchar+1] = '*'; + pathname[lastchar+2] = 0; + + if (remove_contents) { + WIN32_FIND_DATA fd; + HANDLE h = FindFirstFile(pathname, &fd); + + // It's a bad idea to alter the contents of a directory while enumerating + // its contents. So build a list of its contents first, then destroy them. + + if (h != INVALID_HANDLE_VALUE) { + std::vector list; + + do { + if (strcmp(fd.cFileName, ".") == 0) + continue; + if (strcmp(fd.cFileName, "..") == 0) + continue; + + Path aPath(path); + aPath.appendComponent(&fd.cFileName[0]); + list.push_back(aPath); + } while (FindNextFile(h, &fd)); + + DWORD err = GetLastError(); + FindClose(h); + if (err != ERROR_NO_MORE_FILES) { + SetLastError(err); + return MakeErrMsg(ErrStr, path + ": Can't read directory: "); + } + + for (std::vector::iterator I = list.begin(); I != list.end(); + ++I) { + Path &aPath = *I; + aPath.eraseFromDisk(true); + } + } else { + if (GetLastError() != ERROR_FILE_NOT_FOUND) + return MakeErrMsg(ErrStr, path + ": Can't read directory: "); + } + } + + pathname[lastchar] = 0; + if (!RemoveDirectory(pathname)) + return MakeErrMsg(ErrStr, + std::string(pathname) + ": Can't destroy directory: "); + return false; + } else { + // Read-only files cannot be deleted on Windows. Must remove the read-only + // attribute first. + if (fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + if (!SetFileAttributes(path.c_str(), + fi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)) + return MakeErrMsg(ErrStr, path + ": Can't destroy file: "); + } + + if (!DeleteFile(path.c_str())) + return MakeErrMsg(ErrStr, path + ": Can't destroy file: "); + return false; + } +} + +bool Path::getMagicNumber(std::string& Magic, unsigned len) const { + assert(len < 1024 && "Request for magic string too long"); + char* buf = reinterpret_cast(alloca(len)); + + HANDLE h = CreateFile(path.c_str(), + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (h == INVALID_HANDLE_VALUE) + return false; + + DWORD nRead = 0; + BOOL ret = ReadFile(h, buf, len, &nRead, NULL); + CloseHandle(h); + + if (!ret || nRead != len) + return false; + + Magic = std::string(buf, len); + return true; +} + +bool +Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) { + if (!MoveFileEx(path.c_str(), newName.c_str(), MOVEFILE_REPLACE_EXISTING)) + return MakeErrMsg(ErrMsg, "Can't move '" + path + "' to '" + newName.path + + "': "); + return false; +} + +bool +Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrMsg) const { + // FIXME: should work on directories also. + if (!si.isFile) { + return true; + } + + HANDLE h = CreateFile(path.c_str(), + FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (h == INVALID_HANDLE_VALUE) + return true; + + BY_HANDLE_FILE_INFORMATION bhfi; + if (!GetFileInformationByHandle(h, &bhfi)) { + DWORD err = GetLastError(); + CloseHandle(h); + SetLastError(err); + return MakeErrMsg(ErrMsg, path + ": GetFileInformationByHandle: "); + } + + ULARGE_INTEGER ui; + ui.QuadPart = si.modTime.toWin32Time(); + FILETIME ft; + ft.dwLowDateTime = ui.LowPart; + ft.dwHighDateTime = ui.HighPart; + BOOL ret = SetFileTime(h, NULL, &ft, &ft); + DWORD err = GetLastError(); + CloseHandle(h); + if (!ret) { + SetLastError(err); + return MakeErrMsg(ErrMsg, path + ": SetFileTime: "); + } + + // Best we can do with Unix permission bits is to interpret the owner + // writable bit. + if (si.mode & 0200) { + if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + if (!SetFileAttributes(path.c_str(), + bhfi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)) + return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: "); + } + } else { + if (!(bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) { + if (!SetFileAttributes(path.c_str(), + bhfi.dwFileAttributes | FILE_ATTRIBUTE_READONLY)) + return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: "); + } + } + + return false; +} + +bool +CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg) { + // Can't use CopyFile macro defined in Windows.h because it would mess up the + // above line. We use the expansion it would have in a non-UNICODE build. + if (!::CopyFileA(Src.c_str(), Dest.c_str(), false)) + return MakeErrMsg(ErrMsg, "Can't copy '" + Src.str() + + "' to '" + Dest.str() + "': "); + return false; +} + +bool +Path::makeUnique(bool reuse_current, std::string* ErrMsg) { + bool Exists; + if (reuse_current && (fs::exists(path, Exists) || !Exists)) + return false; // File doesn't exist already, just use it! + + // Reserve space for -XXXXXX at the end. + char *FNBuffer = (char*) alloca(path.size()+8); + unsigned offset = path.size(); + path.copy(FNBuffer, offset); + + // Find a numeric suffix that isn't used by an existing file. Assume there + // won't be more than 1 million files with the same prefix. Probably a safe + // bet. + static unsigned FCounter = 0; + do { + sprintf(FNBuffer+offset, "-%06u", FCounter); + if (++FCounter > 999999) + FCounter = 0; + path = FNBuffer; + } while (!fs::exists(path, Exists) && Exists); + return false; +} + +bool +Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) { + // Make this into a unique file name + makeUnique(reuse_current, ErrMsg); + + // Now go and create it + HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) + return MakeErrMsg(ErrMsg, path + ": can't create file"); + + CloseHandle(h); + return false; +} + +/// MapInFilePages - Not yet implemented on win32. +const char *Path::MapInFilePages(int FD, uint64_t FileSize) { + return 0; +} + +/// MapInFilePages - Not yet implemented on win32. +void Path::UnMapFilePages(const char *Base, uint64_t FileSize) { + assert(0 && "NOT IMPLEMENTED"); +} + +} +} diff --git a/lib/Support/Windows/PathV2.inc b/lib/Support/Windows/PathV2.inc new file mode 100644 index 000000000000..8effb0c737dd --- /dev/null +++ b/lib/Support/Windows/PathV2.inc @@ -0,0 +1,750 @@ +//===- llvm/Support/Windows/PathV2.inc - Windows Path Impl ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Windows specific implementation of the PathV2 API. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Windows code that +//=== is guaranteed to work on *all* Windows variants. +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include +#include +#include +#include +#include + +// MinGW doesn't define this. +#ifndef _ERRNO_T_DEFINED +#define _ERRNO_T_DEFINED +typedef int errno_t; +#endif + +using namespace llvm; + +namespace { + typedef BOOLEAN (WINAPI *PtrCreateSymbolicLinkW)( + /*__in*/ LPCWSTR lpSymlinkFileName, + /*__in*/ LPCWSTR lpTargetFileName, + /*__in*/ DWORD dwFlags); + + PtrCreateSymbolicLinkW create_symbolic_link_api = PtrCreateSymbolicLinkW( + ::GetProcAddress(::GetModuleHandleA("kernel32.dll"), + "CreateSymbolicLinkW")); + + error_code UTF8ToUTF16(StringRef utf8, SmallVectorImpl &utf16) { + int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + utf8.begin(), utf8.size(), + utf16.begin(), 0); + + if (len == 0) + return windows_error(::GetLastError()); + + utf16.reserve(len + 1); + utf16.set_size(len); + + len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, + utf8.begin(), utf8.size(), + utf16.begin(), utf16.size()); + + if (len == 0) + return windows_error(::GetLastError()); + + // Make utf16 null terminated. + utf16.push_back(0); + utf16.pop_back(); + + return success; + } + + error_code UTF16ToUTF8(const wchar_t *utf16, size_t utf16_len, + SmallVectorImpl &utf8) { + // Get length. + int len = ::WideCharToMultiByte(CP_UTF8, 0, + utf16, utf16_len, + utf8.begin(), 0, + NULL, NULL); + + if (len == 0) + return windows_error(::GetLastError()); + + utf8.reserve(len); + utf8.set_size(len); + + // Now do the actual conversion. + len = ::WideCharToMultiByte(CP_UTF8, 0, + utf16, utf16_len, + utf8.data(), utf8.size(), + NULL, NULL); + + if (len == 0) + return windows_error(::GetLastError()); + + // Make utf8 null terminated. + utf8.push_back(0); + utf8.pop_back(); + + return success; + } + + error_code TempDir(SmallVectorImpl &result) { + retry_temp_dir: + DWORD len = ::GetTempPathW(result.capacity(), result.begin()); + + if (len == 0) + return windows_error(::GetLastError()); + + if (len > result.capacity()) { + result.reserve(len); + goto retry_temp_dir; + } + + result.set_size(len); + return success; + } + + // Forwarder for ScopedHandle. + BOOL WINAPI CryptReleaseContext(HCRYPTPROV Provider) { + return ::CryptReleaseContext(Provider, 0); + } + + typedef ScopedHandle + ScopedCryptContext; + bool is_separator(const wchar_t value) { + switch (value) { + case L'\\': + case L'/': + return true; + default: + return false; + } + } +} + +namespace llvm { +namespace sys { +namespace fs { + +error_code current_path(SmallVectorImpl &result) { + SmallVector cur_path; + cur_path.reserve(128); +retry_cur_dir: + DWORD len = ::GetCurrentDirectoryW(cur_path.capacity(), cur_path.data()); + + // A zero return value indicates a failure other than insufficient space. + if (len == 0) + return windows_error(::GetLastError()); + + // If there's insufficient space, the len returned is larger than the len + // given. + if (len > cur_path.capacity()) { + cur_path.reserve(len); + goto retry_cur_dir; + } + + cur_path.set_size(len); + // cur_path now holds the current directory in utf-16. Convert to utf-8. + + // Find out how much space we need. Sadly, this function doesn't return the + // size needed unless you tell it the result size is 0, which means you + // _always_ have to call it twice. + len = ::WideCharToMultiByte(CP_UTF8, 0, + cur_path.data(), cur_path.size(), + result.data(), 0, + NULL, NULL); + + if (len == 0) + return make_error_code(windows_error(::GetLastError())); + + result.reserve(len); + result.set_size(len); + // Now do the actual conversion. + len = ::WideCharToMultiByte(CP_UTF8, 0, + cur_path.data(), cur_path.size(), + result.data(), result.size(), + NULL, NULL); + if (len == 0) + return windows_error(::GetLastError()); + + return success; +} + +error_code copy_file(const Twine &from, const Twine &to, copy_option copt) { + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toStringRef(from_storage); + StringRef t = to.toStringRef(to_storage); + + // Convert to utf-16. + SmallVector wide_from; + SmallVector wide_to; + if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; + if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; + + // Copy the file. + BOOL res = ::CopyFileW(wide_from.begin(), wide_to.begin(), + copt != copy_option::overwrite_if_exists); + + if (res == 0) + return windows_error(::GetLastError()); + + return success; +} + +error_code create_directory(const Twine &path, bool &existed) { + SmallString<128> path_storage; + SmallVector path_utf16; + + if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), + path_utf16)) + return ec; + + if (!::CreateDirectoryW(path_utf16.begin(), NULL)) { + error_code ec = windows_error(::GetLastError()); + if (ec == windows_error::already_exists) + existed = true; + else + return ec; + } else + existed = false; + + return success; +} + +error_code create_hard_link(const Twine &to, const Twine &from) { + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toStringRef(from_storage); + StringRef t = to.toStringRef(to_storage); + + // Convert to utf-16. + SmallVector wide_from; + SmallVector wide_to; + if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; + if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; + + if (!::CreateHardLinkW(wide_from.begin(), wide_to.begin(), NULL)) + return windows_error(::GetLastError()); + + return success; +} + +error_code create_symlink(const Twine &to, const Twine &from) { + // Only do it if the function is available at runtime. + if (!create_symbolic_link_api) + return make_error_code(errc::function_not_supported); + + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toStringRef(from_storage); + StringRef t = to.toStringRef(to_storage); + + // Convert to utf-16. + SmallVector wide_from; + SmallVector wide_to; + if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; + if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; + + if (!create_symbolic_link_api(wide_from.begin(), wide_to.begin(), 0)) + return windows_error(::GetLastError()); + + return success; +} + +error_code remove(const Twine &path, bool &existed) { + SmallString<128> path_storage; + SmallVector path_utf16; + + file_status st; + if (error_code ec = status(path, st)) + return ec; + + if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), + path_utf16)) + return ec; + + if (st.type() == file_type::directory_file) { + if (!::RemoveDirectoryW(c_str(path_utf16))) { + error_code ec = windows_error(::GetLastError()); + if (ec != windows_error::file_not_found) + return ec; + existed = false; + } else + existed = true; + } else { + if (!::DeleteFileW(c_str(path_utf16))) { + error_code ec = windows_error(::GetLastError()); + if (ec != windows_error::file_not_found) + return ec; + existed = false; + } else + existed = true; + } + + return success; +} + +error_code rename(const Twine &from, const Twine &to) { + // Get arguments. + SmallString<128> from_storage; + SmallString<128> to_storage; + StringRef f = from.toStringRef(from_storage); + StringRef t = to.toStringRef(to_storage); + + // Convert to utf-16. + SmallVector wide_from; + SmallVector wide_to; + if (error_code ec = UTF8ToUTF16(f, wide_from)) return ec; + if (error_code ec = UTF8ToUTF16(t, wide_to)) return ec; + + if (!::MoveFileExW(wide_from.begin(), wide_to.begin(), + MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) + return windows_error(::GetLastError()); + + return success; +} + +error_code resize_file(const Twine &path, uint64_t size) { + SmallString<128> path_storage; + SmallVector path_utf16; + + if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), + path_utf16)) + return ec; + + int fd = ::_wopen(path_utf16.begin(), O_BINARY, S_IREAD | S_IWRITE); + if (fd == -1) + return error_code(errno, generic_category()); +#ifdef HAVE__CHSIZE_S + errno_t error = ::_chsize_s(fd, size); +#else + errno_t error = ::_chsize(fd, size); +#endif + ::close(fd); + return error_code(error, generic_category()); +} + +error_code exists(const Twine &path, bool &result) { + SmallString<128> path_storage; + SmallVector path_utf16; + + if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), + path_utf16)) + return ec; + + DWORD attributes = ::GetFileAttributesW(path_utf16.begin()); + + if (attributes == INVALID_FILE_ATTRIBUTES) { + // See if the file didn't actually exist. + error_code ec = make_error_code(windows_error(::GetLastError())); + if (ec != windows_error::file_not_found && + ec != windows_error::path_not_found) + return ec; + result = false; + } else + result = true; + return success; +} + +error_code equivalent(const Twine &A, const Twine &B, bool &result) { + // Get arguments. + SmallString<128> a_storage; + SmallString<128> b_storage; + StringRef a = A.toStringRef(a_storage); + StringRef b = B.toStringRef(b_storage); + + // Convert to utf-16. + SmallVector wide_a; + SmallVector wide_b; + if (error_code ec = UTF8ToUTF16(a, wide_a)) return ec; + if (error_code ec = UTF8ToUTF16(b, wide_b)) return ec; + + AutoHandle HandleB( + ::CreateFileW(wide_b.begin(), + 0, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + 0)); + + AutoHandle HandleA( + ::CreateFileW(wide_a.begin(), + 0, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + 0, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + 0)); + + // If both handles are invalid, it's an error. + if (HandleA == INVALID_HANDLE_VALUE && + HandleB == INVALID_HANDLE_VALUE) + return windows_error(::GetLastError()); + + // If only one is invalid, it's false. + if (HandleA == INVALID_HANDLE_VALUE && + HandleB == INVALID_HANDLE_VALUE) { + result = false; + return success; + } + + // Get file information. + BY_HANDLE_FILE_INFORMATION InfoA, InfoB; + if (!::GetFileInformationByHandle(HandleA, &InfoA)) + return windows_error(::GetLastError()); + if (!::GetFileInformationByHandle(HandleB, &InfoB)) + return windows_error(::GetLastError()); + + // See if it's all the same. + result = + InfoA.dwVolumeSerialNumber == InfoB.dwVolumeSerialNumber && + InfoA.nFileIndexHigh == InfoB.nFileIndexHigh && + InfoA.nFileIndexLow == InfoB.nFileIndexLow && + InfoA.nFileSizeHigh == InfoB.nFileSizeHigh && + InfoA.nFileSizeLow == InfoB.nFileSizeLow && + InfoA.ftLastWriteTime.dwLowDateTime == + InfoB.ftLastWriteTime.dwLowDateTime && + InfoA.ftLastWriteTime.dwHighDateTime == + InfoB.ftLastWriteTime.dwHighDateTime; + + return success; +} + +error_code file_size(const Twine &path, uint64_t &result) { + SmallString<128> path_storage; + SmallVector path_utf16; + + if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), + path_utf16)) + return ec; + + WIN32_FILE_ATTRIBUTE_DATA FileData; + if (!::GetFileAttributesExW(path_utf16.begin(), + ::GetFileExInfoStandard, + &FileData)) + return windows_error(::GetLastError()); + + result = + (uint64_t(FileData.nFileSizeHigh) << (sizeof(FileData.nFileSizeLow) * 8)) + + FileData.nFileSizeLow; + + return success; +} + +error_code status(const Twine &path, file_status &result) { + SmallString<128> path_storage; + SmallVector path_utf16; + + if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), + path_utf16)) + return ec; + + DWORD attr = ::GetFileAttributesW(path_utf16.begin()); + if (attr == INVALID_FILE_ATTRIBUTES) + goto handle_status_error; + + // Handle reparse points. + if (attr & FILE_ATTRIBUTE_REPARSE_POINT) { + AutoHandle h( + ::CreateFileW(path_utf16.begin(), + 0, // Attributes only. + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, + 0)); + if (h == INVALID_HANDLE_VALUE) + goto handle_status_error; + } + + if (attr & FILE_ATTRIBUTE_DIRECTORY) + result = file_status(file_type::directory_file); + else + result = file_status(file_type::regular_file); + + return success; + +handle_status_error: + error_code ec = windows_error(::GetLastError()); + if (ec == windows_error::file_not_found || + ec == windows_error::path_not_found) + result = file_status(file_type::file_not_found); + else if (ec == windows_error::sharing_violation) + result = file_status(file_type::type_unknown); + else { + result = file_status(file_type::status_error); + return ec; + } + + return success; +} + +error_code unique_file(const Twine &model, int &result_fd, + SmallVectorImpl &result_path) { + // Use result_path as temp storage. + result_path.set_size(0); + StringRef m = model.toStringRef(result_path); + + SmallVector model_utf16; + if (error_code ec = UTF8ToUTF16(m, model_utf16)) return ec; + + // Make model absolute by prepending a temp directory if it's not already. + bool absolute = path::is_absolute(m); + + if (!absolute) { + SmallVector temp_dir; + if (error_code ec = TempDir(temp_dir)) return ec; + // Handle c: by removing it. + if (model_utf16.size() > 2 && model_utf16[1] == L':') { + model_utf16.erase(model_utf16.begin(), model_utf16.begin() + 2); + } + model_utf16.insert(model_utf16.begin(), temp_dir.begin(), temp_dir.end()); + } + + // Replace '%' with random chars. From here on, DO NOT modify model. It may be + // needed if the randomly chosen path already exists. + SmallVector random_path_utf16; + + // Get a Crypto Provider for CryptGenRandom. + HCRYPTPROV HCPC; + if (!::CryptAcquireContextW(&HCPC, + NULL, + NULL, + PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) + return windows_error(::GetLastError()); + ScopedCryptContext CryptoProvider(HCPC); + +retry_random_path: + random_path_utf16.set_size(0); + for (SmallVectorImpl::const_iterator i = model_utf16.begin(), + e = model_utf16.end(); + i != e; ++i) { + if (*i == L'%') { + BYTE val = 0; + if (!::CryptGenRandom(CryptoProvider, 1, &val)) + return windows_error(::GetLastError()); + random_path_utf16.push_back("0123456789abcdef"[val & 15]); + } + else + random_path_utf16.push_back(*i); + } + // Make random_path_utf16 null terminated. + random_path_utf16.push_back(0); + random_path_utf16.pop_back(); + + // Try to create + open the path. +retry_create_file: + HANDLE TempFileHandle = ::CreateFileW(random_path_utf16.begin(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + // Return ERROR_FILE_EXISTS if the file + // already exists. + CREATE_NEW, + FILE_ATTRIBUTE_TEMPORARY, + NULL); + if (TempFileHandle == INVALID_HANDLE_VALUE) { + // If the file existed, try again, otherwise, error. + error_code ec = windows_error(::GetLastError()); + if (ec == windows_error::file_exists) + goto retry_random_path; + // Check for non-existing parent directories. + if (ec == windows_error::path_not_found) { + // Create the directories using result_path as temp storage. + if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(), + random_path_utf16.size(), result_path)) + return ec; + StringRef p(result_path.begin(), result_path.size()); + SmallString<64> dir_to_create; + for (path::const_iterator i = path::begin(p), + e = --path::end(p); i != e; ++i) { + path::append(dir_to_create, *i); + bool Exists; + if (error_code ec = exists(Twine(dir_to_create), Exists)) return ec; + if (!Exists) { + // If c: doesn't exist, bail. + if (i->endswith(":")) + return ec; + + SmallVector dir_to_create_utf16; + if (error_code ec = UTF8ToUTF16(dir_to_create, dir_to_create_utf16)) + return ec; + + // Create the directory. + if (!::CreateDirectoryW(dir_to_create_utf16.begin(), NULL)) + return windows_error(::GetLastError()); + } + } + goto retry_create_file; + } + return ec; + } + + // Set result_path to the utf-8 representation of the path. + if (error_code ec = UTF16ToUTF8(random_path_utf16.begin(), + random_path_utf16.size(), result_path)) { + ::CloseHandle(TempFileHandle); + ::DeleteFileW(random_path_utf16.begin()); + return ec; + } + + // Convert the Windows API file handle into a C-runtime handle. + int fd = ::_open_osfhandle(intptr_t(TempFileHandle), 0); + if (fd == -1) { + ::CloseHandle(TempFileHandle); + ::DeleteFileW(random_path_utf16.begin()); + // MSDN doesn't say anything about _open_osfhandle setting errno or + // GetLastError(), so just return invalid_handle. + return windows_error::invalid_handle; + } + + result_fd = fd; + return success; +} + +error_code get_magic(const Twine &path, uint32_t len, + SmallVectorImpl &result) { + SmallString<128> path_storage; + SmallVector path_utf16; + result.set_size(0); + + // Convert path to UTF-16. + if (error_code ec = UTF8ToUTF16(path.toStringRef(path_storage), + path_utf16)) + return ec; + + // Open file. + HANDLE file = ::CreateFileW(c_str(path_utf16), + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_READONLY, + NULL); + if (file == INVALID_HANDLE_VALUE) + return windows_error(::GetLastError()); + + // Allocate buffer. + result.reserve(len); + + // Get magic! + DWORD bytes_read = 0; + BOOL read_success = ::ReadFile(file, result.data(), len, &bytes_read, NULL); + error_code ec = windows_error(::GetLastError()); + ::CloseHandle(file); + if (!read_success || (bytes_read != len)) { + // Set result size to the number of bytes read if it's valid. + if (bytes_read >= 0 && bytes_read <= len) + result.set_size(bytes_read); + // ERROR_HANDLE_EOF is mapped to errc::value_too_large. + return ec; + } + + result.set_size(len); + return success; +} + +error_code directory_iterator_construct(directory_iterator &it, StringRef path){ + SmallVector path_utf16; + + if (error_code ec = UTF8ToUTF16(path, + path_utf16)) + return ec; + + // Convert path to the format that Windows is happy with. + if (path_utf16.size() > 0 && + !is_separator(path_utf16[path.size() - 1]) && + path_utf16[path.size() - 1] != L':') { + path_utf16.push_back(L'\\'); + path_utf16.push_back(L'*'); + } else { + path_utf16.push_back(L'*'); + } + + // Get the first directory entry. + WIN32_FIND_DATAW FirstFind; + ScopedFindHandle FindHandle(::FindFirstFileW(c_str(path_utf16), &FirstFind)); + if (!FindHandle) + return windows_error(::GetLastError()); + + size_t FilenameLen = ::wcslen(FirstFind.cFileName); + while ((FilenameLen == 1 && FirstFind.cFileName[0] == L'.') || + (FilenameLen == 2 && FirstFind.cFileName[0] == L'.' && + FirstFind.cFileName[1] == L'.')) + if (!::FindNextFileW(FindHandle, &FirstFind)) { + error_code ec = windows_error(::GetLastError()); + // Check for end. + if (ec == windows_error::no_more_files) + return directory_iterator_destruct(it); + return ec; + } else + FilenameLen = ::wcslen(FirstFind.cFileName); + + // Construct the current directory entry. + SmallString<128> directory_entry_name_utf8; + if (error_code ec = UTF16ToUTF8(FirstFind.cFileName, + ::wcslen(FirstFind.cFileName), + directory_entry_name_utf8)) + return ec; + + it.IterationHandle = intptr_t(FindHandle.take()); + SmallString<128> directory_entry_path(path); + path::append(directory_entry_path, directory_entry_name_utf8.str()); + it.CurrentEntry = directory_entry(directory_entry_path.str()); + + return success; +} + +error_code directory_iterator_destruct(directory_iterator& it) { + if (it.IterationHandle != 0) + // Closes the handle if it's valid. + ScopedFindHandle close(HANDLE(it.IterationHandle)); + it.IterationHandle = 0; + it.CurrentEntry = directory_entry(); + return success; +} + +error_code directory_iterator_increment(directory_iterator& it) { + WIN32_FIND_DATAW FindData; + if (!::FindNextFileW(HANDLE(it.IterationHandle), &FindData)) { + error_code ec = windows_error(::GetLastError()); + // Check for end. + if (ec == windows_error::no_more_files) + return directory_iterator_destruct(it); + return ec; + } + + size_t FilenameLen = ::wcslen(FindData.cFileName); + if ((FilenameLen == 1 && FindData.cFileName[0] == L'.') || + (FilenameLen == 2 && FindData.cFileName[0] == L'.' && + FindData.cFileName[1] == L'.')) + return directory_iterator_increment(it); + + SmallString<128> directory_entry_path_utf8; + if (error_code ec = UTF16ToUTF8(FindData.cFileName, + ::wcslen(FindData.cFileName), + directory_entry_path_utf8)) + return ec; + + it.CurrentEntry.replace_filename(Twine(directory_entry_path_utf8)); + return success; +} + +} // end namespace fs +} // end namespace sys +} // end namespace llvm diff --git a/lib/Support/Windows/Process.inc b/lib/Support/Windows/Process.inc new file mode 100644 index 000000000000..06a7f0054d50 --- /dev/null +++ b/lib/Support/Windows/Process.inc @@ -0,0 +1,222 @@ +//===- Win32/Process.cpp - Win32 Process Implementation ------- -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of the Process class. +// +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include +#include +#include + +#ifdef __MINGW32__ + #if (HAVE_LIBPSAPI != 1) + #error "libpsapi.a should be present" + #endif +#else + #pragma comment(lib, "psapi.lib") +#endif + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code +//=== and must not be UNIX code +//===----------------------------------------------------------------------===// + +#ifdef __MINGW32__ +// This ban should be lifted when MinGW 1.0+ has defined this value. +# define _HEAPOK (-2) +#endif + +namespace llvm { +using namespace sys; + +// This function retrieves the page size using GetSystemInfo and is present +// solely so it can be called once in Process::GetPageSize to initialize the +// static variable PageSize. +inline unsigned GetPageSizeOnce() { + // NOTE: A 32-bit application running under WOW64 is supposed to use + // GetNativeSystemInfo. However, this interface is not present prior + // to Windows XP so to use it requires dynamic linking. It is not clear + // how this affects the reported page size, if at all. One could argue + // that LLVM ought to run as 64-bits on a 64-bit system, anyway. + SYSTEM_INFO info; + GetSystemInfo(&info); + return static_cast(info.dwPageSize); +} + +unsigned +Process::GetPageSize() { + static const unsigned PageSize = GetPageSizeOnce(); + return PageSize; +} + +size_t +Process::GetMallocUsage() +{ + _HEAPINFO hinfo; + hinfo._pentry = NULL; + + size_t size = 0; + + while (_heapwalk(&hinfo) == _HEAPOK) + size += hinfo._size; + + return size; +} + +size_t +Process::GetTotalMemoryUsage() +{ + PROCESS_MEMORY_COUNTERS pmc; + GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)); + return pmc.PagefileUsage; +} + +void +Process::GetTimeUsage( + TimeValue& elapsed, TimeValue& user_time, TimeValue& sys_time) +{ + elapsed = TimeValue::now(); + + uint64_t ProcCreate, ProcExit, KernelTime, UserTime; + GetProcessTimes(GetCurrentProcess(), (FILETIME*)&ProcCreate, + (FILETIME*)&ProcExit, (FILETIME*)&KernelTime, + (FILETIME*)&UserTime); + + // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond) + user_time.seconds( UserTime / 10000000 ); + user_time.nanoseconds( unsigned(UserTime % 10000000) * 100 ); + sys_time.seconds( KernelTime / 10000000 ); + sys_time.nanoseconds( unsigned(KernelTime % 10000000) * 100 ); +} + +int Process::GetCurrentUserId() +{ + return 65536; +} + +int Process::GetCurrentGroupId() +{ + return 65536; +} + +// Some LLVM programs such as bugpoint produce core files as a normal part of +// their operation. To prevent the disk from filling up, this configuration item +// does what's necessary to prevent their generation. +void Process::PreventCoreFiles() { + // Windows doesn't do core files, but it does do modal pop-up message + // boxes. As this method is used by bugpoint, preventing these pop-ups + // is the moral equivalent of suppressing core files. + SetErrorMode(SEM_FAILCRITICALERRORS | + SEM_NOGPFAULTERRORBOX | + SEM_NOOPENFILEERRORBOX); +} + +bool Process::StandardInIsUserInput() { + return FileDescriptorIsDisplayed(0); +} + +bool Process::StandardOutIsDisplayed() { + return FileDescriptorIsDisplayed(1); +} + +bool Process::StandardErrIsDisplayed() { + return FileDescriptorIsDisplayed(2); +} + +bool Process::FileDescriptorIsDisplayed(int fd) { + DWORD Mode; // Unused + return (GetConsoleMode((HANDLE)_get_osfhandle(fd), &Mode) != 0); +} + +unsigned Process::StandardOutColumns() { + unsigned Columns = 0; + CONSOLE_SCREEN_BUFFER_INFO csbi; + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) + Columns = csbi.dwSize.X; + return Columns; +} + +unsigned Process::StandardErrColumns() { + unsigned Columns = 0; + CONSOLE_SCREEN_BUFFER_INFO csbi; + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi)) + Columns = csbi.dwSize.X; + return Columns; +} + +// It always has colors. +bool Process::StandardErrHasColors() { + return StandardErrIsDisplayed(); +} + +bool Process::StandardOutHasColors() { + return StandardOutIsDisplayed(); +} + +namespace { +class DefaultColors +{ + private: + WORD defaultColor; + public: + DefaultColors() + :defaultColor(GetCurrentColor()) {} + static unsigned GetCurrentColor() { + CONSOLE_SCREEN_BUFFER_INFO csbi; + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) + return csbi.wAttributes; + return 0; + } + WORD operator()() const { return defaultColor; } +}; + +DefaultColors defaultColors; +} + +bool Process::ColorNeedsFlush() { + return true; +} + +const char *Process::OutputBold(bool bg) { + WORD colors = DefaultColors::GetCurrentColor(); + if (bg) + colors |= BACKGROUND_INTENSITY; + else + colors |= FOREGROUND_INTENSITY; + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); + return 0; +} + +const char *Process::OutputColor(char code, bool bold, bool bg) { + WORD colors; + if (bg) { + colors = ((code&1) ? BACKGROUND_RED : 0) | + ((code&2) ? BACKGROUND_GREEN : 0 ) | + ((code&4) ? BACKGROUND_BLUE : 0); + if (bold) + colors |= BACKGROUND_INTENSITY; + } else { + colors = ((code&1) ? FOREGROUND_RED : 0) | + ((code&2) ? FOREGROUND_GREEN : 0 ) | + ((code&4) ? FOREGROUND_BLUE : 0); + if (bold) + colors |= FOREGROUND_INTENSITY; + } + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); + return 0; +} + +const char *Process::ResetColor() { + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors()); + return 0; +} + +} diff --git a/lib/Support/Windows/Program.inc b/lib/Support/Windows/Program.inc new file mode 100644 index 000000000000..350363cf7107 --- /dev/null +++ b/lib/Support/Windows/Program.inc @@ -0,0 +1,403 @@ +//===- Win32/Program.cpp - Win32 Program Implementation ------- -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of the Program class. +// +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include +#include +#include +#include + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code +//=== and must not be UNIX code +//===----------------------------------------------------------------------===// + +namespace { + struct Win32ProcessInfo { + HANDLE hProcess; + DWORD dwProcessId; + }; +} + +namespace llvm { +using namespace sys; + +Program::Program() : Data_(0) {} + +Program::~Program() { + if (Data_) { + Win32ProcessInfo* wpi = reinterpret_cast(Data_); + CloseHandle(wpi->hProcess); + delete wpi; + Data_ = 0; + } +} + +unsigned Program::GetPid() const { + Win32ProcessInfo* wpi = reinterpret_cast(Data_); + return wpi->dwProcessId; +} + +// This function just uses the PATH environment variable to find the program. +Path +Program::FindProgramByName(const std::string& progName) { + + // Check some degenerate cases + if (progName.length() == 0) // no program + return Path(); + Path temp; + if (!temp.set(progName)) // invalid name + return Path(); + // Return paths with slashes verbatim. + if (progName.find('\\') != std::string::npos || + progName.find('/') != std::string::npos) + return temp; + + // At this point, the file name is valid and does not contain slashes. + // Let Windows search for it. + char buffer[MAX_PATH]; + char *dummy = NULL; + DWORD len = SearchPath(NULL, progName.c_str(), ".exe", MAX_PATH, + buffer, &dummy); + + // See if it wasn't found. + if (len == 0) + return Path(); + + // See if we got the entire path. + if (len < MAX_PATH) + return Path(buffer); + + // Buffer was too small; grow and retry. + while (true) { + char *b = reinterpret_cast(_alloca(len+1)); + DWORD len2 = SearchPath(NULL, progName.c_str(), ".exe", len+1, b, &dummy); + + // It is unlikely the search failed, but it's always possible some file + // was added or removed since the last search, so be paranoid... + if (len2 == 0) + return Path(); + else if (len2 <= len) + return Path(b); + + len = len2; + } +} + +static HANDLE RedirectIO(const Path *path, int fd, std::string* ErrMsg) { + HANDLE h; + if (path == 0) { + DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), + GetCurrentProcess(), &h, + 0, TRUE, DUPLICATE_SAME_ACCESS); + return h; + } + + const char *fname; + if (path->isEmpty()) + fname = "NUL"; + else + fname = path->c_str(); + + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = 0; + sa.bInheritHandle = TRUE; + + h = CreateFile(fname, fd ? GENERIC_WRITE : GENERIC_READ, FILE_SHARE_READ, + &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) { + MakeErrMsg(ErrMsg, std::string(fname) + ": Can't open file for " + + (fd ? "input: " : "output: ")); + } + + return h; +} + +/// ArgNeedsQuotes - Check whether argument needs to be quoted when calling +/// CreateProcess. +static bool ArgNeedsQuotes(const char *Str) { + return Str[0] == '\0' || strpbrk(Str, "\t \"&\'()*<>\\`^|") != 0; +} + + +/// ArgLenWithQuotes - Check whether argument needs to be quoted when calling +/// CreateProcess and returns length of quoted arg with escaped quotes +static unsigned int ArgLenWithQuotes(const char *Str) { + unsigned int len = ArgNeedsQuotes(Str) ? 2 : 0; + + while (*Str != '\0') { + if (*Str == '\"') + ++len; + + ++len; + ++Str; + } + + return len; +} + + +bool +Program::Execute(const Path& path, + const char** args, + const char** envp, + const Path** redirects, + unsigned memoryLimit, + std::string* ErrMsg) { + if (Data_) { + Win32ProcessInfo* wpi = reinterpret_cast(Data_); + CloseHandle(wpi->hProcess); + delete wpi; + Data_ = 0; + } + + if (!path.canExecute()) { + if (ErrMsg) + *ErrMsg = "program not executable"; + return false; + } + + // Windows wants a command line, not an array of args, to pass to the new + // process. We have to concatenate them all, while quoting the args that + // have embedded spaces (or are empty). + + // First, determine the length of the command line. + unsigned len = 0; + for (unsigned i = 0; args[i]; i++) { + len += ArgLenWithQuotes(args[i]) + 1; + } + + // Now build the command line. + char *command = reinterpret_cast(_alloca(len+1)); + char *p = command; + + for (unsigned i = 0; args[i]; i++) { + const char *arg = args[i]; + + bool needsQuoting = ArgNeedsQuotes(arg); + if (needsQuoting) + *p++ = '"'; + + while (*arg != '\0') { + if (*arg == '\"') + *p++ = '\\'; + + *p++ = *arg++; + } + + if (needsQuoting) + *p++ = '"'; + *p++ = ' '; + } + + *p = 0; + + // The pointer to the environment block for the new process. + char *envblock = 0; + + if (envp) { + // An environment block consists of a null-terminated block of + // null-terminated strings. Convert the array of environment variables to + // an environment block by concatenating them. + + // First, determine the length of the environment block. + len = 0; + for (unsigned i = 0; envp[i]; i++) + len += strlen(envp[i]) + 1; + + // Now build the environment block. + envblock = reinterpret_cast(_alloca(len+1)); + p = envblock; + + for (unsigned i = 0; envp[i]; i++) { + const char *ev = envp[i]; + size_t len = strlen(ev) + 1; + memcpy(p, ev, len); + p += len; + } + + *p = 0; + } + + // Create a child process. + STARTUPINFO si; + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.hStdInput = INVALID_HANDLE_VALUE; + si.hStdOutput = INVALID_HANDLE_VALUE; + si.hStdError = INVALID_HANDLE_VALUE; + + if (redirects) { + si.dwFlags = STARTF_USESTDHANDLES; + + si.hStdInput = RedirectIO(redirects[0], 0, ErrMsg); + if (si.hStdInput == INVALID_HANDLE_VALUE) { + MakeErrMsg(ErrMsg, "can't redirect stdin"); + return false; + } + si.hStdOutput = RedirectIO(redirects[1], 1, ErrMsg); + if (si.hStdOutput == INVALID_HANDLE_VALUE) { + CloseHandle(si.hStdInput); + MakeErrMsg(ErrMsg, "can't redirect stdout"); + return false; + } + if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) { + // If stdout and stderr should go to the same place, redirect stderr + // to the handle already open for stdout. + DuplicateHandle(GetCurrentProcess(), si.hStdOutput, + GetCurrentProcess(), &si.hStdError, + 0, TRUE, DUPLICATE_SAME_ACCESS); + } else { + // Just redirect stderr + si.hStdError = RedirectIO(redirects[2], 2, ErrMsg); + if (si.hStdError == INVALID_HANDLE_VALUE) { + CloseHandle(si.hStdInput); + CloseHandle(si.hStdOutput); + MakeErrMsg(ErrMsg, "can't redirect stderr"); + return false; + } + } + } + + PROCESS_INFORMATION pi; + memset(&pi, 0, sizeof(pi)); + + fflush(stdout); + fflush(stderr); + BOOL rc = CreateProcess(path.c_str(), command, NULL, NULL, TRUE, 0, + envblock, NULL, &si, &pi); + DWORD err = GetLastError(); + + // Regardless of whether the process got created or not, we are done with + // the handles we created for it to inherit. + CloseHandle(si.hStdInput); + CloseHandle(si.hStdOutput); + CloseHandle(si.hStdError); + + // Now return an error if the process didn't get created. + if (!rc) { + SetLastError(err); + MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") + + path.str() + "'"); + return false; + } + Win32ProcessInfo* wpi = new Win32ProcessInfo; + wpi->hProcess = pi.hProcess; + wpi->dwProcessId = pi.dwProcessId; + Data_ = wpi; + + // Make sure these get closed no matter what. + AutoHandle hThread(pi.hThread); + + // Assign the process to a job if a memory limit is defined. + AutoHandle hJob(0); + if (memoryLimit != 0) { + hJob = CreateJobObject(0, 0); + bool success = false; + if (hJob != 0) { + JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; + memset(&jeli, 0, sizeof(jeli)); + jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY; + jeli.ProcessMemoryLimit = uintptr_t(memoryLimit) * 1048576; + if (SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, + &jeli, sizeof(jeli))) { + if (AssignProcessToJobObject(hJob, pi.hProcess)) + success = true; + } + } + if (!success) { + SetLastError(GetLastError()); + MakeErrMsg(ErrMsg, std::string("Unable to set memory limit")); + TerminateProcess(pi.hProcess, 1); + WaitForSingleObject(pi.hProcess, INFINITE); + return false; + } + } + + return true; +} + +int +Program::Wait(const Path &path, + unsigned secondsToWait, + std::string* ErrMsg) { + if (Data_ == 0) { + MakeErrMsg(ErrMsg, "Process not started!"); + return -1; + } + + Win32ProcessInfo* wpi = reinterpret_cast(Data_); + HANDLE hProcess = wpi->hProcess; + + // Wait for the process to terminate. + DWORD millisecondsToWait = INFINITE; + if (secondsToWait > 0) + millisecondsToWait = secondsToWait * 1000; + + if (WaitForSingleObject(hProcess, millisecondsToWait) == WAIT_TIMEOUT) { + if (!TerminateProcess(hProcess, 1)) { + MakeErrMsg(ErrMsg, "Failed to terminate timed-out program."); + return -1; + } + WaitForSingleObject(hProcess, INFINITE); + } + + // Get its exit status. + DWORD status; + BOOL rc = GetExitCodeProcess(hProcess, &status); + DWORD err = GetLastError(); + + if (!rc) { + SetLastError(err); + MakeErrMsg(ErrMsg, "Failed getting status for program."); + return -1; + } + + return status; +} + +bool +Program::Kill(std::string* ErrMsg) { + if (Data_ == 0) { + MakeErrMsg(ErrMsg, "Process not started!"); + return true; + } + + Win32ProcessInfo* wpi = reinterpret_cast(Data_); + HANDLE hProcess = wpi->hProcess; + if (TerminateProcess(hProcess, 1) == 0) { + MakeErrMsg(ErrMsg, "The process couldn't be killed!"); + return true; + } + + return false; +} + +bool Program::ChangeStdinToBinary(){ + int result = _setmode( _fileno(stdin), _O_BINARY ); + return result == -1; +} + +bool Program::ChangeStdoutToBinary(){ + int result = _setmode( _fileno(stdout), _O_BINARY ); + return result == -1; +} + +bool Program::ChangeStderrToBinary(){ + int result = _setmode( _fileno(stderr), _O_BINARY ); + return result == -1; +} + +} diff --git a/lib/Support/Windows/RWMutex.inc b/lib/Support/Windows/RWMutex.inc new file mode 100644 index 000000000000..471f8fa294be --- /dev/null +++ b/lib/Support/Windows/RWMutex.inc @@ -0,0 +1,58 @@ +//= llvm/Support/Win32/Mutex.inc - Win32 Reader/Writer Mutual Exclusion Lock =// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Win32 specific (non-pthread) RWMutex class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Win32 code that +//=== is guaranteed to work on *all* Win32 variants. +//===----------------------------------------------------------------------===// + +#include "Windows.h" + +// FIXME: Windows does not have reader-writer locks pre-Vista. If you want +// real reader-writer locks, you a threads implementation for Windows. + +namespace llvm { +using namespace sys; + +RWMutexImpl::RWMutexImpl() { + data_ = calloc(1, sizeof(CRITICAL_SECTION)); + InitializeCriticalSection(static_cast(data_)); +} + +RWMutexImpl::~RWMutexImpl() { + DeleteCriticalSection(static_cast(data_)); + free(data_); +} + +bool RWMutexImpl::reader_acquire() { + EnterCriticalSection(static_cast(data_)); + return true; +} + +bool RWMutexImpl::reader_release() { + LeaveCriticalSection(static_cast(data_)); + return true; +} + +bool RWMutexImpl::writer_acquire() { + EnterCriticalSection(static_cast(data_)); + return true; +} + +bool RWMutexImpl::writer_release() { + LeaveCriticalSection(static_cast(data_)); + return true; +} + + +} diff --git a/lib/Support/Windows/Signals.inc b/lib/Support/Windows/Signals.inc new file mode 100644 index 000000000000..14f3f21f02a1 --- /dev/null +++ b/lib/Support/Windows/Signals.inc @@ -0,0 +1,328 @@ +//===- Win32/Signals.cpp - Win32 Signals Implementation ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of the Signals class. +// +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include +#include +#include + +#ifdef __MINGW32__ + #include +#else + #include +#endif +#include + +#ifdef __MINGW32__ + #if ((HAVE_LIBIMAGEHLP != 1) || (HAVE_LIBPSAPI != 1)) + #error "libimagehlp.a & libpsapi.a should be present" + #endif +#else + #pragma comment(lib, "psapi.lib") + #pragma comment(lib, "dbghelp.lib") +#endif + +// Forward declare. +static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep); +static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType); + +// InterruptFunction - The function to call if ctrl-c is pressed. +static void (*InterruptFunction)() = 0; + +static std::vector *FilesToRemove = NULL; +static std::vector > *CallBacksToRun = 0; +static bool RegisteredUnhandledExceptionFilter = false; +static bool CleanupExecuted = false; +static bool ExitOnUnhandledExceptions = false; +static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL; + +// Windows creates a new thread to execute the console handler when an event +// (such as CTRL/C) occurs. This causes concurrency issues with the above +// globals which this critical section addresses. +static CRITICAL_SECTION CriticalSection; + +namespace llvm { + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code +//=== and must not be UNIX code +//===----------------------------------------------------------------------===// + +#ifdef _MSC_VER +/// CRTReportHook - Function called on a CRT debugging event. +static int CRTReportHook(int ReportType, char *Message, int *Return) { + // Don't cause a DebugBreak() on return. + if (Return) + *Return = 0; + + switch (ReportType) { + default: + case _CRT_ASSERT: + fprintf(stderr, "CRT assert: %s\n", Message); + // FIXME: Is there a way to just crash? Perhaps throw to the unhandled + // exception code? Perhaps SetErrorMode() handles this. + _exit(3); + break; + case _CRT_ERROR: + fprintf(stderr, "CRT error: %s\n", Message); + // FIXME: Is there a way to just crash? Perhaps throw to the unhandled + // exception code? Perhaps SetErrorMode() handles this. + _exit(3); + break; + case _CRT_WARN: + fprintf(stderr, "CRT warn: %s\n", Message); + break; + } + + // Don't call _CrtDbgReport. + return TRUE; +} +#endif + +static void RegisterHandler() { + if (RegisteredUnhandledExceptionFilter) { + EnterCriticalSection(&CriticalSection); + return; + } + + // Now's the time to create the critical section. This is the first time + // through here, and there's only one thread. + InitializeCriticalSection(&CriticalSection); + + // Enter it immediately. Now if someone hits CTRL/C, the console handler + // can't proceed until the globals are updated. + EnterCriticalSection(&CriticalSection); + + RegisteredUnhandledExceptionFilter = true; + OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter); + SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE); + + // Environment variable to disable any kind of crash dialog. + if (getenv("LLVM_DISABLE_CRT_DEBUG")) { +#ifdef _MSC_VER + _CrtSetReportHook(CRTReportHook); +#endif + SetErrorMode(SEM_FAILCRITICALERRORS | + SEM_NOGPFAULTERRORBOX | + SEM_NOOPENFILEERRORBOX); + ExitOnUnhandledExceptions = true; + } + + // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or + // else multi-threading problems will ensue. +} + +// RemoveFileOnSignal - The public API +bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) { + RegisterHandler(); + + if (CleanupExecuted) { + if (ErrMsg) + *ErrMsg = "Process terminating -- cannot register for removal"; + return true; + } + + if (FilesToRemove == NULL) + FilesToRemove = new std::vector; + + FilesToRemove->push_back(Filename); + + LeaveCriticalSection(&CriticalSection); + return false; +} + +// DontRemoveFileOnSignal - The public API +void sys::DontRemoveFileOnSignal(const sys::Path &Filename) { + if (FilesToRemove == NULL) + return; + + RegisterHandler(); + + FilesToRemove->push_back(Filename); + std::vector::reverse_iterator I = + std::find(FilesToRemove->rbegin(), FilesToRemove->rend(), Filename); + if (I != FilesToRemove->rend()) + FilesToRemove->erase(I.base()-1); + + LeaveCriticalSection(&CriticalSection); +} + +/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or +/// SIGSEGV) is delivered to the process, print a stack trace and then exit. +void sys::PrintStackTraceOnErrorSignal() { + RegisterHandler(); + LeaveCriticalSection(&CriticalSection); +} + + +void sys::SetInterruptFunction(void (*IF)()) { + RegisterHandler(); + InterruptFunction = IF; + LeaveCriticalSection(&CriticalSection); +} + + +/// AddSignalHandler - Add a function to be called when a signal is delivered +/// to the process. The handler can have a cookie passed to it to identify +/// what instance of the handler it is. +void sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { + if (CallBacksToRun == 0) + CallBacksToRun = new std::vector >(); + CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie)); + RegisterHandler(); + LeaveCriticalSection(&CriticalSection); +} +} + +static void Cleanup() { + EnterCriticalSection(&CriticalSection); + + // Prevent other thread from registering new files and directories for + // removal, should we be executing because of the console handler callback. + CleanupExecuted = true; + + // FIXME: open files cannot be deleted. + + if (FilesToRemove != NULL) + while (!FilesToRemove->empty()) { + FilesToRemove->back().eraseFromDisk(); + FilesToRemove->pop_back(); + } + + if (CallBacksToRun) + for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i) + (*CallBacksToRun)[i].first((*CallBacksToRun)[i].second); + + LeaveCriticalSection(&CriticalSection); +} + +void llvm::sys::RunInterruptHandlers() { + Cleanup(); +} + +static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { + Cleanup(); + +#ifdef _WIN64 + // TODO: provide a x64 friendly version of the following +#else + + // Initialize the STACKFRAME structure. + STACKFRAME StackFrame; + memset(&StackFrame, 0, sizeof(StackFrame)); + + StackFrame.AddrPC.Offset = ep->ContextRecord->Eip; + StackFrame.AddrPC.Mode = AddrModeFlat; + StackFrame.AddrStack.Offset = ep->ContextRecord->Esp; + StackFrame.AddrStack.Mode = AddrModeFlat; + StackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp; + StackFrame.AddrFrame.Mode = AddrModeFlat; + + HANDLE hProcess = GetCurrentProcess(); + HANDLE hThread = GetCurrentThread(); + + // Initialize the symbol handler. + SymSetOptions(SYMOPT_DEFERRED_LOADS|SYMOPT_LOAD_LINES); + SymInitialize(hProcess, NULL, TRUE); + + while (true) { + if (!StackWalk(IMAGE_FILE_MACHINE_I386, hProcess, hThread, &StackFrame, + ep->ContextRecord, NULL, SymFunctionTableAccess, + SymGetModuleBase, NULL)) { + break; + } + + if (StackFrame.AddrFrame.Offset == 0) + break; + + // Print the PC in hexadecimal. + DWORD PC = StackFrame.AddrPC.Offset; + fprintf(stderr, "%08lX", PC); + + // Print the parameters. Assume there are four. + fprintf(stderr, " (0x%08lX 0x%08lX 0x%08lX 0x%08lX)", + StackFrame.Params[0], + StackFrame.Params[1], StackFrame.Params[2], StackFrame.Params[3]); + + // Verify the PC belongs to a module in this process. + if (!SymGetModuleBase(hProcess, PC)) { + fputs(" \n", stderr); + continue; + } + + // Print the symbol name. + char buffer[512]; + IMAGEHLP_SYMBOL *symbol = reinterpret_cast(buffer); + memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL)); + symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL); + symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL); + + DWORD dwDisp; + if (!SymGetSymFromAddr(hProcess, PC, &dwDisp, symbol)) { + fputc('\n', stderr); + continue; + } + + buffer[511] = 0; + if (dwDisp > 0) + fprintf(stderr, ", %s()+%04lu bytes(s)", symbol->Name, dwDisp); + else + fprintf(stderr, ", %s", symbol->Name); + + // Print the source file and line number information. + IMAGEHLP_LINE line; + memset(&line, 0, sizeof(line)); + line.SizeOfStruct = sizeof(line); + if (SymGetLineFromAddr(hProcess, PC, &dwDisp, &line)) { + fprintf(stderr, ", %s, line %lu", line.FileName, line.LineNumber); + if (dwDisp > 0) + fprintf(stderr, "+%04lu byte(s)", dwDisp); + } + + fputc('\n', stderr); + } + +#endif + + if (ExitOnUnhandledExceptions) + _exit(-3); + + // Allow dialog box to pop up allowing choice to start debugger. + if (OldFilter) + return (*OldFilter)(ep); + else + return EXCEPTION_CONTINUE_SEARCH; +} + +static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) { + // We are running in our very own thread, courtesy of Windows. + EnterCriticalSection(&CriticalSection); + Cleanup(); + + // If an interrupt function has been set, go and run one it; otherwise, + // the process dies. + void (*IF)() = InterruptFunction; + InterruptFunction = 0; // Don't run it on another CTRL-C. + + if (IF) { + // Note: if the interrupt function throws an exception, there is nothing + // to catch it in this thread so it will kill the process. + IF(); // Run it now. + LeaveCriticalSection(&CriticalSection); + return TRUE; // Don't kill the process. + } + + // Allow normal processing to take place; i.e., the process dies. + LeaveCriticalSection(&CriticalSection); + return FALSE; +} diff --git a/lib/Support/Windows/ThreadLocal.inc b/lib/Support/Windows/ThreadLocal.inc new file mode 100644 index 000000000000..512462d89005 --- /dev/null +++ b/lib/Support/Windows/ThreadLocal.inc @@ -0,0 +1,54 @@ +//= llvm/Support/Win32/ThreadLocal.inc - Win32 Thread Local Data -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Win32 specific (non-pthread) ThreadLocal class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Win32 code that +//=== is guaranteed to work on *all* Win32 variants. +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include "llvm/Support/ThreadLocal.h" + +namespace llvm { +using namespace sys; + +ThreadLocalImpl::ThreadLocalImpl() { + DWORD* tls = new DWORD; + *tls = TlsAlloc(); + assert(*tls != TLS_OUT_OF_INDEXES); + data = tls; +} + +ThreadLocalImpl::~ThreadLocalImpl() { + DWORD* tls = static_cast(data); + TlsFree(*tls); + delete tls; +} + +const void* ThreadLocalImpl::getInstance() { + DWORD* tls = static_cast(data); + return TlsGetValue(*tls); +} + +void ThreadLocalImpl::setInstance(const void* d){ + DWORD* tls = static_cast(data); + int errorcode = TlsSetValue(*tls, const_cast(d)); + assert(errorcode != 0); + (void)errorcode; +} + +void ThreadLocalImpl::removeInstance() { + setInstance(0); +} + +} diff --git a/lib/Support/Windows/TimeValue.inc b/lib/Support/Windows/TimeValue.inc new file mode 100644 index 000000000000..12275526f1c8 --- /dev/null +++ b/lib/Support/Windows/TimeValue.inc @@ -0,0 +1,51 @@ +//===- Win32/TimeValue.cpp - Win32 TimeValue Implementation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 implementation of the TimeValue class. +// +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include + +namespace llvm { +using namespace sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code. +//===----------------------------------------------------------------------===// + +TimeValue TimeValue::now() { + uint64_t ft; + GetSystemTimeAsFileTime(reinterpret_cast(&ft)); + + TimeValue t(0, 0); + t.fromWin32Time(ft); + return t; +} + +std::string TimeValue::str() const { +#ifdef __MINGW32__ + // This ban may be lifted by either: + // (i) a future MinGW version other than 1.0 inherents the __time64_t type, or + // (ii) configure tests for either the time_t or __time64_t type. + time_t ourTime = time_t(this->toEpochTime()); + struct tm *lt = ::localtime(&ourTime); +#else + __time64_t ourTime = this->toEpochTime(); + struct tm *lt = ::_localtime64(&ourTime); +#endif + + char buffer[25]; + strftime(buffer, 25, "%a %b %d %H:%M:%S %Y", lt); + return std::string(buffer); +} + + +} diff --git a/lib/Support/Windows/Windows.h b/lib/Support/Windows/Windows.h new file mode 100644 index 000000000000..4a1553b599d7 --- /dev/null +++ b/lib/Support/Windows/Windows.h @@ -0,0 +1,120 @@ +//===- Win32/Win32.h - Common Win32 Include File ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines things specific to Win32 implementations. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Win32 code that +//=== is guaranteed to work on *all* Win32 variants. +//===----------------------------------------------------------------------===// + +// mingw-w64 tends to define it as 0x0502 in its headers. +#undef _WIN32_WINNT + +// Require at least Windows 2000 API. +#define _WIN32_WINNT 0x0500 +#define _WIN32_IE 0x0500 // MinGW at it again. +#define WIN32_LEAN_AND_MEAN + +#include "llvm/Config/config.h" // Get build system configuration settings +#include +#include +#include +#include + +inline bool MakeErrMsg(std::string* ErrMsg, const std::string& prefix) { + if (!ErrMsg) + return true; + char *buffer = NULL; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, + NULL, GetLastError(), 0, (LPSTR)&buffer, 1, NULL); + *ErrMsg = prefix + buffer; + LocalFree(buffer); + return true; +} + +class AutoHandle { + HANDLE handle; + +public: + AutoHandle(HANDLE h) : handle(h) {} + + ~AutoHandle() { + if (handle) + CloseHandle(handle); + } + + operator HANDLE() { + return handle; + } + + AutoHandle &operator=(HANDLE h) { + handle = h; + return *this; + } +}; + +template +class ScopedHandle { + HandleType Handle; + +public: + ScopedHandle() : Handle(InvalidHandle) {} + ScopedHandle(HandleType handle) : Handle(handle) {} + + ~ScopedHandle() { + if (Handle != HandleType(InvalidHandle)) + D(Handle); + } + + HandleType take() { + HandleType temp = Handle; + Handle = HandleType(InvalidHandle); + return temp; + } + + operator HandleType() const { return Handle; } + + ScopedHandle &operator=(HandleType handle) { + Handle = handle; + return *this; + } + + typedef void (*unspecified_bool_type)(); + static void unspecified_bool_true() {} + + // True if Handle is valid. + operator unspecified_bool_type() const { + return Handle == HandleType(InvalidHandle) ? 0 : unspecified_bool_true; + } + + bool operator!() const { + return Handle == HandleType(InvalidHandle); + } +}; + +typedef ScopedHandle + ScopedFindHandle; + +namespace llvm { +template +class SmallVectorImpl; + +template +typename SmallVectorImpl::const_pointer +c_str(SmallVectorImpl &str) { + str.push_back(0); + str.pop_back(); + return str.data(); +} +} // end namespace llvm. diff --git a/lib/Support/Windows/explicit_symbols.inc b/lib/Support/Windows/explicit_symbols.inc new file mode 100644 index 000000000000..84862d69e2b5 --- /dev/null +++ b/lib/Support/Windows/explicit_symbols.inc @@ -0,0 +1,66 @@ +/* in libgcc.a */ + +#ifdef HAVE__ALLOCA + EXPLICIT_SYMBOL(_alloca) + EXPLICIT_SYMBOL2(alloca, _alloca); +#endif +#ifdef HAVE___ALLOCA + EXPLICIT_SYMBOL(__alloca) +#endif +#ifdef HAVE___CHKSTK + EXPLICIT_SYMBOL(__chkstk) +#endif +#ifdef HAVE____CHKSTK + EXPLICIT_SYMBOL(___chkstk) +#endif +#ifdef HAVE___MAIN + EXPLICIT_SYMBOL(__main) // FIXME: Don't call it. +#endif + +#ifdef HAVE___ASHLDI3 + EXPLICIT_SYMBOL(__ashldi3) +#endif +#ifdef HAVE___ASHRDI3 + EXPLICIT_SYMBOL(__ashrdi3) +#endif +#ifdef HAVE___CMPDI2 // FIXME: unused + EXPLICIT_SYMBOL(__cmpdi2) +#endif +#ifdef HAVE___DIVDI3 + EXPLICIT_SYMBOL(__divdi3) +#endif +#ifdef HAVE___FIXDFDI + EXPLICIT_SYMBOL(__fixdfdi) +#endif +#ifdef HAVE___FIXSFDI + EXPLICIT_SYMBOL(__fixsfdi) +#endif +#ifdef HAVE___FIXUNSDFDI + EXPLICIT_SYMBOL(__fixunsdfdi) +#endif +#ifdef HAVE___FIXUNSSFDI + EXPLICIT_SYMBOL(__fixunssfdi) +#endif +#ifdef HAVE___FLOATDIDF + EXPLICIT_SYMBOL(__floatdidf) +#endif +#ifdef HAVE___FLOATDISF + EXPLICIT_SYMBOL(__floatdisf) +#endif +#ifdef HAVE___LSHRDI3 + EXPLICIT_SYMBOL(__lshrdi3) +#endif +#ifdef HAVE___MODDI3 + EXPLICIT_SYMBOL(__moddi3) +#endif +#ifdef HAVE___UDIVDI3 + EXPLICIT_SYMBOL(__udivdi3) +#endif +#ifdef HAVE___UMODDI3 + EXPLICIT_SYMBOL(__umoddi3) +#endif + +/* msvcrt */ +#if defined(_MSC_VER) + EXPLICIT_SYMBOL2(alloca, _alloca_probe); +#endif diff --git a/lib/Support/Windows/system_error.inc b/lib/Support/Windows/system_error.inc new file mode 100644 index 000000000000..37ec81dd363c --- /dev/null +++ b/lib/Support/Windows/system_error.inc @@ -0,0 +1,142 @@ +//===- llvm/Support/Win32/system_error.inc - Windows error_code --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Windows specific implementation of the error_code +// and error_condition classes. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Windows code that +//=== is guaranteed to work on *all* Windows variants. +//===----------------------------------------------------------------------===// + +#include +#include + +using namespace llvm; + +std::string +_system_error_category::message(int ev) const { + LPVOID lpMsgBuf = 0; + DWORD retval = ::FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + ev, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPSTR) &lpMsgBuf, + 0, + NULL); + if (retval == 0) { + ::LocalFree(lpMsgBuf); + return std::string("Unknown error"); + } + + std::string str( static_cast(lpMsgBuf) ); + ::LocalFree(lpMsgBuf); + + while (str.size() + && (str[str.size()-1] == '\n' || str[str.size()-1] == '\r')) + str.erase( str.size()-1 ); + if (str.size() && str[str.size()-1] == '.') + str.erase( str.size()-1 ); + return str; +} + +// I'd rather not double the line count of the following. +#define MAP_ERR_TO_COND(x, y) case x: return make_error_condition(errc::y) + +error_condition +_system_error_category::default_error_condition(int ev) const { + switch (ev) { + MAP_ERR_TO_COND(0, success); + // Windows system -> posix_errno decode table ---------------------------// + // see WinError.h comments for descriptions of errors + MAP_ERR_TO_COND(ERROR_ACCESS_DENIED, permission_denied); + MAP_ERR_TO_COND(ERROR_ALREADY_EXISTS, file_exists); + MAP_ERR_TO_COND(ERROR_BAD_UNIT, no_such_device); + MAP_ERR_TO_COND(ERROR_BUFFER_OVERFLOW, filename_too_long); + MAP_ERR_TO_COND(ERROR_BUSY, device_or_resource_busy); + MAP_ERR_TO_COND(ERROR_BUSY_DRIVE, device_or_resource_busy); + MAP_ERR_TO_COND(ERROR_CANNOT_MAKE, permission_denied); + MAP_ERR_TO_COND(ERROR_CANTOPEN, io_error); + MAP_ERR_TO_COND(ERROR_CANTREAD, io_error); + MAP_ERR_TO_COND(ERROR_CANTWRITE, io_error); + MAP_ERR_TO_COND(ERROR_CURRENT_DIRECTORY, permission_denied); + MAP_ERR_TO_COND(ERROR_DEV_NOT_EXIST, no_such_device); + MAP_ERR_TO_COND(ERROR_DEVICE_IN_USE, device_or_resource_busy); + MAP_ERR_TO_COND(ERROR_DIR_NOT_EMPTY, directory_not_empty); + MAP_ERR_TO_COND(ERROR_DIRECTORY, invalid_argument); + MAP_ERR_TO_COND(ERROR_DISK_FULL, no_space_on_device); + MAP_ERR_TO_COND(ERROR_FILE_EXISTS, file_exists); + MAP_ERR_TO_COND(ERROR_FILE_NOT_FOUND, no_such_file_or_directory); + MAP_ERR_TO_COND(ERROR_HANDLE_DISK_FULL, no_space_on_device); + MAP_ERR_TO_COND(ERROR_HANDLE_EOF, value_too_large); + MAP_ERR_TO_COND(ERROR_INVALID_ACCESS, permission_denied); + MAP_ERR_TO_COND(ERROR_INVALID_DRIVE, no_such_device); + MAP_ERR_TO_COND(ERROR_INVALID_FUNCTION, function_not_supported); + MAP_ERR_TO_COND(ERROR_INVALID_HANDLE, invalid_argument); + MAP_ERR_TO_COND(ERROR_INVALID_NAME, invalid_argument); + MAP_ERR_TO_COND(ERROR_LOCK_VIOLATION, no_lock_available); + MAP_ERR_TO_COND(ERROR_LOCKED, no_lock_available); + MAP_ERR_TO_COND(ERROR_NEGATIVE_SEEK, invalid_argument); + MAP_ERR_TO_COND(ERROR_NOACCESS, permission_denied); + MAP_ERR_TO_COND(ERROR_NOT_ENOUGH_MEMORY, not_enough_memory); + MAP_ERR_TO_COND(ERROR_NOT_READY, resource_unavailable_try_again); + MAP_ERR_TO_COND(ERROR_NOT_SAME_DEVICE, cross_device_link); + MAP_ERR_TO_COND(ERROR_OPEN_FAILED, io_error); + MAP_ERR_TO_COND(ERROR_OPEN_FILES, device_or_resource_busy); + MAP_ERR_TO_COND(ERROR_OPERATION_ABORTED, operation_canceled); + MAP_ERR_TO_COND(ERROR_OUTOFMEMORY, not_enough_memory); + MAP_ERR_TO_COND(ERROR_PATH_NOT_FOUND, no_such_file_or_directory); + MAP_ERR_TO_COND(ERROR_BAD_NETPATH, no_such_file_or_directory); + MAP_ERR_TO_COND(ERROR_READ_FAULT, io_error); + MAP_ERR_TO_COND(ERROR_RETRY, resource_unavailable_try_again); + MAP_ERR_TO_COND(ERROR_SEEK, io_error); + MAP_ERR_TO_COND(ERROR_SHARING_VIOLATION, permission_denied); + MAP_ERR_TO_COND(ERROR_TOO_MANY_OPEN_FILES, too_many_files_open); + MAP_ERR_TO_COND(ERROR_WRITE_FAULT, io_error); + MAP_ERR_TO_COND(ERROR_WRITE_PROTECT, permission_denied); + MAP_ERR_TO_COND(ERROR_SEM_TIMEOUT, timed_out); + MAP_ERR_TO_COND(WSAEACCES, permission_denied); + MAP_ERR_TO_COND(WSAEADDRINUSE, address_in_use); + MAP_ERR_TO_COND(WSAEADDRNOTAVAIL, address_not_available); + MAP_ERR_TO_COND(WSAEAFNOSUPPORT, address_family_not_supported); + MAP_ERR_TO_COND(WSAEALREADY, connection_already_in_progress); + MAP_ERR_TO_COND(WSAEBADF, bad_file_descriptor); + MAP_ERR_TO_COND(WSAECONNABORTED, connection_aborted); + MAP_ERR_TO_COND(WSAECONNREFUSED, connection_refused); + MAP_ERR_TO_COND(WSAECONNRESET, connection_reset); + MAP_ERR_TO_COND(WSAEDESTADDRREQ, destination_address_required); + MAP_ERR_TO_COND(WSAEFAULT, bad_address); + MAP_ERR_TO_COND(WSAEHOSTUNREACH, host_unreachable); + MAP_ERR_TO_COND(WSAEINPROGRESS, operation_in_progress); + MAP_ERR_TO_COND(WSAEINTR, interrupted); + MAP_ERR_TO_COND(WSAEINVAL, invalid_argument); + MAP_ERR_TO_COND(WSAEISCONN, already_connected); + MAP_ERR_TO_COND(WSAEMFILE, too_many_files_open); + MAP_ERR_TO_COND(WSAEMSGSIZE, message_size); + MAP_ERR_TO_COND(WSAENAMETOOLONG, filename_too_long); + MAP_ERR_TO_COND(WSAENETDOWN, network_down); + MAP_ERR_TO_COND(WSAENETRESET, network_reset); + MAP_ERR_TO_COND(WSAENETUNREACH, network_unreachable); + MAP_ERR_TO_COND(WSAENOBUFS, no_buffer_space); + MAP_ERR_TO_COND(WSAENOPROTOOPT, no_protocol_option); + MAP_ERR_TO_COND(WSAENOTCONN, not_connected); + MAP_ERR_TO_COND(WSAENOTSOCK, not_a_socket); + MAP_ERR_TO_COND(WSAEOPNOTSUPP, operation_not_supported); + MAP_ERR_TO_COND(WSAEPROTONOSUPPORT, protocol_not_supported); + MAP_ERR_TO_COND(WSAEPROTOTYPE, wrong_protocol_type); + MAP_ERR_TO_COND(WSAETIMEDOUT, timed_out); + MAP_ERR_TO_COND(WSAEWOULDBLOCK, operation_would_block); + default: return error_condition(ev, system_category()); + } +} diff --git a/lib/Support/raw_ostream.cpp b/lib/Support/raw_ostream.cpp index dba46df36256..80ea7407b44e 100644 --- a/lib/Support/raw_ostream.cpp +++ b/lib/Support/raw_ostream.cpp @@ -13,13 +13,13 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Format.h" -#include "llvm/System/Program.h" -#include "llvm/System/Process.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/Process.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Config/config.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/System/Signals.h" #include "llvm/ADT/STLExtras.h" #include #include @@ -32,6 +32,13 @@ #if defined(HAVE_FCNTL_H) # include #endif +#if defined(HAVE_SYS_UIO_H) && defined(HAVE_WRITEV) +# include +#endif + +#if defined(__CYGWIN__) +#include +#endif #if defined(_MSC_VER) #include @@ -164,7 +171,8 @@ raw_ostream &raw_ostream::write_hex(unsigned long long N) { return write(CurPtr, EndPtr-CurPtr); } -raw_ostream &raw_ostream::write_escaped(StringRef Str) { +raw_ostream &raw_ostream::write_escaped(StringRef Str, + bool UseHexEscapes) { for (unsigned i = 0, e = Str.size(); i != e; ++i) { unsigned char c = Str[i]; @@ -187,11 +195,18 @@ raw_ostream &raw_ostream::write_escaped(StringRef Str) { break; } - // Always expand to a 3-character octal escape. - *this << '\\'; - *this << char('0' + ((c >> 6) & 7)); - *this << char('0' + ((c >> 3) & 7)); - *this << char('0' + ((c >> 0) & 7)); + // Write out the escaped representation. + if (UseHexEscapes) { + *this << '\\' << 'x'; + *this << hexdigit((c >> 4 & 0xF)); + *this << hexdigit((c >> 0) & 0xF); + } else { + // Always use a full 3-character octal escape. + *this << '\\'; + *this << char('0' + ((c >> 6) & 7)); + *this << char('0' + ((c >> 3) & 7)); + *this << char('0' + ((c >> 0) & 7)); + } } } @@ -363,7 +378,9 @@ void format_object_base::home() { /// stream should be immediately destroyed; the string will be empty /// if no error occurred. raw_fd_ostream::raw_fd_ostream(const char *Filename, std::string &ErrorInfo, - unsigned Flags) : Error(false), pos(0) { + unsigned Flags) + : Error(false), UseAtomicWrites(false), pos(0) +{ assert(Filename != 0 && "Filename is null"); // Verify that we don't have both "append" and "excl". assert((!(Flags & F_Excl) || !(Flags & F_Append)) && @@ -410,6 +427,26 @@ raw_fd_ostream::raw_fd_ostream(const char *Filename, std::string &ErrorInfo, ShouldClose = true; } +/// raw_fd_ostream ctor - FD is the file descriptor that this writes to. If +/// ShouldClose is true, this closes the file when the stream is destroyed. +raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered) + : raw_ostream(unbuffered), FD(fd), + ShouldClose(shouldClose), Error(false), UseAtomicWrites(false) { +#ifdef O_BINARY + // Setting STDOUT and STDERR to binary mode is necessary in Win32 + // to avoid undesirable linefeed conversion. + if (fd == STDOUT_FILENO || fd == STDERR_FILENO) + setmode(fd, O_BINARY); +#endif + + // Get the starting position. + off_t loc = ::lseek(FD, 0, SEEK_CUR); + if (loc == (off_t)-1) + pos = 0; + else + pos = static_cast(loc); +} + raw_fd_ostream::~raw_fd_ostream() { if (FD >= 0) { flush(); @@ -435,7 +472,20 @@ void raw_fd_ostream::write_impl(const char *Ptr, size_t Size) { pos += Size; do { - ssize_t ret = ::write(FD, Ptr, Size); + ssize_t ret; + + // Check whether we should attempt to use atomic writes. + if (BUILTIN_EXPECT(!UseAtomicWrites, true)) { + ret = ::write(FD, Ptr, Size); + } else { + // Use ::writev() where available. +#if defined(HAVE_WRITEV) + struct iovec IOV = { (void*) Ptr, Size }; + ret = ::writev(FD, &IOV, 1); +#else + ret = ::write(FD, Ptr, Size); +#endif + } if (ret < 0) { // If it's a recoverable error, swallow it and retry the write. @@ -665,34 +715,3 @@ void raw_null_ostream::write_impl(const char *Ptr, size_t Size) { uint64_t raw_null_ostream::current_pos() const { return 0; } - -//===----------------------------------------------------------------------===// -// tool_output_file -//===----------------------------------------------------------------------===// - -tool_output_file::CleanupInstaller::CleanupInstaller(const char *filename) - : Filename(filename), Keep(false) { - // Arrange for the file to be deleted if the process is killed. - if (Filename != "-") - sys::RemoveFileOnSignal(sys::Path(Filename)); -} - -tool_output_file::CleanupInstaller::~CleanupInstaller() { - // Delete the file if the client hasn't told us not to. - if (!Keep && Filename != "-") - sys::Path(Filename).eraseFromDisk(); - - // Ok, the file is successfully written and closed, or deleted. There's no - // further need to clean it up on signals. - if (Filename != "-") - sys::DontRemoveFileOnSignal(sys::Path(Filename)); -} - -tool_output_file::tool_output_file(const char *filename, std::string &ErrorInfo, - unsigned Flags) - : Installer(filename), - OS(filename, ErrorInfo, Flags) { - // If open fails, no cleanup is needed. - if (!ErrorInfo.empty()) - Installer.Keep = true; -} diff --git a/lib/Support/regexec.c b/lib/Support/regexec.c index 41fb2ea46c9a..007861675ba1 100644 --- a/lib/Support/regexec.c +++ b/lib/Support/regexec.c @@ -54,8 +54,9 @@ #include "regex2.h" /* macros for manipulating states, small version */ -#define states long -#define states1 states /* for later use in llvm_regexec() decision */ +/* FIXME: 'states' is assumed as 'long' on small version. */ +#define states1 long /* for later use in llvm_regexec() decision */ +#define states states1 #define CLEAR(v) ((v) = 0) #define SET0(v, n) ((v) &= ~((unsigned long)1 << (n))) #define SET1(v, n) ((v) |= (unsigned long)1 << (n)) diff --git a/lib/Support/system_error.cpp b/lib/Support/system_error.cpp new file mode 100644 index 000000000000..56898de31520 --- /dev/null +++ b/lib/Support/system_error.cpp @@ -0,0 +1,130 @@ +//===---------------------- system_error.cpp ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This was lifted from libc++ and modified for C++03. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/system_error.h" +#include "llvm/Support/Errno.h" +#include +#include + +namespace llvm { + +// class error_category + +error_category::error_category() { +} + +error_category::~error_category() { +} + +error_condition +error_category::default_error_condition(int ev) const { + return error_condition(ev, *this); +} + +bool +error_category::equivalent(int code, const error_condition& condition) const { + return default_error_condition(code) == condition; +} + +bool +error_category::equivalent(const error_code& code, int condition) const { + return *this == code.category() && code.value() == condition; +} + +std::string +_do_message::message(int ev) const { + return std::string(sys::StrError(ev)); +} + +class _generic_error_category : public _do_message { +public: + virtual const char* name() const; + virtual std::string message(int ev) const; +}; + +const char* +_generic_error_category::name() const { + return "generic"; +} + +std::string +_generic_error_category::message(int ev) const { +#ifdef ELAST + if (ev > ELAST) + return std::string("unspecified generic_category error"); +#endif // ELAST + return _do_message::message(ev); +} + +const error_category& +generic_category() { + static _generic_error_category s; + return s; +} + +class _system_error_category : public _do_message { +public: + virtual const char* name() const; + virtual std::string message(int ev) const; + virtual error_condition default_error_condition(int ev) const; +}; + +const char* +_system_error_category::name() const { + return "system"; +} + +// std::string _system_error_category::message(int ev) const { +// Is in Platform/system_error.inc + +// error_condition _system_error_category::default_error_condition(int ev) const +// Is in Platform/system_error.inc + +const error_category& +system_category() { + static _system_error_category s; + return s; +} + +const error_category& +posix_category() { +#ifdef LLVM_ON_WIN32 + return generic_category(); +#else + return system_category(); +#endif +} + +// error_condition + +std::string +error_condition::message() const { + return _cat_->message(_val_); +} + +// error_code + +std::string +error_code::message() const { + return _cat_->message(_val_); +} + +} // end namespace llvm + +// Include the truly platform-specific parts of this class. +#if defined(LLVM_ON_UNIX) +#include "Unix/system_error.inc" +#endif +#if defined(LLVM_ON_WIN32) +#include "Windows/system_error.inc" +#endif diff --git a/lib/System/Alarm.cpp b/lib/System/Alarm.cpp deleted file mode 100644 index 0014ca716b33..000000000000 --- a/lib/System/Alarm.cpp +++ /dev/null @@ -1,33 +0,0 @@ -//===- Alarm.cpp - Alarm Generation Support ---------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Alarm functionality -// -//===----------------------------------------------------------------------===// - -#include "llvm/System/Alarm.h" -#include "llvm/Config/config.h" - -namespace llvm { -using namespace sys; - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only TRULY operating system -//=== independent code. -//===----------------------------------------------------------------------===// - -} - -// Include the platform-specific parts of this class. -#ifdef LLVM_ON_UNIX -#include "Unix/Alarm.inc" -#endif -#ifdef LLVM_ON_WIN32 -#include "Win32/Alarm.inc" -#endif diff --git a/lib/System/Atomic.cpp b/lib/System/Atomic.cpp deleted file mode 100644 index 7ba8b774d5e0..000000000000 --- a/lib/System/Atomic.cpp +++ /dev/null @@ -1,112 +0,0 @@ -//===-- Atomic.cpp - Atomic Operations --------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This header file implements atomic operations. -// -//===----------------------------------------------------------------------===// - -#include "llvm/System/Atomic.h" -#include "llvm/Config/config.h" - -using namespace llvm; - -#if defined(_MSC_VER) -#include -#undef MemoryFence -#endif - -void sys::MemoryFence() { -#if LLVM_MULTITHREADED==0 - return; -#else -# if defined(__GNUC__) - __sync_synchronize(); -# elif defined(_MSC_VER) - MemoryBarrier(); -# else -# error No memory fence implementation for your platform! -# endif -#endif -} - -sys::cas_flag sys::CompareAndSwap(volatile sys::cas_flag* ptr, - sys::cas_flag new_value, - sys::cas_flag old_value) { -#if LLVM_MULTITHREADED==0 - sys::cas_flag result = *ptr; - if (result == old_value) - *ptr = new_value; - return result; -#elif defined(__GNUC__) - return __sync_val_compare_and_swap(ptr, old_value, new_value); -#elif defined(_MSC_VER) - return InterlockedCompareExchange(ptr, new_value, old_value); -#else -# error No compare-and-swap implementation for your platform! -#endif -} - -sys::cas_flag sys::AtomicIncrement(volatile sys::cas_flag* ptr) { -#if LLVM_MULTITHREADED==0 - ++(*ptr); - return *ptr; -#elif defined(__GNUC__) - return __sync_add_and_fetch(ptr, 1); -#elif defined(_MSC_VER) - return InterlockedIncrement(ptr); -#else -# error No atomic increment implementation for your platform! -#endif -} - -sys::cas_flag sys::AtomicDecrement(volatile sys::cas_flag* ptr) { -#if LLVM_MULTITHREADED==0 - --(*ptr); - return *ptr; -#elif defined(__GNUC__) - return __sync_sub_and_fetch(ptr, 1); -#elif defined(_MSC_VER) - return InterlockedDecrement(ptr); -#else -# error No atomic decrement implementation for your platform! -#endif -} - -sys::cas_flag sys::AtomicAdd(volatile sys::cas_flag* ptr, sys::cas_flag val) { -#if LLVM_MULTITHREADED==0 - *ptr += val; - return *ptr; -#elif defined(__GNUC__) - return __sync_add_and_fetch(ptr, val); -#elif defined(_MSC_VER) - return InterlockedExchangeAdd(ptr, val) + val; -#else -# error No atomic add implementation for your platform! -#endif -} - -sys::cas_flag sys::AtomicMul(volatile sys::cas_flag* ptr, sys::cas_flag val) { - sys::cas_flag original, result; - do { - original = *ptr; - result = original * val; - } while (sys::CompareAndSwap(ptr, result, original) != original); - - return result; -} - -sys::cas_flag sys::AtomicDiv(volatile sys::cas_flag* ptr, sys::cas_flag val) { - sys::cas_flag original, result; - do { - original = *ptr; - result = original / val; - } while (sys::CompareAndSwap(ptr, result, original) != original); - - return result; -} diff --git a/lib/System/CMakeLists.txt b/lib/System/CMakeLists.txt deleted file mode 100644 index b43c3afa5248..000000000000 --- a/lib/System/CMakeLists.txt +++ /dev/null @@ -1,48 +0,0 @@ -add_llvm_library(LLVMSystem - Alarm.cpp - Atomic.cpp - Disassembler.cpp - DynamicLibrary.cpp - Errno.cpp - Host.cpp - IncludeFile.cpp - Memory.cpp - Mutex.cpp - Path.cpp - Process.cpp - Program.cpp - RWMutex.cpp - SearchForAddressOfSpecialSymbol.cpp - Signals.cpp - ThreadLocal.cpp - Threading.cpp - TimeValue.cpp - Valgrind.cpp - Unix/Alarm.inc - Unix/Host.inc - Unix/Memory.inc - Unix/Mutex.inc - Unix/Path.inc - Unix/Process.inc - Unix/Program.inc - Unix/RWMutex.inc - Unix/Signals.inc - Unix/ThreadLocal.inc - Unix/TimeValue.inc - Win32/Alarm.inc - Win32/DynamicLibrary.inc - Win32/Host.inc - Win32/Memory.inc - Win32/Mutex.inc - Win32/Path.inc - Win32/Process.inc - Win32/Program.inc - Win32/RWMutex.inc - Win32/Signals.inc - Win32/ThreadLocal.inc - Win32/TimeValue.inc - ) - -if( BUILD_SHARED_LIBS AND NOT WIN32 ) - target_link_libraries(LLVMSystem ${CMAKE_DL_LIBS}) -endif() diff --git a/lib/System/Disassembler.cpp b/lib/System/Disassembler.cpp deleted file mode 100644 index 139e3be1aaee..000000000000 --- a/lib/System/Disassembler.cpp +++ /dev/null @@ -1,75 +0,0 @@ -//===- lib/System/Disassembler.cpp ------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the necessary glue to call external disassembler -// libraries. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Config/config.h" -#include "llvm/System/Disassembler.h" - -#include -#include -#include -#include - -#if USE_UDIS86 -#include -#endif - -using namespace llvm; - -bool llvm::sys::hasDisassembler() -{ -#if defined (__i386__) || defined (__amd64__) || defined (__x86_64__) - // We have option to enable udis86 library. -# if USE_UDIS86 - return true; -#else - return false; -#endif -#else - return false; -#endif -} - -std::string llvm::sys::disassembleBuffer(uint8_t* start, size_t length, - uint64_t pc) { - std::stringstream res; - -#if (defined (__i386__) || defined (__amd64__) || defined (__x86_64__)) \ - && USE_UDIS86 - unsigned bits; -# if defined(__i386__) - bits = 32; -# else - bits = 64; -# endif - - ud_t ud_obj; - - ud_init(&ud_obj); - ud_set_input_buffer(&ud_obj, start, length); - ud_set_mode(&ud_obj, bits); - ud_set_pc(&ud_obj, pc); - ud_set_syntax(&ud_obj, UD_SYN_ATT); - - res << std::setbase(16) - << std::setw(bits/4); - - while (ud_disassemble(&ud_obj)) { - res << ud_insn_off(&ud_obj) << ":\t" << ud_insn_asm(&ud_obj) << "\n"; - } -#else - res << "No disassembler available. See configure help for options.\n"; -#endif - - return res.str(); -} diff --git a/lib/System/DynamicLibrary.cpp b/lib/System/DynamicLibrary.cpp deleted file mode 100644 index 660db492d6b9..000000000000 --- a/lib/System/DynamicLibrary.cpp +++ /dev/null @@ -1,161 +0,0 @@ -//===-- DynamicLibrary.cpp - Runtime link/load libraries --------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This header file implements the operating system DynamicLibrary concept. -// -// FIXME: This file leaks the ExplicitSymbols and OpenedHandles vector, and is -// not thread safe! -// -//===----------------------------------------------------------------------===// - -#include "llvm/System/DynamicLibrary.h" -#include "llvm/Config/config.h" -#include -#include -#include -#include - -// Collection of symbol name/value pairs to be searched prior to any libraries. -static std::map *ExplicitSymbols = 0; - -namespace { - -struct ExplicitSymbolsDeleter { - ~ExplicitSymbolsDeleter() { - if (ExplicitSymbols) - delete ExplicitSymbols; - } -}; - -} - -static ExplicitSymbolsDeleter Dummy; - -void llvm::sys::DynamicLibrary::AddSymbol(const char* symbolName, - void *symbolValue) { - if (ExplicitSymbols == 0) - ExplicitSymbols = new std::map(); - (*ExplicitSymbols)[symbolName] = symbolValue; -} - -#ifdef LLVM_ON_WIN32 - -#include "Win32/DynamicLibrary.inc" - -#else - -#if HAVE_DLFCN_H -#include -using namespace llvm; -using namespace llvm::sys; - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only TRULY operating system -//=== independent code. -//===----------------------------------------------------------------------===// - -static std::vector *OpenedHandles = 0; - - -bool DynamicLibrary::LoadLibraryPermanently(const char *Filename, - std::string *ErrMsg) { - void *H = dlopen(Filename, RTLD_LAZY|RTLD_GLOBAL); - if (H == 0) { - if (ErrMsg) *ErrMsg = dlerror(); - return true; - } -#ifdef __CYGWIN__ - // Cygwin searches symbols only in the main - // with the handle of dlopen(NULL, RTLD_GLOBAL). - if (Filename == NULL) - H = RTLD_DEFAULT; -#endif - if (OpenedHandles == 0) - OpenedHandles = new std::vector(); - OpenedHandles->push_back(H); - return false; -} -#else - -using namespace llvm; -using namespace llvm::sys; - -bool DynamicLibrary::LoadLibraryPermanently(const char *Filename, - std::string *ErrMsg) { - if (ErrMsg) *ErrMsg = "dlopen() not supported on this platform"; - return true; -} -#endif - -namespace llvm { -void *SearchForAddressOfSpecialSymbol(const char* symbolName); -} - -void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) { - // First check symbols added via AddSymbol(). - if (ExplicitSymbols) { - std::map::iterator I = - ExplicitSymbols->find(symbolName); - std::map::iterator E = ExplicitSymbols->end(); - - if (I != E) - return I->second; - } - -#if HAVE_DLFCN_H - // Now search the libraries. - if (OpenedHandles) { - for (std::vector::iterator I = OpenedHandles->begin(), - E = OpenedHandles->end(); I != E; ++I) { - //lt_ptr ptr = lt_dlsym(*I, symbolName); - void *ptr = dlsym(*I, symbolName); - if (ptr) { - return ptr; - } - } - } -#endif - - if (void *Result = llvm::SearchForAddressOfSpecialSymbol(symbolName)) - return Result; - -// This macro returns the address of a well-known, explicit symbol -#define EXPLICIT_SYMBOL(SYM) \ - if (!strcmp(symbolName, #SYM)) return &SYM - -// On linux we have a weird situation. The stderr/out/in symbols are both -// macros and global variables because of standards requirements. So, we -// boldly use the EXPLICIT_SYMBOL macro without checking for a #define first. -#if defined(__linux__) - { - EXPLICIT_SYMBOL(stderr); - EXPLICIT_SYMBOL(stdout); - EXPLICIT_SYMBOL(stdin); - } -#else - // For everything else, we want to check to make sure the symbol isn't defined - // as a macro before using EXPLICIT_SYMBOL. - { -#ifndef stdin - EXPLICIT_SYMBOL(stdin); -#endif -#ifndef stdout - EXPLICIT_SYMBOL(stdout); -#endif -#ifndef stderr - EXPLICIT_SYMBOL(stderr); -#endif - } -#endif -#undef EXPLICIT_SYMBOL - - return 0; -} - -#endif // LLVM_ON_WIN32 diff --git a/lib/System/Errno.cpp b/lib/System/Errno.cpp deleted file mode 100644 index 68f66f6e439b..000000000000 --- a/lib/System/Errno.cpp +++ /dev/null @@ -1,74 +0,0 @@ -//===- Errno.cpp - errno support --------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the errno wrappers. -// -//===----------------------------------------------------------------------===// - -#include "llvm/System/Errno.h" -#include "llvm/Config/config.h" // Get autoconf configuration settings - -#if HAVE_STRING_H -#include - -#if HAVE_ERRNO_H -#include -#endif - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only TRULY operating system -//=== independent code. -//===----------------------------------------------------------------------===// - -namespace llvm { -namespace sys { - -#if HAVE_ERRNO_H -std::string StrError() { - return StrError(errno); -} -#endif // HAVE_ERRNO_H - -std::string StrError(int errnum) { - const int MaxErrStrLen = 2000; - char buffer[MaxErrStrLen]; - buffer[0] = '\0'; - char* str = buffer; -#ifdef HAVE_STRERROR_R - // strerror_r is thread-safe. - if (errnum) -# if defined(__GLIBC__) && defined(_GNU_SOURCE) - // glibc defines its own incompatible version of strerror_r - // which may not use the buffer supplied. - str = strerror_r(errnum,buffer,MaxErrStrLen-1); -# else - strerror_r(errnum,buffer,MaxErrStrLen-1); -# endif -#elif defined(HAVE_STRERROR_S) // Windows. - if (errnum) - strerror_s(buffer, errnum); -#elif defined(HAVE_STRERROR) - // Copy the thread un-safe result of strerror into - // the buffer as fast as possible to minimize impact - // of collision of strerror in multiple threads. - if (errnum) - strncpy(buffer,strerror(errnum),MaxErrStrLen-1); - buffer[MaxErrStrLen-1] = '\0'; -#else - // Strange that this system doesn't even have strerror - // but, oh well, just use a generic message - sprintf(buffer, "Error #%d", errnum); -#endif - return str; -} - -} // namespace sys -} // namespace llvm - -#endif // HAVE_STRING_H diff --git a/lib/System/Host.cpp b/lib/System/Host.cpp deleted file mode 100644 index e7193dbce92e..000000000000 --- a/lib/System/Host.cpp +++ /dev/null @@ -1,305 +0,0 @@ -//===-- Host.cpp - Implement OS Host Concept --------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This header file implements the operating system Host concept. -// -//===----------------------------------------------------------------------===// - -#include "llvm/System/Host.h" -#include "llvm/Config/config.h" -#include - -// Include the platform-specific parts of this class. -#ifdef LLVM_ON_UNIX -#include "Unix/Host.inc" -#endif -#ifdef LLVM_ON_WIN32 -#include "Win32/Host.inc" -#endif -#ifdef _MSC_VER -#include -#endif - -//===----------------------------------------------------------------------===// -// -// Implementations of the CPU detection routines -// -//===----------------------------------------------------------------------===// - -using namespace llvm; - -#if defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86)\ - || defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64) - -/// GetX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in the -/// specified arguments. If we can't run cpuid on the host, return true. -static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX, - unsigned *rEBX, unsigned *rECX, unsigned *rEDX) { -#if defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64) - #if defined(__GNUC__) - // gcc doesn't know cpuid would clobber ebx/rbx. Preseve it manually. - asm ("movq\t%%rbx, %%rsi\n\t" - "cpuid\n\t" - "xchgq\t%%rbx, %%rsi\n\t" - : "=a" (*rEAX), - "=S" (*rEBX), - "=c" (*rECX), - "=d" (*rEDX) - : "a" (value)); - return false; - #elif defined(_MSC_VER) - int registers[4]; - __cpuid(registers, value); - *rEAX = registers[0]; - *rEBX = registers[1]; - *rECX = registers[2]; - *rEDX = registers[3]; - return false; - #endif -#elif defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86) - #if defined(__GNUC__) - asm ("movl\t%%ebx, %%esi\n\t" - "cpuid\n\t" - "xchgl\t%%ebx, %%esi\n\t" - : "=a" (*rEAX), - "=S" (*rEBX), - "=c" (*rECX), - "=d" (*rEDX) - : "a" (value)); - return false; - #elif defined(_MSC_VER) - __asm { - mov eax,value - cpuid - mov esi,rEAX - mov dword ptr [esi],eax - mov esi,rEBX - mov dword ptr [esi],ebx - mov esi,rECX - mov dword ptr [esi],ecx - mov esi,rEDX - mov dword ptr [esi],edx - } - return false; - #endif -#endif - return true; -} - -static void DetectX86FamilyModel(unsigned EAX, unsigned &Family, unsigned &Model) { - Family = (EAX >> 8) & 0xf; // Bits 8 - 11 - Model = (EAX >> 4) & 0xf; // Bits 4 - 7 - if (Family == 6 || Family == 0xf) { - if (Family == 0xf) - // Examine extended family ID if family ID is F. - Family += (EAX >> 20) & 0xff; // Bits 20 - 27 - // Examine extended model ID if family ID is 6 or F. - Model += ((EAX >> 16) & 0xf) << 4; // Bits 16 - 19 - } -} - -std::string sys::getHostCPUName() { - unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0; - if (GetX86CpuIDAndInfo(0x1, &EAX, &EBX, &ECX, &EDX)) - return "generic"; - unsigned Family = 0; - unsigned Model = 0; - DetectX86FamilyModel(EAX, Family, Model); - - GetX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); - bool Em64T = (EDX >> 29) & 0x1; - bool HasSSE3 = (ECX & 0x1); - - union { - unsigned u[3]; - char c[12]; - } text; - - GetX86CpuIDAndInfo(0, &EAX, text.u+0, text.u+2, text.u+1); - if (memcmp(text.c, "GenuineIntel", 12) == 0) { - switch (Family) { - case 3: - return "i386"; - case 4: - switch (Model) { - case 0: // Intel486TM DX processors - case 1: // Intel486TM DX processors - case 2: // Intel486 SX processors - case 3: // Intel487TM processors, IntelDX2 OverDrive® processors, - // IntelDX2TM processors - case 4: // Intel486 SL processor - case 5: // IntelSX2TM processors - case 7: // Write-Back Enhanced IntelDX2 processors - case 8: // IntelDX4 OverDrive processors, IntelDX4TM processors - default: return "i486"; - } - case 5: - switch (Model) { - case 1: // Pentium OverDrive processor for Pentium processor (60, 66), - // Pentium® processors (60, 66) - case 2: // Pentium OverDrive processor for Pentium processor (75, 90, - // 100, 120, 133), Pentium processors (75, 90, 100, 120, 133, - // 150, 166, 200) - case 3: // Pentium OverDrive processors for Intel486 processor-based - // systems - return "pentium"; - - case 4: // Pentium OverDrive processor with MMXTM technology for Pentium - // processor (75, 90, 100, 120, 133), Pentium processor with - // MMXTM technology (166, 200) - return "pentium-mmx"; - - default: return "pentium"; - } - case 6: - switch (Model) { - case 1: // Pentium Pro processor - return "pentiumpro"; - - case 3: // Intel Pentium II OverDrive processor, Pentium II processor, - // model 03 - case 5: // Pentium II processor, model 05, Pentium II Xeon processor, - // model 05, and Intel® Celeron® processor, model 05 - case 6: // Celeron processor, model 06 - return "pentium2"; - - case 7: // Pentium III processor, model 07, and Pentium III Xeon - // processor, model 07 - case 8: // Pentium III processor, model 08, Pentium III Xeon processor, - // model 08, and Celeron processor, model 08 - case 10: // Pentium III Xeon processor, model 0Ah - case 11: // Pentium III processor, model 0Bh - return "pentium3"; - - case 9: // Intel Pentium M processor, Intel Celeron M processor model 09. - case 13: // Intel Pentium M processor, Intel Celeron M processor, model - // 0Dh. All processors are manufactured using the 90 nm process. - return "pentium-m"; - - case 14: // Intel CoreTM Duo processor, Intel CoreTM Solo processor, model - // 0Eh. All processors are manufactured using the 65 nm process. - return "yonah"; - - case 15: // Intel CoreTM2 Duo processor, Intel CoreTM2 Duo mobile - // processor, Intel CoreTM2 Quad processor, Intel CoreTM2 Quad - // mobile processor, Intel CoreTM2 Extreme processor, Intel - // Pentium Dual-Core processor, Intel Xeon processor, model - // 0Fh. All processors are manufactured using the 65 nm process. - case 22: // Intel Celeron processor model 16h. All processors are - // manufactured using the 65 nm process - return "core2"; - - case 21: // Intel EP80579 Integrated Processor and Intel EP80579 - // Integrated Processor with Intel QuickAssist Technology - return "i686"; // FIXME: ??? - - case 23: // Intel CoreTM2 Extreme processor, Intel Xeon processor, model - // 17h. All processors are manufactured using the 45 nm process. - // - // 45nm: Penryn , Wolfdale, Yorkfield (XE) - return "penryn"; - - case 26: // Intel Core i7 processor and Intel Xeon processor. All - // processors are manufactured using the 45 nm process. - case 29: // Intel Xeon processor MP. All processors are manufactured using - // the 45 nm process. - return "corei7"; - - case 28: // Intel Atom processor. All processors are manufactured using - // the 45 nm process - return "atom"; - - default: return "i686"; - } - case 15: { - switch (Model) { - case 0: // Pentium 4 processor, Intel Xeon processor. All processors are - // model 00h and manufactured using the 0.18 micron process. - case 1: // Pentium 4 processor, Intel Xeon processor, Intel Xeon - // processor MP, and Intel Celeron processor. All processors are - // model 01h and manufactured using the 0.18 micron process. - case 2: // Pentium 4 processor, Mobile Intel Pentium 4 processor – M, - // Intel Xeon processor, Intel Xeon processor MP, Intel Celeron - // processor, and Mobile Intel Celeron processor. All processors - // are model 02h and manufactured using the 0.13 micron process. - return (Em64T) ? "x86-64" : "pentium4"; - - case 3: // Pentium 4 processor, Intel Xeon processor, Intel Celeron D - // processor. All processors are model 03h and manufactured using - // the 90 nm process. - case 4: // Pentium 4 processor, Pentium 4 processor Extreme Edition, - // Pentium D processor, Intel Xeon processor, Intel Xeon - // processor MP, Intel Celeron D processor. All processors are - // model 04h and manufactured using the 90 nm process. - case 6: // Pentium 4 processor, Pentium D processor, Pentium processor - // Extreme Edition, Intel Xeon processor, Intel Xeon processor - // MP, Intel Celeron D processor. All processors are model 06h - // and manufactured using the 65 nm process. - return (Em64T) ? "nocona" : "prescott"; - - default: - return (Em64T) ? "x86-64" : "pentium4"; - } - } - - default: - return "generic"; - } - } else if (memcmp(text.c, "AuthenticAMD", 12) == 0) { - // FIXME: this poorly matches the generated SubtargetFeatureKV table. There - // appears to be no way to generate the wide variety of AMD-specific targets - // from the information returned from CPUID. - switch (Family) { - case 4: - return "i486"; - case 5: - switch (Model) { - case 6: - case 7: return "k6"; - case 8: return "k6-2"; - case 9: - case 13: return "k6-3"; - default: return "pentium"; - } - case 6: - switch (Model) { - case 4: return "athlon-tbird"; - case 6: - case 7: - case 8: return "athlon-mp"; - case 10: return "athlon-xp"; - default: return "athlon"; - } - case 15: - if (HasSSE3) { - return "k8-sse3"; - } else { - switch (Model) { - case 1: return "opteron"; - case 5: return "athlon-fx"; // also opteron - default: return "athlon64"; - } - } - case 16: - return "amdfam10"; - default: - return "generic"; - } - } - return "generic"; -} -#else -std::string sys::getHostCPUName() { - return "generic"; -} -#endif - -bool sys::getHostCPUFeatures(StringMap &Features){ - return false; -} diff --git a/lib/System/IncludeFile.cpp b/lib/System/IncludeFile.cpp deleted file mode 100644 index 8258d40326f9..000000000000 --- a/lib/System/IncludeFile.cpp +++ /dev/null @@ -1,20 +0,0 @@ -//===- lib/System/IncludeFile.cpp - Ensure Linking Of Implementation -----===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the IncludeFile constructor. -// -//===----------------------------------------------------------------------===// - -#include "llvm/System/IncludeFile.h" - -using namespace llvm; - -// This constructor is used to ensure linking of other modules. See the -// llvm/System/IncludeFile.h header for details. -IncludeFile::IncludeFile(const void*) {} diff --git a/lib/System/Makefile b/lib/System/Makefile deleted file mode 100644 index bb013b9f1f16..000000000000 --- a/lib/System/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -##===- lib/System/Makefile ---------------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../.. -LIBRARYNAME = LLVMSystem -BUILD_ARCHIVE = 1 -REQUIRES_RTTI = 1 -include $(LEVEL)/Makefile.config - -ifeq ($(HOST_OS),MingW) - REQUIRES_EH := 1 -endif - -EXTRA_DIST = Unix Win32 README.txt - -include $(LEVEL)/Makefile.common - -CompileCommonOpts := $(filter-out -pedantic,$(CompileCommonOpts)) -CompileCommonOpts := $(filter-out -Wno-long-long,$(CompileCommonOpts)) diff --git a/lib/System/Memory.cpp b/lib/System/Memory.cpp deleted file mode 100644 index ef23b8d12aab..000000000000 --- a/lib/System/Memory.cpp +++ /dev/null @@ -1,74 +0,0 @@ -//===- Memory.cpp - Memory Handling Support ---------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines some helpful functions for allocating memory and dealing -// with memory mapped files -// -//===----------------------------------------------------------------------===// - -#include "llvm/System/Memory.h" -#include "llvm/System/Valgrind.h" -#include "llvm/Config/config.h" - -namespace llvm { -using namespace sys; -} - -// Include the platform-specific parts of this class. -#ifdef LLVM_ON_UNIX -#include "Unix/Memory.inc" -#endif -#ifdef LLVM_ON_WIN32 -#include "Win32/Memory.inc" -#endif - -extern "C" void sys_icache_invalidate(const void *Addr, size_t len); - -/// InvalidateInstructionCache - Before the JIT can run a block of code -/// that has been emitted it must invalidate the instruction cache on some -/// platforms. -void llvm::sys::Memory::InvalidateInstructionCache(const void *Addr, - size_t Len) { - -// icache invalidation for PPC and ARM. -#if defined(__APPLE__) - -# if (defined(__POWERPC__) || defined (__ppc__) || \ - defined(_POWER) || defined(_ARCH_PPC)) || defined(__arm__) - sys_icache_invalidate(Addr, Len); -# endif - -#else - -# if (defined(__POWERPC__) || defined (__ppc__) || \ - defined(_POWER) || defined(_ARCH_PPC)) && defined(__GNUC__) - const size_t LineSize = 32; - - const intptr_t Mask = ~(LineSize - 1); - const intptr_t StartLine = ((intptr_t) Addr) & Mask; - const intptr_t EndLine = ((intptr_t) Addr + Len + LineSize - 1) & Mask; - - for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) - asm volatile("dcbf 0, %0" : : "r"(Line)); - asm volatile("sync"); - - for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) - asm volatile("icbi 0, %0" : : "r"(Line)); - asm volatile("isync"); -# elif defined(__arm__) && defined(__GNUC__) - // FIXME: Can we safely always call this for __GNUC__ everywhere? - char *Start = (char*) Addr; - char *End = Start + Len; - __clear_cache(Start, End); -# endif - -#endif // end apple - - ValgrindDiscardTranslations(Addr, Len); -} diff --git a/lib/System/Mutex.cpp b/lib/System/Mutex.cpp deleted file mode 100644 index 8ccd6e52c4d5..000000000000 --- a/lib/System/Mutex.cpp +++ /dev/null @@ -1,157 +0,0 @@ -//===- Mutex.cpp - Mutual Exclusion Lock ------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the llvm::sys::Mutex class. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Config/config.h" -#include "llvm/System/Mutex.h" - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only TRULY operating system -//=== independent code. -//===----------------------------------------------------------------------===// - -#if !defined(ENABLE_THREADS) || ENABLE_THREADS == 0 -// Define all methods as no-ops if threading is explicitly disabled -namespace llvm { -using namespace sys; -MutexImpl::MutexImpl( bool recursive) { } -MutexImpl::~MutexImpl() { } -bool MutexImpl::acquire() { return true; } -bool MutexImpl::release() { return true; } -bool MutexImpl::tryacquire() { return true; } -} -#else - -#if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_MUTEX_LOCK) - -#include -#include -#include - -namespace llvm { -using namespace sys; - - -// This variable is useful for situations where the pthread library has been -// compiled with weak linkage for its interface symbols. This allows the -// threading support to be turned off by simply not linking against -lpthread. -// In that situation, the value of pthread_mutex_init will be 0 and -// consequently pthread_enabled will be false. In such situations, all the -// pthread operations become no-ops and the functions all return false. If -// pthread_mutex_init does have an address, then mutex support is enabled. -// Note: all LLVM tools will link against -lpthread if its available since it -// is configured into the LIBS variable. -// Note: this line of code generates a warning if pthread_mutex_init is not -// declared with weak linkage. It's safe to ignore the warning. -static const bool pthread_enabled = true; - -// Construct a Mutex using pthread calls -MutexImpl::MutexImpl( bool recursive) - : data_(0) -{ - if (pthread_enabled) - { - // Declare the pthread_mutex data structures - pthread_mutex_t* mutex = - static_cast(malloc(sizeof(pthread_mutex_t))); - pthread_mutexattr_t attr; - - // Initialize the mutex attributes - int errorcode = pthread_mutexattr_init(&attr); - assert(errorcode == 0); - - // Initialize the mutex as a recursive mutex, if requested, or normal - // otherwise. - int kind = ( recursive ? PTHREAD_MUTEX_RECURSIVE : PTHREAD_MUTEX_NORMAL ); - errorcode = pthread_mutexattr_settype(&attr, kind); - assert(errorcode == 0); - -#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__DragonFly__) - // Make it a process local mutex - errorcode = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE); -#endif - - // Initialize the mutex - errorcode = pthread_mutex_init(mutex, &attr); - assert(errorcode == 0); - - // Destroy the attributes - errorcode = pthread_mutexattr_destroy(&attr); - assert(errorcode == 0); - - // Assign the data member - data_ = mutex; - } -} - -// Destruct a Mutex -MutexImpl::~MutexImpl() -{ - if (pthread_enabled) - { - pthread_mutex_t* mutex = static_cast(data_); - assert(mutex != 0); - pthread_mutex_destroy(mutex); - free(mutex); - } -} - -bool -MutexImpl::acquire() -{ - if (pthread_enabled) - { - pthread_mutex_t* mutex = static_cast(data_); - assert(mutex != 0); - - int errorcode = pthread_mutex_lock(mutex); - return errorcode == 0; - } else return false; -} - -bool -MutexImpl::release() -{ - if (pthread_enabled) - { - pthread_mutex_t* mutex = static_cast(data_); - assert(mutex != 0); - - int errorcode = pthread_mutex_unlock(mutex); - return errorcode == 0; - } else return false; -} - -bool -MutexImpl::tryacquire() -{ - if (pthread_enabled) - { - pthread_mutex_t* mutex = static_cast(data_); - assert(mutex != 0); - - int errorcode = pthread_mutex_trylock(mutex); - return errorcode == 0; - } else return false; -} - -} - -#elif defined(LLVM_ON_UNIX) -#include "Unix/Mutex.inc" -#elif defined( LLVM_ON_WIN32) -#include "Win32/Mutex.inc" -#else -#warning Neither LLVM_ON_UNIX nor LLVM_ON_WIN32 was set in System/Mutex.cpp -#endif -#endif - diff --git a/lib/System/Path.cpp b/lib/System/Path.cpp deleted file mode 100644 index 4445c667d86e..000000000000 --- a/lib/System/Path.cpp +++ /dev/null @@ -1,264 +0,0 @@ -//===-- Path.cpp - Implement OS Path Concept --------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This header file implements the operating system Path concept. -// -//===----------------------------------------------------------------------===// - -#include "llvm/System/Path.h" -#include "llvm/Config/config.h" -#include -#include -#include -using namespace llvm; -using namespace sys; - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only TRULY operating system -//=== independent code. -//===----------------------------------------------------------------------===// - -bool Path::operator==(const Path &that) const { - return path == that.path; -} - -bool Path::operator<(const Path& that) const { - return path < that.path; -} - -Path -Path::GetLLVMConfigDir() { - Path result; -#ifdef LLVM_ETCDIR - if (result.set(LLVM_ETCDIR)) - return result; -#endif - return GetLLVMDefaultConfigDir(); -} - -LLVMFileType -sys::IdentifyFileType(const char *magic, unsigned length) { - assert(magic && "Invalid magic number string"); - assert(length >=4 && "Invalid magic number length"); - switch ((unsigned char)magic[0]) { - case 0xDE: // 0x0B17C0DE = BC wraper - if (magic[1] == (char)0xC0 && magic[2] == (char)0x17 && - magic[3] == (char)0x0B) - return Bitcode_FileType; - break; - case 'B': - if (magic[1] == 'C' && magic[2] == (char)0xC0 && magic[3] == (char)0xDE) - return Bitcode_FileType; - break; - case '!': - if (length >= 8) - if (memcmp(magic,"!\n",8) == 0) - return Archive_FileType; - break; - - case '\177': - if (magic[1] == 'E' && magic[2] == 'L' && magic[3] == 'F') { - if (length >= 18 && magic[17] == 0) - switch (magic[16]) { - default: break; - case 1: return ELF_Relocatable_FileType; - case 2: return ELF_Executable_FileType; - case 3: return ELF_SharedObject_FileType; - case 4: return ELF_Core_FileType; - } - } - break; - - case 0xCA: - if (magic[1] == char(0xFE) && magic[2] == char(0xBA) && - magic[3] == char(0xBE)) { - // This is complicated by an overlap with Java class files. - // See the Mach-O section in /usr/share/file/magic for details. - if (length >= 8 && magic[7] < 43) - // FIXME: Universal Binary of any type. - return Mach_O_DynamicallyLinkedSharedLib_FileType; - } - break; - - case 0xFE: - case 0xCE: { - uint16_t type = 0; - if (magic[0] == char(0xFE) && magic[1] == char(0xED) && - magic[2] == char(0xFA) && magic[3] == char(0xCE)) { - /* Native endian */ - if (length >= 16) type = magic[14] << 8 | magic[15]; - } else if (magic[0] == char(0xCE) && magic[1] == char(0xFA) && - magic[2] == char(0xED) && magic[3] == char(0xFE)) { - /* Reverse endian */ - if (length >= 14) type = magic[13] << 8 | magic[12]; - } - switch (type) { - default: break; - case 1: return Mach_O_Object_FileType; - case 2: return Mach_O_Executable_FileType; - case 3: return Mach_O_FixedVirtualMemorySharedLib_FileType; - case 4: return Mach_O_Core_FileType; - case 5: return Mach_O_PreloadExectuable_FileType; - case 6: return Mach_O_DynamicallyLinkedSharedLib_FileType; - case 7: return Mach_O_DynamicLinker_FileType; - case 8: return Mach_O_Bundle_FileType; - case 9: return Mach_O_DynamicallyLinkedSharedLibStub_FileType; - case 10: break; // FIXME: MH_DSYM companion file with only debug. - } - break; - } - case 0xF0: // PowerPC Windows - case 0x83: // Alpha 32-bit - case 0x84: // Alpha 64-bit - case 0x66: // MPS R4000 Windows - case 0x50: // mc68K - case 0x4c: // 80386 Windows - if (magic[1] == 0x01) - return COFF_FileType; - - case 0x90: // PA-RISC Windows - case 0x68: // mc68K Windows - if (magic[1] == 0x02) - return COFF_FileType; - break; - - default: - break; - } - return Unknown_FileType; -} - -bool -Path::isArchive() const { - return hasMagicNumber("!\012"); -} - -bool -Path::isDynamicLibrary() const { - std::string Magic; - if (getMagicNumber(Magic, 64)) - switch (IdentifyFileType(Magic.c_str(), - static_cast(Magic.length()))) { - default: return false; - case Mach_O_FixedVirtualMemorySharedLib_FileType: - case Mach_O_DynamicallyLinkedSharedLib_FileType: - case Mach_O_DynamicallyLinkedSharedLibStub_FileType: - case ELF_SharedObject_FileType: - case COFF_FileType: return true; - } - - return false; -} - -Path -Path::FindLibrary(std::string& name) { - std::vector LibPaths; - GetSystemLibraryPaths(LibPaths); - for (unsigned i = 0; i < LibPaths.size(); ++i) { - sys::Path FullPath(LibPaths[i]); - FullPath.appendComponent("lib" + name + LTDL_SHLIB_EXT); - if (FullPath.isDynamicLibrary()) - return FullPath; - FullPath.eraseSuffix(); - FullPath.appendSuffix("a"); - if (FullPath.isArchive()) - return FullPath; - } - return sys::Path(); -} - -StringRef Path::GetDLLSuffix() { - return LTDL_SHLIB_EXT; -} - -bool -Path::isBitcodeFile() const { - std::string actualMagic; - if (!getMagicNumber(actualMagic, 4)) - return false; - LLVMFileType FT = - IdentifyFileType(actualMagic.c_str(), - static_cast(actualMagic.length())); - return FT == Bitcode_FileType; -} - -bool Path::hasMagicNumber(StringRef Magic) const { - std::string actualMagic; - if (getMagicNumber(actualMagic, static_cast(Magic.size()))) - return Magic == actualMagic; - return false; -} - -static void getPathList(const char*path, std::vector& Paths) { - const char* at = path; - const char* delim = strchr(at, PathSeparator); - Path tmpPath; - while (delim != 0) { - std::string tmp(at, size_t(delim-at)); - if (tmpPath.set(tmp)) - if (tmpPath.canRead()) - Paths.push_back(tmpPath); - at = delim + 1; - delim = strchr(at, PathSeparator); - } - - if (*at != 0) - if (tmpPath.set(std::string(at))) - if (tmpPath.canRead()) - Paths.push_back(tmpPath); -} - -static StringRef getDirnameCharSep(StringRef path, const char *Sep) { - assert(Sep[0] != '\0' && Sep[1] == '\0' && - "Sep must be a 1-character string literal."); - if (path.empty()) - return "."; - - // If the path is all slashes, return a single slash. - // Otherwise, remove all trailing slashes. - - signed pos = static_cast(path.size()) - 1; - - while (pos >= 0 && path[pos] == Sep[0]) - --pos; - - if (pos < 0) - return path[0] == Sep[0] ? Sep : "."; - - // Any slashes left? - signed i = 0; - - while (i < pos && path[i] != Sep[0]) - ++i; - - if (i == pos) // No slashes? Return "." - return "."; - - // There is at least one slash left. Remove all trailing non-slashes. - while (pos >= 0 && path[pos] != Sep[0]) - --pos; - - // Remove any trailing slashes. - while (pos >= 0 && path[pos] == Sep[0]) - --pos; - - if (pos < 0) - return path[0] == Sep[0] ? Sep : "."; - - return path.substr(0, pos+1); -} - -// Include the truly platform-specific parts of this class. -#if defined(LLVM_ON_UNIX) -#include "Unix/Path.inc" -#endif -#if defined(LLVM_ON_WIN32) -#include "Win32/Path.inc" -#endif - diff --git a/lib/System/Process.cpp b/lib/System/Process.cpp deleted file mode 100644 index e93b2af4c12b..000000000000 --- a/lib/System/Process.cpp +++ /dev/null @@ -1,33 +0,0 @@ -//===-- Process.cpp - Implement OS Process Concept --------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This header file implements the operating system Process concept. -// -//===----------------------------------------------------------------------===// - -#include "llvm/System/Process.h" -#include "llvm/Config/config.h" - -namespace llvm { -using namespace sys; - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only TRULY operating system -//=== independent code. -//===----------------------------------------------------------------------===// - -} - -// Include the platform-specific parts of this class. -#ifdef LLVM_ON_UNIX -#include "Unix/Process.inc" -#endif -#ifdef LLVM_ON_WIN32 -#include "Win32/Process.inc" -#endif diff --git a/lib/System/Program.cpp b/lib/System/Program.cpp deleted file mode 100644 index cd58c2cc578c..000000000000 --- a/lib/System/Program.cpp +++ /dev/null @@ -1,56 +0,0 @@ -//===-- Program.cpp - Implement OS Program Concept --------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This header file implements the operating system Program concept. -// -//===----------------------------------------------------------------------===// - -#include "llvm/System/Program.h" -#include "llvm/Config/config.h" -using namespace llvm; -using namespace sys; - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only TRULY operating system -//=== independent code. -//===----------------------------------------------------------------------===// - -int -Program::ExecuteAndWait(const Path& path, - const char** args, - const char** envp, - const Path** redirects, - unsigned secondsToWait, - unsigned memoryLimit, - std::string* ErrMsg) { - Program prg; - if (prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg)) - return prg.Wait(secondsToWait, ErrMsg); - else - return -1; -} - -void -Program::ExecuteNoWait(const Path& path, - const char** args, - const char** envp, - const Path** redirects, - unsigned memoryLimit, - std::string* ErrMsg) { - Program prg; - prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg); -} - -// Include the platform-specific parts of this class. -#ifdef LLVM_ON_UNIX -#include "Unix/Program.inc" -#endif -#ifdef LLVM_ON_WIN32 -#include "Win32/Program.inc" -#endif diff --git a/lib/System/README.txt b/lib/System/README.txt deleted file mode 100644 index eacb20094a61..000000000000 --- a/lib/System/README.txt +++ /dev/null @@ -1,43 +0,0 @@ -Design Of lib/System -==================== - -The software in this directory is designed to completely shield LLVM from any -and all operating system specific functionality. It is not intended to be a -complete operating system wrapper (such as ACE), but only to provide the -functionality necessary to support LLVM. - -The software located here, of necessity, has very specific and stringent design -rules. Violation of these rules means that cracks in the shield could form and -the primary goal of the library is defeated. By consistently using this library, -LLVM becomes more easily ported to new platforms since the only thing requiring -porting is this library. - -Complete documentation for the library can be found in the file: - llvm/docs/SystemLibrary.html -or at this URL: - http://llvm.org/docs/SystemLibrary.html - -While we recommend that you read the more detailed documentation, for the -impatient, here's a high level summary of the library's requirements. - - 1. No system header files are to be exposed through the interface. - 2. Std C++ and Std C header files are okay to be exposed through the interface. - 3. No exposed system-specific functions. - 4. No exposed system-specific data. - 5. Data in lib/System classes must use only simple C++ intrinsic types. - 6. Errors are handled by returning "true" and setting an optional std::string - 7. Library must not throw any exceptions, period. - 8. Interface functions must not have throw() specifications. - 9. No duplicate function impementations are permitted within an operating - system class. - -To accomplish these requirements, the library has numerous design criteria that -must be satisfied. Here's a high level summary of the library's design criteria: - - 1. No unused functionality (only what LLVM needs) - 2. High-Level Interfaces - 3. Use Opaque Classes - 4. Common Implementations - 5. Multiple Implementations - 6. Minimize Memory Allocation - 7. No Virtual Methods diff --git a/lib/System/RWMutex.cpp b/lib/System/RWMutex.cpp deleted file mode 100644 index deb04709d829..000000000000 --- a/lib/System/RWMutex.cpp +++ /dev/null @@ -1,157 +0,0 @@ -//===- RWMutex.cpp - Reader/Writer Mutual Exclusion Lock --------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the llvm::sys::RWMutex class. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Config/config.h" -#include "llvm/System/RWMutex.h" -#include - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only TRULY operating system -//=== independent code. -//===----------------------------------------------------------------------===// - -#if !defined(ENABLE_THREADS) || ENABLE_THREADS == 0 -// Define all methods as no-ops if threading is explicitly disabled -namespace llvm { -using namespace sys; -RWMutexImpl::RWMutexImpl() { } -RWMutexImpl::~RWMutexImpl() { } -bool RWMutexImpl::reader_acquire() { return true; } -bool RWMutexImpl::reader_release() { return true; } -bool RWMutexImpl::writer_acquire() { return true; } -bool RWMutexImpl::writer_release() { return true; } -} -#else - -#if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_RWLOCK_INIT) - -#include -#include -#include - -namespace llvm { -using namespace sys; - - -// This variable is useful for situations where the pthread library has been -// compiled with weak linkage for its interface symbols. This allows the -// threading support to be turned off by simply not linking against -lpthread. -// In that situation, the value of pthread_mutex_init will be 0 and -// consequently pthread_enabled will be false. In such situations, all the -// pthread operations become no-ops and the functions all return false. If -// pthread_rwlock_init does have an address, then rwlock support is enabled. -// Note: all LLVM tools will link against -lpthread if its available since it -// is configured into the LIBS variable. -// Note: this line of code generates a warning if pthread_rwlock_init is not -// declared with weak linkage. It's safe to ignore the warning. -static const bool pthread_enabled = true; - -// Construct a RWMutex using pthread calls -RWMutexImpl::RWMutexImpl() - : data_(0) -{ - if (pthread_enabled) - { - // Declare the pthread_rwlock data structures - pthread_rwlock_t* rwlock = - static_cast(malloc(sizeof(pthread_rwlock_t))); - -#ifdef __APPLE__ - // Workaround a bug/mis-feature in Darwin's pthread_rwlock_init. - bzero(rwlock, sizeof(pthread_rwlock_t)); -#endif - - // Initialize the rwlock - int errorcode = pthread_rwlock_init(rwlock, NULL); - (void)errorcode; - assert(errorcode == 0); - - // Assign the data member - data_ = rwlock; - } -} - -// Destruct a RWMutex -RWMutexImpl::~RWMutexImpl() -{ - if (pthread_enabled) - { - pthread_rwlock_t* rwlock = static_cast(data_); - assert(rwlock != 0); - pthread_rwlock_destroy(rwlock); - free(rwlock); - } -} - -bool -RWMutexImpl::reader_acquire() -{ - if (pthread_enabled) - { - pthread_rwlock_t* rwlock = static_cast(data_); - assert(rwlock != 0); - - int errorcode = pthread_rwlock_rdlock(rwlock); - return errorcode == 0; - } else return false; -} - -bool -RWMutexImpl::reader_release() -{ - if (pthread_enabled) - { - pthread_rwlock_t* rwlock = static_cast(data_); - assert(rwlock != 0); - - int errorcode = pthread_rwlock_unlock(rwlock); - return errorcode == 0; - } else return false; -} - -bool -RWMutexImpl::writer_acquire() -{ - if (pthread_enabled) - { - pthread_rwlock_t* rwlock = static_cast(data_); - assert(rwlock != 0); - - int errorcode = pthread_rwlock_wrlock(rwlock); - return errorcode == 0; - } else return false; -} - -bool -RWMutexImpl::writer_release() -{ - if (pthread_enabled) - { - pthread_rwlock_t* rwlock = static_cast(data_); - assert(rwlock != 0); - - int errorcode = pthread_rwlock_unlock(rwlock); - return errorcode == 0; - } else return false; -} - -} - -#elif defined(LLVM_ON_UNIX) -#include "Unix/RWMutex.inc" -#elif defined( LLVM_ON_WIN32) -#include "Win32/RWMutex.inc" -#else -#warning Neither LLVM_ON_UNIX nor LLVM_ON_WIN32 was set in System/Mutex.cpp -#endif -#endif diff --git a/lib/System/SearchForAddressOfSpecialSymbol.cpp b/lib/System/SearchForAddressOfSpecialSymbol.cpp deleted file mode 100644 index 73b484c2e917..000000000000 --- a/lib/System/SearchForAddressOfSpecialSymbol.cpp +++ /dev/null @@ -1,64 +0,0 @@ -//===- SearchForAddressOfSpecialSymbol.cpp - Function addresses -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file pulls the addresses of certain symbols out of the linker. It must -// include as few header files as possible because it declares the symbols as -// void*, which would conflict with the actual symbol type if any header -// declared it. -// -//===----------------------------------------------------------------------===// - -#include - -// Must declare the symbols in the global namespace. -static void *DoSearch(const char* symbolName) { -#define EXPLICIT_SYMBOL(SYM) \ - extern void *SYM; if (!strcmp(symbolName, #SYM)) return &SYM - - // If this is darwin, it has some funky issues, try to solve them here. Some - // important symbols are marked 'private external' which doesn't allow - // SearchForAddressOfSymbol to find them. As such, we special case them here, - // there is only a small handful of them. - -#ifdef __APPLE__ - { - EXPLICIT_SYMBOL(__ashldi3); - EXPLICIT_SYMBOL(__ashrdi3); - EXPLICIT_SYMBOL(__cmpdi2); - EXPLICIT_SYMBOL(__divdi3); - EXPLICIT_SYMBOL(__eprintf); - EXPLICIT_SYMBOL(__fixdfdi); - EXPLICIT_SYMBOL(__fixsfdi); - EXPLICIT_SYMBOL(__fixunsdfdi); - EXPLICIT_SYMBOL(__fixunssfdi); - EXPLICIT_SYMBOL(__floatdidf); - EXPLICIT_SYMBOL(__floatdisf); - EXPLICIT_SYMBOL(__lshrdi3); - EXPLICIT_SYMBOL(__moddi3); - EXPLICIT_SYMBOL(__udivdi3); - EXPLICIT_SYMBOL(__umoddi3); - } -#endif - -#ifdef __CYGWIN__ - { - EXPLICIT_SYMBOL(_alloca); - EXPLICIT_SYMBOL(__main); - } -#endif - -#undef EXPLICIT_SYMBOL - return 0; -} - -namespace llvm { -void *SearchForAddressOfSpecialSymbol(const char* symbolName) { - return DoSearch(symbolName); -} -} // namespace llvm diff --git a/lib/System/Signals.cpp b/lib/System/Signals.cpp deleted file mode 100644 index d345b0a9aed4..000000000000 --- a/lib/System/Signals.cpp +++ /dev/null @@ -1,34 +0,0 @@ -//===- Signals.cpp - Signal Handling support --------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines some helpful functions for dealing with the possibility of -// Unix signals occuring while your program is running. -// -//===----------------------------------------------------------------------===// - -#include "llvm/System/Signals.h" -#include "llvm/Config/config.h" - -namespace llvm { -using namespace sys; - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only TRULY operating system -//=== independent code. -//===----------------------------------------------------------------------===// - -} - -// Include the platform-specific parts of this class. -#ifdef LLVM_ON_UNIX -#include "Unix/Signals.inc" -#endif -#ifdef LLVM_ON_WIN32 -#include "Win32/Signals.inc" -#endif diff --git a/lib/System/ThreadLocal.cpp b/lib/System/ThreadLocal.cpp deleted file mode 100644 index f6a55a1c0b9b..000000000000 --- a/lib/System/ThreadLocal.cpp +++ /dev/null @@ -1,85 +0,0 @@ -//===- ThreadLocal.cpp - Thread Local Data ----------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the llvm::sys::ThreadLocal class. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Config/config.h" -#include "llvm/System/ThreadLocal.h" - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only TRULY operating system -//=== independent code. -//===----------------------------------------------------------------------===// - -#if !defined(ENABLE_THREADS) || ENABLE_THREADS == 0 -// Define all methods as no-ops if threading is explicitly disabled -namespace llvm { -using namespace sys; -ThreadLocalImpl::ThreadLocalImpl() { } -ThreadLocalImpl::~ThreadLocalImpl() { } -void ThreadLocalImpl::setInstance(const void* d) { data = const_cast(d);} -const void* ThreadLocalImpl::getInstance() { return data; } -void ThreadLocalImpl::removeInstance() { data = 0; } -} -#else - -#if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_GETSPECIFIC) - -#include -#include -#include - -namespace llvm { -using namespace sys; - -ThreadLocalImpl::ThreadLocalImpl() : data(0) { - pthread_key_t* key = new pthread_key_t; - int errorcode = pthread_key_create(key, NULL); - assert(errorcode == 0); - (void) errorcode; - data = (void*)key; -} - -ThreadLocalImpl::~ThreadLocalImpl() { - pthread_key_t* key = static_cast(data); - int errorcode = pthread_key_delete(*key); - assert(errorcode == 0); - (void) errorcode; - delete key; -} - -void ThreadLocalImpl::setInstance(const void* d) { - pthread_key_t* key = static_cast(data); - int errorcode = pthread_setspecific(*key, d); - assert(errorcode == 0); - (void) errorcode; -} - -const void* ThreadLocalImpl::getInstance() { - pthread_key_t* key = static_cast(data); - return pthread_getspecific(*key); -} - -void ThreadLocalImpl::removeInstance() { - setInstance(0); -} - -} - -#elif defined(LLVM_ON_UNIX) -#include "Unix/ThreadLocal.inc" -#elif defined( LLVM_ON_WIN32) -#include "Win32/ThreadLocal.inc" -#else -#warning Neither LLVM_ON_UNIX nor LLVM_ON_WIN32 was set in System/ThreadLocal.cpp -#endif -#endif - diff --git a/lib/System/Threading.cpp b/lib/System/Threading.cpp deleted file mode 100644 index 466c46802647..000000000000 --- a/lib/System/Threading.cpp +++ /dev/null @@ -1,64 +0,0 @@ -//===-- llvm/System/Threading.cpp- Control multithreading mode --*- C++ -*-==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements llvm_start_multithreaded() and friends. -// -//===----------------------------------------------------------------------===// - -#include "llvm/System/Threading.h" -#include "llvm/System/Atomic.h" -#include "llvm/System/Mutex.h" -#include "llvm/Config/config.h" -#include - -using namespace llvm; - -static bool multithreaded_mode = false; - -static sys::Mutex* global_lock = 0; - -bool llvm::llvm_start_multithreaded() { -#ifdef LLVM_MULTITHREADED - assert(!multithreaded_mode && "Already multithreaded!"); - multithreaded_mode = true; - global_lock = new sys::Mutex(true); - - // We fence here to ensure that all initialization is complete BEFORE we - // return from llvm_start_multithreaded(). - sys::MemoryFence(); - return true; -#else - return false; -#endif -} - -void llvm::llvm_stop_multithreaded() { -#ifdef LLVM_MULTITHREADED - assert(multithreaded_mode && "Not currently multithreaded!"); - - // We fence here to insure that all threaded operations are complete BEFORE we - // return from llvm_stop_multithreaded(). - sys::MemoryFence(); - - multithreaded_mode = false; - delete global_lock; -#endif -} - -bool llvm::llvm_is_multithreaded() { - return multithreaded_mode; -} - -void llvm::llvm_acquire_global_lock() { - if (multithreaded_mode) global_lock->acquire(); -} - -void llvm::llvm_release_global_lock() { - if (multithreaded_mode) global_lock->release(); -} diff --git a/lib/System/TimeValue.cpp b/lib/System/TimeValue.cpp deleted file mode 100644 index cf4984cc4d1b..000000000000 --- a/lib/System/TimeValue.cpp +++ /dev/null @@ -1,58 +0,0 @@ -//===-- TimeValue.cpp - Implement OS TimeValue Concept ----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the operating system TimeValue concept. -// -//===----------------------------------------------------------------------===// - -#include "llvm/System/TimeValue.h" -#include "llvm/Config/config.h" - -namespace llvm { -using namespace sys; - -const TimeValue TimeValue::MinTime = TimeValue ( INT64_MIN,0 ); -const TimeValue TimeValue::MaxTime = TimeValue ( INT64_MAX,0 ); -const TimeValue TimeValue::ZeroTime = TimeValue ( 0,0 ); -const TimeValue TimeValue::PosixZeroTime = TimeValue ( -946684800,0 ); -const TimeValue TimeValue::Win32ZeroTime = TimeValue ( -12591158400ULL,0 ); - -void -TimeValue::normalize( void ) { - if ( nanos_ >= NANOSECONDS_PER_SECOND ) { - do { - seconds_++; - nanos_ -= NANOSECONDS_PER_SECOND; - } while ( nanos_ >= NANOSECONDS_PER_SECOND ); - } else if (nanos_ <= -NANOSECONDS_PER_SECOND ) { - do { - seconds_--; - nanos_ += NANOSECONDS_PER_SECOND; - } while (nanos_ <= -NANOSECONDS_PER_SECOND); - } - - if (seconds_ >= 1 && nanos_ < 0) { - seconds_--; - nanos_ += NANOSECONDS_PER_SECOND; - } else if (seconds_ < 0 && nanos_ > 0) { - seconds_++; - nanos_ -= NANOSECONDS_PER_SECOND; - } -} - -} - -/// Include the platform specific portion of TimeValue class -#ifdef LLVM_ON_UNIX -#include "Unix/TimeValue.inc" -#endif -#ifdef LLVM_ON_WIN32 -#include "Win32/TimeValue.inc" -#endif - diff --git a/lib/System/Unix/Alarm.inc b/lib/System/Unix/Alarm.inc deleted file mode 100644 index fb42b6c65da1..000000000000 --- a/lib/System/Unix/Alarm.inc +++ /dev/null @@ -1,72 +0,0 @@ -//===-- Alarm.inc - Implement Unix Alarm Support ----------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the UNIX Alarm support. -// -//===----------------------------------------------------------------------===// - -#include -#include -#include -using namespace llvm; - -/// AlarmCancelled - This flag is set by the SIGINT signal handler if the -/// user presses CTRL-C. -static volatile bool AlarmCancelled = false; - -/// AlarmTriggered - This flag is set by the SIGALRM signal handler if the -/// alarm was triggered. -static volatile bool AlarmTriggered = false; - -/// NestedSOI - Sanity check. Alarms cannot be nested or run in parallel. -/// This ensures that they never do. -static bool NestedSOI = false; - -static RETSIGTYPE SigIntHandler(int Sig) { - AlarmCancelled = true; - signal(SIGINT, SigIntHandler); -} - -static RETSIGTYPE SigAlarmHandler(int Sig) { - AlarmTriggered = true; -} - -static void (*OldSigIntHandler) (int); - -void sys::SetupAlarm(unsigned seconds) { - assert(!NestedSOI && "sys::SetupAlarm calls cannot be nested!"); - NestedSOI = true; - AlarmCancelled = false; - AlarmTriggered = false; - ::signal(SIGALRM, SigAlarmHandler); - OldSigIntHandler = ::signal(SIGINT, SigIntHandler); - ::alarm(seconds); -} - -void sys::TerminateAlarm() { - assert(NestedSOI && "sys::TerminateAlarm called without sys::SetupAlarm!"); - ::alarm(0); - ::signal(SIGALRM, SIG_DFL); - ::signal(SIGINT, OldSigIntHandler); - AlarmCancelled = false; - AlarmTriggered = false; - NestedSOI = false; -} - -int sys::AlarmStatus() { - if (AlarmCancelled) - return -1; - if (AlarmTriggered) - return 1; - return 0; -} - -void sys::Sleep(unsigned n) { - ::sleep(n); -} diff --git a/lib/System/Unix/Host.inc b/lib/System/Unix/Host.inc deleted file mode 100644 index c76d6a4e18f1..000000000000 --- a/lib/System/Unix/Host.inc +++ /dev/null @@ -1,96 +0,0 @@ - //===- llvm/System/Unix/Host.inc -------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the UNIX Host support. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic UNIX code that -//=== is guaranteed to work on *all* UNIX variants. -//===----------------------------------------------------------------------===// - -#include "llvm/Config/config.h" -#include "llvm/ADT/StringRef.h" -#include "Unix.h" -#include -#include - -using namespace llvm; - -static std::string getOSVersion() { - struct utsname info; - - if (uname(&info)) - return ""; - - return info.release; -} - -std::string sys::getHostTriple() { - // FIXME: Derive directly instead of relying on the autoconf generated - // variable. - - StringRef HostTripleString(LLVM_HOSTTRIPLE); - std::pair ArchSplit = HostTripleString.split('-'); - - // Normalize the arch, since the host triple may not actually match the host. - std::string Arch = ArchSplit.first; - - // It would be nice to do this in terms of llvm::Triple, but that is in - // Support which is layered above us. -#if defined(__x86_64__) - Arch = "x86_64"; -#elif defined(__i386__) - Arch = "i386"; -#elif defined(__ppc64__) - Arch = "powerpc64"; -#elif defined(__ppc__) - Arch = "powerpc"; -#elif defined(__arm__) - - // FIXME: We need to pick the right ARM triple (which involves querying the - // chip). However, for now this is most important for LLVM arch selection, so - // we only need to make sure to distinguish ARM and Thumb. -# if defined(__thumb__) - Arch = "thumb"; -# else - Arch = "arm"; -# endif - -#else - - // FIXME: When enough auto-detection is in place, this should just - // #error. Then at least the arch selection is done, and we only need the OS - // etc selection to kill off the use of LLVM_HOSTTRIPLE. - -#endif - - std::string Triple(Arch); - Triple += '-'; - Triple += ArchSplit.second; - - // Force i86 to i386. - if (Triple[0] == 'i' && isdigit(Triple[1]) && - Triple[2] == '8' && Triple[3] == '6') - Triple[1] = '3'; - - // On darwin, we want to update the version to match that of the - // host. - std::string::size_type DarwinDashIdx = Triple.find("-darwin"); - if (DarwinDashIdx != std::string::npos) { - Triple.resize(DarwinDashIdx + strlen("-darwin")); - - // Only add the major part of the os version. - std::string Version = getOSVersion(); - Triple += Version.substr(0, Version.find('.')); - } - - return Triple; -} diff --git a/lib/System/Unix/Memory.inc b/lib/System/Unix/Memory.inc deleted file mode 100644 index 1b038f9c6e0b..000000000000 --- a/lib/System/Unix/Memory.inc +++ /dev/null @@ -1,151 +0,0 @@ -//===- Unix/Memory.cpp - Generic UNIX System Configuration ------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines some functions for various memory management utilities. -// -//===----------------------------------------------------------------------===// - -#include "Unix.h" -#include "llvm/System/DataTypes.h" -#include "llvm/System/Process.h" - -#ifdef HAVE_SYS_MMAN_H -#include -#endif - -#ifdef __APPLE__ -#include -#endif - -/// AllocateRWX - Allocate a slab of memory with read/write/execute -/// permissions. This is typically used for JIT applications where we want -/// to emit code to the memory then jump to it. Getting this type of memory -/// is very OS specific. -/// -llvm::sys::MemoryBlock -llvm::sys::Memory::AllocateRWX(size_t NumBytes, const MemoryBlock* NearBlock, - std::string *ErrMsg) { - if (NumBytes == 0) return MemoryBlock(); - - size_t pageSize = Process::GetPageSize(); - size_t NumPages = (NumBytes+pageSize-1)/pageSize; - - int fd = -1; -#ifdef NEED_DEV_ZERO_FOR_MMAP - static int zero_fd = open("/dev/zero", O_RDWR); - if (zero_fd == -1) { - MakeErrMsg(ErrMsg, "Can't open /dev/zero device"); - return MemoryBlock(); - } - fd = zero_fd; -#endif - - int flags = MAP_PRIVATE | -#ifdef HAVE_MMAP_ANONYMOUS - MAP_ANONYMOUS -#else - MAP_ANON -#endif - ; - - void* start = NearBlock ? (unsigned char*)NearBlock->base() + - NearBlock->size() : 0; - -#if defined(__APPLE__) && defined(__arm__) - void *pa = ::mmap(start, pageSize*NumPages, PROT_READ|PROT_EXEC, - flags, fd, 0); -#else - void *pa = ::mmap(start, pageSize*NumPages, PROT_READ|PROT_WRITE|PROT_EXEC, - flags, fd, 0); -#endif - if (pa == MAP_FAILED) { - if (NearBlock) //Try again without a near hint - return AllocateRWX(NumBytes, 0); - - MakeErrMsg(ErrMsg, "Can't allocate RWX Memory"); - return MemoryBlock(); - } - -#if defined(__APPLE__) && defined(__arm__) - kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)pa, - (vm_size_t)(pageSize*NumPages), 0, - VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); - if (KERN_SUCCESS != kr) { - MakeErrMsg(ErrMsg, "vm_protect max RX failed"); - return sys::MemoryBlock(); - } - - kr = vm_protect(mach_task_self(), (vm_address_t)pa, - (vm_size_t)(pageSize*NumPages), 0, - VM_PROT_READ | VM_PROT_WRITE); - if (KERN_SUCCESS != kr) { - MakeErrMsg(ErrMsg, "vm_protect RW failed"); - return sys::MemoryBlock(); - } -#endif - - MemoryBlock result; - result.Address = pa; - result.Size = NumPages*pageSize; - - return result; -} - -bool llvm::sys::Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { - if (M.Address == 0 || M.Size == 0) return false; - if (0 != ::munmap(M.Address, M.Size)) - return MakeErrMsg(ErrMsg, "Can't release RWX Memory"); - return false; -} - -bool llvm::sys::Memory::setWritable (MemoryBlock &M, std::string *ErrMsg) { -#if defined(__APPLE__) && defined(__arm__) - if (M.Address == 0 || M.Size == 0) return false; - sys::Memory::InvalidateInstructionCache(M.Address, M.Size); - kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address, - (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_WRITE); - return KERN_SUCCESS == kr; -#else - return true; -#endif -} - -bool llvm::sys::Memory::setExecutable (MemoryBlock &M, std::string *ErrMsg) { -#if defined(__APPLE__) && defined(__arm__) - if (M.Address == 0 || M.Size == 0) return false; - sys::Memory::InvalidateInstructionCache(M.Address, M.Size); - kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address, - (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); - return KERN_SUCCESS == kr; -#else - return false; -#endif -} - -bool llvm::sys::Memory::setRangeWritable(const void *Addr, size_t Size) { -#if defined(__APPLE__) && defined(__arm__) - kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)Addr, - (vm_size_t)Size, 0, - VM_PROT_READ | VM_PROT_WRITE); - return KERN_SUCCESS == kr; -#else - return true; -#endif -} - -bool llvm::sys::Memory::setRangeExecutable(const void *Addr, size_t Size) { -#if defined(__APPLE__) && defined(__arm__) - kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)Addr, - (vm_size_t)Size, 0, - VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); - return KERN_SUCCESS == kr; -#else - return true; -#endif -} diff --git a/lib/System/Unix/Mutex.inc b/lib/System/Unix/Mutex.inc deleted file mode 100644 index 4a5e28de27b0..000000000000 --- a/lib/System/Unix/Mutex.inc +++ /dev/null @@ -1,43 +0,0 @@ -//===- llvm/System/Unix/Mutex.inc - Unix Mutex Implementation ---*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Unix specific (non-pthread) Mutex class. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic UNIX code that -//=== is guaranteed to work on *all* UNIX variants. -//===----------------------------------------------------------------------===// - -namespace llvm -{ -using namespace sys; - -MutexImpl::MutexImpl( bool recursive) -{ -} - -MutexImpl::~MutexImpl() -{ -} - -bool -MutexImpl::release() -{ - return true; -} - -bool -MutexImpl::tryacquire( void ) -{ - return true; -} - -} diff --git a/lib/System/Unix/Path.inc b/lib/System/Unix/Path.inc deleted file mode 100644 index 47e4d1ac3c6b..000000000000 --- a/lib/System/Unix/Path.inc +++ /dev/null @@ -1,923 +0,0 @@ -//===- llvm/System/Unix/Path.cpp - Unix Path Implementation -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Unix specific portion of the Path class. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic UNIX code that -//=== is guaranteed to work on *all* UNIX variants. -//===----------------------------------------------------------------------===// - -#include "Unix.h" -#if HAVE_SYS_STAT_H -#include -#endif -#if HAVE_FCNTL_H -#include -#endif -#ifdef HAVE_SYS_MMAN_H -#include -#endif -#ifdef HAVE_SYS_STAT_H -#include -#endif -#if HAVE_UTIME_H -#include -#endif -#if HAVE_TIME_H -#include -#endif -#if HAVE_DIRENT_H -# include -# define NAMLEN(dirent) strlen((dirent)->d_name) -#else -# define dirent direct -# define NAMLEN(dirent) (dirent)->d_namlen -# if HAVE_SYS_NDIR_H -# include -# endif -# if HAVE_SYS_DIR_H -# include -# endif -# if HAVE_NDIR_H -# include -# endif -#endif - -#if HAVE_DLFCN_H -#include -#endif - -#ifdef __APPLE__ -#include -#endif - -// Put in a hack for Cygwin which falsely reports that the mkdtemp function -// is available when it is not. -#ifdef __CYGWIN__ -# undef HAVE_MKDTEMP -#endif - -namespace { -inline bool lastIsSlash(const std::string& path) { - return !path.empty() && path[path.length() - 1] == '/'; -} - -} - -namespace llvm { -using namespace sys; - -const char sys::PathSeparator = ':'; - -Path::Path(StringRef p) - : path(p) {} - -Path::Path(const char *StrStart, unsigned StrLen) - : path(StrStart, StrLen) {} - -Path& -Path::operator=(StringRef that) { - path.assign(that.data(), that.size()); - return *this; -} - -bool -Path::isValid() const { - // Check some obvious things - if (path.empty()) - return false; - return path.length() < MAXPATHLEN; -} - -bool -Path::isAbsolute(const char *NameStart, unsigned NameLen) { - assert(NameStart); - if (NameLen == 0) - return false; - return NameStart[0] == '/'; -} - -bool -Path::isAbsolute() const { - if (path.empty()) - return false; - return path[0] == '/'; -} - -void Path::makeAbsolute() { - if (isAbsolute()) - return; - - Path CWD = Path::GetCurrentDirectory(); - assert(CWD.isAbsolute() && "GetCurrentDirectory returned relative path!"); - - CWD.appendComponent(path); - - path = CWD.str(); -} - -Path -Path::GetRootDirectory() { - Path result; - result.set("/"); - return result; -} - -Path -Path::GetTemporaryDirectory(std::string *ErrMsg) { -#if defined(HAVE_MKDTEMP) - // The best way is with mkdtemp but that's not available on many systems, - // Linux and FreeBSD have it. Others probably won't. - char pathname[MAXPATHLEN]; - strcpy(pathname,"/tmp/llvm_XXXXXX"); - if (0 == mkdtemp(pathname)) { - MakeErrMsg(ErrMsg, - std::string(pathname) + ": can't create temporary directory"); - return Path(); - } - Path result; - result.set(pathname); - assert(result.isValid() && "mkdtemp didn't create a valid pathname!"); - return result; -#elif defined(HAVE_MKSTEMP) - // If no mkdtemp is available, mkstemp can be used to create a temporary file - // which is then removed and created as a directory. We prefer this over - // mktemp because of mktemp's inherent security and threading risks. We still - // have a slight race condition from the time the temporary file is created to - // the time it is re-created as a directoy. - char pathname[MAXPATHLEN]; - strcpy(pathname, "/tmp/llvm_XXXXXX"); - int fd = 0; - if (-1 == (fd = mkstemp(pathname))) { - MakeErrMsg(ErrMsg, - std::string(pathname) + ": can't create temporary directory"); - return Path(); - } - ::close(fd); - ::unlink(pathname); // start race condition, ignore errors - if (-1 == ::mkdir(pathname, S_IRWXU)) { // end race condition - MakeErrMsg(ErrMsg, - std::string(pathname) + ": can't create temporary directory"); - return Path(); - } - Path result; - result.set(pathname); - assert(result.isValid() && "mkstemp didn't create a valid pathname!"); - return result; -#elif defined(HAVE_MKTEMP) - // If a system doesn't have mkdtemp(3) or mkstemp(3) but it does have - // mktemp(3) then we'll assume that system (e.g. AIX) has a reasonable - // implementation of mktemp(3) and doesn't follow BSD 4.3's lead of replacing - // the XXXXXX with the pid of the process and a letter. That leads to only - // twenty six temporary files that can be generated. - char pathname[MAXPATHLEN]; - strcpy(pathname, "/tmp/llvm_XXXXXX"); - char *TmpName = ::mktemp(pathname); - if (TmpName == 0) { - MakeErrMsg(ErrMsg, - std::string(TmpName) + ": can't create unique directory name"); - return Path(); - } - if (-1 == ::mkdir(TmpName, S_IRWXU)) { - MakeErrMsg(ErrMsg, - std::string(TmpName) + ": can't create temporary directory"); - return Path(); - } - Path result; - result.set(TmpName); - assert(result.isValid() && "mktemp didn't create a valid pathname!"); - return result; -#else - // This is the worst case implementation. tempnam(3) leaks memory unless its - // on an SVID2 (or later) system. On BSD 4.3 it leaks. tmpnam(3) has thread - // issues. The mktemp(3) function doesn't have enough variability in the - // temporary name generated. So, we provide our own implementation that - // increments an integer from a random number seeded by the current time. This - // should be sufficiently unique that we don't have many collisions between - // processes. Generally LLVM processes don't run very long and don't use very - // many temporary files so this shouldn't be a big issue for LLVM. - static time_t num = ::time(0); - char pathname[MAXPATHLEN]; - do { - num++; - sprintf(pathname, "/tmp/llvm_%010u", unsigned(num)); - } while ( 0 == access(pathname, F_OK ) ); - if (-1 == ::mkdir(pathname, S_IRWXU)) { - MakeErrMsg(ErrMsg, - std::string(pathname) + ": can't create temporary directory"); - return Path(); - } - Path result; - result.set(pathname); - assert(result.isValid() && "mkstemp didn't create a valid pathname!"); - return result; -#endif -} - -void -Path::GetSystemLibraryPaths(std::vector& Paths) { -#ifdef LTDL_SHLIBPATH_VAR - char* env_var = getenv(LTDL_SHLIBPATH_VAR); - if (env_var != 0) { - getPathList(env_var,Paths); - } -#endif - // FIXME: Should this look at LD_LIBRARY_PATH too? - Paths.push_back(sys::Path("/usr/local/lib/")); - Paths.push_back(sys::Path("/usr/X11R6/lib/")); - Paths.push_back(sys::Path("/usr/lib/")); - Paths.push_back(sys::Path("/lib/")); -} - -void -Path::GetBitcodeLibraryPaths(std::vector& Paths) { - char * env_var = getenv("LLVM_LIB_SEARCH_PATH"); - if (env_var != 0) { - getPathList(env_var,Paths); - } -#ifdef LLVM_LIBDIR - { - Path tmpPath; - if (tmpPath.set(LLVM_LIBDIR)) - if (tmpPath.canRead()) - Paths.push_back(tmpPath); - } -#endif - GetSystemLibraryPaths(Paths); -} - -Path -Path::GetLLVMDefaultConfigDir() { - return Path("/etc/llvm/"); -} - -Path -Path::GetUserHomeDirectory() { - const char* home = getenv("HOME"); - if (home) { - Path result; - if (result.set(home)) - return result; - } - return GetRootDirectory(); -} - -Path -Path::GetCurrentDirectory() { - char pathname[MAXPATHLEN]; - if (!getcwd(pathname,MAXPATHLEN)) { - assert (false && "Could not query current working directory."); - return Path(); - } - - return Path(pathname); -} - -#if defined(__FreeBSD__) || defined (__NetBSD__) || defined(__minix) -static int -test_dir(char buf[PATH_MAX], char ret[PATH_MAX], - const char *dir, const char *bin) -{ - struct stat sb; - - snprintf(buf, PATH_MAX, "%s/%s", dir, bin); - if (realpath(buf, ret) == NULL) - return (1); - if (stat(buf, &sb) != 0) - return (1); - - return (0); -} - -static char * -getprogpath(char ret[PATH_MAX], const char *bin) -{ - char *pv, *s, *t, buf[PATH_MAX]; - - /* First approach: absolute path. */ - if (bin[0] == '/') { - if (test_dir(buf, ret, "/", bin) == 0) - return (ret); - return (NULL); - } - - /* Second approach: relative path. */ - if (strchr(bin, '/') != NULL) { - if (getcwd(buf, PATH_MAX) == NULL) - return (NULL); - if (test_dir(buf, ret, buf, bin) == 0) - return (ret); - return (NULL); - } - - /* Third approach: $PATH */ - if ((pv = getenv("PATH")) == NULL) - return (NULL); - s = pv = strdup(pv); - if (pv == NULL) - return (NULL); - while ((t = strsep(&s, ":")) != NULL) { - if (test_dir(buf, ret, t, bin) == 0) { - free(pv); - return (ret); - } - } - free(pv); - return (NULL); -} -#endif // __FreeBSD__ || __NetBSD__ - -/// GetMainExecutable - Return the path to the main executable, given the -/// value of argv[0] from program startup. -Path Path::GetMainExecutable(const char *argv0, void *MainAddr) { -#if defined(__APPLE__) - // On OS X the executable path is saved to the stack by dyld. Reading it - // from there is much faster than calling dladdr, especially for large - // binaries with symbols. - char exe_path[MAXPATHLEN]; - uint32_t size = sizeof(exe_path); - if (_NSGetExecutablePath(exe_path, &size) == 0) { - char link_path[MAXPATHLEN]; - if (realpath(exe_path, link_path)) - return Path(std::string(link_path)); - } -#elif defined(__FreeBSD__) || defined (__NetBSD__) || defined(__minix) - char exe_path[PATH_MAX]; - - if (getprogpath(exe_path, argv0) != NULL) - return Path(std::string(exe_path)); -#elif defined(__linux__) || defined(__CYGWIN__) - char exe_path[MAXPATHLEN]; - ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path)); - if (len >= 0) - return Path(std::string(exe_path, len)); -#elif defined(HAVE_DLFCN_H) - // Use dladdr to get executable path if available. - Dl_info DLInfo; - int err = dladdr(MainAddr, &DLInfo); - if (err == 0) - return Path(); - - // If the filename is a symlink, we need to resolve and return the location of - // the actual executable. - char link_path[MAXPATHLEN]; - if (realpath(DLInfo.dli_fname, link_path)) - return Path(std::string(link_path)); -#endif - return Path(); -} - - -StringRef Path::getDirname() const { - return getDirnameCharSep(path, "/"); -} - -StringRef -Path::getBasename() const { - // Find the last slash - std::string::size_type slash = path.rfind('/'); - if (slash == std::string::npos) - slash = 0; - else - slash++; - - std::string::size_type dot = path.rfind('.'); - if (dot == std::string::npos || dot < slash) - return StringRef(path).substr(slash); - else - return StringRef(path).substr(slash, dot - slash); -} - -StringRef -Path::getSuffix() const { - // Find the last slash - std::string::size_type slash = path.rfind('/'); - if (slash == std::string::npos) - slash = 0; - else - slash++; - - std::string::size_type dot = path.rfind('.'); - if (dot == std::string::npos || dot < slash) - return StringRef(); - else - return StringRef(path).substr(dot + 1); -} - -bool Path::getMagicNumber(std::string &Magic, unsigned len) const { - assert(len < 1024 && "Request for magic string too long"); - char Buf[1025]; - int fd = ::open(path.c_str(), O_RDONLY); - if (fd < 0) - return false; - ssize_t bytes_read = ::read(fd, Buf, len); - ::close(fd); - if (ssize_t(len) != bytes_read) - return false; - Magic.assign(Buf, len); - return true; -} - -bool -Path::exists() const { - return 0 == access(path.c_str(), F_OK ); -} - -bool -Path::isDirectory() const { - struct stat buf; - if (0 != stat(path.c_str(), &buf)) - return false; - return buf.st_mode & S_IFDIR ? true : false; -} - -bool -Path::canRead() const { - return 0 == access(path.c_str(), R_OK); -} - -bool -Path::canWrite() const { - return 0 == access(path.c_str(), W_OK); -} - -bool -Path::isRegularFile() const { - // Get the status so we can determine if it's a file or directory - struct stat buf; - - if (0 != stat(path.c_str(), &buf)) - return false; - - if (S_ISREG(buf.st_mode)) - return true; - - return false; -} - -bool -Path::canExecute() const { - if (0 != access(path.c_str(), R_OK | X_OK )) - return false; - struct stat buf; - if (0 != stat(path.c_str(), &buf)) - return false; - if (!S_ISREG(buf.st_mode)) - return false; - return true; -} - -StringRef -Path::getLast() const { - // Find the last slash - size_t pos = path.rfind('/'); - - // Handle the corner cases - if (pos == std::string::npos) - return path; - - // If the last character is a slash - if (pos == path.length()-1) { - // Find the second to last slash - size_t pos2 = path.rfind('/', pos-1); - if (pos2 == std::string::npos) - return StringRef(path).substr(0,pos); - else - return StringRef(path).substr(pos2+1,pos-pos2-1); - } - // Return everything after the last slash - return StringRef(path).substr(pos+1); -} - -const FileStatus * -PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const { - if (!fsIsValid || update) { - struct stat buf; - if (0 != stat(path.c_str(), &buf)) { - MakeErrMsg(ErrStr, path + ": can't get status of file"); - return 0; - } - status.fileSize = buf.st_size; - status.modTime.fromEpochTime(buf.st_mtime); - status.mode = buf.st_mode; - status.user = buf.st_uid; - status.group = buf.st_gid; - status.uniqueID = uint64_t(buf.st_ino); - status.isDir = S_ISDIR(buf.st_mode); - status.isFile = S_ISREG(buf.st_mode); - fsIsValid = true; - } - return &status; -} - -static bool AddPermissionBits(const Path &File, int bits) { - // Get the umask value from the operating system. We want to use it - // when changing the file's permissions. Since calling umask() sets - // the umask and returns its old value, we must call it a second - // time to reset it to the user's preference. - int mask = umask(0777); // The arg. to umask is arbitrary. - umask(mask); // Restore the umask. - - // Get the file's current mode. - struct stat buf; - if (0 != stat(File.c_str(), &buf)) - return false; - // Change the file to have whichever permissions bits from 'bits' - // that the umask would not disable. - if ((chmod(File.c_str(), (buf.st_mode | (bits & ~mask)))) == -1) - return false; - return true; -} - -bool Path::makeReadableOnDisk(std::string* ErrMsg) { - if (!AddPermissionBits(*this, 0444)) - return MakeErrMsg(ErrMsg, path + ": can't make file readable"); - return false; -} - -bool Path::makeWriteableOnDisk(std::string* ErrMsg) { - if (!AddPermissionBits(*this, 0222)) - return MakeErrMsg(ErrMsg, path + ": can't make file writable"); - return false; -} - -bool Path::makeExecutableOnDisk(std::string* ErrMsg) { - if (!AddPermissionBits(*this, 0111)) - return MakeErrMsg(ErrMsg, path + ": can't make file executable"); - return false; -} - -bool -Path::getDirectoryContents(std::set& result, std::string* ErrMsg) const { - DIR* direntries = ::opendir(path.c_str()); - if (direntries == 0) - return MakeErrMsg(ErrMsg, path + ": can't open directory"); - - std::string dirPath = path; - if (!lastIsSlash(dirPath)) - dirPath += '/'; - - result.clear(); - struct dirent* de = ::readdir(direntries); - for ( ; de != 0; de = ::readdir(direntries)) { - if (de->d_name[0] != '.') { - Path aPath(dirPath + (const char*)de->d_name); - struct stat st; - if (0 != lstat(aPath.path.c_str(), &st)) { - if (S_ISLNK(st.st_mode)) - continue; // dangling symlink -- ignore - return MakeErrMsg(ErrMsg, - aPath.path + ": can't determine file object type"); - } - result.insert(aPath); - } - } - - closedir(direntries); - return false; -} - -bool -Path::set(StringRef a_path) { - if (a_path.empty()) - return false; - std::string save(path); - path = a_path; - if (!isValid()) { - path = save; - return false; - } - return true; -} - -bool -Path::appendComponent(StringRef name) { - if (name.empty()) - return false; - std::string save(path); - if (!lastIsSlash(path)) - path += '/'; - path += name; - if (!isValid()) { - path = save; - return false; - } - return true; -} - -bool -Path::eraseComponent() { - size_t slashpos = path.rfind('/',path.size()); - if (slashpos == 0 || slashpos == std::string::npos) { - path.erase(); - return true; - } - if (slashpos == path.size() - 1) - slashpos = path.rfind('/',slashpos-1); - if (slashpos == std::string::npos) { - path.erase(); - return true; - } - path.erase(slashpos); - return true; -} - -bool -Path::appendSuffix(StringRef suffix) { - std::string save(path); - path.append("."); - path.append(suffix); - if (!isValid()) { - path = save; - return false; - } - return true; -} - -bool -Path::eraseSuffix() { - std::string save = path; - size_t dotpos = path.rfind('.',path.size()); - size_t slashpos = path.rfind('/',path.size()); - if (dotpos != std::string::npos) { - if (slashpos == std::string::npos || dotpos > slashpos+1) { - path.erase(dotpos, path.size()-dotpos); - return true; - } - } - if (!isValid()) - path = save; - return false; -} - -static bool createDirectoryHelper(char* beg, char* end, bool create_parents) { - - if (access(beg, R_OK | W_OK) == 0) - return false; - - if (create_parents) { - - char* c = end; - - for (; c != beg; --c) - if (*c == '/') { - - // Recurse to handling the parent directory. - *c = '\0'; - bool x = createDirectoryHelper(beg, c, create_parents); - *c = '/'; - - // Return if we encountered an error. - if (x) - return true; - - break; - } - } - - return mkdir(beg, S_IRWXU | S_IRWXG) != 0; -} - -bool -Path::createDirectoryOnDisk( bool create_parents, std::string* ErrMsg ) { - // Get a writeable copy of the path name - char pathname[MAXPATHLEN]; - path.copy(pathname,MAXPATHLEN); - - // Null-terminate the last component - size_t lastchar = path.length() - 1 ; - - if (pathname[lastchar] != '/') - ++lastchar; - - pathname[lastchar] = 0; - - if (createDirectoryHelper(pathname, pathname+lastchar, create_parents)) - return MakeErrMsg(ErrMsg, - std::string(pathname) + ": can't create directory"); - - return false; -} - -bool -Path::createFileOnDisk(std::string* ErrMsg) { - // Create the file - int fd = ::creat(path.c_str(), S_IRUSR | S_IWUSR); - if (fd < 0) - return MakeErrMsg(ErrMsg, path + ": can't create file"); - ::close(fd); - return false; -} - -bool -Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) { - // Make this into a unique file name - if (makeUnique( reuse_current, ErrMsg )) - return true; - - // create the file - int fd = ::open(path.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0666); - if (fd < 0) - return MakeErrMsg(ErrMsg, path + ": can't create temporary file"); - ::close(fd); - return false; -} - -bool -Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const { - // Get the status so we can determine if it's a file or directory. - struct stat buf; - if (0 != stat(path.c_str(), &buf)) { - MakeErrMsg(ErrStr, path + ": can't get status of file"); - return true; - } - - // Note: this check catches strange situations. In all cases, LLVM should - // only be involved in the creation and deletion of regular files. This - // check ensures that what we're trying to erase is a regular file. It - // effectively prevents LLVM from erasing things like /dev/null, any block - // special file, or other things that aren't "regular" files. - if (S_ISREG(buf.st_mode)) { - if (unlink(path.c_str()) != 0) - return MakeErrMsg(ErrStr, path + ": can't destroy file"); - return false; - } - - if (!S_ISDIR(buf.st_mode)) { - if (ErrStr) *ErrStr = "not a file or directory"; - return true; - } - - if (remove_contents) { - // Recursively descend the directory to remove its contents. - std::string cmd = "/bin/rm -rf " + path; - if (system(cmd.c_str()) != 0) { - MakeErrMsg(ErrStr, path + ": failed to recursively remove directory."); - return true; - } - return false; - } - - // Otherwise, try to just remove the one directory. - char pathname[MAXPATHLEN]; - path.copy(pathname, MAXPATHLEN); - size_t lastchar = path.length() - 1; - if (pathname[lastchar] == '/') - pathname[lastchar] = 0; - else - pathname[lastchar+1] = 0; - - if (rmdir(pathname) != 0) - return MakeErrMsg(ErrStr, - std::string(pathname) + ": can't erase directory"); - return false; -} - -bool -Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) { - if (0 != ::rename(path.c_str(), newName.c_str())) - return MakeErrMsg(ErrMsg, std::string("can't rename '") + path + "' as '" + - newName.str() + "'"); - return false; -} - -bool -Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrStr) const { - struct utimbuf utb; - utb.actime = si.modTime.toPosixTime(); - utb.modtime = utb.actime; - if (0 != ::utime(path.c_str(),&utb)) - return MakeErrMsg(ErrStr, path + ": can't set file modification time"); - if (0 != ::chmod(path.c_str(),si.mode)) - return MakeErrMsg(ErrStr, path + ": can't set mode"); - return false; -} - -bool -sys::CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg){ - int inFile = -1; - int outFile = -1; - inFile = ::open(Src.c_str(), O_RDONLY); - if (inFile == -1) - return MakeErrMsg(ErrMsg, Src.str() + - ": can't open source file to copy"); - - outFile = ::open(Dest.c_str(), O_WRONLY|O_CREAT, 0666); - if (outFile == -1) { - ::close(inFile); - return MakeErrMsg(ErrMsg, Dest.str() + - ": can't create destination file for copy"); - } - - char Buffer[16*1024]; - while (ssize_t Amt = ::read(inFile, Buffer, 16*1024)) { - if (Amt == -1) { - if (errno != EINTR && errno != EAGAIN) { - ::close(inFile); - ::close(outFile); - return MakeErrMsg(ErrMsg, Src.str()+": can't read source file"); - } - } else { - char *BufPtr = Buffer; - while (Amt) { - ssize_t AmtWritten = ::write(outFile, BufPtr, Amt); - if (AmtWritten == -1) { - if (errno != EINTR && errno != EAGAIN) { - ::close(inFile); - ::close(outFile); - return MakeErrMsg(ErrMsg, Dest.str() + - ": can't write destination file"); - } - } else { - Amt -= AmtWritten; - BufPtr += AmtWritten; - } - } - } - } - ::close(inFile); - ::close(outFile); - return false; -} - -bool -Path::makeUnique(bool reuse_current, std::string* ErrMsg) { - if (reuse_current && !exists()) - return false; // File doesn't exist already, just use it! - - // Append an XXXXXX pattern to the end of the file for use with mkstemp, - // mktemp or our own implementation. - // This uses std::vector instead of SmallVector to avoid a dependence on - // libSupport. And performance isn't critical here. - std::vector Buf; - Buf.resize(path.size()+8); - char *FNBuffer = &Buf[0]; - path.copy(FNBuffer,path.size()); - if (isDirectory()) - strcpy(FNBuffer+path.size(), "/XXXXXX"); - else - strcpy(FNBuffer+path.size(), "-XXXXXX"); - -#if defined(HAVE_MKSTEMP) - int TempFD; - if ((TempFD = mkstemp(FNBuffer)) == -1) - return MakeErrMsg(ErrMsg, path + ": can't make unique filename"); - - // We don't need to hold the temp file descriptor... we will trust that no one - // will overwrite/delete the file before we can open it again. - close(TempFD); - - // Save the name - path = FNBuffer; -#elif defined(HAVE_MKTEMP) - // If we don't have mkstemp, use the old and obsolete mktemp function. - if (mktemp(FNBuffer) == 0) - return MakeErrMsg(ErrMsg, path + ": can't make unique filename"); - - // Save the name - path = FNBuffer; -#else - // Okay, looks like we have to do it all by our lonesome. - static unsigned FCounter = 0; - // Try to initialize with unique value. - if (FCounter == 0) FCounter = ((unsigned)getpid() & 0xFFFF) << 8; - char* pos = strstr(FNBuffer, "XXXXXX"); - do { - if (++FCounter > 0xFFFFFF) { - return MakeErrMsg(ErrMsg, - path + ": can't make unique filename: too many files"); - } - sprintf(pos, "%06X", FCounter); - path = FNBuffer; - } while (exists()); - // POSSIBLE SECURITY BUG: An attacker can easily guess the name and exploit - // LLVM. -#endif - return false; -} - -const char *Path::MapInFilePages(int FD, uint64_t FileSize) { - int Flags = MAP_PRIVATE; -#ifdef MAP_FILE - Flags |= MAP_FILE; -#endif - void *BasePtr = ::mmap(0, FileSize, PROT_READ, Flags, FD, 0); - if (BasePtr == MAP_FAILED) - return 0; - return (const char*)BasePtr; -} - -void Path::UnMapFilePages(const char *BasePtr, uint64_t FileSize) { - ::munmap((void*)BasePtr, FileSize); -} - -} // end llvm namespace diff --git a/lib/System/Unix/Process.inc b/lib/System/Unix/Process.inc deleted file mode 100644 index cf6a47a31c80..000000000000 --- a/lib/System/Unix/Process.inc +++ /dev/null @@ -1,295 +0,0 @@ -//===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file provides the generic Unix implementation of the Process class. -// -//===----------------------------------------------------------------------===// - -#include "Unix.h" -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_SYS_RESOURCE_H -#include -#endif -// DragonFly BSD has deprecated for instead, -// Unix.h includes this for us already. -#if defined(HAVE_MALLOC_H) && !defined(__DragonFly__) -#include -#endif -#ifdef HAVE_MALLOC_MALLOC_H -#include -#endif -#ifdef HAVE_SYS_IOCTL_H -# include -#endif -#ifdef HAVE_TERMIOS_H -# include -#endif - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic UNIX code that -//=== is guaranteed to work on *all* UNIX variants. -//===----------------------------------------------------------------------===// - -using namespace llvm; -using namespace sys; - -unsigned -Process::GetPageSize() -{ -#if defined(__CYGWIN__) - // On Cygwin, getpagesize() returns 64k but the page size for the purposes of - // memory protection and mmap() is 4k. - // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492 - const int page_size = 0x1000; -#elif defined(HAVE_GETPAGESIZE) - const int page_size = ::getpagesize(); -#elif defined(HAVE_SYSCONF) - long page_size = ::sysconf(_SC_PAGE_SIZE); -#else -#warning Cannot get the page size on this machine -#endif - return static_cast(page_size); -} - -size_t Process::GetMallocUsage() { -#if defined(HAVE_MALLINFO) - struct mallinfo mi; - mi = ::mallinfo(); - return mi.uordblks; -#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) - malloc_statistics_t Stats; - malloc_zone_statistics(malloc_default_zone(), &Stats); - return Stats.size_in_use; // darwin -#elif defined(HAVE_SBRK) - // Note this is only an approximation and more closely resembles - // the value returned by mallinfo in the arena field. - static char *StartOfMemory = reinterpret_cast(::sbrk(0)); - char *EndOfMemory = (char*)sbrk(0); - if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1)) - return EndOfMemory - StartOfMemory; - else - return 0; -#else -#warning Cannot get malloc info on this platform - return 0; -#endif -} - -size_t -Process::GetTotalMemoryUsage() -{ -#if defined(HAVE_MALLINFO) - struct mallinfo mi = ::mallinfo(); - return mi.uordblks + mi.hblkhd; -#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) - malloc_statistics_t Stats; - malloc_zone_statistics(malloc_default_zone(), &Stats); - return Stats.size_allocated; // darwin -#elif defined(HAVE_GETRUSAGE) && !defined(__HAIKU__) - struct rusage usage; - ::getrusage(RUSAGE_SELF, &usage); - return usage.ru_maxrss; -#else -#warning Cannot get total memory size on this platform - return 0; -#endif -} - -void -Process::GetTimeUsage(TimeValue& elapsed, TimeValue& user_time, - TimeValue& sys_time) -{ - elapsed = TimeValue::now(); -#if defined(HAVE_GETRUSAGE) - struct rusage usage; - ::getrusage(RUSAGE_SELF, &usage); - user_time = TimeValue( - static_cast( usage.ru_utime.tv_sec ), - static_cast( usage.ru_utime.tv_usec * - TimeValue::NANOSECONDS_PER_MICROSECOND ) ); - sys_time = TimeValue( - static_cast( usage.ru_stime.tv_sec ), - static_cast( usage.ru_stime.tv_usec * - TimeValue::NANOSECONDS_PER_MICROSECOND ) ); -#else -#warning Cannot get usage times on this platform - user_time.seconds(0); - user_time.microseconds(0); - sys_time.seconds(0); - sys_time.microseconds(0); -#endif -} - -int Process::GetCurrentUserId() { - return getuid(); -} - -int Process::GetCurrentGroupId() { - return getgid(); -} - -#ifdef HAVE_MACH_MACH_H -#include -#endif - -// Some LLVM programs such as bugpoint produce core files as a normal part of -// their operation. To prevent the disk from filling up, this function -// does what's necessary to prevent their generation. -void Process::PreventCoreFiles() { -#if HAVE_SETRLIMIT - struct rlimit rlim; - rlim.rlim_cur = rlim.rlim_max = 0; - setrlimit(RLIMIT_CORE, &rlim); -#endif - -#ifdef HAVE_MACH_MACH_H - // Disable crash reporting on Mac OS X 10.0-10.4 - - // get information about the original set of exception ports for the task - mach_msg_type_number_t Count = 0; - exception_mask_t OriginalMasks[EXC_TYPES_COUNT]; - exception_port_t OriginalPorts[EXC_TYPES_COUNT]; - exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT]; - thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT]; - kern_return_t err = - task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks, - &Count, OriginalPorts, OriginalBehaviors, - OriginalFlavors); - if (err == KERN_SUCCESS) { - // replace each with MACH_PORT_NULL. - for (unsigned i = 0; i != Count; ++i) - task_set_exception_ports(mach_task_self(), OriginalMasks[i], - MACH_PORT_NULL, OriginalBehaviors[i], - OriginalFlavors[i]); - } - - // Disable crash reporting on Mac OS X 10.5 - signal(SIGABRT, _exit); - signal(SIGILL, _exit); - signal(SIGFPE, _exit); - signal(SIGSEGV, _exit); - signal(SIGBUS, _exit); -#endif -} - -bool Process::StandardInIsUserInput() { - return FileDescriptorIsDisplayed(STDIN_FILENO); -} - -bool Process::StandardOutIsDisplayed() { - return FileDescriptorIsDisplayed(STDOUT_FILENO); -} - -bool Process::StandardErrIsDisplayed() { - return FileDescriptorIsDisplayed(STDERR_FILENO); -} - -bool Process::FileDescriptorIsDisplayed(int fd) { -#if HAVE_ISATTY - return isatty(fd); -#else - // If we don't have isatty, just return false. - return false; -#endif -} - -static unsigned getColumns(int FileID) { - // If COLUMNS is defined in the environment, wrap to that many columns. - if (const char *ColumnsStr = std::getenv("COLUMNS")) { - int Columns = std::atoi(ColumnsStr); - if (Columns > 0) - return Columns; - } - - unsigned Columns = 0; - -#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H) - // Try to determine the width of the terminal. - struct winsize ws; - if (ioctl(FileID, TIOCGWINSZ, &ws) == 0) - Columns = ws.ws_col; -#endif - - return Columns; -} - -unsigned Process::StandardOutColumns() { - if (!StandardOutIsDisplayed()) - return 0; - - return getColumns(1); -} - -unsigned Process::StandardErrColumns() { - if (!StandardErrIsDisplayed()) - return 0; - - return getColumns(2); -} - -static bool terminalHasColors() { - if (const char *term = std::getenv("TERM")) { - // Most modern terminals support ANSI escape sequences for colors. - // We could check terminfo, or have a list of known terms that support - // colors, but that would be overkill. - // The user can always ask for no colors by setting TERM to dumb, or - // using a commandline flag. - return strcmp(term, "dumb") != 0; - } - return false; -} - -bool Process::StandardOutHasColors() { - if (!StandardOutIsDisplayed()) - return false; - return terminalHasColors(); -} - -bool Process::StandardErrHasColors() { - if (!StandardErrIsDisplayed()) - return false; - return terminalHasColors(); -} - -bool Process::ColorNeedsFlush() { - // No, we use ANSI escape sequences. - return false; -} - -#define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m" - -#define ALLCOLORS(FGBG,BOLD) {\ - COLOR(FGBG, "0", BOLD),\ - COLOR(FGBG, "1", BOLD),\ - COLOR(FGBG, "2", BOLD),\ - COLOR(FGBG, "3", BOLD),\ - COLOR(FGBG, "4", BOLD),\ - COLOR(FGBG, "5", BOLD),\ - COLOR(FGBG, "6", BOLD),\ - COLOR(FGBG, "7", BOLD)\ - } - -static const char colorcodes[2][2][8][10] = { - { ALLCOLORS("3",""), ALLCOLORS("3","1;") }, - { ALLCOLORS("4",""), ALLCOLORS("4","1;") } -}; - -const char *Process::OutputColor(char code, bool bold, bool bg) { - return colorcodes[bg?1:0][bold?1:0][code&7]; -} - -const char *Process::OutputBold(bool bg) { - return "\033[1m"; -} - -const char *Process::ResetColor() { - return "\033[0m"; -} diff --git a/lib/System/Unix/Program.inc b/lib/System/Unix/Program.inc deleted file mode 100644 index 0209f5aaf832..000000000000 --- a/lib/System/Unix/Program.inc +++ /dev/null @@ -1,402 +0,0 @@ -//===- llvm/System/Unix/Program.cpp -----------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Unix specific portion of the Program class. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic UNIX code that -//=== is guaranteed to work on *all* UNIX variants. -//===----------------------------------------------------------------------===// - -#include -#include "Unix.h" -#if HAVE_SYS_STAT_H -#include -#endif -#if HAVE_SYS_RESOURCE_H -#include -#endif -#if HAVE_SIGNAL_H -#include -#endif -#if HAVE_FCNTL_H -#include -#endif -#ifdef HAVE_POSIX_SPAWN -#include -#if !defined(__APPLE__) - extern char **environ; -#else -#include // _NSGetEnviron -#endif -#endif - -namespace llvm { -using namespace sys; - -Program::Program() : Data_(0) {} - -Program::~Program() {} - -unsigned Program::GetPid() const { - uint64_t pid = reinterpret_cast(Data_); - return static_cast(pid); -} - -// This function just uses the PATH environment variable to find the program. -Path -Program::FindProgramByName(const std::string& progName) { - - // Check some degenerate cases - if (progName.length() == 0) // no program - return Path(); - Path temp; - if (!temp.set(progName)) // invalid name - return Path(); - // Use the given path verbatim if it contains any slashes; this matches - // the behavior of sh(1) and friends. - if (progName.find('/') != std::string::npos) - return temp; - - // At this point, the file name does not contain slashes. Search for it - // through the directories specified in the PATH environment variable. - - // Get the path. If its empty, we can't do anything to find it. - const char *PathStr = getenv("PATH"); - if (PathStr == 0) - return Path(); - - // Now we have a colon separated list of directories to search; try them. - size_t PathLen = strlen(PathStr); - while (PathLen) { - // Find the first colon... - const char *Colon = std::find(PathStr, PathStr+PathLen, ':'); - - // Check to see if this first directory contains the executable... - Path FilePath; - if (FilePath.set(std::string(PathStr,Colon))) { - FilePath.appendComponent(progName); - if (FilePath.canExecute()) - return FilePath; // Found the executable! - } - - // Nope it wasn't in this directory, check the next path in the list! - PathLen -= Colon-PathStr; - PathStr = Colon; - - // Advance past duplicate colons - while (*PathStr == ':') { - PathStr++; - PathLen--; - } - } - return Path(); -} - -static bool RedirectIO(const Path *Path, int FD, std::string* ErrMsg) { - if (Path == 0) // Noop - return false; - const char *File; - if (Path->isEmpty()) - // Redirect empty paths to /dev/null - File = "/dev/null"; - else - File = Path->c_str(); - - // Open the file - int InFD = open(File, FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666); - if (InFD == -1) { - MakeErrMsg(ErrMsg, "Cannot open file '" + std::string(File) + "' for " - + (FD == 0 ? "input" : "output")); - return true; - } - - // Install it as the requested FD - if (dup2(InFD, FD) == -1) { - MakeErrMsg(ErrMsg, "Cannot dup2"); - close(InFD); - return true; - } - close(InFD); // Close the original FD - return false; -} - -#ifdef HAVE_POSIX_SPAWN -static bool RedirectIO_PS(const Path *Path, int FD, std::string *ErrMsg, - posix_spawn_file_actions_t &FileActions) { - if (Path == 0) // Noop - return false; - const char *File; - if (Path->isEmpty()) - // Redirect empty paths to /dev/null - File = "/dev/null"; - else - File = Path->c_str(); - - if (int Err = posix_spawn_file_actions_addopen(&FileActions, FD, - File, FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666)) - return MakeErrMsg(ErrMsg, "Cannot dup2", Err); - return false; -} -#endif - -static void TimeOutHandler(int Sig) { -} - -static void SetMemoryLimits (unsigned size) -{ -#if HAVE_SYS_RESOURCE_H && HAVE_GETRLIMIT && HAVE_SETRLIMIT - struct rlimit r; - __typeof__ (r.rlim_cur) limit = (__typeof__ (r.rlim_cur)) (size) * 1048576; - - // Heap size - getrlimit (RLIMIT_DATA, &r); - r.rlim_cur = limit; - setrlimit (RLIMIT_DATA, &r); -#ifdef RLIMIT_RSS - // Resident set size. - getrlimit (RLIMIT_RSS, &r); - r.rlim_cur = limit; - setrlimit (RLIMIT_RSS, &r); -#endif -#ifdef RLIMIT_AS // e.g. NetBSD doesn't have it. - // Virtual memory. - getrlimit (RLIMIT_AS, &r); - r.rlim_cur = limit; - setrlimit (RLIMIT_AS, &r); -#endif -#endif -} - -bool -Program::Execute(const Path &path, const char **args, const char **envp, - const Path **redirects, unsigned memoryLimit, - std::string *ErrMsg) { - // If this OS has posix_spawn and there is no memory limit being implied, use - // posix_spawn. It is more efficient than fork/exec. -#ifdef HAVE_POSIX_SPAWN - if (memoryLimit == 0) { - posix_spawn_file_actions_t FileActions; - posix_spawn_file_actions_init(&FileActions); - - if (redirects) { - // Redirect stdin/stdout. - if (RedirectIO_PS(redirects[0], 0, ErrMsg, FileActions) || - RedirectIO_PS(redirects[1], 1, ErrMsg, FileActions)) - return false; - if (redirects[1] == 0 || redirects[2] == 0 || - *redirects[1] != *redirects[2]) { - // Just redirect stderr - if (RedirectIO_PS(redirects[2], 2, ErrMsg, FileActions)) return false; - } else { - // If stdout and stderr should go to the same place, redirect stderr - // to the FD already open for stdout. - if (int Err = posix_spawn_file_actions_adddup2(&FileActions, 1, 2)) - return !MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout", Err); - } - } - - if (!envp) -#if !defined(__APPLE__) - envp = const_cast(environ); -#else - // environ is missing in dylibs. - envp = const_cast(*_NSGetEnviron()); -#endif - - pid_t PID; - int Err = posix_spawn(&PID, path.c_str(), &FileActions, /*attrp*/0, - const_cast(args), const_cast(envp)); - - posix_spawn_file_actions_destroy(&FileActions); - - if (Err) - return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err); - - Data_ = reinterpret_cast(PID); - return true; - } -#endif - - if (!path.canExecute()) { - if (ErrMsg) - *ErrMsg = path.str() + " is not executable"; - return false; - } - - // Create a child process. - int child = fork(); - switch (child) { - // An error occured: Return to the caller. - case -1: - MakeErrMsg(ErrMsg, "Couldn't fork"); - return false; - - // Child process: Execute the program. - case 0: { - // Redirect file descriptors... - if (redirects) { - // Redirect stdin - if (RedirectIO(redirects[0], 0, ErrMsg)) { return false; } - // Redirect stdout - if (RedirectIO(redirects[1], 1, ErrMsg)) { return false; } - if (redirects[1] && redirects[2] && - *(redirects[1]) == *(redirects[2])) { - // If stdout and stderr should go to the same place, redirect stderr - // to the FD already open for stdout. - if (-1 == dup2(1,2)) { - MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout"); - return false; - } - } else { - // Just redirect stderr - if (RedirectIO(redirects[2], 2, ErrMsg)) { return false; } - } - } - - // Set memory limits - if (memoryLimit!=0) { - SetMemoryLimits(memoryLimit); - } - - // Execute! - if (envp != 0) - execve(path.c_str(), - const_cast(args), - const_cast(envp)); - else - execv(path.c_str(), - const_cast(args)); - // If the execve() failed, we should exit. Follow Unix protocol and - // return 127 if the executable was not found, and 126 otherwise. - // Use _exit rather than exit so that atexit functions and static - // object destructors cloned from the parent process aren't - // redundantly run, and so that any data buffered in stdio buffers - // cloned from the parent aren't redundantly written out. - _exit(errno == ENOENT ? 127 : 126); - } - - // Parent process: Break out of the switch to do our processing. - default: - break; - } - - Data_ = reinterpret_cast(child); - - return true; -} - -int -Program::Wait(unsigned secondsToWait, - std::string* ErrMsg) -{ -#ifdef HAVE_SYS_WAIT_H - struct sigaction Act, Old; - - if (Data_ == 0) { - MakeErrMsg(ErrMsg, "Process not started!"); - return -1; - } - - // Install a timeout handler. The handler itself does nothing, but the simple - // fact of having a handler at all causes the wait below to return with EINTR, - // unlike if we used SIG_IGN. - if (secondsToWait) { - memset(&Act, 0, sizeof(Act)); - Act.sa_handler = TimeOutHandler; - sigemptyset(&Act.sa_mask); - sigaction(SIGALRM, &Act, &Old); - alarm(secondsToWait); - } - - // Parent process: Wait for the child process to terminate. - int status; - uint64_t pid = reinterpret_cast(Data_); - pid_t child = static_cast(pid); - while (waitpid(pid, &status, 0) != child) - if (secondsToWait && errno == EINTR) { - // Kill the child. - kill(child, SIGKILL); - - // Turn off the alarm and restore the signal handler - alarm(0); - sigaction(SIGALRM, &Old, 0); - - // Wait for child to die - if (wait(&status) != child) - MakeErrMsg(ErrMsg, "Child timed out but wouldn't die"); - else - MakeErrMsg(ErrMsg, "Child timed out", 0); - - return -1; // Timeout detected - } else if (errno != EINTR) { - MakeErrMsg(ErrMsg, "Error waiting for child process"); - return -1; - } - - // We exited normally without timeout, so turn off the timer. - if (secondsToWait) { - alarm(0); - sigaction(SIGALRM, &Old, 0); - } - - // Return the proper exit status. 0=success, >0 is programs' exit status, - // <0 means a signal was returned, -9999999 means the program dumped core. - int result = 0; - if (WIFEXITED(status)) - result = WEXITSTATUS(status); - else if (WIFSIGNALED(status)) - result = 0 - WTERMSIG(status); -#ifdef WCOREDUMP - else if (WCOREDUMP(status)) - result |= 0x01000000; -#endif - return result; -#else - return -99; -#endif - -} - -bool -Program::Kill(std::string* ErrMsg) { - if (Data_ == 0) { - MakeErrMsg(ErrMsg, "Process not started!"); - return true; - } - - uint64_t pid64 = reinterpret_cast(Data_); - pid_t pid = static_cast(pid64); - - if (kill(pid, SIGKILL) != 0) { - MakeErrMsg(ErrMsg, "The process couldn't be killed!"); - return true; - } - - return false; -} - -bool Program::ChangeStdinToBinary(){ - // Do nothing, as Unix doesn't differentiate between text and binary. - return false; -} - -bool Program::ChangeStdoutToBinary(){ - // Do nothing, as Unix doesn't differentiate between text and binary. - return false; -} - -bool Program::ChangeStderrToBinary(){ - // Do nothing, as Unix doesn't differentiate between text and binary. - return false; -} - -} diff --git a/lib/System/Unix/README.txt b/lib/System/Unix/README.txt deleted file mode 100644 index b3bace483e5d..000000000000 --- a/lib/System/Unix/README.txt +++ /dev/null @@ -1,16 +0,0 @@ -llvm/lib/System/Unix README -=========================== - -This directory provides implementations of the lib/System classes that -are common to two or more variants of UNIX. For example, the directory -structure underneath this directory could look like this: - -Unix - only code that is truly generic to all UNIX platforms - Posix - code that is specific to Posix variants of UNIX - SUS - code that is specific to the Single Unix Specification - SysV - code that is specific to System V variants of UNIX - -As a rule, only those directories actually needing to be created should be -created. Also, further subdirectories could be created to reflect versions of -the various standards. For example, under SUS there could be v1, v2, and v3 -subdirectories to reflect the three major versions of SUS. diff --git a/lib/System/Unix/RWMutex.inc b/lib/System/Unix/RWMutex.inc deleted file mode 100644 index e83d41ef4cfe..000000000000 --- a/lib/System/Unix/RWMutex.inc +++ /dev/null @@ -1,43 +0,0 @@ -//= llvm/System/Unix/RWMutex.inc - Unix Reader/Writer Mutual Exclusion Lock =// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Unix specific (non-pthread) RWMutex class. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic UNIX code that -//=== is guaranteed to work on *all* UNIX variants. -//===----------------------------------------------------------------------===// - -namespace llvm { - -using namespace sys; - -RWMutexImpl::RWMutexImpl() { } - -RWMutexImpl::~RWMutexImpl() { } - -bool RWMutexImpl::reader_acquire() { - return true; -} - -bool RWMutexImpl::reader_release() { - return true; -} - -bool RWMutexImpl::writer_acquire() { - return true; -} - -bool RWMutexImpl::writer_release() { - return true; -} - -} diff --git a/lib/System/Unix/Signals.inc b/lib/System/Unix/Signals.inc deleted file mode 100644 index 7b7c43efc786..000000000000 --- a/lib/System/Unix/Signals.inc +++ /dev/null @@ -1,299 +0,0 @@ -//===- Signals.cpp - Generic Unix Signals Implementation -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines some helpful functions for dealing with the possibility of -// Unix signals occuring while your program is running. -// -//===----------------------------------------------------------------------===// - -#include "Unix.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/System/Mutex.h" -#include -#include -#if HAVE_EXECINFO_H -# include // For backtrace(). -#endif -#if HAVE_SIGNAL_H -#include -#endif -#if HAVE_SYS_STAT_H -#include -#endif -#if HAVE_DLFCN_H && __GNUG__ -#include -#include -#endif -using namespace llvm; - -static RETSIGTYPE SignalHandler(int Sig); // defined below. - -static SmartMutex SignalsMutex; - -/// InterruptFunction - The function to call if ctrl-c is pressed. -static void (*InterruptFunction)() = 0; - -static std::vector FilesToRemove; -static std::vector > CallBacksToRun; - -// IntSigs - Signals that may interrupt the program at any time. -static const int IntSigs[] = { - SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2 -}; -static const int *const IntSigsEnd = - IntSigs + sizeof(IntSigs) / sizeof(IntSigs[0]); - -// KillSigs - Signals that are synchronous with the program that will cause it -// to die. -static const int KillSigs[] = { - SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV -#ifdef SIGSYS - , SIGSYS -#endif -#ifdef SIGXCPU - , SIGXCPU -#endif -#ifdef SIGXFSZ - , SIGXFSZ -#endif -#ifdef SIGEMT - , SIGEMT -#endif -}; -static const int *const KillSigsEnd = - KillSigs + sizeof(KillSigs) / sizeof(KillSigs[0]); - -static unsigned NumRegisteredSignals = 0; -static struct { - struct sigaction SA; - int SigNo; -} RegisteredSignalInfo[(sizeof(IntSigs)+sizeof(KillSigs))/sizeof(KillSigs[0])]; - - -static void RegisterHandler(int Signal) { - assert(NumRegisteredSignals < - sizeof(RegisteredSignalInfo)/sizeof(RegisteredSignalInfo[0]) && - "Out of space for signal handlers!"); - - struct sigaction NewHandler; - - NewHandler.sa_handler = SignalHandler; - NewHandler.sa_flags = SA_NODEFER|SA_RESETHAND; - sigemptyset(&NewHandler.sa_mask); - - // Install the new handler, save the old one in RegisteredSignalInfo. - sigaction(Signal, &NewHandler, - &RegisteredSignalInfo[NumRegisteredSignals].SA); - RegisteredSignalInfo[NumRegisteredSignals].SigNo = Signal; - ++NumRegisteredSignals; -} - -static void RegisterHandlers() { - // If the handlers are already registered, we're done. - if (NumRegisteredSignals != 0) return; - - std::for_each(IntSigs, IntSigsEnd, RegisterHandler); - std::for_each(KillSigs, KillSigsEnd, RegisterHandler); -} - -static void UnregisterHandlers() { - // Restore all of the signal handlers to how they were before we showed up. - for (unsigned i = 0, e = NumRegisteredSignals; i != e; ++i) - sigaction(RegisteredSignalInfo[i].SigNo, - &RegisteredSignalInfo[i].SA, 0); - NumRegisteredSignals = 0; -} - - -/// RemoveFilesToRemove - Process the FilesToRemove list. This function -/// should be called with the SignalsMutex lock held. -static void RemoveFilesToRemove() { - while (!FilesToRemove.empty()) { - FilesToRemove.back().eraseFromDisk(true); - FilesToRemove.pop_back(); - } -} - -// SignalHandler - The signal handler that runs. -static RETSIGTYPE SignalHandler(int Sig) { - // Restore the signal behavior to default, so that the program actually - // crashes when we return and the signal reissues. This also ensures that if - // we crash in our signal handler that the program will terminate immediately - // instead of recursing in the signal handler. - UnregisterHandlers(); - - // Unmask all potentially blocked kill signals. - sigset_t SigMask; - sigfillset(&SigMask); - sigprocmask(SIG_UNBLOCK, &SigMask, 0); - - SignalsMutex.acquire(); - RemoveFilesToRemove(); - - if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd) { - if (InterruptFunction) { - void (*IF)() = InterruptFunction; - SignalsMutex.release(); - InterruptFunction = 0; - IF(); // run the interrupt function. - return; - } - - SignalsMutex.release(); - raise(Sig); // Execute the default handler. - return; - } - - SignalsMutex.release(); - - // Otherwise if it is a fault (like SEGV) run any handler. - for (unsigned i = 0, e = CallBacksToRun.size(); i != e; ++i) - CallBacksToRun[i].first(CallBacksToRun[i].second); -} - -void llvm::sys::RunInterruptHandlers() { - SignalsMutex.acquire(); - RemoveFilesToRemove(); - SignalsMutex.release(); -} - -void llvm::sys::SetInterruptFunction(void (*IF)()) { - SignalsMutex.acquire(); - InterruptFunction = IF; - SignalsMutex.release(); - RegisterHandlers(); -} - -// RemoveFileOnSignal - The public API -bool llvm::sys::RemoveFileOnSignal(const sys::Path &Filename, - std::string* ErrMsg) { - SignalsMutex.acquire(); - FilesToRemove.push_back(Filename); - - SignalsMutex.release(); - - RegisterHandlers(); - return false; -} - -// DontRemoveFileOnSignal - The public API -void llvm::sys::DontRemoveFileOnSignal(const sys::Path &Filename) { - SignalsMutex.acquire(); - std::vector::reverse_iterator I = - std::find(FilesToRemove.rbegin(), FilesToRemove.rend(), Filename); - if (I != FilesToRemove.rend()) - FilesToRemove.erase(I.base()-1); - SignalsMutex.release(); -} - -/// AddSignalHandler - Add a function to be called when a signal is delivered -/// to the process. The handler can have a cookie passed to it to identify -/// what instance of the handler it is. -void llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { - CallBacksToRun.push_back(std::make_pair(FnPtr, Cookie)); - RegisterHandlers(); -} - - -// PrintStackTrace - In the case of a program crash or fault, print out a stack -// trace so that the user has an indication of why and where we died. -// -// On glibc systems we have the 'backtrace' function, which works nicely, but -// doesn't demangle symbols. -static void PrintStackTrace(void *) { -#ifdef HAVE_BACKTRACE - static void* StackTrace[256]; - // Use backtrace() to output a backtrace on Linux systems with glibc. - int depth = backtrace(StackTrace, - static_cast(array_lengthof(StackTrace))); -#if HAVE_DLFCN_H && __GNUG__ - int width = 0; - for (int i = 0; i < depth; ++i) { - Dl_info dlinfo; - dladdr(StackTrace[i], &dlinfo); - const char* name = strrchr(dlinfo.dli_fname, '/'); - - int nwidth; - if (name == NULL) nwidth = strlen(dlinfo.dli_fname); - else nwidth = strlen(name) - 1; - - if (nwidth > width) width = nwidth; - } - - for (int i = 0; i < depth; ++i) { - Dl_info dlinfo; - dladdr(StackTrace[i], &dlinfo); - - fprintf(stderr, "%-2d", i); - - const char* name = strrchr(dlinfo.dli_fname, '/'); - if (name == NULL) fprintf(stderr, " %-*s", width, dlinfo.dli_fname); - else fprintf(stderr, " %-*s", width, name+1); - - fprintf(stderr, " %#0*lx", - (int)(sizeof(void*) * 2) + 2, (unsigned long)StackTrace[i]); - - if (dlinfo.dli_sname != NULL) { - int res; - fputc(' ', stderr); - char* d = abi::__cxa_demangle(dlinfo.dli_sname, NULL, NULL, &res); - if (d == NULL) fputs(dlinfo.dli_sname, stderr); - else fputs(d, stderr); - free(d); - - fprintf(stderr, " + %tu",(char*)StackTrace[i]-(char*)dlinfo.dli_saddr); - } - fputc('\n', stderr); - } -#else - backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO); -#endif -#endif -} - -/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or -/// SIGSEGV) is delivered to the process, print a stack trace and then exit. -void llvm::sys::PrintStackTraceOnErrorSignal() { - AddSignalHandler(PrintStackTrace, 0); -} - - -/***/ - -// On Darwin, raise sends a signal to the main thread instead of the current -// thread. This has the unfortunate effect that assert() and abort() will end up -// bypassing our crash recovery attempts. We work around this for anything in -// the same linkage unit by just defining our own versions of the assert handler -// and abort. - -#ifdef __APPLE__ - -void __assert_rtn(const char *func, - const char *file, - int line, - const char *expr) { - if (func) - fprintf(stderr, "Assertion failed: (%s), function %s, file %s, line %d.\n", - expr, func, file, line); - else - fprintf(stderr, "Assertion failed: (%s), file %s, line %d.\n", - expr, file, line); - abort(); -} - -#include -#include - -void abort() { - pthread_kill(pthread_self(), SIGABRT); - usleep(1000); - __builtin_trap(); -} - -#endif diff --git a/lib/System/Unix/ThreadLocal.inc b/lib/System/Unix/ThreadLocal.inc deleted file mode 100644 index 6769520a6fb6..000000000000 --- a/lib/System/Unix/ThreadLocal.inc +++ /dev/null @@ -1,26 +0,0 @@ -//=== llvm/System/Unix/ThreadLocal.inc - Unix Thread Local Data -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Unix specific (non-pthread) ThreadLocal class. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic UNIX code that -//=== is guaranteed to work on *all* UNIX variants. -//===----------------------------------------------------------------------===// - -namespace llvm { -using namespace sys; -ThreadLocalImpl::ThreadLocalImpl() { } -ThreadLocalImpl::~ThreadLocalImpl() { } -void ThreadLocalImpl::setInstance(const void* d) { data = const_cast(d);} -const void* ThreadLocalImpl::getInstance() { return data; } -void ThreadLocalImpl::removeInstance() { setInstance(0); } -} diff --git a/lib/System/Unix/TimeValue.inc b/lib/System/Unix/TimeValue.inc deleted file mode 100644 index d8cc8f55eecc..000000000000 --- a/lib/System/Unix/TimeValue.inc +++ /dev/null @@ -1,56 +0,0 @@ -//===- Unix/TimeValue.cpp - Unix TimeValue Implementation -------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Unix specific portion of the TimeValue class. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic UNIX code that -//=== is guaranteed to work on *all* UNIX variants. -//===----------------------------------------------------------------------===// - -#include "Unix.h" - -namespace llvm { - using namespace sys; - -std::string TimeValue::str() const { - char buffer[32]; - - time_t ourTime = time_t(this->toEpochTime()); -#ifdef __hpux -// note that the following line needs -D_REENTRANT on HP-UX to be picked up - asctime_r(localtime(&ourTime), buffer); -#else - ::asctime_r(::localtime(&ourTime), buffer); -#endif - - std::string result(buffer); - return result.substr(0,24); -} - -TimeValue TimeValue::now() { - struct timeval the_time; - timerclear(&the_time); - if (0 != ::gettimeofday(&the_time,0)) { - // This is *really* unlikely to occur because the only gettimeofday - // errors concern the timezone parameter which we're passing in as 0. - // In the unlikely case it does happen, just return MinTime, no error - // message needed. - return MinTime; - } - - return TimeValue( - static_cast( the_time.tv_sec + PosixZeroTime.seconds_ ), - static_cast( the_time.tv_usec * - NANOSECONDS_PER_MICROSECOND ) ); -} - -} diff --git a/lib/System/Unix/Unix.h b/lib/System/Unix/Unix.h deleted file mode 100644 index c15866f3d90a..000000000000 --- a/lib/System/Unix/Unix.h +++ /dev/null @@ -1,87 +0,0 @@ -//===- llvm/System/Unix/Unix.h - Common Unix Include File -------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines things specific to Unix implementations. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_SYSTEM_UNIX_UNIX_H -#define LLVM_SYSTEM_UNIX_UNIX_H - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic UNIX code that -//=== is guaranteed to work on all UNIX variants. -//===----------------------------------------------------------------------===// - -#include "llvm/Config/config.h" // Get autoconf configuration settings -#include "llvm/System/Errno.h" -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_UNISTD_H -#include -#endif - -#ifdef HAVE_SYS_TYPES_H -#include -#endif - -#ifdef HAVE_SYS_PARAM_H -#include -#endif - -#ifdef HAVE_ASSERT_H -#include -#endif - -#ifdef TIME_WITH_SYS_TIME -# include -# include -#else -# ifdef HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif - -#ifdef HAVE_SYS_WAIT_H -# include -#endif - -#ifndef WEXITSTATUS -# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) -#endif - -#ifndef WIFEXITED -# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) -#endif - -/// This function builds an error message into \p ErrMsg using the \p prefix -/// string and the Unix error number given by \p errnum. If errnum is -1, the -/// default then the value of errno is used. -/// @brief Make an error message -/// -/// If the error number can be converted to a string, it will be -/// separated from prefix by ": ". -static inline bool MakeErrMsg( - std::string* ErrMsg, const std::string& prefix, int errnum = -1) { - if (!ErrMsg) - return true; - if (errnum == -1) - errnum = errno; - *ErrMsg = prefix + ": " + llvm::sys::StrError(errnum); - return true; -} - -#endif diff --git a/lib/System/Valgrind.cpp b/lib/System/Valgrind.cpp deleted file mode 100644 index c76cfe40d3e0..000000000000 --- a/lib/System/Valgrind.cpp +++ /dev/null @@ -1,54 +0,0 @@ -//===-- Valgrind.cpp - Implement Valgrind communication ---------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Defines Valgrind communication methods, if HAVE_VALGRIND_VALGRIND_H is -// defined. If we have valgrind.h but valgrind isn't running, its macros are -// no-ops. -// -//===----------------------------------------------------------------------===// - -#include "llvm/System/Valgrind.h" -#include "llvm/Config/config.h" - -#if HAVE_VALGRIND_VALGRIND_H -#include - -static bool InitNotUnderValgrind() { - return !RUNNING_ON_VALGRIND; -} - -// This bool is negated from what we'd expect because code may run before it -// gets initialized. If that happens, it will appear to be 0 (false), and we -// want that to cause the rest of the code in this file to run the -// Valgrind-provided macros. -static const bool NotUnderValgrind = InitNotUnderValgrind(); - -bool llvm::sys::RunningOnValgrind() { - if (NotUnderValgrind) - return false; - return RUNNING_ON_VALGRIND; -} - -void llvm::sys::ValgrindDiscardTranslations(const void *Addr, size_t Len) { - if (NotUnderValgrind) - return; - - VALGRIND_DISCARD_TRANSLATIONS(Addr, Len); -} - -#else // !HAVE_VALGRIND_VALGRIND_H - -bool llvm::sys::RunningOnValgrind() { - return false; -} - -void llvm::sys::ValgrindDiscardTranslations(const void *Addr, size_t Len) { -} - -#endif // !HAVE_VALGRIND_VALGRIND_H diff --git a/lib/System/Win32/Alarm.inc b/lib/System/Win32/Alarm.inc deleted file mode 100644 index e0d00a0142bf..000000000000 --- a/lib/System/Win32/Alarm.inc +++ /dev/null @@ -1,43 +0,0 @@ -//===-- Alarm.inc - Implement Win32 Alarm Support ---------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Win32 Alarm support. -// -//===----------------------------------------------------------------------===// - -#include -using namespace llvm; - -/// NestedSOI - Sanity check. Alarms cannot be nested or run in parallel. -/// This ensures that they never do. -static bool NestedSOI = false; - -void sys::SetupAlarm(unsigned seconds) { - assert(!NestedSOI && "sys::SetupAlarm calls cannot be nested!"); - NestedSOI = true; - // FIXME: Implement for Win32 -} - -void sys::TerminateAlarm() { - assert(NestedSOI && "sys::TerminateAlarm called without sys::SetupAlarm!"); - // FIXME: Implement for Win32 - NestedSOI = false; -} - -int sys::AlarmStatus() { - // FIXME: Implement for Win32 - return 0; -} - -// Don't pull in all of the Windows headers. -extern "C" void __stdcall Sleep(unsigned long); - -void sys::Sleep(unsigned n) { - ::Sleep(n*1000); -} diff --git a/lib/System/Win32/DynamicLibrary.inc b/lib/System/Win32/DynamicLibrary.inc deleted file mode 100644 index c9a89e5b8c49..000000000000 --- a/lib/System/Win32/DynamicLibrary.inc +++ /dev/null @@ -1,200 +0,0 @@ -//===- Win32/DynamicLibrary.cpp - Win32 DL Implementation -------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file provides the Win32 specific implementation of DynamicLibrary. -// -//===----------------------------------------------------------------------===// - -#include "Win32.h" - -#ifdef __MINGW32__ - #include -#else - #include -#endif - -#ifdef _MSC_VER - #include -#endif - -#ifdef __MINGW32__ - #if (HAVE_LIBIMAGEHLP != 1) - #error "libimagehlp.a should be present" - #endif -#else - #pragma comment(lib, "dbghelp.lib") -#endif - -namespace llvm { -using namespace sys; - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only Win32 specific code -//=== and must not be UNIX code. -//===----------------------------------------------------------------------===// - -static std::vector OpenedHandles; - -#ifdef _WIN64 - typedef DWORD64 ModuleBaseType; -#else - typedef ULONG ModuleBaseType; -#endif - -extern "C" { -// Use old callback if: -// - Not using Visual Studio -// - Visual Studio 2005 or earlier but only if we are not using the Windows SDK -// or Windows SDK version is older than 6.0 -// Use new callback if: -// - Newer Visual Studio (comes with newer SDK). -// - Visual Studio 2005 with Windows SDK 6.0+ -#if !defined(_MSC_VER) || _MSC_VER < 1500 && (!defined(VER_PRODUCTBUILD) || VER_PRODUCTBUILD < 6000) - static BOOL CALLBACK ELM_Callback(PSTR ModuleName, - ModuleBaseType ModuleBase, - ULONG ModuleSize, - PVOID UserContext) -#else - static BOOL CALLBACK ELM_Callback(PCSTR ModuleName, - ModuleBaseType ModuleBase, - ULONG ModuleSize, - PVOID UserContext) -#endif - { - // Ignore VC++ runtimes prior to 7.1. Somehow some of them get loaded - // into the process. - if (stricmp(ModuleName, "msvci70") != 0 && - stricmp(ModuleName, "msvcirt") != 0 && - stricmp(ModuleName, "msvcp50") != 0 && - stricmp(ModuleName, "msvcp60") != 0 && - stricmp(ModuleName, "msvcp70") != 0 && - stricmp(ModuleName, "msvcr70") != 0 && -#ifndef __MINGW32__ - // Mingw32 uses msvcrt.dll by default. Don't ignore it. - // Otherwise, user should be aware, what he's doing :) - stricmp(ModuleName, "msvcrt") != 0 && -#endif - stricmp(ModuleName, "msvcrt20") != 0 && - stricmp(ModuleName, "msvcrt40") != 0) { - OpenedHandles.push_back((HMODULE)ModuleBase); - } - return TRUE; - } -} - -bool DynamicLibrary::LoadLibraryPermanently(const char *filename, - std::string *ErrMsg) { - if (filename) { - HMODULE a_handle = LoadLibrary(filename); - - if (a_handle == 0) - return MakeErrMsg(ErrMsg, std::string(filename) + ": Can't open : "); - - OpenedHandles.push_back(a_handle); - } else { - // When no file is specified, enumerate all DLLs and EXEs in the - // process. - EnumerateLoadedModules(GetCurrentProcess(), ELM_Callback, 0); - } - - // Because we don't remember the handle, we will never free it; hence, - // it is loaded permanently. - return false; -} - -// Stack probing routines are in the support library (e.g. libgcc), but we don't -// have dynamic linking on windows. Provide a hook. -#if defined(__MINGW32__) || defined (_MSC_VER) - #define EXPLICIT_SYMBOL(SYM) \ - if (!strcmp(symbolName, #SYM)) return (void*)&SYM - #define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) \ - if (!strcmp(symbolName, #SYMFROM)) return (void*)&SYMTO - #define EXPLICIT_SYMBOL_DEF(SYM) \ - extern "C" { extern void *SYM; } - - #if defined(__MINGW32__) - EXPLICIT_SYMBOL_DEF(_alloca) - EXPLICIT_SYMBOL_DEF(__main) - EXPLICIT_SYMBOL_DEF(__ashldi3) - EXPLICIT_SYMBOL_DEF(__ashrdi3) - EXPLICIT_SYMBOL_DEF(__cmpdi2) - EXPLICIT_SYMBOL_DEF(__divdi3) - EXPLICIT_SYMBOL_DEF(__fixdfdi) - EXPLICIT_SYMBOL_DEF(__fixsfdi) - EXPLICIT_SYMBOL_DEF(__fixunsdfdi) - EXPLICIT_SYMBOL_DEF(__fixunssfdi) - EXPLICIT_SYMBOL_DEF(__floatdidf) - EXPLICIT_SYMBOL_DEF(__floatdisf) - EXPLICIT_SYMBOL_DEF(__lshrdi3) - EXPLICIT_SYMBOL_DEF(__moddi3) - EXPLICIT_SYMBOL_DEF(__udivdi3) - EXPLICIT_SYMBOL_DEF(__umoddi3) - #elif defined(_MSC_VER) - EXPLICIT_SYMBOL_DEF(_alloca_probe) - #endif -#endif - -void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) { - // First check symbols added via AddSymbol(). - if (ExplicitSymbols) { - std::map::iterator I = - ExplicitSymbols->find(symbolName); - std::map::iterator E = ExplicitSymbols->end(); - if (I != E) - return I->second; - } - - // Now search the libraries. - for (std::vector::iterator I = OpenedHandles.begin(), - E = OpenedHandles.end(); I != E; ++I) { - FARPROC ptr = GetProcAddress((HMODULE)*I, symbolName); - if (ptr) { - return (void *) ptr; - } - } - -#if defined(__MINGW32__) - { - EXPLICIT_SYMBOL(_alloca); - EXPLICIT_SYMBOL(__main); - EXPLICIT_SYMBOL(__ashldi3); - EXPLICIT_SYMBOL(__ashrdi3); - EXPLICIT_SYMBOL(__cmpdi2); - EXPLICIT_SYMBOL(__divdi3); - EXPLICIT_SYMBOL(__fixdfdi); - EXPLICIT_SYMBOL(__fixsfdi); - EXPLICIT_SYMBOL(__fixunsdfdi); - EXPLICIT_SYMBOL(__fixunssfdi); - EXPLICIT_SYMBOL(__floatdidf); - EXPLICIT_SYMBOL(__floatdisf); - EXPLICIT_SYMBOL(__lshrdi3); - EXPLICIT_SYMBOL(__moddi3); - EXPLICIT_SYMBOL(__udivdi3); - EXPLICIT_SYMBOL(__umoddi3); - - EXPLICIT_SYMBOL2(alloca, _alloca); -#undef EXPLICIT_SYMBOL -#undef EXPLICIT_SYMBOL2 -#undef EXPLICIT_SYMBOL_DEF - } -#elif defined(_MSC_VER) - { - EXPLICIT_SYMBOL2(alloca, _alloca_probe); - EXPLICIT_SYMBOL2(_alloca, _alloca_probe); -#undef EXPLICIT_SYMBOL -#undef EXPLICIT_SYMBOL2 -#undef EXPLICIT_SYMBOL_DEF - } -#endif - - return 0; -} - -} - diff --git a/lib/System/Win32/Host.inc b/lib/System/Win32/Host.inc deleted file mode 100644 index 18f00f8bc07b..000000000000 --- a/lib/System/Win32/Host.inc +++ /dev/null @@ -1,23 +0,0 @@ -//===- llvm/System/Win32/Host.inc -------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Win32 Host support. -// -//===----------------------------------------------------------------------===// - -#include "Win32.h" -#include -#include - -using namespace llvm; - -std::string sys::getHostTriple() { - // FIXME: Adapt to running version. - return LLVM_HOSTTRIPLE; -} diff --git a/lib/System/Win32/Memory.inc b/lib/System/Win32/Memory.inc deleted file mode 100644 index 19fccbddc26b..000000000000 --- a/lib/System/Win32/Memory.inc +++ /dev/null @@ -1,73 +0,0 @@ -//===- Win32/Memory.cpp - Win32 Memory Implementation -----------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file provides the Win32 specific implementation of various Memory -// management utilities -// -//===----------------------------------------------------------------------===// - -#include "Win32.h" -#include "llvm/System/DataTypes.h" -#include "llvm/System/Process.h" - -namespace llvm { -using namespace sys; - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only Win32 specific code -//=== and must not be UNIX code -//===----------------------------------------------------------------------===// - -MemoryBlock Memory::AllocateRWX(size_t NumBytes, - const MemoryBlock *NearBlock, - std::string *ErrMsg) { - if (NumBytes == 0) return MemoryBlock(); - - static const size_t pageSize = Process::GetPageSize(); - size_t NumPages = (NumBytes+pageSize-1)/pageSize; - - //FIXME: support NearBlock if ever needed on Win64. - - void *pa = VirtualAlloc(NULL, NumPages*pageSize, MEM_COMMIT, - PAGE_EXECUTE_READWRITE); - if (pa == NULL) { - MakeErrMsg(ErrMsg, "Can't allocate RWX Memory: "); - return MemoryBlock(); - } - - MemoryBlock result; - result.Address = pa; - result.Size = NumPages*pageSize; - return result; -} - -bool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { - if (M.Address == 0 || M.Size == 0) return false; - if (!VirtualFree(M.Address, 0, MEM_RELEASE)) - return MakeErrMsg(ErrMsg, "Can't release RWX Memory: "); - return false; -} - -bool Memory::setWritable(MemoryBlock &M, std::string *ErrMsg) { - return true; -} - -bool Memory::setExecutable(MemoryBlock &M, std::string *ErrMsg) { - return false; -} - -bool Memory::setRangeWritable(const void *Addr, size_t Size) { - return true; -} - -bool Memory::setRangeExecutable(const void *Addr, size_t Size) { - return false; -} - -} diff --git a/lib/System/Win32/Mutex.inc b/lib/System/Win32/Mutex.inc deleted file mode 100644 index 75f01fefacbb..000000000000 --- a/lib/System/Win32/Mutex.inc +++ /dev/null @@ -1,58 +0,0 @@ -//===- llvm/System/Win32/Mutex.inc - Win32 Mutex Implementation -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Win32 specific (non-pthread) Mutex class. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic Win32 code that -//=== is guaranteed to work on *all* Win32 variants. -//===----------------------------------------------------------------------===// - -#include "Win32.h" -#include "llvm/System/Mutex.h" - -namespace llvm { -using namespace sys; - -MutexImpl::MutexImpl(bool /*recursive*/) -{ - data_ = new CRITICAL_SECTION; - InitializeCriticalSection((LPCRITICAL_SECTION)data_); -} - -MutexImpl::~MutexImpl() -{ - DeleteCriticalSection((LPCRITICAL_SECTION)data_); - delete (LPCRITICAL_SECTION)data_; - data_ = 0; -} - -bool -MutexImpl::acquire() -{ - EnterCriticalSection((LPCRITICAL_SECTION)data_); - return true; -} - -bool -MutexImpl::release() -{ - LeaveCriticalSection((LPCRITICAL_SECTION)data_); - return true; -} - -bool -MutexImpl::tryacquire() -{ - return TryEnterCriticalSection((LPCRITICAL_SECTION)data_); -} - -} diff --git a/lib/System/Win32/Path.inc b/lib/System/Win32/Path.inc deleted file mode 100644 index 4a6dbd3ddf29..000000000000 --- a/lib/System/Win32/Path.inc +++ /dev/null @@ -1,872 +0,0 @@ -//===- llvm/System/Win32/Path.cpp - Win32 Path Implementation ---*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -// Modified by Henrik Bach to comply with at least MinGW. -// Ported to Win32 by Jeff Cohen. -// -//===----------------------------------------------------------------------===// -// -// This file provides the Win32 specific implementation of the Path class. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic Win32 code that -//=== is guaranteed to work on *all* Win32 variants. -//===----------------------------------------------------------------------===// - -#include "Win32.h" -#include -#include - -// We need to undo a macro defined in Windows.h, otherwise we won't compile: -#undef CopyFile -#undef GetCurrentDirectory - -// Windows happily accepts either forward or backward slashes, though any path -// returned by a Win32 API will have backward slashes. As LLVM code basically -// assumes forward slashes are used, backward slashs are converted where they -// can be introduced into a path. -// -// Another invariant is that a path ends with a slash if and only if the path -// is a root directory. Any other use of a trailing slash is stripped. Unlike -// in Unix, Windows has a rather complicated notion of a root path and this -// invariant helps simply the code. - -static void FlipBackSlashes(std::string& s) { - for (size_t i = 0; i < s.size(); i++) - if (s[i] == '\\') - s[i] = '/'; -} - -namespace llvm { -namespace sys { -const char PathSeparator = ';'; - -Path::Path(llvm::StringRef p) - : path(p) { - FlipBackSlashes(path); -} - -Path::Path(const char *StrStart, unsigned StrLen) - : path(StrStart, StrLen) { - FlipBackSlashes(path); -} - -Path& -Path::operator=(StringRef that) { - path.assign(that.data(), that.size()); - FlipBackSlashes(path); - return *this; -} - -bool -Path::isValid() const { - if (path.empty()) - return false; - - // If there is a colon, it must be the second character, preceded by a letter - // and followed by something. - size_t len = path.size(); - size_t pos = path.rfind(':',len); - size_t rootslash = 0; - if (pos != std::string::npos) { - if (pos != 1 || !isalpha(path[0]) || len < 3) - return false; - rootslash = 2; - } - - // Look for a UNC path, and if found adjust our notion of the root slash. - if (len > 3 && path[0] == '/' && path[1] == '/') { - rootslash = path.find('/', 2); - if (rootslash == std::string::npos) - rootslash = 0; - } - - // Check for illegal characters. - if (path.find_first_of("\\<>\"|\001\002\003\004\005\006\007\010\011\012" - "\013\014\015\016\017\020\021\022\023\024\025\026" - "\027\030\031\032\033\034\035\036\037") - != std::string::npos) - return false; - - // Remove trailing slash, unless it's a root slash. - if (len > rootslash+1 && path[len-1] == '/') - path.erase(--len); - - // Check each component for legality. - for (pos = 0; pos < len; ++pos) { - // A component may not end in a space. - if (path[pos] == ' ') { - if (path[pos+1] == '/' || path[pos+1] == '\0') - return false; - } - - // A component may not end in a period. - if (path[pos] == '.') { - if (path[pos+1] == '/' || path[pos+1] == '\0') { - // Unless it is the pseudo-directory "."... - if (pos == 0 || path[pos-1] == '/' || path[pos-1] == ':') - return true; - // or "..". - if (pos > 0 && path[pos-1] == '.') { - if (pos == 1 || path[pos-2] == '/' || path[pos-2] == ':') - return true; - } - return false; - } - } - } - - return true; -} - -void Path::makeAbsolute() { - TCHAR FullPath[MAX_PATH + 1] = {0}; - LPTSTR FilePart = NULL; - - DWORD RetLength = ::GetFullPathNameA(path.c_str(), - sizeof(FullPath)/sizeof(FullPath[0]), - FullPath, &FilePart); - - if (0 == RetLength) { - // FIXME: Report the error GetLastError() - assert(0 && "Unable to make absolute path!"); - } else if (RetLength > MAX_PATH) { - // FIXME: Report too small buffer (needed RetLength bytes). - assert(0 && "Unable to make absolute path!"); - } else { - path = FullPath; - } -} - -bool -Path::isAbsolute(const char *NameStart, unsigned NameLen) { - assert(NameStart); - // FIXME: This does not handle correctly an absolute path starting from - // a drive letter or in UNC format. - switch (NameLen) { - case 0: - return false; - case 1: - case 2: - return NameStart[0] == '/'; - default: - return (NameStart[0] == '/' || (NameStart[1] == ':' && NameStart[2] == '/')) || - (NameStart[0] == '\\' || (NameStart[1] == ':' && NameStart[2] == '\\')); - } -} - -bool -Path::isAbsolute() const { - // FIXME: This does not handle correctly an absolute path starting from - // a drive letter or in UNC format. - switch (path.length()) { - case 0: - return false; - case 1: - case 2: - return path[0] == '/'; - default: - return path[0] == '/' || (path[1] == ':' && path[2] == '/'); - } -} - -static Path *TempDirectory; - -Path -Path::GetTemporaryDirectory(std::string* ErrMsg) { - if (TempDirectory) - return *TempDirectory; - - char pathname[MAX_PATH]; - if (!GetTempPath(MAX_PATH, pathname)) { - if (ErrMsg) - *ErrMsg = "Can't determine temporary directory"; - return Path(); - } - - Path result; - result.set(pathname); - - // Append a subdirectory passed on our process id so multiple LLVMs don't - // step on each other's toes. -#ifdef __MINGW32__ - // Mingw's Win32 header files are broken. - sprintf(pathname, "LLVM_%u", unsigned(GetCurrentProcessId())); -#else - sprintf(pathname, "LLVM_%u", GetCurrentProcessId()); -#endif - result.appendComponent(pathname); - - // If there's a directory left over from a previous LLVM execution that - // happened to have the same process id, get rid of it. - result.eraseFromDisk(true); - - // And finally (re-)create the empty directory. - result.createDirectoryOnDisk(false); - TempDirectory = new Path(result); - return *TempDirectory; -} - -// FIXME: the following set of functions don't map to Windows very well. -Path -Path::GetRootDirectory() { - Path result; - result.set("C:/"); - return result; -} - -void -Path::GetSystemLibraryPaths(std::vector& Paths) { - Paths.push_back(sys::Path("C:/WINDOWS/SYSTEM32")); - Paths.push_back(sys::Path("C:/WINDOWS")); -} - -void -Path::GetBitcodeLibraryPaths(std::vector& Paths) { - char * env_var = getenv("LLVM_LIB_SEARCH_PATH"); - if (env_var != 0) { - getPathList(env_var,Paths); - } -#ifdef LLVM_LIBDIR - { - Path tmpPath; - if (tmpPath.set(LLVM_LIBDIR)) - if (tmpPath.canRead()) - Paths.push_back(tmpPath); - } -#endif - GetSystemLibraryPaths(Paths); -} - -Path -Path::GetLLVMDefaultConfigDir() { - // TODO: this isn't going to fly on Windows - return Path("/etc/llvm"); -} - -Path -Path::GetUserHomeDirectory() { - // TODO: Typical Windows setup doesn't define HOME. - const char* home = getenv("HOME"); - if (home) { - Path result; - if (result.set(home)) - return result; - } - return GetRootDirectory(); -} - -Path -Path::GetCurrentDirectory() { - char pathname[MAX_PATH]; - ::GetCurrentDirectoryA(MAX_PATH,pathname); - return Path(pathname); -} - -/// GetMainExecutable - Return the path to the main executable, given the -/// value of argv[0] from program startup. -Path Path::GetMainExecutable(const char *argv0, void *MainAddr) { - char pathname[MAX_PATH]; - DWORD ret = ::GetModuleFileNameA(NULL, pathname, MAX_PATH); - return ret != MAX_PATH ? Path(pathname) : Path(); -} - - -// FIXME: the above set of functions don't map to Windows very well. - - -StringRef Path::getDirname() const { - return getDirnameCharSep(path, "/"); -} - -StringRef -Path::getBasename() const { - // Find the last slash - size_t slash = path.rfind('/'); - if (slash == std::string::npos) - slash = 0; - else - slash++; - - size_t dot = path.rfind('.'); - if (dot == std::string::npos || dot < slash) - return StringRef(path).substr(slash); - else - return StringRef(path).substr(slash, dot - slash); -} - -StringRef -Path::getSuffix() const { - // Find the last slash - size_t slash = path.rfind('/'); - if (slash == std::string::npos) - slash = 0; - else - slash++; - - size_t dot = path.rfind('.'); - if (dot == std::string::npos || dot < slash) - return StringRef(""); - else - return StringRef(path).substr(dot + 1); -} - -bool -Path::exists() const { - DWORD attr = GetFileAttributes(path.c_str()); - return attr != INVALID_FILE_ATTRIBUTES; -} - -bool -Path::isDirectory() const { - DWORD attr = GetFileAttributes(path.c_str()); - return (attr != INVALID_FILE_ATTRIBUTES) && - (attr & FILE_ATTRIBUTE_DIRECTORY); -} - -bool -Path::canRead() const { - // FIXME: take security attributes into account. - DWORD attr = GetFileAttributes(path.c_str()); - return attr != INVALID_FILE_ATTRIBUTES; -} - -bool -Path::canWrite() const { - // FIXME: take security attributes into account. - DWORD attr = GetFileAttributes(path.c_str()); - return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_READONLY); -} - -bool -Path::canExecute() const { - // FIXME: take security attributes into account. - DWORD attr = GetFileAttributes(path.c_str()); - return attr != INVALID_FILE_ATTRIBUTES; -} - -bool -Path::isRegularFile() const { - if (isDirectory()) - return false; - return true; -} - -StringRef -Path::getLast() const { - // Find the last slash - size_t pos = path.rfind('/'); - - // Handle the corner cases - if (pos == std::string::npos) - return path; - - // If the last character is a slash, we have a root directory - if (pos == path.length()-1) - return path; - - // Return everything after the last slash - return StringRef(path).substr(pos+1); -} - -const FileStatus * -PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const { - if (!fsIsValid || update) { - WIN32_FILE_ATTRIBUTE_DATA fi; - if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) { - MakeErrMsg(ErrStr, "getStatusInfo():" + std::string(path) + - ": Can't get status: "); - return 0; - } - - status.fileSize = fi.nFileSizeHigh; - status.fileSize <<= sizeof(fi.nFileSizeHigh)*8; - status.fileSize += fi.nFileSizeLow; - - status.mode = fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? 0555 : 0777; - status.user = 9999; // Not applicable to Windows, so... - status.group = 9999; // Not applicable to Windows, so... - - // FIXME: this is only unique if the file is accessed by the same file path. - // How do we do this for C:\dir\file and ..\dir\file ? Unix has inode - // numbers, but the concept doesn't exist in Windows. - status.uniqueID = 0; - for (unsigned i = 0; i < path.length(); ++i) - status.uniqueID += path[i]; - - ULARGE_INTEGER ui; - ui.LowPart = fi.ftLastWriteTime.dwLowDateTime; - ui.HighPart = fi.ftLastWriteTime.dwHighDateTime; - status.modTime.fromWin32Time(ui.QuadPart); - - status.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; - fsIsValid = true; - } - return &status; -} - -bool Path::makeReadableOnDisk(std::string* ErrMsg) { - // All files are readable on Windows (ignoring security attributes). - return false; -} - -bool Path::makeWriteableOnDisk(std::string* ErrMsg) { - DWORD attr = GetFileAttributes(path.c_str()); - - // If it doesn't exist, we're done. - if (attr == INVALID_FILE_ATTRIBUTES) - return false; - - if (attr & FILE_ATTRIBUTE_READONLY) { - if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY)) { - MakeErrMsg(ErrMsg, std::string(path) + ": Can't make file writable: "); - return true; - } - } - return false; -} - -bool Path::makeExecutableOnDisk(std::string* ErrMsg) { - // All files are executable on Windows (ignoring security attributes). - return false; -} - -bool -Path::getDirectoryContents(std::set& result, std::string* ErrMsg) const { - WIN32_FILE_ATTRIBUTE_DATA fi; - if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) { - MakeErrMsg(ErrMsg, path + ": can't get status of file"); - return true; - } - - if (!(fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - if (ErrMsg) - *ErrMsg = path + ": not a directory"; - return true; - } - - result.clear(); - WIN32_FIND_DATA fd; - std::string searchpath = path; - if (path.size() == 0 || searchpath[path.size()-1] == '/') - searchpath += "*"; - else - searchpath += "/*"; - - HANDLE h = FindFirstFile(searchpath.c_str(), &fd); - if (h == INVALID_HANDLE_VALUE) { - if (GetLastError() == ERROR_FILE_NOT_FOUND) - return true; // not really an error, now is it? - MakeErrMsg(ErrMsg, path + ": Can't read directory: "); - return true; - } - - do { - if (fd.cFileName[0] == '.') - continue; - Path aPath(path); - aPath.appendComponent(&fd.cFileName[0]); - result.insert(aPath); - } while (FindNextFile(h, &fd)); - - DWORD err = GetLastError(); - FindClose(h); - if (err != ERROR_NO_MORE_FILES) { - SetLastError(err); - MakeErrMsg(ErrMsg, path + ": Can't read directory: "); - return true; - } - return false; -} - -bool -Path::set(StringRef a_path) { - if (a_path.empty()) - return false; - std::string save(path); - path = a_path; - FlipBackSlashes(path); - if (!isValid()) { - path = save; - return false; - } - return true; -} - -bool -Path::appendComponent(StringRef name) { - if (name.empty()) - return false; - std::string save(path); - if (!path.empty()) { - size_t last = path.size() - 1; - if (path[last] != '/') - path += '/'; - } - path += name; - if (!isValid()) { - path = save; - return false; - } - return true; -} - -bool -Path::eraseComponent() { - size_t slashpos = path.rfind('/',path.size()); - if (slashpos == path.size() - 1 || slashpos == std::string::npos) - return false; - std::string save(path); - path.erase(slashpos); - if (!isValid()) { - path = save; - return false; - } - return true; -} - -bool -Path::appendSuffix(StringRef suffix) { - std::string save(path); - path.append("."); - path.append(suffix); - if (!isValid()) { - path = save; - return false; - } - return true; -} - -bool -Path::eraseSuffix() { - size_t dotpos = path.rfind('.',path.size()); - size_t slashpos = path.rfind('/',path.size()); - if (dotpos != std::string::npos) { - if (slashpos == std::string::npos || dotpos > slashpos+1) { - std::string save(path); - path.erase(dotpos, path.size()-dotpos); - if (!isValid()) { - path = save; - return false; - } - return true; - } - } - return false; -} - -inline bool PathMsg(std::string* ErrMsg, const char* pathname, const char*msg) { - if (ErrMsg) - *ErrMsg = std::string(pathname) + ": " + std::string(msg); - return true; -} - -bool -Path::createDirectoryOnDisk(bool create_parents, std::string* ErrMsg) { - // Get a writeable copy of the path name - size_t len = path.length(); - char *pathname = reinterpret_cast(_alloca(len+2)); - path.copy(pathname, len); - pathname[len] = 0; - - // Make sure it ends with a slash. - if (len == 0 || pathname[len - 1] != '/') { - pathname[len] = '/'; - pathname[++len] = 0; - } - - // Determine starting point for initial / search. - char *next = pathname; - if (pathname[0] == '/' && pathname[1] == '/') { - // Skip host name. - next = strchr(pathname+2, '/'); - if (next == NULL) - return PathMsg(ErrMsg, pathname, "badly formed remote directory"); - - // Skip share name. - next = strchr(next+1, '/'); - if (next == NULL) - return PathMsg(ErrMsg, pathname,"badly formed remote directory"); - - next++; - if (*next == 0) - return PathMsg(ErrMsg, pathname, "badly formed remote directory"); - - } else { - if (pathname[1] == ':') - next += 2; // skip drive letter - if (*next == '/') - next++; // skip root directory - } - - // If we're supposed to create intermediate directories - if (create_parents) { - // Loop through the directory components until we're done - while (*next) { - next = strchr(next, '/'); - *next = 0; - if (!CreateDirectory(pathname, NULL) && - GetLastError() != ERROR_ALREADY_EXISTS) - return MakeErrMsg(ErrMsg, - std::string(pathname) + ": Can't create directory: "); - *next++ = '/'; - } - } else { - // Drop trailing slash. - pathname[len-1] = 0; - if (!CreateDirectory(pathname, NULL) && - GetLastError() != ERROR_ALREADY_EXISTS) { - return MakeErrMsg(ErrMsg, std::string(pathname) + ": Can't create directory: "); - } - } - return false; -} - -bool -Path::createFileOnDisk(std::string* ErrMsg) { - // Create the file - HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, - FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) - return MakeErrMsg(ErrMsg, path + ": Can't create file: "); - - CloseHandle(h); - return false; -} - -bool -Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const { - WIN32_FILE_ATTRIBUTE_DATA fi; - if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) - return true; - - if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - // If it doesn't exist, we're done. - if (!exists()) - return false; - - char *pathname = reinterpret_cast(_alloca(path.length()+3)); - int lastchar = path.length() - 1 ; - path.copy(pathname, lastchar+1); - - // Make path end with '/*'. - if (pathname[lastchar] != '/') - pathname[++lastchar] = '/'; - pathname[lastchar+1] = '*'; - pathname[lastchar+2] = 0; - - if (remove_contents) { - WIN32_FIND_DATA fd; - HANDLE h = FindFirstFile(pathname, &fd); - - // It's a bad idea to alter the contents of a directory while enumerating - // its contents. So build a list of its contents first, then destroy them. - - if (h != INVALID_HANDLE_VALUE) { - std::vector list; - - do { - if (strcmp(fd.cFileName, ".") == 0) - continue; - if (strcmp(fd.cFileName, "..") == 0) - continue; - - Path aPath(path); - aPath.appendComponent(&fd.cFileName[0]); - list.push_back(aPath); - } while (FindNextFile(h, &fd)); - - DWORD err = GetLastError(); - FindClose(h); - if (err != ERROR_NO_MORE_FILES) { - SetLastError(err); - return MakeErrMsg(ErrStr, path + ": Can't read directory: "); - } - - for (std::vector::iterator I = list.begin(); I != list.end(); - ++I) { - Path &aPath = *I; - aPath.eraseFromDisk(true); - } - } else { - if (GetLastError() != ERROR_FILE_NOT_FOUND) - return MakeErrMsg(ErrStr, path + ": Can't read directory: "); - } - } - - pathname[lastchar] = 0; - if (!RemoveDirectory(pathname)) - return MakeErrMsg(ErrStr, - std::string(pathname) + ": Can't destroy directory: "); - return false; - } else { - // Read-only files cannot be deleted on Windows. Must remove the read-only - // attribute first. - if (fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { - if (!SetFileAttributes(path.c_str(), - fi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)) - return MakeErrMsg(ErrStr, path + ": Can't destroy file: "); - } - - if (!DeleteFile(path.c_str())) - return MakeErrMsg(ErrStr, path + ": Can't destroy file: "); - return false; - } -} - -bool Path::getMagicNumber(std::string& Magic, unsigned len) const { - assert(len < 1024 && "Request for magic string too long"); - char* buf = reinterpret_cast(alloca(len)); - - HANDLE h = CreateFile(path.c_str(), - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - if (h == INVALID_HANDLE_VALUE) - return false; - - DWORD nRead = 0; - BOOL ret = ReadFile(h, buf, len, &nRead, NULL); - CloseHandle(h); - - if (!ret || nRead != len) - return false; - - Magic = std::string(buf, len); - return true; -} - -bool -Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) { - if (!MoveFileEx(path.c_str(), newName.c_str(), MOVEFILE_REPLACE_EXISTING)) - return MakeErrMsg(ErrMsg, "Can't move '" + path + "' to '" + newName.path - + "': "); - return false; -} - -bool -Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrMsg) const { - // FIXME: should work on directories also. - if (!si.isFile) { - return true; - } - - HANDLE h = CreateFile(path.c_str(), - FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); - if (h == INVALID_HANDLE_VALUE) - return true; - - BY_HANDLE_FILE_INFORMATION bhfi; - if (!GetFileInformationByHandle(h, &bhfi)) { - DWORD err = GetLastError(); - CloseHandle(h); - SetLastError(err); - return MakeErrMsg(ErrMsg, path + ": GetFileInformationByHandle: "); - } - - ULARGE_INTEGER ui; - ui.QuadPart = si.modTime.toWin32Time(); - FILETIME ft; - ft.dwLowDateTime = ui.LowPart; - ft.dwHighDateTime = ui.HighPart; - BOOL ret = SetFileTime(h, NULL, &ft, &ft); - DWORD err = GetLastError(); - CloseHandle(h); - if (!ret) { - SetLastError(err); - return MakeErrMsg(ErrMsg, path + ": SetFileTime: "); - } - - // Best we can do with Unix permission bits is to interpret the owner - // writable bit. - if (si.mode & 0200) { - if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { - if (!SetFileAttributes(path.c_str(), - bhfi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)) - return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: "); - } - } else { - if (!(bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) { - if (!SetFileAttributes(path.c_str(), - bhfi.dwFileAttributes | FILE_ATTRIBUTE_READONLY)) - return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: "); - } - } - - return false; -} - -bool -CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg) { - // Can't use CopyFile macro defined in Windows.h because it would mess up the - // above line. We use the expansion it would have in a non-UNICODE build. - if (!::CopyFileA(Src.c_str(), Dest.c_str(), false)) - return MakeErrMsg(ErrMsg, "Can't copy '" + Src.str() + - "' to '" + Dest.str() + "': "); - return false; -} - -bool -Path::makeUnique(bool reuse_current, std::string* ErrMsg) { - if (reuse_current && !exists()) - return false; // File doesn't exist already, just use it! - - // Reserve space for -XXXXXX at the end. - char *FNBuffer = (char*) alloca(path.size()+8); - unsigned offset = path.size(); - path.copy(FNBuffer, offset); - - // Find a numeric suffix that isn't used by an existing file. Assume there - // won't be more than 1 million files with the same prefix. Probably a safe - // bet. - static unsigned FCounter = 0; - do { - sprintf(FNBuffer+offset, "-%06u", FCounter); - if (++FCounter > 999999) - FCounter = 0; - path = FNBuffer; - } while (exists()); - return false; -} - -bool -Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) { - // Make this into a unique file name - makeUnique(reuse_current, ErrMsg); - - // Now go and create it - HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, - FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) - return MakeErrMsg(ErrMsg, path + ": can't create file"); - - CloseHandle(h); - return false; -} - -/// MapInFilePages - Not yet implemented on win32. -const char *Path::MapInFilePages(int FD, uint64_t FileSize) { - return 0; -} - -/// MapInFilePages - Not yet implemented on win32. -void Path::UnMapFilePages(const char *Base, uint64_t FileSize) { - assert(0 && "NOT IMPLEMENTED"); -} - -} -} diff --git a/lib/System/Win32/Process.inc b/lib/System/Win32/Process.inc deleted file mode 100644 index feb0806116e4..000000000000 --- a/lib/System/Win32/Process.inc +++ /dev/null @@ -1,221 +0,0 @@ -//===- Win32/Process.cpp - Win32 Process Implementation ------- -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file provides the Win32 specific implementation of the Process class. -// -//===----------------------------------------------------------------------===// - -#include "Win32.h" -#include -#include -#include - -#ifdef __MINGW32__ - #if (HAVE_LIBPSAPI != 1) - #error "libpsapi.a should be present" - #endif -#else - #pragma comment(lib, "psapi.lib") -#endif - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only Win32 specific code -//=== and must not be UNIX code -//===----------------------------------------------------------------------===// - -#ifdef __MINGW32__ -// This ban should be lifted when MinGW 1.0+ has defined this value. -# define _HEAPOK (-2) -#endif - -namespace llvm { -using namespace sys; - -// This function retrieves the page size using GetSystemInfo and is present -// solely so it can be called once in Process::GetPageSize to initialize the -// static variable PageSize. -inline unsigned GetPageSizeOnce() { - // NOTE: A 32-bit application running under WOW64 is supposed to use - // GetNativeSystemInfo. However, this interface is not present prior - // to Windows XP so to use it requires dynamic linking. It is not clear - // how this affects the reported page size, if at all. One could argue - // that LLVM ought to run as 64-bits on a 64-bit system, anyway. - SYSTEM_INFO info; - GetSystemInfo(&info); - return static_cast(info.dwPageSize); -} - -unsigned -Process::GetPageSize() { - static const unsigned PageSize = GetPageSizeOnce(); - return PageSize; -} - -size_t -Process::GetMallocUsage() -{ - _HEAPINFO hinfo; - hinfo._pentry = NULL; - - size_t size = 0; - - while (_heapwalk(&hinfo) == _HEAPOK) - size += hinfo._size; - - return size; -} - -size_t -Process::GetTotalMemoryUsage() -{ - PROCESS_MEMORY_COUNTERS pmc; - GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)); - return pmc.PagefileUsage; -} - -void -Process::GetTimeUsage( - TimeValue& elapsed, TimeValue& user_time, TimeValue& sys_time) -{ - elapsed = TimeValue::now(); - - uint64_t ProcCreate, ProcExit, KernelTime, UserTime; - GetProcessTimes(GetCurrentProcess(), (FILETIME*)&ProcCreate, - (FILETIME*)&ProcExit, (FILETIME*)&KernelTime, - (FILETIME*)&UserTime); - - // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond) - user_time.seconds( UserTime / 10000000 ); - user_time.nanoseconds( unsigned(UserTime % 10000000) * 100 ); - sys_time.seconds( KernelTime / 10000000 ); - sys_time.nanoseconds( unsigned(KernelTime % 10000000) * 100 ); -} - -int Process::GetCurrentUserId() -{ - return 65536; -} - -int Process::GetCurrentGroupId() -{ - return 65536; -} - -// Some LLVM programs such as bugpoint produce core files as a normal part of -// their operation. To prevent the disk from filling up, this configuration item -// does what's necessary to prevent their generation. -void Process::PreventCoreFiles() { - // Windows doesn't do core files, but it does do modal pop-up message - // boxes. As this method is used by bugpoint, preventing these pop-ups - // is the moral equivalent of suppressing core files. - SetErrorMode(SEM_FAILCRITICALERRORS | - SEM_NOGPFAULTERRORBOX | - SEM_NOOPENFILEERRORBOX); -} - -bool Process::StandardInIsUserInput() { - return FileDescriptorIsDisplayed(0); -} - -bool Process::StandardOutIsDisplayed() { - return FileDescriptorIsDisplayed(1); -} - -bool Process::StandardErrIsDisplayed() { - return FileDescriptorIsDisplayed(2); -} - -bool Process::FileDescriptorIsDisplayed(int fd) { - return GetFileType((HANDLE)_get_osfhandle(fd)) == FILE_TYPE_CHAR; -} - -unsigned Process::StandardOutColumns() { - unsigned Columns = 0; - CONSOLE_SCREEN_BUFFER_INFO csbi; - if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) - Columns = csbi.dwSize.X; - return Columns; -} - -unsigned Process::StandardErrColumns() { - unsigned Columns = 0; - CONSOLE_SCREEN_BUFFER_INFO csbi; - if (GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi)) - Columns = csbi.dwSize.X; - return Columns; -} - -// It always has colors. -bool Process::StandardErrHasColors() { - return StandardErrIsDisplayed(); -} - -bool Process::StandardOutHasColors() { - return StandardOutIsDisplayed(); -} - -namespace { -class DefaultColors -{ - private: - WORD defaultColor; - public: - DefaultColors() - :defaultColor(GetCurrentColor()) {} - static unsigned GetCurrentColor() { - CONSOLE_SCREEN_BUFFER_INFO csbi; - if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) - return csbi.wAttributes; - return 0; - } - WORD operator()() const { return defaultColor; } -}; - -DefaultColors defaultColors; -} - -bool Process::ColorNeedsFlush() { - return true; -} - -const char *Process::OutputBold(bool bg) { - WORD colors = DefaultColors::GetCurrentColor(); - if (bg) - colors |= BACKGROUND_INTENSITY; - else - colors |= FOREGROUND_INTENSITY; - SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); - return 0; -} - -const char *Process::OutputColor(char code, bool bold, bool bg) { - WORD colors; - if (bg) { - colors = ((code&1) ? BACKGROUND_RED : 0) | - ((code&2) ? BACKGROUND_GREEN : 0 ) | - ((code&4) ? BACKGROUND_BLUE : 0); - if (bold) - colors |= BACKGROUND_INTENSITY; - } else { - colors = ((code&1) ? FOREGROUND_RED : 0) | - ((code&2) ? FOREGROUND_GREEN : 0 ) | - ((code&4) ? FOREGROUND_BLUE : 0); - if (bold) - colors |= FOREGROUND_INTENSITY; - } - SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); - return 0; -} - -const char *Process::ResetColor() { - SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors()); - return 0; -} - -} diff --git a/lib/System/Win32/Program.inc b/lib/System/Win32/Program.inc deleted file mode 100644 index 16bb28e17a21..000000000000 --- a/lib/System/Win32/Program.inc +++ /dev/null @@ -1,409 +0,0 @@ -//===- Win32/Program.cpp - Win32 Program Implementation ------- -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file provides the Win32 specific implementation of the Program class. -// -//===----------------------------------------------------------------------===// - -#include "Win32.h" -#include -#include -#include -#include - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only Win32 specific code -//=== and must not be UNIX code -//===----------------------------------------------------------------------===// - -namespace { - struct Win32ProcessInfo { - HANDLE hProcess; - DWORD dwProcessId; - }; -} - -namespace llvm { -using namespace sys; - -Program::Program() : Data_(0) {} - -Program::~Program() { - if (Data_) { - Win32ProcessInfo* wpi = reinterpret_cast(Data_); - CloseHandle(wpi->hProcess); - delete wpi; - Data_ = 0; - } -} - -unsigned Program::GetPid() const { - Win32ProcessInfo* wpi = reinterpret_cast(Data_); - return wpi->dwProcessId; -} - -// This function just uses the PATH environment variable to find the program. -Path -Program::FindProgramByName(const std::string& progName) { - - // Check some degenerate cases - if (progName.length() == 0) // no program - return Path(); - Path temp; - if (!temp.set(progName)) // invalid name - return Path(); - if (temp.canExecute()) // already executable as is - return temp; - - // At this point, the file name is valid and its not executable. - // Let Windows search for it. - char buffer[MAX_PATH]; - char *dummy = NULL; - DWORD len = SearchPath(NULL, progName.c_str(), ".exe", MAX_PATH, - buffer, &dummy); - - // See if it wasn't found. - if (len == 0) - return Path(); - - // See if we got the entire path. - if (len < MAX_PATH) - return Path(buffer); - - // Buffer was too small; grow and retry. - while (true) { - char *b = reinterpret_cast(_alloca(len+1)); - DWORD len2 = SearchPath(NULL, progName.c_str(), ".exe", len+1, b, &dummy); - - // It is unlikely the search failed, but it's always possible some file - // was added or removed since the last search, so be paranoid... - if (len2 == 0) - return Path(); - else if (len2 <= len) - return Path(b); - - len = len2; - } -} - -static HANDLE RedirectIO(const Path *path, int fd, std::string* ErrMsg) { - HANDLE h; - if (path == 0) { - DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), - GetCurrentProcess(), &h, - 0, TRUE, DUPLICATE_SAME_ACCESS); - return h; - } - - const char *fname; - if (path->isEmpty()) - fname = "NUL"; - else - fname = path->c_str(); - - SECURITY_ATTRIBUTES sa; - sa.nLength = sizeof(sa); - sa.lpSecurityDescriptor = 0; - sa.bInheritHandle = TRUE; - - h = CreateFile(fname, fd ? GENERIC_WRITE : GENERIC_READ, FILE_SHARE_READ, - &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) { - MakeErrMsg(ErrMsg, std::string(fname) + ": Can't open file for " + - (fd ? "input: " : "output: ")); - } - - return h; -} - -#ifdef __MINGW32__ - // Due to unknown reason, mingw32's w32api doesn't have this declaration. - extern "C" - BOOL WINAPI SetInformationJobObject(HANDLE hJob, - JOBOBJECTINFOCLASS JobObjectInfoClass, - LPVOID lpJobObjectInfo, - DWORD cbJobObjectInfoLength); -#endif - -/// ArgNeedsQuotes - Check whether argument needs to be quoted when calling -/// CreateProcess. -static bool ArgNeedsQuotes(const char *Str) { - return Str[0] == '\0' || strchr(Str, ' ') != 0; -} - - -/// ArgLenWithQuotes - Check whether argument needs to be quoted when calling -/// CreateProcess and returns length of quoted arg with escaped quotes -static unsigned int ArgLenWithQuotes(const char *Str) { - unsigned int len = ArgNeedsQuotes(Str) ? 2 : 0; - - while (*Str != '\0') { - if (*Str == '\"') - ++len; - - ++len; - ++Str; - } - - return len; -} - - -bool -Program::Execute(const Path& path, - const char** args, - const char** envp, - const Path** redirects, - unsigned memoryLimit, - std::string* ErrMsg) { - if (Data_) { - Win32ProcessInfo* wpi = reinterpret_cast(Data_); - CloseHandle(wpi->hProcess); - delete wpi; - Data_ = 0; - } - - if (!path.canExecute()) { - if (ErrMsg) - *ErrMsg = "program not executable"; - return false; - } - - // Windows wants a command line, not an array of args, to pass to the new - // process. We have to concatenate them all, while quoting the args that - // have embedded spaces (or are empty). - - // First, determine the length of the command line. - unsigned len = 0; - for (unsigned i = 0; args[i]; i++) { - len += ArgLenWithQuotes(args[i]) + 1; - } - - // Now build the command line. - char *command = reinterpret_cast(_alloca(len+1)); - char *p = command; - - for (unsigned i = 0; args[i]; i++) { - const char *arg = args[i]; - - bool needsQuoting = ArgNeedsQuotes(arg); - if (needsQuoting) - *p++ = '"'; - - while (*arg != '\0') { - if (*arg == '\"') - *p++ = '\\'; - - *p++ = *arg++; - } - - if (needsQuoting) - *p++ = '"'; - *p++ = ' '; - } - - *p = 0; - - // The pointer to the environment block for the new process. - char *envblock = 0; - - if (envp) { - // An environment block consists of a null-terminated block of - // null-terminated strings. Convert the array of environment variables to - // an environment block by concatenating them. - - // First, determine the length of the environment block. - len = 0; - for (unsigned i = 0; envp[i]; i++) - len += strlen(envp[i]) + 1; - - // Now build the environment block. - envblock = reinterpret_cast(_alloca(len+1)); - p = envblock; - - for (unsigned i = 0; envp[i]; i++) { - const char *ev = envp[i]; - size_t len = strlen(ev) + 1; - memcpy(p, ev, len); - p += len; - } - - *p = 0; - } - - // Create a child process. - STARTUPINFO si; - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - si.hStdInput = INVALID_HANDLE_VALUE; - si.hStdOutput = INVALID_HANDLE_VALUE; - si.hStdError = INVALID_HANDLE_VALUE; - - if (redirects) { - si.dwFlags = STARTF_USESTDHANDLES; - - si.hStdInput = RedirectIO(redirects[0], 0, ErrMsg); - if (si.hStdInput == INVALID_HANDLE_VALUE) { - MakeErrMsg(ErrMsg, "can't redirect stdin"); - return false; - } - si.hStdOutput = RedirectIO(redirects[1], 1, ErrMsg); - if (si.hStdOutput == INVALID_HANDLE_VALUE) { - CloseHandle(si.hStdInput); - MakeErrMsg(ErrMsg, "can't redirect stdout"); - return false; - } - if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) { - // If stdout and stderr should go to the same place, redirect stderr - // to the handle already open for stdout. - DuplicateHandle(GetCurrentProcess(), si.hStdOutput, - GetCurrentProcess(), &si.hStdError, - 0, TRUE, DUPLICATE_SAME_ACCESS); - } else { - // Just redirect stderr - si.hStdError = RedirectIO(redirects[2], 2, ErrMsg); - if (si.hStdError == INVALID_HANDLE_VALUE) { - CloseHandle(si.hStdInput); - CloseHandle(si.hStdOutput); - MakeErrMsg(ErrMsg, "can't redirect stderr"); - return false; - } - } - } - - PROCESS_INFORMATION pi; - memset(&pi, 0, sizeof(pi)); - - fflush(stdout); - fflush(stderr); - BOOL rc = CreateProcess(path.c_str(), command, NULL, NULL, TRUE, 0, - envblock, NULL, &si, &pi); - DWORD err = GetLastError(); - - // Regardless of whether the process got created or not, we are done with - // the handles we created for it to inherit. - CloseHandle(si.hStdInput); - CloseHandle(si.hStdOutput); - CloseHandle(si.hStdError); - - // Now return an error if the process didn't get created. - if (!rc) { - SetLastError(err); - MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") + - path.str() + "'"); - return false; - } - Win32ProcessInfo* wpi = new Win32ProcessInfo; - wpi->hProcess = pi.hProcess; - wpi->dwProcessId = pi.dwProcessId; - Data_ = wpi; - - // Make sure these get closed no matter what. - AutoHandle hThread(pi.hThread); - - // Assign the process to a job if a memory limit is defined. - AutoHandle hJob(0); - if (memoryLimit != 0) { - hJob = CreateJobObject(0, 0); - bool success = false; - if (hJob != 0) { - JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; - memset(&jeli, 0, sizeof(jeli)); - jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY; - jeli.ProcessMemoryLimit = uintptr_t(memoryLimit) * 1048576; - if (SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, - &jeli, sizeof(jeli))) { - if (AssignProcessToJobObject(hJob, pi.hProcess)) - success = true; - } - } - if (!success) { - SetLastError(GetLastError()); - MakeErrMsg(ErrMsg, std::string("Unable to set memory limit")); - TerminateProcess(pi.hProcess, 1); - WaitForSingleObject(pi.hProcess, INFINITE); - return false; - } - } - - return true; -} - -int -Program::Wait(unsigned secondsToWait, - std::string* ErrMsg) { - if (Data_ == 0) { - MakeErrMsg(ErrMsg, "Process not started!"); - return -1; - } - - Win32ProcessInfo* wpi = reinterpret_cast(Data_); - HANDLE hProcess = wpi->hProcess; - - // Wait for the process to terminate. - DWORD millisecondsToWait = INFINITE; - if (secondsToWait > 0) - millisecondsToWait = secondsToWait * 1000; - - if (WaitForSingleObject(hProcess, millisecondsToWait) == WAIT_TIMEOUT) { - if (!TerminateProcess(hProcess, 1)) { - MakeErrMsg(ErrMsg, "Failed to terminate timed-out program."); - return -1; - } - WaitForSingleObject(hProcess, INFINITE); - } - - // Get its exit status. - DWORD status; - BOOL rc = GetExitCodeProcess(hProcess, &status); - DWORD err = GetLastError(); - - if (!rc) { - SetLastError(err); - MakeErrMsg(ErrMsg, "Failed getting status for program."); - return -1; - } - - return status; -} - -bool -Program::Kill(std::string* ErrMsg) { - if (Data_ == 0) { - MakeErrMsg(ErrMsg, "Process not started!"); - return true; - } - - Win32ProcessInfo* wpi = reinterpret_cast(Data_); - HANDLE hProcess = wpi->hProcess; - if (TerminateProcess(hProcess, 1) == 0) { - MakeErrMsg(ErrMsg, "The process couldn't be killed!"); - return true; - } - - return false; -} - -bool Program::ChangeStdinToBinary(){ - int result = _setmode( _fileno(stdin), _O_BINARY ); - return result == -1; -} - -bool Program::ChangeStdoutToBinary(){ - int result = _setmode( _fileno(stdout), _O_BINARY ); - return result == -1; -} - -bool Program::ChangeStderrToBinary(){ - int result = _setmode( _fileno(stderr), _O_BINARY ); - return result == -1; -} - -} diff --git a/lib/System/Win32/RWMutex.inc b/lib/System/Win32/RWMutex.inc deleted file mode 100644 index e2692269e3a0..000000000000 --- a/lib/System/Win32/RWMutex.inc +++ /dev/null @@ -1,58 +0,0 @@ -//= llvm/System/Win32/Mutex.inc - Win32 Reader/Writer Mutual Exclusion Lock =// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Win32 specific (non-pthread) RWMutex class. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic Win32 code that -//=== is guaranteed to work on *all* Win32 variants. -//===----------------------------------------------------------------------===// - -#include "Win32.h" - -// FIXME: Windows does not have reader-writer locks pre-Vista. If you want -// real reader-writer locks, you a pthreads implementation for Windows. - -namespace llvm { -using namespace sys; - -RWMutexImpl::RWMutexImpl() { - data_ = calloc(1, sizeof(CRITICAL_SECTION)); - InitializeCriticalSection(static_cast(data_)); -} - -RWMutexImpl::~RWMutexImpl() { - DeleteCriticalSection(static_cast(data_)); - free(data_); -} - -bool RWMutexImpl::reader_acquire() { - EnterCriticalSection(static_cast(data_)); - return true; -} - -bool RWMutexImpl::reader_release() { - LeaveCriticalSection(static_cast(data_)); - return true; -} - -bool RWMutexImpl::writer_acquire() { - EnterCriticalSection(static_cast(data_)); - return true; -} - -bool RWMutexImpl::writer_release() { - LeaveCriticalSection(static_cast(data_)); - return true; -} - - -} diff --git a/lib/System/Win32/Signals.inc b/lib/System/Win32/Signals.inc deleted file mode 100644 index 2498a26ea99c..000000000000 --- a/lib/System/Win32/Signals.inc +++ /dev/null @@ -1,332 +0,0 @@ -//===- Win32/Signals.cpp - Win32 Signals Implementation ---------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file provides the Win32 specific implementation of the Signals class. -// -//===----------------------------------------------------------------------===// - -#include "Win32.h" -#include -#include -#include - -#ifdef __MINGW32__ - #include -#else - #include -#endif -#include - -#ifdef __MINGW32__ - #if ((HAVE_LIBIMAGEHLP != 1) || (HAVE_LIBPSAPI != 1)) - #error "libimagehlp.a & libpsapi.a should be present" - #endif -#else - #pragma comment(lib, "psapi.lib") - #pragma comment(lib, "dbghelp.lib") -#endif - -// Forward declare. -static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep); -static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType); - -// InterruptFunction - The function to call if ctrl-c is pressed. -static void (*InterruptFunction)() = 0; - -static std::vector *FilesToRemove = NULL; -static std::vector > *CallBacksToRun = 0; -static bool RegisteredUnhandledExceptionFilter = false; -static bool CleanupExecuted = false; -#ifdef _MSC_VER -static bool ExitOnUnhandledExceptions = false; -#endif -static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL; - -// Windows creates a new thread to execute the console handler when an event -// (such as CTRL/C) occurs. This causes concurrency issues with the above -// globals which this critical section addresses. -static CRITICAL_SECTION CriticalSection; - -namespace llvm { - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only Win32 specific code -//=== and must not be UNIX code -//===----------------------------------------------------------------------===// - -#ifdef _MSC_VER -/// CRTReportHook - Function called on a CRT debugging event. -static int CRTReportHook(int ReportType, char *Message, int *Return) { - // Don't cause a DebugBreak() on return. - if (Return) - *Return = 0; - - switch (ReportType) { - default: - case _CRT_ASSERT: - fprintf(stderr, "CRT assert: %s\n", Message); - // FIXME: Is there a way to just crash? Perhaps throw to the unhandled - // exception code? Perhaps SetErrorMode() handles this. - _exit(3); - break; - case _CRT_ERROR: - fprintf(stderr, "CRT error: %s\n", Message); - // FIXME: Is there a way to just crash? Perhaps throw to the unhandled - // exception code? Perhaps SetErrorMode() handles this. - _exit(3); - break; - case _CRT_WARN: - fprintf(stderr, "CRT warn: %s\n", Message); - break; - } - - // Don't call _CrtDbgReport. - return TRUE; -} -#endif - -static void RegisterHandler() { - if (RegisteredUnhandledExceptionFilter) { - EnterCriticalSection(&CriticalSection); - return; - } - - // Now's the time to create the critical section. This is the first time - // through here, and there's only one thread. - InitializeCriticalSection(&CriticalSection); - - // Enter it immediately. Now if someone hits CTRL/C, the console handler - // can't proceed until the globals are updated. - EnterCriticalSection(&CriticalSection); - - RegisteredUnhandledExceptionFilter = true; - OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter); - SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE); - - // Environment variable to disable any kind of crash dialog. -#ifdef _MSC_VER - if (getenv("LLVM_DISABLE_CRT_DEBUG")) { - _CrtSetReportHook(CRTReportHook); - ExitOnUnhandledExceptions = true; - } -#endif - - // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or - // else multi-threading problems will ensue. -} - -// RemoveFileOnSignal - The public API -bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) { - RegisterHandler(); - - if (CleanupExecuted) { - if (ErrMsg) - *ErrMsg = "Process terminating -- cannot register for removal"; - return true; - } - - if (FilesToRemove == NULL) - FilesToRemove = new std::vector; - - FilesToRemove->push_back(Filename); - - LeaveCriticalSection(&CriticalSection); - return false; -} - -// DontRemoveFileOnSignal - The public API -void sys::DontRemoveFileOnSignal(const sys::Path &Filename) { - if (FilesToRemove == NULL) - return; - - FilesToRemove->push_back(Filename); - std::vector::reverse_iterator I = - std::find(FilesToRemove->rbegin(), FilesToRemove->rend(), Filename); - if (I != FilesToRemove->rend()) - FilesToRemove->erase(I.base()-1); - - LeaveCriticalSection(&CriticalSection); -} - -/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or -/// SIGSEGV) is delivered to the process, print a stack trace and then exit. -void sys::PrintStackTraceOnErrorSignal() { - RegisterHandler(); - LeaveCriticalSection(&CriticalSection); -} - - -void sys::SetInterruptFunction(void (*IF)()) { - RegisterHandler(); - InterruptFunction = IF; - LeaveCriticalSection(&CriticalSection); -} - - -/// AddSignalHandler - Add a function to be called when a signal is delivered -/// to the process. The handler can have a cookie passed to it to identify -/// what instance of the handler it is. -void sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { - if (CallBacksToRun == 0) - CallBacksToRun = new std::vector >(); - CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie)); - RegisterHandler(); - LeaveCriticalSection(&CriticalSection); -} -} - -static void Cleanup() { - EnterCriticalSection(&CriticalSection); - - // Prevent other thread from registering new files and directories for - // removal, should we be executing because of the console handler callback. - CleanupExecuted = true; - - // FIXME: open files cannot be deleted. - - if (FilesToRemove != NULL) - while (!FilesToRemove->empty()) { - FilesToRemove->back().eraseFromDisk(); - FilesToRemove->pop_back(); - } - - if (CallBacksToRun) - for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i) - (*CallBacksToRun)[i].first((*CallBacksToRun)[i].second); - - LeaveCriticalSection(&CriticalSection); -} - -void llvm::sys::RunInterruptHandlers() { - Cleanup(); -} - -static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { - try { - Cleanup(); - -#ifdef _WIN64 - // TODO: provide a x64 friendly version of the following -#else - - // Initialize the STACKFRAME structure. - STACKFRAME StackFrame; - memset(&StackFrame, 0, sizeof(StackFrame)); - - StackFrame.AddrPC.Offset = ep->ContextRecord->Eip; - StackFrame.AddrPC.Mode = AddrModeFlat; - StackFrame.AddrStack.Offset = ep->ContextRecord->Esp; - StackFrame.AddrStack.Mode = AddrModeFlat; - StackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp; - StackFrame.AddrFrame.Mode = AddrModeFlat; - - HANDLE hProcess = GetCurrentProcess(); - HANDLE hThread = GetCurrentThread(); - - // Initialize the symbol handler. - SymSetOptions(SYMOPT_DEFERRED_LOADS|SYMOPT_LOAD_LINES); - SymInitialize(hProcess, NULL, TRUE); - - while (true) { - if (!StackWalk(IMAGE_FILE_MACHINE_I386, hProcess, hThread, &StackFrame, - ep->ContextRecord, NULL, SymFunctionTableAccess, - SymGetModuleBase, NULL)) { - break; - } - - if (StackFrame.AddrFrame.Offset == 0) - break; - - // Print the PC in hexadecimal. - DWORD PC = StackFrame.AddrPC.Offset; - fprintf(stderr, "%08lX", PC); - - // Print the parameters. Assume there are four. - fprintf(stderr, " (0x%08lX 0x%08lX 0x%08lX 0x%08lX)", StackFrame.Params[0], - StackFrame.Params[1], StackFrame.Params[2], StackFrame.Params[3]); - - // Verify the PC belongs to a module in this process. - if (!SymGetModuleBase(hProcess, PC)) { - fputs(" \n", stderr); - continue; - } - - // Print the symbol name. - char buffer[512]; - IMAGEHLP_SYMBOL *symbol = reinterpret_cast(buffer); - memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL)); - symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL); - symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL); - - DWORD dwDisp; - if (!SymGetSymFromAddr(hProcess, PC, &dwDisp, symbol)) { - fputc('\n', stderr); - continue; - } - - buffer[511] = 0; - if (dwDisp > 0) - fprintf(stderr, ", %s()+%04lu bytes(s)", symbol->Name, dwDisp); - else - fprintf(stderr, ", %s", symbol->Name); - - // Print the source file and line number information. - IMAGEHLP_LINE line; - memset(&line, 0, sizeof(line)); - line.SizeOfStruct = sizeof(line); - if (SymGetLineFromAddr(hProcess, PC, &dwDisp, &line)) { - fprintf(stderr, ", %s, line %lu", line.FileName, line.LineNumber); - if (dwDisp > 0) - fprintf(stderr, "+%04lu byte(s)", dwDisp); - } - - fputc('\n', stderr); - } - -#endif - - } catch (...) { - assert(0 && "Crashed in LLVMUnhandledExceptionFilter"); - } - -#ifdef _MSC_VER - if (ExitOnUnhandledExceptions) - _exit(-3); -#endif - - // Allow dialog box to pop up allowing choice to start debugger. - if (OldFilter) - return (*OldFilter)(ep); - else - return EXCEPTION_CONTINUE_SEARCH; -} - -static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) { - // We are running in our very own thread, courtesy of Windows. - EnterCriticalSection(&CriticalSection); - Cleanup(); - - // If an interrupt function has been set, go and run one it; otherwise, - // the process dies. - void (*IF)() = InterruptFunction; - InterruptFunction = 0; // Don't run it on another CTRL-C. - - if (IF) { - // Note: if the interrupt function throws an exception, there is nothing - // to catch it in this thread so it will kill the process. - IF(); // Run it now. - LeaveCriticalSection(&CriticalSection); - return TRUE; // Don't kill the process. - } - - // Allow normal processing to take place; i.e., the process dies. - LeaveCriticalSection(&CriticalSection); - return FALSE; -} - diff --git a/lib/System/Win32/ThreadLocal.inc b/lib/System/Win32/ThreadLocal.inc deleted file mode 100644 index b8b933c4d29d..000000000000 --- a/lib/System/Win32/ThreadLocal.inc +++ /dev/null @@ -1,53 +0,0 @@ -//= llvm/System/Win32/ThreadLocal.inc - Win32 Thread Local Data -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Win32 specific (non-pthread) ThreadLocal class. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic Win32 code that -//=== is guaranteed to work on *all* Win32 variants. -//===----------------------------------------------------------------------===// - -#include "Win32.h" -#include "llvm/System/ThreadLocal.h" - -namespace llvm { -using namespace sys; - -ThreadLocalImpl::ThreadLocalImpl() { - DWORD* tls = new DWORD; - *tls = TlsAlloc(); - assert(*tls != TLS_OUT_OF_INDEXES); - data = tls; -} - -ThreadLocalImpl::~ThreadLocalImpl() { - DWORD* tls = static_cast(data); - TlsFree(*tls); - delete tls; -} - -const void* ThreadLocalImpl::getInstance() { - DWORD* tls = static_cast(data); - return TlsGetValue(*tls); -} - -void ThreadLocalImpl::setInstance(const void* d){ - DWORD* tls = static_cast(data); - int errorcode = TlsSetValue(*tls, const_cast(d)); - assert(errorcode != 0); -} - -void ThreadLocalImpl::removeInstance() { - setInstance(0); -} - -} diff --git a/lib/System/Win32/TimeValue.inc b/lib/System/Win32/TimeValue.inc deleted file mode 100644 index e37f111fc77c..000000000000 --- a/lib/System/Win32/TimeValue.inc +++ /dev/null @@ -1,51 +0,0 @@ -//===- Win32/TimeValue.cpp - Win32 TimeValue Implementation -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file provides the Win32 implementation of the TimeValue class. -// -//===----------------------------------------------------------------------===// - -#include "Win32.h" -#include - -namespace llvm { -using namespace sys; - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only Win32 specific code. -//===----------------------------------------------------------------------===// - -TimeValue TimeValue::now() { - uint64_t ft; - GetSystemTimeAsFileTime(reinterpret_cast(&ft)); - - TimeValue t(0, 0); - t.fromWin32Time(ft); - return t; -} - -std::string TimeValue::str() const { -#ifdef __MINGW32__ - // This ban may be lifted by either: - // (i) a future MinGW version other than 1.0 inherents the __time64_t type, or - // (ii) configure tests for either the time_t or __time64_t type. - time_t ourTime = time_t(this->toEpochTime()); - struct tm *lt = ::localtime(&ourTime); -#else - __time64_t ourTime = this->toEpochTime(); - struct tm *lt = ::_localtime64(&ourTime); -#endif - - char buffer[25]; - strftime(buffer, 25, "%a %b %d %H:%M:%S %Y", lt); - return std::string(buffer); -} - - -} diff --git a/lib/System/Win32/Win32.h b/lib/System/Win32/Win32.h deleted file mode 100644 index 8f505b1a6cdb..000000000000 --- a/lib/System/Win32/Win32.h +++ /dev/null @@ -1,57 +0,0 @@ -//===- Win32/Win32.h - Common Win32 Include File ----------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines things specific to Win32 implementations. -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only generic Win32 code that -//=== is guaranteed to work on *all* Win32 variants. -//===----------------------------------------------------------------------===// - -// Require at least Windows 2000 API. -#define _WIN32_WINNT 0x0500 - -#include "llvm/Config/config.h" // Get autoconf configuration settings -#include "windows.h" -#include -#include - -inline bool MakeErrMsg(std::string* ErrMsg, const std::string& prefix) { - if (!ErrMsg) - return true; - char *buffer = NULL; - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, - NULL, GetLastError(), 0, (LPSTR)&buffer, 1, NULL); - *ErrMsg = prefix + buffer; - LocalFree(buffer); - return true; -} - -class AutoHandle { - HANDLE handle; - -public: - AutoHandle(HANDLE h) : handle(h) {} - - ~AutoHandle() { - if (handle) - CloseHandle(handle); - } - - operator HANDLE() { - return handle; - } - - AutoHandle &operator=(HANDLE h) { - handle = h; - return *this; - } -}; diff --git a/lib/Target/ARM/ARM.h b/lib/Target/ARM/ARM.h index 271ca44c2b69..4679f7443bfc 100644 --- a/lib/Target/ARM/ARM.h +++ b/lib/Target/ARM/ARM.h @@ -15,6 +15,7 @@ #ifndef TARGET_ARM_H #define TARGET_ARM_H +#include "ARMBaseInfo.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Target/TargetMachine.h" #include @@ -25,97 +26,17 @@ class ARMBaseTargetMachine; class FunctionPass; class JITCodeEmitter; class formatted_raw_ostream; +class MCCodeEmitter; +class TargetAsmBackend; +class MachineInstr; +class ARMAsmPrinter; +class MCInst; -// Enums corresponding to ARM condition codes -namespace ARMCC { - // The CondCodes constants map directly to the 4-bit encoding of the - // condition field for predicated instructions. - enum CondCodes { // Meaning (integer) Meaning (floating-point) - EQ, // Equal Equal - NE, // Not equal Not equal, or unordered - HS, // Carry set >, ==, or unordered - LO, // Carry clear Less than - MI, // Minus, negative Less than - PL, // Plus, positive or zero >, ==, or unordered - VS, // Overflow Unordered - VC, // No overflow Not unordered - HI, // Unsigned higher Greater than, or unordered - LS, // Unsigned lower or same Less than or equal - GE, // Greater than or equal Greater than or equal - LT, // Less than Less than, or unordered - GT, // Greater than Greater than - LE, // Less than or equal <, ==, or unordered - AL // Always (unconditional) Always (unconditional) - }; +MCCodeEmitter *createARMMCCodeEmitter(const Target &, + TargetMachine &TM, + MCContext &Ctx); - inline static CondCodes getOppositeCondition(CondCodes CC) { - switch (CC) { - default: llvm_unreachable("Unknown condition code"); - case EQ: return NE; - case NE: return EQ; - case HS: return LO; - case LO: return HS; - case MI: return PL; - case PL: return MI; - case VS: return VC; - case VC: return VS; - case HI: return LS; - case LS: return HI; - case GE: return LT; - case LT: return GE; - case GT: return LE; - case LE: return GT; - } - } -} // namespace ARMCC - -inline static const char *ARMCondCodeToString(ARMCC::CondCodes CC) { - switch (CC) { - default: llvm_unreachable("Unknown condition code"); - case ARMCC::EQ: return "eq"; - case ARMCC::NE: return "ne"; - case ARMCC::HS: return "hs"; - case ARMCC::LO: return "lo"; - case ARMCC::MI: return "mi"; - case ARMCC::PL: return "pl"; - case ARMCC::VS: return "vs"; - case ARMCC::VC: return "vc"; - case ARMCC::HI: return "hi"; - case ARMCC::LS: return "ls"; - case ARMCC::GE: return "ge"; - case ARMCC::LT: return "lt"; - case ARMCC::GT: return "gt"; - case ARMCC::LE: return "le"; - case ARMCC::AL: return "al"; - } -} - -namespace ARM_MB { - // The Memory Barrier Option constants map directly to the 4-bit encoding of - // the option field for memory barrier operations. - enum MemBOpt { - ST = 14, - ISH = 11, - ISHST = 10, - NSH = 7, - NSHST = 6, - OSH = 3, - OSHST = 2 - }; - - inline static const char *MemBOptToString(unsigned val) { - switch (val) { - default: llvm_unreachable("Unknown memory opetion"); - case ST: return "st"; - case ISH: return "ish"; - case ISHST: return "ishst"; - case NSH: return "nsh"; - case NSHST: return "nshst"; - case OSH: return "osh"; - case OSHST: return "oshst"; - } - } -} // namespace ARM_MB +TargetAsmBackend *createARMAsmBackend(const Target &, const std::string &); FunctionPass *createARMISelDag(ARMBaseTargetMachine &TM, CodeGenOpt::Level OptLevel); @@ -127,23 +48,16 @@ FunctionPass *createARMLoadStoreOptimizationPass(bool PreAlloc = false); FunctionPass *createARMExpandPseudoPass(); FunctionPass *createARMGlobalMergePass(const TargetLowering* tli); FunctionPass *createARMConstantIslandPass(); -FunctionPass *createNEONPreAllocPass(); FunctionPass *createNEONMoveFixPass(); +FunctionPass *createMLxExpansionPass(); FunctionPass *createThumb2ITBlockPass(); FunctionPass *createThumb2SizeReductionPass(); extern Target TheARMTarget, TheThumbTarget; -} // end namespace llvm; - -// Defines symbolic names for ARM registers. This defines a mapping from -// register name to register number. -// -#include "ARMGenRegisterNames.inc" - -// Defines symbolic names for the ARM instructions. -// -#include "ARMGenInstrNames.inc" +void LowerARMMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI, + ARMAsmPrinter &AP); +} // end namespace llvm; #endif diff --git a/lib/Target/ARM/ARM.td b/lib/Target/ARM/ARM.td index d6a8f19724dc..bf4315fc6c3e 100644 --- a/lib/Target/ARM/ARM.td +++ b/lib/Target/ARM/ARM.td @@ -16,6 +16,7 @@ include "llvm/Target/Target.td" + //===----------------------------------------------------------------------===// // ARM Subtarget features. // @@ -32,6 +33,8 @@ def FeatureNoARM : SubtargetFeature<"noarm", "NoARM", "true", "Does not support ARM mode execution">; def FeatureFP16 : SubtargetFeature<"fp16", "HasFP16", "true", "Enable half-precision floating point">; +def FeatureD16 : SubtargetFeature<"d16", "HasD16", "true", + "Restrict VFP3 to 16 double registers">; def FeatureHWDiv : SubtargetFeature<"hwdiv", "HasHardwareDivide", "true", "Enable divide instructions">; def FeatureT2XtPk : SubtargetFeature<"t2xtpk", "HasT2ExtractPack", "true", @@ -43,14 +46,11 @@ def FeatureSlowFPBrcc : SubtargetFeature<"slow-fp-brcc", "SlowFPBrcc", "true", def FeatureVFPOnlySP : SubtargetFeature<"fp-only-sp", "FPOnlySP", "true", "Floating point unit supports single precision only">; -// Some processors have multiply-accumulate instructions that don't -// play nicely with other VFP instructions, and it's generally better +// Some processors have FP multiply-accumulate instructions that don't +// play nicely with other VFP / NEON instructions, and it's generally better // to just not use them. -// FIXME: Currently, this is only flagged for Cortex-A8. It may be true for -// others as well. We should do more benchmarking and confirm one way or -// the other. -def FeatureHasSlowVMLx : SubtargetFeature<"vmlx", "SlowVMLx", "true", - "Disable VFP MAC instructions">; +def FeatureHasSlowFPVMLx : SubtargetFeature<"slowfpvmlx", "SlowFPVMLx", "true", + "Disable VFP / NEON MAC instructions">; // Some processors benefit from using NEON instructions for scalar // single-precision FP operations. def FeatureNEONForFP : SubtargetFeature<"neonfp", "UseNEONForSinglePrecisionFP", @@ -61,6 +61,9 @@ def FeatureNEONForFP : SubtargetFeature<"neonfp", "UseNEONForSinglePrecisionFP", def FeaturePref32BitThumb : SubtargetFeature<"32bit", "Pref32BitThumb", "true", "Prefer 32-bit Thumb instrs">; +// Multiprocessing extension. +def FeatureMP : SubtargetFeature<"mp", "HasMPExtension", "true", + "Supports Multiprocessing extension">; // ARM architectures. def ArchV4T : SubtargetFeature<"v4t", "ARMArchVersion", "V4T", @@ -91,6 +94,18 @@ def ArchV7M : SubtargetFeature<"v7m", "ARMArchVersion", "V7M", include "ARMSchedule.td" +// ARM processor families. +def ProcOthers : SubtargetFeature<"others", "ARMProcFamily", "Others", + "One of the other ARM processor families">; +def ProcA8 : SubtargetFeature<"a8", "ARMProcFamily", "CortexA8", + "Cortex-A8 ARM processors", + [FeatureSlowFPBrcc, FeatureNEONForFP, + FeatureHasSlowFPVMLx, FeatureT2XtPk]>; +def ProcA9 : SubtargetFeature<"a9", "ARMProcFamily", "CortexA9", + "Cortex-A9 ARM processors", + [FeatureHasSlowFPVMLx, FeatureT2XtPk, + FeatureFP16]>; + class ProcNoItin Features> : Processor; @@ -135,25 +150,27 @@ def : ProcNoItin<"iwmmxt", [ArchV5TE]>; // V6 Processors. def : Processor<"arm1136j-s", ARMV6Itineraries, [ArchV6]>; def : Processor<"arm1136jf-s", ARMV6Itineraries, [ArchV6, FeatureVFP2, - FeatureHasSlowVMLx]>; + FeatureHasSlowFPVMLx]>; def : Processor<"arm1176jz-s", ARMV6Itineraries, [ArchV6]>; -def : Processor<"arm1176jzf-s", ARMV6Itineraries, [ArchV6, FeatureVFP2]>; +def : Processor<"arm1176jzf-s", ARMV6Itineraries, [ArchV6, FeatureVFP2, + FeatureHasSlowFPVMLx]>; def : Processor<"mpcorenovfp", ARMV6Itineraries, [ArchV6]>; -def : Processor<"mpcore", ARMV6Itineraries, [ArchV6, FeatureVFP2]>; +def : Processor<"mpcore", ARMV6Itineraries, [ArchV6, FeatureVFP2, + FeatureHasSlowFPVMLx]>; // V6M Processors. def : Processor<"cortex-m0", ARMV6Itineraries, [ArchV6M]>; // V6T2 Processors. def : Processor<"arm1156t2-s", ARMV6Itineraries, [ArchV6T2]>; -def : Processor<"arm1156t2f-s", ARMV6Itineraries, [ArchV6T2, FeatureVFP2]>; +def : Processor<"arm1156t2f-s", ARMV6Itineraries, [ArchV6T2, FeatureVFP2, + FeatureHasSlowFPVMLx]>; // V7 Processors. def : Processor<"cortex-a8", CortexA8Itineraries, - [ArchV7A, FeatureHasSlowVMLx, - FeatureSlowFPBrcc, FeatureNEONForFP, FeatureT2XtPk]>; + [ArchV7A, ProcA8]>; def : Processor<"cortex-a9", CortexA9Itineraries, - [ArchV7A, FeatureT2XtPk]>; + [ArchV7A, ProcA9]>; // V7M Processors. def : ProcNoItin<"cortex-m3", [ArchV7M]>; @@ -175,6 +192,17 @@ include "ARMInstrInfo.td" def ARMInstrInfo : InstrInfo; + +//===----------------------------------------------------------------------===// +// Assembly printer +//===----------------------------------------------------------------------===// +// ARM Uses the MC printer for asm output, so make sure the TableGen +// AsmWriter bits get associated with the correct class. +def ARMAsmWriter : AsmWriter { + string AsmWriterClassName = "InstPrinter"; + bit isMCAsmWriter = 1; +} + //===----------------------------------------------------------------------===// // Declare the target which we are implementing //===----------------------------------------------------------------------===// @@ -182,4 +210,6 @@ def ARMInstrInfo : InstrInfo; def ARM : Target { // Pull in Instruction Info: let InstructionSet = ARMInstrInfo; + + let AssemblyWriters = [ARMAsmWriter]; } diff --git a/lib/Target/ARM/ARMAddressingModes.h b/lib/Target/ARM/ARMAddressingModes.h index db481005b3a4..19fbf0548b02 100644 --- a/lib/Target/ARM/ARMAddressingModes.h +++ b/lib/Target/ARM/ARMAddressingModes.h @@ -50,6 +50,16 @@ namespace ARM_AM { } } + static inline unsigned getShiftOpcEncoding(ShiftOpc Op) { + switch (Op) { + default: assert(0 && "Unknown shift opc!"); + case ARM_AM::asr: return 2; + case ARM_AM::lsl: return 0; + case ARM_AM::lsr: return 1; + case ARM_AM::ror: return 3; + } + } + static inline ShiftOpc getShiftOpcForNode(SDValue N) { switch (N.getOpcode()) { default: return ARM_AM::no_shift; @@ -566,6 +576,8 @@ namespace ARM_AM { return Val; } + AMSubMode getLoadStoreMultipleSubMode(int Opcode); + } // end namespace ARM_AM } // end namespace llvm diff --git a/lib/Target/ARM/ARMAsmBackend.cpp b/lib/Target/ARM/ARMAsmBackend.cpp new file mode 100644 index 000000000000..ec23449d7d42 --- /dev/null +++ b/lib/Target/ARM/ARMAsmBackend.cpp @@ -0,0 +1,512 @@ +//===-- ARMAsmBackend.cpp - ARM Assembler Backend -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ARM.h" +#include "ARMAddressingModes.h" +#include "ARMFixupKinds.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCDirectives.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCMachObjectWriter.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/Object/MachOFormat.h" +#include "llvm/Support/ELF.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetAsmBackend.h" +#include "llvm/Target/TargetRegistry.h" +using namespace llvm; + +namespace { +class ARMMachObjectWriter : public MCMachObjectTargetWriter { +public: + ARMMachObjectWriter(bool Is64Bit, uint32_t CPUType, + uint32_t CPUSubtype) + : MCMachObjectTargetWriter(Is64Bit, CPUType, CPUSubtype, + /*UseAggressiveSymbolFolding=*/true) {} +}; + +class ARMELFObjectWriter : public MCELFObjectTargetWriter { +public: + ARMELFObjectWriter(Triple::OSType OSType) + : MCELFObjectTargetWriter(/*Is64Bit*/ false, OSType, ELF::EM_ARM, + /*HasRelocationAddend*/ false) {} +}; + +class ARMAsmBackend : public TargetAsmBackend { + bool isThumbMode; // Currently emitting Thumb code. +public: + ARMAsmBackend(const Target &T) : TargetAsmBackend(), isThumbMode(false) {} + + unsigned getNumFixupKinds() const { return ARM::NumTargetFixupKinds; } + + const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const { + const static MCFixupKindInfo Infos[ARM::NumTargetFixupKinds] = { +// This table *must* be in the order that the fixup_* kinds are defined in +// ARMFixupKinds.h. +// +// Name Offset (bits) Size (bits) Flags +{ "fixup_arm_ldst_pcrel_12", 1, 24, MCFixupKindInfo::FKF_IsPCRel }, +{ "fixup_t2_ldst_pcrel_12", 0, 32, MCFixupKindInfo::FKF_IsPCRel | + MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}, +{ "fixup_arm_pcrel_10", 1, 24, MCFixupKindInfo::FKF_IsPCRel }, +{ "fixup_t2_pcrel_10", 0, 32, MCFixupKindInfo::FKF_IsPCRel | + MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}, +{ "fixup_thumb_adr_pcrel_10",0, 8, MCFixupKindInfo::FKF_IsPCRel | + MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}, +{ "fixup_arm_adr_pcrel_12", 1, 24, MCFixupKindInfo::FKF_IsPCRel }, +{ "fixup_t2_adr_pcrel_12", 0, 32, MCFixupKindInfo::FKF_IsPCRel | + MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}, +{ "fixup_arm_condbranch", 0, 24, MCFixupKindInfo::FKF_IsPCRel }, +{ "fixup_arm_uncondbranch", 0, 24, MCFixupKindInfo::FKF_IsPCRel }, +{ "fixup_t2_condbranch", 0, 32, MCFixupKindInfo::FKF_IsPCRel }, +{ "fixup_t2_uncondbranch", 0, 32, MCFixupKindInfo::FKF_IsPCRel }, +{ "fixup_arm_thumb_br", 0, 16, MCFixupKindInfo::FKF_IsPCRel }, +{ "fixup_arm_thumb_bl", 0, 32, MCFixupKindInfo::FKF_IsPCRel }, +{ "fixup_arm_thumb_blx", 7, 21, MCFixupKindInfo::FKF_IsPCRel }, +{ "fixup_arm_thumb_cb", 0, 16, MCFixupKindInfo::FKF_IsPCRel }, +{ "fixup_arm_thumb_cp", 1, 8, MCFixupKindInfo::FKF_IsPCRel }, +{ "fixup_arm_thumb_bcc", 1, 8, MCFixupKindInfo::FKF_IsPCRel }, +// movw / movt: 16-bits immediate but scattered into two chunks 0 - 12, 16 - 19. +{ "fixup_arm_movt_hi16", 0, 20, 0 }, +{ "fixup_arm_movw_lo16", 0, 20, 0 }, +{ "fixup_t2_movt_hi16", 0, 20, 0 }, +{ "fixup_t2_movw_lo16", 0, 20, 0 }, +{ "fixup_arm_movt_hi16_pcrel", 0, 20, MCFixupKindInfo::FKF_IsPCRel }, +{ "fixup_arm_movw_lo16_pcrel", 0, 20, MCFixupKindInfo::FKF_IsPCRel }, +{ "fixup_t2_movt_hi16_pcrel", 0, 20, MCFixupKindInfo::FKF_IsPCRel }, +{ "fixup_t2_movw_lo16_pcrel", 0, 20, MCFixupKindInfo::FKF_IsPCRel }, + }; + + if (Kind < FirstTargetFixupKind) + return TargetAsmBackend::getFixupKindInfo(Kind); + + assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && + "Invalid kind!"); + return Infos[Kind - FirstTargetFixupKind]; + } + + bool MayNeedRelaxation(const MCInst &Inst) const; + + void RelaxInstruction(const MCInst &Inst, MCInst &Res) const; + + bool WriteNopData(uint64_t Count, MCObjectWriter *OW) const; + + void HandleAssemblerFlag(MCAssemblerFlag Flag) { + switch (Flag) { + default: break; + case MCAF_Code16: + setIsThumb(true); + break; + case MCAF_Code32: + setIsThumb(false); + break; + } + } + + unsigned getPointerSize() const { return 4; } + bool isThumb() const { return isThumbMode; } + void setIsThumb(bool it) { isThumbMode = it; } +}; +} // end anonymous namespace + +bool ARMAsmBackend::MayNeedRelaxation(const MCInst &Inst) const { + // FIXME: Thumb targets, different move constant targets.. + return false; +} + +void ARMAsmBackend::RelaxInstruction(const MCInst &Inst, MCInst &Res) const { + assert(0 && "ARMAsmBackend::RelaxInstruction() unimplemented"); + return; +} + +bool ARMAsmBackend::WriteNopData(uint64_t Count, MCObjectWriter *OW) const { + if (isThumb()) { + // FIXME: 0xbf00 is the ARMv7 value. For v6 and before, we'll need to + // use 0x46c0 (which is a 'mov r8, r8' insn). + uint64_t NumNops = Count / 2; + for (uint64_t i = 0; i != NumNops; ++i) + OW->Write16(0xbf00); + if (Count & 1) + OW->Write8(0); + return true; + } + // ARM mode + uint64_t NumNops = Count / 4; + for (uint64_t i = 0; i != NumNops; ++i) + OW->Write32(0xe1a00000); + switch (Count % 4) { + default: break; // No leftover bytes to write + case 1: OW->Write8(0); break; + case 2: OW->Write16(0); break; + case 3: OW->Write16(0); OW->Write8(0xa0); break; + } + + return true; +} + +static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) { + switch (Kind) { + default: + llvm_unreachable("Unknown fixup kind!"); + case FK_Data_1: + case FK_Data_2: + case FK_Data_4: + return Value; + case ARM::fixup_arm_movt_hi16: + case ARM::fixup_arm_movt_hi16_pcrel: + Value >>= 16; + // Fallthrough + case ARM::fixup_arm_movw_lo16: + case ARM::fixup_arm_movw_lo16_pcrel: { + unsigned Hi4 = (Value & 0xF000) >> 12; + unsigned Lo12 = Value & 0x0FFF; + // inst{19-16} = Hi4; + // inst{11-0} = Lo12; + Value = (Hi4 << 16) | (Lo12); + return Value; + } + case ARM::fixup_t2_movt_hi16: + case ARM::fixup_t2_movt_hi16_pcrel: + Value >>= 16; + // Fallthrough + case ARM::fixup_t2_movw_lo16: + case ARM::fixup_t2_movw_lo16_pcrel: { + unsigned Hi4 = (Value & 0xF000) >> 12; + unsigned i = (Value & 0x800) >> 11; + unsigned Mid3 = (Value & 0x700) >> 8; + unsigned Lo8 = Value & 0x0FF; + // inst{19-16} = Hi4; + // inst{26} = i; + // inst{14-12} = Mid3; + // inst{7-0} = Lo8; + Value = (Hi4 << 16) | (i << 26) | (Mid3 << 12) | (Lo8); + + uint64_t swapped = (Value & 0xFFFF0000) >> 16; + swapped |= (Value & 0x0000FFFF) << 16; + return swapped; + } + case ARM::fixup_arm_ldst_pcrel_12: + // ARM PC-relative values are offset by 8. + Value -= 4; + // FALLTHROUGH + case ARM::fixup_t2_ldst_pcrel_12: { + // Offset by 4, adjusted by two due to the half-word ordering of thumb. + Value -= 4; + bool isAdd = true; + if ((int64_t)Value < 0) { + Value = -Value; + isAdd = false; + } + assert ((Value < 4096) && "Out of range pc-relative fixup value!"); + Value |= isAdd << 23; + + // Same addressing mode as fixup_arm_pcrel_10, + // but with 16-bit halfwords swapped. + if (Kind == ARM::fixup_t2_ldst_pcrel_12) { + uint64_t swapped = (Value & 0xFFFF0000) >> 16; + swapped |= (Value & 0x0000FFFF) << 16; + return swapped; + } + + return Value; + } + case ARM::fixup_thumb_adr_pcrel_10: + return ((Value - 4) >> 2) & 0xff; + case ARM::fixup_arm_adr_pcrel_12: { + // ARM PC-relative values are offset by 8. + Value -= 8; + unsigned opc = 4; // bits {24-21}. Default to add: 0b0100 + if ((int64_t)Value < 0) { + Value = -Value; + opc = 2; // 0b0010 + } + assert(ARM_AM::getSOImmVal(Value) != -1 && + "Out of range pc-relative fixup value!"); + // Encode the immediate and shift the opcode into place. + return ARM_AM::getSOImmVal(Value) | (opc << 21); + } + + case ARM::fixup_t2_adr_pcrel_12: { + Value -= 4; + unsigned opc = 0; + if ((int64_t)Value < 0) { + Value = -Value; + opc = 5; + } + + uint32_t out = (opc << 21); + out |= (Value & 0x800) << 14; + out |= (Value & 0x700) << 4; + out |= (Value & 0x0FF); + + uint64_t swapped = (out & 0xFFFF0000) >> 16; + swapped |= (out & 0x0000FFFF) << 16; + return swapped; + } + + case ARM::fixup_arm_condbranch: + case ARM::fixup_arm_uncondbranch: + // These values don't encode the low two bits since they're always zero. + // Offset by 8 just as above. + return 0xffffff & ((Value - 8) >> 2); + case ARM::fixup_t2_uncondbranch: { + Value = Value - 4; + Value >>= 1; // Low bit is not encoded. + + uint32_t out = 0; + bool I = Value & 0x800000; + bool J1 = Value & 0x400000; + bool J2 = Value & 0x200000; + J1 ^= I; + J2 ^= I; + + out |= I << 26; // S bit + out |= !J1 << 13; // J1 bit + out |= !J2 << 11; // J2 bit + out |= (Value & 0x1FF800) << 5; // imm6 field + out |= (Value & 0x0007FF); // imm11 field + + uint64_t swapped = (out & 0xFFFF0000) >> 16; + swapped |= (out & 0x0000FFFF) << 16; + return swapped; + } + case ARM::fixup_t2_condbranch: { + Value = Value - 4; + Value >>= 1; // Low bit is not encoded. + + uint64_t out = 0; + out |= (Value & 0x80000) << 7; // S bit + out |= (Value & 0x40000) >> 7; // J2 bit + out |= (Value & 0x20000) >> 4; // J1 bit + out |= (Value & 0x1F800) << 5; // imm6 field + out |= (Value & 0x007FF); // imm11 field + + uint32_t swapped = (out & 0xFFFF0000) >> 16; + swapped |= (out & 0x0000FFFF) << 16; + return swapped; + } + case ARM::fixup_arm_thumb_bl: { + // The value doesn't encode the low bit (always zero) and is offset by + // four. The value is encoded into disjoint bit positions in the destination + // opcode. x = unchanged, I = immediate value bit, S = sign extension bit + // + // BL: xxxxxSIIIIIIIIII xxxxxIIIIIIIIIII + // + // Note that the halfwords are stored high first, low second; so we need + // to transpose the fixup value here to map properly. + unsigned isNeg = (int64_t(Value) < 0) ? 1 : 0; + uint32_t Binary = 0; + Value = 0x3fffff & ((Value - 4) >> 1); + Binary = (Value & 0x7ff) << 16; // Low imm11 value. + Binary |= (Value & 0x1ffc00) >> 11; // High imm10 value. + Binary |= isNeg << 10; // Sign bit. + return Binary; + } + case ARM::fixup_arm_thumb_blx: { + // The value doesn't encode the low two bits (always zero) and is offset by + // four (see fixup_arm_thumb_cp). The value is encoded into disjoint bit + // positions in the destination opcode. x = unchanged, I = immediate value + // bit, S = sign extension bit, 0 = zero. + // + // BLX: xxxxxSIIIIIIIIII xxxxxIIIIIIIIII0 + // + // Note that the halfwords are stored high first, low second; so we need + // to transpose the fixup value here to map properly. + unsigned isNeg = (int64_t(Value) < 0) ? 1 : 0; + uint32_t Binary = 0; + Value = 0xfffff & ((Value - 2) >> 2); + Binary = (Value & 0x3ff) << 17; // Low imm10L value. + Binary |= (Value & 0xffc00) >> 10; // High imm10H value. + Binary |= isNeg << 10; // Sign bit. + return Binary; + } + case ARM::fixup_arm_thumb_cp: + // Offset by 4, and don't encode the low two bits. Two bytes of that + // 'off by 4' is implicitly handled by the half-word ordering of the + // Thumb encoding, so we only need to adjust by 2 here. + return ((Value - 2) >> 2) & 0xff; + case ARM::fixup_arm_thumb_cb: { + // Offset by 4 and don't encode the lower bit, which is always 0. + uint32_t Binary = (Value - 4) >> 1; + return ((Binary & 0x20) << 4) | ((Binary & 0x1f) << 3); + } + case ARM::fixup_arm_thumb_br: + // Offset by 4 and don't encode the lower bit, which is always 0. + return ((Value - 4) >> 1) & 0x7ff; + case ARM::fixup_arm_thumb_bcc: + // Offset by 4 and don't encode the lower bit, which is always 0. + return ((Value - 4) >> 1) & 0xff; + case ARM::fixup_arm_pcrel_10: + Value = Value - 4; // ARM fixups offset by an additional word and don't + // need to adjust for the half-word ordering. + // Fall through. + case ARM::fixup_t2_pcrel_10: { + // Offset by 4, adjusted by two due to the half-word ordering of thumb. + Value = Value - 4; + bool isAdd = true; + if ((int64_t)Value < 0) { + Value = -Value; + isAdd = false; + } + // These values don't encode the low two bits since they're always zero. + Value >>= 2; + assert ((Value < 256) && "Out of range pc-relative fixup value!"); + Value |= isAdd << 23; + + // Same addressing mode as fixup_arm_pcrel_10, + // but with 16-bit halfwords swapped. + if (Kind == ARM::fixup_t2_pcrel_10) { + uint32_t swapped = (Value & 0xFFFF0000) >> 16; + swapped |= (Value & 0x0000FFFF) << 16; + return swapped; + } + + return Value; + } + } +} + +namespace { + +// FIXME: This should be in a separate file. +// ELF is an ELF of course... +class ELFARMAsmBackend : public ARMAsmBackend { +public: + Triple::OSType OSType; + ELFARMAsmBackend(const Target &T, Triple::OSType _OSType) + : ARMAsmBackend(T), OSType(_OSType) { } + + void ApplyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, + uint64_t Value) const; + + MCObjectWriter *createObjectWriter(raw_ostream &OS) const { + return createELFObjectWriter(new ARMELFObjectWriter(OSType), OS, + /*IsLittleEndian*/ true); + } +}; + +// FIXME: Raise this to share code between Darwin and ELF. +void ELFARMAsmBackend::ApplyFixup(const MCFixup &Fixup, char *Data, + unsigned DataSize, uint64_t Value) const { + unsigned NumBytes = 4; // FIXME: 2 for Thumb + Value = adjustFixupValue(Fixup.getKind(), Value); + if (!Value) return; // Doesn't change encoding. + + unsigned Offset = Fixup.getOffset(); + assert(Offset % NumBytes == 0 && "Offset mod NumBytes is nonzero!"); + + // For each byte of the fragment that the fixup touches, mask in the bits from + // the fixup value. The Value has been "split up" into the appropriate + // bitfields above. + for (unsigned i = 0; i != NumBytes; ++i) + Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff); +} + +// FIXME: This should be in a separate file. +class DarwinARMAsmBackend : public ARMAsmBackend { +public: + DarwinARMAsmBackend(const Target &T) : ARMAsmBackend(T) { } + + void ApplyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, + uint64_t Value) const; + + MCObjectWriter *createObjectWriter(raw_ostream &OS) const { + // FIXME: Subtarget info should be derived. Force v7 for now. + return createMachObjectWriter(new ARMMachObjectWriter( + /*Is64Bit=*/false, + object::mach::CTM_ARM, + object::mach::CSARM_V7), + OS, + /*IsLittleEndian=*/true); + } + + virtual bool doesSectionRequireSymbols(const MCSection &Section) const { + return false; + } +}; + +/// getFixupKindNumBytes - The number of bytes the fixup may change. +static unsigned getFixupKindNumBytes(unsigned Kind) { + switch (Kind) { + default: + llvm_unreachable("Unknown fixup kind!"); + + case FK_Data_1: + case ARM::fixup_arm_thumb_bcc: + case ARM::fixup_arm_thumb_cp: + case ARM::fixup_thumb_adr_pcrel_10: + return 1; + + case FK_Data_2: + case ARM::fixup_arm_thumb_br: + case ARM::fixup_arm_thumb_cb: + return 2; + + case ARM::fixup_arm_ldst_pcrel_12: + case ARM::fixup_arm_pcrel_10: + case ARM::fixup_arm_adr_pcrel_12: + case ARM::fixup_arm_condbranch: + case ARM::fixup_arm_uncondbranch: + return 3; + + case FK_Data_4: + case ARM::fixup_t2_ldst_pcrel_12: + case ARM::fixup_t2_condbranch: + case ARM::fixup_t2_uncondbranch: + case ARM::fixup_t2_pcrel_10: + case ARM::fixup_t2_adr_pcrel_12: + case ARM::fixup_arm_thumb_bl: + case ARM::fixup_arm_thumb_blx: + case ARM::fixup_arm_movt_hi16: + case ARM::fixup_arm_movw_lo16: + case ARM::fixup_arm_movt_hi16_pcrel: + case ARM::fixup_arm_movw_lo16_pcrel: + case ARM::fixup_t2_movt_hi16: + case ARM::fixup_t2_movw_lo16: + case ARM::fixup_t2_movt_hi16_pcrel: + case ARM::fixup_t2_movw_lo16_pcrel: + return 4; + } +} + +void DarwinARMAsmBackend::ApplyFixup(const MCFixup &Fixup, char *Data, + unsigned DataSize, uint64_t Value) const { + unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind()); + Value = adjustFixupValue(Fixup.getKind(), Value); + if (!Value) return; // Doesn't change encoding. + + unsigned Offset = Fixup.getOffset(); + assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!"); + + // For each byte of the fragment that the fixup touches, mask in the + // bits from the fixup value. + for (unsigned i = 0; i != NumBytes; ++i) + Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff); +} + +} // end anonymous namespace + +TargetAsmBackend *llvm::createARMAsmBackend(const Target &T, + const std::string &TT) { + switch (Triple(TT).getOS()) { + case Triple::Darwin: + return new DarwinARMAsmBackend(T); + case Triple::MinGW32: + case Triple::Cygwin: + case Triple::Win32: + assert(0 && "Windows not supported on ARM"); + default: + return new ELFARMAsmBackend(T, Triple(TT).getOS()); + } +} diff --git a/lib/Target/ARM/ARMAsmPrinter.cpp b/lib/Target/ARM/ARMAsmPrinter.cpp index 6cfd5961149f..db12b8e4fc2d 100644 --- a/lib/Target/ARM/ARMAsmPrinter.cpp +++ b/lib/Target/ARM/ARMAsmPrinter.cpp @@ -14,28 +14,31 @@ #define DEBUG_TYPE "asm-printer" #include "ARM.h" -#include "ARMBuildAttrs.h" +#include "ARMAsmPrinter.h" #include "ARMAddressingModes.h" +#include "ARMBuildAttrs.h" +#include "ARMBaseRegisterInfo.h" #include "ARMConstantPoolValue.h" -#include "AsmPrinter/ARMInstPrinter.h" #include "ARMMachineFunctionInfo.h" -#include "ARMMCInstLower.h" +#include "ARMMCExpr.h" #include "ARMTargetMachine.h" +#include "ARMTargetObjectFile.h" +#include "InstPrinter/ARMInstPrinter.h" #include "llvm/Analysis/DebugInfo.h" #include "llvm/Constants.h" #include "llvm/Module.h" #include "llvm/Type.h" #include "llvm/Assembly/Writer.h" -#include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" -#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCObjectStreamer.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Target/Mangler.h" @@ -53,270 +56,127 @@ #include using namespace llvm; -static cl::opt -EnableMCInst("enable-arm-mcinst-printer", cl::Hidden, - cl::desc("enable experimental asmprinter gunk in the arm backend")); - -namespace llvm { - namespace ARM { - enum DW_ISA { - DW_ISA_ARM_thumb = 1, - DW_ISA_ARM_arm = 2 - }; - } -} - namespace { - class ARMAsmPrinter : public AsmPrinter { - /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can - /// make the right decision when printing asm code for different targets. - const ARMSubtarget *Subtarget; - - /// AFI - Keep a pointer to ARMFunctionInfo for the current - /// MachineFunction. - ARMFunctionInfo *AFI; + // Per section and per symbol attributes are not supported. + // To implement them we would need the ability to delay this emission + // until the assembly file is fully parsed/generated as only then do we + // know the symbol and section numbers. + class AttributeEmitter { + public: + virtual void MaybeSwitchVendor(StringRef Vendor) = 0; + virtual void EmitAttribute(unsigned Attribute, unsigned Value) = 0; + virtual void EmitTextAttribute(unsigned Attribute, StringRef String) = 0; + virtual void Finish() = 0; + virtual ~AttributeEmitter() {} + }; - /// MCP - Keep a pointer to constantpool entries of the current - /// MachineFunction. - const MachineConstantPool *MCP; + class AsmAttributeEmitter : public AttributeEmitter { + MCStreamer &Streamer; public: - explicit ARMAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) - : AsmPrinter(TM, Streamer), AFI(NULL), MCP(NULL) { - Subtarget = &TM.getSubtarget(); - } + AsmAttributeEmitter(MCStreamer &Streamer_) : Streamer(Streamer_) {} + void MaybeSwitchVendor(StringRef Vendor) { } - virtual const char *getPassName() const { - return "ARM Assembly Printer"; + void EmitAttribute(unsigned Attribute, unsigned Value) { + Streamer.EmitRawText("\t.eabi_attribute " + + Twine(Attribute) + ", " + Twine(Value)); } - void printInstructionThroughMCStreamer(const MachineInstr *MI); - - - void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O, - const char *Modifier = 0); - void printSOImmOperand(const MachineInstr *MI, int OpNum, raw_ostream &O); - void printSOImm2PartOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printSORegOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printAddrMode2Operand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printAddrMode2OffsetOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printAddrMode3Operand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printAddrMode3OffsetOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printAddrMode4Operand(const MachineInstr *MI, int OpNum,raw_ostream &O, - const char *Modifier = 0); - void printAddrMode5Operand(const MachineInstr *MI, int OpNum,raw_ostream &O, - const char *Modifier = 0); - void printAddrMode6Operand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printAddrMode6OffsetOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printAddrModePCOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O, - const char *Modifier = 0); - void printBitfieldInvMaskImmOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printMemBOption(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printShiftImmOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - - void printThumbS4ImmOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printThumbITMask(const MachineInstr *MI, int OpNum, raw_ostream &O); - void printThumbAddrModeRROperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printThumbAddrModeRI5Operand(const MachineInstr *MI, int OpNum, - raw_ostream &O, - unsigned Scale); - void printThumbAddrModeS1Operand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printThumbAddrModeS2Operand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printThumbAddrModeS4Operand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printThumbAddrModeSPOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - - void printT2SOOperand(const MachineInstr *MI, int OpNum, raw_ostream &O); - void printT2AddrModeImm12Operand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printT2AddrModeImm8Operand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printT2AddrModeImm8s4Operand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printT2AddrModeImm8OffsetOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) {} - void printT2AddrModeSoRegOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - - void printCPSOptionOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) {} - void printMSRMaskOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) {} - void printNegZeroOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) {} - void printPredicateOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printMandatoryPredicateOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printSBitModifierOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printPCLabel(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printRegisterList(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printCPInstOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O, - const char *Modifier); - void printJTBlockOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printJT2BlockOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printTBAddrMode(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printNoHashImmediate(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printVFPf32ImmOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printVFPf64ImmOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - void printNEONModImmOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O); - - virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, - unsigned AsmVariant, const char *ExtraCode, - raw_ostream &O); - virtual bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, - unsigned AsmVariant, - const char *ExtraCode, raw_ostream &O); - - void printInstruction(const MachineInstr *MI, raw_ostream &O); // autogen - static const char *getRegisterName(unsigned RegNo); - - virtual void EmitInstruction(const MachineInstr *MI); - bool runOnMachineFunction(MachineFunction &F); - - virtual void EmitConstantPool() {} // we emit constant pools customly! - virtual void EmitFunctionEntryLabel(); - void EmitStartOfAsmFile(Module &M); - void EmitEndOfAsmFile(Module &M); - - MachineLocation getDebugValueLocation(const MachineInstr *MI) const { - MachineLocation Location; - assert (MI->getNumOperands() == 4 && "Invalid no. of machine operands!"); - // Frame address. Currently handles register +- offset only. - if (MI->getOperand(0).isReg() && MI->getOperand(1).isImm()) - Location.set(MI->getOperand(0).getReg(), MI->getOperand(1).getImm()); - else { - DEBUG(dbgs() << "DBG_VALUE instruction ignored! " << *MI << "\n"); + void EmitTextAttribute(unsigned Attribute, StringRef String) { + switch (Attribute) { + case ARMBuildAttrs::CPU_name: + Streamer.EmitRawText(StringRef("\t.cpu ") + LowercaseString(String)); + break; + default: assert(0 && "Unsupported Text attribute in ASM Mode"); break; } - return Location; + } + void Finish() { } + }; + + class ObjectAttributeEmitter : public AttributeEmitter { + MCObjectStreamer &Streamer; + StringRef CurrentVendor; + SmallString<64> Contents; + + public: + ObjectAttributeEmitter(MCObjectStreamer &Streamer_) : + Streamer(Streamer_), CurrentVendor("") { } + + void MaybeSwitchVendor(StringRef Vendor) { + assert(!Vendor.empty() && "Vendor cannot be empty."); + + if (CurrentVendor.empty()) + CurrentVendor = Vendor; + else if (CurrentVendor == Vendor) + return; + else + Finish(); + + CurrentVendor = Vendor; + + assert(Contents.size() == 0); } - virtual unsigned getISAEncoding() { - // ARM/Darwin adds ISA to the DWARF info for each function. - if (!Subtarget->isTargetDarwin()) - return 0; - return Subtarget->isThumb() ? - llvm::ARM::DW_ISA_ARM_thumb : llvm::ARM::DW_ISA_ARM_arm; + void EmitAttribute(unsigned Attribute, unsigned Value) { + // FIXME: should be ULEB + Contents += Attribute; + Contents += Value; } - MCSymbol *GetARMSetPICJumpTableLabel2(unsigned uid, unsigned uid2, - const MachineBasicBlock *MBB) const; - MCSymbol *GetARMJTIPICJumpTableLabel2(unsigned uid, unsigned uid2) const; - - /// EmitMachineConstantPoolValue - Print a machine constantpool value to - /// the .s file. - virtual void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) { - SmallString<128> Str; - raw_svector_ostream OS(Str); - EmitMachineConstantPoolValue(MCPV, OS); - OutStreamer.EmitRawText(OS.str()); + void EmitTextAttribute(unsigned Attribute, StringRef String) { + Contents += Attribute; + Contents += UppercaseString(String); + Contents += 0; } - void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV, - raw_ostream &O) { - switch (TM.getTargetData()->getTypeAllocSize(MCPV->getType())) { - case 1: O << MAI->getData8bitsDirective(0); break; - case 2: O << MAI->getData16bitsDirective(0); break; - case 4: O << MAI->getData32bitsDirective(0); break; - default: assert(0 && "Unknown CPV size"); - } + void Finish() { + const size_t ContentsSize = Contents.size(); - ARMConstantPoolValue *ACPV = static_cast(MCPV); - - if (ACPV->isLSDA()) { - O << MAI->getPrivateGlobalPrefix() << "_LSDA_" << getFunctionNumber(); - } else if (ACPV->isBlockAddress()) { - O << *GetBlockAddressSymbol(ACPV->getBlockAddress()); - } else if (ACPV->isGlobalValue()) { - const GlobalValue *GV = ACPV->getGV(); - bool isIndirect = Subtarget->isTargetDarwin() && - Subtarget->GVIsIndirectSymbol(GV, TM.getRelocationModel()); - if (!isIndirect) - O << *Mang->getSymbol(GV); - else { - // FIXME: Remove this when Darwin transition to @GOT like syntax. - MCSymbol *Sym = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); - O << *Sym; - - MachineModuleInfoMachO &MMIMachO = - MMI->getObjFileInfo(); - MachineModuleInfoImpl::StubValueTy &StubSym = - GV->hasHiddenVisibility() ? MMIMachO.getHiddenGVStubEntry(Sym) : - MMIMachO.getGVStubEntry(Sym); - if (StubSym.getPointer() == 0) - StubSym = MachineModuleInfoImpl:: - StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); - } - } else { - assert(ACPV->isExtSymbol() && "unrecognized constant pool value"); - O << *GetExternalSymbolSymbol(ACPV->getSymbol()); - } + // Vendor size + Vendor name + '\0' + const size_t VendorHeaderSize = 4 + CurrentVendor.size() + 1; - if (ACPV->hasModifier()) O << "(" << ACPV->getModifier() << ")"; - if (ACPV->getPCAdjustment() != 0) { - O << "-(" << MAI->getPrivateGlobalPrefix() << "PC" - << getFunctionNumber() << "_" << ACPV->getLabelId() - << "+" << (unsigned)ACPV->getPCAdjustment(); - if (ACPV->mustAddCurrentAddress()) - O << "-."; - O << ')'; - } + // Tag + Tag Size + const size_t TagHeaderSize = 1 + 4; + + Streamer.EmitIntValue(VendorHeaderSize + TagHeaderSize + ContentsSize, 4); + Streamer.EmitBytes(CurrentVendor, 0); + Streamer.EmitIntValue(0, 1); // '\0' + + Streamer.EmitIntValue(ARMBuildAttrs::File, 1); + Streamer.EmitIntValue(TagHeaderSize + ContentsSize, 4); + + Streamer.EmitBytes(Contents, 0); + + Contents.clear(); } }; + } // end of anonymous namespace -#include "ARMGenAsmWriter.inc" +MachineLocation ARMAsmPrinter:: +getDebugValueLocation(const MachineInstr *MI) const { + MachineLocation Location; + assert(MI->getNumOperands() == 4 && "Invalid no. of machine operands!"); + // Frame address. Currently handles register +- offset only. + if (MI->getOperand(0).isReg() && MI->getOperand(1).isImm()) + Location.set(MI->getOperand(0).getReg(), MI->getOperand(1).getImm()); + else { + DEBUG(dbgs() << "DBG_VALUE instruction ignored! " << *MI << "\n"); + } + return Location; +} void ARMAsmPrinter::EmitFunctionEntryLabel() { if (AFI->isThumbFunction()) { - OutStreamer.EmitRawText(StringRef("\t.code\t16")); - if (!Subtarget->isTargetDarwin()) - OutStreamer.EmitRawText(StringRef("\t.thumb_func")); - else { - // This needs to emit to a temporary string to get properly quoted - // MCSymbols when they have spaces in them. - SmallString<128> Tmp; - raw_svector_ostream OS(Tmp); - OS << "\t.thumb_func\t" << *CurrentFnSym; - OutStreamer.EmitRawText(OS.str()); - } + OutStreamer.EmitAssemblerFlag(MCAF_Code16); + OutStreamer.EmitThumbFunc(Subtarget->isTargetDarwin()? CurrentFnSym : 0); } OutStreamer.EmitLabel(CurrentFnSym); } -/// runOnMachineFunction - This uses the printInstruction() +/// runOnMachineFunction - This uses the EmitInstruction() /// method to print assembly for each instruction. /// bool ARMAsmPrinter::runOnMachineFunction(MachineFunction &MF) { @@ -337,32 +197,18 @@ void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, case MachineOperand::MO_Register: { unsigned Reg = MO.getReg(); assert(TargetRegisterInfo::isPhysicalRegister(Reg)); - if (Modifier && strcmp(Modifier, "dregpair") == 0) { - unsigned DRegLo = TM.getRegisterInfo()->getSubReg(Reg, ARM::dsub_0); - unsigned DRegHi = TM.getRegisterInfo()->getSubReg(Reg, ARM::dsub_1); - O << '{' - << getRegisterName(DRegLo) << ", " << getRegisterName(DRegHi) - << '}'; - } else if (Modifier && strcmp(Modifier, "lane") == 0) { - unsigned RegNum = ARMRegisterInfo::getRegisterNumbering(Reg); - unsigned DReg = - TM.getRegisterInfo()->getMatchingSuperReg(Reg, - RegNum & 1 ? ARM::ssub_1 : ARM::ssub_0, &ARM::DPR_VFP2RegClass); - O << getRegisterName(DReg) << '[' << (RegNum & 1) << ']'; - } else { - assert(!MO.getSubReg() && "Subregs should be eliminated!"); - O << getRegisterName(Reg); - } + assert(!MO.getSubReg() && "Subregs should be eliminated!"); + O << ARMInstPrinter::getRegisterName(Reg); break; } case MachineOperand::MO_Immediate: { int64_t Imm = MO.getImm(); O << '#'; if ((Modifier && strcmp(Modifier, "lo16") == 0) || - (TF & ARMII::MO_LO16)) + (TF == ARMII::MO_LO16)) O << ":lower16:"; else if ((Modifier && strcmp(Modifier, "hi16") == 0) || - (TF & ARMII::MO_HI16)) + (TF == ARMII::MO_HI16)) O << ":upper16:"; O << Imm; break; @@ -371,9 +217,7 @@ void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, O << *MO.getMBB()->getSymbol(); return; case MachineOperand::MO_GlobalAddress: { - bool isCallOp = Modifier && !strcmp(Modifier, "call"); const GlobalValue *GV = MO.getGlobal(); - if ((Modifier && strcmp(Modifier, "lo16") == 0) || (TF & ARMII::MO_LO16)) O << ":lower16:"; @@ -383,18 +227,13 @@ void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, O << *Mang->getSymbol(GV); printOffset(MO.getOffset(), O); - - if (isCallOp && Subtarget->isTargetELF() && - TM.getRelocationModel() == Reloc::PIC_) + if (TF == ARMII::MO_PLT) O << "(PLT)"; break; } case MachineOperand::MO_ExternalSymbol: { - bool isCallOp = Modifier && !strcmp(Modifier, "call"); O << *GetExternalSymbolSymbol(MO.getSymbolName()); - - if (isCallOp && Subtarget->isTargetELF() && - TM.getRelocationModel() == Reloc::PIC_) + if (TF == ARMII::MO_PLT) O << "(PLT)"; break; } @@ -407,538 +246,8 @@ void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, } } -static void printSOImm(raw_ostream &O, int64_t V, bool VerboseAsm, - const MCAsmInfo *MAI) { - // Break it up into two parts that make up a shifter immediate. - V = ARM_AM::getSOImmVal(V); - assert(V != -1 && "Not a valid so_imm value!"); - - unsigned Imm = ARM_AM::getSOImmValImm(V); - unsigned Rot = ARM_AM::getSOImmValRot(V); - - // Print low-level immediate formation info, per - // A5.1.3: "Data-processing operands - Immediate". - if (Rot) { - O << "#" << Imm << ", " << Rot; - // Pretty printed version. - if (VerboseAsm) { - O << "\t" << MAI->getCommentString() << ' '; - O << (int)ARM_AM::rotr32(Imm, Rot); - } - } else { - O << "#" << Imm; - } -} - -/// printSOImmOperand - SOImm is 4-bit rotate amount in bits 8-11 with 8-bit -/// immediate in bits 0-7. -void ARMAsmPrinter::printSOImmOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - const MachineOperand &MO = MI->getOperand(OpNum); - assert(MO.isImm() && "Not a valid so_imm value!"); - printSOImm(O, MO.getImm(), isVerbose(), MAI); -} - -/// printSOImm2PartOperand - SOImm is broken into two pieces using a 'mov' -/// followed by an 'orr' to materialize. -void ARMAsmPrinter::printSOImm2PartOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - const MachineOperand &MO = MI->getOperand(OpNum); - assert(MO.isImm() && "Not a valid so_imm value!"); - unsigned V1 = ARM_AM::getSOImmTwoPartFirst(MO.getImm()); - unsigned V2 = ARM_AM::getSOImmTwoPartSecond(MO.getImm()); - printSOImm(O, V1, isVerbose(), MAI); - O << "\n\torr"; - printPredicateOperand(MI, 2, O); - O << "\t"; - printOperand(MI, 0, O); - O << ", "; - printOperand(MI, 0, O); - O << ", "; - printSOImm(O, V2, isVerbose(), MAI); -} - -// so_reg is a 4-operand unit corresponding to register forms of the A5.1 -// "Addressing Mode 1 - Data-processing operands" forms. This includes: -// REG 0 0 - e.g. R5 -// REG REG 0,SH_OPC - e.g. R5, ROR R3 -// REG 0 IMM,SH_OPC - e.g. R5, LSL #3 -void ARMAsmPrinter::printSORegOperand(const MachineInstr *MI, int Op, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(Op); - const MachineOperand &MO2 = MI->getOperand(Op+1); - const MachineOperand &MO3 = MI->getOperand(Op+2); - - O << getRegisterName(MO1.getReg()); - - // Print the shift opc. - ARM_AM::ShiftOpc ShOpc = ARM_AM::getSORegShOp(MO3.getImm()); - O << ", " << ARM_AM::getShiftOpcStr(ShOpc); - if (MO2.getReg()) { - O << ' ' << getRegisterName(MO2.getReg()); - assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0); - } else if (ShOpc != ARM_AM::rrx) { - O << " #" << ARM_AM::getSORegOffset(MO3.getImm()); - } -} - -void ARMAsmPrinter::printAddrMode2Operand(const MachineInstr *MI, int Op, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(Op); - const MachineOperand &MO2 = MI->getOperand(Op+1); - const MachineOperand &MO3 = MI->getOperand(Op+2); - - if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. - printOperand(MI, Op, O); - return; - } - - O << "[" << getRegisterName(MO1.getReg()); - - if (!MO2.getReg()) { - if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. - O << ", #" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) - << ARM_AM::getAM2Offset(MO3.getImm()); - O << "]"; - return; - } - - O << ", " - << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) - << getRegisterName(MO2.getReg()); - - if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm())) - O << ", " - << ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO3.getImm())) - << " #" << ShImm; - O << "]"; -} - -void ARMAsmPrinter::printAddrMode2OffsetOperand(const MachineInstr *MI, int Op, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(Op); - const MachineOperand &MO2 = MI->getOperand(Op+1); - - if (!MO1.getReg()) { - unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm()); - O << "#" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) - << ImmOffs; - return; - } - - O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) - << getRegisterName(MO1.getReg()); - - if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm())) - O << ", " - << ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO2.getImm())) - << " #" << ShImm; -} - -void ARMAsmPrinter::printAddrMode3Operand(const MachineInstr *MI, int Op, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(Op); - const MachineOperand &MO2 = MI->getOperand(Op+1); - const MachineOperand &MO3 = MI->getOperand(Op+2); - - assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg())); - O << "[" << getRegisterName(MO1.getReg()); - - if (MO2.getReg()) { - O << ", " - << (char)ARM_AM::getAM3Op(MO3.getImm()) - << getRegisterName(MO2.getReg()) - << "]"; - return; - } - - if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm())) - O << ", #" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO3.getImm())) - << ImmOffs; - O << "]"; -} - -void ARMAsmPrinter::printAddrMode3OffsetOperand(const MachineInstr *MI, int Op, - raw_ostream &O){ - const MachineOperand &MO1 = MI->getOperand(Op); - const MachineOperand &MO2 = MI->getOperand(Op+1); - - if (MO1.getReg()) { - O << (char)ARM_AM::getAM3Op(MO2.getImm()) - << getRegisterName(MO1.getReg()); - return; - } - - unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm()); - O << "#" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO2.getImm())) - << ImmOffs; -} - -void ARMAsmPrinter::printAddrMode4Operand(const MachineInstr *MI, int Op, - raw_ostream &O, - const char *Modifier) { - const MachineOperand &MO2 = MI->getOperand(Op+1); - ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm()); - if (Modifier && strcmp(Modifier, "submode") == 0) { - O << ARM_AM::getAMSubModeStr(Mode); - } else if (Modifier && strcmp(Modifier, "wide") == 0) { - ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm()); - if (Mode == ARM_AM::ia) - O << ".w"; - } else { - printOperand(MI, Op, O); - } -} - -void ARMAsmPrinter::printAddrMode5Operand(const MachineInstr *MI, int Op, - raw_ostream &O, - const char *Modifier) { - const MachineOperand &MO1 = MI->getOperand(Op); - const MachineOperand &MO2 = MI->getOperand(Op+1); - - if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. - printOperand(MI, Op, O); - return; - } - - assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg())); - - O << "[" << getRegisterName(MO1.getReg()); - - if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) { - O << ", #" - << ARM_AM::getAddrOpcStr(ARM_AM::getAM5Op(MO2.getImm())) - << ImmOffs*4; - } - O << "]"; -} - -void ARMAsmPrinter::printAddrMode6Operand(const MachineInstr *MI, int Op, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(Op); - const MachineOperand &MO2 = MI->getOperand(Op+1); - - O << "[" << getRegisterName(MO1.getReg()); - if (MO2.getImm()) { - // FIXME: Both darwin as and GNU as violate ARM docs here. - O << ", :" << (MO2.getImm() << 3); - } - O << "]"; -} - -void ARMAsmPrinter::printAddrMode6OffsetOperand(const MachineInstr *MI, int Op, - raw_ostream &O){ - const MachineOperand &MO = MI->getOperand(Op); - if (MO.getReg() == 0) - O << "!"; - else - O << ", " << getRegisterName(MO.getReg()); -} - -void ARMAsmPrinter::printAddrModePCOperand(const MachineInstr *MI, int Op, - raw_ostream &O, - const char *Modifier) { - if (Modifier && strcmp(Modifier, "label") == 0) { - printPCLabel(MI, Op+1, O); - return; - } - - const MachineOperand &MO1 = MI->getOperand(Op); - assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg())); - O << "[pc, " << getRegisterName(MO1.getReg()) << "]"; -} - -void -ARMAsmPrinter::printBitfieldInvMaskImmOperand(const MachineInstr *MI, int Op, - raw_ostream &O) { - const MachineOperand &MO = MI->getOperand(Op); - uint32_t v = ~MO.getImm(); - int32_t lsb = CountTrailingZeros_32(v); - int32_t width = (32 - CountLeadingZeros_32 (v)) - lsb; - assert(MO.isImm() && "Not a valid bf_inv_mask_imm value!"); - O << "#" << lsb << ", #" << width; -} - -void -ARMAsmPrinter::printMemBOption(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - unsigned val = MI->getOperand(OpNum).getImm(); - O << ARM_MB::MemBOptToString(val); -} - -void ARMAsmPrinter::printShiftImmOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - unsigned ShiftOp = MI->getOperand(OpNum).getImm(); - ARM_AM::ShiftOpc Opc = ARM_AM::getSORegShOp(ShiftOp); - switch (Opc) { - case ARM_AM::no_shift: - return; - case ARM_AM::lsl: - O << ", lsl #"; - break; - case ARM_AM::asr: - O << ", asr #"; - break; - default: - assert(0 && "unexpected shift opcode for shift immediate operand"); - } - O << ARM_AM::getSORegOffset(ShiftOp); -} - -//===--------------------------------------------------------------------===// - -void ARMAsmPrinter::printThumbS4ImmOperand(const MachineInstr *MI, int Op, - raw_ostream &O) { - O << "#" << MI->getOperand(Op).getImm() * 4; -} - -void -ARMAsmPrinter::printThumbITMask(const MachineInstr *MI, int Op, - raw_ostream &O) { - // (3 - the number of trailing zeros) is the number of then / else. - unsigned Mask = MI->getOperand(Op).getImm(); - unsigned CondBit0 = Mask >> 4 & 1; - unsigned NumTZ = CountTrailingZeros_32(Mask); - assert(NumTZ <= 3 && "Invalid IT mask!"); - for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) { - bool T = ((Mask >> Pos) & 1) == CondBit0; - if (T) - O << 't'; - else - O << 'e'; - } -} - -void -ARMAsmPrinter::printThumbAddrModeRROperand(const MachineInstr *MI, int Op, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(Op); - const MachineOperand &MO2 = MI->getOperand(Op+1); - O << "[" << getRegisterName(MO1.getReg()); - O << ", " << getRegisterName(MO2.getReg()) << "]"; -} - -void -ARMAsmPrinter::printThumbAddrModeRI5Operand(const MachineInstr *MI, int Op, - raw_ostream &O, - unsigned Scale) { - const MachineOperand &MO1 = MI->getOperand(Op); - const MachineOperand &MO2 = MI->getOperand(Op+1); - const MachineOperand &MO3 = MI->getOperand(Op+2); - - if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. - printOperand(MI, Op, O); - return; - } - - O << "[" << getRegisterName(MO1.getReg()); - if (MO3.getReg()) - O << ", " << getRegisterName(MO3.getReg()); - else if (unsigned ImmOffs = MO2.getImm()) - O << ", #" << ImmOffs * Scale; - O << "]"; -} - -void -ARMAsmPrinter::printThumbAddrModeS1Operand(const MachineInstr *MI, int Op, - raw_ostream &O) { - printThumbAddrModeRI5Operand(MI, Op, O, 1); -} -void -ARMAsmPrinter::printThumbAddrModeS2Operand(const MachineInstr *MI, int Op, - raw_ostream &O) { - printThumbAddrModeRI5Operand(MI, Op, O, 2); -} -void -ARMAsmPrinter::printThumbAddrModeS4Operand(const MachineInstr *MI, int Op, - raw_ostream &O) { - printThumbAddrModeRI5Operand(MI, Op, O, 4); -} - -void ARMAsmPrinter::printThumbAddrModeSPOperand(const MachineInstr *MI,int Op, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(Op); - const MachineOperand &MO2 = MI->getOperand(Op+1); - O << "[" << getRegisterName(MO1.getReg()); - if (unsigned ImmOffs = MO2.getImm()) - O << ", #" << ImmOffs*4; - O << "]"; -} - -//===--------------------------------------------------------------------===// - -// Constant shifts t2_so_reg is a 2-operand unit corresponding to the Thumb2 -// register with shift forms. -// REG 0 0 - e.g. R5 -// REG IMM, SH_OPC - e.g. R5, LSL #3 -void ARMAsmPrinter::printT2SOOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(OpNum); - const MachineOperand &MO2 = MI->getOperand(OpNum+1); - - unsigned Reg = MO1.getReg(); - assert(TargetRegisterInfo::isPhysicalRegister(Reg)); - O << getRegisterName(Reg); - - // Print the shift opc. - assert(MO2.isImm() && "Not a valid t2_so_reg value!"); - ARM_AM::ShiftOpc ShOpc = ARM_AM::getSORegShOp(MO2.getImm()); - O << ", " << ARM_AM::getShiftOpcStr(ShOpc); - if (ShOpc != ARM_AM::rrx) - O << " #" << ARM_AM::getSORegOffset(MO2.getImm()); -} - -void ARMAsmPrinter::printT2AddrModeImm12Operand(const MachineInstr *MI, - int OpNum, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(OpNum); - const MachineOperand &MO2 = MI->getOperand(OpNum+1); - - O << "[" << getRegisterName(MO1.getReg()); - - unsigned OffImm = MO2.getImm(); - if (OffImm) // Don't print +0. - O << ", #" << OffImm; - O << "]"; -} - -void ARMAsmPrinter::printT2AddrModeImm8Operand(const MachineInstr *MI, - int OpNum, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(OpNum); - const MachineOperand &MO2 = MI->getOperand(OpNum+1); - - O << "[" << getRegisterName(MO1.getReg()); - - int32_t OffImm = (int32_t)MO2.getImm(); - // Don't print +0. - if (OffImm < 0) - O << ", #-" << -OffImm; - else if (OffImm > 0) - O << ", #" << OffImm; - O << "]"; -} - -void ARMAsmPrinter::printT2AddrModeImm8s4Operand(const MachineInstr *MI, - int OpNum, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(OpNum); - const MachineOperand &MO2 = MI->getOperand(OpNum+1); - - O << "[" << getRegisterName(MO1.getReg()); - - int32_t OffImm = (int32_t)MO2.getImm() / 4; - // Don't print +0. - if (OffImm < 0) - O << ", #-" << -OffImm * 4; - else if (OffImm > 0) - O << ", #" << OffImm * 4; - O << "]"; -} - -void ARMAsmPrinter::printT2AddrModeImm8OffsetOperand(const MachineInstr *MI, - int OpNum, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(OpNum); - int32_t OffImm = (int32_t)MO1.getImm(); - // Don't print +0. - if (OffImm < 0) - O << "#-" << -OffImm; - else if (OffImm > 0) - O << "#" << OffImm; -} - -void ARMAsmPrinter::printT2AddrModeSoRegOperand(const MachineInstr *MI, - int OpNum, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(OpNum); - const MachineOperand &MO2 = MI->getOperand(OpNum+1); - const MachineOperand &MO3 = MI->getOperand(OpNum+2); - - O << "[" << getRegisterName(MO1.getReg()); - - assert(MO2.getReg() && "Invalid so_reg load / store address!"); - O << ", " << getRegisterName(MO2.getReg()); - - unsigned ShAmt = MO3.getImm(); - if (ShAmt) { - assert(ShAmt <= 3 && "Not a valid Thumb2 addressing mode!"); - O << ", lsl #" << ShAmt; - } - O << "]"; -} - - //===--------------------------------------------------------------------===// -void ARMAsmPrinter::printPredicateOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm(); - if (CC != ARMCC::AL) - O << ARMCondCodeToString(CC); -} - -void ARMAsmPrinter::printMandatoryPredicateOperand(const MachineInstr *MI, - int OpNum, - raw_ostream &O) { - ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm(); - O << ARMCondCodeToString(CC); -} - -void ARMAsmPrinter::printSBitModifierOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O){ - unsigned Reg = MI->getOperand(OpNum).getReg(); - if (Reg) { - assert(Reg == ARM::CPSR && "Expect ARM CPSR register!"); - O << 's'; - } -} - -void ARMAsmPrinter::printPCLabel(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - int Id = (int)MI->getOperand(OpNum).getImm(); - O << MAI->getPrivateGlobalPrefix() - << "PC" << getFunctionNumber() << "_" << Id; -} - -void ARMAsmPrinter::printRegisterList(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - O << "{"; - for (unsigned i = OpNum, e = MI->getNumOperands(); i != e; ++i) { - if (MI->getOperand(i).isImplicit()) - continue; - if ((int)i != OpNum) O << ", "; - printOperand(MI, i, O); - } - O << "}"; -} - -void ARMAsmPrinter::printCPInstOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O, const char *Modifier) { - assert(Modifier && "This operand only works with a modifier!"); - // There are two aspects to a CONSTANTPOOL_ENTRY operand, the label and the - // data itself. - if (!strcmp(Modifier, "label")) { - unsigned ID = MI->getOperand(OpNum).getImm(); - OutStreamer.EmitLabel(GetCPISymbol(ID)); - } else { - assert(!strcmp(Modifier, "cpentry") && "Unknown modifier for CPE"); - unsigned CPI = MI->getOperand(OpNum).getIndex(); - - const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPI]; - - if (MCPE.isMachineConstantPoolEntry()) { - EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal); - } else { - EmitGlobalConstant(MCPE.Val.ConstVal); - } - } -} - MCSymbol *ARMAsmPrinter:: GetARMSetPICJumpTableLabel2(unsigned uid, unsigned uid2, const MachineBasicBlock *MBB) const { @@ -957,126 +266,12 @@ GetARMJTIPICJumpTableLabel2(unsigned uid, unsigned uid2) const { return OutContext.GetOrCreateSymbol(Name.str()); } -void ARMAsmPrinter::printJTBlockOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - assert(!Subtarget->isThumb2() && "Thumb2 should use double-jump jumptables!"); - - const MachineOperand &MO1 = MI->getOperand(OpNum); - const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id - - unsigned JTI = MO1.getIndex(); - MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel2(JTI, MO2.getImm()); - // Can't use EmitLabel until instprinter happens, label comes out in the wrong - // order. - O << "\n" << *JTISymbol << ":\n"; - - const char *JTEntryDirective = MAI->getData32bitsDirective(); - - const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); - const std::vector &JT = MJTI->getJumpTables(); - const std::vector &JTBBs = JT[JTI].MBBs; - bool UseSet= MAI->hasSetDirective() && TM.getRelocationModel() == Reloc::PIC_; - SmallPtrSet JTSets; - for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) { - MachineBasicBlock *MBB = JTBBs[i]; - bool isNew = JTSets.insert(MBB); - - if (UseSet && isNew) { - O << "\t.set\t" - << *GetARMSetPICJumpTableLabel2(JTI, MO2.getImm(), MBB) << ',' - << *MBB->getSymbol() << '-' << *JTISymbol << '\n'; - } - - O << JTEntryDirective << ' '; - if (UseSet) - O << *GetARMSetPICJumpTableLabel2(JTI, MO2.getImm(), MBB); - else if (TM.getRelocationModel() == Reloc::PIC_) - O << *MBB->getSymbol() << '-' << *JTISymbol; - else - O << *MBB->getSymbol(); - - if (i != e-1) - O << '\n'; - } -} - -void ARMAsmPrinter::printJT2BlockOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - const MachineOperand &MO1 = MI->getOperand(OpNum); - const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id - unsigned JTI = MO1.getIndex(); - - MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel2(JTI, MO2.getImm()); - - // Can't use EmitLabel until instprinter happens, label comes out in the wrong - // order. - O << "\n" << *JTISymbol << ":\n"; - - const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); - const std::vector &JT = MJTI->getJumpTables(); - const std::vector &JTBBs = JT[JTI].MBBs; - bool ByteOffset = false, HalfWordOffset = false; - if (MI->getOpcode() == ARM::t2TBB) - ByteOffset = true; - else if (MI->getOpcode() == ARM::t2TBH) - HalfWordOffset = true; - - for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) { - MachineBasicBlock *MBB = JTBBs[i]; - if (ByteOffset) - O << MAI->getData8bitsDirective(); - else if (HalfWordOffset) - O << MAI->getData16bitsDirective(); - - if (ByteOffset || HalfWordOffset) - O << '(' << *MBB->getSymbol() << "-" << *JTISymbol << ")/2"; - else - O << "\tb.w " << *MBB->getSymbol(); - - if (i != e-1) - O << '\n'; - } -} - -void ARMAsmPrinter::printTBAddrMode(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - O << "[pc, " << getRegisterName(MI->getOperand(OpNum).getReg()); - if (MI->getOpcode() == ARM::t2TBH) - O << ", lsl #1"; - O << ']'; -} - -void ARMAsmPrinter::printNoHashImmediate(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - O << MI->getOperand(OpNum).getImm(); -} - -void ARMAsmPrinter::printVFPf32ImmOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - const ConstantFP *FP = MI->getOperand(OpNum).getFPImm(); - O << '#' << FP->getValueAPF().convertToFloat(); - if (isVerbose()) { - O << "\t\t" << MAI->getCommentString() << ' '; - WriteAsOperand(O, FP, /*PrintType=*/false); - } -} - -void ARMAsmPrinter::printVFPf64ImmOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - const ConstantFP *FP = MI->getOperand(OpNum).getFPImm(); - O << '#' << FP->getValueAPF().convertToDouble(); - if (isVerbose()) { - O << "\t\t" << MAI->getCommentString() << ' '; - WriteAsOperand(O, FP, /*PrintType=*/false); - } -} -void ARMAsmPrinter::printNEONModImmOperand(const MachineInstr *MI, int OpNum, - raw_ostream &O) { - unsigned EncodedImm = MI->getOperand(OpNum).getImm(); - unsigned EltBits; - uint64_t Val = ARM_AM::decodeNEONModImm(EncodedImm, EltBits); - O << "#0x" << utohexstr(Val); +MCSymbol *ARMAsmPrinter::GetARMSJLJEHLabel(void) const { + SmallString<60> Name; + raw_svector_ostream(Name) << MAI->getPrivateGlobalPrefix() << "SJLJEH" + << getFunctionNumber(); + return OutContext.GetOrCreateSymbol(Name.str()); } bool ARMAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, @@ -1090,14 +285,16 @@ bool ARMAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, default: return true; // Unknown modifier. case 'a': // Print as a memory address. if (MI->getOperand(OpNum).isReg()) { - O << "[" << getRegisterName(MI->getOperand(OpNum).getReg()) << "]"; + O << "[" + << ARMInstPrinter::getRegisterName(MI->getOperand(OpNum).getReg()) + << "]"; return false; } // Fallthrough case 'c': // Don't print "#" before an immediate operand. if (!MI->getOperand(OpNum).isImm()) return true; - printNoHashImmediate(MI, OpNum, O); + O << MI->getOperand(OpNum).getImm(); return false; case 'P': // Print a VFP double precision register. case 'q': // Print a NEON quad precision register. @@ -1106,7 +303,7 @@ bool ARMAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, case 'Q': case 'R': case 'H': - report_fatal_error("llvm does not support 'Q', 'R', and 'H' modifiers!"); + // These modifiers are not yet supported. return true; } } @@ -1124,48 +321,10 @@ bool ARMAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, const MachineOperand &MO = MI->getOperand(OpNum); assert(MO.isReg() && "unexpected inline asm memory operand"); - O << "[" << getRegisterName(MO.getReg()) << "]"; + O << "[" << ARMInstPrinter::getRegisterName(MO.getReg()) << "]"; return false; } -void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) { - if (EnableMCInst) { - printInstructionThroughMCStreamer(MI); - return; - } - - if (MI->getOpcode() == ARM::CONSTPOOL_ENTRY) - EmitAlignment(2); - - SmallString<128> Str; - raw_svector_ostream OS(Str); - if (MI->getOpcode() == ARM::DBG_VALUE) { - unsigned NOps = MI->getNumOperands(); - assert(NOps==4); - OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: "; - // cast away const; DIetc do not take const operands for some reason. - DIVariable V(const_cast(MI->getOperand(NOps-1).getMetadata())); - OS << V.getName(); - OS << " <- "; - // Frame address. Currently handles register +- offset only. - assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm()); - OS << '['; printOperand(MI, 0, OS); OS << '+'; printOperand(MI, 1, OS); - OS << ']'; - OS << "+"; - printOperand(MI, NOps-2, OS); - OutStreamer.EmitRawText(OS.str()); - return; - } - - printInstruction(MI, OS); - OutStreamer.EmitRawText(OS.str()); - - // Make sure the instruction that follows TBB is 2-byte aligned. - // FIXME: Constant island pass should insert an "ALIGN" instruction instead. - if (MI->getOpcode() == ARM::t2TBB) - EmitAlignment(1); -} - void ARMAsmPrinter::EmitStartOfAsmFile(Module &M) { if (Subtarget->isTargetDarwin()) { Reloc::Model RelocM = TM.getRelocationModel(); @@ -1205,49 +364,12 @@ void ARMAsmPrinter::EmitStartOfAsmFile(Module &M) { } // Use unified assembler syntax. - OutStreamer.EmitRawText(StringRef("\t.syntax unified")); + OutStreamer.EmitAssemblerFlag(MCAF_SyntaxUnified); // Emit ARM Build Attributes if (Subtarget->isTargetELF()) { - // CPU Type - std::string CPUString = Subtarget->getCPUString(); - if (CPUString != "generic") - OutStreamer.EmitRawText("\t.cpu " + Twine(CPUString)); - - // FIXME: Emit FPU type - if (Subtarget->hasVFP2()) - OutStreamer.EmitRawText("\t.eabi_attribute " + - Twine(ARMBuildAttrs::VFP_arch) + ", 2"); - - // Signal various FP modes. - if (!UnsafeFPMath) { - OutStreamer.EmitRawText("\t.eabi_attribute " + - Twine(ARMBuildAttrs::ABI_FP_denormal) + ", 1"); - OutStreamer.EmitRawText("\t.eabi_attribute " + - Twine(ARMBuildAttrs::ABI_FP_exceptions) + ", 1"); - } - if (NoInfsFPMath && NoNaNsFPMath) - OutStreamer.EmitRawText("\t.eabi_attribute " + - Twine(ARMBuildAttrs::ABI_FP_number_model)+ ", 1"); - else - OutStreamer.EmitRawText("\t.eabi_attribute " + - Twine(ARMBuildAttrs::ABI_FP_number_model)+ ", 3"); - - // 8-bytes alignment stuff. - OutStreamer.EmitRawText("\t.eabi_attribute " + - Twine(ARMBuildAttrs::ABI_align8_needed) + ", 1"); - OutStreamer.EmitRawText("\t.eabi_attribute " + - Twine(ARMBuildAttrs::ABI_align8_preserved) + ", 1"); - - // Hard float. Use both S and D registers and conform to AAPCS-VFP. - if (Subtarget->isAAPCS_ABI() && FloatABIType == FloatABI::Hard) { - OutStreamer.EmitRawText("\t.eabi_attribute " + - Twine(ARMBuildAttrs::ABI_HardFP_use) + ", 3"); - OutStreamer.EmitRawText("\t.eabi_attribute " + - Twine(ARMBuildAttrs::ABI_VFP_args) + ", 1"); - } - // FIXME: Should we signal R9 usage? + emitAttributes(); } } @@ -1280,10 +402,10 @@ void ARMAsmPrinter::EmitEndOfAsmFile(Module &M) { else // Internal to current translation unit. // - // When we place the LSDA into the TEXT section, the type info pointers - // need to be indirect and pc-rel. We accomplish this by using NLPs. - // However, sometimes the types are local to the file. So we need to - // fill in the value for the NLP in those cases. + // When we place the LSDA into the TEXT section, the type info + // pointers need to be indirect and pc-rel. We accomplish this by + // using NLPs; however, sometimes the types are local to the file. + // We need to fill in the value for the NLP in those cases. OutStreamer.EmitValue(MCSymbolRefExpr::Create(MCSym.getPointer(), OutContext), 4/*size*/, 0/*addrspace*/); @@ -1321,38 +443,631 @@ void ARMAsmPrinter::EmitEndOfAsmFile(Module &M) { } //===----------------------------------------------------------------------===// +// Helper routines for EmitStartOfAsmFile() and EmitEndOfAsmFile() +// FIXME: +// The following seem like one-off assembler flags, but they actually need +// to appear in the .ARM.attributes section in ELF. +// Instead of subclassing the MCELFStreamer, we do the work here. + +void ARMAsmPrinter::emitAttributes() { + + emitARMAttributeSection(); + + AttributeEmitter *AttrEmitter; + if (OutStreamer.hasRawTextSupport()) + AttrEmitter = new AsmAttributeEmitter(OutStreamer); + else { + MCObjectStreamer &O = static_cast(OutStreamer); + AttrEmitter = new ObjectAttributeEmitter(O); + } + + AttrEmitter->MaybeSwitchVendor("aeabi"); + + std::string CPUString = Subtarget->getCPUString(); + + if (CPUString == "cortex-a8" || + Subtarget->isCortexA8()) { + AttrEmitter->EmitTextAttribute(ARMBuildAttrs::CPU_name, "cortex-a8"); + AttrEmitter->EmitAttribute(ARMBuildAttrs::CPU_arch, ARMBuildAttrs::v7); + AttrEmitter->EmitAttribute(ARMBuildAttrs::CPU_arch_profile, + ARMBuildAttrs::ApplicationProfile); + AttrEmitter->EmitAttribute(ARMBuildAttrs::ARM_ISA_use, + ARMBuildAttrs::Allowed); + AttrEmitter->EmitAttribute(ARMBuildAttrs::THUMB_ISA_use, + ARMBuildAttrs::AllowThumb32); + // Fixme: figure out when this is emitted. + //AttrEmitter->EmitAttribute(ARMBuildAttrs::WMMX_arch, + // ARMBuildAttrs::AllowWMMXv1); + // + + /// ADD additional Else-cases here! + } else if (CPUString == "generic") { + // FIXME: Why these defaults? + AttrEmitter->EmitAttribute(ARMBuildAttrs::CPU_arch, ARMBuildAttrs::v4T); + AttrEmitter->EmitAttribute(ARMBuildAttrs::ARM_ISA_use, + ARMBuildAttrs::Allowed); + AttrEmitter->EmitAttribute(ARMBuildAttrs::THUMB_ISA_use, + ARMBuildAttrs::Allowed); + } + + // FIXME: Emit FPU type + if (Subtarget->hasVFP2()) + AttrEmitter->EmitAttribute(ARMBuildAttrs::VFP_arch, + ARMBuildAttrs::AllowFPv2); + + // Signal various FP modes. + if (!UnsafeFPMath) { + AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_FP_denormal, + ARMBuildAttrs::Allowed); + AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_FP_exceptions, + ARMBuildAttrs::Allowed); + } + + if (NoInfsFPMath && NoNaNsFPMath) + AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_FP_number_model, + ARMBuildAttrs::Allowed); + else + AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_FP_number_model, + ARMBuildAttrs::AllowIEE754); + + // FIXME: add more flags to ARMBuildAttrs.h + // 8-bytes alignment stuff. + AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_align8_needed, 1); + AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_align8_preserved, 1); + + // Hard float. Use both S and D registers and conform to AAPCS-VFP. + if (Subtarget->isAAPCS_ABI() && FloatABIType == FloatABI::Hard) { + AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_HardFP_use, 3); + AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_VFP_args, 1); + } + // FIXME: Should we signal R9 usage? + + if (Subtarget->hasDivide()) + AttrEmitter->EmitAttribute(ARMBuildAttrs::DIV_use, 1); + + AttrEmitter->Finish(); + delete AttrEmitter; +} + +void ARMAsmPrinter::emitARMAttributeSection() { + // + // [ "vendor-name" + // [ * + // | * 0 * + // | * 0 * + // ]+ + // ]* + + if (OutStreamer.hasRawTextSupport()) + return; + + const ARMElfTargetObjectFile &TLOFELF = + static_cast + (getObjFileLowering()); + + OutStreamer.SwitchSection(TLOFELF.getAttributesSection()); + + // Format version + OutStreamer.EmitIntValue(0x41, 1); +} + +//===----------------------------------------------------------------------===// + +static MCSymbol *getPICLabel(const char *Prefix, unsigned FunctionNumber, + unsigned LabelId, MCContext &Ctx) { + + MCSymbol *Label = Ctx.GetOrCreateSymbol(Twine(Prefix) + + "PC" + Twine(FunctionNumber) + "_" + Twine(LabelId)); + return Label; +} + +static MCSymbolRefExpr::VariantKind +getModifierVariantKind(ARMCP::ARMCPModifier Modifier) { + switch (Modifier) { + default: llvm_unreachable("Unknown modifier!"); + case ARMCP::no_modifier: return MCSymbolRefExpr::VK_None; + case ARMCP::TLSGD: return MCSymbolRefExpr::VK_ARM_TLSGD; + case ARMCP::TPOFF: return MCSymbolRefExpr::VK_ARM_TPOFF; + case ARMCP::GOTTPOFF: return MCSymbolRefExpr::VK_ARM_GOTTPOFF; + case ARMCP::GOT: return MCSymbolRefExpr::VK_ARM_GOT; + case ARMCP::GOTOFF: return MCSymbolRefExpr::VK_ARM_GOTOFF; + } + return MCSymbolRefExpr::VK_None; +} + +MCSymbol *ARMAsmPrinter::GetARMGVSymbol(const GlobalValue *GV) { + bool isIndirect = Subtarget->isTargetDarwin() && + Subtarget->GVIsIndirectSymbol(GV, TM.getRelocationModel()); + if (!isIndirect) + return Mang->getSymbol(GV); + + // FIXME: Remove this when Darwin transition to @GOT like syntax. + MCSymbol *MCSym = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); + MachineModuleInfoMachO &MMIMachO = + MMI->getObjFileInfo(); + MachineModuleInfoImpl::StubValueTy &StubSym = + GV->hasHiddenVisibility() ? MMIMachO.getHiddenGVStubEntry(MCSym) : + MMIMachO.getGVStubEntry(MCSym); + if (StubSym.getPointer() == 0) + StubSym = MachineModuleInfoImpl:: + StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); + return MCSym; +} + +void ARMAsmPrinter:: +EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) { + int Size = TM.getTargetData()->getTypeAllocSize(MCPV->getType()); + + ARMConstantPoolValue *ACPV = static_cast(MCPV); + + MCSymbol *MCSym; + if (ACPV->isLSDA()) { + SmallString<128> Str; + raw_svector_ostream OS(Str); + OS << MAI->getPrivateGlobalPrefix() << "_LSDA_" << getFunctionNumber(); + MCSym = OutContext.GetOrCreateSymbol(OS.str()); + } else if (ACPV->isBlockAddress()) { + MCSym = GetBlockAddressSymbol(ACPV->getBlockAddress()); + } else if (ACPV->isGlobalValue()) { + const GlobalValue *GV = ACPV->getGV(); + MCSym = GetARMGVSymbol(GV); + } else { + assert(ACPV->isExtSymbol() && "unrecognized constant pool value"); + MCSym = GetExternalSymbolSymbol(ACPV->getSymbol()); + } + + // Create an MCSymbol for the reference. + const MCExpr *Expr = + MCSymbolRefExpr::Create(MCSym, getModifierVariantKind(ACPV->getModifier()), + OutContext); + + if (ACPV->getPCAdjustment()) { + MCSymbol *PCLabel = getPICLabel(MAI->getPrivateGlobalPrefix(), + getFunctionNumber(), + ACPV->getLabelId(), + OutContext); + const MCExpr *PCRelExpr = MCSymbolRefExpr::Create(PCLabel, OutContext); + PCRelExpr = + MCBinaryExpr::CreateAdd(PCRelExpr, + MCConstantExpr::Create(ACPV->getPCAdjustment(), + OutContext), + OutContext); + if (ACPV->mustAddCurrentAddress()) { + // We want "( - .)", but MC doesn't have a concept of the '.' + // label, so just emit a local label end reference that instead. + MCSymbol *DotSym = OutContext.CreateTempSymbol(); + OutStreamer.EmitLabel(DotSym); + const MCExpr *DotExpr = MCSymbolRefExpr::Create(DotSym, OutContext); + PCRelExpr = MCBinaryExpr::CreateSub(PCRelExpr, DotExpr, OutContext); + } + Expr = MCBinaryExpr::CreateSub(Expr, PCRelExpr, OutContext); + } + OutStreamer.EmitValue(Expr, Size); +} + +void ARMAsmPrinter::EmitJumpTable(const MachineInstr *MI) { + unsigned Opcode = MI->getOpcode(); + int OpNum = 1; + if (Opcode == ARM::BR_JTadd) + OpNum = 2; + else if (Opcode == ARM::BR_JTm) + OpNum = 3; + + const MachineOperand &MO1 = MI->getOperand(OpNum); + const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id + unsigned JTI = MO1.getIndex(); + + // Emit a label for the jump table. + MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel2(JTI, MO2.getImm()); + OutStreamer.EmitLabel(JTISymbol); + + // Emit each entry of the table. + const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); + const std::vector &JT = MJTI->getJumpTables(); + const std::vector &JTBBs = JT[JTI].MBBs; + + for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) { + MachineBasicBlock *MBB = JTBBs[i]; + // Construct an MCExpr for the entry. We want a value of the form: + // (BasicBlockAddr - TableBeginAddr) + // + // For example, a table with entries jumping to basic blocks BB0 and BB1 + // would look like: + // LJTI_0_0: + // .word (LBB0 - LJTI_0_0) + // .word (LBB1 - LJTI_0_0) + const MCExpr *Expr = MCSymbolRefExpr::Create(MBB->getSymbol(), OutContext); + + if (TM.getRelocationModel() == Reloc::PIC_) + Expr = MCBinaryExpr::CreateSub(Expr, MCSymbolRefExpr::Create(JTISymbol, + OutContext), + OutContext); + OutStreamer.EmitValue(Expr, 4); + } +} + +void ARMAsmPrinter::EmitJump2Table(const MachineInstr *MI) { + unsigned Opcode = MI->getOpcode(); + int OpNum = (Opcode == ARM::t2BR_JT) ? 2 : 1; + const MachineOperand &MO1 = MI->getOperand(OpNum); + const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id + unsigned JTI = MO1.getIndex(); + + // Emit a label for the jump table. + MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel2(JTI, MO2.getImm()); + OutStreamer.EmitLabel(JTISymbol); + + // Emit each entry of the table. + const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); + const std::vector &JT = MJTI->getJumpTables(); + const std::vector &JTBBs = JT[JTI].MBBs; + unsigned OffsetWidth = 4; + if (MI->getOpcode() == ARM::t2TBB_JT) + OffsetWidth = 1; + else if (MI->getOpcode() == ARM::t2TBH_JT) + OffsetWidth = 2; + + for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) { + MachineBasicBlock *MBB = JTBBs[i]; + const MCExpr *MBBSymbolExpr = MCSymbolRefExpr::Create(MBB->getSymbol(), + OutContext); + // If this isn't a TBB or TBH, the entries are direct branch instructions. + if (OffsetWidth == 4) { + MCInst BrInst; + BrInst.setOpcode(ARM::t2B); + BrInst.addOperand(MCOperand::CreateExpr(MBBSymbolExpr)); + OutStreamer.EmitInstruction(BrInst); + continue; + } + // Otherwise it's an offset from the dispatch instruction. Construct an + // MCExpr for the entry. We want a value of the form: + // (BasicBlockAddr - TableBeginAddr) / 2 + // + // For example, a TBB table with entries jumping to basic blocks BB0 and BB1 + // would look like: + // LJTI_0_0: + // .byte (LBB0 - LJTI_0_0) / 2 + // .byte (LBB1 - LJTI_0_0) / 2 + const MCExpr *Expr = + MCBinaryExpr::CreateSub(MBBSymbolExpr, + MCSymbolRefExpr::Create(JTISymbol, OutContext), + OutContext); + Expr = MCBinaryExpr::CreateDiv(Expr, MCConstantExpr::Create(2, OutContext), + OutContext); + OutStreamer.EmitValue(Expr, OffsetWidth); + } +} + +void ARMAsmPrinter::PrintDebugValueComment(const MachineInstr *MI, + raw_ostream &OS) { + unsigned NOps = MI->getNumOperands(); + assert(NOps==4); + OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: "; + // cast away const; DIetc do not take const operands for some reason. + DIVariable V(const_cast(MI->getOperand(NOps-1).getMetadata())); + OS << V.getName(); + OS << " <- "; + // Frame address. Currently handles register +- offset only. + assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm()); + OS << '['; printOperand(MI, 0, OS); OS << '+'; printOperand(MI, 1, OS); + OS << ']'; + OS << "+"; + printOperand(MI, NOps-2, OS); +} + +static void populateADROperands(MCInst &Inst, unsigned Dest, + const MCSymbol *Label, + unsigned pred, unsigned ccreg, + MCContext &Ctx) { + const MCExpr *SymbolExpr = MCSymbolRefExpr::Create(Label, Ctx); + Inst.addOperand(MCOperand::CreateReg(Dest)); + Inst.addOperand(MCOperand::CreateExpr(SymbolExpr)); + // Add predicate operands. + Inst.addOperand(MCOperand::CreateImm(pred)); + Inst.addOperand(MCOperand::CreateReg(ccreg)); +} + +void ARMAsmPrinter::EmitPatchedInstruction(const MachineInstr *MI, + unsigned Opcode) { + MCInst TmpInst; -void ARMAsmPrinter::printInstructionThroughMCStreamer(const MachineInstr *MI) { - ARMMCInstLower MCInstLowering(OutContext, *Mang, *this); - switch (MI->getOpcode()) { - case ARM::t2MOVi32imm: - assert(0 && "Should be lowered by thumb2it pass"); + // Emit the instruction as usual, just patch the opcode. + LowerARMMachineInstrToMCInst(MI, TmpInst, *this); + TmpInst.setOpcode(Opcode); + OutStreamer.EmitInstruction(TmpInst); +} + +void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) { + unsigned Opc = MI->getOpcode(); + switch (Opc) { default: break; - case ARM::PICADD: { // FIXME: Remove asm string from td file. + case ARM::t2ADDrSPi: + case ARM::t2ADDrSPi12: + case ARM::t2SUBrSPi: + case ARM::t2SUBrSPi12: + assert ((MI->getOperand(1).getReg() == ARM::SP) && + "Unexpected source register!"); + break; + + case ARM::t2MOVi32imm: assert(0 && "Should be lowered by thumb2it pass"); + case ARM::DBG_VALUE: { + if (isVerbose() && OutStreamer.hasRawTextSupport()) { + SmallString<128> TmpStr; + raw_svector_ostream OS(TmpStr); + PrintDebugValueComment(MI, OS); + OutStreamer.EmitRawText(StringRef(OS.str())); + } + return; + } + case ARM::tBfar: { + MCInst TmpInst; + TmpInst.setOpcode(ARM::tBL); + TmpInst.addOperand(MCOperand::CreateExpr(MCSymbolRefExpr::Create( + MI->getOperand(0).getMBB()->getSymbol(), OutContext))); + OutStreamer.EmitInstruction(TmpInst); + return; + } + case ARM::LEApcrel: + case ARM::tLEApcrel: + case ARM::t2LEApcrel: { + // FIXME: Need to also handle globals and externals + MCInst TmpInst; + TmpInst.setOpcode(MI->getOpcode() == ARM::t2LEApcrel ? ARM::t2ADR + : (MI->getOpcode() == ARM::tLEApcrel ? ARM::tADR + : ARM::ADR)); + populateADROperands(TmpInst, MI->getOperand(0).getReg(), + GetCPISymbol(MI->getOperand(1).getIndex()), + MI->getOperand(2).getImm(), MI->getOperand(3).getReg(), + OutContext); + OutStreamer.EmitInstruction(TmpInst); + return; + } + case ARM::LEApcrelJT: + case ARM::tLEApcrelJT: + case ARM::t2LEApcrelJT: { + MCInst TmpInst; + TmpInst.setOpcode(MI->getOpcode() == ARM::t2LEApcrelJT ? ARM::t2ADR + : (MI->getOpcode() == ARM::tLEApcrelJT ? ARM::tADR + : ARM::ADR)); + populateADROperands(TmpInst, MI->getOperand(0).getReg(), + GetARMJTIPICJumpTableLabel2(MI->getOperand(1).getIndex(), + MI->getOperand(2).getImm()), + MI->getOperand(3).getImm(), MI->getOperand(4).getReg(), + OutContext); + OutStreamer.EmitInstruction(TmpInst); + return; + } + case ARM::MOVPCRX: { + MCInst TmpInst; + TmpInst.setOpcode(ARM::MOVr); + TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + // Add predicate operands. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + // Add 's' bit operand (always reg0 for this) + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + return; + } + case ARM::BXr9_CALL: + case ARM::BX_CALL: { + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::MOVr); + TmpInst.addOperand(MCOperand::CreateReg(ARM::LR)); + TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); + // Add predicate operands. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + // Add 's' bit operand (always reg0 for this) + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::BX); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + OutStreamer.EmitInstruction(TmpInst); + } + return; + } + case ARM::BMOVPCRXr9_CALL: + case ARM::BMOVPCRX_CALL: { + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::MOVr); + TmpInst.addOperand(MCOperand::CreateReg(ARM::LR)); + TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); + // Add predicate operands. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + // Add 's' bit operand (always reg0 for this) + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::MOVr); + TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + // Add predicate operands. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + // Add 's' bit operand (always reg0 for this) + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + return; + } + case ARM::MOVi16_ga_pcrel: + case ARM::t2MOVi16_ga_pcrel: { + MCInst TmpInst; + TmpInst.setOpcode(Opc == ARM::MOVi16_ga_pcrel? ARM::MOVi16 : ARM::t2MOVi16); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + + unsigned TF = MI->getOperand(1).getTargetFlags(); + bool isPIC = TF == ARMII::MO_LO16_NONLAZY_PIC; + const GlobalValue *GV = MI->getOperand(1).getGlobal(); + MCSymbol *GVSym = GetARMGVSymbol(GV); + const MCExpr *GVSymExpr = MCSymbolRefExpr::Create(GVSym, OutContext); + if (isPIC) { + MCSymbol *LabelSym = getPICLabel(MAI->getPrivateGlobalPrefix(), + getFunctionNumber(), + MI->getOperand(2).getImm(), OutContext); + const MCExpr *LabelSymExpr= MCSymbolRefExpr::Create(LabelSym, OutContext); + unsigned PCAdj = (Opc == ARM::MOVi16_ga_pcrel) ? 8 : 4; + const MCExpr *PCRelExpr = + ARMMCExpr::CreateLower16(MCBinaryExpr::CreateSub(GVSymExpr, + MCBinaryExpr::CreateAdd(LabelSymExpr, + MCConstantExpr::Create(PCAdj, OutContext), + OutContext), OutContext), OutContext); + TmpInst.addOperand(MCOperand::CreateExpr(PCRelExpr)); + } else { + const MCExpr *RefExpr= ARMMCExpr::CreateLower16(GVSymExpr, OutContext); + TmpInst.addOperand(MCOperand::CreateExpr(RefExpr)); + } + + // Add predicate operands. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + // Add 's' bit operand (always reg0 for this) + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + return; + } + case ARM::MOVTi16_ga_pcrel: + case ARM::t2MOVTi16_ga_pcrel: { + MCInst TmpInst; + TmpInst.setOpcode(Opc == ARM::MOVTi16_ga_pcrel + ? ARM::MOVTi16 : ARM::t2MOVTi16); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg())); + + unsigned TF = MI->getOperand(2).getTargetFlags(); + bool isPIC = TF == ARMII::MO_HI16_NONLAZY_PIC; + const GlobalValue *GV = MI->getOperand(2).getGlobal(); + MCSymbol *GVSym = GetARMGVSymbol(GV); + const MCExpr *GVSymExpr = MCSymbolRefExpr::Create(GVSym, OutContext); + if (isPIC) { + MCSymbol *LabelSym = getPICLabel(MAI->getPrivateGlobalPrefix(), + getFunctionNumber(), + MI->getOperand(3).getImm(), OutContext); + const MCExpr *LabelSymExpr= MCSymbolRefExpr::Create(LabelSym, OutContext); + unsigned PCAdj = (Opc == ARM::MOVTi16_ga_pcrel) ? 8 : 4; + const MCExpr *PCRelExpr = + ARMMCExpr::CreateUpper16(MCBinaryExpr::CreateSub(GVSymExpr, + MCBinaryExpr::CreateAdd(LabelSymExpr, + MCConstantExpr::Create(PCAdj, OutContext), + OutContext), OutContext), OutContext); + TmpInst.addOperand(MCOperand::CreateExpr(PCRelExpr)); + } else { + const MCExpr *RefExpr= ARMMCExpr::CreateUpper16(GVSymExpr, OutContext); + TmpInst.addOperand(MCOperand::CreateExpr(RefExpr)); + } + // Add predicate operands. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + // Add 's' bit operand (always reg0 for this) + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + return; + } + case ARM::tPICADD: { // This is a pseudo op for a label + instruction sequence, which looks like: // LPC0: - // add r0, pc, r0 + // add r0, pc // This adds the address of LPC0 to r0. // Emit the label. - // FIXME: MOVE TO SHARED PLACE. - unsigned Id = (unsigned)MI->getOperand(2).getImm(); - const char *Prefix = MAI->getPrivateGlobalPrefix(); - MCSymbol *Label =OutContext.GetOrCreateSymbol(Twine(Prefix) - + "PC" + Twine(getFunctionNumber()) + "_" + Twine(Id)); - OutStreamer.EmitLabel(Label); + OutStreamer.EmitLabel(getPICLabel(MAI->getPrivateGlobalPrefix(), + getFunctionNumber(), MI->getOperand(2).getImm(), + OutContext)); + // Form and emit the add. + MCInst AddInst; + AddInst.setOpcode(ARM::tADDhirr); + AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + AddInst.addOperand(MCOperand::CreateReg(ARM::PC)); + // Add predicate operands. + AddInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + AddInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(AddInst); + return; + } + case ARM::PICADD: { + // This is a pseudo op for a label + instruction sequence, which looks like: + // LPC0: + // add r0, pc, r0 + // This adds the address of LPC0 to r0. - // Form and emit tha dd. + // Emit the label. + OutStreamer.EmitLabel(getPICLabel(MAI->getPrivateGlobalPrefix(), + getFunctionNumber(), MI->getOperand(2).getImm(), + OutContext)); + + // Form and emit the add. MCInst AddInst; AddInst.setOpcode(ARM::ADDrr); AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); AddInst.addOperand(MCOperand::CreateReg(ARM::PC)); AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg())); + // Add predicate operands. + AddInst.addOperand(MCOperand::CreateImm(MI->getOperand(3).getImm())); + AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(4).getReg())); + // Add 's' bit operand (always reg0 for this) + AddInst.addOperand(MCOperand::CreateReg(0)); OutStreamer.EmitInstruction(AddInst); return; } - case ARM::CONSTPOOL_ENTRY: { // FIXME: Remove asm string from td file. + case ARM::PICSTR: + case ARM::PICSTRB: + case ARM::PICSTRH: + case ARM::PICLDR: + case ARM::PICLDRB: + case ARM::PICLDRH: + case ARM::PICLDRSB: + case ARM::PICLDRSH: { + // This is a pseudo op for a label + instruction sequence, which looks like: + // LPC0: + // OP r0, [pc, r0] + // The LCP0 label is referenced by a constant pool entry in order to get + // a PC-relative address at the ldr instruction. + + // Emit the label. + OutStreamer.EmitLabel(getPICLabel(MAI->getPrivateGlobalPrefix(), + getFunctionNumber(), MI->getOperand(2).getImm(), + OutContext)); + + // Form and emit the load + unsigned Opcode; + switch (MI->getOpcode()) { + default: + llvm_unreachable("Unexpected opcode!"); + case ARM::PICSTR: Opcode = ARM::STRrs; break; + case ARM::PICSTRB: Opcode = ARM::STRBrs; break; + case ARM::PICSTRH: Opcode = ARM::STRH; break; + case ARM::PICLDR: Opcode = ARM::LDRrs; break; + case ARM::PICLDRB: Opcode = ARM::LDRBrs; break; + case ARM::PICLDRH: Opcode = ARM::LDRH; break; + case ARM::PICLDRSB: Opcode = ARM::LDRSB; break; + case ARM::PICLDRSH: Opcode = ARM::LDRSH; break; + } + MCInst LdStInst; + LdStInst.setOpcode(Opcode); + LdStInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + LdStInst.addOperand(MCOperand::CreateReg(ARM::PC)); + LdStInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg())); + LdStInst.addOperand(MCOperand::CreateImm(0)); + // Add predicate operands. + LdStInst.addOperand(MCOperand::CreateImm(MI->getOperand(3).getImm())); + LdStInst.addOperand(MCOperand::CreateReg(MI->getOperand(4).getReg())); + OutStreamer.EmitInstruction(LdStInst); + + return; + } + case ARM::CONSTPOOL_ENTRY: { /// CONSTPOOL_ENTRY - This instruction represents a floating constant pool /// in the function. The first operand is the ID# for this instruction, the /// second is the index into the MachineConstantPool that this is, the third @@ -1371,100 +1086,450 @@ void ARMAsmPrinter::printInstructionThroughMCStreamer(const MachineInstr *MI) { return; } - case ARM::MOVi2pieces: { // FIXME: Remove asmstring from td file. - // This is a hack that lowers as a two instruction sequence. - unsigned DstReg = MI->getOperand(0).getReg(); - unsigned ImmVal = (unsigned)MI->getOperand(1).getImm(); + case ARM::t2BR_JT: { + // Lower and emit the instruction itself, then the jump table following it. + MCInst TmpInst; + TmpInst.setOpcode(ARM::tMOVgpr2gpr); + TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + // Add predicate operands. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + // Output the data for the jump table itself + EmitJump2Table(MI); + return; + } + case ARM::t2TBB_JT: { + // Lower and emit the instruction itself, then the jump table following it. + MCInst TmpInst; + + TmpInst.setOpcode(ARM::t2TBB); + TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + // Add predicate operands. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + // Output the data for the jump table itself + EmitJump2Table(MI); + // Make sure the next instruction is 2-byte aligned. + EmitAlignment(1); + return; + } + case ARM::t2TBH_JT: { + // Lower and emit the instruction itself, then the jump table following it. + MCInst TmpInst; + + TmpInst.setOpcode(ARM::t2TBH); + TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + // Add predicate operands. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + // Output the data for the jump table itself + EmitJump2Table(MI); + return; + } + case ARM::tBR_JTr: + case ARM::BR_JTr: { + // Lower and emit the instruction itself, then the jump table following it. + // mov pc, target + MCInst TmpInst; + unsigned Opc = MI->getOpcode() == ARM::BR_JTr ? + ARM::MOVr : ARM::tMOVgpr2gpr; + TmpInst.setOpcode(Opc); + TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + // Add predicate operands. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + // Add 's' bit operand (always reg0 for this) + if (Opc == ARM::MOVr) + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + + // Make sure the Thumb jump table is 4-byte aligned. + if (Opc == ARM::tMOVgpr2gpr) + EmitAlignment(2); - unsigned SOImmValV1 = ARM_AM::getSOImmTwoPartFirst(ImmVal); - unsigned SOImmValV2 = ARM_AM::getSOImmTwoPartSecond(ImmVal); + // Output the data for the jump table itself + EmitJumpTable(MI); + return; + } + case ARM::BR_JTm: { + // Lower and emit the instruction itself, then the jump table following it. + // ldr pc, target + MCInst TmpInst; + if (MI->getOperand(1).getReg() == 0) { + // literal offset + TmpInst.setOpcode(ARM::LDRi12); + TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); + } else { + TmpInst.setOpcode(ARM::LDRrs); + TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg())); + TmpInst.addOperand(MCOperand::CreateImm(0)); + } + // Add predicate operands. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + // Output the data for the jump table itself + EmitJumpTable(MI); + return; + } + case ARM::BR_JTadd: { + // Lower and emit the instruction itself, then the jump table following it. + // add pc, target, idx + MCInst TmpInst; + TmpInst.setOpcode(ARM::ADDrr); + TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg())); + // Add predicate operands. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + // Add 's' bit operand (always reg0 for this) + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + + // Output the data for the jump table itself + EmitJumpTable(MI); + return; + } + case ARM::TRAP: { + // Non-Darwin binutils don't yet support the "trap" mnemonic. + // FIXME: Remove this special case when they do. + if (!Subtarget->isTargetDarwin()) { + //.long 0xe7ffdefe @ trap + uint32_t Val = 0xe7ffdefeUL; + OutStreamer.AddComment("trap"); + OutStreamer.EmitIntValue(Val, 4); + return; + } + break; + } + case ARM::tTRAP: { + // Non-Darwin binutils don't yet support the "trap" mnemonic. + // FIXME: Remove this special case when they do. + if (!Subtarget->isTargetDarwin()) { + //.short 57086 @ trap + uint16_t Val = 0xdefe; + OutStreamer.AddComment("trap"); + OutStreamer.EmitIntValue(Val, 2); + return; + } + break; + } + case ARM::t2Int_eh_sjlj_setjmp: + case ARM::t2Int_eh_sjlj_setjmp_nofp: + case ARM::tInt_eh_sjlj_setjmp: { + // Two incoming args: GPR:$src, GPR:$val + // mov $val, pc + // adds $val, #7 + // str $val, [$src, #4] + // movs r0, #0 + // b 1f + // movs r0, #1 + // 1: + unsigned SrcReg = MI->getOperand(0).getReg(); + unsigned ValReg = MI->getOperand(1).getReg(); + MCSymbol *Label = GetARMSJLJEHLabel(); { MCInst TmpInst; - TmpInst.setOpcode(ARM::MOVi); - TmpInst.addOperand(MCOperand::CreateReg(DstReg)); - TmpInst.addOperand(MCOperand::CreateImm(SOImmValV1)); - + TmpInst.setOpcode(ARM::tMOVgpr2tgpr); + TmpInst.addOperand(MCOperand::CreateReg(ValReg)); + TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); + // 's' bit operand + TmpInst.addOperand(MCOperand::CreateReg(ARM::CPSR)); + OutStreamer.AddComment("eh_setjmp begin"); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::tADDi3); + TmpInst.addOperand(MCOperand::CreateReg(ValReg)); + // 's' bit operand + TmpInst.addOperand(MCOperand::CreateReg(ARM::CPSR)); + TmpInst.addOperand(MCOperand::CreateReg(ValReg)); + TmpInst.addOperand(MCOperand::CreateImm(7)); // Predicate. - TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); - TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); - - TmpInst.addOperand(MCOperand::CreateReg(0)); // cc_out + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); OutStreamer.EmitInstruction(TmpInst); } - { MCInst TmpInst; - TmpInst.setOpcode(ARM::ORRri); - TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // dstreg - TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // inreg - TmpInst.addOperand(MCOperand::CreateImm(SOImmValV2)); // so_imm + TmpInst.setOpcode(ARM::tSTRi); + TmpInst.addOperand(MCOperand::CreateReg(ValReg)); + TmpInst.addOperand(MCOperand::CreateReg(SrcReg)); + // The offset immediate is #4. The operand value is scaled by 4 for the + // tSTR instruction. + TmpInst.addOperand(MCOperand::CreateImm(1)); // Predicate. - TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); - TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::tMOVi8); + TmpInst.addOperand(MCOperand::CreateReg(ARM::R0)); + TmpInst.addOperand(MCOperand::CreateReg(ARM::CPSR)); + TmpInst.addOperand(MCOperand::CreateImm(0)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + const MCExpr *SymbolExpr = MCSymbolRefExpr::Create(Label, OutContext); + MCInst TmpInst; + TmpInst.setOpcode(ARM::tB); + TmpInst.addOperand(MCOperand::CreateExpr(SymbolExpr)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::tMOVi8); + TmpInst.addOperand(MCOperand::CreateReg(ARM::R0)); + TmpInst.addOperand(MCOperand::CreateReg(ARM::CPSR)); + TmpInst.addOperand(MCOperand::CreateImm(1)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.AddComment("eh_setjmp end"); + OutStreamer.EmitInstruction(TmpInst); + } + OutStreamer.EmitLabel(Label); + return; + } + + case ARM::Int_eh_sjlj_setjmp_nofp: + case ARM::Int_eh_sjlj_setjmp: { + // Two incoming args: GPR:$src, GPR:$val + // add $val, pc, #8 + // str $val, [$src, #+4] + // mov r0, #0 + // add pc, pc, #0 + // mov r0, #1 + unsigned SrcReg = MI->getOperand(0).getReg(); + unsigned ValReg = MI->getOperand(1).getReg(); - TmpInst.addOperand(MCOperand::CreateReg(0)); // cc_out + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::ADDri); + TmpInst.addOperand(MCOperand::CreateReg(ValReg)); + TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); + TmpInst.addOperand(MCOperand::CreateImm(8)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + // 's' bit operand (always reg0 for this). + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.AddComment("eh_setjmp begin"); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::STRi12); + TmpInst.addOperand(MCOperand::CreateReg(ValReg)); + TmpInst.addOperand(MCOperand::CreateReg(SrcReg)); + TmpInst.addOperand(MCOperand::CreateImm(4)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::MOVi); + TmpInst.addOperand(MCOperand::CreateReg(ARM::R0)); + TmpInst.addOperand(MCOperand::CreateImm(0)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + // 's' bit operand (always reg0 for this). + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::ADDri); + TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); + TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); + TmpInst.addOperand(MCOperand::CreateImm(0)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + // 's' bit operand (always reg0 for this). + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::MOVi); + TmpInst.addOperand(MCOperand::CreateReg(ARM::R0)); + TmpInst.addOperand(MCOperand::CreateImm(1)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + // 's' bit operand (always reg0 for this). + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.AddComment("eh_setjmp end"); OutStreamer.EmitInstruction(TmpInst); } return; } - case ARM::MOVi32imm: { // FIXME: Remove asmstring from td file. - // This is a hack that lowers as a two instruction sequence. - unsigned DstReg = MI->getOperand(0).getReg(); - const MachineOperand &MO = MI->getOperand(1); - MCOperand V1, V2; - if (MO.isImm()) { - unsigned ImmVal = (unsigned)MI->getOperand(1).getImm(); - V1 = MCOperand::CreateImm(ImmVal & 65535); - V2 = MCOperand::CreateImm(ImmVal >> 16); - } else if (MO.isGlobal()) { - MCSymbol *Symbol = MCInstLowering.GetGlobalAddressSymbol(MO); - const MCSymbolRefExpr *SymRef1 = - MCSymbolRefExpr::Create(Symbol, - MCSymbolRefExpr::VK_ARM_LO16, OutContext); - const MCSymbolRefExpr *SymRef2 = - MCSymbolRefExpr::Create(Symbol, - MCSymbolRefExpr::VK_ARM_HI16, OutContext); - V1 = MCOperand::CreateExpr(SymRef1); - V2 = MCOperand::CreateExpr(SymRef2); - } else { - MI->dump(); - llvm_unreachable("cannot handle this operand"); + case ARM::Int_eh_sjlj_longjmp: { + // ldr sp, [$src, #8] + // ldr $scratch, [$src, #4] + // ldr r7, [$src] + // bx $scratch + unsigned SrcReg = MI->getOperand(0).getReg(); + unsigned ScratchReg = MI->getOperand(1).getReg(); + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::LDRi12); + TmpInst.addOperand(MCOperand::CreateReg(ARM::SP)); + TmpInst.addOperand(MCOperand::CreateReg(SrcReg)); + TmpInst.addOperand(MCOperand::CreateImm(8)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); } - { MCInst TmpInst; - TmpInst.setOpcode(ARM::MOVi16); - TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // dstreg - TmpInst.addOperand(V1); // lower16(imm) - + TmpInst.setOpcode(ARM::LDRi12); + TmpInst.addOperand(MCOperand::CreateReg(ScratchReg)); + TmpInst.addOperand(MCOperand::CreateReg(SrcReg)); + TmpInst.addOperand(MCOperand::CreateImm(4)); // Predicate. - TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); - TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); - + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); OutStreamer.EmitInstruction(TmpInst); } - { MCInst TmpInst; - TmpInst.setOpcode(ARM::MOVTi16); - TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // dstreg - TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // srcreg - TmpInst.addOperand(V2); // upper16(imm) - + TmpInst.setOpcode(ARM::LDRi12); + TmpInst.addOperand(MCOperand::CreateReg(ARM::R7)); + TmpInst.addOperand(MCOperand::CreateReg(SrcReg)); + TmpInst.addOperand(MCOperand::CreateImm(0)); // Predicate. - TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); - TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); - + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::BX); + TmpInst.addOperand(MCOperand::CreateReg(ScratchReg)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); OutStreamer.EmitInstruction(TmpInst); } - return; } + case ARM::tInt_eh_sjlj_longjmp: { + // ldr $scratch, [$src, #8] + // mov sp, $scratch + // ldr $scratch, [$src, #4] + // ldr r7, [$src] + // bx $scratch + unsigned SrcReg = MI->getOperand(0).getReg(); + unsigned ScratchReg = MI->getOperand(1).getReg(); + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::tLDRi); + TmpInst.addOperand(MCOperand::CreateReg(ScratchReg)); + TmpInst.addOperand(MCOperand::CreateReg(SrcReg)); + // The offset immediate is #8. The operand value is scaled by 4 for the + // tLDR instruction. + TmpInst.addOperand(MCOperand::CreateImm(2)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::tMOVtgpr2gpr); + TmpInst.addOperand(MCOperand::CreateReg(ARM::SP)); + TmpInst.addOperand(MCOperand::CreateReg(ScratchReg)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::tLDRi); + TmpInst.addOperand(MCOperand::CreateReg(ScratchReg)); + TmpInst.addOperand(MCOperand::CreateReg(SrcReg)); + TmpInst.addOperand(MCOperand::CreateImm(1)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::tLDRr); + TmpInst.addOperand(MCOperand::CreateReg(ARM::R7)); + TmpInst.addOperand(MCOperand::CreateReg(SrcReg)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::tBX_RET_vararg); + TmpInst.addOperand(MCOperand::CreateReg(ScratchReg)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + return; + } + // These are the pseudos created to comply with stricter operand restrictions + // on ARMv5. Lower them now to "normal" instructions, since all the + // restrictions are already satisfied. + case ARM::MULv5: + EmitPatchedInstruction(MI, ARM::MUL); + return; + case ARM::MLAv5: + EmitPatchedInstruction(MI, ARM::MLA); + return; + case ARM::SMULLv5: + EmitPatchedInstruction(MI, ARM::SMULL); + return; + case ARM::UMULLv5: + EmitPatchedInstruction(MI, ARM::UMULL); + return; + case ARM::SMLALv5: + EmitPatchedInstruction(MI, ARM::SMLAL); + return; + case ARM::UMLALv5: + EmitPatchedInstruction(MI, ARM::UMLAL); + return; + case ARM::UMAALv5: + EmitPatchedInstruction(MI, ARM::UMAAL); + return; } MCInst TmpInst; - MCInstLowering.Lower(MI, TmpInst); + LowerARMMachineInstrToMCInst(MI, TmpInst, *this); OutStreamer.EmitInstruction(TmpInst); } @@ -1476,7 +1541,7 @@ static MCInstPrinter *createARMMCInstPrinter(const Target &T, unsigned SyntaxVariant, const MCAsmInfo &MAI) { if (SyntaxVariant == 0) - return new ARMInstPrinter(MAI, false); + return new ARMInstPrinter(MAI); return 0; } diff --git a/lib/Target/ARM/ARMAsmPrinter.h b/lib/Target/ARM/ARMAsmPrinter.h new file mode 100644 index 000000000000..585268442ce4 --- /dev/null +++ b/lib/Target/ARM/ARMAsmPrinter.h @@ -0,0 +1,112 @@ +//===-- ARMAsmPrinter.h - Print machine code to an ARM .s file ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// ARM Assembly printer class. +// +//===----------------------------------------------------------------------===// + +#ifndef ARMASMPRINTER_H +#define ARMASMPRINTER_H + +#include "ARM.h" +#include "ARMTargetMachine.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/Support/Compiler.h" + +namespace llvm { + +namespace ARM { + enum DW_ISA { + DW_ISA_ARM_thumb = 1, + DW_ISA_ARM_arm = 2 + }; +} + +class LLVM_LIBRARY_VISIBILITY ARMAsmPrinter : public AsmPrinter { + + /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can + /// make the right decision when printing asm code for different targets. + const ARMSubtarget *Subtarget; + + /// AFI - Keep a pointer to ARMFunctionInfo for the current + /// MachineFunction. + ARMFunctionInfo *AFI; + + /// MCP - Keep a pointer to constantpool entries of the current + /// MachineFunction. + const MachineConstantPool *MCP; + +public: + explicit ARMAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) + : AsmPrinter(TM, Streamer), AFI(NULL), MCP(NULL) { + Subtarget = &TM.getSubtarget(); + } + + virtual const char *getPassName() const { + return "ARM Assembly Printer"; + } + + void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O, + const char *Modifier = 0); + + virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O); + virtual bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, + unsigned AsmVariant, + const char *ExtraCode, raw_ostream &O); + + void EmitJumpTable(const MachineInstr *MI); + void EmitJump2Table(const MachineInstr *MI); + virtual void EmitInstruction(const MachineInstr *MI); + bool runOnMachineFunction(MachineFunction &F); + + virtual void EmitConstantPool() {} // we emit constant pools customly! + virtual void EmitFunctionEntryLabel(); + void EmitStartOfAsmFile(Module &M); + void EmitEndOfAsmFile(Module &M); + +private: + // Helpers for EmitStartOfAsmFile() and EmitEndOfAsmFile() + void emitAttributes(); + + // Helper for ELF .o only + void emitARMAttributeSection(); + + // Generic helper used to emit e.g. ARMv5 mul pseudos + void EmitPatchedInstruction(const MachineInstr *MI, unsigned TargetOpc); + +public: + void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS); + + MachineLocation getDebugValueLocation(const MachineInstr *MI) const; + + virtual unsigned getISAEncoding() { + // ARM/Darwin adds ISA to the DWARF info for each function. + if (!Subtarget->isTargetDarwin()) + return 0; + return Subtarget->isThumb() ? + llvm::ARM::DW_ISA_ARM_thumb : llvm::ARM::DW_ISA_ARM_arm; + } + + MCSymbol *GetARMSetPICJumpTableLabel2(unsigned uid, unsigned uid2, + const MachineBasicBlock *MBB) const; + MCSymbol *GetARMJTIPICJumpTableLabel2(unsigned uid, unsigned uid2) const; + + MCSymbol *GetARMSJLJEHLabel(void) const; + + MCSymbol *GetARMGVSymbol(const GlobalValue *GV); + + /// EmitMachineConstantPoolValue - Print a machine constantpool value to + /// the .s file. + virtual void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV); +}; +} // end namespace llvm + +#endif diff --git a/lib/Target/ARM/ARMBaseInfo.h b/lib/Target/ARM/ARMBaseInfo.h new file mode 100644 index 000000000000..a56cc1a9f249 --- /dev/null +++ b/lib/Target/ARM/ARMBaseInfo.h @@ -0,0 +1,249 @@ +//===-- ARMBaseInfo.h - Top level definitions for ARM -------- --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains small standalone helper functions and enum definitions for +// the ARM target useful for the compiler back-end and the MC libraries. +// As such, it deliberately does not include references to LLVM core +// code gen types, passes, etc.. +// +//===----------------------------------------------------------------------===// + +#ifndef ARMBASEINFO_H +#define ARMBASEINFO_H + +#include "llvm/Support/ErrorHandling.h" + +// Note that the following auto-generated files only defined enum types, and +// so are safe to include here. + +// Defines symbolic names for ARM registers. This defines a mapping from +// register name to register number. +// +#include "ARMGenRegisterNames.inc" + +// Defines symbolic names for the ARM instructions. +// +#include "ARMGenInstrNames.inc" + +namespace llvm { + +// Enums corresponding to ARM condition codes +namespace ARMCC { + // The CondCodes constants map directly to the 4-bit encoding of the + // condition field for predicated instructions. + enum CondCodes { // Meaning (integer) Meaning (floating-point) + EQ, // Equal Equal + NE, // Not equal Not equal, or unordered + HS, // Carry set >, ==, or unordered + LO, // Carry clear Less than + MI, // Minus, negative Less than + PL, // Plus, positive or zero >, ==, or unordered + VS, // Overflow Unordered + VC, // No overflow Not unordered + HI, // Unsigned higher Greater than, or unordered + LS, // Unsigned lower or same Less than or equal + GE, // Greater than or equal Greater than or equal + LT, // Less than Less than, or unordered + GT, // Greater than Greater than + LE, // Less than or equal <, ==, or unordered + AL // Always (unconditional) Always (unconditional) + }; + + inline static CondCodes getOppositeCondition(CondCodes CC) { + switch (CC) { + default: llvm_unreachable("Unknown condition code"); + case EQ: return NE; + case NE: return EQ; + case HS: return LO; + case LO: return HS; + case MI: return PL; + case PL: return MI; + case VS: return VC; + case VC: return VS; + case HI: return LS; + case LS: return HI; + case GE: return LT; + case LT: return GE; + case GT: return LE; + case LE: return GT; + } + } +} // namespace ARMCC + +inline static const char *ARMCondCodeToString(ARMCC::CondCodes CC) { + switch (CC) { + default: llvm_unreachable("Unknown condition code"); + case ARMCC::EQ: return "eq"; + case ARMCC::NE: return "ne"; + case ARMCC::HS: return "hs"; + case ARMCC::LO: return "lo"; + case ARMCC::MI: return "mi"; + case ARMCC::PL: return "pl"; + case ARMCC::VS: return "vs"; + case ARMCC::VC: return "vc"; + case ARMCC::HI: return "hi"; + case ARMCC::LS: return "ls"; + case ARMCC::GE: return "ge"; + case ARMCC::LT: return "lt"; + case ARMCC::GT: return "gt"; + case ARMCC::LE: return "le"; + case ARMCC::AL: return "al"; + } +} + +namespace ARM_PROC { + enum IMod { + IE = 2, + ID = 3 + }; + + enum IFlags { + F = 1, + I = 2, + A = 4 + }; + + inline static const char *IFlagsToString(unsigned val) { + switch (val) { + default: llvm_unreachable("Unknown iflags operand"); + case F: return "f"; + case I: return "i"; + case A: return "a"; + } + } + + inline static const char *IModToString(unsigned val) { + switch (val) { + default: llvm_unreachable("Unknown imod operand"); + case IE: return "ie"; + case ID: return "id"; + } + } +} + +namespace ARM_MB { + // The Memory Barrier Option constants map directly to the 4-bit encoding of + // the option field for memory barrier operations. + enum MemBOpt { + SY = 15, + ST = 14, + ISH = 11, + ISHST = 10, + NSH = 7, + NSHST = 6, + OSH = 3, + OSHST = 2 + }; + + inline static const char *MemBOptToString(unsigned val) { + switch (val) { + default: llvm_unreachable("Unknown memory operation"); + case SY: return "sy"; + case ST: return "st"; + case ISH: return "ish"; + case ISHST: return "ishst"; + case NSH: return "nsh"; + case NSHST: return "nshst"; + case OSH: return "osh"; + case OSHST: return "oshst"; + } + } +} // namespace ARM_MB + +/// getARMRegisterNumbering - Given the enum value for some register, e.g. +/// ARM::LR, return the number that it corresponds to (e.g. 14). +inline static unsigned getARMRegisterNumbering(unsigned Reg) { + using namespace ARM; + switch (Reg) { + default: + llvm_unreachable("Unknown ARM register!"); + case R0: case S0: case D0: case Q0: return 0; + case R1: case S1: case D1: case Q1: return 1; + case R2: case S2: case D2: case Q2: return 2; + case R3: case S3: case D3: case Q3: return 3; + case R4: case S4: case D4: case Q4: return 4; + case R5: case S5: case D5: case Q5: return 5; + case R6: case S6: case D6: case Q6: return 6; + case R7: case S7: case D7: case Q7: return 7; + case R8: case S8: case D8: case Q8: return 8; + case R9: case S9: case D9: case Q9: return 9; + case R10: case S10: case D10: case Q10: return 10; + case R11: case S11: case D11: case Q11: return 11; + case R12: case S12: case D12: case Q12: return 12; + case SP: case S13: case D13: case Q13: return 13; + case LR: case S14: case D14: case Q14: return 14; + case PC: case S15: case D15: case Q15: return 15; + + case S16: case D16: return 16; + case S17: case D17: return 17; + case S18: case D18: return 18; + case S19: case D19: return 19; + case S20: case D20: return 20; + case S21: case D21: return 21; + case S22: case D22: return 22; + case S23: case D23: return 23; + case S24: case D24: return 24; + case S25: case D25: return 25; + case S26: case D26: return 26; + case S27: case D27: return 27; + case S28: case D28: return 28; + case S29: case D29: return 29; + case S30: case D30: return 30; + case S31: case D31: return 31; + } +} + +namespace ARMII { + /// Target Operand Flag enum. + enum TOF { + //===------------------------------------------------------------------===// + // ARM Specific MachineOperand flags. + + MO_NO_FLAG, + + /// MO_LO16 - On a symbol operand, this represents a relocation containing + /// lower 16 bit of the address. Used only via movw instruction. + MO_LO16, + + /// MO_HI16 - On a symbol operand, this represents a relocation containing + /// higher 16 bit of the address. Used only via movt instruction. + MO_HI16, + + /// MO_LO16_NONLAZY - On a symbol operand "FOO", this represents a + /// relocation containing lower 16 bit of the non-lazy-ptr indirect symbol, + /// i.e. "FOO$non_lazy_ptr". + /// Used only via movw instruction. + MO_LO16_NONLAZY, + + /// MO_HI16_NONLAZY - On a symbol operand "FOO", this represents a + /// relocation containing lower 16 bit of the non-lazy-ptr indirect symbol, + /// i.e. "FOO$non_lazy_ptr". Used only via movt instruction. + MO_HI16_NONLAZY, + + /// MO_LO16_NONLAZY_PIC - On a symbol operand "FOO", this represents a + /// relocation containing lower 16 bit of the PC relative address of the + /// non-lazy-ptr indirect symbol, i.e. "FOO$non_lazy_ptr - LABEL". + /// Used only via movw instruction. + MO_LO16_NONLAZY_PIC, + + /// MO_HI16_NONLAZY_PIC - On a symbol operand "FOO", this represents a + /// relocation containing lower 16 bit of the PC relative address of the + /// non-lazy-ptr indirect symbol, i.e. "FOO$non_lazy_ptr - LABEL". + /// Used only via movt instruction. + MO_HI16_NONLAZY_PIC, + + /// MO_PLT - On a symbol operand, this represents an ELF PLT reference on a + /// call operand. + MO_PLT + }; +} // end namespace ARMII + +} // end namespace llvm; + +#endif diff --git a/lib/Target/ARM/ARMBaseInstrInfo.cpp b/lib/Target/ARM/ARMBaseInstrInfo.cpp index e4f10f93fb74..2268e59ea7b1 100644 --- a/lib/Target/ARM/ARMBaseInstrInfo.cpp +++ b/lib/Target/ARM/ARMBaseInstrInfo.cpp @@ -15,13 +15,13 @@ #include "ARM.h" #include "ARMAddressingModes.h" #include "ARMConstantPoolValue.h" +#include "ARMHazardRecognizer.h" #include "ARMMachineFunctionInfo.h" #include "ARMRegisterInfo.h" #include "ARMGenInstrInfo.inc" #include "llvm/Constants.h" #include "llvm/Function.h" #include "llvm/GlobalValue.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/CodeGen/LiveVariables.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFrameInfo.h" @@ -34,15 +34,75 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/ADT/STLExtras.h" using namespace llvm; static cl::opt EnableARM3Addr("enable-arm-3-addr-conv", cl::Hidden, cl::desc("Enable ARM 2-addr to 3-addr conv")); +/// ARM_MLxEntry - Record information about MLA / MLS instructions. +struct ARM_MLxEntry { + unsigned MLxOpc; // MLA / MLS opcode + unsigned MulOpc; // Expanded multiplication opcode + unsigned AddSubOpc; // Expanded add / sub opcode + bool NegAcc; // True if the acc is negated before the add / sub. + bool HasLane; // True if instruction has an extra "lane" operand. +}; + +static const ARM_MLxEntry ARM_MLxTable[] = { + // MLxOpc, MulOpc, AddSubOpc, NegAcc, HasLane + // fp scalar ops + { ARM::VMLAS, ARM::VMULS, ARM::VADDS, false, false }, + { ARM::VMLSS, ARM::VMULS, ARM::VSUBS, false, false }, + { ARM::VMLAD, ARM::VMULD, ARM::VADDD, false, false }, + { ARM::VMLSD, ARM::VMULD, ARM::VSUBD, false, false }, + { ARM::VNMLAS, ARM::VNMULS, ARM::VSUBS, true, false }, + { ARM::VNMLSS, ARM::VMULS, ARM::VSUBS, true, false }, + { ARM::VNMLAD, ARM::VNMULD, ARM::VSUBD, true, false }, + { ARM::VNMLSD, ARM::VMULD, ARM::VSUBD, true, false }, + + // fp SIMD ops + { ARM::VMLAfd, ARM::VMULfd, ARM::VADDfd, false, false }, + { ARM::VMLSfd, ARM::VMULfd, ARM::VSUBfd, false, false }, + { ARM::VMLAfq, ARM::VMULfq, ARM::VADDfq, false, false }, + { ARM::VMLSfq, ARM::VMULfq, ARM::VSUBfq, false, false }, + { ARM::VMLAslfd, ARM::VMULslfd, ARM::VADDfd, false, true }, + { ARM::VMLSslfd, ARM::VMULslfd, ARM::VSUBfd, false, true }, + { ARM::VMLAslfq, ARM::VMULslfq, ARM::VADDfq, false, true }, + { ARM::VMLSslfq, ARM::VMULslfq, ARM::VSUBfq, false, true }, +}; + ARMBaseInstrInfo::ARMBaseInstrInfo(const ARMSubtarget& STI) : TargetInstrInfoImpl(ARMInsts, array_lengthof(ARMInsts)), Subtarget(STI) { + for (unsigned i = 0, e = array_lengthof(ARM_MLxTable); i != e; ++i) { + if (!MLxEntryMap.insert(std::make_pair(ARM_MLxTable[i].MLxOpc, i)).second) + assert(false && "Duplicated entries?"); + MLxHazardOpcodes.insert(ARM_MLxTable[i].AddSubOpc); + MLxHazardOpcodes.insert(ARM_MLxTable[i].MulOpc); + } +} + +// Use a ScoreboardHazardRecognizer for prepass ARM scheduling. TargetInstrImpl +// currently defaults to no prepass hazard recognizer. +ScheduleHazardRecognizer *ARMBaseInstrInfo:: +CreateTargetHazardRecognizer(const TargetMachine *TM, + const ScheduleDAG *DAG) const { + if (usePreRAHazardRecognizer()) { + const InstrItineraryData *II = TM->getInstrItineraryData(); + return new ScoreboardHazardRecognizer(II, DAG, "pre-RA-sched"); + } + return TargetInstrInfoImpl::CreateTargetHazardRecognizer(TM, DAG); +} + +ScheduleHazardRecognizer *ARMBaseInstrInfo:: +CreateTargetPostRAHazardRecognizer(const InstrItineraryData *II, + const ScheduleDAG *DAG) const { + if (Subtarget.isThumb2() || Subtarget.hasVFP2()) + return (ScheduleHazardRecognizer *) + new ARMHazardRecognizer(II, *this, getRegisterInfo(), Subtarget, DAG); + return TargetInstrInfoImpl::CreateTargetPostRAHazardRecognizer(II, DAG); } MachineInstr * @@ -140,7 +200,7 @@ ARMBaseInstrInfo::convertToThreeAddress(MachineFunction::iterator &MFI, if (isLoad) MemMI = BuildMI(MF, MI->getDebugLoc(), get(MemOpc), MI->getOperand(0).getReg()) - .addReg(WBReg).addReg(0).addImm(0).addImm(Pred); + .addReg(WBReg).addImm(0).addImm(Pred); else MemMI = BuildMI(MF, MI->getDebugLoc(), get(MemOpc)).addReg(MI->getOperand(1).getReg()) @@ -151,7 +211,7 @@ ARMBaseInstrInfo::convertToThreeAddress(MachineFunction::iterator &MFI, if (isLoad) MemMI = BuildMI(MF, MI->getDebugLoc(), get(MemOpc), MI->getOperand(0).getReg()) - .addReg(BaseReg).addReg(0).addImm(0).addImm(Pred); + .addReg(BaseReg).addImm(0).addImm(Pred); else MemMI = BuildMI(MF, MI->getDebugLoc(), get(MemOpc)).addReg(MI->getOperand(1).getReg()) @@ -166,8 +226,7 @@ ARMBaseInstrInfo::convertToThreeAddress(MachineFunction::iterator &MFI, if (LV) { for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { MachineOperand &MO = MI->getOperand(i); - if (MO.isReg() && MO.getReg() && - TargetRegisterInfo::isVirtualRegister(MO.getReg())) { + if (MO.isReg() && TargetRegisterInfo::isVirtualRegister(MO.getReg())) { unsigned Reg = MO.getReg(); LiveVariables::VarInfo &VI = LV->getVarInfo(Reg); @@ -197,43 +256,6 @@ ARMBaseInstrInfo::convertToThreeAddress(MachineFunction::iterator &MFI, return NewMIs[0]; } -bool -ARMBaseInstrInfo::spillCalleeSavedRegisters(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, - const std::vector &CSI, - const TargetRegisterInfo *TRI) const { - if (CSI.empty()) - return false; - - DebugLoc DL; - if (MI != MBB.end()) DL = MI->getDebugLoc(); - - for (unsigned i = 0, e = CSI.size(); i != e; ++i) { - unsigned Reg = CSI[i].getReg(); - bool isKill = true; - - // Add the callee-saved register as live-in unless it's LR and - // @llvm.returnaddress is called. If LR is returned for @llvm.returnaddress - // then it's already added to the function and entry block live-in sets. - if (Reg == ARM::LR) { - MachineFunction &MF = *MBB.getParent(); - if (MF.getFrameInfo()->isReturnAddressTaken() && - MF.getRegInfo().isLiveIn(Reg)) - isKill = false; - } - - if (isKill) - MBB.addLiveIn(Reg); - - // Insert the spill to the stack frame. The register is killed at the spill - // - const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg); - storeRegToStackSlot(MBB, MI, Reg, isKill, - CSI[i].getFrameIdx(), RC, TRI); - } - return true; -} - // Branch analysis. bool ARMBaseInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB,MachineBasicBlock *&TBB, @@ -275,13 +297,31 @@ ARMBaseInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB,MachineBasicBlock *&TBB, // Get the instruction before it if it is a terminator. MachineInstr *SecondLastInst = I; + unsigned SecondLastOpc = SecondLastInst->getOpcode(); + + // If AllowModify is true and the block ends with two or more unconditional + // branches, delete all but the first unconditional branch. + if (AllowModify && isUncondBranchOpcode(LastOpc)) { + while (isUncondBranchOpcode(SecondLastOpc)) { + LastInst->eraseFromParent(); + LastInst = SecondLastInst; + LastOpc = LastInst->getOpcode(); + if (I == MBB.begin() || !isUnpredicatedTerminator(--I)) { + // Return now the only terminator is an unconditional branch. + TBB = LastInst->getOperand(0).getMBB(); + return false; + } else { + SecondLastInst = I; + SecondLastOpc = SecondLastInst->getOpcode(); + } + } + } // If there are three terminators, we don't know what sort of block this is. if (SecondLastInst && I != MBB.begin() && isUnpredicatedTerminator(--I)) return true; // If the block ends with a B and a Bcc, handle it. - unsigned SecondLastOpc = SecondLastInst->getOpcode(); if (isCondBranchOpcode(SecondLastOpc) && isUncondBranchOpcode(LastOpc)) { TBB = SecondLastInst->getOperand(0).getMBB(); Cond.push_back(SecondLastInst->getOperand(1)); @@ -468,7 +508,7 @@ bool ARMBaseInstrInfo::isPredicable(MachineInstr *MI) const { } /// FIXME: Works around a gcc miscompilation with -fstrict-aliasing. -DISABLE_INLINE +LLVM_ATTRIBUTE_NOINLINE static unsigned getNumJTEntries(const std::vector &JT, unsigned JTI); static unsigned getNumJTEntries(const std::vector &JT, @@ -513,6 +553,14 @@ unsigned ARMBaseInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const { case ARMII::Size2Bytes: return 2; // Thumb1 instruction. case ARMII::SizeSpecial: { switch (Opc) { + case ARM::MOVi16_ga_pcrel: + case ARM::MOVTi16_ga_pcrel: + case ARM::t2MOVi16_ga_pcrel: + case ARM::t2MOVTi16_ga_pcrel: + return 4; + case ARM::MOVi32imm: + case ARM::t2MOVi32imm: + return 8; case ARM::CONSTPOOL_ENTRY: // If this machine instr is a constant pool entry, its size is recorded as // operand #2. @@ -533,13 +581,13 @@ unsigned ARMBaseInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const { case ARM::BR_JTadd: case ARM::tBR_JTr: case ARM::t2BR_JT: - case ARM::t2TBB: - case ARM::t2TBH: { + case ARM::t2TBB_JT: + case ARM::t2TBH_JT: { // These are jumptable branches, i.e. a branch followed by an inlined // jumptable. The size is 4 + 4 * number of entries. For TBB, each // entry is one byte; TBH two byte each. - unsigned EntrySize = (Opc == ARM::t2TBB) - ? 1 : ((Opc == ARM::t2TBH) ? 2 : 4); + unsigned EntrySize = (Opc == ARM::t2TBB_JT) + ? 1 : ((Opc == ARM::t2TBH_JT) ? 2 : 4); unsigned NumOps = TID.getNumOperands(); MachineOperand JTOP = MI->getOperand(NumOps - (TID.isPredicable() ? 3 : 2)); @@ -557,7 +605,7 @@ unsigned ARMBaseInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const { // alignment issue. unsigned InstSize = (Opc == ARM::tBR_JTr || Opc == ARM::t2BR_JT) ? 2 : 4; unsigned NumEntries = getNumJTEntries(JT, JTI); - if (Opc == ARM::t2TBB && (NumEntries & 1)) + if (Opc == ARM::t2TBB_JT && (NumEntries & 1)) // Make sure the instruction that follows TBB is 2-byte aligned. // FIXME: Constant island pass should insert an "ALIGN" instruction // instead. @@ -573,84 +621,6 @@ unsigned ARMBaseInstrInfo::GetInstSizeInBytes(const MachineInstr *MI) const { return 0; // Not reached } -unsigned -ARMBaseInstrInfo::isLoadFromStackSlot(const MachineInstr *MI, - int &FrameIndex) const { - switch (MI->getOpcode()) { - default: break; - case ARM::LDR: - case ARM::t2LDRs: // FIXME: don't use t2LDRs to access frame. - if (MI->getOperand(1).isFI() && - MI->getOperand(2).isReg() && - MI->getOperand(3).isImm() && - MI->getOperand(2).getReg() == 0 && - MI->getOperand(3).getImm() == 0) { - FrameIndex = MI->getOperand(1).getIndex(); - return MI->getOperand(0).getReg(); - } - break; - case ARM::t2LDRi12: - case ARM::tRestore: - if (MI->getOperand(1).isFI() && - MI->getOperand(2).isImm() && - MI->getOperand(2).getImm() == 0) { - FrameIndex = MI->getOperand(1).getIndex(); - return MI->getOperand(0).getReg(); - } - break; - case ARM::VLDRD: - case ARM::VLDRS: - if (MI->getOperand(1).isFI() && - MI->getOperand(2).isImm() && - MI->getOperand(2).getImm() == 0) { - FrameIndex = MI->getOperand(1).getIndex(); - return MI->getOperand(0).getReg(); - } - break; - } - - return 0; -} - -unsigned -ARMBaseInstrInfo::isStoreToStackSlot(const MachineInstr *MI, - int &FrameIndex) const { - switch (MI->getOpcode()) { - default: break; - case ARM::STR: - case ARM::t2STRs: // FIXME: don't use t2STRs to access frame. - if (MI->getOperand(1).isFI() && - MI->getOperand(2).isReg() && - MI->getOperand(3).isImm() && - MI->getOperand(2).getReg() == 0 && - MI->getOperand(3).getImm() == 0) { - FrameIndex = MI->getOperand(1).getIndex(); - return MI->getOperand(0).getReg(); - } - break; - case ARM::t2STRi12: - case ARM::tSpill: - if (MI->getOperand(1).isFI() && - MI->getOperand(2).isImm() && - MI->getOperand(2).getImm() == 0) { - FrameIndex = MI->getOperand(1).getIndex(); - return MI->getOperand(0).getReg(); - } - break; - case ARM::VSTRD: - case ARM::VSTRS: - if (MI->getOperand(1).isFI() && - MI->getOperand(2).isImm() && - MI->getOperand(2).getImm() == 0) { - FrameIndex = MI->getOperand(1).getIndex(); - return MI->getOperand(0).getReg(); - } - break; - } - - return 0; -} - void ARMBaseInstrInfo::copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, DebugLoc DL, unsigned DestReg, unsigned SrcReg, @@ -715,8 +685,9 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, unsigned Align = MFI.getObjectAlignment(FI); MachineMemOperand *MMO = - MF.getMachineMemOperand(PseudoSourceValue::getFixedStack(FI), - MachineMemOperand::MOStore, 0, + MF.getMachineMemOperand(MachinePointerInfo( + PseudoSourceValue::getFixedStack(FI)), + MachineMemOperand::MOStore, MFI.getObjectSize(FI), Align); @@ -728,9 +699,9 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, switch (RC->getID()) { case ARM::GPRRegClassID: - AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::STR)) + AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::STRi12)) .addReg(SrcReg, getKillRegState(isKill)) - .addFrameIndex(FI).addReg(0).addImm(0).addMemOperand(MMO)); + .addFrameIndex(FI).addImm(0).addMemOperand(MMO)); break; case ARM::SPRRegClassID: AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VSTRS)) @@ -747,17 +718,15 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, case ARM::QPRRegClassID: case ARM::QPR_VFP2RegClassID: case ARM::QPR_8RegClassID: - // FIXME: Neon instructions should support predicates - if (Align >= 16 && getRegisterInfo().canRealignStack(MF)) { - AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VST1q)) + if (Align >= 16 && getRegisterInfo().needsStackRealignment(MF)) { + AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VST1q64Pseudo)) .addFrameIndex(FI).addImm(16) .addReg(SrcReg, getKillRegState(isKill)) .addMemOperand(MMO)); } else { - AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VSTMQ)) + AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VSTMQIA)) .addReg(SrcReg, getKillRegState(isKill)) .addFrameIndex(FI) - .addImm(ARM_AM::getAM4ModeImm(ARM_AM::ia)) .addMemOperand(MMO)); } break; @@ -766,18 +735,14 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, if (Align >= 16 && getRegisterInfo().canRealignStack(MF)) { // FIXME: It's possible to only store part of the QQ register if the // spilled def has a sub-register index. - MachineInstrBuilder MIB = BuildMI(MBB, I, DL, get(ARM::VST1d64Q)) - .addFrameIndex(FI).addImm(16); - MIB = AddDReg(MIB, SrcReg, ARM::dsub_0, getKillRegState(isKill), TRI); - MIB = AddDReg(MIB, SrcReg, ARM::dsub_1, 0, TRI); - MIB = AddDReg(MIB, SrcReg, ARM::dsub_2, 0, TRI); - MIB = AddDReg(MIB, SrcReg, ARM::dsub_3, 0, TRI); - AddDefaultPred(MIB.addMemOperand(MMO)); + AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VST1d64QPseudo)) + .addFrameIndex(FI).addImm(16) + .addReg(SrcReg, getKillRegState(isKill)) + .addMemOperand(MMO)); } else { MachineInstrBuilder MIB = - AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VSTMD)) - .addFrameIndex(FI) - .addImm(ARM_AM::getAM4ModeImm(ARM_AM::ia))) + AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VSTMDIA)) + .addFrameIndex(FI)) .addMemOperand(MMO); MIB = AddDReg(MIB, SrcReg, ARM::dsub_0, getKillRegState(isKill), TRI); MIB = AddDReg(MIB, SrcReg, ARM::dsub_1, 0, TRI); @@ -787,9 +752,8 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, break; case ARM::QQQQPRRegClassID: { MachineInstrBuilder MIB = - AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VSTMD)) - .addFrameIndex(FI) - .addImm(ARM_AM::getAM4ModeImm(ARM_AM::ia))) + AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VSTMDIA)) + .addFrameIndex(FI)) .addMemOperand(MMO); MIB = AddDReg(MIB, SrcReg, ARM::dsub_0, getKillRegState(isKill), TRI); MIB = AddDReg(MIB, SrcReg, ARM::dsub_1, 0, TRI); @@ -806,6 +770,53 @@ storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, } } +unsigned +ARMBaseInstrInfo::isStoreToStackSlot(const MachineInstr *MI, + int &FrameIndex) const { + switch (MI->getOpcode()) { + default: break; + case ARM::STRrs: + case ARM::t2STRs: // FIXME: don't use t2STRs to access frame. + if (MI->getOperand(1).isFI() && + MI->getOperand(2).isReg() && + MI->getOperand(3).isImm() && + MI->getOperand(2).getReg() == 0 && + MI->getOperand(3).getImm() == 0) { + FrameIndex = MI->getOperand(1).getIndex(); + return MI->getOperand(0).getReg(); + } + break; + case ARM::STRi12: + case ARM::t2STRi12: + case ARM::tSpill: + case ARM::VSTRD: + case ARM::VSTRS: + if (MI->getOperand(1).isFI() && + MI->getOperand(2).isImm() && + MI->getOperand(2).getImm() == 0) { + FrameIndex = MI->getOperand(1).getIndex(); + return MI->getOperand(0).getReg(); + } + break; + case ARM::VST1q64Pseudo: + if (MI->getOperand(0).isFI() && + MI->getOperand(2).getSubReg() == 0) { + FrameIndex = MI->getOperand(0).getIndex(); + return MI->getOperand(2).getReg(); + } + break; + case ARM::VSTMQIA: + if (MI->getOperand(1).isFI() && + MI->getOperand(0).getSubReg() == 0) { + FrameIndex = MI->getOperand(1).getIndex(); + return MI->getOperand(0).getReg(); + } + break; + } + + return 0; +} + void ARMBaseInstrInfo:: loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, unsigned DestReg, int FI, @@ -817,8 +828,9 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, MachineFrameInfo &MFI = *MF.getFrameInfo(); unsigned Align = MFI.getObjectAlignment(FI); MachineMemOperand *MMO = - MF.getMachineMemOperand(PseudoSourceValue::getFixedStack(FI), - MachineMemOperand::MOLoad, 0, + MF.getMachineMemOperand( + MachinePointerInfo(PseudoSourceValue::getFixedStack(FI)), + MachineMemOperand::MOLoad, MFI.getObjectSize(FI), Align); @@ -830,8 +842,8 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, switch (RC->getID()) { case ARM::GPRRegClassID: - AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::LDR), DestReg) - .addFrameIndex(FI).addReg(0).addImm(0).addMemOperand(MMO)); + AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::LDRi12), DestReg) + .addFrameIndex(FI).addImm(0).addMemOperand(MMO)); break; case ARM::SPRRegClassID: AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VLDRS), DestReg) @@ -846,31 +858,26 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, case ARM::QPRRegClassID: case ARM::QPR_VFP2RegClassID: case ARM::QPR_8RegClassID: - if (Align >= 16 && getRegisterInfo().canRealignStack(MF)) { - AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VLD1q), DestReg) + if (Align >= 16 && getRegisterInfo().needsStackRealignment(MF)) { + AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VLD1q64Pseudo), DestReg) .addFrameIndex(FI).addImm(16) .addMemOperand(MMO)); } else { - AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VLDMQ), DestReg) + AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VLDMQIA), DestReg) .addFrameIndex(FI) - .addImm(ARM_AM::getAM4ModeImm(ARM_AM::ia)) .addMemOperand(MMO)); } break; case ARM::QQPRRegClassID: case ARM::QQPR_VFP2RegClassID: if (Align >= 16 && getRegisterInfo().canRealignStack(MF)) { - MachineInstrBuilder MIB = BuildMI(MBB, I, DL, get(ARM::VLD1d64Q)); - MIB = AddDReg(MIB, DestReg, ARM::dsub_0, RegState::Define, TRI); - MIB = AddDReg(MIB, DestReg, ARM::dsub_1, RegState::Define, TRI); - MIB = AddDReg(MIB, DestReg, ARM::dsub_2, RegState::Define, TRI); - MIB = AddDReg(MIB, DestReg, ARM::dsub_3, RegState::Define, TRI); - AddDefaultPred(MIB.addFrameIndex(FI).addImm(16).addMemOperand(MMO)); + AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VLD1d64QPseudo), DestReg) + .addFrameIndex(FI).addImm(16) + .addMemOperand(MMO)); } else { MachineInstrBuilder MIB = - AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VLDMD)) - .addFrameIndex(FI) - .addImm(ARM_AM::getAM4ModeImm(ARM_AM::ia))) + AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VLDMDIA)) + .addFrameIndex(FI)) .addMemOperand(MMO); MIB = AddDReg(MIB, DestReg, ARM::dsub_0, RegState::Define, TRI); MIB = AddDReg(MIB, DestReg, ARM::dsub_1, RegState::Define, TRI); @@ -880,9 +887,8 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, break; case ARM::QQQQPRRegClassID: { MachineInstrBuilder MIB = - AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VLDMD)) - .addFrameIndex(FI) - .addImm(ARM_AM::getAM4ModeImm(ARM_AM::ia))) + AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::VLDMDIA)) + .addFrameIndex(FI)) .addMemOperand(MMO); MIB = AddDReg(MIB, DestReg, ARM::dsub_0, RegState::Define, TRI); MIB = AddDReg(MIB, DestReg, ARM::dsub_1, RegState::Define, TRI); @@ -899,6 +905,53 @@ loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, } } +unsigned +ARMBaseInstrInfo::isLoadFromStackSlot(const MachineInstr *MI, + int &FrameIndex) const { + switch (MI->getOpcode()) { + default: break; + case ARM::LDRrs: + case ARM::t2LDRs: // FIXME: don't use t2LDRs to access frame. + if (MI->getOperand(1).isFI() && + MI->getOperand(2).isReg() && + MI->getOperand(3).isImm() && + MI->getOperand(2).getReg() == 0 && + MI->getOperand(3).getImm() == 0) { + FrameIndex = MI->getOperand(1).getIndex(); + return MI->getOperand(0).getReg(); + } + break; + case ARM::LDRi12: + case ARM::t2LDRi12: + case ARM::tRestore: + case ARM::VLDRD: + case ARM::VLDRS: + if (MI->getOperand(1).isFI() && + MI->getOperand(2).isImm() && + MI->getOperand(2).getImm() == 0) { + FrameIndex = MI->getOperand(1).getIndex(); + return MI->getOperand(0).getReg(); + } + break; + case ARM::VLD1q64Pseudo: + if (MI->getOperand(1).isFI() && + MI->getOperand(0).getSubReg() == 0) { + FrameIndex = MI->getOperand(1).getIndex(); + return MI->getOperand(0).getReg(); + } + break; + case ARM::VLDMQIA: + if (MI->getOperand(1).isFI() && + MI->getOperand(0).getSubReg() == 0) { + FrameIndex = MI->getOperand(1).getIndex(); + return MI->getOperand(0).getReg(); + } + break; + } + + return 0; +} + MachineInstr* ARMBaseInstrInfo::emitFrameIndexDebugValue(MachineFunction &MF, int FrameIx, uint64_t Offset, @@ -921,7 +974,7 @@ static unsigned duplicateCPV(MachineFunction &MF, unsigned &CPI) { ARMConstantPoolValue *ACPV = static_cast(MCPE.Val.MachineCPVal); - unsigned PCLabelId = AFI->createConstPoolEntryUId(); + unsigned PCLabelId = AFI->createPICLabelUId(); ARMConstantPoolValue *NewCPV = 0; // FIXME: The below assumes PIC relocation model and that the function // is Thumb mode (t1 or t2). PCAdjustment would be 8 for ARM mode PIC, and @@ -991,12 +1044,18 @@ ARMBaseInstrInfo::duplicate(MachineInstr *Orig, MachineFunction &MF) const { } bool ARMBaseInstrInfo::produceSameValue(const MachineInstr *MI0, - const MachineInstr *MI1) const { + const MachineInstr *MI1, + const MachineRegisterInfo *MRI) const { int Opcode = MI0->getOpcode(); if (Opcode == ARM::t2LDRpci || Opcode == ARM::t2LDRpci_pic || Opcode == ARM::tLDRpci || - Opcode == ARM::tLDRpci_pic) { + Opcode == ARM::tLDRpci_pic || + Opcode == ARM::MOV_ga_dyn || + Opcode == ARM::MOV_ga_pcrel || + Opcode == ARM::MOV_ga_pcrel_ldr || + Opcode == ARM::t2MOV_ga_dyn || + Opcode == ARM::t2MOV_ga_pcrel) { if (MI1->getOpcode() != Opcode) return false; if (MI0->getNumOperands() != MI1->getNumOperands()) @@ -1007,6 +1066,14 @@ bool ARMBaseInstrInfo::produceSameValue(const MachineInstr *MI0, if (MO0.getOffset() != MO1.getOffset()) return false; + if (Opcode == ARM::MOV_ga_dyn || + Opcode == ARM::MOV_ga_pcrel || + Opcode == ARM::MOV_ga_pcrel_ldr || + Opcode == ARM::t2MOV_ga_dyn || + Opcode == ARM::t2MOV_ga_pcrel) + // Ignore the PC labels. + return MO0.getGlobal() == MO1.getGlobal(); + const MachineFunction *MF = MI0->getParent()->getParent(); const MachineConstantPool *MCP = MF->getConstantPool(); int CPI0 = MO0.getIndex(); @@ -1018,6 +1085,37 @@ bool ARMBaseInstrInfo::produceSameValue(const MachineInstr *MI0, ARMConstantPoolValue *ACPV1 = static_cast(MCPE1.Val.MachineCPVal); return ACPV0->hasSameValue(ACPV1); + } else if (Opcode == ARM::PICLDR) { + if (MI1->getOpcode() != Opcode) + return false; + if (MI0->getNumOperands() != MI1->getNumOperands()) + return false; + + unsigned Addr0 = MI0->getOperand(1).getReg(); + unsigned Addr1 = MI1->getOperand(1).getReg(); + if (Addr0 != Addr1) { + if (!MRI || + !TargetRegisterInfo::isVirtualRegister(Addr0) || + !TargetRegisterInfo::isVirtualRegister(Addr1)) + return false; + + // This assumes SSA form. + MachineInstr *Def0 = MRI->getVRegDef(Addr0); + MachineInstr *Def1 = MRI->getVRegDef(Addr1); + // Check if the loaded value, e.g. a constantpool of a global address, are + // the same. + if (!produceSameValue(Def0, Def1, MRI)) + return false; + } + + for (unsigned i = 3, e = MI0->getNumOperands(); i != e; ++i) { + // %vreg12 = PICLDR %vreg11, 0, pred:14, pred:%noreg + const MachineOperand &MO0 = MI0->getOperand(i); + const MachineOperand &MO1 = MI1->getOperand(i); + if (!MO0.isIdenticalTo(MO1)) + return false; + } + return true; } return MI0->isIdenticalTo(MI1, MachineInstr::IgnoreVRegDefs); @@ -1040,8 +1138,8 @@ bool ARMBaseInstrInfo::areLoadsFromSameBasePtr(SDNode *Load1, SDNode *Load2, switch (Load1->getMachineOpcode()) { default: return false; - case ARM::LDR: - case ARM::LDRB: + case ARM::LDRi12: + case ARM::LDRBi12: case ARM::LDRD: case ARM::LDRH: case ARM::LDRSB: @@ -1059,8 +1157,8 @@ bool ARMBaseInstrInfo::areLoadsFromSameBasePtr(SDNode *Load1, SDNode *Load2, switch (Load2->getMachineOpcode()) { default: return false; - case ARM::LDR: - case ARM::LDRB: + case ARM::LDRi12: + case ARM::LDRBi12: case ARM::LDRD: case ARM::LDRH: case ARM::LDRSB: @@ -1164,22 +1262,37 @@ bool ARMBaseInstrInfo::isSchedulingBoundary(const MachineInstr *MI, return false; } -bool ARMBaseInstrInfo:: -isProfitableToIfCvt(MachineBasicBlock &MBB, unsigned NumInstrs) const { - if (!NumInstrs) +bool ARMBaseInstrInfo::isProfitableToIfCvt(MachineBasicBlock &MBB, + unsigned NumCyles, + unsigned ExtraPredCycles, + float Probability, + float Confidence) const { + if (!NumCyles) return false; - if (Subtarget.getCPUString() == "generic") - // Generic (and overly aggressive) if-conversion limits for testing. - return NumInstrs <= 10; - else if (Subtarget.hasV7Ops()) - return NumInstrs <= 3; - return NumInstrs <= 2; + + // Attempt to estimate the relative costs of predication versus branching. + float UnpredCost = Probability * NumCyles; + UnpredCost += 1.0; // The branch itself + UnpredCost += (1.0 - Confidence) * Subtarget.getMispredictionPenalty(); + + return (float)(NumCyles + ExtraPredCycles) < UnpredCost; } - + bool ARMBaseInstrInfo:: -isProfitableToIfCvt(MachineBasicBlock &TMBB, unsigned NumT, - MachineBasicBlock &FMBB, unsigned NumF) const { - return NumT && NumF && NumT <= 2 && NumF <= 2; +isProfitableToIfCvt(MachineBasicBlock &TMBB, + unsigned TCycles, unsigned TExtra, + MachineBasicBlock &FMBB, + unsigned FCycles, unsigned FExtra, + float Probability, float Confidence) const { + if (!TCycles || !FCycles) + return false; + + // Attempt to estimate the relative costs of predication versus branching. + float UnpredCost = Probability * TCycles + (1.0 - Probability) * FCycles; + UnpredCost += 1.0; // The branch itself + UnpredCost += (1.0 - Confidence) * Subtarget.getMispredictionPenalty(); + + return (float)(TCycles + FCycles + TExtra + FExtra) < UnpredCost; } /// getInstrPredicate - If instruction is predicated, returns its predicate @@ -1292,6 +1405,12 @@ bool llvm::rewriteARMFrameIndex(MachineInstr &MI, unsigned FrameRegIdx, unsigned NumBits = 0; unsigned Scale = 1; switch (AddrMode) { + case ARMII::AddrMode_i12: { + ImmIdx = FrameRegIdx + 1; + InstrOffs = MI.getOperand(ImmIdx).getImm(); + NumBits = 12; + break; + } case ARMII::AddrMode2: { ImmIdx = FrameRegIdx+2; InstrOffs = ARM_AM::getAM2Offset(MI.getOperand(ImmIdx).getImm()); @@ -1342,8 +1461,15 @@ bool llvm::rewriteARMFrameIndex(MachineInstr &MI, unsigned FrameRegIdx, if ((unsigned)Offset <= Mask * Scale) { // Replace the FrameIndex with sp MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false); - if (isSub) - ImmedOffset |= 1 << NumBits; + // FIXME: When addrmode2 goes away, this will simplify (like the + // T2 version), as the LDR.i12 versions don't need the encoding + // tricks for the offset value. + if (isSub) { + if (AddrMode == ARMII::AddrMode_i12) + ImmedOffset = -ImmedOffset; + else + ImmedOffset |= 1 << NumBits; + } ImmOp.ChangeToImmediate(ImmedOffset); Offset = 0; return true; @@ -1351,8 +1477,12 @@ bool llvm::rewriteARMFrameIndex(MachineInstr &MI, unsigned FrameRegIdx, // Otherwise, it didn't fit. Pull in what we can to simplify the immed. ImmedOffset = ImmedOffset & Mask; - if (isSub) - ImmedOffset |= 1 << NumBits; + if (isSub) { + if (AddrMode == ARMII::AddrMode_i12) + ImmedOffset = -ImmedOffset; + else + ImmedOffset |= 1 << NumBits; + } ImmOp.ChangeToImmediate(ImmedOffset); Offset &= ~(Mask*Scale); } @@ -1363,25 +1493,88 @@ bool llvm::rewriteARMFrameIndex(MachineInstr &MI, unsigned FrameRegIdx, } bool ARMBaseInstrInfo:: -AnalyzeCompare(const MachineInstr *MI, unsigned &SrcReg, int &CmpValue) const { +AnalyzeCompare(const MachineInstr *MI, unsigned &SrcReg, int &CmpMask, + int &CmpValue) const { switch (MI->getOpcode()) { default: break; case ARM::CMPri: - case ARM::CMPzri: case ARM::t2CMPri: - case ARM::t2CMPzri: SrcReg = MI->getOperand(0).getReg(); + CmpMask = ~0; CmpValue = MI->getOperand(1).getImm(); return true; + case ARM::TSTri: + case ARM::t2TSTri: + SrcReg = MI->getOperand(0).getReg(); + CmpMask = MI->getOperand(1).getImm(); + CmpValue = 0; + return true; } return false; } -/// ConvertToSetZeroFlag - Convert the instruction to set the "zero" flag so -/// that we can remove a "comparison with zero". +/// isSuitableForMask - Identify a suitable 'and' instruction that +/// operates on the given source register and applies the same mask +/// as a 'tst' instruction. Provide a limited look-through for copies. +/// When successful, MI will hold the found instruction. +static bool isSuitableForMask(MachineInstr *&MI, unsigned SrcReg, + int CmpMask, bool CommonUse) { + switch (MI->getOpcode()) { + case ARM::ANDri: + case ARM::t2ANDri: + if (CmpMask != MI->getOperand(2).getImm()) + return false; + if (SrcReg == MI->getOperand(CommonUse ? 1 : 0).getReg()) + return true; + break; + case ARM::COPY: { + // Walk down one instruction which is potentially an 'and'. + const MachineInstr &Copy = *MI; + MachineBasicBlock::iterator AND( + llvm::next(MachineBasicBlock::iterator(MI))); + if (AND == MI->getParent()->end()) return false; + MI = AND; + return isSuitableForMask(MI, Copy.getOperand(0).getReg(), + CmpMask, true); + } + } + + return false; +} + +/// OptimizeCompareInstr - Convert the instruction supplying the argument to the +/// comparison into one that sets the zero bit in the flags register. bool ARMBaseInstrInfo:: -ConvertToSetZeroFlag(MachineInstr *MI, MachineInstr *CmpInstr) const { +OptimizeCompareInstr(MachineInstr *CmpInstr, unsigned SrcReg, int CmpMask, + int CmpValue, const MachineRegisterInfo *MRI) const { + if (CmpValue != 0) + return false; + + MachineRegisterInfo::def_iterator DI = MRI->def_begin(SrcReg); + if (llvm::next(DI) != MRI->def_end()) + // Only support one definition. + return false; + + MachineInstr *MI = &*DI; + + // Masked compares sometimes use the same register as the corresponding 'and'. + if (CmpMask != ~0) { + if (!isSuitableForMask(MI, SrcReg, CmpMask, false)) { + MI = 0; + for (MachineRegisterInfo::use_iterator UI = MRI->use_begin(SrcReg), + UE = MRI->use_end(); UI != UE; ++UI) { + if (UI->getParent() != CmpInstr->getParent()) continue; + MachineInstr *PotentialAND = &*UI; + if (!isSuitableForMask(PotentialAND, SrcReg, CmpMask, true)) + continue; + MI = PotentialAND; + break; + } + if (!MI) return false; + } + } + // Conservatively refuse to convert an instruction which isn't in the same BB // as the comparison. if (MI->getParent() != CmpInstr->getParent()) @@ -1391,16 +1584,20 @@ ConvertToSetZeroFlag(MachineInstr *MI, MachineInstr *CmpInstr) const { // want to change. MachineBasicBlock::const_iterator I = CmpInstr, E = MI, B = MI->getParent()->begin(); + + // Early exit if CmpInstr is at the beginning of the BB. + if (I == B) return false; + --I; for (; I != E; --I) { const MachineInstr &Instr = *I; for (unsigned IO = 0, EO = Instr.getNumOperands(); IO != EO; ++IO) { const MachineOperand &MO = Instr.getOperand(IO); - if (!MO.isReg() || !MO.isDef()) continue; + if (!MO.isReg()) continue; - // This instruction modifies CPSR before the one we want to change. We - // can't do this transformation. + // This instruction modifies or uses CPSR after the one we want to + // change. We can't do this transformation. if (MO.getReg() == ARM::CPSR) return false; } @@ -1414,15 +1611,713 @@ ConvertToSetZeroFlag(MachineInstr *MI, MachineInstr *CmpInstr) const { switch (MI->getOpcode()) { default: break; case ARM::ADDri: + case ARM::ANDri: + case ARM::t2ANDri: case ARM::SUBri: case ARM::t2ADDri: case ARM::t2SUBri: - MI->RemoveOperand(5); - MachineInstrBuilder(MI) - .addReg(ARM::CPSR, RegState::Define | RegState::Implicit); + // Toggle the optional operand to CPSR. + MI->getOperand(5).setReg(ARM::CPSR); + MI->getOperand(5).setIsDef(true); CmpInstr->eraseFromParent(); return true; } return false; } + +bool ARMBaseInstrInfo::FoldImmediate(MachineInstr *UseMI, + MachineInstr *DefMI, unsigned Reg, + MachineRegisterInfo *MRI) const { + // Fold large immediates into add, sub, or, xor. + unsigned DefOpc = DefMI->getOpcode(); + if (DefOpc != ARM::t2MOVi32imm && DefOpc != ARM::MOVi32imm) + return false; + if (!DefMI->getOperand(1).isImm()) + // Could be t2MOVi32imm + return false; + + if (!MRI->hasOneNonDBGUse(Reg)) + return false; + + unsigned UseOpc = UseMI->getOpcode(); + unsigned NewUseOpc = 0; + uint32_t ImmVal = (uint32_t)DefMI->getOperand(1).getImm(); + uint32_t SOImmValV1 = 0, SOImmValV2 = 0; + bool Commute = false; + switch (UseOpc) { + default: return false; + case ARM::SUBrr: + case ARM::ADDrr: + case ARM::ORRrr: + case ARM::EORrr: + case ARM::t2SUBrr: + case ARM::t2ADDrr: + case ARM::t2ORRrr: + case ARM::t2EORrr: { + Commute = UseMI->getOperand(2).getReg() != Reg; + switch (UseOpc) { + default: break; + case ARM::SUBrr: { + if (Commute) + return false; + ImmVal = -ImmVal; + NewUseOpc = ARM::SUBri; + // Fallthrough + } + case ARM::ADDrr: + case ARM::ORRrr: + case ARM::EORrr: { + if (!ARM_AM::isSOImmTwoPartVal(ImmVal)) + return false; + SOImmValV1 = (uint32_t)ARM_AM::getSOImmTwoPartFirst(ImmVal); + SOImmValV2 = (uint32_t)ARM_AM::getSOImmTwoPartSecond(ImmVal); + switch (UseOpc) { + default: break; + case ARM::ADDrr: NewUseOpc = ARM::ADDri; break; + case ARM::ORRrr: NewUseOpc = ARM::ORRri; break; + case ARM::EORrr: NewUseOpc = ARM::EORri; break; + } + break; + } + case ARM::t2SUBrr: { + if (Commute) + return false; + ImmVal = -ImmVal; + NewUseOpc = ARM::t2SUBri; + // Fallthrough + } + case ARM::t2ADDrr: + case ARM::t2ORRrr: + case ARM::t2EORrr: { + if (!ARM_AM::isT2SOImmTwoPartVal(ImmVal)) + return false; + SOImmValV1 = (uint32_t)ARM_AM::getT2SOImmTwoPartFirst(ImmVal); + SOImmValV2 = (uint32_t)ARM_AM::getT2SOImmTwoPartSecond(ImmVal); + switch (UseOpc) { + default: break; + case ARM::t2ADDrr: NewUseOpc = ARM::t2ADDri; break; + case ARM::t2ORRrr: NewUseOpc = ARM::t2ORRri; break; + case ARM::t2EORrr: NewUseOpc = ARM::t2EORri; break; + } + break; + } + } + } + } + + unsigned OpIdx = Commute ? 2 : 1; + unsigned Reg1 = UseMI->getOperand(OpIdx).getReg(); + bool isKill = UseMI->getOperand(OpIdx).isKill(); + unsigned NewReg = MRI->createVirtualRegister(MRI->getRegClass(Reg)); + AddDefaultCC(AddDefaultPred(BuildMI(*UseMI->getParent(), + *UseMI, UseMI->getDebugLoc(), + get(NewUseOpc), NewReg) + .addReg(Reg1, getKillRegState(isKill)) + .addImm(SOImmValV1))); + UseMI->setDesc(get(NewUseOpc)); + UseMI->getOperand(1).setReg(NewReg); + UseMI->getOperand(1).setIsKill(); + UseMI->getOperand(2).ChangeToImmediate(SOImmValV2); + DefMI->eraseFromParent(); + return true; +} + +unsigned +ARMBaseInstrInfo::getNumMicroOps(const InstrItineraryData *ItinData, + const MachineInstr *MI) const { + if (!ItinData || ItinData->isEmpty()) + return 1; + + const TargetInstrDesc &Desc = MI->getDesc(); + unsigned Class = Desc.getSchedClass(); + unsigned UOps = ItinData->Itineraries[Class].NumMicroOps; + if (UOps) + return UOps; + + unsigned Opc = MI->getOpcode(); + switch (Opc) { + default: + llvm_unreachable("Unexpected multi-uops instruction!"); + break; + case ARM::VLDMQIA: + case ARM::VLDMQDB: + case ARM::VSTMQIA: + case ARM::VSTMQDB: + return 2; + + // The number of uOps for load / store multiple are determined by the number + // registers. + // + // On Cortex-A8, each pair of register loads / stores can be scheduled on the + // same cycle. The scheduling for the first load / store must be done + // separately by assuming the the address is not 64-bit aligned. + // + // On Cortex-A9, the formula is simply (#reg / 2) + (#reg % 2). If the address + // is not 64-bit aligned, then AGU would take an extra cycle. For VFP / NEON + // load / store multiple, the formula is (#reg / 2) + (#reg % 2) + 1. + case ARM::VLDMDIA: + case ARM::VLDMDDB: + case ARM::VLDMDIA_UPD: + case ARM::VLDMDDB_UPD: + case ARM::VLDMSIA: + case ARM::VLDMSDB: + case ARM::VLDMSIA_UPD: + case ARM::VLDMSDB_UPD: + case ARM::VSTMDIA: + case ARM::VSTMDDB: + case ARM::VSTMDIA_UPD: + case ARM::VSTMDDB_UPD: + case ARM::VSTMSIA: + case ARM::VSTMSDB: + case ARM::VSTMSIA_UPD: + case ARM::VSTMSDB_UPD: { + unsigned NumRegs = MI->getNumOperands() - Desc.getNumOperands(); + return (NumRegs / 2) + (NumRegs % 2) + 1; + } + + case ARM::LDMIA_RET: + case ARM::LDMIA: + case ARM::LDMDA: + case ARM::LDMDB: + case ARM::LDMIB: + case ARM::LDMIA_UPD: + case ARM::LDMDA_UPD: + case ARM::LDMDB_UPD: + case ARM::LDMIB_UPD: + case ARM::STMIA: + case ARM::STMDA: + case ARM::STMDB: + case ARM::STMIB: + case ARM::STMIA_UPD: + case ARM::STMDA_UPD: + case ARM::STMDB_UPD: + case ARM::STMIB_UPD: + case ARM::tLDMIA: + case ARM::tLDMIA_UPD: + case ARM::tSTMIA: + case ARM::tSTMIA_UPD: + case ARM::tPOP_RET: + case ARM::tPOP: + case ARM::tPUSH: + case ARM::t2LDMIA_RET: + case ARM::t2LDMIA: + case ARM::t2LDMDB: + case ARM::t2LDMIA_UPD: + case ARM::t2LDMDB_UPD: + case ARM::t2STMIA: + case ARM::t2STMDB: + case ARM::t2STMIA_UPD: + case ARM::t2STMDB_UPD: { + unsigned NumRegs = MI->getNumOperands() - Desc.getNumOperands() + 1; + if (Subtarget.isCortexA8()) { + if (NumRegs < 4) + return 2; + // 4 registers would be issued: 2, 2. + // 5 registers would be issued: 2, 2, 1. + UOps = (NumRegs / 2); + if (NumRegs % 2) + ++UOps; + return UOps; + } else if (Subtarget.isCortexA9()) { + UOps = (NumRegs / 2); + // If there are odd number of registers or if it's not 64-bit aligned, + // then it takes an extra AGU (Address Generation Unit) cycle. + if ((NumRegs % 2) || + !MI->hasOneMemOperand() || + (*MI->memoperands_begin())->getAlignment() < 8) + ++UOps; + return UOps; + } else { + // Assume the worst. + return NumRegs; + } + } + } +} + +int +ARMBaseInstrInfo::getVLDMDefCycle(const InstrItineraryData *ItinData, + const TargetInstrDesc &DefTID, + unsigned DefClass, + unsigned DefIdx, unsigned DefAlign) const { + int RegNo = (int)(DefIdx+1) - DefTID.getNumOperands() + 1; + if (RegNo <= 0) + // Def is the address writeback. + return ItinData->getOperandCycle(DefClass, DefIdx); + + int DefCycle; + if (Subtarget.isCortexA8()) { + // (regno / 2) + (regno % 2) + 1 + DefCycle = RegNo / 2 + 1; + if (RegNo % 2) + ++DefCycle; + } else if (Subtarget.isCortexA9()) { + DefCycle = RegNo; + bool isSLoad = false; + + switch (DefTID.getOpcode()) { + default: break; + case ARM::VLDMSIA: + case ARM::VLDMSDB: + case ARM::VLDMSIA_UPD: + case ARM::VLDMSDB_UPD: + isSLoad = true; + break; + } + + // If there are odd number of 'S' registers or if it's not 64-bit aligned, + // then it takes an extra cycle. + if ((isSLoad && (RegNo % 2)) || DefAlign < 8) + ++DefCycle; + } else { + // Assume the worst. + DefCycle = RegNo + 2; + } + + return DefCycle; +} + +int +ARMBaseInstrInfo::getLDMDefCycle(const InstrItineraryData *ItinData, + const TargetInstrDesc &DefTID, + unsigned DefClass, + unsigned DefIdx, unsigned DefAlign) const { + int RegNo = (int)(DefIdx+1) - DefTID.getNumOperands() + 1; + if (RegNo <= 0) + // Def is the address writeback. + return ItinData->getOperandCycle(DefClass, DefIdx); + + int DefCycle; + if (Subtarget.isCortexA8()) { + // 4 registers would be issued: 1, 2, 1. + // 5 registers would be issued: 1, 2, 2. + DefCycle = RegNo / 2; + if (DefCycle < 1) + DefCycle = 1; + // Result latency is issue cycle + 2: E2. + DefCycle += 2; + } else if (Subtarget.isCortexA9()) { + DefCycle = (RegNo / 2); + // If there are odd number of registers or if it's not 64-bit aligned, + // then it takes an extra AGU (Address Generation Unit) cycle. + if ((RegNo % 2) || DefAlign < 8) + ++DefCycle; + // Result latency is AGU cycles + 2. + DefCycle += 2; + } else { + // Assume the worst. + DefCycle = RegNo + 2; + } + + return DefCycle; +} + +int +ARMBaseInstrInfo::getVSTMUseCycle(const InstrItineraryData *ItinData, + const TargetInstrDesc &UseTID, + unsigned UseClass, + unsigned UseIdx, unsigned UseAlign) const { + int RegNo = (int)(UseIdx+1) - UseTID.getNumOperands() + 1; + if (RegNo <= 0) + return ItinData->getOperandCycle(UseClass, UseIdx); + + int UseCycle; + if (Subtarget.isCortexA8()) { + // (regno / 2) + (regno % 2) + 1 + UseCycle = RegNo / 2 + 1; + if (RegNo % 2) + ++UseCycle; + } else if (Subtarget.isCortexA9()) { + UseCycle = RegNo; + bool isSStore = false; + + switch (UseTID.getOpcode()) { + default: break; + case ARM::VSTMSIA: + case ARM::VSTMSDB: + case ARM::VSTMSIA_UPD: + case ARM::VSTMSDB_UPD: + isSStore = true; + break; + } + + // If there are odd number of 'S' registers or if it's not 64-bit aligned, + // then it takes an extra cycle. + if ((isSStore && (RegNo % 2)) || UseAlign < 8) + ++UseCycle; + } else { + // Assume the worst. + UseCycle = RegNo + 2; + } + + return UseCycle; +} + +int +ARMBaseInstrInfo::getSTMUseCycle(const InstrItineraryData *ItinData, + const TargetInstrDesc &UseTID, + unsigned UseClass, + unsigned UseIdx, unsigned UseAlign) const { + int RegNo = (int)(UseIdx+1) - UseTID.getNumOperands() + 1; + if (RegNo <= 0) + return ItinData->getOperandCycle(UseClass, UseIdx); + + int UseCycle; + if (Subtarget.isCortexA8()) { + UseCycle = RegNo / 2; + if (UseCycle < 2) + UseCycle = 2; + // Read in E3. + UseCycle += 2; + } else if (Subtarget.isCortexA9()) { + UseCycle = (RegNo / 2); + // If there are odd number of registers or if it's not 64-bit aligned, + // then it takes an extra AGU (Address Generation Unit) cycle. + if ((RegNo % 2) || UseAlign < 8) + ++UseCycle; + } else { + // Assume the worst. + UseCycle = 1; + } + return UseCycle; +} + +int +ARMBaseInstrInfo::getOperandLatency(const InstrItineraryData *ItinData, + const TargetInstrDesc &DefTID, + unsigned DefIdx, unsigned DefAlign, + const TargetInstrDesc &UseTID, + unsigned UseIdx, unsigned UseAlign) const { + unsigned DefClass = DefTID.getSchedClass(); + unsigned UseClass = UseTID.getSchedClass(); + + if (DefIdx < DefTID.getNumDefs() && UseIdx < UseTID.getNumOperands()) + return ItinData->getOperandLatency(DefClass, DefIdx, UseClass, UseIdx); + + // This may be a def / use of a variable_ops instruction, the operand + // latency might be determinable dynamically. Let the target try to + // figure it out. + int DefCycle = -1; + bool LdmBypass = false; + switch (DefTID.getOpcode()) { + default: + DefCycle = ItinData->getOperandCycle(DefClass, DefIdx); + break; + + case ARM::VLDMDIA: + case ARM::VLDMDDB: + case ARM::VLDMDIA_UPD: + case ARM::VLDMDDB_UPD: + case ARM::VLDMSIA: + case ARM::VLDMSDB: + case ARM::VLDMSIA_UPD: + case ARM::VLDMSDB_UPD: + DefCycle = getVLDMDefCycle(ItinData, DefTID, DefClass, DefIdx, DefAlign); + break; + + case ARM::LDMIA_RET: + case ARM::LDMIA: + case ARM::LDMDA: + case ARM::LDMDB: + case ARM::LDMIB: + case ARM::LDMIA_UPD: + case ARM::LDMDA_UPD: + case ARM::LDMDB_UPD: + case ARM::LDMIB_UPD: + case ARM::tLDMIA: + case ARM::tLDMIA_UPD: + case ARM::tPUSH: + case ARM::t2LDMIA_RET: + case ARM::t2LDMIA: + case ARM::t2LDMDB: + case ARM::t2LDMIA_UPD: + case ARM::t2LDMDB_UPD: + LdmBypass = 1; + DefCycle = getLDMDefCycle(ItinData, DefTID, DefClass, DefIdx, DefAlign); + break; + } + + if (DefCycle == -1) + // We can't seem to determine the result latency of the def, assume it's 2. + DefCycle = 2; + + int UseCycle = -1; + switch (UseTID.getOpcode()) { + default: + UseCycle = ItinData->getOperandCycle(UseClass, UseIdx); + break; + + case ARM::VSTMDIA: + case ARM::VSTMDDB: + case ARM::VSTMDIA_UPD: + case ARM::VSTMDDB_UPD: + case ARM::VSTMSIA: + case ARM::VSTMSDB: + case ARM::VSTMSIA_UPD: + case ARM::VSTMSDB_UPD: + UseCycle = getVSTMUseCycle(ItinData, UseTID, UseClass, UseIdx, UseAlign); + break; + + case ARM::STMIA: + case ARM::STMDA: + case ARM::STMDB: + case ARM::STMIB: + case ARM::STMIA_UPD: + case ARM::STMDA_UPD: + case ARM::STMDB_UPD: + case ARM::STMIB_UPD: + case ARM::tSTMIA: + case ARM::tSTMIA_UPD: + case ARM::tPOP_RET: + case ARM::tPOP: + case ARM::t2STMIA: + case ARM::t2STMDB: + case ARM::t2STMIA_UPD: + case ARM::t2STMDB_UPD: + UseCycle = getSTMUseCycle(ItinData, UseTID, UseClass, UseIdx, UseAlign); + break; + } + + if (UseCycle == -1) + // Assume it's read in the first stage. + UseCycle = 1; + + UseCycle = DefCycle - UseCycle + 1; + if (UseCycle > 0) { + if (LdmBypass) { + // It's a variable_ops instruction so we can't use DefIdx here. Just use + // first def operand. + if (ItinData->hasPipelineForwarding(DefClass, DefTID.getNumOperands()-1, + UseClass, UseIdx)) + --UseCycle; + } else if (ItinData->hasPipelineForwarding(DefClass, DefIdx, + UseClass, UseIdx)) { + --UseCycle; + } + } + + return UseCycle; +} + +int +ARMBaseInstrInfo::getOperandLatency(const InstrItineraryData *ItinData, + const MachineInstr *DefMI, unsigned DefIdx, + const MachineInstr *UseMI, unsigned UseIdx) const { + if (DefMI->isCopyLike() || DefMI->isInsertSubreg() || + DefMI->isRegSequence() || DefMI->isImplicitDef()) + return 1; + + const TargetInstrDesc &DefTID = DefMI->getDesc(); + if (!ItinData || ItinData->isEmpty()) + return DefTID.mayLoad() ? 3 : 1; + + const TargetInstrDesc &UseTID = UseMI->getDesc(); + const MachineOperand &DefMO = DefMI->getOperand(DefIdx); + if (DefMO.getReg() == ARM::CPSR) { + if (DefMI->getOpcode() == ARM::FMSTAT) { + // fpscr -> cpsr stalls over 20 cycles on A8 (and earlier?) + return Subtarget.isCortexA9() ? 1 : 20; + } + + // CPSR set and branch can be paired in the same cycle. + if (UseTID.isBranch()) + return 0; + } + + unsigned DefAlign = DefMI->hasOneMemOperand() + ? (*DefMI->memoperands_begin())->getAlignment() : 0; + unsigned UseAlign = UseMI->hasOneMemOperand() + ? (*UseMI->memoperands_begin())->getAlignment() : 0; + int Latency = getOperandLatency(ItinData, DefTID, DefIdx, DefAlign, + UseTID, UseIdx, UseAlign); + + if (Latency > 1 && + (Subtarget.isCortexA8() || Subtarget.isCortexA9())) { + // FIXME: Shifter op hack: no shift (i.e. [r +/- r]) or [r + r << 2] + // variants are one cycle cheaper. + switch (DefTID.getOpcode()) { + default: break; + case ARM::LDRrs: + case ARM::LDRBrs: { + unsigned ShOpVal = DefMI->getOperand(3).getImm(); + unsigned ShImm = ARM_AM::getAM2Offset(ShOpVal); + if (ShImm == 0 || + (ShImm == 2 && ARM_AM::getAM2ShiftOpc(ShOpVal) == ARM_AM::lsl)) + --Latency; + break; + } + case ARM::t2LDRs: + case ARM::t2LDRBs: + case ARM::t2LDRHs: + case ARM::t2LDRSHs: { + // Thumb2 mode: lsl only. + unsigned ShAmt = DefMI->getOperand(3).getImm(); + if (ShAmt == 0 || ShAmt == 2) + --Latency; + break; + } + } + } + + return Latency; +} + +int +ARMBaseInstrInfo::getOperandLatency(const InstrItineraryData *ItinData, + SDNode *DefNode, unsigned DefIdx, + SDNode *UseNode, unsigned UseIdx) const { + if (!DefNode->isMachineOpcode()) + return 1; + + const TargetInstrDesc &DefTID = get(DefNode->getMachineOpcode()); + + if (isZeroCost(DefTID.Opcode)) + return 0; + + if (!ItinData || ItinData->isEmpty()) + return DefTID.mayLoad() ? 3 : 1; + + if (!UseNode->isMachineOpcode()) { + int Latency = ItinData->getOperandCycle(DefTID.getSchedClass(), DefIdx); + if (Subtarget.isCortexA9()) + return Latency <= 2 ? 1 : Latency - 1; + else + return Latency <= 3 ? 1 : Latency - 2; + } + + const TargetInstrDesc &UseTID = get(UseNode->getMachineOpcode()); + const MachineSDNode *DefMN = dyn_cast(DefNode); + unsigned DefAlign = !DefMN->memoperands_empty() + ? (*DefMN->memoperands_begin())->getAlignment() : 0; + const MachineSDNode *UseMN = dyn_cast(UseNode); + unsigned UseAlign = !UseMN->memoperands_empty() + ? (*UseMN->memoperands_begin())->getAlignment() : 0; + int Latency = getOperandLatency(ItinData, DefTID, DefIdx, DefAlign, + UseTID, UseIdx, UseAlign); + + if (Latency > 1 && + (Subtarget.isCortexA8() || Subtarget.isCortexA9())) { + // FIXME: Shifter op hack: no shift (i.e. [r +/- r]) or [r + r << 2] + // variants are one cycle cheaper. + switch (DefTID.getOpcode()) { + default: break; + case ARM::LDRrs: + case ARM::LDRBrs: { + unsigned ShOpVal = + cast(DefNode->getOperand(2))->getZExtValue(); + unsigned ShImm = ARM_AM::getAM2Offset(ShOpVal); + if (ShImm == 0 || + (ShImm == 2 && ARM_AM::getAM2ShiftOpc(ShOpVal) == ARM_AM::lsl)) + --Latency; + break; + } + case ARM::t2LDRs: + case ARM::t2LDRBs: + case ARM::t2LDRHs: + case ARM::t2LDRSHs: { + // Thumb2 mode: lsl only. + unsigned ShAmt = + cast(DefNode->getOperand(2))->getZExtValue(); + if (ShAmt == 0 || ShAmt == 2) + --Latency; + break; + } + } + } + + return Latency; +} + +int ARMBaseInstrInfo::getInstrLatency(const InstrItineraryData *ItinData, + const MachineInstr *MI, + unsigned *PredCost) const { + if (MI->isCopyLike() || MI->isInsertSubreg() || + MI->isRegSequence() || MI->isImplicitDef()) + return 1; + + if (!ItinData || ItinData->isEmpty()) + return 1; + + const TargetInstrDesc &TID = MI->getDesc(); + unsigned Class = TID.getSchedClass(); + unsigned UOps = ItinData->Itineraries[Class].NumMicroOps; + if (PredCost && TID.hasImplicitDefOfPhysReg(ARM::CPSR)) + // When predicated, CPSR is an additional source operand for CPSR updating + // instructions, this apparently increases their latencies. + *PredCost = 1; + if (UOps) + return ItinData->getStageLatency(Class); + return getNumMicroOps(ItinData, MI); +} + +int ARMBaseInstrInfo::getInstrLatency(const InstrItineraryData *ItinData, + SDNode *Node) const { + if (!Node->isMachineOpcode()) + return 1; + + if (!ItinData || ItinData->isEmpty()) + return 1; + + unsigned Opcode = Node->getMachineOpcode(); + switch (Opcode) { + default: + return ItinData->getStageLatency(get(Opcode).getSchedClass()); + case ARM::VLDMQIA: + case ARM::VLDMQDB: + case ARM::VSTMQIA: + case ARM::VSTMQDB: + return 2; + } +} + +bool ARMBaseInstrInfo:: +hasHighOperandLatency(const InstrItineraryData *ItinData, + const MachineRegisterInfo *MRI, + const MachineInstr *DefMI, unsigned DefIdx, + const MachineInstr *UseMI, unsigned UseIdx) const { + unsigned DDomain = DefMI->getDesc().TSFlags & ARMII::DomainMask; + unsigned UDomain = UseMI->getDesc().TSFlags & ARMII::DomainMask; + if (Subtarget.isCortexA8() && + (DDomain == ARMII::DomainVFP || UDomain == ARMII::DomainVFP)) + // CortexA8 VFP instructions are not pipelined. + return true; + + // Hoist VFP / NEON instructions with 4 or higher latency. + int Latency = getOperandLatency(ItinData, DefMI, DefIdx, UseMI, UseIdx); + if (Latency <= 3) + return false; + return DDomain == ARMII::DomainVFP || DDomain == ARMII::DomainNEON || + UDomain == ARMII::DomainVFP || UDomain == ARMII::DomainNEON; +} + +bool ARMBaseInstrInfo:: +hasLowDefLatency(const InstrItineraryData *ItinData, + const MachineInstr *DefMI, unsigned DefIdx) const { + if (!ItinData || ItinData->isEmpty()) + return false; + + unsigned DDomain = DefMI->getDesc().TSFlags & ARMII::DomainMask; + if (DDomain == ARMII::DomainGeneral) { + unsigned DefClass = DefMI->getDesc().getSchedClass(); + int DefCycle = ItinData->getOperandCycle(DefClass, DefIdx); + return (DefCycle != -1 && DefCycle <= 2); + } + return false; +} + +bool +ARMBaseInstrInfo::isFpMLxInstruction(unsigned Opcode, unsigned &MulOpc, + unsigned &AddSubOpc, + bool &NegAcc, bool &HasLane) const { + DenseMap::const_iterator I = MLxEntryMap.find(Opcode); + if (I == MLxEntryMap.end()) + return false; + + const ARM_MLxEntry &Entry = ARM_MLxTable[I->second]; + MulOpc = Entry.MulOpc; + AddSubOpc = Entry.AddSubOpc; + NegAcc = Entry.NegAcc; + HasLane = Entry.HasLane; + return true; +} diff --git a/lib/Target/ARM/ARMBaseInstrInfo.h b/lib/Target/ARM/ARMBaseInstrInfo.h index b4f4a33a70ad..1fb88726d0de 100644 --- a/lib/Target/ARM/ARMBaseInstrInfo.h +++ b/lib/Target/ARM/ARMBaseInstrInfo.h @@ -17,6 +17,8 @@ #include "ARM.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/Target/TargetInstrInfo.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallSet.h" namespace llvm { class ARMSubtarget; @@ -33,7 +35,7 @@ namespace ARMII { //===------------------------------------------------------------------===// // This four-bit field describes the addressing mode used. - AddrModeMask = 0xf, + AddrModeMask = 0x1f, AddrModeNone = 0, AddrMode1 = 1, AddrMode2 = 2, @@ -50,9 +52,10 @@ namespace ARMII { AddrModeT2_so = 13, AddrModeT2_pc = 14, // +/- i12 for pc relative data AddrModeT2_i8s4 = 15, // i8 * 4 + AddrMode_i12 = 16, // Size* - Flags to keep track of the size of an instruction. - SizeShift = 4, + SizeShift = 5, SizeMask = 7 << SizeShift, SizeSpecial = 1, // 0 byte pseudo or special case. Size8Bytes = 2, @@ -61,7 +64,7 @@ namespace ARMII { // IndexMode - Unindex, pre-indexed, or post-indexed are valid for load // and store ops only. Generic "updating" flag is used for ld/st multiple. - IndexModeShift = 7, + IndexModeShift = 8, IndexModeMask = 3 << IndexModeShift, IndexModePre = 1, IndexModePost = 2, @@ -70,7 +73,7 @@ namespace ARMII { //===------------------------------------------------------------------===// // Instruction encoding formats. // - FormShift = 9, + FormShift = 10, FormMask = 0x3f << FormShift, // Pseudo instructions @@ -143,15 +146,15 @@ namespace ARMII { // UnaryDP - Indicates this is a unary data processing instruction, i.e. // it doesn't have a Rn operand. - UnaryDP = 1 << 15, + UnaryDP = 1 << 16, // Xform16Bit - Indicates this Thumb2 instruction may be transformed into // a 16-bit Thumb instruction if certain conditions are met. - Xform16Bit = 1 << 16, + Xform16Bit = 1 << 17, //===------------------------------------------------------------------===// // Code domain. - DomainShift = 17, + DomainShift = 18, DomainMask = 3 << DomainShift, DomainGeneral = 0 << DomainShift, DomainVFP = 1 << DomainShift, @@ -160,6 +163,11 @@ namespace ARMII { //===------------------------------------------------------------------===// // Field shifts - such shifts are used to set field while generating // machine instructions. + // + // FIXME: This list will need adjusting/fixing as the MC code emitter + // takes shape and the ARMCodeEmitter.cpp bits go away. + ShiftTypeShift = 4, + M_BitShift = 5, ShiftImmShift = 5, ShiftShift = 7, @@ -181,29 +189,15 @@ namespace ARMII { I_BitShift = 25, CondShift = 28 }; - - /// Target Operand Flag enum. - enum TOF { - //===------------------------------------------------------------------===// - // ARM Specific MachineOperand flags. - - MO_NO_FLAG, - - /// MO_LO16 - On a symbol operand, this represents a relocation containing - /// lower 16 bit of the address. Used only via movw instruction. - MO_LO16, - - /// MO_HI16 - On a symbol operand, this represents a relocation containing - /// higher 16 bit of the address. Used only via movt instruction. - MO_HI16 - }; } class ARMBaseInstrInfo : public TargetInstrInfoImpl { const ARMSubtarget &Subtarget; + protected: // Can be only subclassed. explicit ARMBaseInstrInfo(const ARMSubtarget &STI); + public: // Return the non-pre/post incrementing version of 'Opc'. Return 0 // if there is not such an opcode. @@ -216,10 +210,13 @@ public: virtual const ARMBaseRegisterInfo &getRegisterInfo() const =0; const ARMSubtarget &getSubtarget() const { return Subtarget; } - bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, - MachineBasicBlock::iterator MI, - const std::vector &CSI, - const TargetRegisterInfo *TRI) const; + ScheduleHazardRecognizer * + CreateTargetHazardRecognizer(const TargetMachine *TM, + const ScheduleDAG *DAG) const; + + ScheduleHazardRecognizer * + CreateTargetPostRAHazardRecognizer(const InstrItineraryData *II, + const ScheduleDAG *DAG) const; // Branch analysis. virtual bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, @@ -301,7 +298,8 @@ public: MachineInstr *duplicate(MachineInstr *Orig, MachineFunction &MF) const; virtual bool produceSameValue(const MachineInstr *MI0, - const MachineInstr *MI1) const; + const MachineInstr *MI1, + const MachineRegisterInfo *MRI) const; /// areLoadsFromSameBasePtr - This is used by the pre-regalloc scheduler to /// determine if two loads are loading from the same base address. It should @@ -328,26 +326,117 @@ public: const MachineFunction &MF) const; virtual bool isProfitableToIfCvt(MachineBasicBlock &MBB, - unsigned NumInstrs) const; + unsigned NumCyles, unsigned ExtraPredCycles, + float Prob, float Confidence) const; - virtual bool isProfitableToIfCvt(MachineBasicBlock &TMBB,unsigned NumT, - MachineBasicBlock &FMBB,unsigned NumF) const; + virtual bool isProfitableToIfCvt(MachineBasicBlock &TMBB, + unsigned NumT, unsigned ExtraT, + MachineBasicBlock &FMBB, + unsigned NumF, unsigned ExtraF, + float Probability, float Confidence) const; virtual bool isProfitableToDupForIfCvt(MachineBasicBlock &MBB, - unsigned NumInstrs) const { - return NumInstrs && NumInstrs == 1; + unsigned NumCyles, + float Probability, + float Confidence) const { + return NumCyles == 1; } /// AnalyzeCompare - For a comparison instruction, return the source register /// in SrcReg and the value it compares against in CmpValue. Return true if /// the comparison instruction can be analyzed. virtual bool AnalyzeCompare(const MachineInstr *MI, unsigned &SrcReg, - int &CmpValue) const; + int &CmpMask, int &CmpValue) const; - /// ConvertToSetZeroFlag - Convert the instruction to set the zero flag so + /// OptimizeCompareInstr - Convert the instruction to set the zero flag so /// that we can remove a "comparison with zero". - virtual bool ConvertToSetZeroFlag(MachineInstr *Instr, - MachineInstr *CmpInstr) const; + virtual bool OptimizeCompareInstr(MachineInstr *CmpInstr, unsigned SrcReg, + int CmpMask, int CmpValue, + const MachineRegisterInfo *MRI) const; + + /// FoldImmediate - 'Reg' is known to be defined by a move immediate + /// instruction, try to fold the immediate into the use instruction. + virtual bool FoldImmediate(MachineInstr *UseMI, MachineInstr *DefMI, + unsigned Reg, MachineRegisterInfo *MRI) const; + + virtual unsigned getNumMicroOps(const InstrItineraryData *ItinData, + const MachineInstr *MI) const; + + virtual + int getOperandLatency(const InstrItineraryData *ItinData, + const MachineInstr *DefMI, unsigned DefIdx, + const MachineInstr *UseMI, unsigned UseIdx) const; + virtual + int getOperandLatency(const InstrItineraryData *ItinData, + SDNode *DefNode, unsigned DefIdx, + SDNode *UseNode, unsigned UseIdx) const; +private: + int getVLDMDefCycle(const InstrItineraryData *ItinData, + const TargetInstrDesc &DefTID, + unsigned DefClass, + unsigned DefIdx, unsigned DefAlign) const; + int getLDMDefCycle(const InstrItineraryData *ItinData, + const TargetInstrDesc &DefTID, + unsigned DefClass, + unsigned DefIdx, unsigned DefAlign) const; + int getVSTMUseCycle(const InstrItineraryData *ItinData, + const TargetInstrDesc &UseTID, + unsigned UseClass, + unsigned UseIdx, unsigned UseAlign) const; + int getSTMUseCycle(const InstrItineraryData *ItinData, + const TargetInstrDesc &UseTID, + unsigned UseClass, + unsigned UseIdx, unsigned UseAlign) const; + int getOperandLatency(const InstrItineraryData *ItinData, + const TargetInstrDesc &DefTID, + unsigned DefIdx, unsigned DefAlign, + const TargetInstrDesc &UseTID, + unsigned UseIdx, unsigned UseAlign) const; + + int getInstrLatency(const InstrItineraryData *ItinData, + const MachineInstr *MI, unsigned *PredCost = 0) const; + + int getInstrLatency(const InstrItineraryData *ItinData, + SDNode *Node) const; + + bool hasHighOperandLatency(const InstrItineraryData *ItinData, + const MachineRegisterInfo *MRI, + const MachineInstr *DefMI, unsigned DefIdx, + const MachineInstr *UseMI, unsigned UseIdx) const; + bool hasLowDefLatency(const InstrItineraryData *ItinData, + const MachineInstr *DefMI, unsigned DefIdx) const; + +private: + /// Modeling special VFP / NEON fp MLA / MLS hazards. + + /// MLxEntryMap - Map fp MLA / MLS to the corresponding entry in the internal + /// MLx table. + DenseMap MLxEntryMap; + + /// MLxHazardOpcodes - Set of add / sub and multiply opcodes that would cause + /// stalls when scheduled together with fp MLA / MLS opcodes. + SmallSet MLxHazardOpcodes; + +public: + /// isFpMLxInstruction - Return true if the specified opcode is a fp MLA / MLS + /// instruction. + bool isFpMLxInstruction(unsigned Opcode) const { + return MLxEntryMap.count(Opcode); + } + + /// isFpMLxInstruction - This version also returns the multiply opcode and the + /// addition / subtraction opcode to expand to. Return true for 'HasLane' for + /// the MLX instructions with an extra lane operand. + bool isFpMLxInstruction(unsigned Opcode, unsigned &MulOpc, + unsigned &AddSubOpc, bool &NegAcc, + bool &HasLane) const; + + /// canCauseFpMLxStall - Return true if an instruction of the specified opcode + /// will cause stalls when scheduled after (within 4-cycle window) a fp + /// MLA / MLS instruction. + bool canCauseFpMLxStall(unsigned Opcode) const { + return MLxHazardOpcodes.count(Opcode); + } }; static inline @@ -389,7 +478,7 @@ bool isJumpTableBranchOpcode(int Opc) { static inline bool isIndirectBranchOpcode(int Opc) { - return Opc == ARM::BRIND || Opc == ARM::MOVPCRX || Opc == ARM::tBRIND; + return Opc == ARM::BX || Opc == ARM::MOVPCRX || Opc == ARM::tBRIND; } /// getInstrPredicate - If instruction is predicated, returns its predicate @@ -413,6 +502,12 @@ void emitT2RegPlusImmediate(MachineBasicBlock &MBB, unsigned DestReg, unsigned BaseReg, int NumBytes, ARMCC::CondCodes Pred, unsigned PredReg, const ARMBaseInstrInfo &TII); +void emitThumbRegPlusImmediate(MachineBasicBlock &MBB, + MachineBasicBlock::iterator &MBBI, + unsigned DestReg, unsigned BaseReg, + int NumBytes, const TargetInstrInfo &TII, + const ARMBaseRegisterInfo& MRI, + DebugLoc dl); /// rewriteARMFrameIndex / rewriteT2FrameIndex - diff --git a/lib/Target/ARM/ARMBaseRegisterInfo.cpp b/lib/Target/ARM/ARMBaseRegisterInfo.cpp index eceafad63f17..67a4b7d49398 100644 --- a/lib/Target/ARM/ARMBaseRegisterInfo.cpp +++ b/lib/Target/ARM/ARMBaseRegisterInfo.cpp @@ -15,6 +15,7 @@ #include "ARMAddressingModes.h" #include "ARMBaseInstrInfo.h" #include "ARMBaseRegisterInfo.h" +#include "ARMFrameLowering.h" #include "ARMInstrInfo.h" #include "ARMMachineFunctionInfo.h" #include "ARMSubtarget.h" @@ -32,120 +33,25 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetFrameInfo.h" +#include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/CommandLine.h" -namespace llvm { +using namespace llvm; + static cl::opt ForceAllBaseRegAlloc("arm-force-base-reg-alloc", cl::Hidden, cl::init(false), cl::desc("Force use of virtual base registers for stack load/store")); static cl::opt EnableLocalStackAlloc("enable-local-stack-alloc", cl::init(true), cl::Hidden, cl::desc("Enable pre-regalloc stack frame index allocation")); -} - -using namespace llvm; - static cl::opt EnableBasePointer("arm-use-base-pointer", cl::Hidden, cl::init(true), cl::desc("Enable use of a base pointer for complex stack frames")); -unsigned ARMBaseRegisterInfo::getRegisterNumbering(unsigned RegEnum, - bool *isSPVFP) { - if (isSPVFP) - *isSPVFP = false; - - using namespace ARM; - switch (RegEnum) { - default: - llvm_unreachable("Unknown ARM register!"); - case R0: case D0: case Q0: return 0; - case R1: case D1: case Q1: return 1; - case R2: case D2: case Q2: return 2; - case R3: case D3: case Q3: return 3; - case R4: case D4: case Q4: return 4; - case R5: case D5: case Q5: return 5; - case R6: case D6: case Q6: return 6; - case R7: case D7: case Q7: return 7; - case R8: case D8: case Q8: return 8; - case R9: case D9: case Q9: return 9; - case R10: case D10: case Q10: return 10; - case R11: case D11: case Q11: return 11; - case R12: case D12: case Q12: return 12; - case SP: case D13: case Q13: return 13; - case LR: case D14: case Q14: return 14; - case PC: case D15: case Q15: return 15; - - case D16: return 16; - case D17: return 17; - case D18: return 18; - case D19: return 19; - case D20: return 20; - case D21: return 21; - case D22: return 22; - case D23: return 23; - case D24: return 24; - case D25: return 25; - case D26: return 26; - case D27: return 27; - case D28: return 28; - case D29: return 29; - case D30: return 30; - case D31: return 31; - - case S0: case S1: case S2: case S3: - case S4: case S5: case S6: case S7: - case S8: case S9: case S10: case S11: - case S12: case S13: case S14: case S15: - case S16: case S17: case S18: case S19: - case S20: case S21: case S22: case S23: - case S24: case S25: case S26: case S27: - case S28: case S29: case S30: case S31: { - if (isSPVFP) - *isSPVFP = true; - switch (RegEnum) { - default: return 0; // Avoid compile time warning. - case S0: return 0; - case S1: return 1; - case S2: return 2; - case S3: return 3; - case S4: return 4; - case S5: return 5; - case S6: return 6; - case S7: return 7; - case S8: return 8; - case S9: return 9; - case S10: return 10; - case S11: return 11; - case S12: return 12; - case S13: return 13; - case S14: return 14; - case S15: return 15; - case S16: return 16; - case S17: return 17; - case S18: return 18; - case S19: return 19; - case S20: return 20; - case S21: return 21; - case S22: return 22; - case S23: return 23; - case S24: return 24; - case S25: return 25; - case S26: return 26; - case S27: return 27; - case S28: return 28; - case S29: return 29; - case S30: return 30; - case S31: return 31; - } - } - } -} - ARMBaseRegisterInfo::ARMBaseRegisterInfo(const ARMBaseInstrInfo &tii, const ARMSubtarget &sti) : ARMGenRegisterInfo(ARM::ADJCALLSTACKDOWN, ARM::ADJCALLSTACKUP), @@ -180,12 +86,14 @@ ARMBaseRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { BitVector ARMBaseRegisterInfo:: getReservedRegs(const MachineFunction &MF) const { + const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); + // FIXME: avoid re-calculating this everytime. BitVector Reserved(getNumRegs()); Reserved.set(ARM::SP); Reserved.set(ARM::PC); Reserved.set(ARM::FPSCR); - if (hasFP(MF)) + if (TFI->hasFP(MF)) Reserved.set(FramePtr); if (hasBasePointer(MF)) Reserved.set(BasePtr); @@ -197,6 +105,8 @@ getReservedRegs(const MachineFunction &MF) const { bool ARMBaseRegisterInfo::isReservedReg(const MachineFunction &MF, unsigned Reg) const { + const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); + switch (Reg) { default: break; case ARM::SP: @@ -208,7 +118,7 @@ bool ARMBaseRegisterInfo::isReservedReg(const MachineFunction &MF, break; case ARM::R7: case ARM::R11: - if (FramePtr == Reg && hasFP(MF)) + if (FramePtr == Reg && TFI->hasFP(MF)) return true; break; case ARM::R9: @@ -444,6 +354,7 @@ std::pair ARMBaseRegisterInfo::getAllocationOrder(const TargetRegisterClass *RC, unsigned HintType, unsigned HintReg, const MachineFunction &MF) const { + const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); // Alternative register allocation orders when favoring even / odd registers // of register pairs. @@ -525,7 +436,7 @@ ARMBaseRegisterInfo::getAllocationOrder(const TargetRegisterClass *RC, return std::make_pair(RC->allocation_order_begin(MF), RC->allocation_order_end(MF)); - if (!hasFP(MF)) { + if (!TFI->hasFP(MF)) { if (!STI.isR9Reserved()) return std::make_pair(GPREven1, GPREven1 + (sizeof(GPREven1)/sizeof(unsigned))); @@ -554,7 +465,7 @@ ARMBaseRegisterInfo::getAllocationOrder(const TargetRegisterClass *RC, return std::make_pair(RC->allocation_order_begin(MF), RC->allocation_order_end(MF)); - if (!hasFP(MF)) { + if (!TFI->hasFP(MF)) { if (!STI.isR9Reserved()) return std::make_pair(GPROdd1, GPROdd1 + (sizeof(GPROdd1)/sizeof(unsigned))); @@ -606,7 +517,7 @@ ARMBaseRegisterInfo::UpdateRegAllocHint(unsigned Reg, unsigned NewReg, std::pair Hint = MRI->getRegAllocationHint(Reg); if ((Hint.first == (unsigned)ARMRI::RegPairOdd || Hint.first == (unsigned)ARMRI::RegPairEven) && - Hint.second && TargetRegisterInfo::isVirtualRegister(Hint.second)) { + TargetRegisterInfo::isVirtualRegister(Hint.second)) { // If 'Reg' is one of the even / odd register pair and it's now changed // (e.g. coalesced) into a different register. The other register of the // pair allocation hint must be updated to reflect the relationship @@ -619,23 +530,6 @@ ARMBaseRegisterInfo::UpdateRegAllocHint(unsigned Reg, unsigned NewReg, } } -/// hasFP - Return true if the specified function should have a dedicated frame -/// pointer register. This is true if the function has variable sized allocas -/// or if frame pointer elimination is disabled. -/// -bool ARMBaseRegisterInfo::hasFP(const MachineFunction &MF) const { - // Mac OS X requires FP not to be clobbered for backtracing purpose. - if (STI.isTargetDarwin()) - return true; - - const MachineFrameInfo *MFI = MF.getFrameInfo(); - // Always eliminate non-leaf frame pointers. - return ((DisableFramePointerElim(MF) && MFI->hasCalls()) || - needsStackRealignment(MF) || - MFI->hasVarSizedObjects() || - MFI->isFrameAddressTaken()); -} - bool ARMBaseRegisterInfo::hasBasePointer(const MachineFunction &MF) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); const ARMFunctionInfo *AFI = MF.getInfo(); @@ -681,7 +575,7 @@ bool ARMBaseRegisterInfo:: needsStackRealignment(const MachineFunction &MF) const { const MachineFrameInfo *MFI = MF.getFrameInfo(); const Function *F = MF.getFunction(); - unsigned StackAlign = MF.getTarget().getFrameInfo()->getStackAlignment(); + unsigned StackAlign = MF.getTarget().getFrameLowering()->getStackAlignment(); bool requiresRealignment = ((MFI->getLocalFrameMaxAlign() > StackAlign) || F->hasFnAttr(Attribute::StackAlignment)); @@ -697,417 +591,19 @@ cannotEliminateFrame(const MachineFunction &MF) const { || needsStackRealignment(MF); } -/// estimateStackSize - Estimate and return the size of the frame. -static unsigned estimateStackSize(MachineFunction &MF) { - const MachineFrameInfo *FFI = MF.getFrameInfo(); - int Offset = 0; - for (int i = FFI->getObjectIndexBegin(); i != 0; ++i) { - int FixedOff = -FFI->getObjectOffset(i); - if (FixedOff > Offset) Offset = FixedOff; - } - for (unsigned i = 0, e = FFI->getObjectIndexEnd(); i != e; ++i) { - if (FFI->isDeadObjectIndex(i)) - continue; - Offset += FFI->getObjectSize(i); - unsigned Align = FFI->getObjectAlignment(i); - // Adjust to alignment boundary - Offset = (Offset+Align-1)/Align*Align; - } - return (unsigned)Offset; -} - -/// estimateRSStackSizeLimit - Look at each instruction that references stack -/// frames and return the stack size limit beyond which some of these -/// instructions will require a scratch register during their expansion later. -unsigned -ARMBaseRegisterInfo::estimateRSStackSizeLimit(MachineFunction &MF) const { - const ARMFunctionInfo *AFI = MF.getInfo(); - unsigned Limit = (1 << 12) - 1; - for (MachineFunction::iterator BB = MF.begin(),E = MF.end(); BB != E; ++BB) { - for (MachineBasicBlock::iterator I = BB->begin(), E = BB->end(); - I != E; ++I) { - for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) { - if (!I->getOperand(i).isFI()) continue; - - // When using ADDri to get the address of a stack object, 255 is the - // largest offset guaranteed to fit in the immediate offset. - if (I->getOpcode() == ARM::ADDri) { - Limit = std::min(Limit, (1U << 8) - 1); - break; - } - - // Otherwise check the addressing mode. - switch (I->getDesc().TSFlags & ARMII::AddrModeMask) { - case ARMII::AddrMode3: - case ARMII::AddrModeT2_i8: - Limit = std::min(Limit, (1U << 8) - 1); - break; - case ARMII::AddrMode5: - case ARMII::AddrModeT2_i8s4: - Limit = std::min(Limit, ((1U << 8) - 1) * 4); - break; - case ARMII::AddrModeT2_i12: - // i12 supports only positive offset so these will be converted to - // i8 opcodes. See llvm::rewriteT2FrameIndex. - if (hasFP(MF) && AFI->hasStackFrame()) - Limit = std::min(Limit, (1U << 8) - 1); - break; - case ARMII::AddrMode6: - // Addressing mode 6 (load/store) instructions can't encode an - // immediate offset for stack references. - return 0; - default: - break; - } - break; // At most one FI per instruction - } - } - } - - return Limit; -} - -static unsigned GetFunctionSizeInBytes(const MachineFunction &MF, - const ARMBaseInstrInfo &TII) { - unsigned FnSize = 0; - for (MachineFunction::const_iterator MBBI = MF.begin(), E = MF.end(); - MBBI != E; ++MBBI) { - const MachineBasicBlock &MBB = *MBBI; - for (MachineBasicBlock::const_iterator I = MBB.begin(),E = MBB.end(); - I != E; ++I) - FnSize += TII.GetInstSizeInBytes(I); - } - return FnSize; -} - -void -ARMBaseRegisterInfo::processFunctionBeforeCalleeSavedScan(MachineFunction &MF, - RegScavenger *RS) const { - // This tells PEI to spill the FP as if it is any other callee-save register - // to take advantage the eliminateFrameIndex machinery. This also ensures it - // is spilled in the order specified by getCalleeSavedRegs() to make it easier - // to combine multiple loads / stores. - bool CanEliminateFrame = true; - bool CS1Spilled = false; - bool LRSpilled = false; - unsigned NumGPRSpills = 0; - SmallVector UnspilledCS1GPRs; - SmallVector UnspilledCS2GPRs; - ARMFunctionInfo *AFI = MF.getInfo(); - MachineFrameInfo *MFI = MF.getFrameInfo(); - - // Spill R4 if Thumb2 function requires stack realignment - it will be used as - // scratch register. - // FIXME: It will be better just to find spare register here. - if (needsStackRealignment(MF) && - AFI->isThumb2Function()) - MF.getRegInfo().setPhysRegUsed(ARM::R4); - - // Spill LR if Thumb1 function uses variable length argument lists. - if (AFI->isThumb1OnlyFunction() && AFI->getVarArgsRegSaveSize() > 0) - MF.getRegInfo().setPhysRegUsed(ARM::LR); - - // Spill the BasePtr if it's used. - if (hasBasePointer(MF)) - MF.getRegInfo().setPhysRegUsed(BasePtr); - - // Don't spill FP if the frame can be eliminated. This is determined - // by scanning the callee-save registers to see if any is used. - const unsigned *CSRegs = getCalleeSavedRegs(); - for (unsigned i = 0; CSRegs[i]; ++i) { - unsigned Reg = CSRegs[i]; - bool Spilled = false; - if (MF.getRegInfo().isPhysRegUsed(Reg)) { - AFI->setCSRegisterIsSpilled(Reg); - Spilled = true; - CanEliminateFrame = false; - } else { - // Check alias registers too. - for (const unsigned *Aliases = getAliasSet(Reg); *Aliases; ++Aliases) { - if (MF.getRegInfo().isPhysRegUsed(*Aliases)) { - Spilled = true; - CanEliminateFrame = false; - } - } - } - - if (!ARM::GPRRegisterClass->contains(Reg)) - continue; - - if (Spilled) { - NumGPRSpills++; - - if (!STI.isTargetDarwin()) { - if (Reg == ARM::LR) - LRSpilled = true; - CS1Spilled = true; - continue; - } - - // Keep track if LR and any of R4, R5, R6, and R7 is spilled. - switch (Reg) { - case ARM::LR: - LRSpilled = true; - // Fallthrough - case ARM::R4: - case ARM::R5: - case ARM::R6: - case ARM::R7: - CS1Spilled = true; - break; - default: - break; - } - } else { - if (!STI.isTargetDarwin()) { - UnspilledCS1GPRs.push_back(Reg); - continue; - } - - switch (Reg) { - case ARM::R4: - case ARM::R5: - case ARM::R6: - case ARM::R7: - case ARM::LR: - UnspilledCS1GPRs.push_back(Reg); - break; - default: - UnspilledCS2GPRs.push_back(Reg); - break; - } - } - } - - bool ForceLRSpill = false; - if (!LRSpilled && AFI->isThumb1OnlyFunction()) { - unsigned FnSize = GetFunctionSizeInBytes(MF, TII); - // Force LR to be spilled if the Thumb function size is > 2048. This enables - // use of BL to implement far jump. If it turns out that it's not needed - // then the branch fix up path will undo it. - if (FnSize >= (1 << 11)) { - CanEliminateFrame = false; - ForceLRSpill = true; - } - } - - // If any of the stack slot references may be out of range of an immediate - // offset, make sure a register (or a spill slot) is available for the - // register scavenger. Note that if we're indexing off the frame pointer, the - // effective stack size is 4 bytes larger since the FP points to the stack - // slot of the previous FP. Also, if we have variable sized objects in the - // function, stack slot references will often be negative, and some of - // our instructions are positive-offset only, so conservatively consider - // that case to want a spill slot (or register) as well. Similarly, if - // the function adjusts the stack pointer during execution and the - // adjustments aren't already part of our stack size estimate, our offset - // calculations may be off, so be conservative. - // FIXME: We could add logic to be more precise about negative offsets - // and which instructions will need a scratch register for them. Is it - // worth the effort and added fragility? - bool BigStack = - (RS && - (estimateStackSize(MF) + ((hasFP(MF) && AFI->hasStackFrame()) ? 4:0) >= - estimateRSStackSizeLimit(MF))) - || MFI->hasVarSizedObjects() - || (MFI->adjustsStack() && !canSimplifyCallFramePseudos(MF)); - - bool ExtraCSSpill = false; - if (BigStack || !CanEliminateFrame || cannotEliminateFrame(MF)) { - AFI->setHasStackFrame(true); - - // If LR is not spilled, but at least one of R4, R5, R6, and R7 is spilled. - // Spill LR as well so we can fold BX_RET to the registers restore (LDM). - if (!LRSpilled && CS1Spilled) { - MF.getRegInfo().setPhysRegUsed(ARM::LR); - AFI->setCSRegisterIsSpilled(ARM::LR); - NumGPRSpills++; - UnspilledCS1GPRs.erase(std::find(UnspilledCS1GPRs.begin(), - UnspilledCS1GPRs.end(), (unsigned)ARM::LR)); - ForceLRSpill = false; - ExtraCSSpill = true; - } - - if (hasFP(MF)) { - MF.getRegInfo().setPhysRegUsed(FramePtr); - NumGPRSpills++; - } - - // If stack and double are 8-byte aligned and we are spilling an odd number - // of GPRs. Spill one extra callee save GPR so we won't have to pad between - // the integer and double callee save areas. - unsigned TargetAlign = MF.getTarget().getFrameInfo()->getStackAlignment(); - if (TargetAlign == 8 && (NumGPRSpills & 1)) { - if (CS1Spilled && !UnspilledCS1GPRs.empty()) { - for (unsigned i = 0, e = UnspilledCS1GPRs.size(); i != e; ++i) { - unsigned Reg = UnspilledCS1GPRs[i]; - // Don't spill high register if the function is thumb1 - if (!AFI->isThumb1OnlyFunction() || - isARMLowRegister(Reg) || Reg == ARM::LR) { - MF.getRegInfo().setPhysRegUsed(Reg); - AFI->setCSRegisterIsSpilled(Reg); - if (!isReservedReg(MF, Reg)) - ExtraCSSpill = true; - break; - } - } - } else if (!UnspilledCS2GPRs.empty() && - !AFI->isThumb1OnlyFunction()) { - unsigned Reg = UnspilledCS2GPRs.front(); - MF.getRegInfo().setPhysRegUsed(Reg); - AFI->setCSRegisterIsSpilled(Reg); - if (!isReservedReg(MF, Reg)) - ExtraCSSpill = true; - } - } - - // Estimate if we might need to scavenge a register at some point in order - // to materialize a stack offset. If so, either spill one additional - // callee-saved register or reserve a special spill slot to facilitate - // register scavenging. Thumb1 needs a spill slot for stack pointer - // adjustments also, even when the frame itself is small. - if (BigStack && !ExtraCSSpill) { - // If any non-reserved CS register isn't spilled, just spill one or two - // extra. That should take care of it! - unsigned NumExtras = TargetAlign / 4; - SmallVector Extras; - while (NumExtras && !UnspilledCS1GPRs.empty()) { - unsigned Reg = UnspilledCS1GPRs.back(); - UnspilledCS1GPRs.pop_back(); - if (!isReservedReg(MF, Reg) && - (!AFI->isThumb1OnlyFunction() || isARMLowRegister(Reg) || - Reg == ARM::LR)) { - Extras.push_back(Reg); - NumExtras--; - } - } - // For non-Thumb1 functions, also check for hi-reg CS registers - if (!AFI->isThumb1OnlyFunction()) { - while (NumExtras && !UnspilledCS2GPRs.empty()) { - unsigned Reg = UnspilledCS2GPRs.back(); - UnspilledCS2GPRs.pop_back(); - if (!isReservedReg(MF, Reg)) { - Extras.push_back(Reg); - NumExtras--; - } - } - } - if (Extras.size() && NumExtras == 0) { - for (unsigned i = 0, e = Extras.size(); i != e; ++i) { - MF.getRegInfo().setPhysRegUsed(Extras[i]); - AFI->setCSRegisterIsSpilled(Extras[i]); - } - } else if (!AFI->isThumb1OnlyFunction()) { - // note: Thumb1 functions spill to R12, not the stack. Reserve a slot - // closest to SP or frame pointer. - const TargetRegisterClass *RC = ARM::GPRRegisterClass; - RS->setScavengingFrameIndex(MFI->CreateStackObject(RC->getSize(), - RC->getAlignment(), - false)); - } - } - } - - if (ForceLRSpill) { - MF.getRegInfo().setPhysRegUsed(ARM::LR); - AFI->setCSRegisterIsSpilled(ARM::LR); - AFI->setLRIsSpilledForFarJump(true); - } -} - unsigned ARMBaseRegisterInfo::getRARegister() const { return ARM::LR; } unsigned ARMBaseRegisterInfo::getFrameRegister(const MachineFunction &MF) const { - if (hasFP(MF)) + const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); + + if (TFI->hasFP(MF)) return FramePtr; return ARM::SP; } -// Provide a base+offset reference to an FI slot for debug info. It's the -// same as what we use for resolving the code-gen references for now. -// FIXME: This can go wrong when references are SP-relative and simple call -// frames aren't used. -int -ARMBaseRegisterInfo::getFrameIndexReference(const MachineFunction &MF, int FI, - unsigned &FrameReg) const { - return ResolveFrameIndexReference(MF, FI, FrameReg, 0); -} - -int -ARMBaseRegisterInfo::ResolveFrameIndexReference(const MachineFunction &MF, - int FI, - unsigned &FrameReg, - int SPAdj) const { - const MachineFrameInfo *MFI = MF.getFrameInfo(); - const ARMFunctionInfo *AFI = MF.getInfo(); - int Offset = MFI->getObjectOffset(FI) + MFI->getStackSize(); - int FPOffset = Offset - AFI->getFramePtrSpillOffset(); - bool isFixed = MFI->isFixedObjectIndex(FI); - - FrameReg = ARM::SP; - Offset += SPAdj; - if (AFI->isGPRCalleeSavedArea1Frame(FI)) - return Offset - AFI->getGPRCalleeSavedArea1Offset(); - else if (AFI->isGPRCalleeSavedArea2Frame(FI)) - return Offset - AFI->getGPRCalleeSavedArea2Offset(); - else if (AFI->isDPRCalleeSavedAreaFrame(FI)) - return Offset - AFI->getDPRCalleeSavedAreaOffset(); - - // When dynamically realigning the stack, use the frame pointer for - // parameters, and the stack/base pointer for locals. - if (needsStackRealignment(MF)) { - assert (hasFP(MF) && "dynamic stack realignment without a FP!"); - if (isFixed) { - FrameReg = getFrameRegister(MF); - Offset = FPOffset; - } else if (MFI->hasVarSizedObjects()) { - assert(hasBasePointer(MF) && - "VLAs and dynamic stack alignment, but missing base pointer!"); - FrameReg = BasePtr; - } - return Offset; - } - - // If there is a frame pointer, use it when we can. - if (hasFP(MF) && AFI->hasStackFrame()) { - // Use frame pointer to reference fixed objects. Use it for locals if - // there are VLAs (and thus the SP isn't reliable as a base). - if (isFixed || (MFI->hasVarSizedObjects() && !hasBasePointer(MF))) { - FrameReg = getFrameRegister(MF); - return FPOffset; - } else if (MFI->hasVarSizedObjects()) { - assert(hasBasePointer(MF) && "missing base pointer!"); - // Use the base register since we have it. - FrameReg = BasePtr; - } else if (AFI->isThumb2Function()) { - // In Thumb2 mode, the negative offset is very limited. Try to avoid - // out of range references. - if (FPOffset >= -255 && FPOffset < 0) { - FrameReg = getFrameRegister(MF); - return FPOffset; - } - } else if (Offset > (FPOffset < 0 ? -FPOffset : FPOffset)) { - // Otherwise, use SP or FP, whichever is closer to the stack slot. - FrameReg = getFrameRegister(MF); - return FPOffset; - } - } - // Use the base pointer if we have one. - if (hasBasePointer(MF)) - FrameReg = BasePtr; - return Offset; -} - -int -ARMBaseRegisterInfo::getFrameIndexOffset(const MachineFunction &MF, - int FI) const { - unsigned FrameReg; - return getFrameIndexReference(MF, FI, FrameReg); -} - unsigned ARMBaseRegisterInfo::getEHExceptionRegister() const { llvm_unreachable("What is the exception register"); return 0; @@ -1320,7 +816,7 @@ emitLoadConstPool(MachineBasicBlock &MBB, BuildMI(MBB, MBBI, dl, TII.get(ARM::LDRcp)) .addReg(DestReg, getDefRegState(true), SubIdx) .addConstantPoolIndex(Idx) - .addReg(0).addImm(0).addImm(Pred).addReg(PredReg); + .addImm(0).addImm(Pred).addReg(PredReg); } bool ARMBaseRegisterInfo:: @@ -1338,34 +834,6 @@ requiresVirtualBaseRegisters(const MachineFunction &MF) const { return EnableLocalStackAlloc; } -// hasReservedCallFrame - Under normal circumstances, when a frame pointer is -// not required, we reserve argument space for call sites in the function -// immediately on entry to the current function. This eliminates the need for -// add/sub sp brackets around call sites. Returns true if the call frame is -// included as part of the stack frame. -bool ARMBaseRegisterInfo:: -hasReservedCallFrame(const MachineFunction &MF) const { - const MachineFrameInfo *FFI = MF.getFrameInfo(); - unsigned CFSize = FFI->getMaxCallFrameSize(); - // It's not always a good idea to include the call frame as part of the - // stack frame. ARM (especially Thumb) has small immediate offset to - // address the stack frame. So a large call frame can cause poor codegen - // and may even makes it impossible to scavenge a register. - if (CFSize >= ((1 << 12) - 1) / 2) // Half of imm12 - return false; - - return !MF.getFrameInfo()->hasVarSizedObjects(); -} - -// canSimplifyCallFramePseudos - If there is a reserved call frame, the -// call frame pseudos can be simplified. Unlike most targets, having a FP -// is not sufficient here since we still may reference some objects via SP -// even when FP is available in Thumb2 mode. -bool ARMBaseRegisterInfo:: -canSimplifyCallFramePseudos(const MachineFunction &MF) const { - return hasReservedCallFrame(MF) || MF.getFrameInfo()->hasVarSizedObjects(); -} - static void emitSPUpdate(bool isARM, MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, @@ -1384,7 +852,8 @@ emitSPUpdate(bool isARM, void ARMBaseRegisterInfo:: eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const { - if (!hasReservedCallFrame(MF)) { + const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); + if (!TFI->hasReservedCallFrame(MF)) { // If we have alloca, convert as follows: // ADJCALLSTACKDOWN -> sub, sp, sp, amount // ADJCALLSTACKUP -> add, sp, sp, amount @@ -1395,7 +864,7 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, // We need to keep the stack aligned properly. To do this, we round the // amount of space needed for the outgoing arguments up to the next // alignment boundary. - unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment(); + unsigned Align = TFI->getStackAlignment(); Amount = (Amount+Align-1)/Align*Align; ARMFunctionInfo *AFI = MF.getInfo(); @@ -1433,8 +902,7 @@ getFrameIndexInstrOffset(const MachineInstr *MI, int Idx) const { switch (AddrMode) { case ARMII::AddrModeT2_i8: case ARMII::AddrModeT2_i12: - // i8 supports only negative, and i12 supports only positive, so - // based on Offset sign, consider the appropriate instruction + case ARMII::AddrMode_i12: InstrOffs = MI->getOperand(Idx+1).getImm(); Scale = 1; break; @@ -1496,8 +964,8 @@ needsFrameBaseReg(MachineInstr *MI, int64_t Offset) const { // return false for everything else. unsigned Opc = MI->getOpcode(); switch (Opc) { - case ARM::LDR: case ARM::LDRH: case ARM::LDRB: - case ARM::STR: case ARM::STRH: case ARM::STRB: + case ARM::LDRi12: case ARM::LDRH: case ARM::LDRBi12: + case ARM::STRi12: case ARM::STRH: case ARM::STRBi12: case ARM::t2LDRi12: case ARM::t2LDRi8: case ARM::t2STRi12: case ARM::t2STRi8: case ARM::VLDRS: case ARM::VLDRD: @@ -1516,6 +984,7 @@ needsFrameBaseReg(MachineInstr *MI, int64_t Offset) const { // Note that the incoming offset is based on the SP value at function entry, // so it'll be negative. MachineFunction &MF = *MI->getParent()->getParent(); + const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); MachineFrameInfo *MFI = MF.getFrameInfo(); ARMFunctionInfo *AFI = MF.getInfo(); @@ -1542,8 +1011,8 @@ needsFrameBaseReg(MachineInstr *MI, int64_t Offset) const { // The FP is only available if there is no dynamic realignment. We // don't know for sure yet whether we'll need that, so we guess based // on whether there are any local variables that would trigger it. - unsigned StackAlign = MF.getTarget().getFrameInfo()->getStackAlignment(); - if (hasFP(MF) && + unsigned StackAlign = TFI->getStackAlignment(); + if (TFI->hasFP(MF) && !((MFI->getLocalFrameMaxAlign() > StackAlign) && canRealignStack(MF))) { if (isFrameOffsetLegal(MI, FPOffset)) return false; @@ -1560,19 +1029,25 @@ needsFrameBaseReg(MachineInstr *MI, int64_t Offset) const { return true; } -/// materializeFrameBaseRegister - Insert defining instruction(s) for -/// BaseReg to be a pointer to FrameIdx before insertion point I. +/// materializeFrameBaseRegister - Insert defining instruction(s) for BaseReg to +/// be a pointer to FrameIdx at the beginning of the basic block. void ARMBaseRegisterInfo:: -materializeFrameBaseRegister(MachineBasicBlock::iterator I, unsigned BaseReg, - int FrameIdx, int64_t Offset) const { - ARMFunctionInfo *AFI = - I->getParent()->getParent()->getInfo(); +materializeFrameBaseRegister(MachineBasicBlock *MBB, + unsigned BaseReg, int FrameIdx, + int64_t Offset) const { + ARMFunctionInfo *AFI = MBB->getParent()->getInfo(); unsigned ADDriOpc = !AFI->isThumbFunction() ? ARM::ADDri : (AFI->isThumb1OnlyFunction() ? ARM::tADDrSPi : ARM::t2ADDri); + MachineBasicBlock::iterator Ins = MBB->begin(); + DebugLoc DL; // Defaults to "unknown" + if (Ins != MBB->end()) + DL = Ins->getDebugLoc(); + MachineInstrBuilder MIB = - BuildMI(*I->getParent(), I, I->getDebugLoc(), TII.get(ADDriOpc), BaseReg) + BuildMI(*MBB, Ins, DL, TII.get(ADDriOpc), BaseReg) .addFrameIndex(FrameIdx).addImm(Offset); + if (!AFI->isThumb1OnlyFunction()) AddDefaultCC(AddDefaultPred(MIB)); } @@ -1640,6 +1115,7 @@ bool ARMBaseRegisterInfo::isFrameOffsetLegal(const MachineInstr *MI, NumBits = 8; Scale = 4; break; + case ARMII::AddrMode_i12: case ARMII::AddrMode2: NumBits = 12; break; @@ -1679,6 +1155,8 @@ ARMBaseRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, MachineInstr &MI = *II; MachineBasicBlock &MBB = *MI.getParent(); MachineFunction &MF = *MBB.getParent(); + const ARMFrameLowering *TFI = + static_cast(MF.getTarget().getFrameLowering()); ARMFunctionInfo *AFI = MF.getInfo(); assert(!AFI->isThumb1OnlyFunction() && "This eliminateFrameIndex does not support Thumb1!"); @@ -1691,7 +1169,7 @@ ARMBaseRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, int FrameIndex = MI.getOperand(i).getIndex(); unsigned FrameReg; - int Offset = ResolveFrameIndexReference(MF, FrameIndex, FrameReg, SPAdj); + int Offset = TFI->ResolveFrameIndexReference(MF, FrameIndex, FrameReg, SPAdj); // Special handling of dbg_value instructions. if (MI.isDebugValue()) { @@ -1737,339 +1215,13 @@ ARMBaseRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, emitT2RegPlusImmediate(MBB, II, MI.getDebugLoc(), ScratchReg, FrameReg, Offset, Pred, PredReg, TII); } + // Update the original instruction to use the scratch register. MI.getOperand(i).ChangeToRegister(ScratchReg, false, false, true); + if (MI.getOpcode() == ARM::t2ADDrSPi) + MI.setDesc(TII.get(ARM::t2ADDri)); + else if (MI.getOpcode() == ARM::t2SUBrSPi) + MI.setDesc(TII.get(ARM::t2SUBri)); } } -/// Move iterator past the next bunch of callee save load / store ops for -/// the particular spill area (1: integer area 1, 2: integer area 2, -/// 3: fp area, 0: don't care). -static void movePastCSLoadStoreOps(MachineBasicBlock &MBB, - MachineBasicBlock::iterator &MBBI, - int Opc1, int Opc2, unsigned Area, - const ARMSubtarget &STI) { - while (MBBI != MBB.end() && - ((MBBI->getOpcode() == Opc1) || (MBBI->getOpcode() == Opc2)) && - MBBI->getOperand(1).isFI()) { - if (Area != 0) { - bool Done = false; - unsigned Category = 0; - switch (MBBI->getOperand(0).getReg()) { - case ARM::R4: case ARM::R5: case ARM::R6: case ARM::R7: - case ARM::LR: - Category = 1; - break; - case ARM::R8: case ARM::R9: case ARM::R10: case ARM::R11: - Category = STI.isTargetDarwin() ? 2 : 1; - break; - case ARM::D8: case ARM::D9: case ARM::D10: case ARM::D11: - case ARM::D12: case ARM::D13: case ARM::D14: case ARM::D15: - Category = 3; - break; - default: - Done = true; - break; - } - if (Done || Category != Area) - break; - } - - ++MBBI; - } -} - -void ARMBaseRegisterInfo:: -emitPrologue(MachineFunction &MF) const { - MachineBasicBlock &MBB = MF.front(); - MachineBasicBlock::iterator MBBI = MBB.begin(); - MachineFrameInfo *MFI = MF.getFrameInfo(); - ARMFunctionInfo *AFI = MF.getInfo(); - assert(!AFI->isThumb1OnlyFunction() && - "This emitPrologue does not support Thumb1!"); - bool isARM = !AFI->isThumbFunction(); - unsigned VARegSaveSize = AFI->getVarArgsRegSaveSize(); - unsigned NumBytes = MFI->getStackSize(); - const std::vector &CSI = MFI->getCalleeSavedInfo(); - DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); - - // Determine the sizes of each callee-save spill areas and record which frame - // belongs to which callee-save spill areas. - unsigned GPRCS1Size = 0, GPRCS2Size = 0, DPRCSSize = 0; - int FramePtrSpillFI = 0; - - // Allocate the vararg register save area. This is not counted in NumBytes. - if (VARegSaveSize) - emitSPUpdate(isARM, MBB, MBBI, dl, TII, -VARegSaveSize); - - if (!AFI->hasStackFrame()) { - if (NumBytes != 0) - emitSPUpdate(isARM, MBB, MBBI, dl, TII, -NumBytes); - return; - } - - for (unsigned i = 0, e = CSI.size(); i != e; ++i) { - unsigned Reg = CSI[i].getReg(); - int FI = CSI[i].getFrameIdx(); - switch (Reg) { - case ARM::R4: - case ARM::R5: - case ARM::R6: - case ARM::R7: - case ARM::LR: - if (Reg == FramePtr) - FramePtrSpillFI = FI; - AFI->addGPRCalleeSavedArea1Frame(FI); - GPRCS1Size += 4; - break; - case ARM::R8: - case ARM::R9: - case ARM::R10: - case ARM::R11: - if (Reg == FramePtr) - FramePtrSpillFI = FI; - if (STI.isTargetDarwin()) { - AFI->addGPRCalleeSavedArea2Frame(FI); - GPRCS2Size += 4; - } else { - AFI->addGPRCalleeSavedArea1Frame(FI); - GPRCS1Size += 4; - } - break; - default: - AFI->addDPRCalleeSavedAreaFrame(FI); - DPRCSSize += 8; - } - } - - // Build the new SUBri to adjust SP for integer callee-save spill area 1. - emitSPUpdate(isARM, MBB, MBBI, dl, TII, -GPRCS1Size); - movePastCSLoadStoreOps(MBB, MBBI, ARM::STR, ARM::t2STRi12, 1, STI); - - // Set FP to point to the stack slot that contains the previous FP. - // For Darwin, FP is R7, which has now been stored in spill area 1. - // Otherwise, if this is not Darwin, all the callee-saved registers go - // into spill area 1, including the FP in R11. In either case, it is - // now safe to emit this assignment. - bool HasFP = hasFP(MF); - if (HasFP) { - unsigned ADDriOpc = !AFI->isThumbFunction() ? ARM::ADDri : ARM::t2ADDri; - MachineInstrBuilder MIB = - BuildMI(MBB, MBBI, dl, TII.get(ADDriOpc), FramePtr) - .addFrameIndex(FramePtrSpillFI).addImm(0); - AddDefaultCC(AddDefaultPred(MIB)); - } - - // Build the new SUBri to adjust SP for integer callee-save spill area 2. - emitSPUpdate(isARM, MBB, MBBI, dl, TII, -GPRCS2Size); - - // Build the new SUBri to adjust SP for FP callee-save spill area. - movePastCSLoadStoreOps(MBB, MBBI, ARM::STR, ARM::t2STRi12, 2, STI); - emitSPUpdate(isARM, MBB, MBBI, dl, TII, -DPRCSSize); - - // Determine starting offsets of spill areas. - unsigned DPRCSOffset = NumBytes - (GPRCS1Size + GPRCS2Size + DPRCSSize); - unsigned GPRCS2Offset = DPRCSOffset + DPRCSSize; - unsigned GPRCS1Offset = GPRCS2Offset + GPRCS2Size; - if (HasFP) - AFI->setFramePtrSpillOffset(MFI->getObjectOffset(FramePtrSpillFI) + - NumBytes); - AFI->setGPRCalleeSavedArea1Offset(GPRCS1Offset); - AFI->setGPRCalleeSavedArea2Offset(GPRCS2Offset); - AFI->setDPRCalleeSavedAreaOffset(DPRCSOffset); - - movePastCSLoadStoreOps(MBB, MBBI, ARM::VSTRD, 0, 3, STI); - NumBytes = DPRCSOffset; - if (NumBytes) { - // Adjust SP after all the callee-save spills. - emitSPUpdate(isARM, MBB, MBBI, dl, TII, -NumBytes); - if (HasFP) - AFI->setShouldRestoreSPFromFP(true); - } - - if (STI.isTargetELF() && hasFP(MF)) { - MFI->setOffsetAdjustment(MFI->getOffsetAdjustment() - - AFI->getFramePtrSpillOffset()); - AFI->setShouldRestoreSPFromFP(true); - } - - AFI->setGPRCalleeSavedArea1Size(GPRCS1Size); - AFI->setGPRCalleeSavedArea2Size(GPRCS2Size); - AFI->setDPRCalleeSavedAreaSize(DPRCSSize); - - // If we need dynamic stack realignment, do it here. Be paranoid and make - // sure if we also have VLAs, we have a base pointer for frame access. - if (needsStackRealignment(MF)) { - unsigned MaxAlign = MFI->getMaxAlignment(); - assert (!AFI->isThumb1OnlyFunction()); - if (!AFI->isThumbFunction()) { - // Emit bic sp, sp, MaxAlign - AddDefaultCC(AddDefaultPred(BuildMI(MBB, MBBI, dl, - TII.get(ARM::BICri), ARM::SP) - .addReg(ARM::SP, RegState::Kill) - .addImm(MaxAlign-1))); - } else { - // We cannot use sp as source/dest register here, thus we're emitting the - // following sequence: - // mov r4, sp - // bic r4, r4, MaxAlign - // mov sp, r4 - // FIXME: It will be better just to find spare register here. - BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2tgpr), ARM::R4) - .addReg(ARM::SP, RegState::Kill); - AddDefaultCC(AddDefaultPred(BuildMI(MBB, MBBI, dl, - TII.get(ARM::t2BICri), ARM::R4) - .addReg(ARM::R4, RegState::Kill) - .addImm(MaxAlign-1))); - BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVtgpr2gpr), ARM::SP) - .addReg(ARM::R4, RegState::Kill); - } - - AFI->setShouldRestoreSPFromFP(true); - } - - // If we need a base pointer, set it up here. It's whatever the value - // of the stack pointer is at this point. Any variable size objects - // will be allocated after this, so we can still use the base pointer - // to reference locals. - if (hasBasePointer(MF)) { - if (isARM) - BuildMI(MBB, MBBI, dl, TII.get(ARM::MOVr), BasePtr) - .addReg(ARM::SP) - .addImm((unsigned)ARMCC::AL).addReg(0).addReg(0); - else - BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2gpr), BasePtr) - .addReg(ARM::SP); - } - - // If the frame has variable sized objects then the epilogue must restore - // the sp from fp. - if (!AFI->shouldRestoreSPFromFP() && MFI->hasVarSizedObjects()) - AFI->setShouldRestoreSPFromFP(true); -} - -static bool isCalleeSavedRegister(unsigned Reg, const unsigned *CSRegs) { - for (unsigned i = 0; CSRegs[i]; ++i) - if (Reg == CSRegs[i]) - return true; - return false; -} - -static bool isCSRestore(MachineInstr *MI, - const ARMBaseInstrInfo &TII, - const unsigned *CSRegs) { - return ((MI->getOpcode() == (int)ARM::VLDRD || - MI->getOpcode() == (int)ARM::LDR || - MI->getOpcode() == (int)ARM::t2LDRi12) && - MI->getOperand(1).isFI() && - isCalleeSavedRegister(MI->getOperand(0).getReg(), CSRegs)); -} - -void ARMBaseRegisterInfo:: -emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { - MachineBasicBlock::iterator MBBI = prior(MBB.end()); - assert(MBBI->getDesc().isReturn() && - "Can only insert epilog into returning blocks"); - unsigned RetOpcode = MBBI->getOpcode(); - DebugLoc dl = MBBI->getDebugLoc(); - MachineFrameInfo *MFI = MF.getFrameInfo(); - ARMFunctionInfo *AFI = MF.getInfo(); - assert(!AFI->isThumb1OnlyFunction() && - "This emitEpilogue does not support Thumb1!"); - bool isARM = !AFI->isThumbFunction(); - - unsigned VARegSaveSize = AFI->getVarArgsRegSaveSize(); - int NumBytes = (int)MFI->getStackSize(); - - if (!AFI->hasStackFrame()) { - if (NumBytes != 0) - emitSPUpdate(isARM, MBB, MBBI, dl, TII, NumBytes); - } else { - // Unwind MBBI to point to first LDR / VLDRD. - const unsigned *CSRegs = getCalleeSavedRegs(); - if (MBBI != MBB.begin()) { - do - --MBBI; - while (MBBI != MBB.begin() && isCSRestore(MBBI, TII, CSRegs)); - if (!isCSRestore(MBBI, TII, CSRegs)) - ++MBBI; - } - - // Move SP to start of FP callee save spill area. - NumBytes -= (AFI->getGPRCalleeSavedArea1Size() + - AFI->getGPRCalleeSavedArea2Size() + - AFI->getDPRCalleeSavedAreaSize()); - - // Reset SP based on frame pointer only if the stack frame extends beyond - // frame pointer stack slot or target is ELF and the function has FP. - if (AFI->shouldRestoreSPFromFP()) { - NumBytes = AFI->getFramePtrSpillOffset() - NumBytes; - if (NumBytes) { - if (isARM) - emitARMRegPlusImmediate(MBB, MBBI, dl, ARM::SP, FramePtr, -NumBytes, - ARMCC::AL, 0, TII); - else - emitT2RegPlusImmediate(MBB, MBBI, dl, ARM::SP, FramePtr, -NumBytes, - ARMCC::AL, 0, TII); - } else { - // Thumb2 or ARM. - if (isARM) - BuildMI(MBB, MBBI, dl, TII.get(ARM::MOVr), ARM::SP) - .addReg(FramePtr).addImm((unsigned)ARMCC::AL).addReg(0).addReg(0); - else - BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2gpr), ARM::SP) - .addReg(FramePtr); - } - } else if (NumBytes) - emitSPUpdate(isARM, MBB, MBBI, dl, TII, NumBytes); - - // Move SP to start of integer callee save spill area 2. - movePastCSLoadStoreOps(MBB, MBBI, ARM::VLDRD, 0, 3, STI); - emitSPUpdate(isARM, MBB, MBBI, dl, TII, AFI->getDPRCalleeSavedAreaSize()); - - // Move SP to start of integer callee save spill area 1. - movePastCSLoadStoreOps(MBB, MBBI, ARM::LDR, ARM::t2LDRi12, 2, STI); - emitSPUpdate(isARM, MBB, MBBI, dl, TII, AFI->getGPRCalleeSavedArea2Size()); - - // Move SP to SP upon entry to the function. - movePastCSLoadStoreOps(MBB, MBBI, ARM::LDR, ARM::t2LDRi12, 1, STI); - emitSPUpdate(isARM, MBB, MBBI, dl, TII, AFI->getGPRCalleeSavedArea1Size()); - } - - if (RetOpcode == ARM::TCRETURNdi || RetOpcode == ARM::TCRETURNdiND || - RetOpcode == ARM::TCRETURNri || RetOpcode == ARM::TCRETURNriND) { - // Tail call return: adjust the stack pointer and jump to callee. - MBBI = prior(MBB.end()); - MachineOperand &JumpTarget = MBBI->getOperand(0); - - // Jump to label or value in register. - if (RetOpcode == ARM::TCRETURNdi) { - BuildMI(MBB, MBBI, dl, - TII.get(STI.isThumb() ? ARM::TAILJMPdt : ARM::TAILJMPd)). - addGlobalAddress(JumpTarget.getGlobal(), JumpTarget.getOffset(), - JumpTarget.getTargetFlags()); - } else if (RetOpcode == ARM::TCRETURNdiND) { - BuildMI(MBB, MBBI, dl, - TII.get(STI.isThumb() ? ARM::TAILJMPdNDt : ARM::TAILJMPdND)). - addGlobalAddress(JumpTarget.getGlobal(), JumpTarget.getOffset(), - JumpTarget.getTargetFlags()); - } else if (RetOpcode == ARM::TCRETURNri) { - BuildMI(MBB, MBBI, dl, TII.get(ARM::TAILJMPr)). - addReg(JumpTarget.getReg(), RegState::Kill); - } else if (RetOpcode == ARM::TCRETURNriND) { - BuildMI(MBB, MBBI, dl, TII.get(ARM::TAILJMPrND)). - addReg(JumpTarget.getReg(), RegState::Kill); - } - - MachineInstr *NewMI = prior(MBBI); - for (unsigned i = 1, e = MBBI->getNumOperands(); i != e; ++i) - NewMI->addOperand(MBBI->getOperand(i)); - - // Delete the pseudo instruction TCRETURN. - MBB.erase(MBBI); - } - - if (VARegSaveSize) - emitSPUpdate(isARM, MBB, MBBI, dl, TII, VARegSaveSize); -} - #include "ARMGenRegisterInfo.inc" diff --git a/lib/Target/ARM/ARMBaseRegisterInfo.h b/lib/Target/ARM/ARMBaseRegisterInfo.h index fa2eb6c10498..ba6bd2b32082 100644 --- a/lib/Target/ARM/ARMBaseRegisterInfo.h +++ b/lib/Target/ARM/ARMBaseRegisterInfo.h @@ -44,6 +44,45 @@ static inline bool isARMLowRegister(unsigned Reg) { } } +/// isARMArea1Register - Returns true if the register is a low register (r0-r7) +/// or a stack/pc register that we should push/pop. +static inline bool isARMArea1Register(unsigned Reg, bool isDarwin) { + using namespace ARM; + switch (Reg) { + case R0: case R1: case R2: case R3: + case R4: case R5: case R6: case R7: + case LR: case SP: case PC: + return true; + case R8: case R9: case R10: case R11: + // For darwin we want r7 and lr to be next to each other. + return !isDarwin; + default: + return false; + } +} + +static inline bool isARMArea2Register(unsigned Reg, bool isDarwin) { + using namespace ARM; + switch (Reg) { + case R8: case R9: case R10: case R11: + // Darwin has this second area. + return isDarwin; + default: + return false; + } +} + +static inline bool isARMArea3Register(unsigned Reg, bool isDarwin) { + using namespace ARM; + switch (Reg) { + case D15: case D14: case D13: case D12: + case D11: case D10: case D9: case D8: + return true; + default: + return false; + } +} + class ARMBaseRegisterInfo : public ARMGenRegisterInfo { protected: const ARMBaseInstrInfo &TII; @@ -65,12 +104,6 @@ protected: unsigned getOpcode(int Op) const; public: - /// getRegisterNumbering - Given the enum value for some register, e.g. - /// ARM::LR, return the number that it corresponds to (e.g. 14). It - /// also returns true in isSPVFP if the register is a single precision - /// VFP register. - static unsigned getRegisterNumbering(unsigned RegEnum, bool *isSPVFP = 0); - /// Code Generation virtual methods... const unsigned *getCalleeSavedRegs(const MachineFunction *MF = 0) const; @@ -106,14 +139,13 @@ public: void UpdateRegAllocHint(unsigned Reg, unsigned NewReg, MachineFunction &MF) const; - bool hasFP(const MachineFunction &MF) const; bool hasBasePointer(const MachineFunction &MF) const; bool canRealignStack(const MachineFunction &MF) const; bool needsStackRealignment(const MachineFunction &MF) const; int64_t getFrameIndexInstrOffset(const MachineInstr *MI, int Idx) const; bool needsFrameBaseReg(MachineInstr *MI, int64_t Offset) const; - void materializeFrameBaseRegister(MachineBasicBlock::iterator I, + void materializeFrameBaseRegister(MachineBasicBlock *MBB, unsigned BaseReg, int FrameIdx, int64_t Offset) const; void resolveFrameIndex(MachineBasicBlock::iterator I, @@ -122,17 +154,10 @@ public: bool cannotEliminateFrame(const MachineFunction &MF) const; - void processFunctionBeforeCalleeSavedScan(MachineFunction &MF, - RegScavenger *RS = NULL) const; - // Debug information queries. unsigned getRARegister() const; unsigned getFrameRegister(const MachineFunction &MF) const; - int getFrameIndexReference(const MachineFunction &MF, int FI, - unsigned &FrameReg) const; - int ResolveFrameIndexReference(const MachineFunction &MF, int FI, - unsigned &FrameReg, int SPAdj) const; - int getFrameIndexOffset(const MachineFunction &MF, int FI) const; + unsigned getBaseRegister() const { return BasePtr; } // Exception handling queries. unsigned getEHExceptionRegister() const; @@ -162,9 +187,6 @@ public: virtual bool requiresVirtualBaseRegisters(const MachineFunction &MF) const; - virtual bool hasReservedCallFrame(const MachineFunction &MF) const; - virtual bool canSimplifyCallFramePseudos(const MachineFunction &MF) const; - virtual void eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const; @@ -172,12 +194,7 @@ public: virtual void eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, RegScavenger *RS = NULL) const; - virtual void emitPrologue(MachineFunction &MF) const; - virtual void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; - private: - unsigned estimateRSStackSizeLimit(MachineFunction &MF) const; - unsigned getRegisterPairEven(unsigned Reg, const MachineFunction &MF) const; unsigned getRegisterPairOdd(unsigned Reg, const MachineFunction &MF) const; diff --git a/lib/Target/ARM/ARMBuildAttrs.h b/lib/Target/ARM/ARMBuildAttrs.h index 3b38375fbc71..69eddf03ec94 100644 --- a/lib/Target/ARM/ARMBuildAttrs.h +++ b/lib/Target/ARM/ARMBuildAttrs.h @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // // This file contains enumerations and support routines for ARM build attributes -// as defined in ARM ABI addenda document (ABI release 2.07). +// as defined in ARM ABI addenda document (ABI release 2.08). // //===----------------------------------------------------------------------===// @@ -16,7 +16,14 @@ #define __TARGET_ARMBUILDATTRS_H__ namespace ARMBuildAttrs { - enum { + enum SpecialAttr { + // This is for the .cpu asm attr. It translates into one or more + // AttrType (below) entries in the .ARM.attributes section in the ELF. + SEL_CPU + }; + + enum AttrType { + // Rest correspond to ELF/.ARM.attributes File = 1, Section = 2, Symbol = 3, @@ -52,12 +59,72 @@ namespace ARMBuildAttrs { CPU_unaligned_access = 34, VFP_HP_extension = 36, ABI_FP_16bit_format = 38, + MPextension_use = 42, // was 70, 2.08 ABI + DIV_use = 44, nodefaults = 64, also_compatible_with = 65, T2EE_use = 66, conformance = 67, Virtualization_use = 68, - MPextension_use = 70 + MPextension_use_old = 70 + }; + + // Magic numbers for .ARM.attributes + enum AttrMagic { + Format_Version = 0x41 + }; + + // Legal Values for CPU_arch, (=6), uleb128 + enum CPUArch { + Pre_v4 = 0, + v4 = 1, // e.g. SA110 + v4T = 2, // e.g. ARM7TDMI + v5T = 3, // e.g. ARM9TDMI + v5TE = 4, // e.g. ARM946E_S + v5TEJ = 5, // e.g. ARM926EJ_S + v6 = 6, // e.g. ARM1136J_S + v6KZ = 7, // e.g. ARM1176JZ_S + v6T2 = 8, // e.g. ARM1156T2F_S + v6K = 9, // e.g. ARM1136J_S + v7 = 10, // e.g. Cortex A8, Cortex M3 + v6_M = 11, // e.g. Cortex M1 + v6S_M = 12, // v6_M with the System extensions + v7E_M = 13 // v7_M with DSP extensions + }; + + enum CPUArchProfile { // (=7), uleb128 + Not_Applicable = 0, // pre v7, or cross-profile code + ApplicationProfile = (0x41), // 'A' (e.g. for Cortex A8) + RealTimeProfile = (0x52), // 'R' (e.g. for Cortex R4) + MicroControllerProfile = (0x4D), // 'M' (e.g. for Cortex M3) + SystemProfile = (0x53) // 'S' Application or real-time profile + }; + + // The following have a lot of common use cases + enum { + //ARMISAUse (=8), uleb128 and THUMBISAUse (=9), uleb128 + Not_Allowed = 0, + Allowed = 1, + + // FP_arch (=10), uleb128 (formerly Tag_VFP_arch = 10) + AllowFPv2 = 2, // v2 FP ISA permitted (implies use of the v1 FP ISA) + AllowFPv3A = 3, // v3 FP ISA permitted (implies use of the v2 FP ISA) + AllowFPv3B = 4, // v3 FP ISA permitted, but only D0-D15, S0-S31 + AllowFPv4A = 5, // v4 FP ISA permitted (implies use of v3 FP ISA) + AllowFPv4B = 6, // v4 FP ISA was permitted, but only D0-D15, S0-S31 + + // Tag_WMMX_arch, (=11), uleb128 + AllowThumb32 = 2, // 32-bit Thumb (implies 16-bit instructions) + + // Tag_WMMX_arch, (=11), uleb128 + AllowWMMXv1 = 2, // The user permitted this entity to use WMMX v2 + + // Tag_ABI_FP_denormal, (=20), uleb128 + PreserveFPSign = 2, // sign when flushed-to-zero is preserved + + // Tag_ABI_FP_number_model, (=23), uleb128 + AllowRTABI = 2, // numbers, infinities, and one quiet NaN (see [RTABI]) + AllowIEE754 = 3 // this code to use all the IEEE 754-defined FP encodings }; } diff --git a/lib/Target/ARM/ARMCallingConv.h b/lib/Target/ARM/ARMCallingConv.h new file mode 100644 index 000000000000..ff7db1ff62ed --- /dev/null +++ b/lib/Target/ARM/ARMCallingConv.h @@ -0,0 +1,160 @@ +//===-- ARMCallingConv.h - ARM Custom Calling Convention Routines ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the custom routines for the ARM Calling Convention that +// aren't done by tablegen. +// +//===----------------------------------------------------------------------===// + +#ifndef ARMCALLINGCONV_H +#define ARMCALLINGCONV_H + +#include "llvm/CallingConv.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/Target/TargetInstrInfo.h" +#include "ARMBaseInstrInfo.h" +#include "ARMRegisterInfo.h" +#include "ARMSubtarget.h" +#include "ARM.h" + +namespace llvm { + +// APCS f64 is in register pairs, possibly split to stack +static bool f64AssignAPCS(unsigned &ValNo, MVT &ValVT, MVT &LocVT, + CCValAssign::LocInfo &LocInfo, + CCState &State, bool CanFail) { + static const unsigned RegList[] = { ARM::R0, ARM::R1, ARM::R2, ARM::R3 }; + + // Try to get the first register. + if (unsigned Reg = State.AllocateReg(RegList, 4)) + State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); + else { + // For the 2nd half of a v2f64, do not fail. + if (CanFail) + return false; + + // Put the whole thing on the stack. + State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT, + State.AllocateStack(8, 4), + LocVT, LocInfo)); + return true; + } + + // Try to get the second register. + if (unsigned Reg = State.AllocateReg(RegList, 4)) + State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); + else + State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT, + State.AllocateStack(4, 4), + LocVT, LocInfo)); + return true; +} + +static bool CC_ARM_APCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT, + CCValAssign::LocInfo &LocInfo, + ISD::ArgFlagsTy &ArgFlags, + CCState &State) { + if (!f64AssignAPCS(ValNo, ValVT, LocVT, LocInfo, State, true)) + return false; + if (LocVT == MVT::v2f64 && + !f64AssignAPCS(ValNo, ValVT, LocVT, LocInfo, State, false)) + return false; + return true; // we handled it +} + +// AAPCS f64 is in aligned register pairs +static bool f64AssignAAPCS(unsigned &ValNo, MVT &ValVT, MVT &LocVT, + CCValAssign::LocInfo &LocInfo, + CCState &State, bool CanFail) { + static const unsigned HiRegList[] = { ARM::R0, ARM::R2 }; + static const unsigned LoRegList[] = { ARM::R1, ARM::R3 }; + static const unsigned ShadowRegList[] = { ARM::R0, ARM::R1 }; + + unsigned Reg = State.AllocateReg(HiRegList, ShadowRegList, 2); + if (Reg == 0) { + // For the 2nd half of a v2f64, do not just fail. + if (CanFail) + return false; + + // Put the whole thing on the stack. + State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT, + State.AllocateStack(8, 8), + LocVT, LocInfo)); + return true; + } + + unsigned i; + for (i = 0; i < 2; ++i) + if (HiRegList[i] == Reg) + break; + + unsigned T = State.AllocateReg(LoRegList[i]); + (void)T; + assert(T == LoRegList[i] && "Could not allocate register"); + + State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); + State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, LoRegList[i], + LocVT, LocInfo)); + return true; +} + +static bool CC_ARM_AAPCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT, + CCValAssign::LocInfo &LocInfo, + ISD::ArgFlagsTy &ArgFlags, + CCState &State) { + if (!f64AssignAAPCS(ValNo, ValVT, LocVT, LocInfo, State, true)) + return false; + if (LocVT == MVT::v2f64 && + !f64AssignAAPCS(ValNo, ValVT, LocVT, LocInfo, State, false)) + return false; + return true; // we handled it +} + +static bool f64RetAssign(unsigned &ValNo, MVT &ValVT, MVT &LocVT, + CCValAssign::LocInfo &LocInfo, CCState &State) { + static const unsigned HiRegList[] = { ARM::R0, ARM::R2 }; + static const unsigned LoRegList[] = { ARM::R1, ARM::R3 }; + + unsigned Reg = State.AllocateReg(HiRegList, LoRegList, 2); + if (Reg == 0) + return false; // we didn't handle it + + unsigned i; + for (i = 0; i < 2; ++i) + if (HiRegList[i] == Reg) + break; + + State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); + State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, LoRegList[i], + LocVT, LocInfo)); + return true; +} + +static bool RetCC_ARM_APCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT, + CCValAssign::LocInfo &LocInfo, + ISD::ArgFlagsTy &ArgFlags, + CCState &State) { + if (!f64RetAssign(ValNo, ValVT, LocVT, LocInfo, State)) + return false; + if (LocVT == MVT::v2f64 && !f64RetAssign(ValNo, ValVT, LocVT, LocInfo, State)) + return false; + return true; // we handled it +} + +static bool RetCC_ARM_AAPCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT, + CCValAssign::LocInfo &LocInfo, + ISD::ArgFlagsTy &ArgFlags, + CCState &State) { + return RetCC_ARM_APCS_Custom_f64(ValNo, ValVT, LocVT, LocInfo, ArgFlags, + State); +} + +} // End llvm namespace + +#endif diff --git a/lib/Target/ARM/ARMCallingConv.td b/lib/Target/ARM/ARMCallingConv.td index 293e32aa5376..426ba13a8e11 100644 --- a/lib/Target/ARM/ARMCallingConv.td +++ b/lib/Target/ARM/ARMCallingConv.td @@ -52,6 +52,34 @@ def RetCC_ARM_APCS : CallingConv<[ CCIfType<[i64], CCAssignToRegWithShadow<[R0, R2], [R1, R3]>> ]>; +//===----------------------------------------------------------------------===// +// ARM APCS Calling Convention for FastCC (when VFP2 or later is available) +//===----------------------------------------------------------------------===// +def FastCC_ARM_APCS : CallingConv<[ + // Handle all vector types as either f64 or v2f64. + CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType>, + CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType>, + + CCIfType<[v2f64], CCAssignToReg<[Q0, Q1, Q2, Q3]>>, + CCIfType<[f64], CCAssignToReg<[D0, D1, D2, D3, D4, D5, D6, D7]>>, + CCIfType<[f32], CCAssignToReg<[S0, S1, S2, S3, S4, S5, S6, S7, S8, + S9, S10, S11, S12, S13, S14, S15]>>, + CCDelegateTo +]>; + +def RetFastCC_ARM_APCS : CallingConv<[ + // Handle all vector types as either f64 or v2f64. + CCIfType<[v1i64, v2i32, v4i16, v8i8, v2f32], CCBitConvertToType>, + CCIfType<[v2i64, v4i32, v8i16, v16i8, v4f32], CCBitConvertToType>, + + CCIfType<[v2f64], CCAssignToReg<[Q0, Q1, Q2, Q3]>>, + CCIfType<[f64], CCAssignToReg<[D0, D1, D2, D3, D4, D5, D6, D7]>>, + CCIfType<[f32], CCAssignToReg<[S0, S1, S2, S3, S4, S5, S6, S7, S8, + S9, S10, S11, S12, S13, S14, S15]>>, + CCDelegateTo +]>; + + //===----------------------------------------------------------------------===// // ARM AAPCS (EABI) Calling Convention, common parts //===----------------------------------------------------------------------===// @@ -105,6 +133,7 @@ def RetCC_ARM_AAPCS : CallingConv<[ //===----------------------------------------------------------------------===// // ARM AAPCS-VFP (EABI) Calling Convention +// Also used for FastCC (when VFP2 or later is available) //===----------------------------------------------------------------------===// def CC_ARM_AAPCS_VFP : CallingConv<[ diff --git a/lib/Target/ARM/ARMCodeEmitter.cpp b/lib/Target/ARM/ARMCodeEmitter.cpp index b1a702f90cfc..9bbf6a030687 100644 --- a/lib/Target/ARM/ARMCodeEmitter.cpp +++ b/lib/Target/ARM/ARMCodeEmitter.cpp @@ -74,7 +74,7 @@ namespace { /// getBinaryCodeForInstr - This function, generated by the /// CodeEmitterGenerator using TableGen, produces the binary encoding for /// machine instructions. - unsigned getBinaryCodeForInstr(const MachineInstr &MI); + unsigned getBinaryCodeForInstr(const MachineInstr &MI) const; bool runOnMachineFunction(MachineFunction &MF); @@ -101,7 +101,6 @@ namespace { unsigned OpIdx); unsigned getMachineSoImmOpValue(unsigned SoImm); - unsigned getAddrModeSBit(const MachineInstr &MI, const TargetInstrDesc &TID) const; @@ -140,8 +139,6 @@ namespace { void emitVFPLoadStoreMultipleInstruction(const MachineInstr &MI); - void emitMiscInstruction(const MachineInstr &MI); - void emitNEONLaneInstruction(const MachineInstr &MI); void emitNEONDupInstruction(const MachineInstr &MI); void emitNEON1RegModImmInstruction(const MachineInstr &MI); @@ -150,20 +147,176 @@ namespace { /// getMachineOpValue - Return binary encoding of operand. If the machine /// operand requires relocation, record the relocation and return zero. - unsigned getMachineOpValue(const MachineInstr &MI,const MachineOperand &MO); - unsigned getMachineOpValue(const MachineInstr &MI, unsigned OpIdx) { + unsigned getMachineOpValue(const MachineInstr &MI, + const MachineOperand &MO) const; + unsigned getMachineOpValue(const MachineInstr &MI, unsigned OpIdx) const { return getMachineOpValue(MI, MI.getOperand(OpIdx)); } + // FIXME: The legacy JIT ARMCodeEmitter doesn't rely on the the + // TableGen'erated getBinaryCodeForInstr() function to encode any + // operand values, instead querying getMachineOpValue() directly for + // each operand it needs to encode. Thus, any of the new encoder + // helper functions can simply return 0 as the values the return + // are already handled elsewhere. They are placeholders to allow this + // encoder to continue to function until the MC encoder is sufficiently + // far along that this one can be eliminated entirely. + unsigned NEONThumb2DataIPostEncoder(const MachineInstr &MI, unsigned Val) + const { return 0; } + unsigned NEONThumb2LoadStorePostEncoder(const MachineInstr &MI,unsigned Val) + const { return 0; } + unsigned NEONThumb2DupPostEncoder(const MachineInstr &MI,unsigned Val) + const { return 0; } + unsigned VFPThumb2PostEncoder(const MachineInstr&MI, unsigned Val) + const { return 0; } + unsigned getAdrLabelOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getThumbAdrLabelOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getThumbBLTargetOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getThumbBLXTargetOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getThumbBRTargetOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getThumbBCCTargetOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getThumbCBTargetOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getBranchTargetOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getUnconditionalBranchTargetOpValue(const MachineInstr &MI, + unsigned Op) const { return 0; } + unsigned getARMBranchTargetOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getCCOutOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getSOImmOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getT2SOImmOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getSORegOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getThumbAddrModeRegRegOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getT2AddrModeImm12OpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getT2AddrModeImm8OpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getT2AddrModeImm8s4OpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getT2AddrModeImm8OffsetOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getT2AddrModeImm12OffsetOpValue(const MachineInstr &MI,unsigned Op) + const { return 0; } + unsigned getT2AddrModeSORegOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getT2SORegOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getRotImmOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getImmMinusOneOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getT2AdrLabelOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getAddrMode6AddressOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getAddrMode6DupAddressOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getAddrMode6OffsetOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + unsigned getBitfieldInvertedMaskOpValue(const MachineInstr &MI, + unsigned Op) const { return 0; } + unsigned getMsbOpValue(const MachineInstr &MI, + unsigned Op) const { return 0; } + uint32_t getLdStmModeOpValue(const MachineInstr &MI, unsigned OpIdx) + const {return 0; } + uint32_t getLdStSORegOpValue(const MachineInstr &MI, unsigned OpIdx) + const { return 0; } + + unsigned getAddrModeImm12OpValue(const MachineInstr &MI, unsigned Op) + const { + // {17-13} = reg + // {12} = (U)nsigned (add == '1', sub == '0') + // {11-0} = imm12 + const MachineOperand &MO = MI.getOperand(Op); + const MachineOperand &MO1 = MI.getOperand(Op + 1); + if (!MO.isReg()) { + emitConstPoolAddress(MO.getIndex(), ARM::reloc_arm_cp_entry); + return 0; + } + unsigned Reg = getARMRegisterNumbering(MO.getReg()); + int32_t Imm12 = MO1.getImm(); + uint32_t Binary; + Binary = Imm12 & 0xfff; + if (Imm12 >= 0) + Binary |= (1 << 12); + Binary |= (Reg << 13); + return Binary; + } + + unsigned getHiLo16ImmOpValue(const MachineInstr &MI, unsigned Op) const { + return 0; + } + + uint32_t getAddrMode2OpValue(const MachineInstr &MI, unsigned OpIdx) + const { return 0;} + uint32_t getAddrMode2OffsetOpValue(const MachineInstr &MI, unsigned OpIdx) + const { return 0;} + uint32_t getAddrMode3OffsetOpValue(const MachineInstr &MI, unsigned OpIdx) + const { return 0;} + uint32_t getAddrMode3OpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + uint32_t getAddrModeThumbSPOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + uint32_t getAddrModeSOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + uint32_t getAddrModeISOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + uint32_t getAddrModePCOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + uint32_t getAddrMode5OpValue(const MachineInstr &MI, unsigned Op) const { + // {17-13} = reg + // {12} = (U)nsigned (add == '1', sub == '0') + // {11-0} = imm12 + const MachineOperand &MO = MI.getOperand(Op); + const MachineOperand &MO1 = MI.getOperand(Op + 1); + if (!MO.isReg()) { + emitConstPoolAddress(MO.getIndex(), ARM::reloc_arm_cp_entry); + return 0; + } + unsigned Reg = getARMRegisterNumbering(MO.getReg()); + int32_t Imm12 = MO1.getImm(); + + // Special value for #-0 + if (Imm12 == INT32_MIN) + Imm12 = 0; + + // Immediate is always encoded as positive. The 'U' bit controls add vs + // sub. + bool isAdd = true; + if (Imm12 < 0) { + Imm12 = -Imm12; + isAdd = false; + } + + uint32_t Binary = Imm12 & 0xfff; + if (isAdd) + Binary |= (1 << 12); + Binary |= (Reg << 13); + return Binary; + } + unsigned getNEONVcvtImm32OpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + + unsigned getRegisterListOpValue(const MachineInstr &MI, unsigned Op) + const { return 0; } + /// getMovi32Value - Return binary encoding of operand for movw/movt. If the /// machine operand requires relocation, record the relocation and return /// zero. unsigned getMovi32Value(const MachineInstr &MI,const MachineOperand &MO, unsigned Reloc); - unsigned getMovi32Value(const MachineInstr &MI, unsigned OpIdx, - unsigned Reloc) { - return getMovi32Value(MI, MI.getOperand(OpIdx), Reloc); - } /// getShiftOp - Return the shift opcode (bit[6:5]) of the immediate value. /// @@ -173,12 +326,12 @@ namespace { /// fixed up by the relocation stage. void emitGlobalAddress(const GlobalValue *GV, unsigned Reloc, bool MayNeedFarStub, bool Indirect, - intptr_t ACPV = 0); - void emitExternalSymbolAddress(const char *ES, unsigned Reloc); - void emitConstPoolAddress(unsigned CPI, unsigned Reloc); - void emitJumpTableAddress(unsigned JTIndex, unsigned Reloc); + intptr_t ACPV = 0) const; + void emitExternalSymbolAddress(const char *ES, unsigned Reloc) const; + void emitConstPoolAddress(unsigned CPI, unsigned Reloc) const; + void emitJumpTableAddress(unsigned JTIndex, unsigned Reloc) const; void emitMachineBasicBlock(MachineBasicBlock *BB, unsigned Reloc, - intptr_t JTBase = 0); + intptr_t JTBase = 0) const; }; } @@ -266,9 +419,9 @@ unsigned ARMCodeEmitter::getMovi32Value(const MachineInstr &MI, /// getMachineOpValue - Return binary encoding of operand. If the machine /// operand requires relocation, record the relocation and return zero. unsigned ARMCodeEmitter::getMachineOpValue(const MachineInstr &MI, - const MachineOperand &MO) { + const MachineOperand &MO) const { if (MO.isReg()) - return ARMRegisterInfo::getRegisterNumbering(MO.getReg()); + return getARMRegisterNumbering(MO.getReg()); else if (MO.isImm()) return static_cast(MO.getImm()); else if (MO.isGlobal()) @@ -285,12 +438,8 @@ unsigned ARMCodeEmitter::getMachineOpValue(const MachineInstr &MI, emitJumpTableAddress(MO.getIndex(), ARM::reloc_arm_relative); else if (MO.isMBB()) emitMachineBasicBlock(MO.getMBB(), ARM::reloc_arm_branch); - else { -#ifndef NDEBUG - errs() << MO; -#endif - llvm_unreachable(0); - } + else + llvm_unreachable("Unable to encode MachineOperand!"); return 0; } @@ -298,7 +447,7 @@ unsigned ARMCodeEmitter::getMachineOpValue(const MachineInstr &MI, /// void ARMCodeEmitter::emitGlobalAddress(const GlobalValue *GV, unsigned Reloc, bool MayNeedFarStub, bool Indirect, - intptr_t ACPV) { + intptr_t ACPV) const { MachineRelocation MR = Indirect ? MachineRelocation::getIndirectSymbol(MCE.getCurrentPCOffset(), Reloc, const_cast(GV), @@ -312,7 +461,8 @@ void ARMCodeEmitter::emitGlobalAddress(const GlobalValue *GV, unsigned Reloc, /// emitExternalSymbolAddress - Arrange for the address of an external symbol to /// be emitted to the current location in the function, and allow it to be PC /// relative. -void ARMCodeEmitter::emitExternalSymbolAddress(const char *ES, unsigned Reloc) { +void ARMCodeEmitter:: +emitExternalSymbolAddress(const char *ES, unsigned Reloc) const { MCE.addRelocation(MachineRelocation::getExtSym(MCE.getCurrentPCOffset(), Reloc, ES)); } @@ -320,7 +470,7 @@ void ARMCodeEmitter::emitExternalSymbolAddress(const char *ES, unsigned Reloc) { /// emitConstPoolAddress - Arrange for the address of an constant pool /// to be emitted to the current location in the function, and allow it to be PC /// relative. -void ARMCodeEmitter::emitConstPoolAddress(unsigned CPI, unsigned Reloc) { +void ARMCodeEmitter::emitConstPoolAddress(unsigned CPI, unsigned Reloc) const { // Tell JIT emitter we'll resolve the address. MCE.addRelocation(MachineRelocation::getConstPool(MCE.getCurrentPCOffset(), Reloc, CPI, 0, true)); @@ -329,14 +479,16 @@ void ARMCodeEmitter::emitConstPoolAddress(unsigned CPI, unsigned Reloc) { /// emitJumpTableAddress - Arrange for the address of a jump table to /// be emitted to the current location in the function, and allow it to be PC /// relative. -void ARMCodeEmitter::emitJumpTableAddress(unsigned JTIndex, unsigned Reloc) { +void ARMCodeEmitter:: +emitJumpTableAddress(unsigned JTIndex, unsigned Reloc) const { MCE.addRelocation(MachineRelocation::getJumpTable(MCE.getCurrentPCOffset(), Reloc, JTIndex, 0, true)); } /// emitMachineBasicBlock - Emit the specified address basic block. void ARMCodeEmitter::emitMachineBasicBlock(MachineBasicBlock *BB, - unsigned Reloc, intptr_t JTBase) { + unsigned Reloc, + intptr_t JTBase) const { MCE.addRelocation(MachineRelocation::getBB(MCE.getCurrentPCOffset(), Reloc, BB, JTBase)); } @@ -364,6 +516,14 @@ void ARMCodeEmitter::emitInstruction(const MachineInstr &MI) { llvm_unreachable("Unhandled instruction encoding format!"); break; } + case ARMII::MiscFrm: + if (MI.getOpcode() == ARM::LEApcrelJT) { + // Materialize jumptable address. + emitLEApcrelJTInstruction(MI); + break; + } + llvm_unreachable("Unhandled instruction encoding!"); + break; case ARMII::Pseudo: emitPseudoInstruction(MI); break; @@ -418,9 +578,7 @@ void ARMCodeEmitter::emitInstruction(const MachineInstr &MI) { case ARMII::VFPLdStMulFrm: emitVFPLoadStoreMultipleInstruction(MI); break; - case ARMII::VFPMiscFrm: - emitMiscInstruction(MI); - break; + // NEON instructions. case ARMII::NGetLnFrm: case ARMII::NSetLnFrm: @@ -488,7 +646,7 @@ void ARMCodeEmitter::emitConstPoolInstruction(const MachineInstr &MI) { emitGlobalAddress(GV, ARM::reloc_arm_absolute, isa(GV), false); emitWordLE(0); } else if (const ConstantInt *CI = dyn_cast(CV)) { - uint32_t Val = *(uint32_t*)CI->getValue().getRawData(); + uint32_t Val = uint32_t(*CI->getValue().getRawData()); emitWordLE(Val); } else if (const ConstantFP *CFP = dyn_cast(CV)) { if (CFP->getType()->isFloatTy()) @@ -588,7 +746,7 @@ void ARMCodeEmitter::emitLEApcrelJTInstruction(const MachineInstr &MI) { const TargetInstrDesc &TID = MI.getDesc(); // Emit the 'add' instruction. - unsigned Binary = 0x4 << 21; // add: Insts{24-31} = 0b0100 + unsigned Binary = 0x4 << 21; // add: Insts{24-21} = 0b0100 // Set the conditional execution predicate Binary |= II->getPredicate(&MI) << ARMII::CondShift; @@ -600,7 +758,7 @@ void ARMCodeEmitter::emitLEApcrelJTInstruction(const MachineInstr &MI) { Binary |= getMachineOpValue(MI, 0) << ARMII::RegRdShift; // Encode Rn which is PC. - Binary |= ARMRegisterInfo::getRegisterNumbering(ARM::PC) << ARMII::RegRnShift; + Binary |= getARMRegisterNumbering(ARM::PC) << ARMII::RegRnShift; // Encode the displacement. Binary |= 1 << ARMII::I_BitShift; @@ -628,7 +786,7 @@ void ARMCodeEmitter::emitPseudoMoveInstruction(const MachineInstr &MI) { // Encode the shift operation. switch (Opcode) { default: break; - case ARM::MOVrx: + case ARM::RRX: // rrx Binary |= 0x6 << 4; break; @@ -659,10 +817,10 @@ void ARMCodeEmitter::emitPseudoInstruction(const MachineInstr &MI) { switch (Opcode) { default: llvm_unreachable("ARMCodeEmitter::emitPseudoInstruction"); - case ARM::BX: - case ARM::BMOVPCRX: - case ARM::BXr9: - case ARM::BMOVPCRXr9: { + case ARM::BX_CALL: + case ARM::BMOVPCRX_CALL: + case ARM::BXr9_CALL: + case ARM::BMOVPCRXr9_CALL: { // First emit mov lr, pc unsigned Binary = 0x01a0e00f; Binary |= II->getPredicate(&MI) << ARMII::CondShift; @@ -720,18 +878,18 @@ void ARMCodeEmitter::emitPseudoInstruction(const MachineInstr &MI) { } case ARM::MOVi32imm: - emitMOVi32immInstruction(MI); - break; - - case ARM::MOVi2pieces: // Two instructions to materialize a constant. - emitMOVi2piecesInstruction(MI); + if (Subtarget->hasV6T2Ops()) + emitMOVi32immInstruction(MI); + else + emitMOVi2piecesInstruction(MI); break; + case ARM::LEApcrelJT: // Materialize jumptable address. emitLEApcrelJTInstruction(MI); break; - case ARM::MOVrx: + case ARM::RRX: case ARM::MOVsrl_flag: case ARM::MOVsra_flag: emitPseudoMoveInstruction(MI); @@ -789,8 +947,7 @@ unsigned ARMCodeEmitter::getMachineSoRegOpValue(const MachineInstr &MI, if (Rs) { // Encode Rs bit[11:8]. assert(ARM_AM::getSORegOffset(MO2.getImm()) == 0); - return Binary | - (ARMRegisterInfo::getRegisterNumbering(Rs) << ARMII::RegRsShift); + return Binary | (getARMRegisterNumbering(Rs) << ARMII::RegRsShift); } // Encode shift_imm bit[11:7]. @@ -841,8 +998,7 @@ void ARMCodeEmitter::emitDataProcessingInstruction(const MachineInstr &MI, Binary |= getMachineOpValue(MI, OpIdx++) << ARMII::RegRdShift; else if (ImplicitRd) // Special handling for implicit use (e.g. PC). - Binary |= (ARMRegisterInfo::getRegisterNumbering(ImplicitRd) - << ARMII::RegRdShift); + Binary |= (getARMRegisterNumbering(ImplicitRd) << ARMII::RegRdShift); if (TID.Opcode == ARM::MOVi16) { // Get immediate from MI. @@ -892,8 +1048,7 @@ void ARMCodeEmitter::emitDataProcessingInstruction(const MachineInstr &MI, if (!isUnary) { if (ImplicitRn) // Special handling for implicit use (e.g. PC). - Binary |= (ARMRegisterInfo::getRegisterNumbering(ImplicitRn) - << ARMII::RegRnShift); + Binary |= (getARMRegisterNumbering(ImplicitRn) << ARMII::RegRnShift); else { Binary |= getMachineOpValue(MI, OpIdx) << ARMII::RegRnShift; ++OpIdx; @@ -910,7 +1065,7 @@ void ARMCodeEmitter::emitDataProcessingInstruction(const MachineInstr &MI, if (MO.isReg()) { // Encode register Rm. - emitWordLE(Binary | ARMRegisterInfo::getRegisterNumbering(MO.getReg())); + emitWordLE(Binary | getARMRegisterNumbering(MO.getReg())); return; } @@ -930,6 +1085,13 @@ void ARMCodeEmitter::emitLoadStoreInstruction(const MachineInstr &MI, // Part of binary is determined by TableGn. unsigned Binary = getBinaryCodeForInstr(MI); + // If this is an LDRi12, STRi12 or LDRcp, nothing more needs be done. + if (MI.getOpcode() == ARM::LDRi12 || MI.getOpcode() == ARM::LDRcp || + MI.getOpcode() == ARM::STRi12) { + emitWordLE(Binary); + return; + } + // Set the conditional execution predicate Binary |= II->getPredicate(&MI) << ARMII::CondShift; @@ -946,16 +1108,14 @@ void ARMCodeEmitter::emitLoadStoreInstruction(const MachineInstr &MI, // Set first operand if (ImplicitRd) // Special handling for implicit use (e.g. PC). - Binary |= (ARMRegisterInfo::getRegisterNumbering(ImplicitRd) - << ARMII::RegRdShift); + Binary |= (getARMRegisterNumbering(ImplicitRd) << ARMII::RegRdShift); else Binary |= getMachineOpValue(MI, OpIdx++) << ARMII::RegRdShift; // Set second operand if (ImplicitRn) // Special handling for implicit use (e.g. PC). - Binary |= (ARMRegisterInfo::getRegisterNumbering(ImplicitRn) - << ARMII::RegRnShift); + Binary |= (getARMRegisterNumbering(ImplicitRn) << ARMII::RegRnShift); else Binary |= getMachineOpValue(MI, OpIdx++) << ARMII::RegRnShift; @@ -978,11 +1138,11 @@ void ARMCodeEmitter::emitLoadStoreInstruction(const MachineInstr &MI, return; } - // Set bit I(25), because this is not in immediate enconding. + // Set bit I(25), because this is not in immediate encoding. Binary |= 1 << ARMII::I_BitShift; assert(TargetRegisterInfo::isPhysicalRegister(MO2.getReg())); // Set bit[3:0] to the corresponding Rm register - Binary |= ARMRegisterInfo::getRegisterNumbering(MO2.getReg()); + Binary |= getARMRegisterNumbering(MO2.getReg()); // If this instr is in scaled register offset/index instruction, set // shift_immed(bit[11:7]) and shift(bit[6:5]) fields. @@ -1026,8 +1186,7 @@ void ARMCodeEmitter::emitMiscLoadStoreInstruction(const MachineInstr &MI, // Set second operand if (ImplicitRn) // Special handling for implicit use (e.g. PC). - Binary |= (ARMRegisterInfo::getRegisterNumbering(ImplicitRn) - << ARMII::RegRnShift); + Binary |= (getARMRegisterNumbering(ImplicitRn) << ARMII::RegRnShift); else Binary |= getMachineOpValue(MI, OpIdx++) << ARMII::RegRnShift; @@ -1046,7 +1205,7 @@ void ARMCodeEmitter::emitMiscLoadStoreInstruction(const MachineInstr &MI, // If this instr is in register offset/index encoding, set bit[3:0] // to the corresponding Rm register. if (MO2.getReg()) { - Binary |= ARMRegisterInfo::getRegisterNumbering(MO2.getReg()); + Binary |= getARMRegisterNumbering(MO2.getReg()); emitWordLE(Binary); return; } @@ -1100,8 +1259,8 @@ void ARMCodeEmitter::emitLoadStoreMultipleInstruction(const MachineInstr &MI) { Binary |= getMachineOpValue(MI, OpIdx++) << ARMII::RegRnShift; // Set addressing mode by modifying bits U(23) and P(24) - const MachineOperand &MO = MI.getOperand(OpIdx++); - Binary |= getAddrModeUPBits(ARM_AM::getAM4SubMode(MO.getImm())); + ARM_AM::AMSubMode Mode = ARM_AM::getLoadStoreMultipleSubMode(MI.getOpcode()); + Binary |= getAddrModeUPBits(ARM_AM::getAM4SubMode(Mode)); // Set bit W(21) if (IsUpdating) @@ -1112,7 +1271,7 @@ void ARMCodeEmitter::emitLoadStoreMultipleInstruction(const MachineInstr &MI) { const MachineOperand &MO = MI.getOperand(i); if (!MO.isReg() || MO.isImplicit()) break; - unsigned RegNum = ARMRegisterInfo::getRegisterNumbering(MO.getReg()); + unsigned RegNum = getARMRegisterNumbering(MO.getReg()); assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg()) && RegNum < 16); Binary |= 0x1 << RegNum; @@ -1349,7 +1508,7 @@ void ARMCodeEmitter::emitMiscBranchInstruction(const MachineInstr &MI) { if (TID.Opcode == ARM::BX_RET || TID.Opcode == ARM::MOVPCLR) // The return register is LR. - Binary |= ARMRegisterInfo::getRegisterNumbering(ARM::LR); + Binary |= getARMRegisterNumbering(ARM::LR); else // otherwise, set the return register Binary |= getMachineOpValue(MI, 0); @@ -1360,8 +1519,8 @@ void ARMCodeEmitter::emitMiscBranchInstruction(const MachineInstr &MI) { static unsigned encodeVFPRd(const MachineInstr &MI, unsigned OpIdx) { unsigned RegD = MI.getOperand(OpIdx).getReg(); unsigned Binary = 0; - bool isSPVFP = false; - RegD = ARMRegisterInfo::getRegisterNumbering(RegD, &isSPVFP); + bool isSPVFP = ARM::SPRRegisterClass->contains(RegD); + RegD = getARMRegisterNumbering(RegD); if (!isSPVFP) Binary |= RegD << ARMII::RegRdShift; else { @@ -1374,8 +1533,8 @@ static unsigned encodeVFPRd(const MachineInstr &MI, unsigned OpIdx) { static unsigned encodeVFPRn(const MachineInstr &MI, unsigned OpIdx) { unsigned RegN = MI.getOperand(OpIdx).getReg(); unsigned Binary = 0; - bool isSPVFP = false; - RegN = ARMRegisterInfo::getRegisterNumbering(RegN, &isSPVFP); + bool isSPVFP = ARM::SPRRegisterClass->contains(RegN); + RegN = getARMRegisterNumbering(RegN); if (!isSPVFP) Binary |= RegN << ARMII::RegRnShift; else { @@ -1388,8 +1547,8 @@ static unsigned encodeVFPRn(const MachineInstr &MI, unsigned OpIdx) { static unsigned encodeVFPRm(const MachineInstr &MI, unsigned OpIdx) { unsigned RegM = MI.getOperand(OpIdx).getReg(); unsigned Binary = 0; - bool isSPVFP = false; - RegM = ARMRegisterInfo::getRegisterNumbering(RegM, &isSPVFP); + bool isSPVFP = ARM::SPRRegisterClass->contains(RegM); + RegM = getARMRegisterNumbering(RegM); if (!isSPVFP) Binary |= RegM; else { @@ -1548,8 +1707,8 @@ ARMCodeEmitter::emitVFPLoadStoreMultipleInstruction(const MachineInstr &MI) { Binary |= getMachineOpValue(MI, OpIdx++) << ARMII::RegRnShift; // Set addressing mode by modifying bits U(23) and P(24) - const MachineOperand &MO = MI.getOperand(OpIdx++); - Binary |= getAddrModeUPBits(ARM_AM::getAM4SubMode(MO.getImm())); + ARM_AM::AMSubMode Mode = ARM_AM::getLoadStoreMultipleSubMode(MI.getOpcode()); + Binary |= getAddrModeUPBits(ARM_AM::getAM4SubMode(Mode)); // Set bit W(21) if (IsUpdating) @@ -1576,63 +1735,10 @@ ARMCodeEmitter::emitVFPLoadStoreMultipleInstruction(const MachineInstr &MI) { emitWordLE(Binary); } -void ARMCodeEmitter::emitMiscInstruction(const MachineInstr &MI) { - unsigned Opcode = MI.getDesc().Opcode; - // Part of binary is determined by TableGn. - unsigned Binary = getBinaryCodeForInstr(MI); - - // Set the conditional execution predicate - Binary |= II->getPredicate(&MI) << ARMII::CondShift; - - switch(Opcode) { - default: - llvm_unreachable("ARMCodeEmitter::emitMiscInstruction"); - - case ARM::FMSTAT: - // No further encoding needed. - break; - - case ARM::VMRS: - case ARM::VMSR: { - const MachineOperand &MO0 = MI.getOperand(0); - // Encode Rt. - Binary |= ARMRegisterInfo::getRegisterNumbering(MO0.getReg()) - << ARMII::RegRdShift; - break; - } - - case ARM::FCONSTD: - case ARM::FCONSTS: { - // Encode Dd / Sd. - Binary |= encodeVFPRd(MI, 0); - - // Encode imm., Table A7-18 VFP modified immediate constants - const MachineOperand &MO1 = MI.getOperand(1); - unsigned Imm = static_cast(MO1.getFPImm()->getValueAPF() - .bitcastToAPInt().getHiBits(32).getLimitedValue()); - unsigned ModifiedImm; - - if(Opcode == ARM::FCONSTS) - ModifiedImm = (Imm & 0x80000000) >> 24 | // a - (Imm & 0x03F80000) >> 19; // bcdefgh - else // Opcode == ARM::FCONSTD - ModifiedImm = (Imm & 0x80000000) >> 24 | // a - (Imm & 0x007F0000) >> 16; // bcdefgh - - // Insts{19-16} = abcd, Insts{3-0} = efgh - Binary |= ((ModifiedImm & 0xF0) >> 4) << 16; - Binary |= (ModifiedImm & 0xF); - break; - } - } - - emitWordLE(Binary); -} - static unsigned encodeNEONRd(const MachineInstr &MI, unsigned OpIdx) { unsigned RegD = MI.getOperand(OpIdx).getReg(); unsigned Binary = 0; - RegD = ARMRegisterInfo::getRegisterNumbering(RegD); + RegD = getARMRegisterNumbering(RegD); Binary |= (RegD & 0xf) << ARMII::RegRdShift; Binary |= ((RegD >> 4) & 1) << ARMII::D_BitShift; return Binary; @@ -1641,7 +1747,7 @@ static unsigned encodeNEONRd(const MachineInstr &MI, unsigned OpIdx) { static unsigned encodeNEONRn(const MachineInstr &MI, unsigned OpIdx) { unsigned RegN = MI.getOperand(OpIdx).getReg(); unsigned Binary = 0; - RegN = ARMRegisterInfo::getRegisterNumbering(RegN); + RegN = getARMRegisterNumbering(RegN); Binary |= (RegN & 0xf) << ARMII::RegRnShift; Binary |= ((RegN >> 4) & 1) << ARMII::N_BitShift; return Binary; @@ -1650,7 +1756,7 @@ static unsigned encodeNEONRn(const MachineInstr &MI, unsigned OpIdx) { static unsigned encodeNEONRm(const MachineInstr &MI, unsigned OpIdx) { unsigned RegM = MI.getOperand(OpIdx).getReg(); unsigned Binary = 0; - RegM = ARMRegisterInfo::getRegisterNumbering(RegM); + RegM = getARMRegisterNumbering(RegM); Binary |= (RegM & 0xf); Binary |= ((RegM >> 4) & 1) << ARMII::M_BitShift; return Binary; @@ -1684,7 +1790,7 @@ void ARMCodeEmitter::emitNEONLaneInstruction(const MachineInstr &MI) { Binary |= (IsThumb ? ARMCC::AL : II->getPredicate(&MI)) << ARMII::CondShift; unsigned RegT = MI.getOperand(RegTOpIdx).getReg(); - RegT = ARMRegisterInfo::getRegisterNumbering(RegT); + RegT = getARMRegisterNumbering(RegT); Binary |= (RegT << ARMII::RegRdShift); Binary |= encodeNEONRn(MI, RegNOpIdx); @@ -1713,7 +1819,7 @@ void ARMCodeEmitter::emitNEONDupInstruction(const MachineInstr &MI) { Binary |= (IsThumb ? ARMCC::AL : II->getPredicate(&MI)) << ARMII::CondShift; unsigned RegT = MI.getOperand(1).getReg(); - RegT = ARMRegisterInfo::getRegisterNumbering(RegT); + RegT = getARMRegisterNumbering(RegT); Binary |= (RegT << ARMII::RegRdShift); Binary |= encodeNEONRn(MI, 0); emitWordLE(Binary); diff --git a/lib/Target/ARM/ARMConstantIslandPass.cpp b/lib/Target/ARM/ARMConstantIslandPass.cpp index 60e923bd2c38..13d1b33d1165 100644 --- a/lib/Target/ARM/ARMConstantIslandPass.cpp +++ b/lib/Target/ARM/ARMConstantIslandPass.cpp @@ -1,4 +1,4 @@ -//===-- ARMConstantIslandPass.cpp - ARM constant islands --------*- C++ -*-===// +//===-- ARMConstantIslandPass.cpp - ARM constant islands ------------------===// // // The LLVM Compiler Infrastructure // @@ -316,7 +316,7 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &MF) { } /// The next UID to take is the first unused one. - AFI->initConstPoolEntryUId(CPEMIs.size()); + AFI->initPICLabelUId(CPEMIs.size()); // Do the initial scan of the function, building up information about the // sizes of each block, the location of all the water, and finding all of the @@ -327,7 +327,7 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &MF) { /// Remove dead constant pool entries. - RemoveUnusedCPEntries(); + MadeChange |= RemoveUnusedCPEntries(); // Iteratively place constant pool entries and fix up branches until there // is no change. @@ -368,6 +368,14 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &MF) { if (isThumb && !HasFarJump && AFI->isLRSpilledForFarJump()) MadeChange |= UndoLRSpillRestore(); + // Save the mapping between original and cloned constpool entries. + for (unsigned i = 0, e = CPEntries.size(); i != e; ++i) { + for (unsigned j = 0, je = CPEntries[i].size(); j != je; ++j) { + const CPEntry & CPE = CPEntries[i][j]; + AFI->recordCPEClone(i, CPE.CPI); + } + } + DEBUG(errs() << '\n'; dumpBBs()); BBSizes.clear(); @@ -482,7 +490,7 @@ void ARMConstantIslands::InitialFunctionScan(MachineFunction &MF, HasInlineAsm = true; } - // Now go back through the instructions and build up our data structures + // Now go back through the instructions and build up our data structures. unsigned Offset = 0; for (MachineFunction::iterator MBBI = MF.begin(), E = MF.end(); MBBI != E; ++MBBI) { @@ -603,7 +611,7 @@ void ARMConstantIslands::InitialFunctionScan(MachineFunction &MF, Scale = 4; break; - case ARM::LDR: + case ARM::LDRi12: case ARM::LDRcp: case ARM::t2LDRpci: Bits = 12; // +-offset_12 @@ -611,7 +619,6 @@ void ARMConstantIslands::InitialFunctionScan(MachineFunction &MF, break; case ARM::tLDRpci: - case ARM::tLDRcp: Bits = 8; Scale = 4; // +(offset_8*4) break; @@ -692,7 +699,7 @@ static bool CompareMBBNumbers(const MachineBasicBlock *LHS, /// machine function, it upsets all of the block numbers. Renumber the blocks /// and update the arrays that parallel this numbering. void ARMConstantIslands::UpdateForInsertedWaterBlock(MachineBasicBlock *NewBB) { - // Renumber the MBB's to keep them consequtive. + // Renumber the MBB's to keep them consecutive. NewBB->getParent()->RenumberBlocks(NewBB); // Insert a size into BBSizes to align it properly with the (newly @@ -1242,7 +1249,7 @@ bool ARMConstantIslands::HandleConstantPoolUser(MachineFunction &MF, // No existing clone of this CPE is within range. // We will be generating a new clone. Get a UID for it. - unsigned ID = AFI->createConstPoolEntryUId(); + unsigned ID = AFI->createPICLabelUId(); // Look for water where we can place this CPE. MachineBasicBlock *NewIsland = MF.CreateMachineBasicBlock(); @@ -1644,7 +1651,7 @@ bool ARMConstantIslands::OptimizeThumb2Branches(MachineFunction &MF) { unsigned DestOffset = BBOffsets[DestBB->getNumber()]; if (BrOffset < DestOffset && (DestOffset - BrOffset) <= 126) { MachineBasicBlock::iterator CmpMI = Br.MI; --CmpMI; - if (CmpMI->getOpcode() == ARM::tCMPzi8) { + if (CmpMI->getOpcode() == ARM::tCMPi8) { unsigned Reg = CmpMI->getOperand(0).getReg(); Pred = llvm::getInstrPredicate(CmpMI, PredReg); if (Pred == ARMCC::AL && @@ -1766,7 +1773,7 @@ bool ARMConstantIslands::OptimizeThumb2JumpTables(MachineFunction &MF) { if (!OptOk) continue; - unsigned Opc = ByteOk ? ARM::t2TBB : ARM::t2TBH; + unsigned Opc = ByteOk ? ARM::t2TBB_JT : ARM::t2TBH_JT; MachineInstr *NewJTMI = BuildMI(MBB, MI->getDebugLoc(), TII->get(Opc)) .addReg(IdxReg, getKillRegState(IdxRegKill)) .addJumpTableIndex(JTI, JTOP.getTargetFlags()) diff --git a/lib/Target/ARM/ARMConstantPoolValue.cpp b/lib/Target/ARM/ARMConstantPoolValue.cpp index f13ccc638448..165a1d849ad5 100644 --- a/lib/Target/ARM/ARMConstantPoolValue.cpp +++ b/lib/Target/ARM/ARMConstantPoolValue.cpp @@ -24,7 +24,7 @@ using namespace llvm; ARMConstantPoolValue::ARMConstantPoolValue(const Constant *cval, unsigned id, ARMCP::ARMCPKind K, unsigned char PCAdj, - const char *Modif, + ARMCP::ARMCPModifier Modif, bool AddCA) : MachineConstantPoolValue((const Type*)cval->getType()), CVal(cval), S(NULL), LabelId(id), Kind(K), PCAdjust(PCAdj), @@ -33,17 +33,17 @@ ARMConstantPoolValue::ARMConstantPoolValue(const Constant *cval, unsigned id, ARMConstantPoolValue::ARMConstantPoolValue(LLVMContext &C, const char *s, unsigned id, unsigned char PCAdj, - const char *Modif, + ARMCP::ARMCPModifier Modif, bool AddCA) : MachineConstantPoolValue((const Type*)Type::getInt32Ty(C)), CVal(NULL), S(strdup(s)), LabelId(id), Kind(ARMCP::CPExtSymbol), PCAdjust(PCAdj), Modifier(Modif), AddCurrentAddress(AddCA) {} ARMConstantPoolValue::ARMConstantPoolValue(const GlobalValue *gv, - const char *Modif) + ARMCP::ARMCPModifier Modif) : MachineConstantPoolValue((const Type*)Type::getInt32Ty(gv->getContext())), CVal(gv), S(NULL), LabelId(0), Kind(ARMCP::CPValue), PCAdjust(0), - Modifier(Modif) {} + Modifier(Modif), AddCurrentAddress(false) {} const GlobalValue *ARMConstantPoolValue::getGV() const { return dyn_cast_or_null(CVal); @@ -53,6 +53,14 @@ const BlockAddress *ARMConstantPoolValue::getBlockAddress() const { return dyn_cast_or_null(CVal); } +static bool CPV_streq(const char *S1, const char *S2) { + if (S1 == S2) + return true; + if (S1 && S2 && strcmp(S1, S2) == 0) + return true; + return false; +} + int ARMConstantPoolValue::getExistingMachineCPValue(MachineConstantPool *CP, unsigned Alignment) { unsigned AlignMask = Alignment - 1; @@ -65,8 +73,8 @@ int ARMConstantPoolValue::getExistingMachineCPValue(MachineConstantPool *CP, if (CPV->CVal == CVal && CPV->LabelId == LabelId && CPV->PCAdjust == PCAdjust && - (CPV->S == S || strcmp(CPV->S, S) == 0) && - (CPV->Modifier == Modifier || strcmp(CPV->Modifier, Modifier) == 0)) + CPV_streq(CPV->S, S) && + CPV->Modifier == Modifier) return i; } } @@ -91,8 +99,8 @@ ARMConstantPoolValue::hasSameValue(ARMConstantPoolValue *ACPV) { if (ACPV->Kind == Kind && ACPV->CVal == CVal && ACPV->PCAdjust == PCAdjust && - (ACPV->S == S || strcmp(ACPV->S, S) == 0) && - (ACPV->Modifier == Modifier || strcmp(ACPV->Modifier, Modifier) == 0)) { + CPV_streq(ACPV->S, S) && + ACPV->Modifier == Modifier) { if (ACPV->LabelId == LabelId) return true; // Two PC relative constpool entries containing the same GV address or @@ -113,7 +121,7 @@ void ARMConstantPoolValue::print(raw_ostream &O) const { O << CVal->getName(); else O << S; - if (Modifier) O << "(" << Modifier << ")"; + if (Modifier) O << "(" << getModifierText() << ")"; if (PCAdjust != 0) { O << "-(LPC" << LabelId << "+" << (unsigned)PCAdjust; if (AddCurrentAddress) O << "-."; diff --git a/lib/Target/ARM/ARMConstantPoolValue.h b/lib/Target/ARM/ARMConstantPoolValue.h index 3119b54563de..d008811c40e4 100644 --- a/lib/Target/ARM/ARMConstantPoolValue.h +++ b/lib/Target/ARM/ARMConstantPoolValue.h @@ -15,6 +15,7 @@ #define LLVM_TARGET_ARM_CONSTANTPOOLVALUE_H #include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/Support/ErrorHandling.h" #include namespace llvm { @@ -31,6 +32,15 @@ namespace ARMCP { CPBlockAddress, CPLSDA }; + + enum ARMCPModifier { + no_modifier, + TLSGD, + GOT, + GOTOFF, + GOTTPOFF, + TPOFF + }; } /// ARMConstantPoolValue - ARM specific constantpool value. This is used to @@ -43,26 +53,41 @@ class ARMConstantPoolValue : public MachineConstantPoolValue { ARMCP::ARMCPKind Kind; // Kind of constant. unsigned char PCAdjust; // Extra adjustment if constantpool is pc-relative. // 8 for ARM, 4 for Thumb. - const char *Modifier; // GV modifier i.e. (&GV(modifier)-(LPIC+8)) + ARMCP::ARMCPModifier Modifier; // GV modifier i.e. (&GV(modifier)-(LPIC+8)) bool AddCurrentAddress; public: ARMConstantPoolValue(const Constant *cval, unsigned id, ARMCP::ARMCPKind Kind = ARMCP::CPValue, - unsigned char PCAdj = 0, const char *Modifier = NULL, + unsigned char PCAdj = 0, + ARMCP::ARMCPModifier Modifier = ARMCP::no_modifier, bool AddCurrentAddress = false); ARMConstantPoolValue(LLVMContext &C, const char *s, unsigned id, - unsigned char PCAdj = 0, const char *Modifier = NULL, + unsigned char PCAdj = 0, + ARMCP::ARMCPModifier Modifier = ARMCP::no_modifier, bool AddCurrentAddress = false); - ARMConstantPoolValue(const GlobalValue *GV, const char *Modifier); + ARMConstantPoolValue(const GlobalValue *GV, ARMCP::ARMCPModifier Modifier); ARMConstantPoolValue(); ~ARMConstantPoolValue(); const GlobalValue *getGV() const; const char *getSymbol() const { return S; } const BlockAddress *getBlockAddress() const; - const char *getModifier() const { return Modifier; } - bool hasModifier() const { return Modifier != NULL; } + ARMCP::ARMCPModifier getModifier() const { return Modifier; } + const char *getModifierText() const { + switch (Modifier) { + default: llvm_unreachable("Unknown modifier!"); + // FIXME: Are these case sensitive? It'd be nice to lower-case all the + // strings if that's legal. + case ARMCP::no_modifier: return "none"; + case ARMCP::TLSGD: return "tlsgd"; + case ARMCP::GOT: return "GOT"; + case ARMCP::GOTOFF: return "GOTOFF"; + case ARMCP::GOTTPOFF: return "gottpoff"; + case ARMCP::TPOFF: return "tpoff"; + } + } + bool hasModifier() const { return Modifier != ARMCP::no_modifier; } bool mustAddCurrentAddress() const { return AddCurrentAddress; } unsigned getLabelId() const { return LabelId; } unsigned char getPCAdjustment() const { return PCAdjust; } @@ -71,11 +96,7 @@ public: bool isBlockAddress() { return Kind == ARMCP::CPBlockAddress; } bool isLSDA() { return Kind == ARMCP::CPLSDA; } - virtual unsigned getRelocationInfo() const { - // FIXME: This is conservatively claiming that these entries require a - // relocation, we may be able to do better than this. - return 2; - } + virtual unsigned getRelocationInfo() const { return 2; } virtual int getExistingMachineCPValue(MachineConstantPool *CP, unsigned Alignment); diff --git a/lib/Target/ARM/ARMELFWriterInfo.cpp b/lib/Target/ARM/ARMELFWriterInfo.cpp new file mode 100644 index 000000000000..51e68b4553ff --- /dev/null +++ b/lib/Target/ARM/ARMELFWriterInfo.cpp @@ -0,0 +1,83 @@ +//===-- ARMELFWriterInfo.cpp - ELF Writer Info for the ARM backend --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements ELF writer information for the ARM backend. +// +//===----------------------------------------------------------------------===// + +#include "ARMELFWriterInfo.h" +#include "ARMRelocations.h" +#include "llvm/Function.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Support/ELF.h" + +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Implementation of the ARMELFWriterInfo class +//===----------------------------------------------------------------------===// + +ARMELFWriterInfo::ARMELFWriterInfo(TargetMachine &TM) + : TargetELFWriterInfo(TM.getTargetData()->getPointerSizeInBits() == 64, + TM.getTargetData()->isLittleEndian()) { +} + +ARMELFWriterInfo::~ARMELFWriterInfo() {} + +unsigned ARMELFWriterInfo::getRelocationType(unsigned MachineRelTy) const { + switch (MachineRelTy) { + case ARM::reloc_arm_absolute: + case ARM::reloc_arm_relative: + case ARM::reloc_arm_cp_entry: + case ARM::reloc_arm_vfp_cp_entry: + case ARM::reloc_arm_machine_cp_entry: + case ARM::reloc_arm_jt_base: + case ARM::reloc_arm_pic_jt: + assert(0 && "unsupported ARM relocation type"); break; + + case ARM::reloc_arm_branch: return ELF::R_ARM_CALL; break; + case ARM::reloc_arm_movt: return ELF::R_ARM_MOVT_ABS; break; + case ARM::reloc_arm_movw: return ELF::R_ARM_MOVW_ABS_NC; break; + default: + llvm_unreachable("unknown ARM relocation type"); break; + } + return 0; +} + +long int ARMELFWriterInfo::getDefaultAddendForRelTy(unsigned RelTy, + long int Modifier) const { + assert(0 && "ARMELFWriterInfo::getDefaultAddendForRelTy() not implemented"); + return 0; +} + +unsigned ARMELFWriterInfo::getRelocationTySize(unsigned RelTy) const { + assert(0 && "ARMELFWriterInfo::getRelocationTySize() not implemented"); + return 0; +} + +bool ARMELFWriterInfo::isPCRelativeRel(unsigned RelTy) const { + assert(0 && "ARMELFWriterInfo::isPCRelativeRel() not implemented"); + return 1; +} + +unsigned ARMELFWriterInfo::getAbsoluteLabelMachineRelTy() const { + assert(0 && + "ARMELFWriterInfo::getAbsoluteLabelMachineRelTy() not implemented"); + return 0; +} + +long int ARMELFWriterInfo::computeRelocation(unsigned SymOffset, + unsigned RelOffset, + unsigned RelTy) const { + assert(0 && + "ARMELFWriterInfo::getAbsoluteLabelMachineRelTy() not implemented"); + return 0; +} diff --git a/lib/Target/ARM/ARMELFWriterInfo.h b/lib/Target/ARM/ARMELFWriterInfo.h new file mode 100644 index 000000000000..1c4e5329ac61 --- /dev/null +++ b/lib/Target/ARM/ARMELFWriterInfo.h @@ -0,0 +1,58 @@ +//===-- ARMELFWriterInfo.h - ELF Writer Info for ARM ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements ELF writer information for the ARM backend. +// +//===----------------------------------------------------------------------===// + +#ifndef ARM_ELF_WRITER_INFO_H +#define ARM_ELF_WRITER_INFO_H + +#include "llvm/Target/TargetELFWriterInfo.h" + +namespace llvm { + + class ARMELFWriterInfo : public TargetELFWriterInfo { + public: + ARMELFWriterInfo(TargetMachine &TM); + virtual ~ARMELFWriterInfo(); + + /// getRelocationType - Returns the target specific ELF Relocation type. + /// 'MachineRelTy' contains the object code independent relocation type + virtual unsigned getRelocationType(unsigned MachineRelTy) const; + + /// hasRelocationAddend - True if the target uses an addend in the + /// ELF relocation entry. + virtual bool hasRelocationAddend() const { return false; } + + /// getDefaultAddendForRelTy - Gets the default addend value for a + /// relocation entry based on the target ELF relocation type. + virtual long int getDefaultAddendForRelTy(unsigned RelTy, + long int Modifier = 0) const; + + /// getRelTySize - Returns the size of relocatable field in bits + virtual unsigned getRelocationTySize(unsigned RelTy) const; + + /// isPCRelativeRel - True if the relocation type is pc relative + virtual bool isPCRelativeRel(unsigned RelTy) const; + + /// getJumpTableRelocationTy - Returns the machine relocation type used + /// to reference a jumptable. + virtual unsigned getAbsoluteLabelMachineRelTy() const; + + /// computeRelocation - Some relocatable fields could be relocated + /// directly, avoiding the relocation symbol emission, compute the + /// final relocation value for this symbol. + virtual long int computeRelocation(unsigned SymOffset, unsigned RelOffset, + unsigned RelTy) const; + }; + +} // end llvm namespace + +#endif // ARM_ELF_WRITER_INFO_H diff --git a/lib/Target/ARM/ARMExpandPseudoInsts.cpp b/lib/Target/ARM/ARMExpandPseudoInsts.cpp index fc2e3c3fadae..bd753d29abde 100644 --- a/lib/Target/ARM/ARMExpandPseudoInsts.cpp +++ b/lib/Target/ARM/ARMExpandPseudoInsts.cpp @@ -7,36 +7,38 @@ // //===----------------------------------------------------------------------===// // -// This file contains a pass that expand pseudo instructions into target +// This file contains a pass that expands pseudo instructions into target // instructions to allow proper scheduling, if-conversion, and other late // optimizations. This pass should be run after register allocation but before -// post- regalloc scheduling pass. +// the post-regalloc scheduling pass. // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "arm-pseudo" #include "ARM.h" +#include "ARMAddressingModes.h" #include "ARMBaseInstrInfo.h" +#include "ARMBaseRegisterInfo.h" +#include "ARMMachineFunctionInfo.h" +#include "ARMRegisterInfo.h" +#include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Support/raw_ostream.h" // FIXME: for debug only. remove! using namespace llvm; namespace { class ARMExpandPseudo : public MachineFunctionPass { - // Constants for register spacing in NEON load/store instructions. - enum NEONRegSpacing { - SingleSpc, - EvenDblSpc, - OddDblSpc - }; - public: static char ID; ARMExpandPseudo() : MachineFunctionPass(ID) {} - const TargetInstrInfo *TII; + const ARMBaseInstrInfo *TII; const TargetRegisterInfo *TRI; + const ARMSubtarget *STI; + ARMFunctionInfo *AFI; virtual bool runOnMachineFunction(MachineFunction &Fn); @@ -47,11 +49,16 @@ namespace { private: void TransferImpOps(MachineInstr &OldMI, MachineInstrBuilder &UseMI, MachineInstrBuilder &DefMI); + bool ExpandMI(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI); bool ExpandMBB(MachineBasicBlock &MBB); - void ExpandVLD(MachineBasicBlock::iterator &MBBI, unsigned Opc, - bool hasWriteBack, NEONRegSpacing RegSpc, unsigned NumRegs); - void ExpandVST(MachineBasicBlock::iterator &MBBI, unsigned Opc, - bool hasWriteBack, NEONRegSpacing RegSpc, unsigned NumRegs); + void ExpandVLD(MachineBasicBlock::iterator &MBBI); + void ExpandVST(MachineBasicBlock::iterator &MBBI); + void ExpandLaneOp(MachineBasicBlock::iterator &MBBI); + void ExpandVTBL(MachineBasicBlock::iterator &MBBI, + unsigned Opc, bool IsExt, unsigned NumRegs); + void ExpandMOV32BitImm(MachineBasicBlock &MBB, + MachineBasicBlock::iterator &MBBI); }; char ARMExpandPseudo::ID = 0; } @@ -67,44 +74,349 @@ void ARMExpandPseudo::TransferImpOps(MachineInstr &OldMI, const MachineOperand &MO = OldMI.getOperand(i); assert(MO.isReg() && MO.getReg()); if (MO.isUse()) - UseMI.addReg(MO.getReg(), getKillRegState(MO.isKill())); + UseMI.addOperand(MO); else - DefMI.addReg(MO.getReg(), - getDefRegState(true) | getDeadRegState(MO.isDead())); + DefMI.addOperand(MO); + } +} + +namespace { + // Constants for register spacing in NEON load/store instructions. + // For quad-register load-lane and store-lane pseudo instructors, the + // spacing is initially assumed to be EvenDblSpc, and that is changed to + // OddDblSpc depending on the lane number operand. + enum NEONRegSpacing { + SingleSpc, + EvenDblSpc, + OddDblSpc + }; + + // Entries for NEON load/store information table. The table is sorted by + // PseudoOpc for fast binary-search lookups. + struct NEONLdStTableEntry { + unsigned PseudoOpc; + unsigned RealOpc; + bool IsLoad; + bool HasWriteBack; + NEONRegSpacing RegSpacing; + unsigned char NumRegs; // D registers loaded or stored + unsigned char RegElts; // elements per D register; used for lane ops + + // Comparison methods for binary search of the table. + bool operator<(const NEONLdStTableEntry &TE) const { + return PseudoOpc < TE.PseudoOpc; + } + friend bool operator<(const NEONLdStTableEntry &TE, unsigned PseudoOpc) { + return TE.PseudoOpc < PseudoOpc; + } + friend bool LLVM_ATTRIBUTE_UNUSED operator<(unsigned PseudoOpc, + const NEONLdStTableEntry &TE) { + return PseudoOpc < TE.PseudoOpc; + } + }; +} + +static const NEONLdStTableEntry NEONLdStTable[] = { +{ ARM::VLD1DUPq16Pseudo, ARM::VLD1DUPq16, true, false, SingleSpc, 2, 4}, +{ ARM::VLD1DUPq16Pseudo_UPD, ARM::VLD1DUPq16_UPD, true, true, SingleSpc, 2, 4}, +{ ARM::VLD1DUPq32Pseudo, ARM::VLD1DUPq32, true, false, SingleSpc, 2, 2}, +{ ARM::VLD1DUPq32Pseudo_UPD, ARM::VLD1DUPq32_UPD, true, true, SingleSpc, 2, 2}, +{ ARM::VLD1DUPq8Pseudo, ARM::VLD1DUPq8, true, false, SingleSpc, 2, 8}, +{ ARM::VLD1DUPq8Pseudo_UPD, ARM::VLD1DUPq8_UPD, true, true, SingleSpc, 2, 8}, + +{ ARM::VLD1LNq16Pseudo, ARM::VLD1LNd16, true, false, EvenDblSpc, 1, 4 }, +{ ARM::VLD1LNq16Pseudo_UPD, ARM::VLD1LNd16_UPD, true, true, EvenDblSpc, 1, 4 }, +{ ARM::VLD1LNq32Pseudo, ARM::VLD1LNd32, true, false, EvenDblSpc, 1, 2 }, +{ ARM::VLD1LNq32Pseudo_UPD, ARM::VLD1LNd32_UPD, true, true, EvenDblSpc, 1, 2 }, +{ ARM::VLD1LNq8Pseudo, ARM::VLD1LNd8, true, false, EvenDblSpc, 1, 8 }, +{ ARM::VLD1LNq8Pseudo_UPD, ARM::VLD1LNd8_UPD, true, true, EvenDblSpc, 1, 8 }, + +{ ARM::VLD1d64QPseudo, ARM::VLD1d64Q, true, false, SingleSpc, 4, 1 }, +{ ARM::VLD1d64QPseudo_UPD, ARM::VLD1d64Q_UPD, true, true, SingleSpc, 4, 1 }, +{ ARM::VLD1d64TPseudo, ARM::VLD1d64T, true, false, SingleSpc, 3, 1 }, +{ ARM::VLD1d64TPseudo_UPD, ARM::VLD1d64T_UPD, true, true, SingleSpc, 3, 1 }, + +{ ARM::VLD1q16Pseudo, ARM::VLD1q16, true, false, SingleSpc, 2, 4 }, +{ ARM::VLD1q16Pseudo_UPD, ARM::VLD1q16_UPD, true, true, SingleSpc, 2, 4 }, +{ ARM::VLD1q32Pseudo, ARM::VLD1q32, true, false, SingleSpc, 2, 2 }, +{ ARM::VLD1q32Pseudo_UPD, ARM::VLD1q32_UPD, true, true, SingleSpc, 2, 2 }, +{ ARM::VLD1q64Pseudo, ARM::VLD1q64, true, false, SingleSpc, 2, 1 }, +{ ARM::VLD1q64Pseudo_UPD, ARM::VLD1q64_UPD, true, true, SingleSpc, 2, 1 }, +{ ARM::VLD1q8Pseudo, ARM::VLD1q8, true, false, SingleSpc, 2, 8 }, +{ ARM::VLD1q8Pseudo_UPD, ARM::VLD1q8_UPD, true, true, SingleSpc, 2, 8 }, + +{ ARM::VLD2DUPd16Pseudo, ARM::VLD2DUPd16, true, false, SingleSpc, 2, 4}, +{ ARM::VLD2DUPd16Pseudo_UPD, ARM::VLD2DUPd16_UPD, true, true, SingleSpc, 2, 4}, +{ ARM::VLD2DUPd32Pseudo, ARM::VLD2DUPd32, true, false, SingleSpc, 2, 2}, +{ ARM::VLD2DUPd32Pseudo_UPD, ARM::VLD2DUPd32_UPD, true, true, SingleSpc, 2, 2}, +{ ARM::VLD2DUPd8Pseudo, ARM::VLD2DUPd8, true, false, SingleSpc, 2, 8}, +{ ARM::VLD2DUPd8Pseudo_UPD, ARM::VLD2DUPd8_UPD, true, true, SingleSpc, 2, 8}, + +{ ARM::VLD2LNd16Pseudo, ARM::VLD2LNd16, true, false, SingleSpc, 2, 4 }, +{ ARM::VLD2LNd16Pseudo_UPD, ARM::VLD2LNd16_UPD, true, true, SingleSpc, 2, 4 }, +{ ARM::VLD2LNd32Pseudo, ARM::VLD2LNd32, true, false, SingleSpc, 2, 2 }, +{ ARM::VLD2LNd32Pseudo_UPD, ARM::VLD2LNd32_UPD, true, true, SingleSpc, 2, 2 }, +{ ARM::VLD2LNd8Pseudo, ARM::VLD2LNd8, true, false, SingleSpc, 2, 8 }, +{ ARM::VLD2LNd8Pseudo_UPD, ARM::VLD2LNd8_UPD, true, true, SingleSpc, 2, 8 }, +{ ARM::VLD2LNq16Pseudo, ARM::VLD2LNq16, true, false, EvenDblSpc, 2, 4 }, +{ ARM::VLD2LNq16Pseudo_UPD, ARM::VLD2LNq16_UPD, true, true, EvenDblSpc, 2, 4 }, +{ ARM::VLD2LNq32Pseudo, ARM::VLD2LNq32, true, false, EvenDblSpc, 2, 2 }, +{ ARM::VLD2LNq32Pseudo_UPD, ARM::VLD2LNq32_UPD, true, true, EvenDblSpc, 2, 2 }, + +{ ARM::VLD2d16Pseudo, ARM::VLD2d16, true, false, SingleSpc, 2, 4 }, +{ ARM::VLD2d16Pseudo_UPD, ARM::VLD2d16_UPD, true, true, SingleSpc, 2, 4 }, +{ ARM::VLD2d32Pseudo, ARM::VLD2d32, true, false, SingleSpc, 2, 2 }, +{ ARM::VLD2d32Pseudo_UPD, ARM::VLD2d32_UPD, true, true, SingleSpc, 2, 2 }, +{ ARM::VLD2d8Pseudo, ARM::VLD2d8, true, false, SingleSpc, 2, 8 }, +{ ARM::VLD2d8Pseudo_UPD, ARM::VLD2d8_UPD, true, true, SingleSpc, 2, 8 }, + +{ ARM::VLD2q16Pseudo, ARM::VLD2q16, true, false, SingleSpc, 4, 4 }, +{ ARM::VLD2q16Pseudo_UPD, ARM::VLD2q16_UPD, true, true, SingleSpc, 4, 4 }, +{ ARM::VLD2q32Pseudo, ARM::VLD2q32, true, false, SingleSpc, 4, 2 }, +{ ARM::VLD2q32Pseudo_UPD, ARM::VLD2q32_UPD, true, true, SingleSpc, 4, 2 }, +{ ARM::VLD2q8Pseudo, ARM::VLD2q8, true, false, SingleSpc, 4, 8 }, +{ ARM::VLD2q8Pseudo_UPD, ARM::VLD2q8_UPD, true, true, SingleSpc, 4, 8 }, + +{ ARM::VLD3DUPd16Pseudo, ARM::VLD3DUPd16, true, false, SingleSpc, 3, 4}, +{ ARM::VLD3DUPd16Pseudo_UPD, ARM::VLD3DUPd16_UPD, true, true, SingleSpc, 3, 4}, +{ ARM::VLD3DUPd32Pseudo, ARM::VLD3DUPd32, true, false, SingleSpc, 3, 2}, +{ ARM::VLD3DUPd32Pseudo_UPD, ARM::VLD3DUPd32_UPD, true, true, SingleSpc, 3, 2}, +{ ARM::VLD3DUPd8Pseudo, ARM::VLD3DUPd8, true, false, SingleSpc, 3, 8}, +{ ARM::VLD3DUPd8Pseudo_UPD, ARM::VLD3DUPd8_UPD, true, true, SingleSpc, 3, 8}, + +{ ARM::VLD3LNd16Pseudo, ARM::VLD3LNd16, true, false, SingleSpc, 3, 4 }, +{ ARM::VLD3LNd16Pseudo_UPD, ARM::VLD3LNd16_UPD, true, true, SingleSpc, 3, 4 }, +{ ARM::VLD3LNd32Pseudo, ARM::VLD3LNd32, true, false, SingleSpc, 3, 2 }, +{ ARM::VLD3LNd32Pseudo_UPD, ARM::VLD3LNd32_UPD, true, true, SingleSpc, 3, 2 }, +{ ARM::VLD3LNd8Pseudo, ARM::VLD3LNd8, true, false, SingleSpc, 3, 8 }, +{ ARM::VLD3LNd8Pseudo_UPD, ARM::VLD3LNd8_UPD, true, true, SingleSpc, 3, 8 }, +{ ARM::VLD3LNq16Pseudo, ARM::VLD3LNq16, true, false, EvenDblSpc, 3, 4 }, +{ ARM::VLD3LNq16Pseudo_UPD, ARM::VLD3LNq16_UPD, true, true, EvenDblSpc, 3, 4 }, +{ ARM::VLD3LNq32Pseudo, ARM::VLD3LNq32, true, false, EvenDblSpc, 3, 2 }, +{ ARM::VLD3LNq32Pseudo_UPD, ARM::VLD3LNq32_UPD, true, true, EvenDblSpc, 3, 2 }, + +{ ARM::VLD3d16Pseudo, ARM::VLD3d16, true, false, SingleSpc, 3, 4 }, +{ ARM::VLD3d16Pseudo_UPD, ARM::VLD3d16_UPD, true, true, SingleSpc, 3, 4 }, +{ ARM::VLD3d32Pseudo, ARM::VLD3d32, true, false, SingleSpc, 3, 2 }, +{ ARM::VLD3d32Pseudo_UPD, ARM::VLD3d32_UPD, true, true, SingleSpc, 3, 2 }, +{ ARM::VLD3d8Pseudo, ARM::VLD3d8, true, false, SingleSpc, 3, 8 }, +{ ARM::VLD3d8Pseudo_UPD, ARM::VLD3d8_UPD, true, true, SingleSpc, 3, 8 }, + +{ ARM::VLD3q16Pseudo_UPD, ARM::VLD3q16_UPD, true, true, EvenDblSpc, 3, 4 }, +{ ARM::VLD3q16oddPseudo, ARM::VLD3q16, true, false, OddDblSpc, 3, 4 }, +{ ARM::VLD3q16oddPseudo_UPD, ARM::VLD3q16_UPD, true, true, OddDblSpc, 3, 4 }, +{ ARM::VLD3q32Pseudo_UPD, ARM::VLD3q32_UPD, true, true, EvenDblSpc, 3, 2 }, +{ ARM::VLD3q32oddPseudo, ARM::VLD3q32, true, false, OddDblSpc, 3, 2 }, +{ ARM::VLD3q32oddPseudo_UPD, ARM::VLD3q32_UPD, true, true, OddDblSpc, 3, 2 }, +{ ARM::VLD3q8Pseudo_UPD, ARM::VLD3q8_UPD, true, true, EvenDblSpc, 3, 8 }, +{ ARM::VLD3q8oddPseudo, ARM::VLD3q8, true, false, OddDblSpc, 3, 8 }, +{ ARM::VLD3q8oddPseudo_UPD, ARM::VLD3q8_UPD, true, true, OddDblSpc, 3, 8 }, + +{ ARM::VLD4DUPd16Pseudo, ARM::VLD4DUPd16, true, false, SingleSpc, 4, 4}, +{ ARM::VLD4DUPd16Pseudo_UPD, ARM::VLD4DUPd16_UPD, true, true, SingleSpc, 4, 4}, +{ ARM::VLD4DUPd32Pseudo, ARM::VLD4DUPd32, true, false, SingleSpc, 4, 2}, +{ ARM::VLD4DUPd32Pseudo_UPD, ARM::VLD4DUPd32_UPD, true, true, SingleSpc, 4, 2}, +{ ARM::VLD4DUPd8Pseudo, ARM::VLD4DUPd8, true, false, SingleSpc, 4, 8}, +{ ARM::VLD4DUPd8Pseudo_UPD, ARM::VLD4DUPd8_UPD, true, true, SingleSpc, 4, 8}, + +{ ARM::VLD4LNd16Pseudo, ARM::VLD4LNd16, true, false, SingleSpc, 4, 4 }, +{ ARM::VLD4LNd16Pseudo_UPD, ARM::VLD4LNd16_UPD, true, true, SingleSpc, 4, 4 }, +{ ARM::VLD4LNd32Pseudo, ARM::VLD4LNd32, true, false, SingleSpc, 4, 2 }, +{ ARM::VLD4LNd32Pseudo_UPD, ARM::VLD4LNd32_UPD, true, true, SingleSpc, 4, 2 }, +{ ARM::VLD4LNd8Pseudo, ARM::VLD4LNd8, true, false, SingleSpc, 4, 8 }, +{ ARM::VLD4LNd8Pseudo_UPD, ARM::VLD4LNd8_UPD, true, true, SingleSpc, 4, 8 }, +{ ARM::VLD4LNq16Pseudo, ARM::VLD4LNq16, true, false, EvenDblSpc, 4, 4 }, +{ ARM::VLD4LNq16Pseudo_UPD, ARM::VLD4LNq16_UPD, true, true, EvenDblSpc, 4, 4 }, +{ ARM::VLD4LNq32Pseudo, ARM::VLD4LNq32, true, false, EvenDblSpc, 4, 2 }, +{ ARM::VLD4LNq32Pseudo_UPD, ARM::VLD4LNq32_UPD, true, true, EvenDblSpc, 4, 2 }, + +{ ARM::VLD4d16Pseudo, ARM::VLD4d16, true, false, SingleSpc, 4, 4 }, +{ ARM::VLD4d16Pseudo_UPD, ARM::VLD4d16_UPD, true, true, SingleSpc, 4, 4 }, +{ ARM::VLD4d32Pseudo, ARM::VLD4d32, true, false, SingleSpc, 4, 2 }, +{ ARM::VLD4d32Pseudo_UPD, ARM::VLD4d32_UPD, true, true, SingleSpc, 4, 2 }, +{ ARM::VLD4d8Pseudo, ARM::VLD4d8, true, false, SingleSpc, 4, 8 }, +{ ARM::VLD4d8Pseudo_UPD, ARM::VLD4d8_UPD, true, true, SingleSpc, 4, 8 }, + +{ ARM::VLD4q16Pseudo_UPD, ARM::VLD4q16_UPD, true, true, EvenDblSpc, 4, 4 }, +{ ARM::VLD4q16oddPseudo, ARM::VLD4q16, true, false, OddDblSpc, 4, 4 }, +{ ARM::VLD4q16oddPseudo_UPD, ARM::VLD4q16_UPD, true, true, OddDblSpc, 4, 4 }, +{ ARM::VLD4q32Pseudo_UPD, ARM::VLD4q32_UPD, true, true, EvenDblSpc, 4, 2 }, +{ ARM::VLD4q32oddPseudo, ARM::VLD4q32, true, false, OddDblSpc, 4, 2 }, +{ ARM::VLD4q32oddPseudo_UPD, ARM::VLD4q32_UPD, true, true, OddDblSpc, 4, 2 }, +{ ARM::VLD4q8Pseudo_UPD, ARM::VLD4q8_UPD, true, true, EvenDblSpc, 4, 8 }, +{ ARM::VLD4q8oddPseudo, ARM::VLD4q8, true, false, OddDblSpc, 4, 8 }, +{ ARM::VLD4q8oddPseudo_UPD, ARM::VLD4q8_UPD, true, true, OddDblSpc, 4, 8 }, + +{ ARM::VST1LNq16Pseudo, ARM::VST1LNd16, false, false, EvenDblSpc, 1, 4 }, +{ ARM::VST1LNq16Pseudo_UPD, ARM::VST1LNd16_UPD,false, true, EvenDblSpc, 1, 4 }, +{ ARM::VST1LNq32Pseudo, ARM::VST1LNd32, false, false, EvenDblSpc, 1, 2 }, +{ ARM::VST1LNq32Pseudo_UPD, ARM::VST1LNd32_UPD,false, true, EvenDblSpc, 1, 2 }, +{ ARM::VST1LNq8Pseudo, ARM::VST1LNd8, false, false, EvenDblSpc, 1, 8 }, +{ ARM::VST1LNq8Pseudo_UPD, ARM::VST1LNd8_UPD, false, true, EvenDblSpc, 1, 8 }, + +{ ARM::VST1d64QPseudo, ARM::VST1d64Q, false, false, SingleSpc, 4, 1 }, +{ ARM::VST1d64QPseudo_UPD, ARM::VST1d64Q_UPD, false, true, SingleSpc, 4, 1 }, +{ ARM::VST1d64TPseudo, ARM::VST1d64T, false, false, SingleSpc, 3, 1 }, +{ ARM::VST1d64TPseudo_UPD, ARM::VST1d64T_UPD, false, true, SingleSpc, 3, 1 }, + +{ ARM::VST1q16Pseudo, ARM::VST1q16, false, false, SingleSpc, 2, 4 }, +{ ARM::VST1q16Pseudo_UPD, ARM::VST1q16_UPD, false, true, SingleSpc, 2, 4 }, +{ ARM::VST1q32Pseudo, ARM::VST1q32, false, false, SingleSpc, 2, 2 }, +{ ARM::VST1q32Pseudo_UPD, ARM::VST1q32_UPD, false, true, SingleSpc, 2, 2 }, +{ ARM::VST1q64Pseudo, ARM::VST1q64, false, false, SingleSpc, 2, 1 }, +{ ARM::VST1q64Pseudo_UPD, ARM::VST1q64_UPD, false, true, SingleSpc, 2, 1 }, +{ ARM::VST1q8Pseudo, ARM::VST1q8, false, false, SingleSpc, 2, 8 }, +{ ARM::VST1q8Pseudo_UPD, ARM::VST1q8_UPD, false, true, SingleSpc, 2, 8 }, + +{ ARM::VST2LNd16Pseudo, ARM::VST2LNd16, false, false, SingleSpc, 2, 4 }, +{ ARM::VST2LNd16Pseudo_UPD, ARM::VST2LNd16_UPD, false, true, SingleSpc, 2, 4 }, +{ ARM::VST2LNd32Pseudo, ARM::VST2LNd32, false, false, SingleSpc, 2, 2 }, +{ ARM::VST2LNd32Pseudo_UPD, ARM::VST2LNd32_UPD, false, true, SingleSpc, 2, 2 }, +{ ARM::VST2LNd8Pseudo, ARM::VST2LNd8, false, false, SingleSpc, 2, 8 }, +{ ARM::VST2LNd8Pseudo_UPD, ARM::VST2LNd8_UPD, false, true, SingleSpc, 2, 8 }, +{ ARM::VST2LNq16Pseudo, ARM::VST2LNq16, false, false, EvenDblSpc, 2, 4}, +{ ARM::VST2LNq16Pseudo_UPD, ARM::VST2LNq16_UPD, false, true, EvenDblSpc, 2, 4}, +{ ARM::VST2LNq32Pseudo, ARM::VST2LNq32, false, false, EvenDblSpc, 2, 2}, +{ ARM::VST2LNq32Pseudo_UPD, ARM::VST2LNq32_UPD, false, true, EvenDblSpc, 2, 2}, + +{ ARM::VST2d16Pseudo, ARM::VST2d16, false, false, SingleSpc, 2, 4 }, +{ ARM::VST2d16Pseudo_UPD, ARM::VST2d16_UPD, false, true, SingleSpc, 2, 4 }, +{ ARM::VST2d32Pseudo, ARM::VST2d32, false, false, SingleSpc, 2, 2 }, +{ ARM::VST2d32Pseudo_UPD, ARM::VST2d32_UPD, false, true, SingleSpc, 2, 2 }, +{ ARM::VST2d8Pseudo, ARM::VST2d8, false, false, SingleSpc, 2, 8 }, +{ ARM::VST2d8Pseudo_UPD, ARM::VST2d8_UPD, false, true, SingleSpc, 2, 8 }, + +{ ARM::VST2q16Pseudo, ARM::VST2q16, false, false, SingleSpc, 4, 4 }, +{ ARM::VST2q16Pseudo_UPD, ARM::VST2q16_UPD, false, true, SingleSpc, 4, 4 }, +{ ARM::VST2q32Pseudo, ARM::VST2q32, false, false, SingleSpc, 4, 2 }, +{ ARM::VST2q32Pseudo_UPD, ARM::VST2q32_UPD, false, true, SingleSpc, 4, 2 }, +{ ARM::VST2q8Pseudo, ARM::VST2q8, false, false, SingleSpc, 4, 8 }, +{ ARM::VST2q8Pseudo_UPD, ARM::VST2q8_UPD, false, true, SingleSpc, 4, 8 }, + +{ ARM::VST3LNd16Pseudo, ARM::VST3LNd16, false, false, SingleSpc, 3, 4 }, +{ ARM::VST3LNd16Pseudo_UPD, ARM::VST3LNd16_UPD, false, true, SingleSpc, 3, 4 }, +{ ARM::VST3LNd32Pseudo, ARM::VST3LNd32, false, false, SingleSpc, 3, 2 }, +{ ARM::VST3LNd32Pseudo_UPD, ARM::VST3LNd32_UPD, false, true, SingleSpc, 3, 2 }, +{ ARM::VST3LNd8Pseudo, ARM::VST3LNd8, false, false, SingleSpc, 3, 8 }, +{ ARM::VST3LNd8Pseudo_UPD, ARM::VST3LNd8_UPD, false, true, SingleSpc, 3, 8 }, +{ ARM::VST3LNq16Pseudo, ARM::VST3LNq16, false, false, EvenDblSpc, 3, 4}, +{ ARM::VST3LNq16Pseudo_UPD, ARM::VST3LNq16_UPD, false, true, EvenDblSpc, 3, 4}, +{ ARM::VST3LNq32Pseudo, ARM::VST3LNq32, false, false, EvenDblSpc, 3, 2}, +{ ARM::VST3LNq32Pseudo_UPD, ARM::VST3LNq32_UPD, false, true, EvenDblSpc, 3, 2}, + +{ ARM::VST3d16Pseudo, ARM::VST3d16, false, false, SingleSpc, 3, 4 }, +{ ARM::VST3d16Pseudo_UPD, ARM::VST3d16_UPD, false, true, SingleSpc, 3, 4 }, +{ ARM::VST3d32Pseudo, ARM::VST3d32, false, false, SingleSpc, 3, 2 }, +{ ARM::VST3d32Pseudo_UPD, ARM::VST3d32_UPD, false, true, SingleSpc, 3, 2 }, +{ ARM::VST3d8Pseudo, ARM::VST3d8, false, false, SingleSpc, 3, 8 }, +{ ARM::VST3d8Pseudo_UPD, ARM::VST3d8_UPD, false, true, SingleSpc, 3, 8 }, + +{ ARM::VST3q16Pseudo_UPD, ARM::VST3q16_UPD, false, true, EvenDblSpc, 3, 4 }, +{ ARM::VST3q16oddPseudo, ARM::VST3q16, false, false, OddDblSpc, 3, 4 }, +{ ARM::VST3q16oddPseudo_UPD, ARM::VST3q16_UPD, false, true, OddDblSpc, 3, 4 }, +{ ARM::VST3q32Pseudo_UPD, ARM::VST3q32_UPD, false, true, EvenDblSpc, 3, 2 }, +{ ARM::VST3q32oddPseudo, ARM::VST3q32, false, false, OddDblSpc, 3, 2 }, +{ ARM::VST3q32oddPseudo_UPD, ARM::VST3q32_UPD, false, true, OddDblSpc, 3, 2 }, +{ ARM::VST3q8Pseudo_UPD, ARM::VST3q8_UPD, false, true, EvenDblSpc, 3, 8 }, +{ ARM::VST3q8oddPseudo, ARM::VST3q8, false, false, OddDblSpc, 3, 8 }, +{ ARM::VST3q8oddPseudo_UPD, ARM::VST3q8_UPD, false, true, OddDblSpc, 3, 8 }, + +{ ARM::VST4LNd16Pseudo, ARM::VST4LNd16, false, false, SingleSpc, 4, 4 }, +{ ARM::VST4LNd16Pseudo_UPD, ARM::VST4LNd16_UPD, false, true, SingleSpc, 4, 4 }, +{ ARM::VST4LNd32Pseudo, ARM::VST4LNd32, false, false, SingleSpc, 4, 2 }, +{ ARM::VST4LNd32Pseudo_UPD, ARM::VST4LNd32_UPD, false, true, SingleSpc, 4, 2 }, +{ ARM::VST4LNd8Pseudo, ARM::VST4LNd8, false, false, SingleSpc, 4, 8 }, +{ ARM::VST4LNd8Pseudo_UPD, ARM::VST4LNd8_UPD, false, true, SingleSpc, 4, 8 }, +{ ARM::VST4LNq16Pseudo, ARM::VST4LNq16, false, false, EvenDblSpc, 4, 4}, +{ ARM::VST4LNq16Pseudo_UPD, ARM::VST4LNq16_UPD, false, true, EvenDblSpc, 4, 4}, +{ ARM::VST4LNq32Pseudo, ARM::VST4LNq32, false, false, EvenDblSpc, 4, 2}, +{ ARM::VST4LNq32Pseudo_UPD, ARM::VST4LNq32_UPD, false, true, EvenDblSpc, 4, 2}, + +{ ARM::VST4d16Pseudo, ARM::VST4d16, false, false, SingleSpc, 4, 4 }, +{ ARM::VST4d16Pseudo_UPD, ARM::VST4d16_UPD, false, true, SingleSpc, 4, 4 }, +{ ARM::VST4d32Pseudo, ARM::VST4d32, false, false, SingleSpc, 4, 2 }, +{ ARM::VST4d32Pseudo_UPD, ARM::VST4d32_UPD, false, true, SingleSpc, 4, 2 }, +{ ARM::VST4d8Pseudo, ARM::VST4d8, false, false, SingleSpc, 4, 8 }, +{ ARM::VST4d8Pseudo_UPD, ARM::VST4d8_UPD, false, true, SingleSpc, 4, 8 }, + +{ ARM::VST4q16Pseudo_UPD, ARM::VST4q16_UPD, false, true, EvenDblSpc, 4, 4 }, +{ ARM::VST4q16oddPseudo, ARM::VST4q16, false, false, OddDblSpc, 4, 4 }, +{ ARM::VST4q16oddPseudo_UPD, ARM::VST4q16_UPD, false, true, OddDblSpc, 4, 4 }, +{ ARM::VST4q32Pseudo_UPD, ARM::VST4q32_UPD, false, true, EvenDblSpc, 4, 2 }, +{ ARM::VST4q32oddPseudo, ARM::VST4q32, false, false, OddDblSpc, 4, 2 }, +{ ARM::VST4q32oddPseudo_UPD, ARM::VST4q32_UPD, false, true, OddDblSpc, 4, 2 }, +{ ARM::VST4q8Pseudo_UPD, ARM::VST4q8_UPD, false, true, EvenDblSpc, 4, 8 }, +{ ARM::VST4q8oddPseudo, ARM::VST4q8, false, false, OddDblSpc, 4, 8 }, +{ ARM::VST4q8oddPseudo_UPD, ARM::VST4q8_UPD, false, true, OddDblSpc, 4, 8 } +}; + +/// LookupNEONLdSt - Search the NEONLdStTable for information about a NEON +/// load or store pseudo instruction. +static const NEONLdStTableEntry *LookupNEONLdSt(unsigned Opcode) { + unsigned NumEntries = array_lengthof(NEONLdStTable); + +#ifndef NDEBUG + // Make sure the table is sorted. + static bool TableChecked = false; + if (!TableChecked) { + for (unsigned i = 0; i != NumEntries-1; ++i) + assert(NEONLdStTable[i] < NEONLdStTable[i+1] && + "NEONLdStTable is not sorted!"); + TableChecked = true; + } +#endif + + const NEONLdStTableEntry *I = + std::lower_bound(NEONLdStTable, NEONLdStTable + NumEntries, Opcode); + if (I != NEONLdStTable + NumEntries && I->PseudoOpc == Opcode) + return I; + return NULL; +} + +/// GetDSubRegs - Get 4 D subregisters of a Q, QQ, or QQQQ register, +/// corresponding to the specified register spacing. Not all of the results +/// are necessarily valid, e.g., a Q register only has 2 D subregisters. +static void GetDSubRegs(unsigned Reg, NEONRegSpacing RegSpc, + const TargetRegisterInfo *TRI, unsigned &D0, + unsigned &D1, unsigned &D2, unsigned &D3) { + if (RegSpc == SingleSpc) { + D0 = TRI->getSubReg(Reg, ARM::dsub_0); + D1 = TRI->getSubReg(Reg, ARM::dsub_1); + D2 = TRI->getSubReg(Reg, ARM::dsub_2); + D3 = TRI->getSubReg(Reg, ARM::dsub_3); + } else if (RegSpc == EvenDblSpc) { + D0 = TRI->getSubReg(Reg, ARM::dsub_0); + D1 = TRI->getSubReg(Reg, ARM::dsub_2); + D2 = TRI->getSubReg(Reg, ARM::dsub_4); + D3 = TRI->getSubReg(Reg, ARM::dsub_6); + } else { + assert(RegSpc == OddDblSpc && "unknown register spacing"); + D0 = TRI->getSubReg(Reg, ARM::dsub_1); + D1 = TRI->getSubReg(Reg, ARM::dsub_3); + D2 = TRI->getSubReg(Reg, ARM::dsub_5); + D3 = TRI->getSubReg(Reg, ARM::dsub_7); } } /// ExpandVLD - Translate VLD pseudo instructions with Q, QQ or QQQQ register /// operands to real VLD instructions with D register operands. -void ARMExpandPseudo::ExpandVLD(MachineBasicBlock::iterator &MBBI, - unsigned Opc, bool hasWriteBack, - NEONRegSpacing RegSpc, unsigned NumRegs) { +void ARMExpandPseudo::ExpandVLD(MachineBasicBlock::iterator &MBBI) { MachineInstr &MI = *MBBI; MachineBasicBlock &MBB = *MI.getParent(); - MachineInstrBuilder MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(Opc)); + const NEONLdStTableEntry *TableEntry = LookupNEONLdSt(MI.getOpcode()); + assert(TableEntry && TableEntry->IsLoad && "NEONLdStTable lookup failed"); + NEONRegSpacing RegSpc = TableEntry->RegSpacing; + unsigned NumRegs = TableEntry->NumRegs; + + MachineInstrBuilder MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(), + TII->get(TableEntry->RealOpc)); unsigned OpIdx = 0; bool DstIsDead = MI.getOperand(OpIdx).isDead(); unsigned DstReg = MI.getOperand(OpIdx++).getReg(); unsigned D0, D1, D2, D3; - if (RegSpc == SingleSpc) { - D0 = TRI->getSubReg(DstReg, ARM::dsub_0); - D1 = TRI->getSubReg(DstReg, ARM::dsub_1); - D2 = TRI->getSubReg(DstReg, ARM::dsub_2); - D3 = TRI->getSubReg(DstReg, ARM::dsub_3); - } else if (RegSpc == EvenDblSpc) { - D0 = TRI->getSubReg(DstReg, ARM::dsub_0); - D1 = TRI->getSubReg(DstReg, ARM::dsub_2); - D2 = TRI->getSubReg(DstReg, ARM::dsub_4); - D3 = TRI->getSubReg(DstReg, ARM::dsub_6); - } else { - assert(RegSpc == OddDblSpc && "unknown register spacing for VLD"); - D0 = TRI->getSubReg(DstReg, ARM::dsub_1); - D1 = TRI->getSubReg(DstReg, ARM::dsub_3); - D2 = TRI->getSubReg(DstReg, ARM::dsub_5); - D3 = TRI->getSubReg(DstReg, ARM::dsub_7); - } + GetDSubRegs(DstReg, RegSpc, TRI, D0, D1, D2, D3); MIB.addReg(D0, RegState::Define | getDeadRegState(DstIsDead)) .addReg(D1, RegState::Define | getDeadRegState(DstIsDead)); if (NumRegs > 2) @@ -112,107 +424,373 @@ void ARMExpandPseudo::ExpandVLD(MachineBasicBlock::iterator &MBBI, if (NumRegs > 3) MIB.addReg(D3, RegState::Define | getDeadRegState(DstIsDead)); - if (hasWriteBack) { - bool WBIsDead = MI.getOperand(OpIdx).isDead(); - unsigned WBReg = MI.getOperand(OpIdx++).getReg(); - MIB.addReg(WBReg, RegState::Define | getDeadRegState(WBIsDead)); - } + if (TableEntry->HasWriteBack) + MIB.addOperand(MI.getOperand(OpIdx++)); + // Copy the addrmode6 operands. - bool AddrIsKill = MI.getOperand(OpIdx).isKill(); - MIB.addReg(MI.getOperand(OpIdx++).getReg(), getKillRegState(AddrIsKill)); - MIB.addImm(MI.getOperand(OpIdx++).getImm()); - if (hasWriteBack) { - // Copy the am6offset operand. - bool OffsetIsKill = MI.getOperand(OpIdx).isKill(); - MIB.addReg(MI.getOperand(OpIdx++).getReg(), getKillRegState(OffsetIsKill)); - } + MIB.addOperand(MI.getOperand(OpIdx++)); + MIB.addOperand(MI.getOperand(OpIdx++)); + // Copy the am6offset operand. + if (TableEntry->HasWriteBack) + MIB.addOperand(MI.getOperand(OpIdx++)); - MIB = AddDefaultPred(MIB); - TransferImpOps(MI, MIB, MIB); - // For an instruction writing the odd subregs, add an implicit use of the - // super-register because the even subregs were loaded separately. - if (RegSpc == OddDblSpc) - MIB.addReg(DstReg, RegState::Implicit); + // For an instruction writing double-spaced subregs, the pseudo instruction + // has an extra operand that is a use of the super-register. Record the + // operand index and skip over it. + unsigned SrcOpIdx = 0; + if (RegSpc == EvenDblSpc || RegSpc == OddDblSpc) + SrcOpIdx = OpIdx++; + + // Copy the predicate operands. + MIB.addOperand(MI.getOperand(OpIdx++)); + MIB.addOperand(MI.getOperand(OpIdx++)); + + // Copy the super-register source operand used for double-spaced subregs over + // to the new instruction as an implicit operand. + if (SrcOpIdx != 0) { + MachineOperand MO = MI.getOperand(SrcOpIdx); + MO.setImplicit(true); + MIB.addOperand(MO); + } // Add an implicit def for the super-register. MIB.addReg(DstReg, RegState::ImplicitDefine | getDeadRegState(DstIsDead)); + TransferImpOps(MI, MIB, MIB); MI.eraseFromParent(); } /// ExpandVST - Translate VST pseudo instructions with Q, QQ or QQQQ register /// operands to real VST instructions with D register operands. -void ARMExpandPseudo::ExpandVST(MachineBasicBlock::iterator &MBBI, - unsigned Opc, bool hasWriteBack, - NEONRegSpacing RegSpc, unsigned NumRegs) { +void ARMExpandPseudo::ExpandVST(MachineBasicBlock::iterator &MBBI) { MachineInstr &MI = *MBBI; MachineBasicBlock &MBB = *MI.getParent(); - MachineInstrBuilder MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(Opc)); + const NEONLdStTableEntry *TableEntry = LookupNEONLdSt(MI.getOpcode()); + assert(TableEntry && !TableEntry->IsLoad && "NEONLdStTable lookup failed"); + NEONRegSpacing RegSpc = TableEntry->RegSpacing; + unsigned NumRegs = TableEntry->NumRegs; + + MachineInstrBuilder MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(), + TII->get(TableEntry->RealOpc)); unsigned OpIdx = 0; - if (hasWriteBack) { - bool DstIsDead = MI.getOperand(OpIdx).isDead(); - unsigned DstReg = MI.getOperand(OpIdx++).getReg(); - MIB.addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead)); - } + if (TableEntry->HasWriteBack) + MIB.addOperand(MI.getOperand(OpIdx++)); + // Copy the addrmode6 operands. - bool AddrIsKill = MI.getOperand(OpIdx).isKill(); - MIB.addReg(MI.getOperand(OpIdx++).getReg(), getKillRegState(AddrIsKill)); - MIB.addImm(MI.getOperand(OpIdx++).getImm()); - if (hasWriteBack) { - // Copy the am6offset operand. - bool OffsetIsKill = MI.getOperand(OpIdx).isKill(); - MIB.addReg(MI.getOperand(OpIdx++).getReg(), getKillRegState(OffsetIsKill)); - } + MIB.addOperand(MI.getOperand(OpIdx++)); + MIB.addOperand(MI.getOperand(OpIdx++)); + // Copy the am6offset operand. + if (TableEntry->HasWriteBack) + MIB.addOperand(MI.getOperand(OpIdx++)); bool SrcIsKill = MI.getOperand(OpIdx).isKill(); - unsigned SrcReg = MI.getOperand(OpIdx).getReg(); + unsigned SrcReg = MI.getOperand(OpIdx++).getReg(); unsigned D0, D1, D2, D3; - if (RegSpc == SingleSpc) { - D0 = TRI->getSubReg(SrcReg, ARM::dsub_0); - D1 = TRI->getSubReg(SrcReg, ARM::dsub_1); - D2 = TRI->getSubReg(SrcReg, ARM::dsub_2); - D3 = TRI->getSubReg(SrcReg, ARM::dsub_3); - } else if (RegSpc == EvenDblSpc) { - D0 = TRI->getSubReg(SrcReg, ARM::dsub_0); - D1 = TRI->getSubReg(SrcReg, ARM::dsub_2); - D2 = TRI->getSubReg(SrcReg, ARM::dsub_4); - D3 = TRI->getSubReg(SrcReg, ARM::dsub_6); - } else { - assert(RegSpc == OddDblSpc && "unknown register spacing for VST"); - D0 = TRI->getSubReg(SrcReg, ARM::dsub_1); - D1 = TRI->getSubReg(SrcReg, ARM::dsub_3); - D2 = TRI->getSubReg(SrcReg, ARM::dsub_5); - D3 = TRI->getSubReg(SrcReg, ARM::dsub_7); - } - + GetDSubRegs(SrcReg, RegSpc, TRI, D0, D1, D2, D3); MIB.addReg(D0).addReg(D1); if (NumRegs > 2) MIB.addReg(D2); if (NumRegs > 3) MIB.addReg(D3); - MIB = AddDefaultPred(MIB); + + // Copy the predicate operands. + MIB.addOperand(MI.getOperand(OpIdx++)); + MIB.addOperand(MI.getOperand(OpIdx++)); + + if (SrcIsKill) + // Add an implicit kill for the super-reg. + (*MIB).addRegisterKilled(SrcReg, TRI, true); + TransferImpOps(MI, MIB, MIB); + MI.eraseFromParent(); +} + +/// ExpandLaneOp - Translate VLD*LN and VST*LN instructions with Q, QQ or QQQQ +/// register operands to real instructions with D register operands. +void ARMExpandPseudo::ExpandLaneOp(MachineBasicBlock::iterator &MBBI) { + MachineInstr &MI = *MBBI; + MachineBasicBlock &MBB = *MI.getParent(); + + const NEONLdStTableEntry *TableEntry = LookupNEONLdSt(MI.getOpcode()); + assert(TableEntry && "NEONLdStTable lookup failed"); + NEONRegSpacing RegSpc = TableEntry->RegSpacing; + unsigned NumRegs = TableEntry->NumRegs; + unsigned RegElts = TableEntry->RegElts; + + MachineInstrBuilder MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(), + TII->get(TableEntry->RealOpc)); + unsigned OpIdx = 0; + // The lane operand is always the 3rd from last operand, before the 2 + // predicate operands. + unsigned Lane = MI.getOperand(MI.getDesc().getNumOperands() - 3).getImm(); + + // Adjust the lane and spacing as needed for Q registers. + assert(RegSpc != OddDblSpc && "unexpected register spacing for VLD/VST-lane"); + if (RegSpc == EvenDblSpc && Lane >= RegElts) { + RegSpc = OddDblSpc; + Lane -= RegElts; + } + assert(Lane < RegElts && "out of range lane for VLD/VST-lane"); + + unsigned D0 = 0, D1 = 0, D2 = 0, D3 = 0; + unsigned DstReg = 0; + bool DstIsDead = false; + if (TableEntry->IsLoad) { + DstIsDead = MI.getOperand(OpIdx).isDead(); + DstReg = MI.getOperand(OpIdx++).getReg(); + GetDSubRegs(DstReg, RegSpc, TRI, D0, D1, D2, D3); + MIB.addReg(D0, RegState::Define | getDeadRegState(DstIsDead)); + if (NumRegs > 1) + MIB.addReg(D1, RegState::Define | getDeadRegState(DstIsDead)); + if (NumRegs > 2) + MIB.addReg(D2, RegState::Define | getDeadRegState(DstIsDead)); + if (NumRegs > 3) + MIB.addReg(D3, RegState::Define | getDeadRegState(DstIsDead)); + } + + if (TableEntry->HasWriteBack) + MIB.addOperand(MI.getOperand(OpIdx++)); + + // Copy the addrmode6 operands. + MIB.addOperand(MI.getOperand(OpIdx++)); + MIB.addOperand(MI.getOperand(OpIdx++)); + // Copy the am6offset operand. + if (TableEntry->HasWriteBack) + MIB.addOperand(MI.getOperand(OpIdx++)); + + // Grab the super-register source. + MachineOperand MO = MI.getOperand(OpIdx++); + if (!TableEntry->IsLoad) + GetDSubRegs(MO.getReg(), RegSpc, TRI, D0, D1, D2, D3); + + // Add the subregs as sources of the new instruction. + unsigned SrcFlags = (getUndefRegState(MO.isUndef()) | + getKillRegState(MO.isKill())); + MIB.addReg(D0, SrcFlags); + if (NumRegs > 1) + MIB.addReg(D1, SrcFlags); + if (NumRegs > 2) + MIB.addReg(D2, SrcFlags); + if (NumRegs > 3) + MIB.addReg(D3, SrcFlags); + + // Add the lane number operand. + MIB.addImm(Lane); + OpIdx += 1; + + // Copy the predicate operands. + MIB.addOperand(MI.getOperand(OpIdx++)); + MIB.addOperand(MI.getOperand(OpIdx++)); + + // Copy the super-register source to be an implicit source. + MO.setImplicit(true); + MIB.addOperand(MO); + if (TableEntry->IsLoad) + // Add an implicit def for the super-register. + MIB.addReg(DstReg, RegState::ImplicitDefine | getDeadRegState(DstIsDead)); TransferImpOps(MI, MIB, MIB); + MI.eraseFromParent(); +} + +/// ExpandVTBL - Translate VTBL and VTBX pseudo instructions with Q or QQ +/// register operands to real instructions with D register operands. +void ARMExpandPseudo::ExpandVTBL(MachineBasicBlock::iterator &MBBI, + unsigned Opc, bool IsExt, unsigned NumRegs) { + MachineInstr &MI = *MBBI; + MachineBasicBlock &MBB = *MI.getParent(); + + MachineInstrBuilder MIB = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(Opc)); + unsigned OpIdx = 0; + + // Transfer the destination register operand. + MIB.addOperand(MI.getOperand(OpIdx++)); + if (IsExt) + MIB.addOperand(MI.getOperand(OpIdx++)); + + bool SrcIsKill = MI.getOperand(OpIdx).isKill(); + unsigned SrcReg = MI.getOperand(OpIdx++).getReg(); + unsigned D0, D1, D2, D3; + GetDSubRegs(SrcReg, SingleSpc, TRI, D0, D1, D2, D3); + MIB.addReg(D0).addReg(D1); + if (NumRegs > 2) + MIB.addReg(D2); + if (NumRegs > 3) + MIB.addReg(D3); + + // Copy the other source register operand. + MIB.addOperand(MI.getOperand(OpIdx++)); + + // Copy the predicate operands. + MIB.addOperand(MI.getOperand(OpIdx++)); + MIB.addOperand(MI.getOperand(OpIdx++)); + if (SrcIsKill) // Add an implicit kill for the super-reg. (*MIB).addRegisterKilled(SrcReg, TRI, true); + TransferImpOps(MI, MIB, MIB); MI.eraseFromParent(); } -bool ARMExpandPseudo::ExpandMBB(MachineBasicBlock &MBB) { - bool Modified = false; +void ARMExpandPseudo::ExpandMOV32BitImm(MachineBasicBlock &MBB, + MachineBasicBlock::iterator &MBBI) { + MachineInstr &MI = *MBBI; + unsigned Opcode = MI.getOpcode(); + unsigned PredReg = 0; + ARMCC::CondCodes Pred = llvm::getInstrPredicate(&MI, PredReg); + unsigned DstReg = MI.getOperand(0).getReg(); + bool DstIsDead = MI.getOperand(0).isDead(); + bool isCC = Opcode == ARM::MOVCCi32imm || Opcode == ARM::t2MOVCCi32imm; + const MachineOperand &MO = MI.getOperand(isCC ? 2 : 1); + MachineInstrBuilder LO16, HI16; - MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); - while (MBBI != E) { - MachineInstr &MI = *MBBI; - MachineBasicBlock::iterator NMBBI = llvm::next(MBBI); + if (!STI->hasV6T2Ops() && + (Opcode == ARM::MOVi32imm || Opcode == ARM::MOVCCi32imm)) { + // Expand into a movi + orr. + LO16 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::MOVi), DstReg); + HI16 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::ORRri)) + .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead)) + .addReg(DstReg); + + assert (MO.isImm() && "MOVi32imm w/ non-immediate source operand!"); + unsigned ImmVal = (unsigned)MO.getImm(); + unsigned SOImmValV1 = ARM_AM::getSOImmTwoPartFirst(ImmVal); + unsigned SOImmValV2 = ARM_AM::getSOImmTwoPartSecond(ImmVal); + LO16 = LO16.addImm(SOImmValV1); + HI16 = HI16.addImm(SOImmValV2); + (*LO16).setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); + (*HI16).setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); + LO16.addImm(Pred).addReg(PredReg).addReg(0); + HI16.addImm(Pred).addReg(PredReg).addReg(0); + TransferImpOps(MI, LO16, HI16); + MI.eraseFromParent(); + return; + } + + unsigned LO16Opc = 0; + unsigned HI16Opc = 0; + if (Opcode == ARM::t2MOVi32imm || Opcode == ARM::t2MOVCCi32imm) { + LO16Opc = ARM::t2MOVi16; + HI16Opc = ARM::t2MOVTi16; + } else { + LO16Opc = ARM::MOVi16; + HI16Opc = ARM::MOVTi16; + } - bool ModifiedOp = true; - unsigned Opcode = MI.getOpcode(); - switch (Opcode) { + LO16 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(LO16Opc), DstReg); + HI16 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(HI16Opc)) + .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead)) + .addReg(DstReg); + + if (MO.isImm()) { + unsigned Imm = MO.getImm(); + unsigned Lo16 = Imm & 0xffff; + unsigned Hi16 = (Imm >> 16) & 0xffff; + LO16 = LO16.addImm(Lo16); + HI16 = HI16.addImm(Hi16); + } else { + const GlobalValue *GV = MO.getGlobal(); + unsigned TF = MO.getTargetFlags(); + LO16 = LO16.addGlobalAddress(GV, MO.getOffset(), TF | ARMII::MO_LO16); + HI16 = HI16.addGlobalAddress(GV, MO.getOffset(), TF | ARMII::MO_HI16); + } + + (*LO16).setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); + (*HI16).setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); + LO16.addImm(Pred).addReg(PredReg); + HI16.addImm(Pred).addReg(PredReg); + + TransferImpOps(MI, LO16, HI16); + MI.eraseFromParent(); +} + +bool ARMExpandPseudo::ExpandMI(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MBBI) { + MachineInstr &MI = *MBBI; + unsigned Opcode = MI.getOpcode(); + switch (Opcode) { default: - ModifiedOp = false; - break; + return false; + case ARM::Int_eh_sjlj_dispatchsetup: { + MachineFunction &MF = *MI.getParent()->getParent(); + const ARMBaseInstrInfo *AII = + static_cast(TII); + const ARMBaseRegisterInfo &RI = AII->getRegisterInfo(); + // For functions using a base pointer, we rematerialize it (via the frame + // pointer) here since eh.sjlj.setjmp and eh.sjlj.longjmp don't do it + // for us. Otherwise, expand to nothing. + if (RI.hasBasePointer(MF)) { + int32_t NumBytes = AFI->getFramePtrSpillOffset(); + unsigned FramePtr = RI.getFrameRegister(MF); + assert(MF.getTarget().getFrameLowering()->hasFP(MF) && + "base pointer without frame pointer?"); + + if (AFI->isThumb2Function()) { + llvm::emitT2RegPlusImmediate(MBB, MBBI, MI.getDebugLoc(), ARM::R6, + FramePtr, -NumBytes, ARMCC::AL, 0, *TII); + } else if (AFI->isThumbFunction()) { + llvm::emitThumbRegPlusImmediate(MBB, MBBI, ARM::R6, + FramePtr, -NumBytes, + *TII, RI, MI.getDebugLoc()); + } else { + llvm::emitARMRegPlusImmediate(MBB, MBBI, MI.getDebugLoc(), ARM::R6, + FramePtr, -NumBytes, ARMCC::AL, 0, + *TII); + } + // If there's dynamic realignment, adjust for it. + if (RI.needsStackRealignment(MF)) { + MachineFrameInfo *MFI = MF.getFrameInfo(); + unsigned MaxAlign = MFI->getMaxAlignment(); + assert (!AFI->isThumb1OnlyFunction()); + // Emit bic r6, r6, MaxAlign + unsigned bicOpc = AFI->isThumbFunction() ? + ARM::t2BICri : ARM::BICri; + AddDefaultCC(AddDefaultPred(BuildMI(MBB, MBBI, MI.getDebugLoc(), + TII->get(bicOpc), ARM::R6) + .addReg(ARM::R6, RegState::Kill) + .addImm(MaxAlign-1))); + } + + } + MI.eraseFromParent(); + return true; + } - case ARM::tLDRpci_pic: + case ARM::MOVsrl_flag: + case ARM::MOVsra_flag: { + // These are just fancy MOVs insructions. + AddDefaultPred(BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::MOVs), + MI.getOperand(0).getReg()) + .addOperand(MI.getOperand(1)) + .addReg(0) + .addImm(ARM_AM::getSORegOpc((Opcode == ARM::MOVsrl_flag ? ARM_AM::lsr + : ARM_AM::asr), 1))) + .addReg(ARM::CPSR, RegState::Define); + MI.eraseFromParent(); + return true; + } + case ARM::RRX: { + // This encodes as "MOVs Rd, Rm, rrx + MachineInstrBuilder MIB = + AddDefaultPred(BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::MOVs), + MI.getOperand(0).getReg()) + .addOperand(MI.getOperand(1)) + .addOperand(MI.getOperand(1)) + .addImm(ARM_AM::getSORegOpc(ARM_AM::rrx, 0))) + .addReg(0); + TransferImpOps(MI, MIB, MIB); + MI.eraseFromParent(); + return true; + } + case ARM::TPsoft: { + MachineInstrBuilder MIB = + BuildMI(MBB, MBBI, MI.getDebugLoc(), + TII->get(ARM::BL)) + .addExternalSymbol("__aeabi_read_tp", 0); + + (*MIB).setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); + TransferImpOps(MI, MIB, MIB); + MI.eraseFromParent(); + return true; + } + case ARM::tLDRpci_pic: case ARM::t2LDRpci_pic: { unsigned NewLdOpc = (Opcode == ARM::tLDRpci_pic) ? ARM::tLDRpci : ARM::t2LDRpci; @@ -225,54 +803,73 @@ bool ARMExpandPseudo::ExpandMBB(MachineBasicBlock &MBB) { (*MIB1).setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); MachineInstrBuilder MIB2 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::tPICADD)) - .addReg(DstReg, getDefRegState(true) | getDeadRegState(DstIsDead)) + .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead)) .addReg(DstReg) .addOperand(MI.getOperand(2)); TransferImpOps(MI, MIB1, MIB2); MI.eraseFromParent(); - break; + return true; } - case ARM::MOVi32imm: - case ARM::t2MOVi32imm: { - unsigned PredReg = 0; - ARMCC::CondCodes Pred = llvm::getInstrPredicate(&MI, PredReg); + case ARM::MOV_ga_dyn: + case ARM::MOV_ga_pcrel: + case ARM::MOV_ga_pcrel_ldr: + case ARM::t2MOV_ga_dyn: + case ARM::t2MOV_ga_pcrel: { + // Expand into movw + movw. Also "add pc" / ldr [pc] in PIC mode. + unsigned LabelId = AFI->createPICLabelUId(); unsigned DstReg = MI.getOperand(0).getReg(); bool DstIsDead = MI.getOperand(0).isDead(); - const MachineOperand &MO = MI.getOperand(1); - MachineInstrBuilder LO16, HI16; - - LO16 = BuildMI(MBB, MBBI, MI.getDebugLoc(), - TII->get(Opcode == ARM::MOVi32imm ? - ARM::MOVi16 : ARM::t2MOVi16), - DstReg); - HI16 = BuildMI(MBB, MBBI, MI.getDebugLoc(), - TII->get(Opcode == ARM::MOVi32imm ? - ARM::MOVTi16 : ARM::t2MOVTi16)) - .addReg(DstReg, getDefRegState(true) | getDeadRegState(DstIsDead)) - .addReg(DstReg); - - if (MO.isImm()) { - unsigned Imm = MO.getImm(); - unsigned Lo16 = Imm & 0xffff; - unsigned Hi16 = (Imm >> 16) & 0xffff; - LO16 = LO16.addImm(Lo16); - HI16 = HI16.addImm(Hi16); - } else { - const GlobalValue *GV = MO.getGlobal(); - unsigned TF = MO.getTargetFlags(); - LO16 = LO16.addGlobalAddress(GV, MO.getOffset(), TF | ARMII::MO_LO16); - HI16 = HI16.addGlobalAddress(GV, MO.getOffset(), TF | ARMII::MO_HI16); + const MachineOperand &MO1 = MI.getOperand(1); + const GlobalValue *GV = MO1.getGlobal(); + unsigned TF = MO1.getTargetFlags(); + bool isARM = Opcode != ARM::t2MOV_ga_pcrel; + bool isPIC = (Opcode != ARM::MOV_ga_dyn && Opcode != ARM::t2MOV_ga_dyn); + unsigned LO16Opc = isARM ? ARM::MOVi16_ga_pcrel : ARM::t2MOVi16_ga_pcrel; + unsigned HI16Opc = isARM ? ARM::MOVTi16_ga_pcrel : ARM::t2MOVTi16_ga_pcrel; + unsigned LO16TF = isPIC + ? ARMII::MO_LO16_NONLAZY_PIC : ARMII::MO_LO16_NONLAZY; + unsigned HI16TF = isPIC + ? ARMII::MO_HI16_NONLAZY_PIC : ARMII::MO_HI16_NONLAZY; + unsigned PICAddOpc = isARM + ? (Opcode == ARM::MOV_ga_pcrel_ldr ? ARM::PICLDR : ARM::PICADD) + : ARM::tPICADD; + MachineInstrBuilder MIB1 = BuildMI(MBB, MBBI, MI.getDebugLoc(), + TII->get(LO16Opc), DstReg) + .addGlobalAddress(GV, MO1.getOffset(), TF | LO16TF) + .addImm(LabelId); + MachineInstrBuilder MIB2 = BuildMI(MBB, MBBI, MI.getDebugLoc(), + TII->get(HI16Opc), DstReg) + .addReg(DstReg) + .addGlobalAddress(GV, MO1.getOffset(), TF | HI16TF) + .addImm(LabelId); + if (!isPIC) { + TransferImpOps(MI, MIB1, MIB2); + MI.eraseFromParent(); + return true; } - (*LO16).setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); - (*HI16).setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); - LO16.addImm(Pred).addReg(PredReg); - HI16.addImm(Pred).addReg(PredReg); - TransferImpOps(MI, LO16, HI16); + + MachineInstrBuilder MIB3 = BuildMI(MBB, MBBI, MI.getDebugLoc(), + TII->get(PICAddOpc)) + .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead)) + .addReg(DstReg).addImm(LabelId); + if (isARM) { + AddDefaultPred(MIB3); + if (Opcode == ARM::MOV_ga_pcrel_ldr) + (*MIB2).setMemRefs(MI.memoperands_begin(), MI.memoperands_end()); + } + TransferImpOps(MI, MIB1, MIB3); MI.eraseFromParent(); - break; + return true; } + case ARM::MOVi32imm: + case ARM::MOVCCi32imm: + case ARM::t2MOVi32imm: + case ARM::t2MOVCCi32imm: + ExpandMOV32BitImm(MBB, MBBI); + return true; + case ARM::VMOVQQ: { unsigned DstReg = MI.getOperand(0).getReg(); bool DstIsDead = MI.getOperand(0).isDead(); @@ -285,222 +882,339 @@ bool ARMExpandPseudo::ExpandMBB(MachineBasicBlock &MBB) { MachineInstrBuilder Even = AddDefaultPred(BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::VMOVQ)) - .addReg(EvenDst, - getDefRegState(true) | getDeadRegState(DstIsDead)) - .addReg(EvenSrc, getKillRegState(SrcIsKill))); + .addReg(EvenDst, + RegState::Define | getDeadRegState(DstIsDead)) + .addReg(EvenSrc, getKillRegState(SrcIsKill))); MachineInstrBuilder Odd = AddDefaultPred(BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::VMOVQ)) - .addReg(OddDst, - getDefRegState(true) | getDeadRegState(DstIsDead)) - .addReg(OddSrc, getKillRegState(SrcIsKill))); + .addReg(OddDst, + RegState::Define | getDeadRegState(DstIsDead)) + .addReg(OddSrc, getKillRegState(SrcIsKill))); TransferImpOps(MI, Even, Odd); MI.eraseFromParent(); + return true; + } + + case ARM::VLDMQIA: + case ARM::VLDMQDB: { + unsigned NewOpc = (Opcode == ARM::VLDMQIA) ? ARM::VLDMDIA : ARM::VLDMDDB; + MachineInstrBuilder MIB = + BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(NewOpc)); + unsigned OpIdx = 0; + + // Grab the Q register destination. + bool DstIsDead = MI.getOperand(OpIdx).isDead(); + unsigned DstReg = MI.getOperand(OpIdx++).getReg(); + + // Copy the source register. + MIB.addOperand(MI.getOperand(OpIdx++)); + + // Copy the predicate operands. + MIB.addOperand(MI.getOperand(OpIdx++)); + MIB.addOperand(MI.getOperand(OpIdx++)); + + // Add the destination operands (D subregs). + unsigned D0 = TRI->getSubReg(DstReg, ARM::dsub_0); + unsigned D1 = TRI->getSubReg(DstReg, ARM::dsub_1); + MIB.addReg(D0, RegState::Define | getDeadRegState(DstIsDead)) + .addReg(D1, RegState::Define | getDeadRegState(DstIsDead)); + + // Add an implicit def for the super-register. + MIB.addReg(DstReg, RegState::ImplicitDefine | getDeadRegState(DstIsDead)); + TransferImpOps(MI, MIB, MIB); + MI.eraseFromParent(); + return true; + } + + case ARM::VSTMQIA: + case ARM::VSTMQDB: { + unsigned NewOpc = (Opcode == ARM::VSTMQIA) ? ARM::VSTMDIA : ARM::VSTMDDB; + MachineInstrBuilder MIB = + BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(NewOpc)); + unsigned OpIdx = 0; + + // Grab the Q register source. + bool SrcIsKill = MI.getOperand(OpIdx).isKill(); + unsigned SrcReg = MI.getOperand(OpIdx++).getReg(); + + // Copy the destination register. + MIB.addOperand(MI.getOperand(OpIdx++)); + + // Copy the predicate operands. + MIB.addOperand(MI.getOperand(OpIdx++)); + MIB.addOperand(MI.getOperand(OpIdx++)); + + // Add the source operands (D subregs). + unsigned D0 = TRI->getSubReg(SrcReg, ARM::dsub_0); + unsigned D1 = TRI->getSubReg(SrcReg, ARM::dsub_1); + MIB.addReg(D0).addReg(D1); + + if (SrcIsKill) + // Add an implicit kill for the Q register. + (*MIB).addRegisterKilled(SrcReg, TRI, true); + + TransferImpOps(MI, MIB, MIB); + MI.eraseFromParent(); + return true; + } + case ARM::VDUPfqf: + case ARM::VDUPfdf:{ + unsigned NewOpc = Opcode == ARM::VDUPfqf ? ARM::VDUPLNfq : ARM::VDUPLNfd; + MachineInstrBuilder MIB = + BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(NewOpc)); + unsigned OpIdx = 0; + unsigned SrcReg = MI.getOperand(1).getReg(); + unsigned Lane = getARMRegisterNumbering(SrcReg) & 1; + unsigned DReg = TRI->getMatchingSuperReg(SrcReg, + Lane & 1 ? ARM::ssub_1 : ARM::ssub_0, &ARM::DPR_VFP2RegClass); + // The lane is [0,1] for the containing DReg superregister. + // Copy the dst/src register operands. + MIB.addOperand(MI.getOperand(OpIdx++)); + MIB.addReg(DReg); + ++OpIdx; + // Add the lane select operand. + MIB.addImm(Lane); + // Add the predicate operands. + MIB.addOperand(MI.getOperand(OpIdx++)); + MIB.addOperand(MI.getOperand(OpIdx++)); + + TransferImpOps(MI, MIB, MIB); + MI.eraseFromParent(); + return true; } case ARM::VLD1q8Pseudo: - ExpandVLD(MBBI, ARM::VLD1q8, false, SingleSpc, 2); break; case ARM::VLD1q16Pseudo: - ExpandVLD(MBBI, ARM::VLD1q16, false, SingleSpc, 2); break; case ARM::VLD1q32Pseudo: - ExpandVLD(MBBI, ARM::VLD1q32, false, SingleSpc, 2); break; case ARM::VLD1q64Pseudo: - ExpandVLD(MBBI, ARM::VLD1q64, false, SingleSpc, 2); break; case ARM::VLD1q8Pseudo_UPD: - ExpandVLD(MBBI, ARM::VLD1q8, true, SingleSpc, 2); break; case ARM::VLD1q16Pseudo_UPD: - ExpandVLD(MBBI, ARM::VLD1q16, true, SingleSpc, 2); break; case ARM::VLD1q32Pseudo_UPD: - ExpandVLD(MBBI, ARM::VLD1q32, true, SingleSpc, 2); break; case ARM::VLD1q64Pseudo_UPD: - ExpandVLD(MBBI, ARM::VLD1q64, true, SingleSpc, 2); break; - case ARM::VLD2d8Pseudo: - ExpandVLD(MBBI, ARM::VLD2d8, false, SingleSpc, 2); break; case ARM::VLD2d16Pseudo: - ExpandVLD(MBBI, ARM::VLD2d16, false, SingleSpc, 2); break; case ARM::VLD2d32Pseudo: - ExpandVLD(MBBI, ARM::VLD2d32, false, SingleSpc, 2); break; case ARM::VLD2q8Pseudo: - ExpandVLD(MBBI, ARM::VLD2q8, false, SingleSpc, 4); break; case ARM::VLD2q16Pseudo: - ExpandVLD(MBBI, ARM::VLD2q16, false, SingleSpc, 4); break; case ARM::VLD2q32Pseudo: - ExpandVLD(MBBI, ARM::VLD2q32, false, SingleSpc, 4); break; case ARM::VLD2d8Pseudo_UPD: - ExpandVLD(MBBI, ARM::VLD2d8, true, SingleSpc, 2); break; case ARM::VLD2d16Pseudo_UPD: - ExpandVLD(MBBI, ARM::VLD2d16, true, SingleSpc, 2); break; case ARM::VLD2d32Pseudo_UPD: - ExpandVLD(MBBI, ARM::VLD2d32, true, SingleSpc, 2); break; case ARM::VLD2q8Pseudo_UPD: - ExpandVLD(MBBI, ARM::VLD2q8, true, SingleSpc, 4); break; case ARM::VLD2q16Pseudo_UPD: - ExpandVLD(MBBI, ARM::VLD2q16, true, SingleSpc, 4); break; case ARM::VLD2q32Pseudo_UPD: - ExpandVLD(MBBI, ARM::VLD2q32, true, SingleSpc, 4); break; - case ARM::VLD3d8Pseudo: - ExpandVLD(MBBI, ARM::VLD3d8, false, SingleSpc, 3); break; case ARM::VLD3d16Pseudo: - ExpandVLD(MBBI, ARM::VLD3d16, false, SingleSpc, 3); break; case ARM::VLD3d32Pseudo: - ExpandVLD(MBBI, ARM::VLD3d32, false, SingleSpc, 3); break; case ARM::VLD1d64TPseudo: - ExpandVLD(MBBI, ARM::VLD1d64T, false, SingleSpc, 3); break; case ARM::VLD3d8Pseudo_UPD: - ExpandVLD(MBBI, ARM::VLD3d8_UPD, true, SingleSpc, 3); break; case ARM::VLD3d16Pseudo_UPD: - ExpandVLD(MBBI, ARM::VLD3d16_UPD, true, SingleSpc, 3); break; case ARM::VLD3d32Pseudo_UPD: - ExpandVLD(MBBI, ARM::VLD3d32_UPD, true, SingleSpc, 3); break; case ARM::VLD1d64TPseudo_UPD: - ExpandVLD(MBBI, ARM::VLD1d64T_UPD, true, SingleSpc, 3); break; case ARM::VLD3q8Pseudo_UPD: - ExpandVLD(MBBI, ARM::VLD3q8_UPD, true, EvenDblSpc, 3); break; case ARM::VLD3q16Pseudo_UPD: - ExpandVLD(MBBI, ARM::VLD3q16_UPD, true, EvenDblSpc, 3); break; case ARM::VLD3q32Pseudo_UPD: - ExpandVLD(MBBI, ARM::VLD3q32_UPD, true, EvenDblSpc, 3); break; + case ARM::VLD3q8oddPseudo: + case ARM::VLD3q16oddPseudo: + case ARM::VLD3q32oddPseudo: case ARM::VLD3q8oddPseudo_UPD: - ExpandVLD(MBBI, ARM::VLD3q8_UPD, true, OddDblSpc, 3); break; case ARM::VLD3q16oddPseudo_UPD: - ExpandVLD(MBBI, ARM::VLD3q16_UPD, true, OddDblSpc, 3); break; case ARM::VLD3q32oddPseudo_UPD: - ExpandVLD(MBBI, ARM::VLD3q32_UPD, true, OddDblSpc, 3); break; - case ARM::VLD4d8Pseudo: - ExpandVLD(MBBI, ARM::VLD4d8, false, SingleSpc, 4); break; case ARM::VLD4d16Pseudo: - ExpandVLD(MBBI, ARM::VLD4d16, false, SingleSpc, 4); break; case ARM::VLD4d32Pseudo: - ExpandVLD(MBBI, ARM::VLD4d32, false, SingleSpc, 4); break; case ARM::VLD1d64QPseudo: - ExpandVLD(MBBI, ARM::VLD1d64Q, false, SingleSpc, 4); break; case ARM::VLD4d8Pseudo_UPD: - ExpandVLD(MBBI, ARM::VLD4d8_UPD, true, SingleSpc, 4); break; case ARM::VLD4d16Pseudo_UPD: - ExpandVLD(MBBI, ARM::VLD4d16_UPD, true, SingleSpc, 4); break; case ARM::VLD4d32Pseudo_UPD: - ExpandVLD(MBBI, ARM::VLD4d32_UPD, true, SingleSpc, 4); break; case ARM::VLD1d64QPseudo_UPD: - ExpandVLD(MBBI, ARM::VLD1d64Q_UPD, true, SingleSpc, 4); break; case ARM::VLD4q8Pseudo_UPD: - ExpandVLD(MBBI, ARM::VLD4q8_UPD, true, EvenDblSpc, 4); break; case ARM::VLD4q16Pseudo_UPD: - ExpandVLD(MBBI, ARM::VLD4q16_UPD, true, EvenDblSpc, 4); break; case ARM::VLD4q32Pseudo_UPD: - ExpandVLD(MBBI, ARM::VLD4q32_UPD, true, EvenDblSpc, 4); break; + case ARM::VLD4q8oddPseudo: + case ARM::VLD4q16oddPseudo: + case ARM::VLD4q32oddPseudo: case ARM::VLD4q8oddPseudo_UPD: - ExpandVLD(MBBI, ARM::VLD4q8_UPD, true, OddDblSpc, 4); break; case ARM::VLD4q16oddPseudo_UPD: - ExpandVLD(MBBI, ARM::VLD4q16_UPD, true, OddDblSpc, 4); break; case ARM::VLD4q32oddPseudo_UPD: - ExpandVLD(MBBI, ARM::VLD4q32_UPD, true, OddDblSpc, 4); break; + case ARM::VLD1DUPq8Pseudo: + case ARM::VLD1DUPq16Pseudo: + case ARM::VLD1DUPq32Pseudo: + case ARM::VLD1DUPq8Pseudo_UPD: + case ARM::VLD1DUPq16Pseudo_UPD: + case ARM::VLD1DUPq32Pseudo_UPD: + case ARM::VLD2DUPd8Pseudo: + case ARM::VLD2DUPd16Pseudo: + case ARM::VLD2DUPd32Pseudo: + case ARM::VLD2DUPd8Pseudo_UPD: + case ARM::VLD2DUPd16Pseudo_UPD: + case ARM::VLD2DUPd32Pseudo_UPD: + case ARM::VLD3DUPd8Pseudo: + case ARM::VLD3DUPd16Pseudo: + case ARM::VLD3DUPd32Pseudo: + case ARM::VLD3DUPd8Pseudo_UPD: + case ARM::VLD3DUPd16Pseudo_UPD: + case ARM::VLD3DUPd32Pseudo_UPD: + case ARM::VLD4DUPd8Pseudo: + case ARM::VLD4DUPd16Pseudo: + case ARM::VLD4DUPd32Pseudo: + case ARM::VLD4DUPd8Pseudo_UPD: + case ARM::VLD4DUPd16Pseudo_UPD: + case ARM::VLD4DUPd32Pseudo_UPD: + ExpandVLD(MBBI); + return true; case ARM::VST1q8Pseudo: - ExpandVST(MBBI, ARM::VST1q8, false, SingleSpc, 2); break; case ARM::VST1q16Pseudo: - ExpandVST(MBBI, ARM::VST1q16, false, SingleSpc, 2); break; case ARM::VST1q32Pseudo: - ExpandVST(MBBI, ARM::VST1q32, false, SingleSpc, 2); break; case ARM::VST1q64Pseudo: - ExpandVST(MBBI, ARM::VST1q64, false, SingleSpc, 2); break; case ARM::VST1q8Pseudo_UPD: - ExpandVST(MBBI, ARM::VST1q8_UPD, true, SingleSpc, 2); break; case ARM::VST1q16Pseudo_UPD: - ExpandVST(MBBI, ARM::VST1q16_UPD, true, SingleSpc, 2); break; case ARM::VST1q32Pseudo_UPD: - ExpandVST(MBBI, ARM::VST1q32_UPD, true, SingleSpc, 2); break; case ARM::VST1q64Pseudo_UPD: - ExpandVST(MBBI, ARM::VST1q64_UPD, true, SingleSpc, 2); break; - case ARM::VST2d8Pseudo: - ExpandVST(MBBI, ARM::VST2d8, false, SingleSpc, 2); break; case ARM::VST2d16Pseudo: - ExpandVST(MBBI, ARM::VST2d16, false, SingleSpc, 2); break; case ARM::VST2d32Pseudo: - ExpandVST(MBBI, ARM::VST2d32, false, SingleSpc, 2); break; case ARM::VST2q8Pseudo: - ExpandVST(MBBI, ARM::VST2q8, false, SingleSpc, 4); break; case ARM::VST2q16Pseudo: - ExpandVST(MBBI, ARM::VST2q16, false, SingleSpc, 4); break; case ARM::VST2q32Pseudo: - ExpandVST(MBBI, ARM::VST2q32, false, SingleSpc, 4); break; case ARM::VST2d8Pseudo_UPD: - ExpandVST(MBBI, ARM::VST2d8_UPD, true, SingleSpc, 2); break; case ARM::VST2d16Pseudo_UPD: - ExpandVST(MBBI, ARM::VST2d16_UPD, true, SingleSpc, 2); break; case ARM::VST2d32Pseudo_UPD: - ExpandVST(MBBI, ARM::VST2d32_UPD, true, SingleSpc, 2); break; case ARM::VST2q8Pseudo_UPD: - ExpandVST(MBBI, ARM::VST2q8_UPD, true, SingleSpc, 4); break; case ARM::VST2q16Pseudo_UPD: - ExpandVST(MBBI, ARM::VST2q16_UPD, true, SingleSpc, 4); break; case ARM::VST2q32Pseudo_UPD: - ExpandVST(MBBI, ARM::VST2q32_UPD, true, SingleSpc, 4); break; - case ARM::VST3d8Pseudo: - ExpandVST(MBBI, ARM::VST3d8, false, SingleSpc, 3); break; case ARM::VST3d16Pseudo: - ExpandVST(MBBI, ARM::VST3d16, false, SingleSpc, 3); break; case ARM::VST3d32Pseudo: - ExpandVST(MBBI, ARM::VST3d32, false, SingleSpc, 3); break; case ARM::VST1d64TPseudo: - ExpandVST(MBBI, ARM::VST1d64T, false, SingleSpc, 3); break; case ARM::VST3d8Pseudo_UPD: - ExpandVST(MBBI, ARM::VST3d8_UPD, true, SingleSpc, 3); break; case ARM::VST3d16Pseudo_UPD: - ExpandVST(MBBI, ARM::VST3d16_UPD, true, SingleSpc, 3); break; case ARM::VST3d32Pseudo_UPD: - ExpandVST(MBBI, ARM::VST3d32_UPD, true, SingleSpc, 3); break; case ARM::VST1d64TPseudo_UPD: - ExpandVST(MBBI, ARM::VST1d64T_UPD, true, SingleSpc, 3); break; case ARM::VST3q8Pseudo_UPD: - ExpandVST(MBBI, ARM::VST3q8_UPD, true, EvenDblSpc, 3); break; case ARM::VST3q16Pseudo_UPD: - ExpandVST(MBBI, ARM::VST3q16_UPD, true, EvenDblSpc, 3); break; case ARM::VST3q32Pseudo_UPD: - ExpandVST(MBBI, ARM::VST3q32_UPD, true, EvenDblSpc, 3); break; + case ARM::VST3q8oddPseudo: + case ARM::VST3q16oddPseudo: + case ARM::VST3q32oddPseudo: case ARM::VST3q8oddPseudo_UPD: - ExpandVST(MBBI, ARM::VST3q8_UPD, true, OddDblSpc, 3); break; case ARM::VST3q16oddPseudo_UPD: - ExpandVST(MBBI, ARM::VST3q16_UPD, true, OddDblSpc, 3); break; case ARM::VST3q32oddPseudo_UPD: - ExpandVST(MBBI, ARM::VST3q32_UPD, true, OddDblSpc, 3); break; - case ARM::VST4d8Pseudo: - ExpandVST(MBBI, ARM::VST4d8, false, SingleSpc, 4); break; case ARM::VST4d16Pseudo: - ExpandVST(MBBI, ARM::VST4d16, false, SingleSpc, 4); break; case ARM::VST4d32Pseudo: - ExpandVST(MBBI, ARM::VST4d32, false, SingleSpc, 4); break; case ARM::VST1d64QPseudo: - ExpandVST(MBBI, ARM::VST1d64Q, false, SingleSpc, 4); break; case ARM::VST4d8Pseudo_UPD: - ExpandVST(MBBI, ARM::VST4d8_UPD, true, SingleSpc, 4); break; case ARM::VST4d16Pseudo_UPD: - ExpandVST(MBBI, ARM::VST4d16_UPD, true, SingleSpc, 4); break; case ARM::VST4d32Pseudo_UPD: - ExpandVST(MBBI, ARM::VST4d32_UPD, true, SingleSpc, 4); break; case ARM::VST1d64QPseudo_UPD: - ExpandVST(MBBI, ARM::VST1d64Q_UPD, true, SingleSpc, 4); break; case ARM::VST4q8Pseudo_UPD: - ExpandVST(MBBI, ARM::VST4q8_UPD, true, EvenDblSpc, 4); break; case ARM::VST4q16Pseudo_UPD: - ExpandVST(MBBI, ARM::VST4q16_UPD, true, EvenDblSpc, 4); break; case ARM::VST4q32Pseudo_UPD: - ExpandVST(MBBI, ARM::VST4q32_UPD, true, EvenDblSpc, 4); break; + case ARM::VST4q8oddPseudo: + case ARM::VST4q16oddPseudo: + case ARM::VST4q32oddPseudo: case ARM::VST4q8oddPseudo_UPD: - ExpandVST(MBBI, ARM::VST4q8_UPD, true, OddDblSpc, 4); break; case ARM::VST4q16oddPseudo_UPD: - ExpandVST(MBBI, ARM::VST4q16_UPD, true, OddDblSpc, 4); break; case ARM::VST4q32oddPseudo_UPD: - ExpandVST(MBBI, ARM::VST4q32_UPD, true, OddDblSpc, 4); break; - } + ExpandVST(MBBI); + return true; + + case ARM::VLD1LNq8Pseudo: + case ARM::VLD1LNq16Pseudo: + case ARM::VLD1LNq32Pseudo: + case ARM::VLD1LNq8Pseudo_UPD: + case ARM::VLD1LNq16Pseudo_UPD: + case ARM::VLD1LNq32Pseudo_UPD: + case ARM::VLD2LNd8Pseudo: + case ARM::VLD2LNd16Pseudo: + case ARM::VLD2LNd32Pseudo: + case ARM::VLD2LNq16Pseudo: + case ARM::VLD2LNq32Pseudo: + case ARM::VLD2LNd8Pseudo_UPD: + case ARM::VLD2LNd16Pseudo_UPD: + case ARM::VLD2LNd32Pseudo_UPD: + case ARM::VLD2LNq16Pseudo_UPD: + case ARM::VLD2LNq32Pseudo_UPD: + case ARM::VLD3LNd8Pseudo: + case ARM::VLD3LNd16Pseudo: + case ARM::VLD3LNd32Pseudo: + case ARM::VLD3LNq16Pseudo: + case ARM::VLD3LNq32Pseudo: + case ARM::VLD3LNd8Pseudo_UPD: + case ARM::VLD3LNd16Pseudo_UPD: + case ARM::VLD3LNd32Pseudo_UPD: + case ARM::VLD3LNq16Pseudo_UPD: + case ARM::VLD3LNq32Pseudo_UPD: + case ARM::VLD4LNd8Pseudo: + case ARM::VLD4LNd16Pseudo: + case ARM::VLD4LNd32Pseudo: + case ARM::VLD4LNq16Pseudo: + case ARM::VLD4LNq32Pseudo: + case ARM::VLD4LNd8Pseudo_UPD: + case ARM::VLD4LNd16Pseudo_UPD: + case ARM::VLD4LNd32Pseudo_UPD: + case ARM::VLD4LNq16Pseudo_UPD: + case ARM::VLD4LNq32Pseudo_UPD: + case ARM::VST1LNq8Pseudo: + case ARM::VST1LNq16Pseudo: + case ARM::VST1LNq32Pseudo: + case ARM::VST1LNq8Pseudo_UPD: + case ARM::VST1LNq16Pseudo_UPD: + case ARM::VST1LNq32Pseudo_UPD: + case ARM::VST2LNd8Pseudo: + case ARM::VST2LNd16Pseudo: + case ARM::VST2LNd32Pseudo: + case ARM::VST2LNq16Pseudo: + case ARM::VST2LNq32Pseudo: + case ARM::VST2LNd8Pseudo_UPD: + case ARM::VST2LNd16Pseudo_UPD: + case ARM::VST2LNd32Pseudo_UPD: + case ARM::VST2LNq16Pseudo_UPD: + case ARM::VST2LNq32Pseudo_UPD: + case ARM::VST3LNd8Pseudo: + case ARM::VST3LNd16Pseudo: + case ARM::VST3LNd32Pseudo: + case ARM::VST3LNq16Pseudo: + case ARM::VST3LNq32Pseudo: + case ARM::VST3LNd8Pseudo_UPD: + case ARM::VST3LNd16Pseudo_UPD: + case ARM::VST3LNd32Pseudo_UPD: + case ARM::VST3LNq16Pseudo_UPD: + case ARM::VST3LNq32Pseudo_UPD: + case ARM::VST4LNd8Pseudo: + case ARM::VST4LNd16Pseudo: + case ARM::VST4LNd32Pseudo: + case ARM::VST4LNq16Pseudo: + case ARM::VST4LNq32Pseudo: + case ARM::VST4LNd8Pseudo_UPD: + case ARM::VST4LNd16Pseudo_UPD: + case ARM::VST4LNd32Pseudo_UPD: + case ARM::VST4LNq16Pseudo_UPD: + case ARM::VST4LNq32Pseudo_UPD: + ExpandLaneOp(MBBI); + return true; + + case ARM::VTBL2Pseudo: ExpandVTBL(MBBI, ARM::VTBL2, false, 2); return true; + case ARM::VTBL3Pseudo: ExpandVTBL(MBBI, ARM::VTBL3, false, 3); return true; + case ARM::VTBL4Pseudo: ExpandVTBL(MBBI, ARM::VTBL4, false, 4); return true; + case ARM::VTBX2Pseudo: ExpandVTBL(MBBI, ARM::VTBX2, true, 2); return true; + case ARM::VTBX3Pseudo: ExpandVTBL(MBBI, ARM::VTBX3, true, 3); return true; + case ARM::VTBX4Pseudo: ExpandVTBL(MBBI, ARM::VTBX4, true, 4); return true; + } + + return false; +} - if (ModifiedOp) - Modified = true; +bool ARMExpandPseudo::ExpandMBB(MachineBasicBlock &MBB) { + bool Modified = false; + + MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); + while (MBBI != E) { + MachineBasicBlock::iterator NMBBI = llvm::next(MBBI); + Modified |= ExpandMI(MBB, MBBI); MBBI = NMBBI; } @@ -508,8 +1222,11 @@ bool ARMExpandPseudo::ExpandMBB(MachineBasicBlock &MBB) { } bool ARMExpandPseudo::runOnMachineFunction(MachineFunction &MF) { - TII = MF.getTarget().getInstrInfo(); - TRI = MF.getTarget().getRegisterInfo(); + const TargetMachine &TM = MF.getTarget(); + TII = static_cast(TM.getInstrInfo()); + TRI = TM.getRegisterInfo(); + STI = &TM.getSubtarget(); + AFI = MF.getInfo(); bool Modified = false; for (MachineFunction::iterator MFI = MF.begin(), E = MF.end(); MFI != E; diff --git a/lib/Target/ARM/ARMFastISel.cpp b/lib/Target/ARM/ARMFastISel.cpp index 4892eae95833..9f295302db0e 100644 --- a/lib/Target/ARM/ARMFastISel.cpp +++ b/lib/Target/ARM/ARMFastISel.cpp @@ -15,14 +15,17 @@ #include "ARM.h" #include "ARMBaseInstrInfo.h" +#include "ARMCallingConv.h" #include "ARMRegisterInfo.h" #include "ARMTargetMachine.h" #include "ARMSubtarget.h" +#include "ARMConstantPoolValue.h" #include "llvm/CallingConv.h" #include "llvm/DerivedTypes.h" #include "llvm/GlobalVariable.h" #include "llvm/Instructions.h" #include "llvm/IntrinsicInst.h" +#include "llvm/Module.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/FastISel.h" #include "llvm/CodeGen/FunctionLoweringInfo.h" @@ -30,7 +33,9 @@ #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/PseudoSourceValue.h" #include "llvm/Support/CallSite.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" @@ -43,12 +48,37 @@ using namespace llvm; static cl::opt -EnableARMFastISel("arm-fast-isel", - cl::desc("Turn on experimental ARM fast-isel support"), - cl::init(false), cl::Hidden); +DisableARMFastISel("disable-arm-fast-isel", + cl::desc("Turn off experimental ARM fast-isel support"), + cl::init(false), cl::Hidden); + +extern cl::opt EnableARMLongCalls; namespace { + // All possible address modes, plus some. + typedef struct Address { + enum { + RegBase, + FrameIndexBase + } BaseType; + + union { + unsigned Reg; + int FI; + } Base; + + int Offset; + unsigned Scale; + unsigned PlusReg; + + // Innocuous defaults for our address. + Address() + : BaseType(RegBase), Offset(0), Scale(0), PlusReg(0) { + Base.Reg = 0; + } + } Address; + class ARMFastISel : public FastISel { /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can @@ -57,13 +87,14 @@ class ARMFastISel : public FastISel { const TargetMachine &TM; const TargetInstrInfo &TII; const TargetLowering &TLI; - const ARMFunctionInfo *AFI; + ARMFunctionInfo *AFI; - // Convenience variable to avoid checking all the time. + // Convenience variables to avoid some queries. bool isThumb; + LLVMContext *Context; public: - explicit ARMFastISel(FunctionLoweringInfo &funcInfo) + explicit ARMFastISel(FunctionLoweringInfo &funcInfo) : FastISel(funcInfo), TM(funcInfo.MF->getTarget()), TII(*TM.getInstrInfo()), @@ -71,6 +102,7 @@ class ARMFastISel : public FastISel { Subtarget = &TM.getSubtarget(); AFI = funcInfo.MF->getInfo(); isThumb = AFI->isThumbFunction(); + Context = &funcInfo.Fn->getContext(); } // Code from FastISel.cpp. @@ -102,36 +134,73 @@ class ARMFastISel : public FastISel { virtual unsigned FastEmitInst_extractsubreg(MVT RetVT, unsigned Op0, bool Op0IsKill, uint32_t Idx); - + // Backend specific FastISel code. virtual bool TargetSelectInstruction(const Instruction *I); virtual unsigned TargetMaterializeConstant(const Constant *C); + virtual unsigned TargetMaterializeAlloca(const AllocaInst *AI); #include "ARMGenFastISel.inc" - + // Instruction selection routines. - virtual bool ARMSelectLoad(const Instruction *I); - virtual bool ARMSelectStore(const Instruction *I); - virtual bool ARMSelectBranch(const Instruction *I); + private: + bool SelectLoad(const Instruction *I); + bool SelectStore(const Instruction *I); + bool SelectBranch(const Instruction *I); + bool SelectCmp(const Instruction *I); + bool SelectFPExt(const Instruction *I); + bool SelectFPTrunc(const Instruction *I); + bool SelectBinaryOp(const Instruction *I, unsigned ISDOpcode); + bool SelectSIToFP(const Instruction *I); + bool SelectFPToSI(const Instruction *I); + bool SelectSDiv(const Instruction *I); + bool SelectSRem(const Instruction *I); + bool SelectCall(const Instruction *I); + bool SelectSelect(const Instruction *I); + bool SelectRet(const Instruction *I); // Utility routines. private: - bool isTypeLegal(const Type *Ty, EVT &VT); - bool isLoadTypeLegal(const Type *Ty, EVT &VT); - bool ARMEmitLoad(EVT VT, unsigned &ResultReg, unsigned Reg, int Offset); - bool ARMEmitStore(EVT VT, unsigned SrcReg, unsigned Reg, int Offset); - bool ARMLoadAlloca(const Instruction *I); - bool ARMStoreAlloca(const Instruction *I, unsigned SrcReg); - bool ARMComputeRegOffset(const Value *Obj, unsigned &Reg, int &Offset); - bool ARMMaterializeConstant(const ConstantInt *Val, unsigned &Reg); - + bool isTypeLegal(const Type *Ty, MVT &VT); + bool isLoadTypeLegal(const Type *Ty, MVT &VT); + bool ARMEmitLoad(EVT VT, unsigned &ResultReg, Address &Addr); + bool ARMEmitStore(EVT VT, unsigned SrcReg, Address &Addr); + bool ARMComputeAddress(const Value *Obj, Address &Addr); + void ARMSimplifyAddress(Address &Addr, EVT VT); + unsigned ARMMaterializeFP(const ConstantFP *CFP, EVT VT); + unsigned ARMMaterializeInt(const Constant *C, EVT VT); + unsigned ARMMaterializeGV(const GlobalValue *GV, EVT VT); + unsigned ARMMoveToFPReg(EVT VT, unsigned SrcReg); + unsigned ARMMoveToIntReg(EVT VT, unsigned SrcReg); + + // Call handling routines. + private: + bool FastEmitExtend(ISD::NodeType Opc, EVT DstVT, unsigned Src, EVT SrcVT, + unsigned &ResultReg); + CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool Return); + bool ProcessCallArgs(SmallVectorImpl &Args, + SmallVectorImpl &ArgRegs, + SmallVectorImpl &ArgVTs, + SmallVectorImpl &ArgFlags, + SmallVectorImpl &RegArgs, + CallingConv::ID CC, + unsigned &NumBytes); + bool FinishCall(MVT RetVT, SmallVectorImpl &UsedRegs, + const Instruction *I, CallingConv::ID CC, + unsigned &NumBytes); + bool ARMEmitLibcall(const Instruction *I, RTLIB::Libcall Call); + + // OptionalDef handling routines. + private: bool DefinesOptionalPredicate(MachineInstr *MI, bool *CPSR); const MachineInstrBuilder &AddOptionalDefs(const MachineInstrBuilder &MIB); + void AddLoadStoreOperands(EVT VT, Address &Addr, + const MachineInstrBuilder &MIB); }; } // end anonymous namespace -// #include "ARMGenCallingConv.inc" +#include "ARMGenCallingConv.inc" // DefinesOptionalPredicate - This is different from DefinesPredicate in that // we don't care about implicit defs here, just places we'll need to add a @@ -153,6 +222,9 @@ bool ARMFastISel::DefinesOptionalPredicate(MachineInstr *MI, bool *CPSR) { // If the machine is predicable go ahead and add the predicate operands, if // it needs default CC operands add those. +// TODO: If we want to support thumb1 then we'll need to deal with optional +// CPSR defs that need to be added before the remaining operands. See s_cc_out +// for descriptions why. const MachineInstrBuilder & ARMFastISel::AddOptionalDefs(const MachineInstrBuilder &MIB) { MachineInstr *MI = &*MIB; @@ -160,7 +232,7 @@ ARMFastISel::AddOptionalDefs(const MachineInstrBuilder &MIB) { // Do we use a predicate? if (TII.isPredicable(MI)) AddDefaultPred(MIB); - + // Do we optionally set a predicate? Preds is size > 0 iff the predicate // defines CPSR. All other OptionalDefines in ARM are the CCR register. bool CPSR = false; @@ -297,7 +369,7 @@ unsigned ARMFastISel::FastEmitInst_i(unsigned MachineInstOpcode, uint64_t Imm) { unsigned ResultReg = createResultReg(RC); const TargetInstrDesc &II = TII.get(MachineInstOpcode); - + if (II.getNumDefs() >= 1) AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, II, ResultReg) .addImm(Imm)); @@ -323,16 +395,84 @@ unsigned ARMFastISel::FastEmitInst_extractsubreg(MVT RetVT, return ResultReg; } -unsigned ARMFastISel::TargetMaterializeConstant(const Constant *C) { - EVT VT = TLI.getValueType(C->getType(), true); +// TODO: Don't worry about 64-bit now, but when this is fixed remove the +// checks from the various callers. +unsigned ARMFastISel::ARMMoveToFPReg(EVT VT, unsigned SrcReg) { + if (VT == MVT::f64) return 0; - // Only handle simple types. - if (!VT.isSimple()) return 0; - - // TODO: This should be safe for fp because they're just bits from the - // Constant. - // TODO: Theoretically we could materialize fp constants with instructions - // from VFP3. + unsigned MoveReg = createResultReg(TLI.getRegClassFor(VT)); + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(ARM::VMOVRS), MoveReg) + .addReg(SrcReg)); + return MoveReg; +} + +unsigned ARMFastISel::ARMMoveToIntReg(EVT VT, unsigned SrcReg) { + if (VT == MVT::i64) return 0; + + unsigned MoveReg = createResultReg(TLI.getRegClassFor(VT)); + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(ARM::VMOVSR), MoveReg) + .addReg(SrcReg)); + return MoveReg; +} + +// For double width floating point we need to materialize two constants +// (the high and the low) into integer registers then use a move to get +// the combined constant into an FP reg. +unsigned ARMFastISel::ARMMaterializeFP(const ConstantFP *CFP, EVT VT) { + const APFloat Val = CFP->getValueAPF(); + bool is64bit = VT == MVT::f64; + + // This checks to see if we can use VFP3 instructions to materialize + // a constant, otherwise we have to go through the constant pool. + if (TLI.isFPImmLegal(Val, VT)) { + unsigned Opc = is64bit ? ARM::FCONSTD : ARM::FCONSTS; + unsigned DestReg = createResultReg(TLI.getRegClassFor(VT)); + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(Opc), + DestReg) + .addFPImm(CFP)); + return DestReg; + } + + // Require VFP2 for loading fp constants. + if (!Subtarget->hasVFP2()) return false; + + // MachineConstantPool wants an explicit alignment. + unsigned Align = TD.getPrefTypeAlignment(CFP->getType()); + if (Align == 0) { + // TODO: Figure out if this is correct. + Align = TD.getTypeAllocSize(CFP->getType()); + } + unsigned Idx = MCP.getConstantPoolIndex(cast(CFP), Align); + unsigned DestReg = createResultReg(TLI.getRegClassFor(VT)); + unsigned Opc = is64bit ? ARM::VLDRD : ARM::VLDRS; + + // The extra reg is for addrmode5. + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(Opc), + DestReg) + .addConstantPoolIndex(Idx) + .addReg(0)); + return DestReg; +} + +unsigned ARMFastISel::ARMMaterializeInt(const Constant *C, EVT VT) { + + // For now 32-bit only. + if (VT != MVT::i32) return false; + + unsigned DestReg = createResultReg(TLI.getRegClassFor(VT)); + + // If we can do this in a single instruction without a constant pool entry + // do so now. + const ConstantInt *CI = cast(C); + if (Subtarget->hasV6T2Ops() && isUInt<16>(CI->getSExtValue())) { + unsigned Opc = isThumb ? ARM::t2MOVi16 : ARM::MOVi16; + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(Opc), DestReg) + .addImm(CI->getSExtValue())); + return DestReg; + } // MachineConstantPool wants an explicit alignment. unsigned Align = TD.getPrefTypeAlignment(C->getType()); @@ -342,58 +482,144 @@ unsigned ARMFastISel::TargetMaterializeConstant(const Constant *C) { } unsigned Idx = MCP.getConstantPoolIndex(C, Align); - unsigned DestReg = createResultReg(TLI.getRegClassFor(VT)); - // Different addressing modes between ARM/Thumb2 for constant pool loads. if (isThumb) AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, - TII.get(ARM::t2LDRpci)) - .addReg(DestReg).addConstantPoolIndex(Idx)); + TII.get(ARM::t2LDRpci), DestReg) + .addConstantPoolIndex(Idx)); else + // The extra immediate is for addrmode2. AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, - TII.get(ARM::LDRcp)) - .addReg(DestReg).addConstantPoolIndex(Idx) - .addReg(0).addImm(0)); - + TII.get(ARM::LDRcp), DestReg) + .addConstantPoolIndex(Idx) + .addImm(0)); + return DestReg; } -bool ARMFastISel::isTypeLegal(const Type *Ty, EVT &VT) { - VT = TLI.getValueType(Ty, true); - +unsigned ARMFastISel::ARMMaterializeGV(const GlobalValue *GV, EVT VT) { + // For now 32-bit only. + if (VT != MVT::i32) return 0; + + Reloc::Model RelocM = TM.getRelocationModel(); + + // TODO: No external globals for now. + if (Subtarget->GVIsIndirectSymbol(GV, RelocM)) return 0; + + // TODO: Need more magic for ARM PIC. + if (!isThumb && (RelocM == Reloc::PIC_)) return 0; + + // MachineConstantPool wants an explicit alignment. + unsigned Align = TD.getPrefTypeAlignment(GV->getType()); + if (Align == 0) { + // TODO: Figure out if this is correct. + Align = TD.getTypeAllocSize(GV->getType()); + } + + // Grab index. + unsigned PCAdj = (RelocM != Reloc::PIC_) ? 0 : (Subtarget->isThumb() ? 4 : 8); + unsigned Id = AFI->createPICLabelUId(); + ARMConstantPoolValue *CPV = new ARMConstantPoolValue(GV, Id, + ARMCP::CPValue, PCAdj); + unsigned Idx = MCP.getConstantPoolIndex(CPV, Align); + + // Load value. + MachineInstrBuilder MIB; + unsigned DestReg = createResultReg(TLI.getRegClassFor(VT)); + if (isThumb) { + unsigned Opc = (RelocM != Reloc::PIC_) ? ARM::t2LDRpci : ARM::t2LDRpci_pic; + MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(Opc), DestReg) + .addConstantPoolIndex(Idx); + if (RelocM == Reloc::PIC_) + MIB.addImm(Id); + } else { + // The extra immediate is for addrmode2. + MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(ARM::LDRcp), + DestReg) + .addConstantPoolIndex(Idx) + .addImm(0); + } + AddOptionalDefs(MIB); + return DestReg; +} + +unsigned ARMFastISel::TargetMaterializeConstant(const Constant *C) { + EVT VT = TLI.getValueType(C->getType(), true); + // Only handle simple types. - if (VT == MVT::Other || !VT.isSimple()) return false; - + if (!VT.isSimple()) return 0; + + if (const ConstantFP *CFP = dyn_cast(C)) + return ARMMaterializeFP(CFP, VT); + else if (const GlobalValue *GV = dyn_cast(C)) + return ARMMaterializeGV(GV, VT); + else if (isa(C)) + return ARMMaterializeInt(C, VT); + + return 0; +} + +unsigned ARMFastISel::TargetMaterializeAlloca(const AllocaInst *AI) { + // Don't handle dynamic allocas. + if (!FuncInfo.StaticAllocaMap.count(AI)) return 0; + + MVT VT; + if (!isLoadTypeLegal(AI->getType(), VT)) return false; + + DenseMap::iterator SI = + FuncInfo.StaticAllocaMap.find(AI); + + // This will get lowered later into the correct offsets and registers + // via rewriteXFrameIndex. + if (SI != FuncInfo.StaticAllocaMap.end()) { + TargetRegisterClass* RC = TLI.getRegClassFor(VT); + unsigned ResultReg = createResultReg(RC); + unsigned Opc = isThumb ? ARM::t2ADDri : ARM::ADDri; + AddOptionalDefs(BuildMI(*FuncInfo.MBB, *FuncInfo.InsertPt, DL, + TII.get(Opc), ResultReg) + .addFrameIndex(SI->second) + .addImm(0)); + return ResultReg; + } + + return 0; +} + +bool ARMFastISel::isTypeLegal(const Type *Ty, MVT &VT) { + EVT evt = TLI.getValueType(Ty, true); + + // Only handle simple types. + if (evt == MVT::Other || !evt.isSimple()) return false; + VT = evt.getSimpleVT(); + // Handle all legal types, i.e. a register that will directly hold this // value. return TLI.isTypeLegal(VT); } -bool ARMFastISel::isLoadTypeLegal(const Type *Ty, EVT &VT) { +bool ARMFastISel::isLoadTypeLegal(const Type *Ty, MVT &VT) { if (isTypeLegal(Ty, VT)) return true; - + // If this is a type than can be sign or zero-extended to a basic operation // go ahead and accept it now. if (VT == MVT::i8 || VT == MVT::i16) return true; - + return false; } -// Computes the Reg+Offset to get to an object. -bool ARMFastISel::ARMComputeRegOffset(const Value *Obj, unsigned &Reg, - int &Offset) { +// Computes the address to get to an object. +bool ARMFastISel::ARMComputeAddress(const Value *Obj, Address &Addr) { // Some boilerplate from the X86 FastISel. const User *U = NULL; unsigned Opcode = Instruction::UserOp1; if (const Instruction *I = dyn_cast(Obj)) { - // Don't walk into other basic blocks; it's possible we haven't - // visited them yet, so the instructions may not yet be assigned - // virtual registers. - if (FuncInfo.MBBMap[I->getParent()] != FuncInfo.MBB) - return false; - - Opcode = I->getOpcode(); - U = I; + // Don't walk into other basic blocks unless the object is an alloca from + // another block, otherwise it may not have a virtual register assigned. + if (FuncInfo.StaticAllocaMap.count(static_cast(Obj)) || + FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) { + Opcode = I->getOpcode(); + U = I; + } } else if (const ConstantExpr *C = dyn_cast(Obj)) { Opcode = C->getOpcode(); U = C; @@ -404,141 +630,282 @@ bool ARMFastISel::ARMComputeRegOffset(const Value *Obj, unsigned &Reg, // Fast instruction selection doesn't support the special // address spaces. return false; - + switch (Opcode) { - default: - //errs() << "Failing Opcode is: " << *Op1 << "\n"; + default: break; + case Instruction::BitCast: { + // Look through bitcasts. + return ARMComputeAddress(U->getOperand(0), Addr); + } + case Instruction::IntToPtr: { + // Look past no-op inttoptrs. + if (TLI.getValueType(U->getOperand(0)->getType()) == TLI.getPointerTy()) + return ARMComputeAddress(U->getOperand(0), Addr); + break; + } + case Instruction::PtrToInt: { + // Look past no-op ptrtoints. + if (TLI.getValueType(U->getType()) == TLI.getPointerTy()) + return ARMComputeAddress(U->getOperand(0), Addr); + break; + } + case Instruction::GetElementPtr: { + Address SavedAddr = Addr; + int TmpOffset = Addr.Offset; + + // Iterate through the GEP folding the constants into offsets where + // we can. + gep_type_iterator GTI = gep_type_begin(U); + for (User::const_op_iterator i = U->op_begin() + 1, e = U->op_end(); + i != e; ++i, ++GTI) { + const Value *Op = *i; + if (const StructType *STy = dyn_cast(*GTI)) { + const StructLayout *SL = TD.getStructLayout(STy); + unsigned Idx = cast(Op)->getZExtValue(); + TmpOffset += SL->getElementOffset(Idx); + } else { + uint64_t S = TD.getTypeAllocSize(GTI.getIndexedType()); + SmallVector Worklist; + Worklist.push_back(Op); + do { + Op = Worklist.pop_back_val(); + if (const ConstantInt *CI = dyn_cast(Op)) { + // Constant-offset addressing. + TmpOffset += CI->getSExtValue() * S; + } else if (isa(Op) && + isa(cast(Op)->getOperand(1))) { + // An add with a constant operand. Fold the constant. + ConstantInt *CI = + cast(cast(Op)->getOperand(1)); + TmpOffset += CI->getSExtValue() * S; + // Add the other operand back to the work list. + Worklist.push_back(cast(Op)->getOperand(0)); + } else + goto unsupported_gep; + } while (!Worklist.empty()); + } + } + + // Try to grab the base operand now. + Addr.Offset = TmpOffset; + if (ARMComputeAddress(U->getOperand(0), Addr)) return true; + + // We failed, restore everything and try the other options. + Addr = SavedAddr; + + unsupported_gep: + break; + } case Instruction::Alloca: { - assert(false && "Alloca should have been handled earlier!"); - return false; + const AllocaInst *AI = cast(Obj); + DenseMap::iterator SI = + FuncInfo.StaticAllocaMap.find(AI); + if (SI != FuncInfo.StaticAllocaMap.end()) { + Addr.BaseType = Address::FrameIndexBase; + Addr.Base.FI = SI->second; + return true; + } + break; } } - + + // Materialize the global variable's address into a reg which can + // then be used later to load the variable. if (const GlobalValue *GV = dyn_cast(Obj)) { - //errs() << "Failing GV is: " << GV << "\n"; - (void)GV; - return false; + unsigned Tmp = ARMMaterializeGV(GV, TLI.getValueType(Obj->getType())); + if (Tmp == 0) return false; + + Addr.Base.Reg = Tmp; + return true; } - + // Try to get this in a register if nothing else has worked. - Reg = getRegForValue(Obj); - if (Reg == 0) return false; + if (Addr.Base.Reg == 0) Addr.Base.Reg = getRegForValue(Obj); + return Addr.Base.Reg != 0; +} + +void ARMFastISel::ARMSimplifyAddress(Address &Addr, EVT VT) { - // Since the offset may be too large for the load instruction + assert(VT.isSimple() && "Non-simple types are invalid here!"); + + bool needsLowering = false; + switch (VT.getSimpleVT().SimpleTy) { + default: + assert(false && "Unhandled load/store type!"); + case MVT::i1: + case MVT::i8: + case MVT::i16: + case MVT::i32: + // Integer loads/stores handle 12-bit offsets. + needsLowering = ((Addr.Offset & 0xfff) != Addr.Offset); + break; + case MVT::f32: + case MVT::f64: + // Floating point operands handle 8-bit offsets. + needsLowering = ((Addr.Offset & 0xff) != Addr.Offset); + break; + } + + // If this is a stack pointer and the offset needs to be simplified then + // put the alloca address into a register, set the base type back to + // register and continue. This should almost never happen. + if (needsLowering && Addr.BaseType == Address::FrameIndexBase) { + TargetRegisterClass *RC = isThumb ? ARM::tGPRRegisterClass : + ARM::GPRRegisterClass; + unsigned ResultReg = createResultReg(RC); + unsigned Opc = isThumb ? ARM::t2ADDri : ARM::ADDri; + AddOptionalDefs(BuildMI(*FuncInfo.MBB, *FuncInfo.InsertPt, DL, + TII.get(Opc), ResultReg) + .addFrameIndex(Addr.Base.FI) + .addImm(0)); + Addr.Base.Reg = ResultReg; + Addr.BaseType = Address::RegBase; + } + + // Since the offset is too large for the load/store instruction // get the reg+offset into a register. - // TODO: Verify the additions work, otherwise we'll need to add the - // offset instead of 0 to the instructions and do all sorts of operand - // munging. - // TODO: Optimize this somewhat. - if (Offset != 0) { + if (needsLowering) { ARMCC::CondCodes Pred = ARMCC::AL; unsigned PredReg = 0; + TargetRegisterClass *RC = isThumb ? ARM::tGPRRegisterClass : + ARM::GPRRegisterClass; + unsigned BaseReg = createResultReg(RC); + if (!isThumb) emitARMRegPlusImmediate(*FuncInfo.MBB, FuncInfo.InsertPt, DL, - Reg, Reg, Offset, Pred, PredReg, + BaseReg, Addr.Base.Reg, Addr.Offset, + Pred, PredReg, static_cast(TII)); else { assert(AFI->isThumb2Function()); emitT2RegPlusImmediate(*FuncInfo.MBB, FuncInfo.InsertPt, DL, - Reg, Reg, Offset, Pred, PredReg, + BaseReg, Addr.Base.Reg, Addr.Offset, Pred, PredReg, static_cast(TII)); } + Addr.Offset = 0; + Addr.Base.Reg = BaseReg; } - - return true; } -bool ARMFastISel::ARMLoadAlloca(const Instruction *I) { - Value *Op0 = I->getOperand(0); +void ARMFastISel::AddLoadStoreOperands(EVT VT, Address &Addr, + const MachineInstrBuilder &MIB) { + // addrmode5 output depends on the selection dag addressing dividing the + // offset by 4 that it then later multiplies. Do this here as well. + if (VT.getSimpleVT().SimpleTy == MVT::f32 || + VT.getSimpleVT().SimpleTy == MVT::f64) + Addr.Offset /= 4; + + // Frame base works a bit differently. Handle it separately. + if (Addr.BaseType == Address::FrameIndexBase) { + int FI = Addr.Base.FI; + int Offset = Addr.Offset; + MachineMemOperand *MMO = + FuncInfo.MF->getMachineMemOperand( + MachinePointerInfo::getFixedStack(FI, Offset), + MachineMemOperand::MOLoad, + MFI.getObjectSize(FI), + MFI.getObjectAlignment(FI)); + // Now add the rest of the operands. + MIB.addFrameIndex(FI); - // Verify it's an alloca. - if (const AllocaInst *AI = dyn_cast(Op0)) { - DenseMap::iterator SI = - FuncInfo.StaticAllocaMap.find(AI); - - if (SI != FuncInfo.StaticAllocaMap.end()) { - TargetRegisterClass* RC = TLI.getRegClassFor(TLI.getPointerTy()); - unsigned ResultReg = createResultReg(RC); - TII.loadRegFromStackSlot(*FuncInfo.MBB, *FuncInfo.InsertPt, - ResultReg, SI->second, RC, - TM.getRegisterInfo()); - UpdateValueMap(I, ResultReg); - return true; - } + // ARM halfword load/stores need an additional operand. + if (!isThumb && VT.getSimpleVT().SimpleTy == MVT::i16) MIB.addReg(0); + + MIB.addImm(Addr.Offset); + MIB.addMemOperand(MMO); + } else { + // Now add the rest of the operands. + MIB.addReg(Addr.Base.Reg); + + // ARM halfword load/stores need an additional operand. + if (!isThumb && VT.getSimpleVT().SimpleTy == MVT::i16) MIB.addReg(0); + + MIB.addImm(Addr.Offset); } - return false; + AddOptionalDefs(MIB); } -bool ARMFastISel::ARMEmitLoad(EVT VT, unsigned &ResultReg, - unsigned Reg, int Offset) { - +bool ARMFastISel::ARMEmitLoad(EVT VT, unsigned &ResultReg, Address &Addr) { + assert(VT.isSimple() && "Non-simple types are invalid here!"); unsigned Opc; - + TargetRegisterClass *RC; switch (VT.getSimpleVT().SimpleTy) { - default: - assert(false && "Trying to emit for an unhandled type!"); - return false; + // This is mostly going to be Neon/vector support. + default: return false; case MVT::i16: - Opc = isThumb ? ARM::tLDRH : ARM::LDRH; - VT = MVT::i32; + Opc = isThumb ? ARM::t2LDRHi12 : ARM::LDRH; + RC = ARM::GPRRegisterClass; break; case MVT::i8: - Opc = isThumb ? ARM::tLDRB : ARM::LDRB; - VT = MVT::i32; + Opc = isThumb ? ARM::t2LDRBi12 : ARM::LDRBi12; + RC = ARM::GPRRegisterClass; break; case MVT::i32: - Opc = isThumb ? ARM::tLDR : ARM::LDR; + Opc = isThumb ? ARM::t2LDRi12 : ARM::LDRi12; + RC = ARM::GPRRegisterClass; + break; + case MVT::f32: + Opc = ARM::VLDRS; + RC = TLI.getRegClassFor(VT); + break; + case MVT::f64: + Opc = ARM::VLDRD; + RC = TLI.getRegClassFor(VT); break; } - - ResultReg = createResultReg(TLI.getRegClassFor(VT)); - - // TODO: Fix the Addressing modes so that these can share some code. - // Since this is a Thumb1 load this will work in Thumb1 or 2 mode. - if (isThumb) - AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, - TII.get(Opc), ResultReg) - .addReg(Reg).addImm(Offset).addReg(0)); - else - AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, - TII.get(Opc), ResultReg) - .addReg(Reg).addReg(0).addImm(Offset)); - + // Simplify this down to something we can handle. + ARMSimplifyAddress(Addr, VT); + + // Create the base instruction, then add the operands. + ResultReg = createResultReg(RC); + MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(Opc), ResultReg); + AddLoadStoreOperands(VT, Addr, MIB); return true; } -bool ARMFastISel::ARMStoreAlloca(const Instruction *I, unsigned SrcReg) { - Value *Op1 = I->getOperand(1); +bool ARMFastISel::SelectLoad(const Instruction *I) { + // Verify we have a legal type before going any further. + MVT VT; + if (!isLoadTypeLegal(I->getType(), VT)) + return false; - // Verify it's an alloca. - if (const AllocaInst *AI = dyn_cast(Op1)) { - DenseMap::iterator SI = - FuncInfo.StaticAllocaMap.find(AI); + // See if we can handle this address. + Address Addr; + if (!ARMComputeAddress(I->getOperand(0), Addr)) return false; - if (SI != FuncInfo.StaticAllocaMap.end()) { - TargetRegisterClass* RC = TLI.getRegClassFor(TLI.getPointerTy()); - assert(SrcReg != 0 && "Nothing to store!"); - TII.storeRegToStackSlot(*FuncInfo.MBB, *FuncInfo.InsertPt, - SrcReg, true /*isKill*/, SI->second, RC, - TM.getRegisterInfo()); - return true; - } - } - return false; + unsigned ResultReg; + if (!ARMEmitLoad(VT, ResultReg, Addr)) return false; + UpdateValueMap(I, ResultReg); + return true; } -bool ARMFastISel::ARMEmitStore(EVT VT, unsigned SrcReg, - unsigned DstReg, int Offset) { +bool ARMFastISel::ARMEmitStore(EVT VT, unsigned SrcReg, Address &Addr) { unsigned StrOpc; switch (VT.getSimpleVT().SimpleTy) { + // This is mostly going to be Neon/vector support. default: return false; - case MVT::i1: - case MVT::i8: StrOpc = isThumb ? ARM::tSTRB : ARM::STRB; break; - case MVT::i16: StrOpc = isThumb ? ARM::tSTRH : ARM::STRH; break; - case MVT::i32: StrOpc = isThumb ? ARM::tSTR : ARM::STR; break; + case MVT::i1: { + unsigned Res = createResultReg(isThumb ? ARM::tGPRRegisterClass : + ARM::GPRRegisterClass); + unsigned Opc = isThumb ? ARM::t2ANDri : ARM::ANDri; + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(Opc), Res) + .addReg(SrcReg).addImm(1)); + SrcReg = Res; + } // Fallthrough here. + case MVT::i8: + StrOpc = isThumb ? ARM::t2STRBi12 : ARM::STRBi12; + break; + case MVT::i16: + StrOpc = isThumb ? ARM::t2STRHi12 : ARM::STRH; + break; + case MVT::i32: + StrOpc = isThumb ? ARM::t2STRi12 : ARM::STRi12; + break; case MVT::f32: if (!Subtarget->hasVFP2()) return false; StrOpc = ARM::VSTRS; @@ -548,91 +915,162 @@ bool ARMFastISel::ARMEmitStore(EVT VT, unsigned SrcReg, StrOpc = ARM::VSTRD; break; } - - if (isThumb) - AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, - TII.get(StrOpc), SrcReg) - .addReg(DstReg).addImm(Offset).addReg(0)); - else - AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, - TII.get(StrOpc), SrcReg) - .addReg(DstReg).addReg(0).addImm(Offset)); - + // Simplify this down to something we can handle. + ARMSimplifyAddress(Addr, VT); + + // Create the base instruction, then add the operands. + MachineInstrBuilder MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(StrOpc)) + .addReg(SrcReg, getKillRegState(true)); + AddLoadStoreOperands(VT, Addr, MIB); return true; } -bool ARMFastISel::ARMSelectStore(const Instruction *I) { +bool ARMFastISel::SelectStore(const Instruction *I) { Value *Op0 = I->getOperand(0); unsigned SrcReg = 0; - // Yay type legalization - EVT VT; + // Verify we have a legal type before going any further. + MVT VT; if (!isLoadTypeLegal(I->getOperand(0)->getType(), VT)) return false; // Get the value to be stored into a register. SrcReg = getRegForValue(Op0); - if (SrcReg == 0) - return false; - - // If we're an alloca we know we have a frame index and can emit the store - // quickly. - if (ARMStoreAlloca(I, SrcReg)) - return true; - - // Our register and offset with innocuous defaults. - unsigned Reg = 0; - int Offset = 0; - - // See if we can handle this as Reg + Offset - if (!ARMComputeRegOffset(I->getOperand(1), Reg, Offset)) - return false; - - if (!ARMEmitStore(VT, SrcReg, Reg, Offset /* 0 */)) return false; - - return false; - -} + if (SrcReg == 0) return false; -bool ARMFastISel::ARMSelectLoad(const Instruction *I) { - // If we're an alloca we know we have a frame index and can emit the load - // directly in short order. - if (ARMLoadAlloca(I)) - return true; - - // Verify we have a legal type before going any further. - EVT VT; - if (!isLoadTypeLegal(I->getType(), VT)) - return false; - - // Our register and offset with innocuous defaults. - unsigned Reg = 0; - int Offset = 0; - - // See if we can handle this as Reg + Offset - if (!ARMComputeRegOffset(I->getOperand(0), Reg, Offset)) + // See if we can handle this address. + Address Addr; + if (!ARMComputeAddress(I->getOperand(1), Addr)) return false; - - unsigned ResultReg; - if (!ARMEmitLoad(VT, ResultReg, Reg, Offset /* 0 */)) return false; - - UpdateValueMap(I, ResultReg); + + if (!ARMEmitStore(VT, SrcReg, Addr)) return false; return true; } -bool ARMFastISel::ARMSelectBranch(const Instruction *I) { +static ARMCC::CondCodes getComparePred(CmpInst::Predicate Pred) { + switch (Pred) { + // Needs two compares... + case CmpInst::FCMP_ONE: + case CmpInst::FCMP_UEQ: + default: + // AL is our "false" for now. The other two need more compares. + return ARMCC::AL; + case CmpInst::ICMP_EQ: + case CmpInst::FCMP_OEQ: + return ARMCC::EQ; + case CmpInst::ICMP_SGT: + case CmpInst::FCMP_OGT: + return ARMCC::GT; + case CmpInst::ICMP_SGE: + case CmpInst::FCMP_OGE: + return ARMCC::GE; + case CmpInst::ICMP_UGT: + case CmpInst::FCMP_UGT: + return ARMCC::HI; + case CmpInst::FCMP_OLT: + return ARMCC::MI; + case CmpInst::ICMP_ULE: + case CmpInst::FCMP_OLE: + return ARMCC::LS; + case CmpInst::FCMP_ORD: + return ARMCC::VC; + case CmpInst::FCMP_UNO: + return ARMCC::VS; + case CmpInst::FCMP_UGE: + return ARMCC::PL; + case CmpInst::ICMP_SLT: + case CmpInst::FCMP_ULT: + return ARMCC::LT; + case CmpInst::ICMP_SLE: + case CmpInst::FCMP_ULE: + return ARMCC::LE; + case CmpInst::FCMP_UNE: + case CmpInst::ICMP_NE: + return ARMCC::NE; + case CmpInst::ICMP_UGE: + return ARMCC::HS; + case CmpInst::ICMP_ULT: + return ARMCC::LO; + } +} + +bool ARMFastISel::SelectBranch(const Instruction *I) { const BranchInst *BI = cast(I); MachineBasicBlock *TBB = FuncInfo.MBBMap[BI->getSuccessor(0)]; MachineBasicBlock *FBB = FuncInfo.MBBMap[BI->getSuccessor(1)]; - + // Simple branch support. - unsigned CondReg = getRegForValue(BI->getCondition()); - if (CondReg == 0) return false; - - unsigned CmpOpc = isThumb ? ARM::t2CMPrr : ARM::CMPrr; - unsigned BrOpc = isThumb ? ARM::t2Bcc : ARM::Bcc; + + // If we can, avoid recomputing the compare - redoing it could lead to wonky + // behavior. + // TODO: Factor this out. + if (const CmpInst *CI = dyn_cast(BI->getCondition())) { + if (CI->hasOneUse() && (CI->getParent() == I->getParent())) { + MVT VT; + const Type *Ty = CI->getOperand(0)->getType(); + if (!isTypeLegal(Ty, VT)) + return false; + + bool isFloat = (Ty->isDoubleTy() || Ty->isFloatTy()); + if (isFloat && !Subtarget->hasVFP2()) + return false; + + unsigned CmpOpc; + switch (VT.SimpleTy) { + default: return false; + // TODO: Verify compares. + case MVT::f32: + CmpOpc = ARM::VCMPES; + break; + case MVT::f64: + CmpOpc = ARM::VCMPED; + break; + case MVT::i32: + CmpOpc = isThumb ? ARM::t2CMPrr : ARM::CMPrr; + break; + } + + // Get the compare predicate. + ARMCC::CondCodes ARMPred = getComparePred(CI->getPredicate()); + + // We may not handle every CC for now. + if (ARMPred == ARMCC::AL) return false; + + unsigned Arg1 = getRegForValue(CI->getOperand(0)); + if (Arg1 == 0) return false; + + unsigned Arg2 = getRegForValue(CI->getOperand(1)); + if (Arg2 == 0) return false; + + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(CmpOpc)) + .addReg(Arg1).addReg(Arg2)); + + // For floating point we need to move the result to a comparison register + // that we can then use for branches. + if (isFloat) + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(ARM::FMSTAT))); + + unsigned BrOpc = isThumb ? ARM::t2Bcc : ARM::Bcc; + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(BrOpc)) + .addMBB(TBB).addImm(ARMPred).addReg(ARM::CPSR); + FastEmitBranch(FBB, DL); + FuncInfo.MBB->addSuccessor(TBB); + return true; + } + } + + unsigned CmpReg = getRegForValue(BI->getCondition()); + if (CmpReg == 0) return false; + + // Re-set the flags just in case. + unsigned CmpOpc = isThumb ? ARM::t2CMPri : ARM::CMPri; AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(CmpOpc)) - .addReg(CondReg).addReg(CondReg)); + .addReg(CmpReg).addImm(0)); + + unsigned BrOpc = isThumb ? ARM::t2Bcc : ARM::Bcc; BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(BrOpc)) .addMBB(TBB).addImm(ARMCC::NE).addReg(ARM::CPSR); FastEmitBranch(FBB, DL); @@ -640,18 +1078,809 @@ bool ARMFastISel::ARMSelectBranch(const Instruction *I) { return true; } +bool ARMFastISel::SelectCmp(const Instruction *I) { + const CmpInst *CI = cast(I); + + MVT VT; + const Type *Ty = CI->getOperand(0)->getType(); + if (!isTypeLegal(Ty, VT)) + return false; + + bool isFloat = (Ty->isDoubleTy() || Ty->isFloatTy()); + if (isFloat && !Subtarget->hasVFP2()) + return false; + + unsigned CmpOpc; + unsigned CondReg; + switch (VT.SimpleTy) { + default: return false; + // TODO: Verify compares. + case MVT::f32: + CmpOpc = ARM::VCMPES; + CondReg = ARM::FPSCR; + break; + case MVT::f64: + CmpOpc = ARM::VCMPED; + CondReg = ARM::FPSCR; + break; + case MVT::i32: + CmpOpc = isThumb ? ARM::t2CMPrr : ARM::CMPrr; + CondReg = ARM::CPSR; + break; + } + + // Get the compare predicate. + ARMCC::CondCodes ARMPred = getComparePred(CI->getPredicate()); + + // We may not handle every CC for now. + if (ARMPred == ARMCC::AL) return false; + + unsigned Arg1 = getRegForValue(CI->getOperand(0)); + if (Arg1 == 0) return false; + + unsigned Arg2 = getRegForValue(CI->getOperand(1)); + if (Arg2 == 0) return false; + + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(CmpOpc)) + .addReg(Arg1).addReg(Arg2)); + + // For floating point we need to move the result to a comparison register + // that we can then use for branches. + if (isFloat) + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(ARM::FMSTAT))); + + // Now set a register based on the comparison. Explicitly set the predicates + // here. + unsigned MovCCOpc = isThumb ? ARM::t2MOVCCi : ARM::MOVCCi; + TargetRegisterClass *RC = isThumb ? ARM::rGPRRegisterClass + : ARM::GPRRegisterClass; + unsigned DestReg = createResultReg(RC); + Constant *Zero + = ConstantInt::get(Type::getInt32Ty(*Context), 0); + unsigned ZeroReg = TargetMaterializeConstant(Zero); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(MovCCOpc), DestReg) + .addReg(ZeroReg).addImm(1) + .addImm(ARMPred).addReg(CondReg); + + UpdateValueMap(I, DestReg); + return true; +} + +bool ARMFastISel::SelectFPExt(const Instruction *I) { + // Make sure we have VFP and that we're extending float to double. + if (!Subtarget->hasVFP2()) return false; + + Value *V = I->getOperand(0); + if (!I->getType()->isDoubleTy() || + !V->getType()->isFloatTy()) return false; + + unsigned Op = getRegForValue(V); + if (Op == 0) return false; + + unsigned Result = createResultReg(ARM::DPRRegisterClass); + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(ARM::VCVTDS), Result) + .addReg(Op)); + UpdateValueMap(I, Result); + return true; +} + +bool ARMFastISel::SelectFPTrunc(const Instruction *I) { + // Make sure we have VFP and that we're truncating double to float. + if (!Subtarget->hasVFP2()) return false; + + Value *V = I->getOperand(0); + if (!(I->getType()->isFloatTy() && + V->getType()->isDoubleTy())) return false; + + unsigned Op = getRegForValue(V); + if (Op == 0) return false; + + unsigned Result = createResultReg(ARM::SPRRegisterClass); + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(ARM::VCVTSD), Result) + .addReg(Op)); + UpdateValueMap(I, Result); + return true; +} + +bool ARMFastISel::SelectSIToFP(const Instruction *I) { + // Make sure we have VFP. + if (!Subtarget->hasVFP2()) return false; + + MVT DstVT; + const Type *Ty = I->getType(); + if (!isTypeLegal(Ty, DstVT)) + return false; + + unsigned Op = getRegForValue(I->getOperand(0)); + if (Op == 0) return false; + + // The conversion routine works on fp-reg to fp-reg and the operand above + // was an integer, move it to the fp registers if possible. + unsigned FP = ARMMoveToFPReg(MVT::f32, Op); + if (FP == 0) return false; + + unsigned Opc; + if (Ty->isFloatTy()) Opc = ARM::VSITOS; + else if (Ty->isDoubleTy()) Opc = ARM::VSITOD; + else return 0; + + unsigned ResultReg = createResultReg(TLI.getRegClassFor(DstVT)); + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(Opc), + ResultReg) + .addReg(FP)); + UpdateValueMap(I, ResultReg); + return true; +} + +bool ARMFastISel::SelectFPToSI(const Instruction *I) { + // Make sure we have VFP. + if (!Subtarget->hasVFP2()) return false; + + MVT DstVT; + const Type *RetTy = I->getType(); + if (!isTypeLegal(RetTy, DstVT)) + return false; + + unsigned Op = getRegForValue(I->getOperand(0)); + if (Op == 0) return false; + + unsigned Opc; + const Type *OpTy = I->getOperand(0)->getType(); + if (OpTy->isFloatTy()) Opc = ARM::VTOSIZS; + else if (OpTy->isDoubleTy()) Opc = ARM::VTOSIZD; + else return 0; + + // f64->s32 or f32->s32 both need an intermediate f32 reg. + unsigned ResultReg = createResultReg(TLI.getRegClassFor(MVT::f32)); + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(Opc), + ResultReg) + .addReg(Op)); + + // This result needs to be in an integer register, but the conversion only + // takes place in fp-regs. + unsigned IntReg = ARMMoveToIntReg(DstVT, ResultReg); + if (IntReg == 0) return false; + + UpdateValueMap(I, IntReg); + return true; +} + +bool ARMFastISel::SelectSelect(const Instruction *I) { + MVT VT; + if (!isTypeLegal(I->getType(), VT)) + return false; + + // Things need to be register sized for register moves. + if (VT != MVT::i32) return false; + const TargetRegisterClass *RC = TLI.getRegClassFor(VT); + + unsigned CondReg = getRegForValue(I->getOperand(0)); + if (CondReg == 0) return false; + unsigned Op1Reg = getRegForValue(I->getOperand(1)); + if (Op1Reg == 0) return false; + unsigned Op2Reg = getRegForValue(I->getOperand(2)); + if (Op2Reg == 0) return false; + + unsigned CmpOpc = isThumb ? ARM::t2TSTri : ARM::TSTri; + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(CmpOpc)) + .addReg(CondReg).addImm(1)); + unsigned ResultReg = createResultReg(RC); + unsigned MovCCOpc = isThumb ? ARM::t2MOVCCr : ARM::MOVCCr; + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(MovCCOpc), ResultReg) + .addReg(Op1Reg).addReg(Op2Reg) + .addImm(ARMCC::EQ).addReg(ARM::CPSR); + UpdateValueMap(I, ResultReg); + return true; +} + +bool ARMFastISel::SelectSDiv(const Instruction *I) { + MVT VT; + const Type *Ty = I->getType(); + if (!isTypeLegal(Ty, VT)) + return false; + + // If we have integer div support we should have selected this automagically. + // In case we have a real miss go ahead and return false and we'll pick + // it up later. + if (Subtarget->hasDivide()) return false; + + // Otherwise emit a libcall. + RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; + if (VT == MVT::i8) + LC = RTLIB::SDIV_I8; + else if (VT == MVT::i16) + LC = RTLIB::SDIV_I16; + else if (VT == MVT::i32) + LC = RTLIB::SDIV_I32; + else if (VT == MVT::i64) + LC = RTLIB::SDIV_I64; + else if (VT == MVT::i128) + LC = RTLIB::SDIV_I128; + assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unsupported SDIV!"); + + return ARMEmitLibcall(I, LC); +} + +bool ARMFastISel::SelectSRem(const Instruction *I) { + MVT VT; + const Type *Ty = I->getType(); + if (!isTypeLegal(Ty, VT)) + return false; + + RTLIB::Libcall LC = RTLIB::UNKNOWN_LIBCALL; + if (VT == MVT::i8) + LC = RTLIB::SREM_I8; + else if (VT == MVT::i16) + LC = RTLIB::SREM_I16; + else if (VT == MVT::i32) + LC = RTLIB::SREM_I32; + else if (VT == MVT::i64) + LC = RTLIB::SREM_I64; + else if (VT == MVT::i128) + LC = RTLIB::SREM_I128; + assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unsupported SREM!"); + + return ARMEmitLibcall(I, LC); +} + +bool ARMFastISel::SelectBinaryOp(const Instruction *I, unsigned ISDOpcode) { + EVT VT = TLI.getValueType(I->getType(), true); + + // We can get here in the case when we want to use NEON for our fp + // operations, but can't figure out how to. Just use the vfp instructions + // if we have them. + // FIXME: It'd be nice to use NEON instructions. + const Type *Ty = I->getType(); + bool isFloat = (Ty->isDoubleTy() || Ty->isFloatTy()); + if (isFloat && !Subtarget->hasVFP2()) + return false; + + unsigned Op1 = getRegForValue(I->getOperand(0)); + if (Op1 == 0) return false; + + unsigned Op2 = getRegForValue(I->getOperand(1)); + if (Op2 == 0) return false; + + unsigned Opc; + bool is64bit = VT == MVT::f64 || VT == MVT::i64; + switch (ISDOpcode) { + default: return false; + case ISD::FADD: + Opc = is64bit ? ARM::VADDD : ARM::VADDS; + break; + case ISD::FSUB: + Opc = is64bit ? ARM::VSUBD : ARM::VSUBS; + break; + case ISD::FMUL: + Opc = is64bit ? ARM::VMULD : ARM::VMULS; + break; + } + unsigned ResultReg = createResultReg(TLI.getRegClassFor(VT)); + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(Opc), ResultReg) + .addReg(Op1).addReg(Op2)); + UpdateValueMap(I, ResultReg); + return true; +} + +// Call Handling Code + +bool ARMFastISel::FastEmitExtend(ISD::NodeType Opc, EVT DstVT, unsigned Src, + EVT SrcVT, unsigned &ResultReg) { + unsigned RR = FastEmit_r(SrcVT.getSimpleVT(), DstVT.getSimpleVT(), Opc, + Src, /*TODO: Kill=*/false); + + if (RR != 0) { + ResultReg = RR; + return true; + } else + return false; +} + +// This is largely taken directly from CCAssignFnForNode - we don't support +// varargs in FastISel so that part has been removed. +// TODO: We may not support all of this. +CCAssignFn *ARMFastISel::CCAssignFnForCall(CallingConv::ID CC, bool Return) { + switch (CC) { + default: + llvm_unreachable("Unsupported calling convention"); + case CallingConv::Fast: + // Ignore fastcc. Silence compiler warnings. + (void)RetFastCC_ARM_APCS; + (void)FastCC_ARM_APCS; + // Fallthrough + case CallingConv::C: + // Use target triple & subtarget features to do actual dispatch. + if (Subtarget->isAAPCS_ABI()) { + if (Subtarget->hasVFP2() && + FloatABIType == FloatABI::Hard) + return (Return ? RetCC_ARM_AAPCS_VFP: CC_ARM_AAPCS_VFP); + else + return (Return ? RetCC_ARM_AAPCS: CC_ARM_AAPCS); + } else + return (Return ? RetCC_ARM_APCS: CC_ARM_APCS); + case CallingConv::ARM_AAPCS_VFP: + return (Return ? RetCC_ARM_AAPCS_VFP: CC_ARM_AAPCS_VFP); + case CallingConv::ARM_AAPCS: + return (Return ? RetCC_ARM_AAPCS: CC_ARM_AAPCS); + case CallingConv::ARM_APCS: + return (Return ? RetCC_ARM_APCS: CC_ARM_APCS); + } +} + +bool ARMFastISel::ProcessCallArgs(SmallVectorImpl &Args, + SmallVectorImpl &ArgRegs, + SmallVectorImpl &ArgVTs, + SmallVectorImpl &ArgFlags, + SmallVectorImpl &RegArgs, + CallingConv::ID CC, + unsigned &NumBytes) { + SmallVector ArgLocs; + CCState CCInfo(CC, false, TM, ArgLocs, *Context); + CCInfo.AnalyzeCallOperands(ArgVTs, ArgFlags, CCAssignFnForCall(CC, false)); + + // Get a count of how many bytes are to be pushed on the stack. + NumBytes = CCInfo.getNextStackOffset(); + + // Issue CALLSEQ_START + unsigned AdjStackDown = TM.getRegisterInfo()->getCallFrameSetupOpcode(); + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(AdjStackDown)) + .addImm(NumBytes)); + + // Process the args. + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + unsigned Arg = ArgRegs[VA.getValNo()]; + MVT ArgVT = ArgVTs[VA.getValNo()]; + + // We don't handle NEON/vector parameters yet. + if (ArgVT.isVector() || ArgVT.getSizeInBits() > 64) + return false; + + // Handle arg promotion, etc. + switch (VA.getLocInfo()) { + case CCValAssign::Full: break; + case CCValAssign::SExt: { + bool Emitted = FastEmitExtend(ISD::SIGN_EXTEND, VA.getLocVT(), + Arg, ArgVT, Arg); + assert(Emitted && "Failed to emit a sext!"); (void)Emitted; + Emitted = true; + ArgVT = VA.getLocVT(); + break; + } + case CCValAssign::ZExt: { + bool Emitted = FastEmitExtend(ISD::ZERO_EXTEND, VA.getLocVT(), + Arg, ArgVT, Arg); + assert(Emitted && "Failed to emit a zext!"); (void)Emitted; + Emitted = true; + ArgVT = VA.getLocVT(); + break; + } + case CCValAssign::AExt: { + bool Emitted = FastEmitExtend(ISD::ANY_EXTEND, VA.getLocVT(), + Arg, ArgVT, Arg); + if (!Emitted) + Emitted = FastEmitExtend(ISD::ZERO_EXTEND, VA.getLocVT(), + Arg, ArgVT, Arg); + if (!Emitted) + Emitted = FastEmitExtend(ISD::SIGN_EXTEND, VA.getLocVT(), + Arg, ArgVT, Arg); + + assert(Emitted && "Failed to emit a aext!"); (void)Emitted; + ArgVT = VA.getLocVT(); + break; + } + case CCValAssign::BCvt: { + unsigned BC = FastEmit_r(ArgVT, VA.getLocVT(), ISD::BITCAST, Arg, + /*TODO: Kill=*/false); + assert(BC != 0 && "Failed to emit a bitcast!"); + Arg = BC; + ArgVT = VA.getLocVT(); + break; + } + default: llvm_unreachable("Unknown arg promotion!"); + } + + // Now copy/store arg to correct locations. + if (VA.isRegLoc() && !VA.needsCustom()) { + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::COPY), + VA.getLocReg()) + .addReg(Arg); + RegArgs.push_back(VA.getLocReg()); + } else if (VA.needsCustom()) { + // TODO: We need custom lowering for vector (v2f64) args. + if (VA.getLocVT() != MVT::f64) return false; + + CCValAssign &NextVA = ArgLocs[++i]; + + // TODO: Only handle register args for now. + if(!(VA.isRegLoc() && NextVA.isRegLoc())) return false; + + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(ARM::VMOVRRD), VA.getLocReg()) + .addReg(NextVA.getLocReg(), RegState::Define) + .addReg(Arg)); + RegArgs.push_back(VA.getLocReg()); + RegArgs.push_back(NextVA.getLocReg()); + } else { + assert(VA.isMemLoc()); + // Need to store on the stack. + Address Addr; + Addr.BaseType = Address::RegBase; + Addr.Base.Reg = ARM::SP; + Addr.Offset = VA.getLocMemOffset(); + + if (!ARMEmitStore(ArgVT, Arg, Addr)) return false; + } + } + return true; +} + +bool ARMFastISel::FinishCall(MVT RetVT, SmallVectorImpl &UsedRegs, + const Instruction *I, CallingConv::ID CC, + unsigned &NumBytes) { + // Issue CALLSEQ_END + unsigned AdjStackUp = TM.getRegisterInfo()->getCallFrameDestroyOpcode(); + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(AdjStackUp)) + .addImm(NumBytes).addImm(0)); + + // Now the return value. + if (RetVT != MVT::isVoid) { + SmallVector RVLocs; + CCState CCInfo(CC, false, TM, RVLocs, *Context); + CCInfo.AnalyzeCallResult(RetVT, CCAssignFnForCall(CC, true)); + + // Copy all of the result registers out of their specified physreg. + if (RVLocs.size() == 2 && RetVT == MVT::f64) { + // For this move we copy into two registers and then move into the + // double fp reg we want. + EVT DestVT = RVLocs[0].getValVT(); + TargetRegisterClass* DstRC = TLI.getRegClassFor(DestVT); + unsigned ResultReg = createResultReg(DstRC); + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(ARM::VMOVDRR), ResultReg) + .addReg(RVLocs[0].getLocReg()) + .addReg(RVLocs[1].getLocReg())); + + UsedRegs.push_back(RVLocs[0].getLocReg()); + UsedRegs.push_back(RVLocs[1].getLocReg()); + + // Finally update the result. + UpdateValueMap(I, ResultReg); + } else { + assert(RVLocs.size() == 1 &&"Can't handle non-double multi-reg retvals!"); + EVT CopyVT = RVLocs[0].getValVT(); + TargetRegisterClass* DstRC = TLI.getRegClassFor(CopyVT); + + unsigned ResultReg = createResultReg(DstRC); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::COPY), + ResultReg).addReg(RVLocs[0].getLocReg()); + UsedRegs.push_back(RVLocs[0].getLocReg()); + + // Finally update the result. + UpdateValueMap(I, ResultReg); + } + } + + return true; +} + +bool ARMFastISel::SelectRet(const Instruction *I) { + const ReturnInst *Ret = cast(I); + const Function &F = *I->getParent()->getParent(); + + if (!FuncInfo.CanLowerReturn) + return false; + + if (F.isVarArg()) + return false; + + CallingConv::ID CC = F.getCallingConv(); + if (Ret->getNumOperands() > 0) { + SmallVector Outs; + GetReturnInfo(F.getReturnType(), F.getAttributes().getRetAttributes(), + Outs, TLI); + + // Analyze operands of the call, assigning locations to each operand. + SmallVector ValLocs; + CCState CCInfo(CC, F.isVarArg(), TM, ValLocs, I->getContext()); + CCInfo.AnalyzeReturn(Outs, CCAssignFnForCall(CC, true /* is Ret */)); + + const Value *RV = Ret->getOperand(0); + unsigned Reg = getRegForValue(RV); + if (Reg == 0) + return false; + + // Only handle a single return value for now. + if (ValLocs.size() != 1) + return false; + + CCValAssign &VA = ValLocs[0]; + + // Don't bother handling odd stuff for now. + if (VA.getLocInfo() != CCValAssign::Full) + return false; + // Only handle register returns for now. + if (!VA.isRegLoc()) + return false; + // TODO: For now, don't try to handle cases where getLocInfo() + // says Full but the types don't match. + if (TLI.getValueType(RV->getType()) != VA.getValVT()) + return false; + + // Make the copy. + unsigned SrcReg = Reg + VA.getValNo(); + unsigned DstReg = VA.getLocReg(); + const TargetRegisterClass* SrcRC = MRI.getRegClass(SrcReg); + // Avoid a cross-class copy. This is very unlikely. + if (!SrcRC->contains(DstReg)) + return false; + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, TII.get(TargetOpcode::COPY), + DstReg).addReg(SrcReg); + + // Mark the register as live out of the function. + MRI.addLiveOut(VA.getLocReg()); + } + + unsigned RetOpc = isThumb ? ARM::tBX_RET : ARM::BX_RET; + AddOptionalDefs(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(RetOpc))); + return true; +} + +// A quick function that will emit a call for a named libcall in F with the +// vector of passed arguments for the Instruction in I. We can assume that we +// can emit a call for any libcall we can produce. This is an abridged version +// of the full call infrastructure since we won't need to worry about things +// like computed function pointers or strange arguments at call sites. +// TODO: Try to unify this and the normal call bits for ARM, then try to unify +// with X86. +bool ARMFastISel::ARMEmitLibcall(const Instruction *I, RTLIB::Libcall Call) { + CallingConv::ID CC = TLI.getLibcallCallingConv(Call); + + // Handle *simple* calls for now. + const Type *RetTy = I->getType(); + MVT RetVT; + if (RetTy->isVoidTy()) + RetVT = MVT::isVoid; + else if (!isTypeLegal(RetTy, RetVT)) + return false; + + // For now we're using BLX etc on the assumption that we have v5t ops. + if (!Subtarget->hasV5TOps()) return false; + + // TODO: For now if we have long calls specified we don't handle the call. + if (EnableARMLongCalls) return false; + + // Set up the argument vectors. + SmallVector Args; + SmallVector ArgRegs; + SmallVector ArgVTs; + SmallVector ArgFlags; + Args.reserve(I->getNumOperands()); + ArgRegs.reserve(I->getNumOperands()); + ArgVTs.reserve(I->getNumOperands()); + ArgFlags.reserve(I->getNumOperands()); + for (unsigned i = 0; i < I->getNumOperands(); ++i) { + Value *Op = I->getOperand(i); + unsigned Arg = getRegForValue(Op); + if (Arg == 0) return false; + + const Type *ArgTy = Op->getType(); + MVT ArgVT; + if (!isTypeLegal(ArgTy, ArgVT)) return false; + + ISD::ArgFlagsTy Flags; + unsigned OriginalAlignment = TD.getABITypeAlignment(ArgTy); + Flags.setOrigAlign(OriginalAlignment); + + Args.push_back(Op); + ArgRegs.push_back(Arg); + ArgVTs.push_back(ArgVT); + ArgFlags.push_back(Flags); + } + + // Handle the arguments now that we've gotten them. + SmallVector RegArgs; + unsigned NumBytes; + if (!ProcessCallArgs(Args, ArgRegs, ArgVTs, ArgFlags, RegArgs, CC, NumBytes)) + return false; + + // Issue the call, BLXr9 for darwin, BLX otherwise. This uses V5 ops. + // TODO: Turn this into the table of arm call ops. + MachineInstrBuilder MIB; + unsigned CallOpc; + if(isThumb) { + CallOpc = Subtarget->isTargetDarwin() ? ARM::tBLXi_r9 : ARM::tBLXi; + // Explicitly adding the predicate here. + MIB = AddDefaultPred(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(CallOpc))) + .addExternalSymbol(TLI.getLibcallName(Call)); + } else { + CallOpc = Subtarget->isTargetDarwin() ? ARM::BLr9 : ARM::BL; + // Explicitly adding the predicate here. + MIB = AddDefaultPred(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(CallOpc)) + .addExternalSymbol(TLI.getLibcallName(Call))); + } + + // Add implicit physical register uses to the call. + for (unsigned i = 0, e = RegArgs.size(); i != e; ++i) + MIB.addReg(RegArgs[i]); + + // Finish off the call including any return values. + SmallVector UsedRegs; + if (!FinishCall(RetVT, UsedRegs, I, CC, NumBytes)) return false; + + // Set all unused physreg defs as dead. + static_cast(MIB)->setPhysRegsDeadExcept(UsedRegs, TRI); + + return true; +} + +bool ARMFastISel::SelectCall(const Instruction *I) { + const CallInst *CI = cast(I); + const Value *Callee = CI->getCalledValue(); + + // Can't handle inline asm or worry about intrinsics yet. + if (isa(Callee) || isa(CI)) return false; + + // Only handle global variable Callees that are direct calls. + const GlobalValue *GV = dyn_cast(Callee); + if (!GV || Subtarget->GVIsIndirectSymbol(GV, TM.getRelocationModel())) + return false; + + // Check the calling convention. + ImmutableCallSite CS(CI); + CallingConv::ID CC = CS.getCallingConv(); + + // TODO: Avoid some calling conventions? + + // Let SDISel handle vararg functions. + const PointerType *PT = cast(CS.getCalledValue()->getType()); + const FunctionType *FTy = cast(PT->getElementType()); + if (FTy->isVarArg()) + return false; + + // Handle *simple* calls for now. + const Type *RetTy = I->getType(); + MVT RetVT; + if (RetTy->isVoidTy()) + RetVT = MVT::isVoid; + else if (!isTypeLegal(RetTy, RetVT)) + return false; + + // For now we're using BLX etc on the assumption that we have v5t ops. + // TODO: Maybe? + if (!Subtarget->hasV5TOps()) return false; + + // TODO: For now if we have long calls specified we don't handle the call. + if (EnableARMLongCalls) return false; + + // Set up the argument vectors. + SmallVector Args; + SmallVector ArgRegs; + SmallVector ArgVTs; + SmallVector ArgFlags; + Args.reserve(CS.arg_size()); + ArgRegs.reserve(CS.arg_size()); + ArgVTs.reserve(CS.arg_size()); + ArgFlags.reserve(CS.arg_size()); + for (ImmutableCallSite::arg_iterator i = CS.arg_begin(), e = CS.arg_end(); + i != e; ++i) { + unsigned Arg = getRegForValue(*i); + + if (Arg == 0) + return false; + ISD::ArgFlagsTy Flags; + unsigned AttrInd = i - CS.arg_begin() + 1; + if (CS.paramHasAttr(AttrInd, Attribute::SExt)) + Flags.setSExt(); + if (CS.paramHasAttr(AttrInd, Attribute::ZExt)) + Flags.setZExt(); + + // FIXME: Only handle *easy* calls for now. + if (CS.paramHasAttr(AttrInd, Attribute::InReg) || + CS.paramHasAttr(AttrInd, Attribute::StructRet) || + CS.paramHasAttr(AttrInd, Attribute::Nest) || + CS.paramHasAttr(AttrInd, Attribute::ByVal)) + return false; + + const Type *ArgTy = (*i)->getType(); + MVT ArgVT; + if (!isTypeLegal(ArgTy, ArgVT)) + return false; + unsigned OriginalAlignment = TD.getABITypeAlignment(ArgTy); + Flags.setOrigAlign(OriginalAlignment); + + Args.push_back(*i); + ArgRegs.push_back(Arg); + ArgVTs.push_back(ArgVT); + ArgFlags.push_back(Flags); + } + + // Handle the arguments now that we've gotten them. + SmallVector RegArgs; + unsigned NumBytes; + if (!ProcessCallArgs(Args, ArgRegs, ArgVTs, ArgFlags, RegArgs, CC, NumBytes)) + return false; + + // Issue the call, BLXr9 for darwin, BLX otherwise. This uses V5 ops. + // TODO: Turn this into the table of arm call ops. + MachineInstrBuilder MIB; + unsigned CallOpc; + // Explicitly adding the predicate here. + if(isThumb) { + CallOpc = Subtarget->isTargetDarwin() ? ARM::tBLXi_r9 : ARM::tBLXi; + // Explicitly adding the predicate here. + MIB = AddDefaultPred(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(CallOpc))) + .addGlobalAddress(GV, 0, 0); + } else { + CallOpc = Subtarget->isTargetDarwin() ? ARM::BLr9 : ARM::BL; + // Explicitly adding the predicate here. + MIB = AddDefaultPred(BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, + TII.get(CallOpc)) + .addGlobalAddress(GV, 0, 0)); + } + + // Add implicit physical register uses to the call. + for (unsigned i = 0, e = RegArgs.size(); i != e; ++i) + MIB.addReg(RegArgs[i]); + + // Finish off the call including any return values. + SmallVector UsedRegs; + if (!FinishCall(RetVT, UsedRegs, I, CC, NumBytes)) return false; + + // Set all unused physreg defs as dead. + static_cast(MIB)->setPhysRegsDeadExcept(UsedRegs, TRI); + + return true; + +} + // TODO: SoftFP support. bool ARMFastISel::TargetSelectInstruction(const Instruction *I) { - // No Thumb-1 for now. - if (isThumb && !AFI->isThumb2Function()) return false; - + switch (I->getOpcode()) { case Instruction::Load: - return ARMSelectLoad(I); + return SelectLoad(I); case Instruction::Store: - return ARMSelectStore(I); + return SelectStore(I); case Instruction::Br: - return ARMSelectBranch(I); + return SelectBranch(I); + case Instruction::ICmp: + case Instruction::FCmp: + return SelectCmp(I); + case Instruction::FPExt: + return SelectFPExt(I); + case Instruction::FPTrunc: + return SelectFPTrunc(I); + case Instruction::SIToFP: + return SelectSIToFP(I); + case Instruction::FPToSI: + return SelectFPToSI(I); + case Instruction::FAdd: + return SelectBinaryOp(I, ISD::FADD); + case Instruction::FSub: + return SelectBinaryOp(I, ISD::FSUB); + case Instruction::FMul: + return SelectBinaryOp(I, ISD::FMUL); + case Instruction::SDiv: + return SelectSDiv(I); + case Instruction::SRem: + return SelectSRem(I); + case Instruction::Call: + return SelectCall(I); + case Instruction::Select: + return SelectSelect(I); + case Instruction::Ret: + return SelectRet(I); default: break; } return false; @@ -659,7 +1888,14 @@ bool ARMFastISel::TargetSelectInstruction(const Instruction *I) { namespace llvm { llvm::FastISel *ARM::createFastISel(FunctionLoweringInfo &funcInfo) { - if (EnableARMFastISel) return new ARMFastISel(funcInfo); + // Completely untested on non-darwin. + const TargetMachine &TM = funcInfo.MF->getTarget(); + + // Darwin and thumb1 only for now. + const ARMSubtarget *Subtarget = &TM.getSubtarget(); + if (Subtarget->isTargetDarwin() && !Subtarget->isThumb1Only() && + !DisableARMFastISel) + return new ARMFastISel(funcInfo); return 0; } } diff --git a/lib/Target/ARM/ARMFixupKinds.h b/lib/Target/ARM/ARMFixupKinds.h new file mode 100644 index 000000000000..3d175e386901 --- /dev/null +++ b/lib/Target/ARM/ARMFixupKinds.h @@ -0,0 +1,97 @@ +//===-- ARM/ARMFixupKinds.h - ARM Specific Fixup Entries --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ARM_ARMFIXUPKINDS_H +#define LLVM_ARM_ARMFIXUPKINDS_H + +#include "llvm/MC/MCFixup.h" + +namespace llvm { +namespace ARM { +enum Fixups { + // fixup_arm_ldst_pcrel_12 - 12-bit PC relative relocation for symbol + // addresses + fixup_arm_ldst_pcrel_12 = FirstTargetFixupKind, + + // fixup_t2_ldst_pcrel_12 - Equivalent to fixup_arm_ldst_pcrel_12, with + // the 16-bit halfwords reordered. + fixup_t2_ldst_pcrel_12, + + // fixup_arm_pcrel_10 - 10-bit PC relative relocation for symbol addresses + // used in VFP instructions where the lower 2 bits are not encoded + // (so it's encoded as an 8-bit immediate). + fixup_arm_pcrel_10, + // fixup_t2_pcrel_10 - Equivalent to fixup_arm_pcrel_10, accounting for + // the short-swapped encoding of Thumb2 instructions. + fixup_t2_pcrel_10, + // fixup_thumb_adr_pcrel_10 - 10-bit PC relative relocation for symbol + // addresses where the lower 2 bits are not encoded (so it's encoded as an + // 8-bit immediate). + fixup_thumb_adr_pcrel_10, + // fixup_arm_adr_pcrel_12 - 12-bit PC relative relocation for the ADR + // instruction. + fixup_arm_adr_pcrel_12, + // fixup_t2_adr_pcrel_12 - 12-bit PC relative relocation for the ADR + // instruction. + fixup_t2_adr_pcrel_12, + // fixup_arm_condbranch - 24-bit PC relative relocation for conditional branch + // instructions. + fixup_arm_condbranch, + // fixup_arm_uncondbranch - 24-bit PC relative relocation for + // branch instructions. (unconditional) + fixup_arm_uncondbranch, + // fixup_t2_condbranch - 20-bit PC relative relocation for Thumb2 direct + // uconditional branch instructions. + fixup_t2_condbranch, + // fixup_t2_uncondbranch - 20-bit PC relative relocation for Thumb2 direct + // branch unconditional branch instructions. + fixup_t2_uncondbranch, + + // fixup_arm_thumb_br - 12-bit fixup for Thumb B instructions. + fixup_arm_thumb_br, + + // fixup_arm_thumb_blx - Fixup for Thumb BL instructions. + fixup_arm_thumb_bl, + + // fixup_arm_thumb_blx - Fixup for Thumb BLX instructions. + fixup_arm_thumb_blx, + + // fixup_arm_thumb_cb - Fixup for Thumb branch instructions. + fixup_arm_thumb_cb, + + // fixup_arm_thumb_cp - Fixup for Thumb load/store from constant pool instrs. + fixup_arm_thumb_cp, + + // fixup_arm_thumb_bcc - Fixup for Thumb conditional branching instructions. + fixup_arm_thumb_bcc, + + // The next two are for the movt/movw pair + // the 16bit imm field are split into imm{15-12} and imm{11-0} + fixup_arm_movt_hi16, // :upper16: + fixup_arm_movw_lo16, // :lower16: + fixup_t2_movt_hi16, // :upper16: + fixup_t2_movw_lo16, // :lower16: + + // It is possible to create an "immediate" that happens to be pcrel. + // movw r0, :lower16:Foo-(Bar+8) and movt r0, :upper16:Foo-(Bar+8) + // result in different reloc tags than the above two. + // Needed to support ELF::R_ARM_MOVT_PREL and ELF::R_ARM_MOVW_PREL_NC + fixup_arm_movt_hi16_pcrel, // :upper16: + fixup_arm_movw_lo16_pcrel, // :lower16: + fixup_t2_movt_hi16_pcrel, // :upper16: + fixup_t2_movw_lo16_pcrel, // :lower16: + + // Marker + LastTargetFixupKind, + NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind +}; +} +} + +#endif diff --git a/lib/Target/ARM/ARMFrameInfo.h b/lib/Target/ARM/ARMFrameInfo.h deleted file mode 100644 index d5dae2442499..000000000000 --- a/lib/Target/ARM/ARMFrameInfo.h +++ /dev/null @@ -1,32 +0,0 @@ -//===-- ARMTargetFrameInfo.h - Define TargetFrameInfo for ARM ---*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// -// -//===----------------------------------------------------------------------===// - -#ifndef ARM_FRAMEINFO_H -#define ARM_FRAMEINFO_H - -#include "ARM.h" -#include "ARMSubtarget.h" -#include "llvm/Target/TargetFrameInfo.h" - -namespace llvm { - -class ARMFrameInfo : public TargetFrameInfo { -public: - explicit ARMFrameInfo(const ARMSubtarget &ST) - : TargetFrameInfo(StackGrowsDown, ST.getStackAlignment(), 0, 4) { - } -}; - -} // End llvm namespace - -#endif diff --git a/lib/Target/ARM/ARMFrameLowering.cpp b/lib/Target/ARM/ARMFrameLowering.cpp new file mode 100644 index 000000000000..f42c6db84fd3 --- /dev/null +++ b/lib/Target/ARM/ARMFrameLowering.cpp @@ -0,0 +1,1021 @@ +//=======- ARMFrameLowering.cpp - ARM Frame Information --------*- C++ -*-====// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the ARM implementation of TargetFrameLowering class. +// +//===----------------------------------------------------------------------===// + +#include "ARMFrameLowering.h" +#include "ARMAddressingModes.h" +#include "ARMBaseInstrInfo.h" +#include "ARMBaseRegisterInfo.h" +#include "ARMMachineFunctionInfo.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/Target/TargetOptions.h" + +using namespace llvm; + +/// hasFP - Return true if the specified function should have a dedicated frame +/// pointer register. This is true if the function has variable sized allocas +/// or if frame pointer elimination is disabled. +bool ARMFrameLowering::hasFP(const MachineFunction &MF) const { + const TargetRegisterInfo *RegInfo = MF.getTarget().getRegisterInfo(); + + // Mac OS X requires FP not to be clobbered for backtracing purpose. + if (STI.isTargetDarwin()) + return true; + + const MachineFrameInfo *MFI = MF.getFrameInfo(); + // Always eliminate non-leaf frame pointers. + return ((DisableFramePointerElim(MF) && MFI->hasCalls()) || + RegInfo->needsStackRealignment(MF) || + MFI->hasVarSizedObjects() || + MFI->isFrameAddressTaken()); +} + +/// hasReservedCallFrame - Under normal circumstances, when a frame pointer is +/// not required, we reserve argument space for call sites in the function +/// immediately on entry to the current function. This eliminates the need for +/// add/sub sp brackets around call sites. Returns true if the call frame is +/// included as part of the stack frame. +bool ARMFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const { + const MachineFrameInfo *FFI = MF.getFrameInfo(); + unsigned CFSize = FFI->getMaxCallFrameSize(); + // It's not always a good idea to include the call frame as part of the + // stack frame. ARM (especially Thumb) has small immediate offset to + // address the stack frame. So a large call frame can cause poor codegen + // and may even makes it impossible to scavenge a register. + if (CFSize >= ((1 << 12) - 1) / 2) // Half of imm12 + return false; + + return !MF.getFrameInfo()->hasVarSizedObjects(); +} + +/// canSimplifyCallFramePseudos - If there is a reserved call frame, the +/// call frame pseudos can be simplified. Unlike most targets, having a FP +/// is not sufficient here since we still may reference some objects via SP +/// even when FP is available in Thumb2 mode. +bool +ARMFrameLowering::canSimplifyCallFramePseudos(const MachineFunction &MF) const { + return hasReservedCallFrame(MF) || MF.getFrameInfo()->hasVarSizedObjects(); +} + +static bool isCalleeSavedRegister(unsigned Reg, const unsigned *CSRegs) { + for (unsigned i = 0; CSRegs[i]; ++i) + if (Reg == CSRegs[i]) + return true; + return false; +} + +static bool isCSRestore(MachineInstr *MI, + const ARMBaseInstrInfo &TII, + const unsigned *CSRegs) { + // Integer spill area is handled with "pop". + if (MI->getOpcode() == ARM::LDMIA_RET || + MI->getOpcode() == ARM::t2LDMIA_RET || + MI->getOpcode() == ARM::LDMIA_UPD || + MI->getOpcode() == ARM::t2LDMIA_UPD || + MI->getOpcode() == ARM::VLDMDIA_UPD) { + // The first two operands are predicates. The last two are + // imp-def and imp-use of SP. Check everything in between. + for (int i = 5, e = MI->getNumOperands(); i != e; ++i) + if (!isCalleeSavedRegister(MI->getOperand(i).getReg(), CSRegs)) + return false; + return true; + } + if ((MI->getOpcode() == ARM::LDR_POST || + MI->getOpcode() == ARM::t2LDR_POST) && + isCalleeSavedRegister(MI->getOperand(0).getReg(), CSRegs) && + MI->getOperand(1).getReg() == ARM::SP) + return true; + + return false; +} + +static void +emitSPUpdate(bool isARM, + MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, + DebugLoc dl, const ARMBaseInstrInfo &TII, + int NumBytes, + ARMCC::CondCodes Pred = ARMCC::AL, unsigned PredReg = 0) { + if (isARM) + emitARMRegPlusImmediate(MBB, MBBI, dl, ARM::SP, ARM::SP, NumBytes, + Pred, PredReg, TII); + else + emitT2RegPlusImmediate(MBB, MBBI, dl, ARM::SP, ARM::SP, NumBytes, + Pred, PredReg, TII); +} + +void ARMFrameLowering::emitPrologue(MachineFunction &MF) const { + MachineBasicBlock &MBB = MF.front(); + MachineBasicBlock::iterator MBBI = MBB.begin(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + ARMFunctionInfo *AFI = MF.getInfo(); + const ARMBaseRegisterInfo *RegInfo = + static_cast(MF.getTarget().getRegisterInfo()); + const ARMBaseInstrInfo &TII = + *static_cast(MF.getTarget().getInstrInfo()); + assert(!AFI->isThumb1OnlyFunction() && + "This emitPrologue does not support Thumb1!"); + bool isARM = !AFI->isThumbFunction(); + unsigned VARegSaveSize = AFI->getVarArgsRegSaveSize(); + unsigned NumBytes = MFI->getStackSize(); + const std::vector &CSI = MFI->getCalleeSavedInfo(); + DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); + unsigned FramePtr = RegInfo->getFrameRegister(MF); + + // Determine the sizes of each callee-save spill areas and record which frame + // belongs to which callee-save spill areas. + unsigned GPRCS1Size = 0, GPRCS2Size = 0, DPRCSSize = 0; + int FramePtrSpillFI = 0; + + // Allocate the vararg register save area. This is not counted in NumBytes. + if (VARegSaveSize) + emitSPUpdate(isARM, MBB, MBBI, dl, TII, -VARegSaveSize); + + if (!AFI->hasStackFrame()) { + if (NumBytes != 0) + emitSPUpdate(isARM, MBB, MBBI, dl, TII, -NumBytes); + return; + } + + for (unsigned i = 0, e = CSI.size(); i != e; ++i) { + unsigned Reg = CSI[i].getReg(); + int FI = CSI[i].getFrameIdx(); + switch (Reg) { + case ARM::R4: + case ARM::R5: + case ARM::R6: + case ARM::R7: + case ARM::LR: + if (Reg == FramePtr) + FramePtrSpillFI = FI; + AFI->addGPRCalleeSavedArea1Frame(FI); + GPRCS1Size += 4; + break; + case ARM::R8: + case ARM::R9: + case ARM::R10: + case ARM::R11: + if (Reg == FramePtr) + FramePtrSpillFI = FI; + if (STI.isTargetDarwin()) { + AFI->addGPRCalleeSavedArea2Frame(FI); + GPRCS2Size += 4; + } else { + AFI->addGPRCalleeSavedArea1Frame(FI); + GPRCS1Size += 4; + } + break; + default: + AFI->addDPRCalleeSavedAreaFrame(FI); + DPRCSSize += 8; + } + } + + // Move past area 1. + if (GPRCS1Size > 0) MBBI++; + + // Set FP to point to the stack slot that contains the previous FP. + // For Darwin, FP is R7, which has now been stored in spill area 1. + // Otherwise, if this is not Darwin, all the callee-saved registers go + // into spill area 1, including the FP in R11. In either case, it is + // now safe to emit this assignment. + bool HasFP = hasFP(MF); + if (HasFP) { + unsigned ADDriOpc = !AFI->isThumbFunction() ? ARM::ADDri : ARM::t2ADDri; + MachineInstrBuilder MIB = + BuildMI(MBB, MBBI, dl, TII.get(ADDriOpc), FramePtr) + .addFrameIndex(FramePtrSpillFI).addImm(0); + AddDefaultCC(AddDefaultPred(MIB)); + } + + // Move past area 2. + if (GPRCS2Size > 0) MBBI++; + + // Determine starting offsets of spill areas. + unsigned DPRCSOffset = NumBytes - (GPRCS1Size + GPRCS2Size + DPRCSSize); + unsigned GPRCS2Offset = DPRCSOffset + DPRCSSize; + unsigned GPRCS1Offset = GPRCS2Offset + GPRCS2Size; + if (HasFP) + AFI->setFramePtrSpillOffset(MFI->getObjectOffset(FramePtrSpillFI) + + NumBytes); + AFI->setGPRCalleeSavedArea1Offset(GPRCS1Offset); + AFI->setGPRCalleeSavedArea2Offset(GPRCS2Offset); + AFI->setDPRCalleeSavedAreaOffset(DPRCSOffset); + + // Move past area 3. + if (DPRCSSize > 0) MBBI++; + + NumBytes = DPRCSOffset; + if (NumBytes) { + // Adjust SP after all the callee-save spills. + emitSPUpdate(isARM, MBB, MBBI, dl, TII, -NumBytes); + if (HasFP && isARM) + // Restore from fp only in ARM mode: e.g. sub sp, r7, #24 + // Note it's not safe to do this in Thumb2 mode because it would have + // taken two instructions: + // mov sp, r7 + // sub sp, #24 + // If an interrupt is taken between the two instructions, then sp is in + // an inconsistent state (pointing to the middle of callee-saved area). + // The interrupt handler can end up clobbering the registers. + AFI->setShouldRestoreSPFromFP(true); + } + + if (STI.isTargetELF() && hasFP(MF)) + MFI->setOffsetAdjustment(MFI->getOffsetAdjustment() - + AFI->getFramePtrSpillOffset()); + + AFI->setGPRCalleeSavedArea1Size(GPRCS1Size); + AFI->setGPRCalleeSavedArea2Size(GPRCS2Size); + AFI->setDPRCalleeSavedAreaSize(DPRCSSize); + + // If we need dynamic stack realignment, do it here. Be paranoid and make + // sure if we also have VLAs, we have a base pointer for frame access. + if (RegInfo->needsStackRealignment(MF)) { + unsigned MaxAlign = MFI->getMaxAlignment(); + assert (!AFI->isThumb1OnlyFunction()); + if (!AFI->isThumbFunction()) { + // Emit bic sp, sp, MaxAlign + AddDefaultCC(AddDefaultPred(BuildMI(MBB, MBBI, dl, + TII.get(ARM::BICri), ARM::SP) + .addReg(ARM::SP, RegState::Kill) + .addImm(MaxAlign-1))); + } else { + // We cannot use sp as source/dest register here, thus we're emitting the + // following sequence: + // mov r4, sp + // bic r4, r4, MaxAlign + // mov sp, r4 + // FIXME: It will be better just to find spare register here. + BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2tgpr), ARM::R4) + .addReg(ARM::SP, RegState::Kill); + AddDefaultCC(AddDefaultPred(BuildMI(MBB, MBBI, dl, + TII.get(ARM::t2BICri), ARM::R4) + .addReg(ARM::R4, RegState::Kill) + .addImm(MaxAlign-1))); + BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVtgpr2gpr), ARM::SP) + .addReg(ARM::R4, RegState::Kill); + } + + AFI->setShouldRestoreSPFromFP(true); + } + + // If we need a base pointer, set it up here. It's whatever the value + // of the stack pointer is at this point. Any variable size objects + // will be allocated after this, so we can still use the base pointer + // to reference locals. + if (RegInfo->hasBasePointer(MF)) { + if (isARM) + BuildMI(MBB, MBBI, dl, + TII.get(ARM::MOVr), RegInfo->getBaseRegister()) + .addReg(ARM::SP) + .addImm((unsigned)ARMCC::AL).addReg(0).addReg(0); + else + BuildMI(MBB, MBBI, dl, + TII.get(ARM::tMOVgpr2gpr), RegInfo->getBaseRegister()) + .addReg(ARM::SP); + } + + // If the frame has variable sized objects then the epilogue must restore + // the sp from fp. We can assume there's an FP here since hasFP already + // checks for hasVarSizedObjects. + if (MFI->hasVarSizedObjects()) + AFI->setShouldRestoreSPFromFP(true); +} + +void ARMFrameLowering::emitEpilogue(MachineFunction &MF, + MachineBasicBlock &MBB) const { + MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); + assert(MBBI->getDesc().isReturn() && + "Can only insert epilog into returning blocks"); + unsigned RetOpcode = MBBI->getOpcode(); + DebugLoc dl = MBBI->getDebugLoc(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + ARMFunctionInfo *AFI = MF.getInfo(); + const TargetRegisterInfo *RegInfo = MF.getTarget().getRegisterInfo(); + const ARMBaseInstrInfo &TII = + *static_cast(MF.getTarget().getInstrInfo()); + assert(!AFI->isThumb1OnlyFunction() && + "This emitEpilogue does not support Thumb1!"); + bool isARM = !AFI->isThumbFunction(); + + unsigned VARegSaveSize = AFI->getVarArgsRegSaveSize(); + int NumBytes = (int)MFI->getStackSize(); + unsigned FramePtr = RegInfo->getFrameRegister(MF); + + if (!AFI->hasStackFrame()) { + if (NumBytes != 0) + emitSPUpdate(isARM, MBB, MBBI, dl, TII, NumBytes); + } else { + // Unwind MBBI to point to first LDR / VLDRD. + const unsigned *CSRegs = RegInfo->getCalleeSavedRegs(); + if (MBBI != MBB.begin()) { + do + --MBBI; + while (MBBI != MBB.begin() && isCSRestore(MBBI, TII, CSRegs)); + if (!isCSRestore(MBBI, TII, CSRegs)) + ++MBBI; + } + + // Move SP to start of FP callee save spill area. + NumBytes -= (AFI->getGPRCalleeSavedArea1Size() + + AFI->getGPRCalleeSavedArea2Size() + + AFI->getDPRCalleeSavedAreaSize()); + + // Reset SP based on frame pointer only if the stack frame extends beyond + // frame pointer stack slot or target is ELF and the function has FP. + if (AFI->shouldRestoreSPFromFP()) { + NumBytes = AFI->getFramePtrSpillOffset() - NumBytes; + if (NumBytes) { + if (isARM) + emitARMRegPlusImmediate(MBB, MBBI, dl, ARM::SP, FramePtr, -NumBytes, + ARMCC::AL, 0, TII); + else { + // It's not possible to restore SP from FP in a single instruction. + // For Darwin, this looks like: + // mov sp, r7 + // sub sp, #24 + // This is bad, if an interrupt is taken after the mov, sp is in an + // inconsistent state. + // Use the first callee-saved register as a scratch register. + assert(MF.getRegInfo().isPhysRegUsed(ARM::R4) && + "No scratch register to restore SP from FP!"); + emitT2RegPlusImmediate(MBB, MBBI, dl, ARM::R4, FramePtr, -NumBytes, + ARMCC::AL, 0, TII); + BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2gpr), ARM::SP) + .addReg(ARM::R4); + } + } else { + // Thumb2 or ARM. + if (isARM) + BuildMI(MBB, MBBI, dl, TII.get(ARM::MOVr), ARM::SP) + .addReg(FramePtr).addImm((unsigned)ARMCC::AL).addReg(0).addReg(0); + else + BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2gpr), ARM::SP) + .addReg(FramePtr); + } + } else if (NumBytes) + emitSPUpdate(isARM, MBB, MBBI, dl, TII, NumBytes); + + // Increment past our save areas. + if (AFI->getDPRCalleeSavedAreaSize()) MBBI++; + if (AFI->getGPRCalleeSavedArea2Size()) MBBI++; + if (AFI->getGPRCalleeSavedArea1Size()) MBBI++; + } + + if (RetOpcode == ARM::TCRETURNdi || RetOpcode == ARM::TCRETURNdiND || + RetOpcode == ARM::TCRETURNri || RetOpcode == ARM::TCRETURNriND) { + // Tail call return: adjust the stack pointer and jump to callee. + MBBI = MBB.getLastNonDebugInstr(); + MachineOperand &JumpTarget = MBBI->getOperand(0); + + // Jump to label or value in register. + if (RetOpcode == ARM::TCRETURNdi || RetOpcode == ARM::TCRETURNdiND) { + unsigned TCOpcode = (RetOpcode == ARM::TCRETURNdi) + ? (STI.isThumb() ? ARM::TAILJMPdt : ARM::TAILJMPd) + : (STI.isThumb() ? ARM::TAILJMPdNDt : ARM::TAILJMPdND); + MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII.get(TCOpcode)); + if (JumpTarget.isGlobal()) + MIB.addGlobalAddress(JumpTarget.getGlobal(), JumpTarget.getOffset(), + JumpTarget.getTargetFlags()); + else { + assert(JumpTarget.isSymbol()); + MIB.addExternalSymbol(JumpTarget.getSymbolName(), + JumpTarget.getTargetFlags()); + } + } else if (RetOpcode == ARM::TCRETURNri) { + BuildMI(MBB, MBBI, dl, TII.get(ARM::TAILJMPr)). + addReg(JumpTarget.getReg(), RegState::Kill); + } else if (RetOpcode == ARM::TCRETURNriND) { + BuildMI(MBB, MBBI, dl, TII.get(ARM::TAILJMPrND)). + addReg(JumpTarget.getReg(), RegState::Kill); + } + + MachineInstr *NewMI = prior(MBBI); + for (unsigned i = 1, e = MBBI->getNumOperands(); i != e; ++i) + NewMI->addOperand(MBBI->getOperand(i)); + + // Delete the pseudo instruction TCRETURN. + MBB.erase(MBBI); + } + + if (VARegSaveSize) + emitSPUpdate(isARM, MBB, MBBI, dl, TII, VARegSaveSize); +} + +/// getFrameIndexReference - Provide a base+offset reference to an FI slot for +/// debug info. It's the same as what we use for resolving the code-gen +/// references for now. FIXME: This can go wrong when references are +/// SP-relative and simple call frames aren't used. +int +ARMFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI, + unsigned &FrameReg) const { + return ResolveFrameIndexReference(MF, FI, FrameReg, 0); +} + +int +ARMFrameLowering::ResolveFrameIndexReference(const MachineFunction &MF, + int FI, + unsigned &FrameReg, + int SPAdj) const { + const MachineFrameInfo *MFI = MF.getFrameInfo(); + const ARMBaseRegisterInfo *RegInfo = + static_cast(MF.getTarget().getRegisterInfo()); + const ARMFunctionInfo *AFI = MF.getInfo(); + int Offset = MFI->getObjectOffset(FI) + MFI->getStackSize(); + int FPOffset = Offset - AFI->getFramePtrSpillOffset(); + bool isFixed = MFI->isFixedObjectIndex(FI); + + FrameReg = ARM::SP; + Offset += SPAdj; + if (AFI->isGPRCalleeSavedArea1Frame(FI)) + return Offset - AFI->getGPRCalleeSavedArea1Offset(); + else if (AFI->isGPRCalleeSavedArea2Frame(FI)) + return Offset - AFI->getGPRCalleeSavedArea2Offset(); + else if (AFI->isDPRCalleeSavedAreaFrame(FI)) + return Offset - AFI->getDPRCalleeSavedAreaOffset(); + + // When dynamically realigning the stack, use the frame pointer for + // parameters, and the stack/base pointer for locals. + if (RegInfo->needsStackRealignment(MF)) { + assert (hasFP(MF) && "dynamic stack realignment without a FP!"); + if (isFixed) { + FrameReg = RegInfo->getFrameRegister(MF); + Offset = FPOffset; + } else if (MFI->hasVarSizedObjects()) { + assert(RegInfo->hasBasePointer(MF) && + "VLAs and dynamic stack alignment, but missing base pointer!"); + FrameReg = RegInfo->getBaseRegister(); + } + return Offset; + } + + // If there is a frame pointer, use it when we can. + if (hasFP(MF) && AFI->hasStackFrame()) { + // Use frame pointer to reference fixed objects. Use it for locals if + // there are VLAs (and thus the SP isn't reliable as a base). + if (isFixed || (MFI->hasVarSizedObjects() && + !RegInfo->hasBasePointer(MF))) { + FrameReg = RegInfo->getFrameRegister(MF); + return FPOffset; + } else if (MFI->hasVarSizedObjects()) { + assert(RegInfo->hasBasePointer(MF) && "missing base pointer!"); + // Try to use the frame pointer if we can, else use the base pointer + // since it's available. This is handy for the emergency spill slot, in + // particular. + if (AFI->isThumb2Function()) { + if (FPOffset >= -255 && FPOffset < 0) { + FrameReg = RegInfo->getFrameRegister(MF); + return FPOffset; + } + } else + FrameReg = RegInfo->getBaseRegister(); + } else if (AFI->isThumb2Function()) { + // In Thumb2 mode, the negative offset is very limited. Try to avoid + // out of range references. + if (FPOffset >= -255 && FPOffset < 0) { + FrameReg = RegInfo->getFrameRegister(MF); + return FPOffset; + } + } else if (Offset > (FPOffset < 0 ? -FPOffset : FPOffset)) { + // Otherwise, use SP or FP, whichever is closer to the stack slot. + FrameReg = RegInfo->getFrameRegister(MF); + return FPOffset; + } + } + // Use the base pointer if we have one. + if (RegInfo->hasBasePointer(MF)) + FrameReg = RegInfo->getBaseRegister(); + return Offset; +} + +int ARMFrameLowering::getFrameIndexOffset(const MachineFunction &MF, + int FI) const { + unsigned FrameReg; + return getFrameIndexReference(MF, FI, FrameReg); +} + +void ARMFrameLowering::emitPushInst(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector &CSI, + unsigned StmOpc, unsigned StrOpc, + bool NoGap, + bool(*Func)(unsigned, bool)) const { + MachineFunction &MF = *MBB.getParent(); + const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); + + DebugLoc DL; + if (MI != MBB.end()) DL = MI->getDebugLoc(); + + SmallVector, 4> Regs; + unsigned i = CSI.size(); + while (i != 0) { + unsigned LastReg = 0; + for (; i != 0; --i) { + unsigned Reg = CSI[i-1].getReg(); + if (!(Func)(Reg, STI.isTargetDarwin())) continue; + + // Add the callee-saved register as live-in unless it's LR and + // @llvm.returnaddress is called. If LR is returned for + // @llvm.returnaddress then it's already added to the function and + // entry block live-in sets. + bool isKill = true; + if (Reg == ARM::LR) { + if (MF.getFrameInfo()->isReturnAddressTaken() && + MF.getRegInfo().isLiveIn(Reg)) + isKill = false; + } + + if (isKill) + MBB.addLiveIn(Reg); + + // If NoGap is true, push consecutive registers and then leave the rest + // for other instructions. e.g. + // vpush {d8, d10, d11} -> vpush {d8}, vpush {d10, d11} + if (NoGap && LastReg && LastReg != Reg-1) + break; + LastReg = Reg; + Regs.push_back(std::make_pair(Reg, isKill)); + } + + if (Regs.empty()) + continue; + if (Regs.size() > 1 || StrOpc== 0) { + MachineInstrBuilder MIB = + AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(StmOpc), ARM::SP) + .addReg(ARM::SP)); + for (unsigned i = 0, e = Regs.size(); i < e; ++i) + MIB.addReg(Regs[i].first, getKillRegState(Regs[i].second)); + } else if (Regs.size() == 1) { + MachineInstrBuilder MIB = BuildMI(MBB, MI, DL, TII.get(StrOpc), + ARM::SP) + .addReg(Regs[0].first, getKillRegState(Regs[0].second)) + .addReg(ARM::SP); + // ARM mode needs an extra reg0 here due to addrmode2. Will go away once + // that refactoring is complete (eventually). + if (StrOpc == ARM::STR_PRE) { + MIB.addReg(0); + MIB.addImm(ARM_AM::getAM2Opc(ARM_AM::sub, 4, ARM_AM::no_shift)); + } else + MIB.addImm(-4); + AddDefaultPred(MIB); + } + Regs.clear(); + } +} + +void ARMFrameLowering::emitPopInst(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector &CSI, + unsigned LdmOpc, unsigned LdrOpc, + bool isVarArg, bool NoGap, + bool(*Func)(unsigned, bool)) const { + MachineFunction &MF = *MBB.getParent(); + const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo(); + ARMFunctionInfo *AFI = MF.getInfo(); + DebugLoc DL = MI->getDebugLoc(); + unsigned RetOpcode = MI->getOpcode(); + bool isTailCall = (RetOpcode == ARM::TCRETURNdi || + RetOpcode == ARM::TCRETURNdiND || + RetOpcode == ARM::TCRETURNri || + RetOpcode == ARM::TCRETURNriND); + + SmallVector Regs; + unsigned i = CSI.size(); + while (i != 0) { + unsigned LastReg = 0; + bool DeleteRet = false; + for (; i != 0; --i) { + unsigned Reg = CSI[i-1].getReg(); + if (!(Func)(Reg, STI.isTargetDarwin())) continue; + + if (Reg == ARM::LR && !isTailCall && !isVarArg && STI.hasV5TOps()) { + Reg = ARM::PC; + LdmOpc = AFI->isThumbFunction() ? ARM::t2LDMIA_RET : ARM::LDMIA_RET; + // Fold the return instruction into the LDM. + DeleteRet = true; + } + + // If NoGap is true, pop consecutive registers and then leave the rest + // for other instructions. e.g. + // vpop {d8, d10, d11} -> vpop {d8}, vpop {d10, d11} + if (NoGap && LastReg && LastReg != Reg-1) + break; + + LastReg = Reg; + Regs.push_back(Reg); + } + + if (Regs.empty()) + continue; + if (Regs.size() > 1 || LdrOpc == 0) { + MachineInstrBuilder MIB = + AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(LdmOpc), ARM::SP) + .addReg(ARM::SP)); + for (unsigned i = 0, e = Regs.size(); i < e; ++i) + MIB.addReg(Regs[i], getDefRegState(true)); + if (DeleteRet) + MI->eraseFromParent(); + MI = MIB; + } else if (Regs.size() == 1) { + // If we adjusted the reg to PC from LR above, switch it back here. We + // only do that for LDM. + if (Regs[0] == ARM::PC) + Regs[0] = ARM::LR; + MachineInstrBuilder MIB = + BuildMI(MBB, MI, DL, TII.get(LdrOpc), Regs[0]) + .addReg(ARM::SP, RegState::Define) + .addReg(ARM::SP); + // ARM mode needs an extra reg0 here due to addrmode2. Will go away once + // that refactoring is complete (eventually). + if (LdrOpc == ARM::LDR_POST) { + MIB.addReg(0); + MIB.addImm(ARM_AM::getAM2Opc(ARM_AM::add, 4, ARM_AM::no_shift)); + } else + MIB.addImm(4); + AddDefaultPred(MIB); + } + Regs.clear(); + } +} + +bool ARMFrameLowering::spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector &CSI, + const TargetRegisterInfo *TRI) const { + if (CSI.empty()) + return false; + + MachineFunction &MF = *MBB.getParent(); + ARMFunctionInfo *AFI = MF.getInfo(); + + unsigned PushOpc = AFI->isThumbFunction() ? ARM::t2STMDB_UPD : ARM::STMDB_UPD; + unsigned PushOneOpc = AFI->isThumbFunction() ? ARM::t2STR_PRE : ARM::STR_PRE; + unsigned FltOpc = ARM::VSTMDDB_UPD; + emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false, &isARMArea1Register); + emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false, &isARMArea2Register); + emitPushInst(MBB, MI, CSI, FltOpc, 0, true, &isARMArea3Register); + + return true; +} + +bool ARMFrameLowering::restoreCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector &CSI, + const TargetRegisterInfo *TRI) const { + if (CSI.empty()) + return false; + + MachineFunction &MF = *MBB.getParent(); + ARMFunctionInfo *AFI = MF.getInfo(); + bool isVarArg = AFI->getVarArgsRegSaveSize() > 0; + + unsigned PopOpc = AFI->isThumbFunction() ? ARM::t2LDMIA_UPD : ARM::LDMIA_UPD; + unsigned LdrOpc = AFI->isThumbFunction() ? ARM::t2LDR_POST : ARM::LDR_POST; + unsigned FltOpc = ARM::VLDMDIA_UPD; + emitPopInst(MBB, MI, CSI, FltOpc, 0, isVarArg, true, &isARMArea3Register); + emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false, + &isARMArea2Register); + emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false, + &isARMArea1Register); + + return true; +} + +// FIXME: Make generic? +static unsigned GetFunctionSizeInBytes(const MachineFunction &MF, + const ARMBaseInstrInfo &TII) { + unsigned FnSize = 0; + for (MachineFunction::const_iterator MBBI = MF.begin(), E = MF.end(); + MBBI != E; ++MBBI) { + const MachineBasicBlock &MBB = *MBBI; + for (MachineBasicBlock::const_iterator I = MBB.begin(),E = MBB.end(); + I != E; ++I) + FnSize += TII.GetInstSizeInBytes(I); + } + return FnSize; +} + +/// estimateStackSize - Estimate and return the size of the frame. +/// FIXME: Make generic? +static unsigned estimateStackSize(MachineFunction &MF) { + const MachineFrameInfo *FFI = MF.getFrameInfo(); + int Offset = 0; + for (int i = FFI->getObjectIndexBegin(); i != 0; ++i) { + int FixedOff = -FFI->getObjectOffset(i); + if (FixedOff > Offset) Offset = FixedOff; + } + for (unsigned i = 0, e = FFI->getObjectIndexEnd(); i != e; ++i) { + if (FFI->isDeadObjectIndex(i)) + continue; + Offset += FFI->getObjectSize(i); + unsigned Align = FFI->getObjectAlignment(i); + // Adjust to alignment boundary + Offset = (Offset+Align-1)/Align*Align; + } + return (unsigned)Offset; +} + +/// estimateRSStackSizeLimit - Look at each instruction that references stack +/// frames and return the stack size limit beyond which some of these +/// instructions will require a scratch register during their expansion later. +// FIXME: Move to TII? +static unsigned estimateRSStackSizeLimit(MachineFunction &MF, + const TargetFrameLowering *TFI) { + const ARMFunctionInfo *AFI = MF.getInfo(); + unsigned Limit = (1 << 12) - 1; + for (MachineFunction::iterator BB = MF.begin(),E = MF.end(); BB != E; ++BB) { + for (MachineBasicBlock::iterator I = BB->begin(), E = BB->end(); + I != E; ++I) { + for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) { + if (!I->getOperand(i).isFI()) continue; + + // When using ADDri to get the address of a stack object, 255 is the + // largest offset guaranteed to fit in the immediate offset. + if (I->getOpcode() == ARM::ADDri) { + Limit = std::min(Limit, (1U << 8) - 1); + break; + } + + // Otherwise check the addressing mode. + switch (I->getDesc().TSFlags & ARMII::AddrModeMask) { + case ARMII::AddrMode3: + case ARMII::AddrModeT2_i8: + Limit = std::min(Limit, (1U << 8) - 1); + break; + case ARMII::AddrMode5: + case ARMII::AddrModeT2_i8s4: + Limit = std::min(Limit, ((1U << 8) - 1) * 4); + break; + case ARMII::AddrModeT2_i12: + // i12 supports only positive offset so these will be converted to + // i8 opcodes. See llvm::rewriteT2FrameIndex. + if (TFI->hasFP(MF) && AFI->hasStackFrame()) + Limit = std::min(Limit, (1U << 8) - 1); + break; + case ARMII::AddrMode4: + case ARMII::AddrMode6: + // Addressing modes 4 & 6 (load/store) instructions can't encode an + // immediate offset for stack references. + return 0; + default: + break; + } + break; // At most one FI per instruction + } + } + } + + return Limit; +} + +void +ARMFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF, + RegScavenger *RS) const { + // This tells PEI to spill the FP as if it is any other callee-save register + // to take advantage the eliminateFrameIndex machinery. This also ensures it + // is spilled in the order specified by getCalleeSavedRegs() to make it easier + // to combine multiple loads / stores. + bool CanEliminateFrame = true; + bool CS1Spilled = false; + bool LRSpilled = false; + unsigned NumGPRSpills = 0; + SmallVector UnspilledCS1GPRs; + SmallVector UnspilledCS2GPRs; + const ARMBaseRegisterInfo *RegInfo = + static_cast(MF.getTarget().getRegisterInfo()); + const ARMBaseInstrInfo &TII = + *static_cast(MF.getTarget().getInstrInfo()); + ARMFunctionInfo *AFI = MF.getInfo(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + unsigned FramePtr = RegInfo->getFrameRegister(MF); + + // Spill R4 if Thumb2 function requires stack realignment - it will be used as + // scratch register. Also spill R4 if Thumb2 function has varsized objects, + // since it's not always possible to restore sp from fp in a single + // instruction. + // FIXME: It will be better just to find spare register here. + if (AFI->isThumb2Function() && + (MFI->hasVarSizedObjects() || RegInfo->needsStackRealignment(MF))) + MF.getRegInfo().setPhysRegUsed(ARM::R4); + + if (AFI->isThumb1OnlyFunction()) { + // Spill LR if Thumb1 function uses variable length argument lists. + if (AFI->getVarArgsRegSaveSize() > 0) + MF.getRegInfo().setPhysRegUsed(ARM::LR); + + // Spill R4 if Thumb1 epilogue has to restore SP from FP since + // FIXME: It will be better just to find spare register here. + if (MFI->hasVarSizedObjects()) + MF.getRegInfo().setPhysRegUsed(ARM::R4); + } + + // Spill the BasePtr if it's used. + if (RegInfo->hasBasePointer(MF)) + MF.getRegInfo().setPhysRegUsed(RegInfo->getBaseRegister()); + + // Don't spill FP if the frame can be eliminated. This is determined + // by scanning the callee-save registers to see if any is used. + const unsigned *CSRegs = RegInfo->getCalleeSavedRegs(); + for (unsigned i = 0; CSRegs[i]; ++i) { + unsigned Reg = CSRegs[i]; + bool Spilled = false; + if (MF.getRegInfo().isPhysRegUsed(Reg)) { + Spilled = true; + CanEliminateFrame = false; + } else { + // Check alias registers too. + for (const unsigned *Aliases = + RegInfo->getAliasSet(Reg); *Aliases; ++Aliases) { + if (MF.getRegInfo().isPhysRegUsed(*Aliases)) { + Spilled = true; + CanEliminateFrame = false; + } + } + } + + if (!ARM::GPRRegisterClass->contains(Reg)) + continue; + + if (Spilled) { + NumGPRSpills++; + + if (!STI.isTargetDarwin()) { + if (Reg == ARM::LR) + LRSpilled = true; + CS1Spilled = true; + continue; + } + + // Keep track if LR and any of R4, R5, R6, and R7 is spilled. + switch (Reg) { + case ARM::LR: + LRSpilled = true; + // Fallthrough + case ARM::R4: case ARM::R5: + case ARM::R6: case ARM::R7: + CS1Spilled = true; + break; + default: + break; + } + } else { + if (!STI.isTargetDarwin()) { + UnspilledCS1GPRs.push_back(Reg); + continue; + } + + switch (Reg) { + case ARM::R4: case ARM::R5: + case ARM::R6: case ARM::R7: + case ARM::LR: + UnspilledCS1GPRs.push_back(Reg); + break; + default: + UnspilledCS2GPRs.push_back(Reg); + break; + } + } + } + + bool ForceLRSpill = false; + if (!LRSpilled && AFI->isThumb1OnlyFunction()) { + unsigned FnSize = GetFunctionSizeInBytes(MF, TII); + // Force LR to be spilled if the Thumb function size is > 2048. This enables + // use of BL to implement far jump. If it turns out that it's not needed + // then the branch fix up path will undo it. + if (FnSize >= (1 << 11)) { + CanEliminateFrame = false; + ForceLRSpill = true; + } + } + + // If any of the stack slot references may be out of range of an immediate + // offset, make sure a register (or a spill slot) is available for the + // register scavenger. Note that if we're indexing off the frame pointer, the + // effective stack size is 4 bytes larger since the FP points to the stack + // slot of the previous FP. Also, if we have variable sized objects in the + // function, stack slot references will often be negative, and some of + // our instructions are positive-offset only, so conservatively consider + // that case to want a spill slot (or register) as well. Similarly, if + // the function adjusts the stack pointer during execution and the + // adjustments aren't already part of our stack size estimate, our offset + // calculations may be off, so be conservative. + // FIXME: We could add logic to be more precise about negative offsets + // and which instructions will need a scratch register for them. Is it + // worth the effort and added fragility? + bool BigStack = + (RS && + (estimateStackSize(MF) + ((hasFP(MF) && AFI->hasStackFrame()) ? 4:0) >= + estimateRSStackSizeLimit(MF, this))) + || MFI->hasVarSizedObjects() + || (MFI->adjustsStack() && !canSimplifyCallFramePseudos(MF)); + + bool ExtraCSSpill = false; + if (BigStack || !CanEliminateFrame || RegInfo->cannotEliminateFrame(MF)) { + AFI->setHasStackFrame(true); + + // If LR is not spilled, but at least one of R4, R5, R6, and R7 is spilled. + // Spill LR as well so we can fold BX_RET to the registers restore (LDM). + if (!LRSpilled && CS1Spilled) { + MF.getRegInfo().setPhysRegUsed(ARM::LR); + NumGPRSpills++; + UnspilledCS1GPRs.erase(std::find(UnspilledCS1GPRs.begin(), + UnspilledCS1GPRs.end(), (unsigned)ARM::LR)); + ForceLRSpill = false; + ExtraCSSpill = true; + } + + if (hasFP(MF)) { + MF.getRegInfo().setPhysRegUsed(FramePtr); + NumGPRSpills++; + } + + // If stack and double are 8-byte aligned and we are spilling an odd number + // of GPRs, spill one extra callee save GPR so we won't have to pad between + // the integer and double callee save areas. + unsigned TargetAlign = getStackAlignment(); + if (TargetAlign == 8 && (NumGPRSpills & 1)) { + if (CS1Spilled && !UnspilledCS1GPRs.empty()) { + for (unsigned i = 0, e = UnspilledCS1GPRs.size(); i != e; ++i) { + unsigned Reg = UnspilledCS1GPRs[i]; + // Don't spill high register if the function is thumb1 + if (!AFI->isThumb1OnlyFunction() || + isARMLowRegister(Reg) || Reg == ARM::LR) { + MF.getRegInfo().setPhysRegUsed(Reg); + if (!RegInfo->isReservedReg(MF, Reg)) + ExtraCSSpill = true; + break; + } + } + } else if (!UnspilledCS2GPRs.empty() && !AFI->isThumb1OnlyFunction()) { + unsigned Reg = UnspilledCS2GPRs.front(); + MF.getRegInfo().setPhysRegUsed(Reg); + if (!RegInfo->isReservedReg(MF, Reg)) + ExtraCSSpill = true; + } + } + + // Estimate if we might need to scavenge a register at some point in order + // to materialize a stack offset. If so, either spill one additional + // callee-saved register or reserve a special spill slot to facilitate + // register scavenging. Thumb1 needs a spill slot for stack pointer + // adjustments also, even when the frame itself is small. + if (BigStack && !ExtraCSSpill) { + // If any non-reserved CS register isn't spilled, just spill one or two + // extra. That should take care of it! + unsigned NumExtras = TargetAlign / 4; + SmallVector Extras; + while (NumExtras && !UnspilledCS1GPRs.empty()) { + unsigned Reg = UnspilledCS1GPRs.back(); + UnspilledCS1GPRs.pop_back(); + if (!RegInfo->isReservedReg(MF, Reg) && + (!AFI->isThumb1OnlyFunction() || isARMLowRegister(Reg) || + Reg == ARM::LR)) { + Extras.push_back(Reg); + NumExtras--; + } + } + // For non-Thumb1 functions, also check for hi-reg CS registers + if (!AFI->isThumb1OnlyFunction()) { + while (NumExtras && !UnspilledCS2GPRs.empty()) { + unsigned Reg = UnspilledCS2GPRs.back(); + UnspilledCS2GPRs.pop_back(); + if (!RegInfo->isReservedReg(MF, Reg)) { + Extras.push_back(Reg); + NumExtras--; + } + } + } + if (Extras.size() && NumExtras == 0) { + for (unsigned i = 0, e = Extras.size(); i != e; ++i) { + MF.getRegInfo().setPhysRegUsed(Extras[i]); + } + } else if (!AFI->isThumb1OnlyFunction()) { + // note: Thumb1 functions spill to R12, not the stack. Reserve a slot + // closest to SP or frame pointer. + const TargetRegisterClass *RC = ARM::GPRRegisterClass; + RS->setScavengingFrameIndex(MFI->CreateStackObject(RC->getSize(), + RC->getAlignment(), + false)); + } + } + } + + if (ForceLRSpill) { + MF.getRegInfo().setPhysRegUsed(ARM::LR); + AFI->setLRIsSpilledForFarJump(true); + } +} diff --git a/lib/Target/ARM/ARMFrameLowering.h b/lib/Target/ARM/ARMFrameLowering.h new file mode 100644 index 000000000000..1288b706c599 --- /dev/null +++ b/lib/Target/ARM/ARMFrameLowering.h @@ -0,0 +1,74 @@ +//==-- ARMTargetFrameLowering.h - Define frame lowering for ARM --*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +// +//===----------------------------------------------------------------------===// + +#ifndef ARM_FRAMEINFO_H +#define ARM_FRAMEINFO_H + +#include "ARM.h" +#include "ARMSubtarget.h" +#include "llvm/Target/TargetFrameLowering.h" + +namespace llvm { + class ARMSubtarget; + +class ARMFrameLowering : public TargetFrameLowering { +protected: + const ARMSubtarget &STI; + +public: + explicit ARMFrameLowering(const ARMSubtarget &sti) + : TargetFrameLowering(StackGrowsDown, sti.getStackAlignment(), 0, 4), + STI(sti) { + } + + /// emitProlog/emitEpilog - These methods insert prolog and epilog code into + /// the function. + void emitPrologue(MachineFunction &MF) const; + void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const; + + bool spillCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector &CSI, + const TargetRegisterInfo *TRI) const; + + bool restoreCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector &CSI, + const TargetRegisterInfo *TRI) const; + + bool hasFP(const MachineFunction &MF) const; + bool hasReservedCallFrame(const MachineFunction &MF) const; + bool canSimplifyCallFramePseudos(const MachineFunction &MF) const; + int getFrameIndexReference(const MachineFunction &MF, int FI, + unsigned &FrameReg) const; + int ResolveFrameIndexReference(const MachineFunction &MF, int FI, + unsigned &FrameReg, int SPAdj) const; + int getFrameIndexOffset(const MachineFunction &MF, int FI) const; + + void processFunctionBeforeCalleeSavedScan(MachineFunction &MF, + RegScavenger *RS) const; + + private: + void emitPushInst(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, + const std::vector &CSI, unsigned StmOpc, + unsigned StrOpc, bool NoGap, + bool(*Func)(unsigned, bool)) const; + void emitPopInst(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, + const std::vector &CSI, unsigned LdmOpc, + unsigned LdrOpc, bool isVarArg, bool NoGap, + bool(*Func)(unsigned, bool)) const; +}; + +} // End llvm namespace + +#endif diff --git a/lib/Target/ARM/ARMGlobalMerge.cpp b/lib/Target/ARM/ARMGlobalMerge.cpp index 85b0c6c248d0..3f0238387a2b 100644 --- a/lib/Target/ARM/ARMGlobalMerge.cpp +++ b/lib/Target/ARM/ARMGlobalMerge.cpp @@ -12,7 +12,8 @@ // global). Such a transformation can significantly reduce the register pressure // when many globals are involved. // -// For example, consider the code which touches several global variables at once: +// For example, consider the code which touches several global variables at +// once: // // static int foo[N], bar[N], baz[N]; // @@ -48,7 +49,7 @@ // str r0, [r5], #4 // // note that we saved 2 registers here almostly "for free". -// ===----------------------------------------------------------------------===// +// ===---------------------------------------------------------------------===// #define DEBUG_TYPE "arm-global-merge" #include "ARM.h" @@ -64,16 +65,17 @@ #include "llvm/Pass.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetLowering.h" +#include "llvm/Target/TargetLoweringObjectFile.h" using namespace llvm; namespace { - class LLVM_LIBRARY_VISIBILITY ARMGlobalMerge : public FunctionPass { + class ARMGlobalMerge : public FunctionPass { /// TLI - Keep a pointer of a TargetLowering to consult for determining /// target type sizes. const TargetLowering *TLI; bool doMerge(SmallVectorImpl &Globals, - Module &M, bool) const; + Module &M, bool isConst) const; public: static char ID; // Pass identification, replacement for typeid. @@ -81,7 +83,7 @@ namespace { : FunctionPass(ID), TLI(tli) {} virtual bool doInitialization(Module &M); - virtual bool runOnFunction(Function& F); + virtual bool runOnFunction(Function &F); const char *getPassName() const { return "Merge internal globals"; @@ -95,13 +97,11 @@ namespace { struct GlobalCmp { const TargetData *TD; - GlobalCmp(const TargetData *td): - TD(td) { } + GlobalCmp(const TargetData *td) : TD(td) { } - bool operator() (const GlobalVariable* GV1, - const GlobalVariable* GV2) { - const Type* Ty1 = cast(GV1->getType())->getElementType(); - const Type* Ty2 = cast(GV2->getType())->getElementType(); + bool operator()(const GlobalVariable *GV1, const GlobalVariable *GV2) { + const Type *Ty1 = cast(GV1->getType())->getElementType(); + const Type *Ty2 = cast(GV2->getType())->getElementType(); return (TD->getTypeAllocSize(Ty1) < TD->getTypeAllocSize(Ty2)); } @@ -130,27 +130,27 @@ bool ARMGlobalMerge::doMerge(SmallVectorImpl &Globals, uint64_t MergedSize = 0; std::vector Tys; std::vector Inits; - for (j = i; MergedSize < MaxOffset && j != e; ++j) { - const Type* Ty = Globals[j]->getType()->getElementType(); + for (j = i; j != e; ++j) { + const Type *Ty = Globals[j]->getType()->getElementType(); + MergedSize += TD->getTypeAllocSize(Ty); + if (MergedSize > MaxOffset) { + break; + } Tys.push_back(Ty); Inits.push_back(Globals[j]->getInitializer()); - MergedSize += TD->getTypeAllocSize(Ty); } - StructType* MergedTy = StructType::get(M.getContext(), Tys); - Constant* MergedInit = ConstantStruct::get(MergedTy, Inits); - GlobalVariable* MergedGV = new GlobalVariable(M, MergedTy, isConst, + StructType *MergedTy = StructType::get(M.getContext(), Tys); + Constant *MergedInit = ConstantStruct::get(MergedTy, Inits); + GlobalVariable *MergedGV = new GlobalVariable(M, MergedTy, isConst, GlobalValue::InternalLinkage, - MergedInit, "merged"); + MergedInit, "_MergedGlobals"); for (size_t k = i; k < j; ++k) { - SmallVector Idx; - Idx.push_back(ConstantInt::get(Int32Ty, 0)); - Idx.push_back(ConstantInt::get(Int32Ty, k-i)); - - Constant* GEP = - ConstantExpr::getInBoundsGetElementPtr(MergedGV, - &Idx[0], Idx.size()); - + Constant *Idx[2] = { + ConstantInt::get(Int32Ty, 0), + ConstantInt::get(Int32Ty, k-i) + }; + Constant *GEP = ConstantExpr::getInBoundsGetElementPtr(MergedGV, Idx, 2); Globals[k]->replaceAllUsesWith(GEP); Globals[k]->eraseFromParent(); } @@ -161,8 +161,8 @@ bool ARMGlobalMerge::doMerge(SmallVectorImpl &Globals, } -bool ARMGlobalMerge::doInitialization(Module& M) { - SmallVector Globals, ConstGlobals; +bool ARMGlobalMerge::doInitialization(Module &M) { + SmallVector Globals, ConstGlobals, BSSGlobals; const TargetData *TD = TLI->getTargetData(); unsigned MaxOffset = TLI->getMaximalGlobalOffset(); bool Changed = false; @@ -183,8 +183,11 @@ bool ARMGlobalMerge::doInitialization(Module& M) { I->getName().startswith(".llvm.")) continue; - if (TD->getTypeAllocSize(I->getType()) < MaxOffset) { - if (I->isConstant()) + if (TD->getTypeAllocSize(I->getType()->getElementType()) < MaxOffset) { + const TargetLoweringObjectFile &TLOF = TLI->getObjFileLowering(); + if (TLOF.getKindForGlobal(I, TLI->getTargetMachine()).isBSSLocal()) + BSSGlobals.push_back(I); + else if (I->isConstant()) ConstGlobals.push_back(I); else Globals.push_back(I); @@ -193,17 +196,19 @@ bool ARMGlobalMerge::doInitialization(Module& M) { if (Globals.size() > 1) Changed |= doMerge(Globals, M, false); + if (BSSGlobals.size() > 1) + Changed |= doMerge(BSSGlobals, M, false); + // FIXME: This currently breaks the EH processing due to way how the // typeinfo detection works. We might want to detect the TIs and ignore // them in the future. - // if (ConstGlobals.size() > 1) // Changed |= doMerge(ConstGlobals, M, true); return Changed; } -bool ARMGlobalMerge::runOnFunction(Function& F) { +bool ARMGlobalMerge::runOnFunction(Function &F) { return false; } diff --git a/lib/Target/ARM/ARMHazardRecognizer.cpp b/lib/Target/ARM/ARMHazardRecognizer.cpp new file mode 100644 index 000000000000..676b01e91c53 --- /dev/null +++ b/lib/Target/ARM/ARMHazardRecognizer.cpp @@ -0,0 +1,121 @@ +//===-- ARMHazardRecognizer.cpp - ARM postra hazard recognizer ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ARMHazardRecognizer.h" +#include "ARMBaseInstrInfo.h" +#include "ARMBaseRegisterInfo.h" +#include "ARMSubtarget.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/ScheduleDAG.h" +#include "llvm/Target/TargetRegisterInfo.h" +using namespace llvm; + +static bool hasRAWHazard(MachineInstr *DefMI, MachineInstr *MI, + const TargetRegisterInfo &TRI) { + // FIXME: Detect integer instructions properly. + const TargetInstrDesc &TID = MI->getDesc(); + unsigned Domain = TID.TSFlags & ARMII::DomainMask; + if (Domain == ARMII::DomainVFP) { + unsigned Opcode = MI->getOpcode(); + if (Opcode == ARM::VSTRS || Opcode == ARM::VSTRD || + Opcode == ARM::VMOVRS || Opcode == ARM::VMOVRRD) + return false; + } else if (Domain == ARMII::DomainNEON) { + if (MI->getDesc().mayStore() || MI->getDesc().mayLoad()) + return false; + } else + return false; + return MI->readsRegister(DefMI->getOperand(0).getReg(), &TRI); +} + +ScheduleHazardRecognizer::HazardType +ARMHazardRecognizer::getHazardType(SUnit *SU, int Stalls) { + assert(Stalls == 0 && "ARM hazards don't support scoreboard lookahead"); + + MachineInstr *MI = SU->getInstr(); + + if (!MI->isDebugValue()) { + if (ITBlockSize && MI != ITBlockMIs[ITBlockSize-1]) + return Hazard; + + // Look for special VMLA / VMLS hazards. A VMUL / VADD / VSUB following + // a VMLA / VMLS will cause 4 cycle stall. + const TargetInstrDesc &TID = MI->getDesc(); + if (LastMI && (TID.TSFlags & ARMII::DomainMask) != ARMII::DomainGeneral) { + MachineInstr *DefMI = LastMI; + const TargetInstrDesc &LastTID = LastMI->getDesc(); + // Skip over one non-VFP / NEON instruction. + if (!LastTID.isBarrier() && + (LastTID.TSFlags & ARMII::DomainMask) == ARMII::DomainGeneral) { + MachineBasicBlock::iterator I = LastMI; + if (I != LastMI->getParent()->begin()) { + I = llvm::prior(I); + DefMI = &*I; + } + } + + if (TII.isFpMLxInstruction(DefMI->getOpcode()) && + (TII.canCauseFpMLxStall(MI->getOpcode()) || + hasRAWHazard(DefMI, MI, TRI))) { + // Try to schedule another instruction for the next 4 cycles. + if (FpMLxStalls == 0) + FpMLxStalls = 4; + return Hazard; + } + } + } + + return ScoreboardHazardRecognizer::getHazardType(SU, Stalls); +} + +void ARMHazardRecognizer::Reset() { + LastMI = 0; + FpMLxStalls = 0; + ITBlockSize = 0; + ScoreboardHazardRecognizer::Reset(); +} + +void ARMHazardRecognizer::EmitInstruction(SUnit *SU) { + MachineInstr *MI = SU->getInstr(); + unsigned Opcode = MI->getOpcode(); + if (ITBlockSize) { + --ITBlockSize; + } else if (Opcode == ARM::t2IT) { + unsigned Mask = MI->getOperand(1).getImm(); + unsigned NumTZ = CountTrailingZeros_32(Mask); + assert(NumTZ <= 3 && "Invalid IT mask!"); + ITBlockSize = 4 - NumTZ; + MachineBasicBlock::iterator I = MI; + for (unsigned i = 0; i < ITBlockSize; ++i) { + // Advance to the next instruction, skipping any dbg_value instructions. + do { + ++I; + } while (I->isDebugValue()); + ITBlockMIs[ITBlockSize-1-i] = &*I; + } + } + + if (!MI->isDebugValue()) { + LastMI = MI; + FpMLxStalls = 0; + } + + ScoreboardHazardRecognizer::EmitInstruction(SU); +} + +void ARMHazardRecognizer::AdvanceCycle() { + if (FpMLxStalls && --FpMLxStalls == 0) + // Stalled for 4 cycles but still can't schedule any other instructions. + LastMI = 0; + ScoreboardHazardRecognizer::AdvanceCycle(); +} + +void ARMHazardRecognizer::RecedeCycle() { + llvm_unreachable("reverse ARM hazard checking unsupported"); +} diff --git a/lib/Target/ARM/ARMHazardRecognizer.h b/lib/Target/ARM/ARMHazardRecognizer.h new file mode 100644 index 000000000000..2bc218d8566b --- /dev/null +++ b/lib/Target/ARM/ARMHazardRecognizer.h @@ -0,0 +1,54 @@ +//===-- ARMHazardRecognizer.h - ARM Hazard Recognizers ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines hazard recognizers for scheduling ARM functions. +// +//===----------------------------------------------------------------------===// + +#ifndef ARMHAZARDRECOGNIZER_H +#define ARMHAZARDRECOGNIZER_H + +#include "llvm/CodeGen/ScoreboardHazardRecognizer.h" + +namespace llvm { + +class ARMBaseInstrInfo; +class ARMBaseRegisterInfo; +class ARMSubtarget; +class MachineInstr; + +class ARMHazardRecognizer : public ScoreboardHazardRecognizer { + const ARMBaseInstrInfo &TII; + const ARMBaseRegisterInfo &TRI; + const ARMSubtarget &STI; + + MachineInstr *LastMI; + unsigned FpMLxStalls; + unsigned ITBlockSize; // No. of MIs in current IT block yet to be scheduled. + MachineInstr *ITBlockMIs[4]; + +public: + ARMHazardRecognizer(const InstrItineraryData *ItinData, + const ARMBaseInstrInfo &tii, + const ARMBaseRegisterInfo &tri, + const ARMSubtarget &sti, + const ScheduleDAG *DAG) : + ScoreboardHazardRecognizer(ItinData, DAG, "post-RA-sched"), TII(tii), + TRI(tri), STI(sti), LastMI(0), ITBlockSize(0) {} + + virtual HazardType getHazardType(SUnit *SU, int Stalls); + virtual void Reset(); + virtual void EmitInstruction(SUnit *SU); + virtual void AdvanceCycle(); + virtual void RecedeCycle(); +}; + +} // end namespace llvm + +#endif // ARMHAZARDRECOGNIZER_H diff --git a/lib/Target/ARM/ARMISelDAGToDAG.cpp b/lib/Target/ARM/ARMISelDAGToDAG.cpp index 51a30c158dd1..a506cffdba34 100644 --- a/lib/Target/ARM/ARMISelDAGToDAG.cpp +++ b/lib/Target/ARM/ARMISelDAGToDAG.cpp @@ -13,6 +13,7 @@ #define DEBUG_TYPE "arm-isel" #include "ARM.h" +#include "ARMBaseInstrInfo.h" #include "ARMAddressingModes.h" #include "ARMTargetMachine.h" #include "llvm/CallingConv.h" @@ -41,13 +42,25 @@ DisableShifterOp("disable-shifter-op", cl::Hidden, cl::desc("Disable isel of shifter-op"), cl::init(false)); +static cl::opt +CheckVMLxHazard("check-vmlx-hazard", cl::Hidden, + cl::desc("Check fp vmla / vmls hazard at isel time"), + cl::init(false)); + //===--------------------------------------------------------------------===// /// ARMDAGToDAGISel - ARM specific code to select ARM machine /// instructions for SelectionDAG operations. /// namespace { + +enum AddrMode2Type { + AM2_BASE, // Simple AM2 (+-imm12) + AM2_SHOP // Shifter-op AM2 +}; + class ARMDAGToDAGISel : public SelectionDAGISel { ARMBaseTargetMachine &TM; + const ARMBaseInstrInfo *TII; /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can /// make the right decision when generating code for different targets. @@ -57,7 +70,8 @@ public: explicit ARMDAGToDAGISel(ARMBaseTargetMachine &tm, CodeGenOpt::Level OptLevel) : SelectionDAGISel(tm, OptLevel), TM(tm), - Subtarget(&TM.getSubtarget()) { + TII(static_cast(TM.getInstrInfo())), + Subtarget(&TM.getSubtarget()) { } virtual const char *getPassName() const { @@ -72,60 +86,101 @@ public: SDNode *Select(SDNode *N); - bool SelectShifterOperandReg(SDNode *Op, SDValue N, SDValue &A, + + bool hasNoVMLxHazardUse(SDNode *N) const; + bool isShifterOpProfitable(const SDValue &Shift, + ARM_AM::ShiftOpc ShOpcVal, unsigned ShAmt); + bool SelectShifterOperandReg(SDValue N, SDValue &A, SDValue &B, SDValue &C); - bool SelectAddrMode2(SDNode *Op, SDValue N, SDValue &Base, - SDValue &Offset, SDValue &Opc); + bool SelectShiftShifterOperandReg(SDValue N, SDValue &A, + SDValue &B, SDValue &C); + bool SelectAddrModeImm12(SDValue N, SDValue &Base, SDValue &OffImm); + bool SelectLdStSOReg(SDValue N, SDValue &Base, SDValue &Offset, SDValue &Opc); + + AddrMode2Type SelectAddrMode2Worker(SDValue N, SDValue &Base, + SDValue &Offset, SDValue &Opc); + bool SelectAddrMode2Base(SDValue N, SDValue &Base, SDValue &Offset, + SDValue &Opc) { + return SelectAddrMode2Worker(N, Base, Offset, Opc) == AM2_BASE; + } + + bool SelectAddrMode2ShOp(SDValue N, SDValue &Base, SDValue &Offset, + SDValue &Opc) { + return SelectAddrMode2Worker(N, Base, Offset, Opc) == AM2_SHOP; + } + + bool SelectAddrMode2(SDValue N, SDValue &Base, SDValue &Offset, + SDValue &Opc) { + SelectAddrMode2Worker(N, Base, Offset, Opc); +// return SelectAddrMode2ShOp(N, Base, Offset, Opc); + // This always matches one way or another. + return true; + } + bool SelectAddrMode2Offset(SDNode *Op, SDValue N, SDValue &Offset, SDValue &Opc); - bool SelectAddrMode3(SDNode *Op, SDValue N, SDValue &Base, + bool SelectAddrMode3(SDValue N, SDValue &Base, SDValue &Offset, SDValue &Opc); bool SelectAddrMode3Offset(SDNode *Op, SDValue N, SDValue &Offset, SDValue &Opc); - bool SelectAddrMode4(SDNode *Op, SDValue N, SDValue &Addr, - SDValue &Mode); - bool SelectAddrMode5(SDNode *Op, SDValue N, SDValue &Base, + bool SelectAddrMode5(SDValue N, SDValue &Base, SDValue &Offset); - bool SelectAddrMode6(SDNode *Op, SDValue N, SDValue &Addr, SDValue &Align); - - bool SelectAddrModePC(SDNode *Op, SDValue N, SDValue &Offset, - SDValue &Label); - - bool SelectThumbAddrModeRR(SDNode *Op, SDValue N, SDValue &Base, - SDValue &Offset); - bool SelectThumbAddrModeRI5(SDNode *Op, SDValue N, unsigned Scale, - SDValue &Base, SDValue &OffImm, - SDValue &Offset); - bool SelectThumbAddrModeS1(SDNode *Op, SDValue N, SDValue &Base, - SDValue &OffImm, SDValue &Offset); - bool SelectThumbAddrModeS2(SDNode *Op, SDValue N, SDValue &Base, - SDValue &OffImm, SDValue &Offset); - bool SelectThumbAddrModeS4(SDNode *Op, SDValue N, SDValue &Base, - SDValue &OffImm, SDValue &Offset); - bool SelectThumbAddrModeSP(SDNode *Op, SDValue N, SDValue &Base, - SDValue &OffImm); - - bool SelectT2ShifterOperandReg(SDNode *Op, SDValue N, + bool SelectAddrMode6(SDNode *Parent, SDValue N, SDValue &Addr,SDValue &Align); + + bool SelectAddrModePC(SDValue N, SDValue &Offset, SDValue &Label); + + // Thumb Addressing Modes: + bool SelectThumbAddrModeRR(SDValue N, SDValue &Base, SDValue &Offset); + bool SelectThumbAddrModeRI(SDValue N, SDValue &Base, SDValue &Offset, + unsigned Scale); + bool SelectThumbAddrModeRI5S1(SDValue N, SDValue &Base, SDValue &Offset); + bool SelectThumbAddrModeRI5S2(SDValue N, SDValue &Base, SDValue &Offset); + bool SelectThumbAddrModeRI5S4(SDValue N, SDValue &Base, SDValue &Offset); + bool SelectThumbAddrModeImm5S(SDValue N, unsigned Scale, SDValue &Base, + SDValue &OffImm); + bool SelectThumbAddrModeImm5S1(SDValue N, SDValue &Base, + SDValue &OffImm); + bool SelectThumbAddrModeImm5S2(SDValue N, SDValue &Base, + SDValue &OffImm); + bool SelectThumbAddrModeImm5S4(SDValue N, SDValue &Base, + SDValue &OffImm); + bool SelectThumbAddrModeSP(SDValue N, SDValue &Base, SDValue &OffImm); + + // Thumb 2 Addressing Modes: + bool SelectT2ShifterOperandReg(SDValue N, SDValue &BaseReg, SDValue &Opc); - bool SelectT2AddrModeImm12(SDNode *Op, SDValue N, SDValue &Base, - SDValue &OffImm); - bool SelectT2AddrModeImm8(SDNode *Op, SDValue N, SDValue &Base, + bool SelectT2AddrModeImm12(SDValue N, SDValue &Base, SDValue &OffImm); + bool SelectT2AddrModeImm8(SDValue N, SDValue &Base, SDValue &OffImm); bool SelectT2AddrModeImm8Offset(SDNode *Op, SDValue N, SDValue &OffImm); - bool SelectT2AddrModeImm8s4(SDNode *Op, SDValue N, SDValue &Base, - SDValue &OffImm); - bool SelectT2AddrModeSoReg(SDNode *Op, SDValue N, SDValue &Base, + bool SelectT2AddrModeSoReg(SDValue N, SDValue &Base, SDValue &OffReg, SDValue &ShImm); + inline bool is_so_imm(unsigned Imm) const { + return ARM_AM::getSOImmVal(Imm) != -1; + } + + inline bool is_so_imm_not(unsigned Imm) const { + return ARM_AM::getSOImmVal(~Imm) != -1; + } + + inline bool is_t2_so_imm(unsigned Imm) const { + return ARM_AM::getT2SOImmVal(Imm) != -1; + } + + inline bool is_t2_so_imm_not(unsigned Imm) const { + return ARM_AM::getT2SOImmVal(~Imm) != -1; + } + inline bool Pred_so_imm(SDNode *inN) const { ConstantSDNode *N = cast(inN); - return ARM_AM::getSOImmVal(N->getZExtValue()) != -1; + return is_so_imm(N->getZExtValue()); } inline bool Pred_t2_so_imm(SDNode *inN) const { ConstantSDNode *N = cast(inN); - return ARM_AM::getT2SOImmVal(N->getZExtValue()) != -1; + return is_t2_so_imm(N->getZExtValue()); } // Include the pieces autogenerated from the target description. @@ -141,22 +196,30 @@ private: /// 1, 2, 3 or 4. The opcode arrays specify the instructions used for /// loads of D registers and even subregs and odd subregs of Q registers. /// For NumVecs <= 2, QOpcodes1 is not used. - SDNode *SelectVLD(SDNode *N, unsigned NumVecs, unsigned *DOpcodes, + SDNode *SelectVLD(SDNode *N, bool isUpdating, unsigned NumVecs, + unsigned *DOpcodes, unsigned *QOpcodes0, unsigned *QOpcodes1); /// SelectVST - Select NEON store intrinsics. NumVecs should /// be 1, 2, 3 or 4. The opcode arrays specify the instructions used for /// stores of D registers and even subregs and odd subregs of Q registers. /// For NumVecs <= 2, QOpcodes1 is not used. - SDNode *SelectVST(SDNode *N, unsigned NumVecs, unsigned *DOpcodes, + SDNode *SelectVST(SDNode *N, bool isUpdating, unsigned NumVecs, + unsigned *DOpcodes, unsigned *QOpcodes0, unsigned *QOpcodes1); /// SelectVLDSTLane - Select NEON load/store lane intrinsics. NumVecs should /// be 2, 3 or 4. The opcode arrays specify the instructions used for - /// load/store of D registers and even subregs and odd subregs of Q registers. - SDNode *SelectVLDSTLane(SDNode *N, bool IsLoad, unsigned NumVecs, - unsigned *DOpcodes, unsigned *QOpcodes0, - unsigned *QOpcodes1); + /// load/store of D registers and Q registers. + SDNode *SelectVLDSTLane(SDNode *N, bool IsLoad, + bool isUpdating, unsigned NumVecs, + unsigned *DOpcodes, unsigned *QOpcodes); + + /// SelectVLDDup - Select NEON load-duplicate intrinsics. NumVecs + /// should be 2, 3 or 4. The opcode array specifies the instructions used + /// for loading D registers. (Q registers are not supported.) + SDNode *SelectVLDDup(SDNode *N, bool isUpdating, unsigned NumVecs, + unsigned *Opcodes); /// SelectVTBL - Select NEON VTBL and VTBX intrinsics. NumVecs should be 2, /// 3 or 4. These are custom-selected so that a REG_SEQUENCE can be @@ -174,10 +237,10 @@ private: SDNode *SelectARMCMOVShiftOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag); - SDNode *SelectT2CMOVSoImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, + SDNode *SelectT2CMOVImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag); - SDNode *SelectARMCMOVSoImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, + SDNode *SelectARMCMOVImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag); @@ -199,9 +262,8 @@ private: SDNode *QuadDRegs(EVT VT, SDValue V0, SDValue V1, SDValue V2, SDValue V3); SDNode *QuadQRegs(EVT VT, SDValue V0, SDValue V1, SDValue V2, SDValue V3); - // Form sequences of 8 consecutive D registers. - SDNode *OctoDRegs(EVT VT, SDValue V0, SDValue V1, SDValue V2, SDValue V3, - SDValue V4, SDValue V5, SDValue V6, SDValue V7); + // Get the alignment operand for a NEON VLD or VST instruction. + SDValue GetVLDSTAlign(SDValue Align, unsigned NumVecs, bool is64BitVector); }; } @@ -229,9 +291,85 @@ static bool isOpcWithIntImmediate(SDNode *N, unsigned Opc, unsigned& Imm) { isInt32Immediate(N->getOperand(1).getNode(), Imm); } +/// \brief Check whether a particular node is a constant value representable as +/// (N * Scale) where (N in [\arg RangeMin, \arg RangeMax). +/// +/// \param ScaledConstant [out] - On success, the pre-scaled constant value. +static bool isScaledConstantInRange(SDValue Node, unsigned Scale, + int RangeMin, int RangeMax, + int &ScaledConstant) { + assert(Scale && "Invalid scale!"); + + // Check that this is a constant. + const ConstantSDNode *C = dyn_cast(Node); + if (!C) + return false; + + ScaledConstant = (int) C->getZExtValue(); + if ((ScaledConstant % Scale) != 0) + return false; + + ScaledConstant /= Scale; + return ScaledConstant >= RangeMin && ScaledConstant < RangeMax; +} + +/// hasNoVMLxHazardUse - Return true if it's desirable to select a FP MLA / MLS +/// node. VFP / NEON fp VMLA / VMLS instructions have special RAW hazards (at +/// least on current ARM implementations) which should be avoidded. +bool ARMDAGToDAGISel::hasNoVMLxHazardUse(SDNode *N) const { + if (OptLevel == CodeGenOpt::None) + return true; + + if (!CheckVMLxHazard) + return true; + + if (!Subtarget->isCortexA8() && !Subtarget->isCortexA9()) + return true; + + if (!N->hasOneUse()) + return false; + + SDNode *Use = *N->use_begin(); + if (Use->getOpcode() == ISD::CopyToReg) + return true; + if (Use->isMachineOpcode()) { + const TargetInstrDesc &TID = TII->get(Use->getMachineOpcode()); + if (TID.mayStore()) + return true; + unsigned Opcode = TID.getOpcode(); + if (Opcode == ARM::VMOVRS || Opcode == ARM::VMOVRRD) + return true; + // vmlx feeding into another vmlx. We actually want to unfold + // the use later in the MLxExpansion pass. e.g. + // vmla + // vmla (stall 8 cycles) + // + // vmul (5 cycles) + // vadd (5 cycles) + // vmla + // This adds up to about 18 - 19 cycles. + // + // vmla + // vmul (stall 4 cycles) + // vadd adds up to about 14 cycles. + return TII->isFpMLxInstruction(Opcode); + } + + return false; +} + +bool ARMDAGToDAGISel::isShifterOpProfitable(const SDValue &Shift, + ARM_AM::ShiftOpc ShOpcVal, + unsigned ShAmt) { + if (!Subtarget->isCortexA9()) + return true; + if (Shift.hasOneUse()) + return true; + // R << 2 is free. + return ShOpcVal == ARM_AM::lsl && ShAmt == 2; +} -bool ARMDAGToDAGISel::SelectShifterOperandReg(SDNode *Op, - SDValue N, +bool ARMDAGToDAGISel::SelectShifterOperandReg(SDValue N, SDValue &BaseReg, SDValue &ShReg, SDValue &Opc) { @@ -251,16 +389,92 @@ bool ARMDAGToDAGISel::SelectShifterOperandReg(SDNode *Op, ShImmVal = RHS->getZExtValue() & 31; } else { ShReg = N.getOperand(1); + if (!isShifterOpProfitable(N, ShOpcVal, ShImmVal)) + return false; } Opc = CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal), MVT::i32); return true; } -bool ARMDAGToDAGISel::SelectAddrMode2(SDNode *Op, SDValue N, - SDValue &Base, SDValue &Offset, +bool ARMDAGToDAGISel::SelectShiftShifterOperandReg(SDValue N, + SDValue &BaseReg, + SDValue &ShReg, + SDValue &Opc) { + ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N); + + // Don't match base register only case. That is matched to a separate + // lower complexity pattern with explicit register operand. + if (ShOpcVal == ARM_AM::no_shift) return false; + + BaseReg = N.getOperand(0); + unsigned ShImmVal = 0; + // Do not check isShifterOpProfitable. This must return true. + if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { + ShReg = CurDAG->getRegister(0, MVT::i32); + ShImmVal = RHS->getZExtValue() & 31; + } else { + ShReg = N.getOperand(1); + } + Opc = CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal), + MVT::i32); + return true; +} + +bool ARMDAGToDAGISel::SelectAddrModeImm12(SDValue N, + SDValue &Base, + SDValue &OffImm) { + // Match simple R + imm12 operands. + + // Base only. + if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB && + !CurDAG->isBaseWithConstantOffset(N)) { + if (N.getOpcode() == ISD::FrameIndex) { + // Match frame index. + int FI = cast(N)->getIndex(); + Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); + OffImm = CurDAG->getTargetConstant(0, MVT::i32); + return true; + } + + if (N.getOpcode() == ARMISD::Wrapper && + !(Subtarget->useMovt() && + N.getOperand(0).getOpcode() == ISD::TargetGlobalAddress)) { + Base = N.getOperand(0); + } else + Base = N; + OffImm = CurDAG->getTargetConstant(0, MVT::i32); + return true; + } + + if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { + int RHSC = (int)RHS->getZExtValue(); + if (N.getOpcode() == ISD::SUB) + RHSC = -RHSC; + + if (RHSC >= 0 && RHSC < 0x1000) { // 12 bits (unsigned) + Base = N.getOperand(0); + if (Base.getOpcode() == ISD::FrameIndex) { + int FI = cast(Base)->getIndex(); + Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); + } + OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32); + return true; + } + } + + // Base only. + Base = N; + OffImm = CurDAG->getTargetConstant(0, MVT::i32); + return true; +} + + + +bool ARMDAGToDAGISel::SelectLdStSOReg(SDValue N, SDValue &Base, SDValue &Offset, SDValue &Opc) { - if (N.getOpcode() == ISD::MUL) { + if (N.getOpcode() == ISD::MUL && + (!Subtarget->isCortexA9() || N.hasOneUse())) { if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { // X * [3,5,9] -> X + X * [2,4,8] etc. int RHSC = (int)RHS->getZExtValue(); @@ -283,7 +497,114 @@ bool ARMDAGToDAGISel::SelectAddrMode2(SDNode *Op, SDValue N, } } - if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB) { + if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB && + // ISD::OR that is equivalent to an ISD::ADD. + !CurDAG->isBaseWithConstantOffset(N)) + return false; + + // Leave simple R +/- imm12 operands for LDRi12 + if (N.getOpcode() == ISD::ADD || N.getOpcode() == ISD::OR) { + int RHSC; + if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/1, + -0x1000+1, 0x1000, RHSC)) // 12 bits. + return false; + } + + if (Subtarget->isCortexA9() && !N.hasOneUse()) + // Compute R +/- (R << N) and reuse it. + return false; + + // Otherwise this is R +/- [possibly shifted] R. + ARM_AM::AddrOpc AddSub = N.getOpcode() == ISD::SUB ? ARM_AM::sub:ARM_AM::add; + ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOperand(1)); + unsigned ShAmt = 0; + + Base = N.getOperand(0); + Offset = N.getOperand(1); + + if (ShOpcVal != ARM_AM::no_shift) { + // Check to see if the RHS of the shift is a constant, if not, we can't fold + // it. + if (ConstantSDNode *Sh = + dyn_cast(N.getOperand(1).getOperand(1))) { + ShAmt = Sh->getZExtValue(); + if (isShifterOpProfitable(Offset, ShOpcVal, ShAmt)) + Offset = N.getOperand(1).getOperand(0); + else { + ShAmt = 0; + ShOpcVal = ARM_AM::no_shift; + } + } else { + ShOpcVal = ARM_AM::no_shift; + } + } + + // Try matching (R shl C) + (R). + if (N.getOpcode() != ISD::SUB && ShOpcVal == ARM_AM::no_shift && + !(Subtarget->isCortexA9() || N.getOperand(0).hasOneUse())) { + ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOperand(0)); + if (ShOpcVal != ARM_AM::no_shift) { + // Check to see if the RHS of the shift is a constant, if not, we can't + // fold it. + if (ConstantSDNode *Sh = + dyn_cast(N.getOperand(0).getOperand(1))) { + ShAmt = Sh->getZExtValue(); + if (!Subtarget->isCortexA9() || + (N.hasOneUse() && + isShifterOpProfitable(N.getOperand(0), ShOpcVal, ShAmt))) { + Offset = N.getOperand(0).getOperand(0); + Base = N.getOperand(1); + } else { + ShAmt = 0; + ShOpcVal = ARM_AM::no_shift; + } + } else { + ShOpcVal = ARM_AM::no_shift; + } + } + } + + Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, ShOpcVal), + MVT::i32); + return true; +} + + + + +//----- + +AddrMode2Type ARMDAGToDAGISel::SelectAddrMode2Worker(SDValue N, + SDValue &Base, + SDValue &Offset, + SDValue &Opc) { + if (N.getOpcode() == ISD::MUL && + (!Subtarget->isCortexA9() || N.hasOneUse())) { + if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { + // X * [3,5,9] -> X + X * [2,4,8] etc. + int RHSC = (int)RHS->getZExtValue(); + if (RHSC & 1) { + RHSC = RHSC & ~1; + ARM_AM::AddrOpc AddSub = ARM_AM::add; + if (RHSC < 0) { + AddSub = ARM_AM::sub; + RHSC = - RHSC; + } + if (isPowerOf2_32(RHSC)) { + unsigned ShAmt = Log2_32(RHSC); + Base = Offset = N.getOperand(0); + Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, + ARM_AM::lsl), + MVT::i32); + return AM2_SHOP; + } + } + } + } + + if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB && + // ISD::OR that is equivalent to an ADD. + !CurDAG->isBaseWithConstantOffset(N)) { Base = N; if (N.getOpcode() == ISD::FrameIndex) { int FI = cast(N)->getIndex(); @@ -297,36 +618,45 @@ bool ARMDAGToDAGISel::SelectAddrMode2(SDNode *Op, SDValue N, Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(ARM_AM::add, 0, ARM_AM::no_shift), MVT::i32); - return true; + return AM2_BASE; } // Match simple R +/- imm12 operands. - if (N.getOpcode() == ISD::ADD) - if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { - int RHSC = (int)RHS->getZExtValue(); - if ((RHSC >= 0 && RHSC < 0x1000) || - (RHSC < 0 && RHSC > -0x1000)) { // 12 bits. - Base = N.getOperand(0); - if (Base.getOpcode() == ISD::FrameIndex) { - int FI = cast(Base)->getIndex(); - Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); - } - Offset = CurDAG->getRegister(0, MVT::i32); + if (N.getOpcode() != ISD::SUB) { + int RHSC; + if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/1, + -0x1000+1, 0x1000, RHSC)) { // 12 bits. + Base = N.getOperand(0); + if (Base.getOpcode() == ISD::FrameIndex) { + int FI = cast(Base)->getIndex(); + Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); + } + Offset = CurDAG->getRegister(0, MVT::i32); - ARM_AM::AddrOpc AddSub = ARM_AM::add; - if (RHSC < 0) { - AddSub = ARM_AM::sub; - RHSC = - RHSC; - } - Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, RHSC, - ARM_AM::no_shift), - MVT::i32); - return true; + ARM_AM::AddrOpc AddSub = ARM_AM::add; + if (RHSC < 0) { + AddSub = ARM_AM::sub; + RHSC = - RHSC; } + Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, RHSC, + ARM_AM::no_shift), + MVT::i32); + return AM2_BASE; } + } + + if (Subtarget->isCortexA9() && !N.hasOneUse()) { + // Compute R +/- (R << N) and reuse it. + Base = N; + Offset = CurDAG->getRegister(0, MVT::i32); + Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(ARM_AM::add, 0, + ARM_AM::no_shift), + MVT::i32); + return AM2_BASE; + } // Otherwise this is R +/- [possibly shifted] R. - ARM_AM::AddrOpc AddSub = N.getOpcode() == ISD::ADD ? ARM_AM::add:ARM_AM::sub; + ARM_AM::AddrOpc AddSub = N.getOpcode() != ISD::SUB ? ARM_AM::add:ARM_AM::sub; ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOperand(1)); unsigned ShAmt = 0; @@ -339,14 +669,20 @@ bool ARMDAGToDAGISel::SelectAddrMode2(SDNode *Op, SDValue N, if (ConstantSDNode *Sh = dyn_cast(N.getOperand(1).getOperand(1))) { ShAmt = Sh->getZExtValue(); - Offset = N.getOperand(1).getOperand(0); + if (isShifterOpProfitable(Offset, ShOpcVal, ShAmt)) + Offset = N.getOperand(1).getOperand(0); + else { + ShAmt = 0; + ShOpcVal = ARM_AM::no_shift; + } } else { ShOpcVal = ARM_AM::no_shift; } } // Try matching (R shl C) + (R). - if (N.getOpcode() == ISD::ADD && ShOpcVal == ARM_AM::no_shift) { + if (N.getOpcode() != ISD::SUB && ShOpcVal == ARM_AM::no_shift && + !(Subtarget->isCortexA9() || N.getOperand(0).hasOneUse())) { ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOperand(0)); if (ShOpcVal != ARM_AM::no_shift) { // Check to see if the RHS of the shift is a constant, if not, we can't @@ -354,8 +690,15 @@ bool ARMDAGToDAGISel::SelectAddrMode2(SDNode *Op, SDValue N, if (ConstantSDNode *Sh = dyn_cast(N.getOperand(0).getOperand(1))) { ShAmt = Sh->getZExtValue(); - Offset = N.getOperand(0).getOperand(0); - Base = N.getOperand(1); + if (!Subtarget->isCortexA9() || + (N.hasOneUse() && + isShifterOpProfitable(N.getOperand(0), ShOpcVal, ShAmt))) { + Offset = N.getOperand(0).getOperand(0); + Base = N.getOperand(1); + } else { + ShAmt = 0; + ShOpcVal = ARM_AM::no_shift; + } } else { ShOpcVal = ARM_AM::no_shift; } @@ -364,7 +707,7 @@ bool ARMDAGToDAGISel::SelectAddrMode2(SDNode *Op, SDValue N, Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, ShOpcVal), MVT::i32); - return true; + return AM2_SHOP; } bool ARMDAGToDAGISel::SelectAddrMode2Offset(SDNode *Op, SDValue N, @@ -375,15 +718,13 @@ bool ARMDAGToDAGISel::SelectAddrMode2Offset(SDNode *Op, SDValue N, : cast(Op)->getAddressingMode(); ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC) ? ARM_AM::add : ARM_AM::sub; - if (ConstantSDNode *C = dyn_cast(N)) { - int Val = (int)C->getZExtValue(); - if (Val >= 0 && Val < 0x1000) { // 12 bits. - Offset = CurDAG->getRegister(0, MVT::i32); - Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, Val, - ARM_AM::no_shift), - MVT::i32); - return true; - } + int Val; + if (isScaledConstantInRange(N, /*Scale=*/1, 0, 0x1000, Val)) { // 12 bits. + Offset = CurDAG->getRegister(0, MVT::i32); + Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, Val, + ARM_AM::no_shift), + MVT::i32); + return true; } Offset = N; @@ -394,7 +735,12 @@ bool ARMDAGToDAGISel::SelectAddrMode2Offset(SDNode *Op, SDValue N, // it. if (ConstantSDNode *Sh = dyn_cast(N.getOperand(1))) { ShAmt = Sh->getZExtValue(); - Offset = N.getOperand(0); + if (isShifterOpProfitable(N, ShOpcVal, ShAmt)) + Offset = N.getOperand(0); + else { + ShAmt = 0; + ShOpcVal = ARM_AM::no_shift; + } } else { ShOpcVal = ARM_AM::no_shift; } @@ -406,7 +752,7 @@ bool ARMDAGToDAGISel::SelectAddrMode2Offset(SDNode *Op, SDValue N, } -bool ARMDAGToDAGISel::SelectAddrMode3(SDNode *Op, SDValue N, +bool ARMDAGToDAGISel::SelectAddrMode3(SDValue N, SDValue &Base, SDValue &Offset, SDValue &Opc) { if (N.getOpcode() == ISD::SUB) { @@ -417,7 +763,7 @@ bool ARMDAGToDAGISel::SelectAddrMode3(SDNode *Op, SDValue N, return true; } - if (N.getOpcode() != ISD::ADD) { + if (!CurDAG->isBaseWithConstantOffset(N)) { Base = N; if (N.getOpcode() == ISD::FrameIndex) { int FI = cast(N)->getIndex(); @@ -429,25 +775,23 @@ bool ARMDAGToDAGISel::SelectAddrMode3(SDNode *Op, SDValue N, } // If the RHS is +/- imm8, fold into addr mode. - if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { - int RHSC = (int)RHS->getZExtValue(); - if ((RHSC >= 0 && RHSC < 256) || - (RHSC < 0 && RHSC > -256)) { // note -256 itself isn't allowed. - Base = N.getOperand(0); - if (Base.getOpcode() == ISD::FrameIndex) { - int FI = cast(Base)->getIndex(); - Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); - } - Offset = CurDAG->getRegister(0, MVT::i32); + int RHSC; + if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/1, + -256 + 1, 256, RHSC)) { // 8 bits. + Base = N.getOperand(0); + if (Base.getOpcode() == ISD::FrameIndex) { + int FI = cast(Base)->getIndex(); + Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); + } + Offset = CurDAG->getRegister(0, MVT::i32); - ARM_AM::AddrOpc AddSub = ARM_AM::add; - if (RHSC < 0) { - AddSub = ARM_AM::sub; - RHSC = - RHSC; - } - Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, RHSC),MVT::i32); - return true; + ARM_AM::AddrOpc AddSub = ARM_AM::add; + if (RHSC < 0) { + AddSub = ARM_AM::sub; + RHSC = -RHSC; } + Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, RHSC),MVT::i32); + return true; } Base = N.getOperand(0); @@ -464,13 +808,11 @@ bool ARMDAGToDAGISel::SelectAddrMode3Offset(SDNode *Op, SDValue N, : cast(Op)->getAddressingMode(); ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC) ? ARM_AM::add : ARM_AM::sub; - if (ConstantSDNode *C = dyn_cast(N)) { - int Val = (int)C->getZExtValue(); - if (Val >= 0 && Val < 256) { - Offset = CurDAG->getRegister(0, MVT::i32); - Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, Val), MVT::i32); - return true; - } + int Val; + if (isScaledConstantInRange(N, /*Scale=*/1, 0, 256, Val)) { // 12 bits. + Offset = CurDAG->getRegister(0, MVT::i32); + Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, Val), MVT::i32); + return true; } Offset = N; @@ -478,16 +820,9 @@ bool ARMDAGToDAGISel::SelectAddrMode3Offset(SDNode *Op, SDValue N, return true; } -bool ARMDAGToDAGISel::SelectAddrMode4(SDNode *Op, SDValue N, - SDValue &Addr, SDValue &Mode) { - Addr = N; - Mode = CurDAG->getTargetConstant(ARM_AM::getAM4ModeImm(ARM_AM::ia), MVT::i32); - return true; -} - -bool ARMDAGToDAGISel::SelectAddrMode5(SDNode *Op, SDValue N, +bool ARMDAGToDAGISel::SelectAddrMode5(SDValue N, SDValue &Base, SDValue &Offset) { - if (N.getOpcode() != ISD::ADD) { + if (!CurDAG->isBaseWithConstantOffset(N)) { Base = N; if (N.getOpcode() == ISD::FrameIndex) { int FI = cast(N)->getIndex(); @@ -503,28 +838,23 @@ bool ARMDAGToDAGISel::SelectAddrMode5(SDNode *Op, SDValue N, } // If the RHS is +/- imm8, fold into addr mode. - if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { - int RHSC = (int)RHS->getZExtValue(); - if ((RHSC & 3) == 0) { // The constant is implicitly multiplied by 4. - RHSC >>= 2; - if ((RHSC >= 0 && RHSC < 256) || - (RHSC < 0 && RHSC > -256)) { // note -256 itself isn't allowed. - Base = N.getOperand(0); - if (Base.getOpcode() == ISD::FrameIndex) { - int FI = cast(Base)->getIndex(); - Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); - } + int RHSC; + if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/4, + -256 + 1, 256, RHSC)) { + Base = N.getOperand(0); + if (Base.getOpcode() == ISD::FrameIndex) { + int FI = cast(Base)->getIndex(); + Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); + } - ARM_AM::AddrOpc AddSub = ARM_AM::add; - if (RHSC < 0) { - AddSub = ARM_AM::sub; - RHSC = - RHSC; - } - Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(AddSub, RHSC), - MVT::i32); - return true; - } + ARM_AM::AddrOpc AddSub = ARM_AM::add; + if (RHSC < 0) { + AddSub = ARM_AM::sub; + RHSC = -RHSC; } + Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(AddSub, RHSC), + MVT::i32); + return true; } Base = N; @@ -533,30 +863,50 @@ bool ARMDAGToDAGISel::SelectAddrMode5(SDNode *Op, SDValue N, return true; } -bool ARMDAGToDAGISel::SelectAddrMode6(SDNode *Op, SDValue N, - SDValue &Addr, SDValue &Align) { +bool ARMDAGToDAGISel::SelectAddrMode6(SDNode *Parent, SDValue N, SDValue &Addr, + SDValue &Align) { Addr = N; - // Default to no alignment. - Align = CurDAG->getTargetConstant(0, MVT::i32); + + unsigned Alignment = 0; + if (LSBaseSDNode *LSN = dyn_cast(Parent)) { + // This case occurs only for VLD1-lane/dup and VST1-lane instructions. + // The maximum alignment is equal to the memory size being referenced. + unsigned LSNAlign = LSN->getAlignment(); + unsigned MemSize = LSN->getMemoryVT().getSizeInBits() / 8; + if (LSNAlign > MemSize && MemSize > 1) + Alignment = MemSize; + } else { + // All other uses of addrmode6 are for intrinsics. For now just record + // the raw alignment value; it will be refined later based on the legal + // alignment operands for the intrinsic. + Alignment = cast(Parent)->getAlignment(); + } + + Align = CurDAG->getTargetConstant(Alignment, MVT::i32); return true; } -bool ARMDAGToDAGISel::SelectAddrModePC(SDNode *Op, SDValue N, +bool ARMDAGToDAGISel::SelectAddrModePC(SDValue N, SDValue &Offset, SDValue &Label) { if (N.getOpcode() == ARMISD::PIC_ADD && N.hasOneUse()) { Offset = N.getOperand(0); SDValue N1 = N.getOperand(1); - Label = CurDAG->getTargetConstant(cast(N1)->getZExtValue(), - MVT::i32); + Label = CurDAG->getTargetConstant(cast(N1)->getZExtValue(), + MVT::i32); return true; } + return false; } -bool ARMDAGToDAGISel::SelectThumbAddrModeRR(SDNode *Op, SDValue N, + +//===----------------------------------------------------------------------===// +// Thumb Addressing Modes +//===----------------------------------------------------------------------===// + +bool ARMDAGToDAGISel::SelectThumbAddrModeRR(SDValue N, SDValue &Base, SDValue &Offset){ - // FIXME dl should come from the parent load or store, not the address - if (N.getOpcode() != ISD::ADD) { + if (N.getOpcode() != ISD::ADD && !CurDAG->isBaseWithConstantOffset(N)) { ConstantSDNode *NC = dyn_cast(N); if (!NC || !NC->isNullValue()) return false; @@ -571,82 +921,137 @@ bool ARMDAGToDAGISel::SelectThumbAddrModeRR(SDNode *Op, SDValue N, } bool -ARMDAGToDAGISel::SelectThumbAddrModeRI5(SDNode *Op, SDValue N, - unsigned Scale, SDValue &Base, - SDValue &OffImm, SDValue &Offset) { +ARMDAGToDAGISel::SelectThumbAddrModeRI(SDValue N, SDValue &Base, + SDValue &Offset, unsigned Scale) { + if (Scale == 4) { + SDValue TmpBase, TmpOffImm; + if (SelectThumbAddrModeSP(N, TmpBase, TmpOffImm)) + return false; // We want to select tLDRspi / tSTRspi instead. + + if (N.getOpcode() == ARMISD::Wrapper && + N.getOperand(0).getOpcode() == ISD::TargetConstantPool) + return false; // We want to select tLDRpci instead. + } + + if (!CurDAG->isBaseWithConstantOffset(N)) + return false; + + // Thumb does not have [sp, r] address mode. + RegisterSDNode *LHSR = dyn_cast(N.getOperand(0)); + RegisterSDNode *RHSR = dyn_cast(N.getOperand(1)); + if ((LHSR && LHSR->getReg() == ARM::SP) || + (RHSR && RHSR->getReg() == ARM::SP)) + return false; + + // FIXME: Why do we explicitly check for a match here and then return false? + // Presumably to allow something else to match, but shouldn't this be + // documented? + int RHSC; + if (isScaledConstantInRange(N.getOperand(1), Scale, 0, 32, RHSC)) + return false; + + Base = N.getOperand(0); + Offset = N.getOperand(1); + return true; +} + +bool +ARMDAGToDAGISel::SelectThumbAddrModeRI5S1(SDValue N, + SDValue &Base, + SDValue &Offset) { + return SelectThumbAddrModeRI(N, Base, Offset, 1); +} + +bool +ARMDAGToDAGISel::SelectThumbAddrModeRI5S2(SDValue N, + SDValue &Base, + SDValue &Offset) { + return SelectThumbAddrModeRI(N, Base, Offset, 2); +} + +bool +ARMDAGToDAGISel::SelectThumbAddrModeRI5S4(SDValue N, + SDValue &Base, + SDValue &Offset) { + return SelectThumbAddrModeRI(N, Base, Offset, 4); +} + +bool +ARMDAGToDAGISel::SelectThumbAddrModeImm5S(SDValue N, unsigned Scale, + SDValue &Base, SDValue &OffImm) { if (Scale == 4) { SDValue TmpBase, TmpOffImm; - if (SelectThumbAddrModeSP(Op, N, TmpBase, TmpOffImm)) + if (SelectThumbAddrModeSP(N, TmpBase, TmpOffImm)) return false; // We want to select tLDRspi / tSTRspi instead. + if (N.getOpcode() == ARMISD::Wrapper && N.getOperand(0).getOpcode() == ISD::TargetConstantPool) return false; // We want to select tLDRpci instead. } - if (N.getOpcode() != ISD::ADD) { + if (!CurDAG->isBaseWithConstantOffset(N)) { if (N.getOpcode() == ARMISD::Wrapper && !(Subtarget->useMovt() && N.getOperand(0).getOpcode() == ISD::TargetGlobalAddress)) { Base = N.getOperand(0); - } else + } else { Base = N; + } - Offset = CurDAG->getRegister(0, MVT::i32); OffImm = CurDAG->getTargetConstant(0, MVT::i32); return true; } - // Thumb does not have [sp, r] address mode. RegisterSDNode *LHSR = dyn_cast(N.getOperand(0)); RegisterSDNode *RHSR = dyn_cast(N.getOperand(1)); if ((LHSR && LHSR->getReg() == ARM::SP) || (RHSR && RHSR->getReg() == ARM::SP)) { + ConstantSDNode *LHS = dyn_cast(N.getOperand(0)); + ConstantSDNode *RHS = dyn_cast(N.getOperand(1)); + unsigned LHSC = LHS ? LHS->getZExtValue() : 0; + unsigned RHSC = RHS ? RHS->getZExtValue() : 0; + + // Thumb does not have [sp, #imm5] address mode for non-zero imm5. + if (LHSC != 0 || RHSC != 0) return false; + Base = N; - Offset = CurDAG->getRegister(0, MVT::i32); OffImm = CurDAG->getTargetConstant(0, MVT::i32); return true; } // If the RHS is + imm5 * scale, fold into addr mode. - if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { - int RHSC = (int)RHS->getZExtValue(); - if ((RHSC & (Scale-1)) == 0) { // The constant is implicitly multiplied. - RHSC /= Scale; - if (RHSC >= 0 && RHSC < 32) { - Base = N.getOperand(0); - Offset = CurDAG->getRegister(0, MVT::i32); - OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32); - return true; - } - } + int RHSC; + if (isScaledConstantInRange(N.getOperand(1), Scale, 0, 32, RHSC)) { + Base = N.getOperand(0); + OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32); + return true; } Base = N.getOperand(0); - Offset = N.getOperand(1); OffImm = CurDAG->getTargetConstant(0, MVT::i32); return true; } -bool ARMDAGToDAGISel::SelectThumbAddrModeS1(SDNode *Op, SDValue N, - SDValue &Base, SDValue &OffImm, - SDValue &Offset) { - return SelectThumbAddrModeRI5(Op, N, 1, Base, OffImm, Offset); +bool +ARMDAGToDAGISel::SelectThumbAddrModeImm5S4(SDValue N, SDValue &Base, + SDValue &OffImm) { + return SelectThumbAddrModeImm5S(N, 4, Base, OffImm); } -bool ARMDAGToDAGISel::SelectThumbAddrModeS2(SDNode *Op, SDValue N, - SDValue &Base, SDValue &OffImm, - SDValue &Offset) { - return SelectThumbAddrModeRI5(Op, N, 2, Base, OffImm, Offset); +bool +ARMDAGToDAGISel::SelectThumbAddrModeImm5S2(SDValue N, SDValue &Base, + SDValue &OffImm) { + return SelectThumbAddrModeImm5S(N, 2, Base, OffImm); } -bool ARMDAGToDAGISel::SelectThumbAddrModeS4(SDNode *Op, SDValue N, - SDValue &Base, SDValue &OffImm, - SDValue &Offset) { - return SelectThumbAddrModeRI5(Op, N, 4, Base, OffImm, Offset); +bool +ARMDAGToDAGISel::SelectThumbAddrModeImm5S1(SDValue N, SDValue &Base, + SDValue &OffImm) { + return SelectThumbAddrModeImm5S(N, 1, Base, OffImm); } -bool ARMDAGToDAGISel::SelectThumbAddrModeSP(SDNode *Op, SDValue N, - SDValue &Base, SDValue &OffImm) { +bool ARMDAGToDAGISel::SelectThumbAddrModeSP(SDValue N, + SDValue &Base, SDValue &OffImm) { if (N.getOpcode() == ISD::FrameIndex) { int FI = cast(N)->getIndex(); Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); @@ -654,35 +1059,35 @@ bool ARMDAGToDAGISel::SelectThumbAddrModeSP(SDNode *Op, SDValue N, return true; } - if (N.getOpcode() != ISD::ADD) + if (!CurDAG->isBaseWithConstantOffset(N)) return false; RegisterSDNode *LHSR = dyn_cast(N.getOperand(0)); if (N.getOperand(0).getOpcode() == ISD::FrameIndex || (LHSR && LHSR->getReg() == ARM::SP)) { // If the RHS is + imm8 * scale, fold into addr mode. - if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { - int RHSC = (int)RHS->getZExtValue(); - if ((RHSC & 3) == 0) { // The constant is implicitly multiplied. - RHSC >>= 2; - if (RHSC >= 0 && RHSC < 256) { - Base = N.getOperand(0); - if (Base.getOpcode() == ISD::FrameIndex) { - int FI = cast(Base)->getIndex(); - Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); - } - OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32); - return true; - } + int RHSC; + if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/4, 0, 256, RHSC)) { + Base = N.getOperand(0); + if (Base.getOpcode() == ISD::FrameIndex) { + int FI = cast(Base)->getIndex(); + Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); } + OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32); + return true; } } return false; } -bool ARMDAGToDAGISel::SelectT2ShifterOperandReg(SDNode *Op, SDValue N, - SDValue &BaseReg, + +//===----------------------------------------------------------------------===// +// Thumb 2 Addressing Modes +//===----------------------------------------------------------------------===// + + +bool ARMDAGToDAGISel::SelectT2ShifterOperandReg(SDValue N, SDValue &BaseReg, SDValue &Opc) { if (DisableShifterOp) return false; @@ -704,19 +1109,22 @@ bool ARMDAGToDAGISel::SelectT2ShifterOperandReg(SDNode *Op, SDValue N, return false; } -bool ARMDAGToDAGISel::SelectT2AddrModeImm12(SDNode *Op, SDValue N, +bool ARMDAGToDAGISel::SelectT2AddrModeImm12(SDValue N, SDValue &Base, SDValue &OffImm) { // Match simple R + imm12 operands. // Base only. - if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB) { + if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB && + !CurDAG->isBaseWithConstantOffset(N)) { if (N.getOpcode() == ISD::FrameIndex) { - // Match frame index... + // Match frame index. int FI = cast(N)->getIndex(); Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); OffImm = CurDAG->getTargetConstant(0, MVT::i32); return true; - } else if (N.getOpcode() == ARMISD::Wrapper && + } + + if (N.getOpcode() == ARMISD::Wrapper && !(Subtarget->useMovt() && N.getOperand(0).getOpcode() == ISD::TargetGlobalAddress)) { Base = N.getOperand(0); @@ -729,7 +1137,7 @@ bool ARMDAGToDAGISel::SelectT2AddrModeImm12(SDNode *Op, SDValue N, } if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { - if (SelectT2AddrModeImm8(Op, N, Base, OffImm)) + if (SelectT2AddrModeImm8(N, Base, OffImm)) // Let t2LDRi8 handle (R - imm8). return false; @@ -754,24 +1162,26 @@ bool ARMDAGToDAGISel::SelectT2AddrModeImm12(SDNode *Op, SDValue N, return true; } -bool ARMDAGToDAGISel::SelectT2AddrModeImm8(SDNode *Op, SDValue N, +bool ARMDAGToDAGISel::SelectT2AddrModeImm8(SDValue N, SDValue &Base, SDValue &OffImm) { // Match simple R - imm8 operands. - if (N.getOpcode() == ISD::ADD || N.getOpcode() == ISD::SUB) { - if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { - int RHSC = (int)RHS->getSExtValue(); - if (N.getOpcode() == ISD::SUB) - RHSC = -RHSC; - - if ((RHSC >= -255) && (RHSC < 0)) { // 8 bits (always negative) - Base = N.getOperand(0); - if (Base.getOpcode() == ISD::FrameIndex) { - int FI = cast(Base)->getIndex(); - Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); - } - OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32); - return true; + if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB && + !CurDAG->isBaseWithConstantOffset(N)) + return false; + + if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { + int RHSC = (int)RHS->getSExtValue(); + if (N.getOpcode() == ISD::SUB) + RHSC = -RHSC; + + if ((RHSC >= -255) && (RHSC < 0)) { // 8 bits (always negative) + Base = N.getOperand(0); + if (Base.getOpcode() == ISD::FrameIndex) { + int FI = cast(Base)->getIndex(); + Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy()); } + OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32); + return true; } } @@ -784,52 +1194,22 @@ bool ARMDAGToDAGISel::SelectT2AddrModeImm8Offset(SDNode *Op, SDValue N, ISD::MemIndexedMode AM = (Opcode == ISD::LOAD) ? cast(Op)->getAddressingMode() : cast(Op)->getAddressingMode(); - if (ConstantSDNode *RHS = dyn_cast(N)) { - int RHSC = (int)RHS->getZExtValue(); - if (RHSC >= 0 && RHSC < 0x100) { // 8 bits. - OffImm = ((AM == ISD::PRE_INC) || (AM == ISD::POST_INC)) - ? CurDAG->getTargetConstant(RHSC, MVT::i32) - : CurDAG->getTargetConstant(-RHSC, MVT::i32); - return true; - } - } - - return false; -} - -bool ARMDAGToDAGISel::SelectT2AddrModeImm8s4(SDNode *Op, SDValue N, - SDValue &Base, SDValue &OffImm) { - if (N.getOpcode() == ISD::ADD) { - if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { - int RHSC = (int)RHS->getZExtValue(); - // 8 bits. - if (((RHSC & 0x3) == 0) && - ((RHSC >= 0 && RHSC < 0x400) || (RHSC < 0 && RHSC > -0x400))) { - Base = N.getOperand(0); - OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32); - return true; - } - } - } else if (N.getOpcode() == ISD::SUB) { - if (ConstantSDNode *RHS = dyn_cast(N.getOperand(1))) { - int RHSC = (int)RHS->getZExtValue(); - // 8 bits. - if (((RHSC & 0x3) == 0) && (RHSC >= 0 && RHSC < 0x400)) { - Base = N.getOperand(0); - OffImm = CurDAG->getTargetConstant(-RHSC, MVT::i32); - return true; - } - } + int RHSC; + if (isScaledConstantInRange(N, /*Scale=*/1, 0, 0x100, RHSC)) { // 8 bits. + OffImm = ((AM == ISD::PRE_INC) || (AM == ISD::POST_INC)) + ? CurDAG->getTargetConstant(RHSC, MVT::i32) + : CurDAG->getTargetConstant(-RHSC, MVT::i32); + return true; } return false; } -bool ARMDAGToDAGISel::SelectT2AddrModeSoReg(SDNode *Op, SDValue N, +bool ARMDAGToDAGISel::SelectT2AddrModeSoReg(SDValue N, SDValue &Base, SDValue &OffReg, SDValue &ShImm) { // (R - imm8) should be handled by t2LDRi8. The rest are handled by t2LDRi12. - if (N.getOpcode() != ISD::ADD) + if (N.getOpcode() != ISD::ADD && !CurDAG->isBaseWithConstantOffset(N)) return false; // Leave (R + imm12) for t2LDRi12, (R - imm8) for t2LDRi8. @@ -841,6 +1221,12 @@ bool ARMDAGToDAGISel::SelectT2AddrModeSoReg(SDNode *Op, SDValue N, return false; } + if (Subtarget->isCortexA9() && !N.hasOneUse()) { + // Compute R + (R << [1,2,3]) and reuse it. + Base = N; + return false; + } + // Look for (R + R) or (R + (R << [1,2,3])). unsigned ShAmt = 0; Base = N.getOperand(0); @@ -859,11 +1245,12 @@ bool ARMDAGToDAGISel::SelectT2AddrModeSoReg(SDNode *Op, SDValue N, // it. if (ConstantSDNode *Sh = dyn_cast(OffReg.getOperand(1))) { ShAmt = Sh->getZExtValue(); - if (ShAmt >= 4) { + if (ShAmt < 4 && isShifterOpProfitable(OffReg, ShOpcVal, ShAmt)) + OffReg = OffReg.getOperand(0); + else { ShAmt = 0; ShOpcVal = ARM_AM::no_shift; - } else - OffReg = OffReg.getOperand(0); + } } else { ShOpcVal = ARM_AM::no_shift; } @@ -1045,52 +1432,43 @@ SDNode *ARMDAGToDAGISel::QuadQRegs(EVT VT, SDValue V0, SDValue V1, return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops, 8); } -/// OctoDRegs - Form 8 consecutive D registers. -/// -SDNode *ARMDAGToDAGISel::OctoDRegs(EVT VT, SDValue V0, SDValue V1, - SDValue V2, SDValue V3, - SDValue V4, SDValue V5, - SDValue V6, SDValue V7) { - DebugLoc dl = V0.getNode()->getDebugLoc(); - SDValue SubReg0 = CurDAG->getTargetConstant(ARM::dsub_0, MVT::i32); - SDValue SubReg1 = CurDAG->getTargetConstant(ARM::dsub_1, MVT::i32); - SDValue SubReg2 = CurDAG->getTargetConstant(ARM::dsub_2, MVT::i32); - SDValue SubReg3 = CurDAG->getTargetConstant(ARM::dsub_3, MVT::i32); - SDValue SubReg4 = CurDAG->getTargetConstant(ARM::dsub_4, MVT::i32); - SDValue SubReg5 = CurDAG->getTargetConstant(ARM::dsub_5, MVT::i32); - SDValue SubReg6 = CurDAG->getTargetConstant(ARM::dsub_6, MVT::i32); - SDValue SubReg7 = CurDAG->getTargetConstant(ARM::dsub_7, MVT::i32); - const SDValue Ops[] ={ V0, SubReg0, V1, SubReg1, V2, SubReg2, V3, SubReg3, - V4, SubReg4, V5, SubReg5, V6, SubReg6, V7, SubReg7 }; - return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops, 16); -} - -/// GetNEONSubregVT - Given a type for a 128-bit NEON vector, return the type -/// for a 64-bit subregister of the vector. -static EVT GetNEONSubregVT(EVT VT) { - switch (VT.getSimpleVT().SimpleTy) { - default: llvm_unreachable("unhandled NEON type"); - case MVT::v16i8: return MVT::v8i8; - case MVT::v8i16: return MVT::v4i16; - case MVT::v4f32: return MVT::v2f32; - case MVT::v4i32: return MVT::v2i32; - case MVT::v2i64: return MVT::v1i64; - } +/// GetVLDSTAlign - Get the alignment (in bytes) for the alignment operand +/// of a NEON VLD or VST instruction. The supported values depend on the +/// number of registers being loaded. +SDValue ARMDAGToDAGISel::GetVLDSTAlign(SDValue Align, unsigned NumVecs, + bool is64BitVector) { + unsigned NumRegs = NumVecs; + if (!is64BitVector && NumVecs < 3) + NumRegs *= 2; + + unsigned Alignment = cast(Align)->getZExtValue(); + if (Alignment >= 32 && NumRegs == 4) + Alignment = 32; + else if (Alignment >= 16 && (NumRegs == 2 || NumRegs == 4)) + Alignment = 16; + else if (Alignment >= 8) + Alignment = 8; + else + Alignment = 0; + + return CurDAG->getTargetConstant(Alignment, MVT::i32); } -SDNode *ARMDAGToDAGISel::SelectVLD(SDNode *N, unsigned NumVecs, +SDNode *ARMDAGToDAGISel::SelectVLD(SDNode *N, bool isUpdating, unsigned NumVecs, unsigned *DOpcodes, unsigned *QOpcodes0, unsigned *QOpcodes1) { assert(NumVecs >= 1 && NumVecs <= 4 && "VLD NumVecs out-of-range"); DebugLoc dl = N->getDebugLoc(); SDValue MemAddr, Align; - if (!SelectAddrMode6(N, N->getOperand(2), MemAddr, Align)) + unsigned AddrOpIdx = isUpdating ? 1 : 2; + if (!SelectAddrMode6(N, N->getOperand(AddrOpIdx), MemAddr, Align)) return NULL; SDValue Chain = N->getOperand(0); EVT VT = N->getValueType(0); bool is64BitVector = VT.is64BitVector(); + Align = GetVLDSTAlign(Align, NumVecs, is64BitVector); unsigned OpcodeIndex; switch (VT.getSimpleVT().SimpleTy) { @@ -1120,88 +1498,97 @@ SDNode *ARMDAGToDAGISel::SelectVLD(SDNode *N, unsigned NumVecs, ResTyElts *= 2; ResTy = EVT::getVectorVT(*CurDAG->getContext(), MVT::i64, ResTyElts); } + std::vector ResTys; + ResTys.push_back(ResTy); + if (isUpdating) + ResTys.push_back(MVT::i32); + ResTys.push_back(MVT::Other); SDValue Pred = getAL(CurDAG); SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); - SDValue SuperReg; - if (is64BitVector) { - unsigned Opc = DOpcodes[OpcodeIndex]; - const SDValue Ops[] = { MemAddr, Align, Pred, Reg0, Chain }; - SDNode *VLd = CurDAG->getMachineNode(Opc, dl, ResTy, MVT::Other, Ops, 5); - if (NumVecs == 1) - return VLd; - - SuperReg = SDValue(VLd, 0); - assert(ARM::dsub_7 == ARM::dsub_0+7 && "Unexpected subreg numbering"); - for (unsigned Vec = 0; Vec < NumVecs; ++Vec) { - SDValue D = CurDAG->getTargetExtractSubreg(ARM::dsub_0+Vec, - dl, VT, SuperReg); - ReplaceUses(SDValue(N, Vec), D); - } - ReplaceUses(SDValue(N, NumVecs), SDValue(VLd, 1)); - return NULL; - } - - if (NumVecs <= 2) { - // Quad registers are directly supported for VLD1 and VLD2, - // loading pairs of D regs. - unsigned Opc = QOpcodes0[OpcodeIndex]; - const SDValue Ops[] = { MemAddr, Align, Pred, Reg0, Chain }; - SDNode *VLd = CurDAG->getMachineNode(Opc, dl, ResTy, MVT::Other, Ops, 5); - if (NumVecs == 1) - return VLd; + SDNode *VLd; + SmallVector Ops; - SuperReg = SDValue(VLd, 0); - Chain = SDValue(VLd, 1); + // Double registers and VLD1/VLD2 quad registers are directly supported. + if (is64BitVector || NumVecs <= 2) { + unsigned Opc = (is64BitVector ? DOpcodes[OpcodeIndex] : + QOpcodes0[OpcodeIndex]); + Ops.push_back(MemAddr); + Ops.push_back(Align); + if (isUpdating) { + SDValue Inc = N->getOperand(AddrOpIdx + 1); + Ops.push_back(isa(Inc.getNode()) ? Reg0 : Inc); + } + Ops.push_back(Pred); + Ops.push_back(Reg0); + Ops.push_back(Chain); + VLd = CurDAG->getMachineNode(Opc, dl, ResTys, Ops.data(), Ops.size()); } else { // Otherwise, quad registers are loaded with two separate instructions, // where one loads the even registers and the other loads the odd registers. EVT AddrTy = MemAddr.getValueType(); - // Load the even subregs. - unsigned Opc = QOpcodes0[OpcodeIndex]; + // Load the even subregs. This is always an updating load, so that it + // provides the address to the second load for the odd subregs. SDValue ImplDef = SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, ResTy), 0); const SDValue OpsA[] = { MemAddr, Align, Reg0, ImplDef, Pred, Reg0, Chain }; - SDNode *VLdA = - CurDAG->getMachineNode(Opc, dl, ResTy, AddrTy, MVT::Other, OpsA, 7); + SDNode *VLdA = CurDAG->getMachineNode(QOpcodes0[OpcodeIndex], dl, + ResTy, AddrTy, MVT::Other, OpsA, 7); Chain = SDValue(VLdA, 2); // Load the odd subregs. - Opc = QOpcodes1[OpcodeIndex]; - const SDValue OpsB[] = { SDValue(VLdA, 1), Align, Reg0, SDValue(VLdA, 0), - Pred, Reg0, Chain }; - SDNode *VLdB = - CurDAG->getMachineNode(Opc, dl, ResTy, AddrTy, MVT::Other, OpsB, 7); - SuperReg = SDValue(VLdB, 0); - Chain = SDValue(VLdB, 2); - } - - // Extract out the Q registers. - assert(ARM::qsub_3 == ARM::qsub_0+3 && "Unexpected subreg numbering"); - for (unsigned Vec = 0; Vec < NumVecs; ++Vec) { - SDValue Q = CurDAG->getTargetExtractSubreg(ARM::qsub_0+Vec, - dl, VT, SuperReg); - ReplaceUses(SDValue(N, Vec), Q); - } - ReplaceUses(SDValue(N, NumVecs), Chain); + Ops.push_back(SDValue(VLdA, 1)); + Ops.push_back(Align); + if (isUpdating) { + SDValue Inc = N->getOperand(AddrOpIdx + 1); + assert(isa(Inc.getNode()) && + "only constant post-increment update allowed for VLD3/4"); + (void)Inc; + Ops.push_back(Reg0); + } + Ops.push_back(SDValue(VLdA, 0)); + Ops.push_back(Pred); + Ops.push_back(Reg0); + Ops.push_back(Chain); + VLd = CurDAG->getMachineNode(QOpcodes1[OpcodeIndex], dl, ResTys, + Ops.data(), Ops.size()); + } + + if (NumVecs == 1) + return VLd; + + // Extract out the subregisters. + SDValue SuperReg = SDValue(VLd, 0); + assert(ARM::dsub_7 == ARM::dsub_0+7 && + ARM::qsub_3 == ARM::qsub_0+3 && "Unexpected subreg numbering"); + unsigned Sub0 = (is64BitVector ? ARM::dsub_0 : ARM::qsub_0); + for (unsigned Vec = 0; Vec < NumVecs; ++Vec) + ReplaceUses(SDValue(N, Vec), + CurDAG->getTargetExtractSubreg(Sub0 + Vec, dl, VT, SuperReg)); + ReplaceUses(SDValue(N, NumVecs), SDValue(VLd, 1)); + if (isUpdating) + ReplaceUses(SDValue(N, NumVecs + 1), SDValue(VLd, 2)); return NULL; } -SDNode *ARMDAGToDAGISel::SelectVST(SDNode *N, unsigned NumVecs, +SDNode *ARMDAGToDAGISel::SelectVST(SDNode *N, bool isUpdating, unsigned NumVecs, unsigned *DOpcodes, unsigned *QOpcodes0, unsigned *QOpcodes1) { assert(NumVecs >= 1 && NumVecs <= 4 && "VST NumVecs out-of-range"); DebugLoc dl = N->getDebugLoc(); SDValue MemAddr, Align; - if (!SelectAddrMode6(N, N->getOperand(2), MemAddr, Align)) + unsigned AddrOpIdx = isUpdating ? 1 : 2; + unsigned Vec0Idx = 3; // AddrOpIdx + (isUpdating ? 2 : 1) + if (!SelectAddrMode6(N, N->getOperand(AddrOpIdx), MemAddr, Align)) return NULL; SDValue Chain = N->getOperand(0); - EVT VT = N->getOperand(3).getValueType(); + EVT VT = N->getOperand(Vec0Idx).getValueType(); bool is64BitVector = VT.is64BitVector(); + Align = GetVLDSTAlign(Align, NumVecs, is64BitVector); unsigned OpcodeIndex; switch (VT.getSimpleVT().SimpleTy) { @@ -1222,119 +1609,128 @@ SDNode *ARMDAGToDAGISel::SelectVST(SDNode *N, unsigned NumVecs, break; } + std::vector ResTys; + if (isUpdating) + ResTys.push_back(MVT::i32); + ResTys.push_back(MVT::Other); + SDValue Pred = getAL(CurDAG); SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); - SmallVector Ops; - Ops.push_back(MemAddr); - Ops.push_back(Align); - if (is64BitVector) { + // Double registers and VST1/VST2 quad registers are directly supported. + if (is64BitVector || NumVecs <= 2) { + SDValue SrcReg; if (NumVecs == 1) { - Ops.push_back(N->getOperand(3)); - } else { - SDValue RegSeq; - SDValue V0 = N->getOperand(0+3); - SDValue V1 = N->getOperand(1+3); - + SrcReg = N->getOperand(Vec0Idx); + } else if (is64BitVector) { // Form a REG_SEQUENCE to force register allocation. + SDValue V0 = N->getOperand(Vec0Idx + 0); + SDValue V1 = N->getOperand(Vec0Idx + 1); if (NumVecs == 2) - RegSeq = SDValue(PairDRegs(MVT::v2i64, V0, V1), 0); + SrcReg = SDValue(PairDRegs(MVT::v2i64, V0, V1), 0); else { - SDValue V2 = N->getOperand(2+3); - // If it's a vld3, form a quad D-register and leave the last part as + SDValue V2 = N->getOperand(Vec0Idx + 2); + // If it's a vst3, form a quad D-register and leave the last part as // an undef. SDValue V3 = (NumVecs == 3) ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF,dl,VT), 0) - : N->getOperand(3+3); - RegSeq = SDValue(QuadDRegs(MVT::v4i64, V0, V1, V2, V3), 0); + : N->getOperand(Vec0Idx + 3); + SrcReg = SDValue(QuadDRegs(MVT::v4i64, V0, V1, V2, V3), 0); } - Ops.push_back(RegSeq); - } - Ops.push_back(Pred); - Ops.push_back(Reg0); // predicate register - Ops.push_back(Chain); - unsigned Opc = DOpcodes[OpcodeIndex]; - return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), 6); - } - - if (NumVecs <= 2) { - // Quad registers are directly supported for VST1 and VST2. - unsigned Opc = QOpcodes0[OpcodeIndex]; - if (NumVecs == 1) { - Ops.push_back(N->getOperand(3)); } else { // Form a QQ register. - SDValue Q0 = N->getOperand(3); - SDValue Q1 = N->getOperand(4); - Ops.push_back(SDValue(PairQRegs(MVT::v4i64, Q0, Q1), 0)); + SDValue Q0 = N->getOperand(Vec0Idx); + SDValue Q1 = N->getOperand(Vec0Idx + 1); + SrcReg = SDValue(PairQRegs(MVT::v4i64, Q0, Q1), 0); + } + + unsigned Opc = (is64BitVector ? DOpcodes[OpcodeIndex] : + QOpcodes0[OpcodeIndex]); + Ops.push_back(MemAddr); + Ops.push_back(Align); + if (isUpdating) { + SDValue Inc = N->getOperand(AddrOpIdx + 1); + Ops.push_back(isa(Inc.getNode()) ? Reg0 : Inc); } + Ops.push_back(SrcReg); Ops.push_back(Pred); - Ops.push_back(Reg0); // predicate register + Ops.push_back(Reg0); Ops.push_back(Chain); - return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), 6); + return CurDAG->getMachineNode(Opc, dl, ResTys, Ops.data(), Ops.size()); } // Otherwise, quad registers are stored with two separate instructions, // where one stores the even registers and the other stores the odd registers. // Form the QQQQ REG_SEQUENCE. - SDValue V0 = N->getOperand(0+3); - SDValue V1 = N->getOperand(1+3); - SDValue V2 = N->getOperand(2+3); + SDValue V0 = N->getOperand(Vec0Idx + 0); + SDValue V1 = N->getOperand(Vec0Idx + 1); + SDValue V2 = N->getOperand(Vec0Idx + 2); SDValue V3 = (NumVecs == 3) ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, VT), 0) - : N->getOperand(3+3); + : N->getOperand(Vec0Idx + 3); SDValue RegSeq = SDValue(QuadQRegs(MVT::v8i64, V0, V1, V2, V3), 0); - // Store the even D registers. - Ops.push_back(Reg0); // post-access address offset - Ops.push_back(RegSeq); - Ops.push_back(Pred); - Ops.push_back(Reg0); // predicate register - Ops.push_back(Chain); - unsigned Opc = QOpcodes0[OpcodeIndex]; - SDNode *VStA = CurDAG->getMachineNode(Opc, dl, MemAddr.getValueType(), - MVT::Other, Ops.data(), 7); + // Store the even D registers. This is always an updating store, so that it + // provides the address to the second store for the odd subregs. + const SDValue OpsA[] = { MemAddr, Align, Reg0, RegSeq, Pred, Reg0, Chain }; + SDNode *VStA = CurDAG->getMachineNode(QOpcodes0[OpcodeIndex], dl, + MemAddr.getValueType(), + MVT::Other, OpsA, 7); Chain = SDValue(VStA, 1); // Store the odd D registers. - Ops[0] = SDValue(VStA, 0); // MemAddr - Ops[6] = Chain; - Opc = QOpcodes1[OpcodeIndex]; - SDNode *VStB = CurDAG->getMachineNode(Opc, dl, MemAddr.getValueType(), - MVT::Other, Ops.data(), 7); - Chain = SDValue(VStB, 1); - ReplaceUses(SDValue(N, 0), Chain); - return NULL; + Ops.push_back(SDValue(VStA, 0)); + Ops.push_back(Align); + if (isUpdating) { + SDValue Inc = N->getOperand(AddrOpIdx + 1); + assert(isa(Inc.getNode()) && + "only constant post-increment update allowed for VST3/4"); + (void)Inc; + Ops.push_back(Reg0); + } + Ops.push_back(RegSeq); + Ops.push_back(Pred); + Ops.push_back(Reg0); + Ops.push_back(Chain); + return CurDAG->getMachineNode(QOpcodes1[OpcodeIndex], dl, ResTys, + Ops.data(), Ops.size()); } SDNode *ARMDAGToDAGISel::SelectVLDSTLane(SDNode *N, bool IsLoad, - unsigned NumVecs, unsigned *DOpcodes, - unsigned *QOpcodes0, - unsigned *QOpcodes1) { + bool isUpdating, unsigned NumVecs, + unsigned *DOpcodes, + unsigned *QOpcodes) { assert(NumVecs >=2 && NumVecs <= 4 && "VLDSTLane NumVecs out-of-range"); DebugLoc dl = N->getDebugLoc(); SDValue MemAddr, Align; - if (!SelectAddrMode6(N, N->getOperand(2), MemAddr, Align)) + unsigned AddrOpIdx = isUpdating ? 1 : 2; + unsigned Vec0Idx = 3; // AddrOpIdx + (isUpdating ? 2 : 1) + if (!SelectAddrMode6(N, N->getOperand(AddrOpIdx), MemAddr, Align)) return NULL; SDValue Chain = N->getOperand(0); unsigned Lane = - cast(N->getOperand(NumVecs+3))->getZExtValue(); - EVT VT = IsLoad ? N->getValueType(0) : N->getOperand(3).getValueType(); + cast(N->getOperand(Vec0Idx + NumVecs))->getZExtValue(); + EVT VT = N->getOperand(Vec0Idx).getValueType(); bool is64BitVector = VT.is64BitVector(); - // Quad registers are handled by load/store of subregs. Find the subreg info. - unsigned NumElts = 0; - bool Even = false; - EVT RegVT = VT; - if (!is64BitVector) { - RegVT = GetNEONSubregVT(VT); - NumElts = RegVT.getVectorNumElements(); - Even = Lane < NumElts; - } + unsigned Alignment = 0; + if (NumVecs != 3) { + Alignment = cast(Align)->getZExtValue(); + unsigned NumBytes = NumVecs * VT.getVectorElementType().getSizeInBits()/8; + if (Alignment > NumBytes) + Alignment = NumBytes; + if (Alignment < 8 && Alignment < NumBytes) + Alignment = 0; + // Alignment must be a power of two; make sure of that. + Alignment = (Alignment & -Alignment); + if (Alignment == 1) + Alignment = 0; + } + Align = CurDAG->getTargetConstant(Alignment, MVT::i32); unsigned OpcodeIndex; switch (VT.getSimpleVT().SimpleTy) { @@ -1350,124 +1746,144 @@ SDNode *ARMDAGToDAGISel::SelectVLDSTLane(SDNode *N, bool IsLoad, case MVT::v4i32: OpcodeIndex = 1; break; } + std::vector ResTys; + if (IsLoad) { + unsigned ResTyElts = (NumVecs == 3) ? 4 : NumVecs; + if (!is64BitVector) + ResTyElts *= 2; + ResTys.push_back(EVT::getVectorVT(*CurDAG->getContext(), + MVT::i64, ResTyElts)); + } + if (isUpdating) + ResTys.push_back(MVT::i32); + ResTys.push_back(MVT::Other); + SDValue Pred = getAL(CurDAG); SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); - SmallVector Ops; + SmallVector Ops; Ops.push_back(MemAddr); Ops.push_back(Align); + if (isUpdating) { + SDValue Inc = N->getOperand(AddrOpIdx + 1); + Ops.push_back(isa(Inc.getNode()) ? Reg0 : Inc); + } - unsigned Opc = 0; - if (is64BitVector) { - Opc = DOpcodes[OpcodeIndex]; - SDValue RegSeq; - SDValue V0 = N->getOperand(0+3); - SDValue V1 = N->getOperand(1+3); - if (NumVecs == 2) { - RegSeq = SDValue(PairDRegs(MVT::v2i64, V0, V1), 0); - } else { - SDValue V2 = N->getOperand(2+3); - SDValue V3 = (NumVecs == 3) - ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF,dl,VT), 0) - : N->getOperand(3+3); - RegSeq = SDValue(QuadDRegs(MVT::v4i64, V0, V1, V2, V3), 0); - } - - // Now extract the D registers back out. - Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::dsub_0, dl, VT, RegSeq)); - Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::dsub_1, dl, VT, RegSeq)); - if (NumVecs > 2) - Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::dsub_2, dl, VT,RegSeq)); - if (NumVecs > 3) - Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::dsub_3, dl, VT,RegSeq)); + SDValue SuperReg; + SDValue V0 = N->getOperand(Vec0Idx + 0); + SDValue V1 = N->getOperand(Vec0Idx + 1); + if (NumVecs == 2) { + if (is64BitVector) + SuperReg = SDValue(PairDRegs(MVT::v2i64, V0, V1), 0); + else + SuperReg = SDValue(PairQRegs(MVT::v4i64, V0, V1), 0); } else { - // Check if this is loading the even or odd subreg of a Q register. - if (Lane < NumElts) { - Opc = QOpcodes0[OpcodeIndex]; - } else { - Lane -= NumElts; - Opc = QOpcodes1[OpcodeIndex]; - } - - SDValue RegSeq; - SDValue V0 = N->getOperand(0+3); - SDValue V1 = N->getOperand(1+3); - if (NumVecs == 2) { - RegSeq = SDValue(PairQRegs(MVT::v4i64, V0, V1), 0); - } else { - SDValue V2 = N->getOperand(2+3); - SDValue V3 = (NumVecs == 3) - ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF,dl,VT), 0) - : N->getOperand(3+3); - RegSeq = SDValue(QuadQRegs(MVT::v8i64, V0, V1, V2, V3), 0); - } - - // Extract the subregs of the input vector. - unsigned SubIdx = Even ? ARM::dsub_0 : ARM::dsub_1; - for (unsigned Vec = 0; Vec < NumVecs; ++Vec) - Ops.push_back(CurDAG->getTargetExtractSubreg(SubIdx+Vec*2, dl, RegVT, - RegSeq)); + SDValue V2 = N->getOperand(Vec0Idx + 2); + SDValue V3 = (NumVecs == 3) + ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, VT), 0) + : N->getOperand(Vec0Idx + 3); + if (is64BitVector) + SuperReg = SDValue(QuadDRegs(MVT::v4i64, V0, V1, V2, V3), 0); + else + SuperReg = SDValue(QuadQRegs(MVT::v8i64, V0, V1, V2, V3), 0); } + Ops.push_back(SuperReg); Ops.push_back(getI32Imm(Lane)); Ops.push_back(Pred); Ops.push_back(Reg0); Ops.push_back(Chain); + unsigned Opc = (is64BitVector ? DOpcodes[OpcodeIndex] : + QOpcodes[OpcodeIndex]); + SDNode *VLdLn = CurDAG->getMachineNode(Opc, dl, ResTys, + Ops.data(), Ops.size()); if (!IsLoad) - return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), NumVecs+6); + return VLdLn; - std::vector ResTys(NumVecs, RegVT); - ResTys.push_back(MVT::Other); - SDNode *VLdLn = CurDAG->getMachineNode(Opc, dl, ResTys, Ops.data(),NumVecs+6); + // Extract the subregisters. + SuperReg = SDValue(VLdLn, 0); + assert(ARM::dsub_7 == ARM::dsub_0+7 && + ARM::qsub_3 == ARM::qsub_0+3 && "Unexpected subreg numbering"); + unsigned Sub0 = is64BitVector ? ARM::dsub_0 : ARM::qsub_0; + for (unsigned Vec = 0; Vec < NumVecs; ++Vec) + ReplaceUses(SDValue(N, Vec), + CurDAG->getTargetExtractSubreg(Sub0 + Vec, dl, VT, SuperReg)); + ReplaceUses(SDValue(N, NumVecs), SDValue(VLdLn, 1)); + if (isUpdating) + ReplaceUses(SDValue(N, NumVecs + 1), SDValue(VLdLn, 2)); + return NULL; +} - // Form a REG_SEQUENCE to force register allocation. - SDValue RegSeq; - if (is64BitVector) { - SDValue V0 = SDValue(VLdLn, 0); - SDValue V1 = SDValue(VLdLn, 1); - if (NumVecs == 2) { - RegSeq = SDValue(PairDRegs(MVT::v2i64, V0, V1), 0); - } else { - SDValue V2 = SDValue(VLdLn, 2); - // If it's a vld3, form a quad D-register but discard the last part. - SDValue V3 = (NumVecs == 3) - ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF,dl,VT), 0) - : SDValue(VLdLn, 3); - RegSeq = SDValue(QuadDRegs(MVT::v4i64, V0, V1, V2, V3), 0); - } - } else { - // For 128-bit vectors, take the 64-bit results of the load and insert - // them as subregs into the result. - SDValue V[8]; - for (unsigned Vec = 0, i = 0; Vec < NumVecs; ++Vec, i+=2) { - if (Even) { - V[i] = SDValue(VLdLn, Vec); - V[i+1] = SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, - dl, RegVT), 0); - } else { - V[i] = SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, - dl, RegVT), 0); - V[i+1] = SDValue(VLdLn, Vec); - } - } - if (NumVecs == 3) - V[6] = V[7] = SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, - dl, RegVT), 0); +SDNode *ARMDAGToDAGISel::SelectVLDDup(SDNode *N, bool isUpdating, + unsigned NumVecs, unsigned *Opcodes) { + assert(NumVecs >=2 && NumVecs <= 4 && "VLDDup NumVecs out-of-range"); + DebugLoc dl = N->getDebugLoc(); - if (NumVecs == 2) - RegSeq = SDValue(QuadDRegs(MVT::v4i64, V[0], V[1], V[2], V[3]), 0); - else - RegSeq = SDValue(OctoDRegs(MVT::v8i64, V[0], V[1], V[2], V[3], - V[4], V[5], V[6], V[7]), 0); + SDValue MemAddr, Align; + if (!SelectAddrMode6(N, N->getOperand(1), MemAddr, Align)) + return NULL; + + SDValue Chain = N->getOperand(0); + EVT VT = N->getValueType(0); + + unsigned Alignment = 0; + if (NumVecs != 3) { + Alignment = cast(Align)->getZExtValue(); + unsigned NumBytes = NumVecs * VT.getVectorElementType().getSizeInBits()/8; + if (Alignment > NumBytes) + Alignment = NumBytes; + if (Alignment < 8 && Alignment < NumBytes) + Alignment = 0; + // Alignment must be a power of two; make sure of that. + Alignment = (Alignment & -Alignment); + if (Alignment == 1) + Alignment = 0; + } + Align = CurDAG->getTargetConstant(Alignment, MVT::i32); + + unsigned OpcodeIndex; + switch (VT.getSimpleVT().SimpleTy) { + default: llvm_unreachable("unhandled vld-dup type"); + case MVT::v8i8: OpcodeIndex = 0; break; + case MVT::v4i16: OpcodeIndex = 1; break; + case MVT::v2f32: + case MVT::v2i32: OpcodeIndex = 2; break; + } + + SDValue Pred = getAL(CurDAG); + SDValue Reg0 = CurDAG->getRegister(0, MVT::i32); + SDValue SuperReg; + unsigned Opc = Opcodes[OpcodeIndex]; + SmallVector Ops; + Ops.push_back(MemAddr); + Ops.push_back(Align); + if (isUpdating) { + SDValue Inc = N->getOperand(2); + Ops.push_back(isa(Inc.getNode()) ? Reg0 : Inc); } + Ops.push_back(Pred); + Ops.push_back(Reg0); + Ops.push_back(Chain); + unsigned ResTyElts = (NumVecs == 3) ? 4 : NumVecs; + std::vector ResTys; + ResTys.push_back(EVT::getVectorVT(*CurDAG->getContext(), MVT::i64, ResTyElts)); + if (isUpdating) + ResTys.push_back(MVT::i32); + ResTys.push_back(MVT::Other); + SDNode *VLdDup = + CurDAG->getMachineNode(Opc, dl, ResTys, Ops.data(), Ops.size()); + SuperReg = SDValue(VLdDup, 0); + + // Extract the subregisters. assert(ARM::dsub_7 == ARM::dsub_0+7 && "Unexpected subreg numbering"); - assert(ARM::qsub_3 == ARM::qsub_0+3 && "Unexpected subreg numbering"); - unsigned SubIdx = is64BitVector ? ARM::dsub_0 : ARM::qsub_0; + unsigned SubIdx = ARM::dsub_0; for (unsigned Vec = 0; Vec < NumVecs; ++Vec) ReplaceUses(SDValue(N, Vec), - CurDAG->getTargetExtractSubreg(SubIdx+Vec, dl, VT, RegSeq)); - ReplaceUses(SDValue(N, NumVecs), SDValue(VLdLn, NumVecs)); + CurDAG->getTargetExtractSubreg(SubIdx+Vec, dl, VT, SuperReg)); + ReplaceUses(SDValue(N, NumVecs), SDValue(VLdDup, 1)); + if (isUpdating) + ReplaceUses(SDValue(N, NumVecs + 1), SDValue(VLdDup, 2)); return NULL; } @@ -1486,7 +1902,7 @@ SDNode *ARMDAGToDAGISel::SelectVTBL(SDNode *N, bool IsExt, unsigned NumVecs, RegSeq = SDValue(PairDRegs(MVT::v16i8, V0, V1), 0); else { SDValue V2 = N->getOperand(FirstTblReg + 2); - // If it's a vtbl3, form a quad D-register and leave the last part as + // If it's a vtbl3, form a quad D-register and leave the last part as // an undef. SDValue V3 = (NumVecs == 3) ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, VT), 0) @@ -1494,17 +1910,10 @@ SDNode *ARMDAGToDAGISel::SelectVTBL(SDNode *N, bool IsExt, unsigned NumVecs, RegSeq = SDValue(QuadDRegs(MVT::v4i64, V0, V1, V2, V3), 0); } - // Now extract the D registers back out. SmallVector Ops; if (IsExt) Ops.push_back(N->getOperand(1)); - Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::dsub_0, dl, VT, RegSeq)); - Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::dsub_1, dl, VT, RegSeq)); - if (NumVecs > 2) - Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::dsub_2, dl, VT, RegSeq)); - if (NumVecs > 3) - Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::dsub_3, dl, VT, RegSeq)); - + Ops.push_back(RegSeq); Ops.push_back(N->getOperand(FirstTblReg + NumVecs)); Ops.push_back(getAL(CurDAG)); // predicate Ops.push_back(CurDAG->getRegister(0, MVT::i32)); // predicate register @@ -1574,7 +1983,7 @@ SelectT2CMOVShiftOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag) { SDValue CPTmp0; SDValue CPTmp1; - if (SelectT2ShifterOperandReg(N, TrueVal, CPTmp0, CPTmp1)) { + if (SelectT2ShifterOperandReg(TrueVal, CPTmp0, CPTmp1)) { unsigned SOVal = cast(CPTmp1)->getZExtValue(); unsigned SOShOp = ARM_AM::getSORegShOp(SOVal); unsigned Opc = 0; @@ -1602,7 +2011,7 @@ SelectARMCMOVShiftOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, SDValue CPTmp0; SDValue CPTmp1; SDValue CPTmp2; - if (SelectShifterOperandReg(N, TrueVal, CPTmp0, CPTmp1, CPTmp2)) { + if (SelectShifterOperandReg(TrueVal, CPTmp0, CPTmp1, CPTmp2)) { SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32); SDValue Ops[] = { FalseVal, CPTmp0, CPTmp1, CPTmp2, CC, CCR, InFlag }; return CurDAG->SelectNodeTo(N, ARM::MOVCCs, MVT::i32, Ops, 7); @@ -1611,36 +2020,66 @@ SelectARMCMOVShiftOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, } SDNode *ARMDAGToDAGISel:: -SelectT2CMOVSoImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, - ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag) { +SelectT2CMOVImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, + ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag) { ConstantSDNode *T = dyn_cast(TrueVal); if (!T) return 0; - if (Pred_t2_so_imm(TrueVal.getNode())) { - SDValue True = CurDAG->getTargetConstant(T->getZExtValue(), MVT::i32); + unsigned Opc = 0; + unsigned TrueImm = T->getZExtValue(); + if (is_t2_so_imm(TrueImm)) { + Opc = ARM::t2MOVCCi; + } else if (TrueImm <= 0xffff) { + Opc = ARM::t2MOVCCi16; + } else if (is_t2_so_imm_not(TrueImm)) { + TrueImm = ~TrueImm; + Opc = ARM::t2MVNCCi; + } else if (TrueVal.getNode()->hasOneUse() && Subtarget->hasV6T2Ops()) { + // Large immediate. + Opc = ARM::t2MOVCCi32imm; + } + + if (Opc) { + SDValue True = CurDAG->getTargetConstant(TrueImm, MVT::i32); SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32); SDValue Ops[] = { FalseVal, True, CC, CCR, InFlag }; - return CurDAG->SelectNodeTo(N, - ARM::t2MOVCCi, MVT::i32, Ops, 5); + return CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops, 5); } + return 0; } SDNode *ARMDAGToDAGISel:: -SelectARMCMOVSoImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, - ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag) { +SelectARMCMOVImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal, + ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag) { ConstantSDNode *T = dyn_cast(TrueVal); if (!T) return 0; - if (Pred_so_imm(TrueVal.getNode())) { - SDValue True = CurDAG->getTargetConstant(T->getZExtValue(), MVT::i32); + unsigned Opc = 0; + unsigned TrueImm = T->getZExtValue(); + bool isSoImm = is_so_imm(TrueImm); + if (isSoImm) { + Opc = ARM::MOVCCi; + } else if (Subtarget->hasV6T2Ops() && TrueImm <= 0xffff) { + Opc = ARM::MOVCCi16; + } else if (is_so_imm_not(TrueImm)) { + TrueImm = ~TrueImm; + Opc = ARM::MVNCCi; + } else if (TrueVal.getNode()->hasOneUse() && + (Subtarget->hasV6T2Ops() || ARM_AM::isSOImmTwoPartVal(TrueImm))) { + // Large immediate. + Opc = ARM::MOVCCi32imm; + } + + if (Opc) { + SDValue True = CurDAG->getTargetConstant(TrueImm, MVT::i32); SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32); SDValue Ops[] = { FalseVal, True, CC, CCR, InFlag }; - return CurDAG->SelectNodeTo(N, - ARM::MOVCCi, MVT::i32, Ops, 5); + return CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops, 5); } + return 0; } @@ -1688,18 +2127,18 @@ SDNode *ARMDAGToDAGISel::SelectCMOVOp(SDNode *N) { // (so_imm:i32 (imm:i32):$true), (imm:i32):$cc) // Pattern complexity = 10 cost = 1 size = 0 if (Subtarget->isThumb()) { - SDNode *Res = SelectT2CMOVSoImmOp(N, FalseVal, TrueVal, + SDNode *Res = SelectT2CMOVImmOp(N, FalseVal, TrueVal, CCVal, CCR, InFlag); if (!Res) - Res = SelectT2CMOVSoImmOp(N, TrueVal, FalseVal, + Res = SelectT2CMOVImmOp(N, TrueVal, FalseVal, ARMCC::getOppositeCondition(CCVal), CCR, InFlag); if (Res) return Res; } else { - SDNode *Res = SelectARMCMOVSoImmOp(N, FalseVal, TrueVal, + SDNode *Res = SelectARMCMOVImmOp(N, FalseVal, TrueVal, CCVal, CCR, InFlag); if (!Res) - Res = SelectARMCMOVSoImmOp(N, TrueVal, FalseVal, + Res = SelectARMCMOVImmOp(N, TrueVal, FalseVal, ARMCC::getOppositeCondition(CCVal), CCR, InFlag); if (Res) return Res; @@ -1742,13 +2181,7 @@ SDNode *ARMDAGToDAGISel::SelectConcatVector(SDNode *N) { EVT VT = N->getValueType(0); if (!VT.is128BitVector() || N->getNumOperands() != 2) llvm_unreachable("unexpected CONCAT_VECTORS"); - DebugLoc dl = N->getDebugLoc(); - SDValue V0 = N->getOperand(0); - SDValue V1 = N->getOperand(1); - SDValue SubReg0 = CurDAG->getTargetConstant(ARM::dsub_0, MVT::i32); - SDValue SubReg1 = CurDAG->getTargetConstant(ARM::dsub_1, MVT::i32); - const SDValue Ops[] = { V0, SubReg0, V1, SubReg1 }; - return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops, 4); + return PairDRegs(VT, N->getOperand(0), N->getOperand(1)); } SDNode *ARMDAGToDAGISel::Select(SDNode *N) { @@ -1788,19 +2221,18 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) { SDValue Pred = getAL(CurDAG); SDValue PredReg = CurDAG->getRegister(0, MVT::i32); SDValue Ops[] = { CPIdx, Pred, PredReg, CurDAG->getEntryNode() }; - ResNode = CurDAG->getMachineNode(ARM::tLDRcp, dl, MVT::i32, MVT::Other, + ResNode = CurDAG->getMachineNode(ARM::tLDRpci, dl, MVT::i32, MVT::Other, Ops, 4); } else { SDValue Ops[] = { CPIdx, - CurDAG->getRegister(0, MVT::i32), CurDAG->getTargetConstant(0, MVT::i32), getAL(CurDAG), CurDAG->getRegister(0, MVT::i32), CurDAG->getEntryNode() }; ResNode=CurDAG->getMachineNode(ARM::LDRcp, dl, MVT::i32, MVT::Other, - Ops, 6); + Ops, 5); } ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0)); return NULL; @@ -1930,7 +2362,9 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) { SDValue Ops[] = { N->getOperand(0), N->getOperand(1), getAL(CurDAG), CurDAG->getRegister(0, MVT::i32), CurDAG->getRegister(0, MVT::i32) }; - return CurDAG->getMachineNode(ARM::UMULL, dl, MVT::i32, MVT::i32, Ops, 5); + return CurDAG->getMachineNode(Subtarget->hasV6Ops() ? + ARM::UMULL : ARM::UMULLv5, + dl, MVT::i32, MVT::i32, Ops, 5); } } case ISD::SMUL_LOHI: { @@ -1944,7 +2378,9 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) { SDValue Ops[] = { N->getOperand(0), N->getOperand(1), getAL(CurDAG), CurDAG->getRegister(0, MVT::i32), CurDAG->getRegister(0, MVT::i32) }; - return CurDAG->getMachineNode(ARM::SMULL, dl, MVT::i32, MVT::i32, Ops, 5); + return CurDAG->getMachineNode(Subtarget->hasV6Ops() ? + ARM::SMULL : ARM::SMULLv5, + dl, MVT::i32, MVT::i32, Ops, 5); } } case ISD::LOAD: { @@ -1987,7 +2423,7 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) { MVT::i32); SDValue Ops[] = { N1, Tmp2, N3, Chain, InFlag }; SDNode *ResNode = CurDAG->getMachineNode(Opc, dl, MVT::Other, - MVT::Flag, Ops, 5); + MVT::Glue, Ops, 5); Chain = SDValue(ResNode, 0); if (N->getNumValues() == 2) { InFlag = SDValue(ResNode, 1); @@ -2088,12 +2524,11 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) { EVT VecVT = N->getValueType(0); EVT EltVT = VecVT.getVectorElementType(); unsigned NumElts = VecVT.getVectorNumElements(); - if (EltVT.getSimpleVT() == MVT::f64) { + if (EltVT == MVT::f64) { assert(NumElts == 2 && "unexpected type for BUILD_VECTOR"); return PairDRegs(VecVT, N->getOperand(0), N->getOperand(1)); } - assert(EltVT.getSimpleVT() == MVT::f32 && - "unexpected type for BUILD_VECTOR"); + assert(EltVT == MVT::f32 && "unexpected type for BUILD_VECTOR"); if (NumElts == 2) return PairSRegs(VecVT, N->getOperand(0), N->getOperand(1)); assert(NumElts == 4 && "unexpected type for BUILD_VECTOR"); @@ -2101,6 +2536,170 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) { N->getOperand(2), N->getOperand(3)); } + case ARMISD::VLD2DUP: { + unsigned Opcodes[] = { ARM::VLD2DUPd8Pseudo, ARM::VLD2DUPd16Pseudo, + ARM::VLD2DUPd32Pseudo }; + return SelectVLDDup(N, false, 2, Opcodes); + } + + case ARMISD::VLD3DUP: { + unsigned Opcodes[] = { ARM::VLD3DUPd8Pseudo, ARM::VLD3DUPd16Pseudo, + ARM::VLD3DUPd32Pseudo }; + return SelectVLDDup(N, false, 3, Opcodes); + } + + case ARMISD::VLD4DUP: { + unsigned Opcodes[] = { ARM::VLD4DUPd8Pseudo, ARM::VLD4DUPd16Pseudo, + ARM::VLD4DUPd32Pseudo }; + return SelectVLDDup(N, false, 4, Opcodes); + } + + case ARMISD::VLD2DUP_UPD: { + unsigned Opcodes[] = { ARM::VLD2DUPd8Pseudo_UPD, ARM::VLD2DUPd16Pseudo_UPD, + ARM::VLD2DUPd32Pseudo_UPD }; + return SelectVLDDup(N, true, 2, Opcodes); + } + + case ARMISD::VLD3DUP_UPD: { + unsigned Opcodes[] = { ARM::VLD3DUPd8Pseudo_UPD, ARM::VLD3DUPd16Pseudo_UPD, + ARM::VLD3DUPd32Pseudo_UPD }; + return SelectVLDDup(N, true, 3, Opcodes); + } + + case ARMISD::VLD4DUP_UPD: { + unsigned Opcodes[] = { ARM::VLD4DUPd8Pseudo_UPD, ARM::VLD4DUPd16Pseudo_UPD, + ARM::VLD4DUPd32Pseudo_UPD }; + return SelectVLDDup(N, true, 4, Opcodes); + } + + case ARMISD::VLD1_UPD: { + unsigned DOpcodes[] = { ARM::VLD1d8_UPD, ARM::VLD1d16_UPD, + ARM::VLD1d32_UPD, ARM::VLD1d64_UPD }; + unsigned QOpcodes[] = { ARM::VLD1q8Pseudo_UPD, ARM::VLD1q16Pseudo_UPD, + ARM::VLD1q32Pseudo_UPD, ARM::VLD1q64Pseudo_UPD }; + return SelectVLD(N, true, 1, DOpcodes, QOpcodes, 0); + } + + case ARMISD::VLD2_UPD: { + unsigned DOpcodes[] = { ARM::VLD2d8Pseudo_UPD, ARM::VLD2d16Pseudo_UPD, + ARM::VLD2d32Pseudo_UPD, ARM::VLD1q64Pseudo_UPD }; + unsigned QOpcodes[] = { ARM::VLD2q8Pseudo_UPD, ARM::VLD2q16Pseudo_UPD, + ARM::VLD2q32Pseudo_UPD }; + return SelectVLD(N, true, 2, DOpcodes, QOpcodes, 0); + } + + case ARMISD::VLD3_UPD: { + unsigned DOpcodes[] = { ARM::VLD3d8Pseudo_UPD, ARM::VLD3d16Pseudo_UPD, + ARM::VLD3d32Pseudo_UPD, ARM::VLD1d64TPseudo_UPD }; + unsigned QOpcodes0[] = { ARM::VLD3q8Pseudo_UPD, + ARM::VLD3q16Pseudo_UPD, + ARM::VLD3q32Pseudo_UPD }; + unsigned QOpcodes1[] = { ARM::VLD3q8oddPseudo_UPD, + ARM::VLD3q16oddPseudo_UPD, + ARM::VLD3q32oddPseudo_UPD }; + return SelectVLD(N, true, 3, DOpcodes, QOpcodes0, QOpcodes1); + } + + case ARMISD::VLD4_UPD: { + unsigned DOpcodes[] = { ARM::VLD4d8Pseudo_UPD, ARM::VLD4d16Pseudo_UPD, + ARM::VLD4d32Pseudo_UPD, ARM::VLD1d64QPseudo_UPD }; + unsigned QOpcodes0[] = { ARM::VLD4q8Pseudo_UPD, + ARM::VLD4q16Pseudo_UPD, + ARM::VLD4q32Pseudo_UPD }; + unsigned QOpcodes1[] = { ARM::VLD4q8oddPseudo_UPD, + ARM::VLD4q16oddPseudo_UPD, + ARM::VLD4q32oddPseudo_UPD }; + return SelectVLD(N, true, 4, DOpcodes, QOpcodes0, QOpcodes1); + } + + case ARMISD::VLD2LN_UPD: { + unsigned DOpcodes[] = { ARM::VLD2LNd8Pseudo_UPD, ARM::VLD2LNd16Pseudo_UPD, + ARM::VLD2LNd32Pseudo_UPD }; + unsigned QOpcodes[] = { ARM::VLD2LNq16Pseudo_UPD, + ARM::VLD2LNq32Pseudo_UPD }; + return SelectVLDSTLane(N, true, true, 2, DOpcodes, QOpcodes); + } + + case ARMISD::VLD3LN_UPD: { + unsigned DOpcodes[] = { ARM::VLD3LNd8Pseudo_UPD, ARM::VLD3LNd16Pseudo_UPD, + ARM::VLD3LNd32Pseudo_UPD }; + unsigned QOpcodes[] = { ARM::VLD3LNq16Pseudo_UPD, + ARM::VLD3LNq32Pseudo_UPD }; + return SelectVLDSTLane(N, true, true, 3, DOpcodes, QOpcodes); + } + + case ARMISD::VLD4LN_UPD: { + unsigned DOpcodes[] = { ARM::VLD4LNd8Pseudo_UPD, ARM::VLD4LNd16Pseudo_UPD, + ARM::VLD4LNd32Pseudo_UPD }; + unsigned QOpcodes[] = { ARM::VLD4LNq16Pseudo_UPD, + ARM::VLD4LNq32Pseudo_UPD }; + return SelectVLDSTLane(N, true, true, 4, DOpcodes, QOpcodes); + } + + case ARMISD::VST1_UPD: { + unsigned DOpcodes[] = { ARM::VST1d8_UPD, ARM::VST1d16_UPD, + ARM::VST1d32_UPD, ARM::VST1d64_UPD }; + unsigned QOpcodes[] = { ARM::VST1q8Pseudo_UPD, ARM::VST1q16Pseudo_UPD, + ARM::VST1q32Pseudo_UPD, ARM::VST1q64Pseudo_UPD }; + return SelectVST(N, true, 1, DOpcodes, QOpcodes, 0); + } + + case ARMISD::VST2_UPD: { + unsigned DOpcodes[] = { ARM::VST2d8Pseudo_UPD, ARM::VST2d16Pseudo_UPD, + ARM::VST2d32Pseudo_UPD, ARM::VST1q64Pseudo_UPD }; + unsigned QOpcodes[] = { ARM::VST2q8Pseudo_UPD, ARM::VST2q16Pseudo_UPD, + ARM::VST2q32Pseudo_UPD }; + return SelectVST(N, true, 2, DOpcodes, QOpcodes, 0); + } + + case ARMISD::VST3_UPD: { + unsigned DOpcodes[] = { ARM::VST3d8Pseudo_UPD, ARM::VST3d16Pseudo_UPD, + ARM::VST3d32Pseudo_UPD, ARM::VST1d64TPseudo_UPD }; + unsigned QOpcodes0[] = { ARM::VST3q8Pseudo_UPD, + ARM::VST3q16Pseudo_UPD, + ARM::VST3q32Pseudo_UPD }; + unsigned QOpcodes1[] = { ARM::VST3q8oddPseudo_UPD, + ARM::VST3q16oddPseudo_UPD, + ARM::VST3q32oddPseudo_UPD }; + return SelectVST(N, true, 3, DOpcodes, QOpcodes0, QOpcodes1); + } + + case ARMISD::VST4_UPD: { + unsigned DOpcodes[] = { ARM::VST4d8Pseudo_UPD, ARM::VST4d16Pseudo_UPD, + ARM::VST4d32Pseudo_UPD, ARM::VST1d64QPseudo_UPD }; + unsigned QOpcodes0[] = { ARM::VST4q8Pseudo_UPD, + ARM::VST4q16Pseudo_UPD, + ARM::VST4q32Pseudo_UPD }; + unsigned QOpcodes1[] = { ARM::VST4q8oddPseudo_UPD, + ARM::VST4q16oddPseudo_UPD, + ARM::VST4q32oddPseudo_UPD }; + return SelectVST(N, true, 4, DOpcodes, QOpcodes0, QOpcodes1); + } + + case ARMISD::VST2LN_UPD: { + unsigned DOpcodes[] = { ARM::VST2LNd8Pseudo_UPD, ARM::VST2LNd16Pseudo_UPD, + ARM::VST2LNd32Pseudo_UPD }; + unsigned QOpcodes[] = { ARM::VST2LNq16Pseudo_UPD, + ARM::VST2LNq32Pseudo_UPD }; + return SelectVLDSTLane(N, false, true, 2, DOpcodes, QOpcodes); + } + + case ARMISD::VST3LN_UPD: { + unsigned DOpcodes[] = { ARM::VST3LNd8Pseudo_UPD, ARM::VST3LNd16Pseudo_UPD, + ARM::VST3LNd32Pseudo_UPD }; + unsigned QOpcodes[] = { ARM::VST3LNq16Pseudo_UPD, + ARM::VST3LNq32Pseudo_UPD }; + return SelectVLDSTLane(N, false, true, 3, DOpcodes, QOpcodes); + } + + case ARMISD::VST4LN_UPD: { + unsigned DOpcodes[] = { ARM::VST4LNd8Pseudo_UPD, ARM::VST4LNd16Pseudo_UPD, + ARM::VST4LNd32Pseudo_UPD }; + unsigned QOpcodes[] = { ARM::VST4LNq16Pseudo_UPD, + ARM::VST4LNq32Pseudo_UPD }; + return SelectVLDSTLane(N, false, true, 4, DOpcodes, QOpcodes); + } + case ISD::INTRINSIC_VOID: case ISD::INTRINSIC_W_CHAIN: { unsigned IntNo = cast(N->getOperand(1))->getZExtValue(); @@ -2113,7 +2712,7 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) { ARM::VLD1d32, ARM::VLD1d64 }; unsigned QOpcodes[] = { ARM::VLD1q8Pseudo, ARM::VLD1q16Pseudo, ARM::VLD1q32Pseudo, ARM::VLD1q64Pseudo }; - return SelectVLD(N, 1, DOpcodes, QOpcodes, 0); + return SelectVLD(N, false, 1, DOpcodes, QOpcodes, 0); } case Intrinsic::arm_neon_vld2: { @@ -2121,7 +2720,7 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) { ARM::VLD2d32Pseudo, ARM::VLD1q64Pseudo }; unsigned QOpcodes[] = { ARM::VLD2q8Pseudo, ARM::VLD2q16Pseudo, ARM::VLD2q32Pseudo }; - return SelectVLD(N, 2, DOpcodes, QOpcodes, 0); + return SelectVLD(N, false, 2, DOpcodes, QOpcodes, 0); } case Intrinsic::arm_neon_vld3: { @@ -2130,10 +2729,10 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) { unsigned QOpcodes0[] = { ARM::VLD3q8Pseudo_UPD, ARM::VLD3q16Pseudo_UPD, ARM::VLD3q32Pseudo_UPD }; - unsigned QOpcodes1[] = { ARM::VLD3q8oddPseudo_UPD, - ARM::VLD3q16oddPseudo_UPD, - ARM::VLD3q32oddPseudo_UPD }; - return SelectVLD(N, 3, DOpcodes, QOpcodes0, QOpcodes1); + unsigned QOpcodes1[] = { ARM::VLD3q8oddPseudo, + ARM::VLD3q16oddPseudo, + ARM::VLD3q32oddPseudo }; + return SelectVLD(N, false, 3, DOpcodes, QOpcodes0, QOpcodes1); } case Intrinsic::arm_neon_vld4: { @@ -2142,31 +2741,31 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) { unsigned QOpcodes0[] = { ARM::VLD4q8Pseudo_UPD, ARM::VLD4q16Pseudo_UPD, ARM::VLD4q32Pseudo_UPD }; - unsigned QOpcodes1[] = { ARM::VLD4q8oddPseudo_UPD, - ARM::VLD4q16oddPseudo_UPD, - ARM::VLD4q32oddPseudo_UPD }; - return SelectVLD(N, 4, DOpcodes, QOpcodes0, QOpcodes1); + unsigned QOpcodes1[] = { ARM::VLD4q8oddPseudo, + ARM::VLD4q16oddPseudo, + ARM::VLD4q32oddPseudo }; + return SelectVLD(N, false, 4, DOpcodes, QOpcodes0, QOpcodes1); } case Intrinsic::arm_neon_vld2lane: { - unsigned DOpcodes[] = { ARM::VLD2LNd8, ARM::VLD2LNd16, ARM::VLD2LNd32 }; - unsigned QOpcodes0[] = { ARM::VLD2LNq16, ARM::VLD2LNq32 }; - unsigned QOpcodes1[] = { ARM::VLD2LNq16odd, ARM::VLD2LNq32odd }; - return SelectVLDSTLane(N, true, 2, DOpcodes, QOpcodes0, QOpcodes1); + unsigned DOpcodes[] = { ARM::VLD2LNd8Pseudo, ARM::VLD2LNd16Pseudo, + ARM::VLD2LNd32Pseudo }; + unsigned QOpcodes[] = { ARM::VLD2LNq16Pseudo, ARM::VLD2LNq32Pseudo }; + return SelectVLDSTLane(N, true, false, 2, DOpcodes, QOpcodes); } case Intrinsic::arm_neon_vld3lane: { - unsigned DOpcodes[] = { ARM::VLD3LNd8, ARM::VLD3LNd16, ARM::VLD3LNd32 }; - unsigned QOpcodes0[] = { ARM::VLD3LNq16, ARM::VLD3LNq32 }; - unsigned QOpcodes1[] = { ARM::VLD3LNq16odd, ARM::VLD3LNq32odd }; - return SelectVLDSTLane(N, true, 3, DOpcodes, QOpcodes0, QOpcodes1); + unsigned DOpcodes[] = { ARM::VLD3LNd8Pseudo, ARM::VLD3LNd16Pseudo, + ARM::VLD3LNd32Pseudo }; + unsigned QOpcodes[] = { ARM::VLD3LNq16Pseudo, ARM::VLD3LNq32Pseudo }; + return SelectVLDSTLane(N, true, false, 3, DOpcodes, QOpcodes); } case Intrinsic::arm_neon_vld4lane: { - unsigned DOpcodes[] = { ARM::VLD4LNd8, ARM::VLD4LNd16, ARM::VLD4LNd32 }; - unsigned QOpcodes0[] = { ARM::VLD4LNq16, ARM::VLD4LNq32 }; - unsigned QOpcodes1[] = { ARM::VLD4LNq16odd, ARM::VLD4LNq32odd }; - return SelectVLDSTLane(N, true, 4, DOpcodes, QOpcodes0, QOpcodes1); + unsigned DOpcodes[] = { ARM::VLD4LNd8Pseudo, ARM::VLD4LNd16Pseudo, + ARM::VLD4LNd32Pseudo }; + unsigned QOpcodes[] = { ARM::VLD4LNq16Pseudo, ARM::VLD4LNq32Pseudo }; + return SelectVLDSTLane(N, true, false, 4, DOpcodes, QOpcodes); } case Intrinsic::arm_neon_vst1: { @@ -2174,7 +2773,7 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) { ARM::VST1d32, ARM::VST1d64 }; unsigned QOpcodes[] = { ARM::VST1q8Pseudo, ARM::VST1q16Pseudo, ARM::VST1q32Pseudo, ARM::VST1q64Pseudo }; - return SelectVST(N, 1, DOpcodes, QOpcodes, 0); + return SelectVST(N, false, 1, DOpcodes, QOpcodes, 0); } case Intrinsic::arm_neon_vst2: { @@ -2182,7 +2781,7 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) { ARM::VST2d32Pseudo, ARM::VST1q64Pseudo }; unsigned QOpcodes[] = { ARM::VST2q8Pseudo, ARM::VST2q16Pseudo, ARM::VST2q32Pseudo }; - return SelectVST(N, 2, DOpcodes, QOpcodes, 0); + return SelectVST(N, false, 2, DOpcodes, QOpcodes, 0); } case Intrinsic::arm_neon_vst3: { @@ -2191,10 +2790,10 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) { unsigned QOpcodes0[] = { ARM::VST3q8Pseudo_UPD, ARM::VST3q16Pseudo_UPD, ARM::VST3q32Pseudo_UPD }; - unsigned QOpcodes1[] = { ARM::VST3q8oddPseudo_UPD, - ARM::VST3q16oddPseudo_UPD, - ARM::VST3q32oddPseudo_UPD }; - return SelectVST(N, 3, DOpcodes, QOpcodes0, QOpcodes1); + unsigned QOpcodes1[] = { ARM::VST3q8oddPseudo, + ARM::VST3q16oddPseudo, + ARM::VST3q32oddPseudo }; + return SelectVST(N, false, 3, DOpcodes, QOpcodes0, QOpcodes1); } case Intrinsic::arm_neon_vst4: { @@ -2203,31 +2802,31 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) { unsigned QOpcodes0[] = { ARM::VST4q8Pseudo_UPD, ARM::VST4q16Pseudo_UPD, ARM::VST4q32Pseudo_UPD }; - unsigned QOpcodes1[] = { ARM::VST4q8oddPseudo_UPD, - ARM::VST4q16oddPseudo_UPD, - ARM::VST4q32oddPseudo_UPD }; - return SelectVST(N, 4, DOpcodes, QOpcodes0, QOpcodes1); + unsigned QOpcodes1[] = { ARM::VST4q8oddPseudo, + ARM::VST4q16oddPseudo, + ARM::VST4q32oddPseudo }; + return SelectVST(N, false, 4, DOpcodes, QOpcodes0, QOpcodes1); } case Intrinsic::arm_neon_vst2lane: { - unsigned DOpcodes[] = { ARM::VST2LNd8, ARM::VST2LNd16, ARM::VST2LNd32 }; - unsigned QOpcodes0[] = { ARM::VST2LNq16, ARM::VST2LNq32 }; - unsigned QOpcodes1[] = { ARM::VST2LNq16odd, ARM::VST2LNq32odd }; - return SelectVLDSTLane(N, false, 2, DOpcodes, QOpcodes0, QOpcodes1); + unsigned DOpcodes[] = { ARM::VST2LNd8Pseudo, ARM::VST2LNd16Pseudo, + ARM::VST2LNd32Pseudo }; + unsigned QOpcodes[] = { ARM::VST2LNq16Pseudo, ARM::VST2LNq32Pseudo }; + return SelectVLDSTLane(N, false, false, 2, DOpcodes, QOpcodes); } case Intrinsic::arm_neon_vst3lane: { - unsigned DOpcodes[] = { ARM::VST3LNd8, ARM::VST3LNd16, ARM::VST3LNd32 }; - unsigned QOpcodes0[] = { ARM::VST3LNq16, ARM::VST3LNq32 }; - unsigned QOpcodes1[] = { ARM::VST3LNq16odd, ARM::VST3LNq32odd }; - return SelectVLDSTLane(N, false, 3, DOpcodes, QOpcodes0, QOpcodes1); + unsigned DOpcodes[] = { ARM::VST3LNd8Pseudo, ARM::VST3LNd16Pseudo, + ARM::VST3LNd32Pseudo }; + unsigned QOpcodes[] = { ARM::VST3LNq16Pseudo, ARM::VST3LNq32Pseudo }; + return SelectVLDSTLane(N, false, false, 3, DOpcodes, QOpcodes); } case Intrinsic::arm_neon_vst4lane: { - unsigned DOpcodes[] = { ARM::VST4LNd8, ARM::VST4LNd16, ARM::VST4LNd32 }; - unsigned QOpcodes0[] = { ARM::VST4LNq16, ARM::VST4LNq32 }; - unsigned QOpcodes1[] = { ARM::VST4LNq16odd, ARM::VST4LNq32odd }; - return SelectVLDSTLane(N, false, 4, DOpcodes, QOpcodes0, QOpcodes1); + unsigned DOpcodes[] = { ARM::VST4LNd8Pseudo, ARM::VST4LNd16Pseudo, + ARM::VST4LNd32Pseudo }; + unsigned QOpcodes[] = { ARM::VST4LNq16Pseudo, ARM::VST4LNq32Pseudo }; + return SelectVLDSTLane(N, false, false, 4, DOpcodes, QOpcodes); } } break; @@ -2240,18 +2839,18 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) { break; case Intrinsic::arm_neon_vtbl2: - return SelectVTBL(N, false, 2, ARM::VTBL2); + return SelectVTBL(N, false, 2, ARM::VTBL2Pseudo); case Intrinsic::arm_neon_vtbl3: - return SelectVTBL(N, false, 3, ARM::VTBL3); + return SelectVTBL(N, false, 3, ARM::VTBL3Pseudo); case Intrinsic::arm_neon_vtbl4: - return SelectVTBL(N, false, 4, ARM::VTBL4); + return SelectVTBL(N, false, 4, ARM::VTBL4Pseudo); case Intrinsic::arm_neon_vtbx2: - return SelectVTBL(N, true, 2, ARM::VTBX2); + return SelectVTBL(N, true, 2, ARM::VTBX2Pseudo); case Intrinsic::arm_neon_vtbx3: - return SelectVTBL(N, true, 3, ARM::VTBX3); + return SelectVTBL(N, true, 3, ARM::VTBX3Pseudo); case Intrinsic::arm_neon_vtbx4: - return SelectVTBL(N, true, 4, ARM::VTBX4); + return SelectVTBL(N, true, 4, ARM::VTBX4Pseudo); } break; } diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp index ce4a2c90689c..1835ec0f0054 100644 --- a/lib/Target/ARM/ARMISelLowering.cpp +++ b/lib/Target/ARM/ARMISelLowering.cpp @@ -15,6 +15,7 @@ #define DEBUG_TYPE "arm-isel" #include "ARM.h" #include "ARMAddressingModes.h" +#include "ARMCallingConv.h" #include "ARMConstantPoolValue.h" #include "ARMISelLowering.h" #include "ARMMachineFunctionInfo.h" @@ -28,9 +29,11 @@ #include "llvm/Function.h" #include "llvm/GlobalValue.h" #include "llvm/Instruction.h" +#include "llvm/Instructions.h" #include "llvm/Intrinsics.h" #include "llvm/Type.h" #include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/IntrinsicLowering.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" @@ -41,6 +44,7 @@ #include "llvm/MC/MCSectionMachO.h" #include "llvm/Target/TargetOptions.h" #include "llvm/ADT/VectorExtras.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" @@ -50,6 +54,7 @@ using namespace llvm; STATISTIC(NumTailCalls, "Number of tail calls"); +STATISTIC(NumMovwMovt, "Number of GAs materialized with movw + movt"); // This option should go away when tail calls fully work. static cl::opt @@ -57,14 +62,7 @@ EnableARMTailCalls("arm-tail-calls", cl::Hidden, cl::desc("Generate tail calls (TEMPORARY OPTION)."), cl::init(false)); -// This option should go away when Machine LICM is smart enough to hoist a -// reg-to-reg VDUP. -static cl::opt -EnableARMVDUPsplat("arm-vdup-splat", cl::Hidden, - cl::desc("Generate VDUP for integer constant splats (TEMPORARY OPTION)."), - cl::init(false)); - -static cl::opt +cl::opt EnableARMLongCalls("arm-long-calls", cl::Hidden, cl::desc("Generate calls via indirect call instructions"), cl::init(false)); @@ -74,28 +72,6 @@ ARMInterworking("arm-interworking", cl::Hidden, cl::desc("Enable / disable ARM interworking (for debugging only)"), cl::init(true)); -static cl::opt -EnableARMCodePlacement("arm-code-placement", cl::Hidden, - cl::desc("Enable code placement pass for ARM"), - cl::init(false)); - -static bool CC_ARM_APCS_Custom_f64(unsigned &ValNo, EVT &ValVT, EVT &LocVT, - CCValAssign::LocInfo &LocInfo, - ISD::ArgFlagsTy &ArgFlags, - CCState &State); -static bool CC_ARM_AAPCS_Custom_f64(unsigned &ValNo, EVT &ValVT, EVT &LocVT, - CCValAssign::LocInfo &LocInfo, - ISD::ArgFlagsTy &ArgFlags, - CCState &State); -static bool RetCC_ARM_APCS_Custom_f64(unsigned &ValNo, EVT &ValVT, EVT &LocVT, - CCValAssign::LocInfo &LocInfo, - ISD::ArgFlagsTy &ArgFlags, - CCState &State); -static bool RetCC_ARM_AAPCS_Custom_f64(unsigned &ValNo, EVT &ValVT, EVT &LocVT, - CCValAssign::LocInfo &LocInfo, - ISD::ArgFlagsTy &ArgFlags, - CCState &State); - void ARMTargetLowering::addTypeForNEON(EVT VT, EVT PromotedLdStVT, EVT PromotedBitwiseVT) { if (VT != PromotedLdStVT) { @@ -111,8 +87,7 @@ void ARMTargetLowering::addTypeForNEON(EVT VT, EVT PromotedLdStVT, EVT ElemTy = VT.getVectorElementType(); if (ElemTy != MVT::i64 && ElemTy != MVT::f64) setOperationAction(ISD::VSETCC, VT.getSimpleVT(), Custom); - if (ElemTy == MVT::i8 || ElemTy == MVT::i16) - setOperationAction(ISD::EXTRACT_VECTOR_ELT, VT.getSimpleVT(), Custom); + setOperationAction(ISD::EXTRACT_VECTOR_ELT, VT.getSimpleVT(), Custom); if (ElemTy != MVT::i32) { setOperationAction(ISD::SINT_TO_FP, VT.getSimpleVT(), Expand); setOperationAction(ISD::UINT_TO_FP, VT.getSimpleVT(), Expand); @@ -122,7 +97,7 @@ void ARMTargetLowering::addTypeForNEON(EVT VT, EVT PromotedLdStVT, setOperationAction(ISD::BUILD_VECTOR, VT.getSimpleVT(), Custom); setOperationAction(ISD::VECTOR_SHUFFLE, VT.getSimpleVT(), Custom); setOperationAction(ISD::CONCAT_VECTORS, VT.getSimpleVT(), Legal); - setOperationAction(ISD::EXTRACT_SUBVECTOR, VT.getSimpleVT(), Expand); + setOperationAction(ISD::EXTRACT_SUBVECTOR, VT.getSimpleVT(), Legal); setOperationAction(ISD::SELECT, VT.getSimpleVT(), Expand); setOperationAction(ISD::SELECT_CC, VT.getSimpleVT(), Expand); if (VT.isInteger()) { @@ -131,6 +106,10 @@ void ARMTargetLowering::addTypeForNEON(EVT VT, EVT PromotedLdStVT, setOperationAction(ISD::SRL, VT.getSimpleVT(), Custom); setLoadExtAction(ISD::SEXTLOAD, VT.getSimpleVT(), Expand); setLoadExtAction(ISD::ZEXTLOAD, VT.getSimpleVT(), Expand); + for (unsigned InnerVT = (unsigned)MVT::FIRST_VECTOR_VALUETYPE; + InnerVT <= (unsigned)MVT::LAST_VECTOR_VALUETYPE; ++InnerVT) + setTruncStoreAction(VT.getSimpleVT(), + (MVT::SimpleValueType)InnerVT, Expand); } setLoadExtAction(ISD::EXTLOAD, VT.getSimpleVT(), Expand); @@ -177,6 +156,7 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) : TargetLowering(TM, createTLOF(TM)) { Subtarget = &TM.getSubtarget(); RegInfo = TM.getRegisterInfo(); + Itins = TM.getInstrItineraryData(); if (Subtarget->isTargetDarwin()) { // Uses VFP for Thumb libfuncs if available. @@ -260,13 +240,157 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) setLibcallName(RTLIB::SRL_I128, 0); setLibcallName(RTLIB::SRA_I128, 0); - // Libcalls should use the AAPCS base standard ABI, even if hard float - // is in effect, as per the ARM RTABI specification, section 4.1.2. if (Subtarget->isAAPCS_ABI()) { - for (int i = 0; i < RTLIB::UNKNOWN_LIBCALL; ++i) { - setLibcallCallingConv(static_cast(i), - CallingConv::ARM_AAPCS); - } + // Double-precision floating-point arithmetic helper functions + // RTABI chapter 4.1.2, Table 2 + setLibcallName(RTLIB::ADD_F64, "__aeabi_dadd"); + setLibcallName(RTLIB::DIV_F64, "__aeabi_ddiv"); + setLibcallName(RTLIB::MUL_F64, "__aeabi_dmul"); + setLibcallName(RTLIB::SUB_F64, "__aeabi_dsub"); + setLibcallCallingConv(RTLIB::ADD_F64, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::DIV_F64, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::MUL_F64, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::SUB_F64, CallingConv::ARM_AAPCS); + + // Double-precision floating-point comparison helper functions + // RTABI chapter 4.1.2, Table 3 + setLibcallName(RTLIB::OEQ_F64, "__aeabi_dcmpeq"); + setCmpLibcallCC(RTLIB::OEQ_F64, ISD::SETNE); + setLibcallName(RTLIB::UNE_F64, "__aeabi_dcmpeq"); + setCmpLibcallCC(RTLIB::UNE_F64, ISD::SETEQ); + setLibcallName(RTLIB::OLT_F64, "__aeabi_dcmplt"); + setCmpLibcallCC(RTLIB::OLT_F64, ISD::SETNE); + setLibcallName(RTLIB::OLE_F64, "__aeabi_dcmple"); + setCmpLibcallCC(RTLIB::OLE_F64, ISD::SETNE); + setLibcallName(RTLIB::OGE_F64, "__aeabi_dcmpge"); + setCmpLibcallCC(RTLIB::OGE_F64, ISD::SETNE); + setLibcallName(RTLIB::OGT_F64, "__aeabi_dcmpgt"); + setCmpLibcallCC(RTLIB::OGT_F64, ISD::SETNE); + setLibcallName(RTLIB::UO_F64, "__aeabi_dcmpun"); + setCmpLibcallCC(RTLIB::UO_F64, ISD::SETNE); + setLibcallName(RTLIB::O_F64, "__aeabi_dcmpun"); + setCmpLibcallCC(RTLIB::O_F64, ISD::SETEQ); + setLibcallCallingConv(RTLIB::OEQ_F64, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::UNE_F64, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::OLT_F64, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::OLE_F64, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::OGE_F64, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::OGT_F64, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::UO_F64, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::O_F64, CallingConv::ARM_AAPCS); + + // Single-precision floating-point arithmetic helper functions + // RTABI chapter 4.1.2, Table 4 + setLibcallName(RTLIB::ADD_F32, "__aeabi_fadd"); + setLibcallName(RTLIB::DIV_F32, "__aeabi_fdiv"); + setLibcallName(RTLIB::MUL_F32, "__aeabi_fmul"); + setLibcallName(RTLIB::SUB_F32, "__aeabi_fsub"); + setLibcallCallingConv(RTLIB::ADD_F32, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::DIV_F32, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::MUL_F32, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::SUB_F32, CallingConv::ARM_AAPCS); + + // Single-precision floating-point comparison helper functions + // RTABI chapter 4.1.2, Table 5 + setLibcallName(RTLIB::OEQ_F32, "__aeabi_fcmpeq"); + setCmpLibcallCC(RTLIB::OEQ_F32, ISD::SETNE); + setLibcallName(RTLIB::UNE_F32, "__aeabi_fcmpeq"); + setCmpLibcallCC(RTLIB::UNE_F32, ISD::SETEQ); + setLibcallName(RTLIB::OLT_F32, "__aeabi_fcmplt"); + setCmpLibcallCC(RTLIB::OLT_F32, ISD::SETNE); + setLibcallName(RTLIB::OLE_F32, "__aeabi_fcmple"); + setCmpLibcallCC(RTLIB::OLE_F32, ISD::SETNE); + setLibcallName(RTLIB::OGE_F32, "__aeabi_fcmpge"); + setCmpLibcallCC(RTLIB::OGE_F32, ISD::SETNE); + setLibcallName(RTLIB::OGT_F32, "__aeabi_fcmpgt"); + setCmpLibcallCC(RTLIB::OGT_F32, ISD::SETNE); + setLibcallName(RTLIB::UO_F32, "__aeabi_fcmpun"); + setCmpLibcallCC(RTLIB::UO_F32, ISD::SETNE); + setLibcallName(RTLIB::O_F32, "__aeabi_fcmpun"); + setCmpLibcallCC(RTLIB::O_F32, ISD::SETEQ); + setLibcallCallingConv(RTLIB::OEQ_F32, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::UNE_F32, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::OLT_F32, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::OLE_F32, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::OGE_F32, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::OGT_F32, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::UO_F32, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::O_F32, CallingConv::ARM_AAPCS); + + // Floating-point to integer conversions. + // RTABI chapter 4.1.2, Table 6 + setLibcallName(RTLIB::FPTOSINT_F64_I32, "__aeabi_d2iz"); + setLibcallName(RTLIB::FPTOUINT_F64_I32, "__aeabi_d2uiz"); + setLibcallName(RTLIB::FPTOSINT_F64_I64, "__aeabi_d2lz"); + setLibcallName(RTLIB::FPTOUINT_F64_I64, "__aeabi_d2ulz"); + setLibcallName(RTLIB::FPTOSINT_F32_I32, "__aeabi_f2iz"); + setLibcallName(RTLIB::FPTOUINT_F32_I32, "__aeabi_f2uiz"); + setLibcallName(RTLIB::FPTOSINT_F32_I64, "__aeabi_f2lz"); + setLibcallName(RTLIB::FPTOUINT_F32_I64, "__aeabi_f2ulz"); + setLibcallCallingConv(RTLIB::FPTOSINT_F64_I32, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::FPTOUINT_F64_I32, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::FPTOSINT_F64_I64, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::FPTOUINT_F64_I64, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::FPTOSINT_F32_I32, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::FPTOUINT_F32_I32, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::FPTOSINT_F32_I64, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::FPTOUINT_F32_I64, CallingConv::ARM_AAPCS); + + // Conversions between floating types. + // RTABI chapter 4.1.2, Table 7 + setLibcallName(RTLIB::FPROUND_F64_F32, "__aeabi_d2f"); + setLibcallName(RTLIB::FPEXT_F32_F64, "__aeabi_f2d"); + setLibcallCallingConv(RTLIB::FPROUND_F64_F32, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::FPEXT_F32_F64, CallingConv::ARM_AAPCS); + + // Integer to floating-point conversions. + // RTABI chapter 4.1.2, Table 8 + setLibcallName(RTLIB::SINTTOFP_I32_F64, "__aeabi_i2d"); + setLibcallName(RTLIB::UINTTOFP_I32_F64, "__aeabi_ui2d"); + setLibcallName(RTLIB::SINTTOFP_I64_F64, "__aeabi_l2d"); + setLibcallName(RTLIB::UINTTOFP_I64_F64, "__aeabi_ul2d"); + setLibcallName(RTLIB::SINTTOFP_I32_F32, "__aeabi_i2f"); + setLibcallName(RTLIB::UINTTOFP_I32_F32, "__aeabi_ui2f"); + setLibcallName(RTLIB::SINTTOFP_I64_F32, "__aeabi_l2f"); + setLibcallName(RTLIB::UINTTOFP_I64_F32, "__aeabi_ul2f"); + setLibcallCallingConv(RTLIB::SINTTOFP_I32_F64, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::UINTTOFP_I32_F64, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::SINTTOFP_I64_F64, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::UINTTOFP_I64_F64, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::SINTTOFP_I32_F32, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::UINTTOFP_I32_F32, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::SINTTOFP_I64_F32, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::UINTTOFP_I64_F32, CallingConv::ARM_AAPCS); + + // Long long helper functions + // RTABI chapter 4.2, Table 9 + setLibcallName(RTLIB::MUL_I64, "__aeabi_lmul"); + setLibcallName(RTLIB::SDIV_I64, "__aeabi_ldivmod"); + setLibcallName(RTLIB::UDIV_I64, "__aeabi_uldivmod"); + setLibcallName(RTLIB::SHL_I64, "__aeabi_llsl"); + setLibcallName(RTLIB::SRL_I64, "__aeabi_llsr"); + setLibcallName(RTLIB::SRA_I64, "__aeabi_lasr"); + setLibcallCallingConv(RTLIB::MUL_I64, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::SDIV_I64, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::UDIV_I64, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::SHL_I64, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::SRL_I64, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::SRA_I64, CallingConv::ARM_AAPCS); + + // Integer division functions + // RTABI chapter 4.3.1 + setLibcallName(RTLIB::SDIV_I8, "__aeabi_idiv"); + setLibcallName(RTLIB::SDIV_I16, "__aeabi_idiv"); + setLibcallName(RTLIB::SDIV_I32, "__aeabi_idiv"); + setLibcallName(RTLIB::UDIV_I8, "__aeabi_uidiv"); + setLibcallName(RTLIB::UDIV_I16, "__aeabi_uidiv"); + setLibcallName(RTLIB::UDIV_I32, "__aeabi_uidiv"); + setLibcallCallingConv(RTLIB::SDIV_I8, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::SDIV_I16, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::SDIV_I32, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::UDIV_I8, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::UDIV_I16, CallingConv::ARM_AAPCS); + setLibcallCallingConv(RTLIB::UDIV_I32, CallingConv::ARM_AAPCS); } if (Subtarget->isThumb1Only()) @@ -330,9 +454,16 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) setOperationAction(ISD::MUL, MVT::v8i16, Custom); setOperationAction(ISD::MUL, MVT::v4i32, Custom); setOperationAction(ISD::MUL, MVT::v2i64, Custom); + // Custom handling for some vector types to avoid expensive expansions + setOperationAction(ISD::SDIV, MVT::v4i16, Custom); + setOperationAction(ISD::SDIV, MVT::v8i8, Custom); + setOperationAction(ISD::UDIV, MVT::v4i16, Custom); + setOperationAction(ISD::UDIV, MVT::v8i8, Custom); setOperationAction(ISD::VSETCC, MVT::v1i64, Expand); setOperationAction(ISD::VSETCC, MVT::v2i64, Expand); + setTargetDAGCombine(ISD::INTRINSIC_VOID); + setTargetDAGCombine(ISD::INTRINSIC_W_CHAIN); setTargetDAGCombine(ISD::INTRINSIC_WO_CHAIN); setTargetDAGCombine(ISD::SHL); setTargetDAGCombine(ISD::SRL); @@ -341,6 +472,10 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) setTargetDAGCombine(ISD::ZERO_EXTEND); setTargetDAGCombine(ISD::ANY_EXTEND); setTargetDAGCombine(ISD::SELECT_CC); + setTargetDAGCombine(ISD::BUILD_VECTOR); + setTargetDAGCombine(ISD::VECTOR_SHUFFLE); + setTargetDAGCombine(ISD::INSERT_VECTOR_ELT); + setTargetDAGCombine(ISD::STORE); } computeRegisterProperties(); @@ -397,7 +532,7 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) setOperationAction(ISD::BSWAP, MVT::i32, Expand); // These are expanded into libcalls. - if (!Subtarget->hasDivide()) { + if (!Subtarget->hasDivide() || !Subtarget->isThumb2()) { // v7M has a hardware divider setOperationAction(ISD::SDIV, MVT::i32, Expand); setOperationAction(ISD::UDIV, MVT::i32, Expand); @@ -423,14 +558,15 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); setOperationAction(ISD::EHSELECTION, MVT::i32, Expand); - // FIXME: Shouldn't need this, since no register is used, but the legalizer - // doesn't yet know how to not do that for SjLj. - setExceptionSelectorRegister(ARM::R0); + setOperationAction(ISD::EXCEPTIONADDR, MVT::i32, Expand); + setExceptionPointerRegister(ARM::R0); + setExceptionSelectorRegister(ARM::R1); + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand); // ARMv6 Thumb1 (except for CPUs that support dmb / dsb) and earlier use // the default expansion. if (Subtarget->hasDataBarrier() || - (Subtarget->hasV6Ops() && !Subtarget->isThumb1Only())) { + (Subtarget->hasV6Ops() && !Subtarget->isThumb())) { // membarrier needs custom lowering; the rest are legal and handled // normally. setOperationAction(ISD::MEMBARRIER, MVT::Other, Custom); @@ -474,6 +610,8 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) setOperationAction(ISD::ATOMIC_LOAD_XOR, MVT::i64, Expand); setOperationAction(ISD::ATOMIC_LOAD_NAND, MVT::i64, Expand); + setOperationAction(ISD::PREFETCH, MVT::Other, Custom); + // Requires SXTB/SXTH, available on v6 and up in both ARM and Thumb modes. if (!Subtarget->hasV6Ops()) { setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand); @@ -484,7 +622,7 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) if (!UseSoftFloat && Subtarget->hasVFP2() && !Subtarget->isThumb1Only()) { // Turn f64->i64 into VMOVRRD, i64 -> f64 to VMOVDRR // iff target supports vfp2. - setOperationAction(ISD::BIT_CONVERT, MVT::i64, Custom); + setOperationAction(ISD::BITCAST, MVT::i64, Custom); setOperationAction(ISD::FLT_ROUNDS_, MVT::i32, Custom); } @@ -493,6 +631,7 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) if (Subtarget->isTargetDarwin()) { setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom); setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom); + setOperationAction(ISD::EH_SJLJ_DISPATCHSETUP, MVT::Other, Custom); } setOperationAction(ISD::SETCC, MVT::i32, Expand); @@ -547,8 +686,10 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) setTargetDAGCombine(ISD::SUB); setTargetDAGCombine(ISD::MUL); - if (Subtarget->hasV6T2Ops()) + if (Subtarget->hasV6T2Ops() || Subtarget->hasNEON()) setTargetDAGCombine(ISD::OR); + if (Subtarget->hasNEON()) + setTargetDAGCombine(ISD::AND); setStackPointerRegisterToSaveRestore(ARM::SP); @@ -557,16 +698,26 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM) else setSchedulingPreference(Sched::Hybrid); - maxStoresPerMemcpy = 1; //// temporary - rewrite interface to use type + //// temporary - rewrite interface to use type + maxStoresPerMemcpy = maxStoresPerMemcpyOptSize = 1; // On ARM arguments smaller than 4 bytes are extended, so all arguments // are at least 4 bytes aligned. setMinStackArgumentAlignment(4); - if (EnableARMCodePlacement) - benefitFromCodePlacementOpt = true; + benefitFromCodePlacementOpt = true; } +// FIXME: It might make sense to define the representative register class as the +// nearest super-register that has a non-null superset. For example, DPR_VFP2 is +// a super-register of SPR, and DPR is a superset if DPR_VFP2. Consequently, +// SPR's representative would be DPR_VFP2. This should work well if register +// pressure tracking were modified such that a register use would increment the +// pressure of the register class's representative and all of it's super +// classes' representatives transitively. We have not implemented this because +// of the difficulty prior to coalescing of modeling operand register classes +// due to the common occurence of cross class copies and subregister insertions +// and extractions. std::pair ARMTargetLowering::findRepresentativeClass(EVT VT) const{ const TargetRegisterClass *RRC = 0; @@ -580,6 +731,12 @@ ARMTargetLowering::findRepresentativeClass(EVT VT) const{ case MVT::f32: case MVT::f64: case MVT::v8i8: case MVT::v4i16: case MVT::v2i32: case MVT::v1i64: case MVT::v2f32: RRC = ARM::DPRRegisterClass; + // When NEON is used for SP, only half of the register file is available + // because operations that define both SP and DP results will be constrained + // to the VFP2 class (D0-D15). We currently model this constraint prior to + // coalescing by double-counting the SP regs. See the FIXME above. + if (Subtarget->useNEONForSinglePrecisionFP()) + Cost = 2; break; case MVT::v16i8: case MVT::v8i16: case MVT::v4i32: case MVT::v2i64: case MVT::v4f32: case MVT::v2f64: @@ -602,6 +759,8 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const { switch (Opcode) { default: return 0; case ARMISD::Wrapper: return "ARMISD::Wrapper"; + case ARMISD::WrapperDYN: return "ARMISD::WrapperDYN"; + case ARMISD::WrapperPIC: return "ARMISD::WrapperPIC"; case ARMISD::WrapperJT: return "ARMISD::WrapperJT"; case ARMISD::CALL: return "ARMISD::CALL"; case ARMISD::CALL_PRED: return "ARMISD::CALL_PRED"; @@ -612,7 +771,6 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const { case ARMISD::BR2_JT: return "ARMISD::BR2_JT"; case ARMISD::RET_FLAG: return "ARMISD::RET_FLAG"; case ARMISD::PIC_ADD: return "ARMISD::PIC_ADD"; - case ARMISD::AND: return "ARMISD::AND"; case ARMISD::CMP: return "ARMISD::CMP"; case ARMISD::CMPZ: return "ARMISD::CMPZ"; case ARMISD::CMPFP: return "ARMISD::CMPFP"; @@ -633,25 +791,33 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const { case ARMISD::SRA_FLAG: return "ARMISD::SRA_FLAG"; case ARMISD::RRX: return "ARMISD::RRX"; - case ARMISD::VMOVRRD: return "ARMISD::VMOVRRD"; - case ARMISD::VMOVDRR: return "ARMISD::VMOVDRR"; + case ARMISD::VMOVRRD: return "ARMISD::VMOVRRD"; + case ARMISD::VMOVDRR: return "ARMISD::VMOVDRR"; case ARMISD::EH_SJLJ_SETJMP: return "ARMISD::EH_SJLJ_SETJMP"; case ARMISD::EH_SJLJ_LONGJMP:return "ARMISD::EH_SJLJ_LONGJMP"; + case ARMISD::EH_SJLJ_DISPATCHSETUP:return "ARMISD::EH_SJLJ_DISPATCHSETUP"; case ARMISD::TC_RETURN: return "ARMISD::TC_RETURN"; - + case ARMISD::THREAD_POINTER:return "ARMISD::THREAD_POINTER"; case ARMISD::DYN_ALLOC: return "ARMISD::DYN_ALLOC"; case ARMISD::MEMBARRIER: return "ARMISD::MEMBARRIER"; - case ARMISD::SYNCBARRIER: return "ARMISD::SYNCBARRIER"; + case ARMISD::MEMBARRIER_MCR: return "ARMISD::MEMBARRIER_MCR"; + + case ARMISD::PRELOAD: return "ARMISD::PRELOAD"; case ARMISD::VCEQ: return "ARMISD::VCEQ"; + case ARMISD::VCEQZ: return "ARMISD::VCEQZ"; case ARMISD::VCGE: return "ARMISD::VCGE"; + case ARMISD::VCGEZ: return "ARMISD::VCGEZ"; + case ARMISD::VCLEZ: return "ARMISD::VCLEZ"; case ARMISD::VCGEU: return "ARMISD::VCGEU"; case ARMISD::VCGT: return "ARMISD::VCGT"; + case ARMISD::VCGTZ: return "ARMISD::VCGTZ"; + case ARMISD::VCLTZ: return "ARMISD::VCLTZ"; case ARMISD::VCGTU: return "ARMISD::VCGTU"; case ARMISD::VTST: return "ARMISD::VTST"; @@ -693,6 +859,28 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const { case ARMISD::FMAX: return "ARMISD::FMAX"; case ARMISD::FMIN: return "ARMISD::FMIN"; case ARMISD::BFI: return "ARMISD::BFI"; + case ARMISD::VORRIMM: return "ARMISD::VORRIMM"; + case ARMISD::VBICIMM: return "ARMISD::VBICIMM"; + case ARMISD::VLD2DUP: return "ARMISD::VLD2DUP"; + case ARMISD::VLD3DUP: return "ARMISD::VLD3DUP"; + case ARMISD::VLD4DUP: return "ARMISD::VLD4DUP"; + case ARMISD::VLD1_UPD: return "ARMISD::VLD1_UPD"; + case ARMISD::VLD2_UPD: return "ARMISD::VLD2_UPD"; + case ARMISD::VLD3_UPD: return "ARMISD::VLD3_UPD"; + case ARMISD::VLD4_UPD: return "ARMISD::VLD4_UPD"; + case ARMISD::VLD2LN_UPD: return "ARMISD::VLD2LN_UPD"; + case ARMISD::VLD3LN_UPD: return "ARMISD::VLD3LN_UPD"; + case ARMISD::VLD4LN_UPD: return "ARMISD::VLD4LN_UPD"; + case ARMISD::VLD2DUP_UPD: return "ARMISD::VLD2DUP_UPD"; + case ARMISD::VLD3DUP_UPD: return "ARMISD::VLD3DUP_UPD"; + case ARMISD::VLD4DUP_UPD: return "ARMISD::VLD4DUP_UPD"; + case ARMISD::VST1_UPD: return "ARMISD::VST1_UPD"; + case ARMISD::VST2_UPD: return "ARMISD::VST2_UPD"; + case ARMISD::VST3_UPD: return "ARMISD::VST3_UPD"; + case ARMISD::VST4_UPD: return "ARMISD::VST4_UPD"; + case ARMISD::VST2LN_UPD: return "ARMISD::VST2LN_UPD"; + case ARMISD::VST3LN_UPD: return "ARMISD::VST3LN_UPD"; + case ARMISD::VST4LN_UPD: return "ARMISD::VST4LN_UPD"; } } @@ -735,6 +923,8 @@ Sched::Preference ARMTargetLowering::getSchedulingPreference(SDNode *N) const { for (unsigned i = 0; i != NumVals; ++i) { EVT VT = N->getValueType(i); + if (VT == MVT::Glue || VT == MVT::Other) + continue; if (VT.isFloatingPoint() || VT.isVector()) return Sched::Latency; } @@ -746,25 +936,29 @@ Sched::Preference ARMTargetLowering::getSchedulingPreference(SDNode *N) const { // is not available. const TargetInstrInfo *TII = getTargetMachine().getInstrInfo(); const TargetInstrDesc &TID = TII->get(N->getMachineOpcode()); - if (TID.mayLoad()) - return Sched::Latency; - const InstrItineraryData &Itins = getTargetMachine().getInstrItineraryData(); - if (!Itins.isEmpty() && Itins.getStageLatency(TID.getSchedClass()) > 2) + if (TID.getNumDefs() == 0) + return Sched::RegPressure; + if (!Itins->isEmpty() && + Itins->getOperandCycle(TID.getSchedClass(), 0) > 2) return Sched::Latency; + return Sched::RegPressure; } +// FIXME: Move to RegInfo unsigned ARMTargetLowering::getRegPressureLimit(const TargetRegisterClass *RC, MachineFunction &MF) const { + const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering(); + switch (RC->getID()) { default: return 0; case ARM::tGPRRegClassID: - return RegInfo->hasFP(MF) ? 4 : 5; + return TFI->hasFP(MF) ? 4 : 5; case ARM::GPRRegClassID: { - unsigned FP = RegInfo->hasFP(MF) ? 1 : 0; + unsigned FP = TFI->hasFP(MF) ? 1 : 0; return 10 - FP - (Subtarget->isR9Reserved() ? 1 : 0); } case ARM::SPRRegClassID: // Currently not used as 'rep' register class. @@ -829,136 +1023,6 @@ static void FPCCToARMCC(ISD::CondCode CC, ARMCC::CondCodes &CondCode, #include "ARMGenCallingConv.inc" -// APCS f64 is in register pairs, possibly split to stack -static bool f64AssignAPCS(unsigned &ValNo, EVT &ValVT, EVT &LocVT, - CCValAssign::LocInfo &LocInfo, - CCState &State, bool CanFail) { - static const unsigned RegList[] = { ARM::R0, ARM::R1, ARM::R2, ARM::R3 }; - - // Try to get the first register. - if (unsigned Reg = State.AllocateReg(RegList, 4)) - State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); - else { - // For the 2nd half of a v2f64, do not fail. - if (CanFail) - return false; - - // Put the whole thing on the stack. - State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT, - State.AllocateStack(8, 4), - LocVT, LocInfo)); - return true; - } - - // Try to get the second register. - if (unsigned Reg = State.AllocateReg(RegList, 4)) - State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); - else - State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT, - State.AllocateStack(4, 4), - LocVT, LocInfo)); - return true; -} - -static bool CC_ARM_APCS_Custom_f64(unsigned &ValNo, EVT &ValVT, EVT &LocVT, - CCValAssign::LocInfo &LocInfo, - ISD::ArgFlagsTy &ArgFlags, - CCState &State) { - if (!f64AssignAPCS(ValNo, ValVT, LocVT, LocInfo, State, true)) - return false; - if (LocVT == MVT::v2f64 && - !f64AssignAPCS(ValNo, ValVT, LocVT, LocInfo, State, false)) - return false; - return true; // we handled it -} - -// AAPCS f64 is in aligned register pairs -static bool f64AssignAAPCS(unsigned &ValNo, EVT &ValVT, EVT &LocVT, - CCValAssign::LocInfo &LocInfo, - CCState &State, bool CanFail) { - static const unsigned HiRegList[] = { ARM::R0, ARM::R2 }; - static const unsigned LoRegList[] = { ARM::R1, ARM::R3 }; - static const unsigned ShadowRegList[] = { ARM::R0, ARM::R1 }; - - unsigned Reg = State.AllocateReg(HiRegList, ShadowRegList, 2); - if (Reg == 0) { - // For the 2nd half of a v2f64, do not just fail. - if (CanFail) - return false; - - // Put the whole thing on the stack. - State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT, - State.AllocateStack(8, 8), - LocVT, LocInfo)); - return true; - } - - unsigned i; - for (i = 0; i < 2; ++i) - if (HiRegList[i] == Reg) - break; - - unsigned T = State.AllocateReg(LoRegList[i]); - (void)T; - assert(T == LoRegList[i] && "Could not allocate register"); - - State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); - State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, LoRegList[i], - LocVT, LocInfo)); - return true; -} - -static bool CC_ARM_AAPCS_Custom_f64(unsigned &ValNo, EVT &ValVT, EVT &LocVT, - CCValAssign::LocInfo &LocInfo, - ISD::ArgFlagsTy &ArgFlags, - CCState &State) { - if (!f64AssignAAPCS(ValNo, ValVT, LocVT, LocInfo, State, true)) - return false; - if (LocVT == MVT::v2f64 && - !f64AssignAAPCS(ValNo, ValVT, LocVT, LocInfo, State, false)) - return false; - return true; // we handled it -} - -static bool f64RetAssign(unsigned &ValNo, EVT &ValVT, EVT &LocVT, - CCValAssign::LocInfo &LocInfo, CCState &State) { - static const unsigned HiRegList[] = { ARM::R0, ARM::R2 }; - static const unsigned LoRegList[] = { ARM::R1, ARM::R3 }; - - unsigned Reg = State.AllocateReg(HiRegList, LoRegList, 2); - if (Reg == 0) - return false; // we didn't handle it - - unsigned i; - for (i = 0; i < 2; ++i) - if (HiRegList[i] == Reg) - break; - - State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); - State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, LoRegList[i], - LocVT, LocInfo)); - return true; -} - -static bool RetCC_ARM_APCS_Custom_f64(unsigned &ValNo, EVT &ValVT, EVT &LocVT, - CCValAssign::LocInfo &LocInfo, - ISD::ArgFlagsTy &ArgFlags, - CCState &State) { - if (!f64RetAssign(ValNo, ValVT, LocVT, LocInfo, State)) - return false; - if (LocVT == MVT::v2f64 && !f64RetAssign(ValNo, ValVT, LocVT, LocInfo, State)) - return false; - return true; // we handled it -} - -static bool RetCC_ARM_AAPCS_Custom_f64(unsigned &ValNo, EVT &ValVT, EVT &LocVT, - CCValAssign::LocInfo &LocInfo, - ISD::ArgFlagsTy &ArgFlags, - CCState &State) { - return RetCC_ARM_APCS_Custom_f64(ValNo, ValVT, LocVT, LocInfo, ArgFlags, - State); -} - /// CCAssignFnForNode - Selects the correct CCAssignFn for a the /// given CallingConvention value. CCAssignFn *ARMTargetLowering::CCAssignFnForNode(CallingConv::ID CC, @@ -967,23 +1031,29 @@ CCAssignFn *ARMTargetLowering::CCAssignFnForNode(CallingConv::ID CC, switch (CC) { default: llvm_unreachable("Unsupported calling convention"); - case CallingConv::C: case CallingConv::Fast: + if (Subtarget->hasVFP2() && !isVarArg) { + if (!Subtarget->isAAPCS_ABI()) + return (Return ? RetFastCC_ARM_APCS : FastCC_ARM_APCS); + // For AAPCS ABI targets, just use VFP variant of the calling convention. + return (Return ? RetCC_ARM_AAPCS_VFP : CC_ARM_AAPCS_VFP); + } + // Fallthrough + case CallingConv::C: { // Use target triple & subtarget features to do actual dispatch. - if (Subtarget->isAAPCS_ABI()) { - if (Subtarget->hasVFP2() && - FloatABIType == FloatABI::Hard && !isVarArg) - return (Return ? RetCC_ARM_AAPCS_VFP: CC_ARM_AAPCS_VFP); - else - return (Return ? RetCC_ARM_AAPCS: CC_ARM_AAPCS); - } else - return (Return ? RetCC_ARM_APCS: CC_ARM_APCS); + if (!Subtarget->isAAPCS_ABI()) + return (Return ? RetCC_ARM_APCS : CC_ARM_APCS); + else if (Subtarget->hasVFP2() && + FloatABIType == FloatABI::Hard && !isVarArg) + return (Return ? RetCC_ARM_AAPCS_VFP : CC_ARM_AAPCS_VFP); + return (Return ? RetCC_ARM_AAPCS : CC_ARM_AAPCS); + } case CallingConv::ARM_AAPCS_VFP: - return (Return ? RetCC_ARM_AAPCS_VFP: CC_ARM_AAPCS_VFP); + return (Return ? RetCC_ARM_AAPCS_VFP : CC_ARM_AAPCS_VFP); case CallingConv::ARM_AAPCS: - return (Return ? RetCC_ARM_AAPCS: CC_ARM_AAPCS); + return (Return ? RetCC_ARM_AAPCS : CC_ARM_AAPCS); case CallingConv::ARM_APCS: - return (Return ? RetCC_ARM_APCS: CC_ARM_APCS); + return (Return ? RetCC_ARM_APCS : CC_ARM_APCS); } } @@ -1050,7 +1120,7 @@ ARMTargetLowering::LowerCallResult(SDValue Chain, SDValue InFlag, default: llvm_unreachable("Unknown loc info!"); case CCValAssign::Full: break; case CCValAssign::BCvt: - Val = DAG.getNode(ISD::BIT_CONVERT, dl, VA.getValVT(), Val); + Val = DAG.getNode(ISD::BITCAST, dl, VA.getValVT(), Val); break; } @@ -1073,7 +1143,7 @@ CreateCopyOfByValArgument(SDValue Src, SDValue Dst, SDValue Chain, SDValue SizeNode = DAG.getConstant(Flags.getByValSize(), MVT::i32); return DAG.getMemcpy(Chain, dl, Dst, Src, SizeNode, Flags.getByValAlign(), /*isVolatile=*/false, /*AlwaysInline=*/false, - NULL, 0, NULL, 0); + MachinePointerInfo(0), MachinePointerInfo(0)); } /// LowerMemOpCallTo - Store the argument to the stack. @@ -1086,11 +1156,11 @@ ARMTargetLowering::LowerMemOpCallTo(SDValue Chain, unsigned LocMemOffset = VA.getLocMemOffset(); SDValue PtrOff = DAG.getIntPtrConstant(LocMemOffset); PtrOff = DAG.getNode(ISD::ADD, dl, getPointerTy(), StackPtr, PtrOff); - if (Flags.isByVal()) { + if (Flags.isByVal()) return CreateCopyOfByValArgument(Arg, PtrOff, Chain, Flags, DAG, dl); - } + return DAG.getStore(Chain, dl, Arg, PtrOff, - PseudoSourceValue::getStack(), LocMemOffset, + MachinePointerInfo::getStack(LocMemOffset), false, false, 0); } @@ -1198,7 +1268,7 @@ ARMTargetLowering::LowerCall(SDValue Chain, SDValue Callee, Arg = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Arg); break; case CCValAssign::BCvt: - Arg = DAG.getNode(ISD::BIT_CONVERT, dl, VA.getLocVT(), Arg); + Arg = DAG.getNode(ISD::BITCAST, dl, VA.getLocVT(), Arg); break; } @@ -1289,7 +1359,7 @@ ARMTargetLowering::LowerCall(SDValue Chain, SDValue Callee, if (GlobalAddressSDNode *G = dyn_cast(Callee)) { const GlobalValue *GV = G->getGlobal(); // Create a constant pool entry for the callee address - unsigned ARMPCLabelIndex = AFI->createConstPoolEntryUId(); + unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); ARMConstantPoolValue *CPV = new ARMConstantPoolValue(GV, ARMPCLabelIndex, ARMCP::CPValue, 0); @@ -1298,13 +1368,13 @@ ARMTargetLowering::LowerCall(SDValue Chain, SDValue Callee, CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); Callee = DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(), CPAddr, - PseudoSourceValue::getConstantPool(), 0, + MachinePointerInfo::getConstantPool(), false, false, 0); } else if (ExternalSymbolSDNode *S=dyn_cast(Callee)) { const char *Sym = S->getSymbol(); // Create a constant pool entry for the callee address - unsigned ARMPCLabelIndex = AFI->createConstPoolEntryUId(); + unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); ARMConstantPoolValue *CPV = new ARMConstantPoolValue(*DAG.getContext(), Sym, ARMPCLabelIndex, 0); // Get the address of the callee into a register @@ -1312,7 +1382,7 @@ ARMTargetLowering::LowerCall(SDValue Chain, SDValue Callee, CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); Callee = DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(), CPAddr, - PseudoSourceValue::getConstantPool(), 0, + MachinePointerInfo::getConstantPool(), false, false, 0); } } else if (GlobalAddressSDNode *G = dyn_cast(Callee)) { @@ -1326,7 +1396,7 @@ ARMTargetLowering::LowerCall(SDValue Chain, SDValue Callee, isLocalARMFunc = !Subtarget->isThumb() && (!isExt || !ARMInterworking); // tBX takes a register source operand. if (isARMFunc && Subtarget->isThumb1Only() && !Subtarget->hasV5TOps()) { - unsigned ARMPCLabelIndex = AFI->createConstPoolEntryUId(); + unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); ARMConstantPoolValue *CPV = new ARMConstantPoolValue(GV, ARMPCLabelIndex, ARMCP::CPValue, 4); @@ -1334,13 +1404,19 @@ ARMTargetLowering::LowerCall(SDValue Chain, SDValue Callee, CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); Callee = DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(), CPAddr, - PseudoSourceValue::getConstantPool(), 0, + MachinePointerInfo::getConstantPool(), false, false, 0); SDValue PICLabel = DAG.getConstant(ARMPCLabelIndex, MVT::i32); Callee = DAG.getNode(ARMISD::PIC_ADD, dl, getPointerTy(), Callee, PICLabel); - } else - Callee = DAG.getTargetGlobalAddress(GV, dl, getPointerTy()); + } else { + // On ELF targets for PIC code, direct calls should go through the PLT + unsigned OpFlags = 0; + if (Subtarget->isTargetELF() && + getTargetMachine().getRelocationModel() == Reloc::PIC_) + OpFlags = ARMII::MO_PLT; + Callee = DAG.getTargetGlobalAddress(GV, dl, getPointerTy(), 0, OpFlags); + } } else if (ExternalSymbolSDNode *S = dyn_cast(Callee)) { isDirect = true; bool isStub = Subtarget->isTargetDarwin() && @@ -1349,20 +1425,26 @@ ARMTargetLowering::LowerCall(SDValue Chain, SDValue Callee, // tBX takes a register source operand. const char *Sym = S->getSymbol(); if (isARMFunc && Subtarget->isThumb1Only() && !Subtarget->hasV5TOps()) { - unsigned ARMPCLabelIndex = AFI->createConstPoolEntryUId(); + unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); ARMConstantPoolValue *CPV = new ARMConstantPoolValue(*DAG.getContext(), Sym, ARMPCLabelIndex, 4); SDValue CPAddr = DAG.getTargetConstantPool(CPV, getPointerTy(), 4); CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); Callee = DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(), CPAddr, - PseudoSourceValue::getConstantPool(), 0, + MachinePointerInfo::getConstantPool(), false, false, 0); SDValue PICLabel = DAG.getConstant(ARMPCLabelIndex, MVT::i32); Callee = DAG.getNode(ARMISD::PIC_ADD, dl, getPointerTy(), Callee, PICLabel); - } else - Callee = DAG.getTargetExternalSymbol(Sym, getPointerTy()); + } else { + unsigned OpFlags = 0; + // On ELF targets for PIC code, direct calls should go through the PLT + if (Subtarget->isTargetELF() && + getTargetMachine().getRelocationModel() == Reloc::PIC_) + OpFlags = ARMII::MO_PLT; + Callee = DAG.getTargetExternalSymbol(Sym, getPointerTy(), OpFlags); + } } // FIXME: handle tail calls differently. @@ -1391,7 +1473,7 @@ ARMTargetLowering::LowerCall(SDValue Chain, SDValue Callee, if (InFlag.getNode()) Ops.push_back(InFlag); - SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Flag); + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); if (isTailCall) return DAG.getNode(ARMISD::TC_RETURN, dl, NodeTys, &Ops[0], Ops.size()); @@ -1421,7 +1503,7 @@ bool MatchingStackOffset(SDValue Arg, unsigned Offset, ISD::ArgFlagsTy Flags, int FI = INT_MAX; if (Arg.getOpcode() == ISD::CopyFromReg) { unsigned VR = cast(Arg.getOperand(1))->getReg(); - if (!VR || TargetRegisterInfo::isPhysicalRegister(VR)) + if (!TargetRegisterInfo::isVirtualRegister(VR)) return false; MachineInstr *Def = MRI->getVRegDef(VR); if (!Def) @@ -1490,32 +1572,15 @@ ARMTargetLowering::IsEligibleForTailCallOptimization(SDValue Callee, // LR. This means if we need to reload LR, it takes an extra instructions, // which outweighs the value of the tail call; but here we don't know yet // whether LR is going to be used. Probably the right approach is to - // generate the tail call here and turn it back into CALL/RET in + // generate the tail call here and turn it back into CALL/RET in // emitEpilogue if LR is used. - if (Subtarget->isThumb1Only()) - return false; - - // For the moment, we can only do this to functions defined in this - // compilation, or to indirect calls. A Thumb B to an ARM function, - // or vice versa, is not easily fixed up in the linker unlike BL. - // (We could do this by loading the address of the callee into a register; - // that is an extra instruction over the direct call and burns a register - // as well, so is not likely to be a win.) - - // It might be safe to remove this restriction on non-Darwin. // Thumb1 PIC calls to external symbols use BX, so they can be tail calls, // but we need to make sure there are enough registers; the only valid // registers are the 4 used for parameters. We don't currently do this // case. - if (isa(Callee)) - return false; - - if (GlobalAddressSDNode *G = dyn_cast(Callee)) { - const GlobalValue *GV = G->getGlobal(); - if (GV->isDeclaration() || GV->isWeakForLinker()) - return false; - } + if (Subtarget->isThumb1Only()) + return false; // If the calling conventions do not match, then we'd better make sure the // results are returned in the same way as what the caller expects. @@ -1583,7 +1648,7 @@ ARMTargetLowering::IsEligibleForTailCallOptimization(SDValue Callee, if (!VA.isRegLoc()) return false; if (!ArgLocs[++i].isRegLoc()) - return false; + return false; if (RegVT == MVT::v2f64) { if (!ArgLocs[++i].isRegLoc()) return false; @@ -1643,7 +1708,7 @@ ARMTargetLowering::LowerReturn(SDValue Chain, default: llvm_unreachable("Unknown loc info!"); case CCValAssign::Full: break; case CCValAssign::BCvt: - Arg = DAG.getNode(ISD::BIT_CONVERT, dl, VA.getLocVT(), Arg); + Arg = DAG.getNode(ISD::BITCAST, dl, VA.getLocVT(), Arg); break; } @@ -1693,6 +1758,61 @@ ARMTargetLowering::LowerReturn(SDValue Chain, return result; } +bool ARMTargetLowering::isUsedByReturnOnly(SDNode *N) const { + if (N->getNumValues() != 1) + return false; + if (!N->hasNUsesOfValue(1, 0)) + return false; + + unsigned NumCopies = 0; + SDNode* Copies[2]; + SDNode *Use = *N->use_begin(); + if (Use->getOpcode() == ISD::CopyToReg) { + Copies[NumCopies++] = Use; + } else if (Use->getOpcode() == ARMISD::VMOVRRD) { + // f64 returned in a pair of GPRs. + for (SDNode::use_iterator UI = Use->use_begin(), UE = Use->use_end(); + UI != UE; ++UI) { + if (UI->getOpcode() != ISD::CopyToReg) + return false; + Copies[UI.getUse().getResNo()] = *UI; + ++NumCopies; + } + } else if (Use->getOpcode() == ISD::BITCAST) { + // f32 returned in a single GPR. + if (!Use->hasNUsesOfValue(1, 0)) + return false; + Use = *Use->use_begin(); + if (Use->getOpcode() != ISD::CopyToReg || !Use->hasNUsesOfValue(1, 0)) + return false; + Copies[NumCopies++] = Use; + } else { + return false; + } + + if (NumCopies != 1 && NumCopies != 2) + return false; + + bool HasRet = false; + for (unsigned i = 0; i < NumCopies; ++i) { + SDNode *Copy = Copies[i]; + for (SDNode::use_iterator UI = Copy->use_begin(), UE = Copy->use_end(); + UI != UE; ++UI) { + if (UI->getOpcode() == ISD::CopyToReg) { + SDNode *Use = *UI; + if (Use == Copies[0] || Use == Copies[1]) + continue; + return false; + } + if (UI->getOpcode() != ARMISD::RET_FLAG) + return false; + HasRet = true; + } + } + + return HasRet; +} + // ConstantPool, JumpTable, GlobalAddress, and ExternalSymbol are lowered as // their target counterpart wrapped in the ARMISD::Wrapper node. Suppose N is // one of the above mentioned nodes. It has to be wrapped because otherwise @@ -1732,7 +1852,7 @@ SDValue ARMTargetLowering::LowerBlockAddress(SDValue Op, CPAddr = DAG.getTargetConstantPool(BA, PtrVT, 4); } else { unsigned PCAdj = Subtarget->isThumb() ? 4 : 8; - ARMPCLabelIndex = AFI->createConstPoolEntryUId(); + ARMPCLabelIndex = AFI->createPICLabelUId(); ARMConstantPoolValue *CPV = new ARMConstantPoolValue(BA, ARMPCLabelIndex, ARMCP::CPBlockAddress, PCAdj); @@ -1740,7 +1860,7 @@ SDValue ARMTargetLowering::LowerBlockAddress(SDValue Op, } CPAddr = DAG.getNode(ARMISD::Wrapper, DL, PtrVT, CPAddr); SDValue Result = DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), CPAddr, - PseudoSourceValue::getConstantPool(), 0, + MachinePointerInfo::getConstantPool(), false, false, 0); if (RelocM == Reloc::Static) return Result; @@ -1757,14 +1877,14 @@ ARMTargetLowering::LowerToTLSGeneralDynamicModel(GlobalAddressSDNode *GA, unsigned char PCAdj = Subtarget->isThumb() ? 4 : 8; MachineFunction &MF = DAG.getMachineFunction(); ARMFunctionInfo *AFI = MF.getInfo(); - unsigned ARMPCLabelIndex = AFI->createConstPoolEntryUId(); + unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); ARMConstantPoolValue *CPV = new ARMConstantPoolValue(GA->getGlobal(), ARMPCLabelIndex, - ARMCP::CPValue, PCAdj, "tlsgd", true); + ARMCP::CPValue, PCAdj, ARMCP::TLSGD, true); SDValue Argument = DAG.getTargetConstantPool(CPV, PtrVT, 4); Argument = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, Argument); Argument = DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), Argument, - PseudoSourceValue::getConstantPool(), 0, + MachinePointerInfo::getConstantPool(), false, false, 0); SDValue Chain = Argument.getValue(1); @@ -1802,16 +1922,16 @@ ARMTargetLowering::LowerToTLSExecModels(GlobalAddressSDNode *GA, if (GV->isDeclaration()) { MachineFunction &MF = DAG.getMachineFunction(); ARMFunctionInfo *AFI = MF.getInfo(); - unsigned ARMPCLabelIndex = AFI->createConstPoolEntryUId(); + unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); // Initial exec model. unsigned char PCAdj = Subtarget->isThumb() ? 4 : 8; ARMConstantPoolValue *CPV = new ARMConstantPoolValue(GA->getGlobal(), ARMPCLabelIndex, - ARMCP::CPValue, PCAdj, "gottpoff", true); + ARMCP::CPValue, PCAdj, ARMCP::GOTTPOFF, true); Offset = DAG.getTargetConstantPool(CPV, PtrVT, 4); Offset = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, Offset); Offset = DAG.getLoad(PtrVT, dl, Chain, Offset, - PseudoSourceValue::getConstantPool(), 0, + MachinePointerInfo::getConstantPool(), false, false, 0); Chain = Offset.getValue(1); @@ -1819,15 +1939,15 @@ ARMTargetLowering::LowerToTLSExecModels(GlobalAddressSDNode *GA, Offset = DAG.getNode(ARMISD::PIC_ADD, dl, PtrVT, Offset, PICLabel); Offset = DAG.getLoad(PtrVT, dl, Chain, Offset, - PseudoSourceValue::getConstantPool(), 0, + MachinePointerInfo::getConstantPool(), false, false, 0); } else { // local exec model - ARMConstantPoolValue *CPV = new ARMConstantPoolValue(GV, "tpoff"); + ARMConstantPoolValue *CPV = new ARMConstantPoolValue(GV, ARMCP::TPOFF); Offset = DAG.getTargetConstantPool(CPV, PtrVT, 4); Offset = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, Offset); Offset = DAG.getLoad(PtrVT, dl, Chain, Offset, - PseudoSourceValue::getConstantPool(), 0, + MachinePointerInfo::getConstantPool(), false, false, 0); } @@ -1859,51 +1979,72 @@ SDValue ARMTargetLowering::LowerGlobalAddressELF(SDValue Op, if (RelocM == Reloc::PIC_) { bool UseGOTOFF = GV->hasLocalLinkage() || GV->hasHiddenVisibility(); ARMConstantPoolValue *CPV = - new ARMConstantPoolValue(GV, UseGOTOFF ? "GOTOFF" : "GOT"); + new ARMConstantPoolValue(GV, UseGOTOFF ? ARMCP::GOTOFF : ARMCP::GOT); SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, 4); CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); SDValue Result = DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), CPAddr, - PseudoSourceValue::getConstantPool(), 0, + MachinePointerInfo::getConstantPool(), false, false, 0); SDValue Chain = Result.getValue(1); SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(PtrVT); Result = DAG.getNode(ISD::ADD, dl, PtrVT, Result, GOT); if (!UseGOTOFF) Result = DAG.getLoad(PtrVT, dl, Chain, Result, - PseudoSourceValue::getGOT(), 0, - false, false, 0); + MachinePointerInfo::getGOT(), false, false, 0); return Result; + } + + // If we have T2 ops, we can materialize the address directly via movt/movw + // pair. This is always cheaper. + if (Subtarget->useMovt()) { + ++NumMovwMovt; + // FIXME: Once remat is capable of dealing with instructions with register + // operands, expand this into two nodes. + return DAG.getNode(ARMISD::Wrapper, dl, PtrVT, + DAG.getTargetGlobalAddress(GV, dl, PtrVT)); } else { - // If we have T2 ops, we can materialize the address directly via movt/movw - // pair. This is always cheaper. - if (Subtarget->useMovt()) { - return DAG.getNode(ARMISD::Wrapper, dl, PtrVT, - DAG.getTargetGlobalAddress(GV, dl, PtrVT)); - } else { - SDValue CPAddr = DAG.getTargetConstantPool(GV, PtrVT, 4); - CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); - return DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), CPAddr, - PseudoSourceValue::getConstantPool(), 0, - false, false, 0); - } + SDValue CPAddr = DAG.getTargetConstantPool(GV, PtrVT, 4); + CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); + return DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), CPAddr, + MachinePointerInfo::getConstantPool(), + false, false, 0); } } SDValue ARMTargetLowering::LowerGlobalAddressDarwin(SDValue Op, SelectionDAG &DAG) const { - MachineFunction &MF = DAG.getMachineFunction(); - ARMFunctionInfo *AFI = MF.getInfo(); - unsigned ARMPCLabelIndex = 0; EVT PtrVT = getPointerTy(); DebugLoc dl = Op.getDebugLoc(); const GlobalValue *GV = cast(Op)->getGlobal(); Reloc::Model RelocM = getTargetMachine().getRelocationModel(); + MachineFunction &MF = DAG.getMachineFunction(); + ARMFunctionInfo *AFI = MF.getInfo(); + + if (Subtarget->useMovt()) { + ++NumMovwMovt; + // FIXME: Once remat is capable of dealing with instructions with register + // operands, expand this into two nodes. + if (RelocM == Reloc::Static) + return DAG.getNode(ARMISD::Wrapper, dl, PtrVT, + DAG.getTargetGlobalAddress(GV, dl, PtrVT)); + + unsigned Wrapper = (RelocM == Reloc::PIC_) + ? ARMISD::WrapperPIC : ARMISD::WrapperDYN; + SDValue Result = DAG.getNode(Wrapper, dl, PtrVT, + DAG.getTargetGlobalAddress(GV, dl, PtrVT)); + if (Subtarget->GVIsIndirectSymbol(GV, RelocM)) + Result = DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), Result, + MachinePointerInfo::getGOT(), false, false, 0); + return Result; + } + + unsigned ARMPCLabelIndex = 0; SDValue CPAddr; - if (RelocM == Reloc::Static) + if (RelocM == Reloc::Static) { CPAddr = DAG.getTargetConstantPool(GV, PtrVT, 4); - else { - ARMPCLabelIndex = AFI->createConstPoolEntryUId(); + } else { + ARMPCLabelIndex = AFI->createPICLabelUId(); unsigned PCAdj = (RelocM != Reloc::PIC_) ? 0 : (Subtarget->isThumb()?4:8); ARMConstantPoolValue *CPV = new ARMConstantPoolValue(GV, ARMPCLabelIndex, ARMCP::CPValue, PCAdj); @@ -1912,7 +2053,7 @@ SDValue ARMTargetLowering::LowerGlobalAddressDarwin(SDValue Op, CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); SDValue Result = DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), CPAddr, - PseudoSourceValue::getConstantPool(), 0, + MachinePointerInfo::getConstantPool(), false, false, 0); SDValue Chain = Result.getValue(1); @@ -1922,8 +2063,7 @@ SDValue ARMTargetLowering::LowerGlobalAddressDarwin(SDValue Op, } if (Subtarget->GVIsIndirectSymbol(GV, RelocM)) - Result = DAG.getLoad(PtrVT, dl, Chain, Result, - PseudoSourceValue::getGOT(), 0, + Result = DAG.getLoad(PtrVT, dl, Chain, Result, MachinePointerInfo::getGOT(), false, false, 0); return Result; @@ -1935,7 +2075,7 @@ SDValue ARMTargetLowering::LowerGLOBAL_OFFSET_TABLE(SDValue Op, "GLOBAL OFFSET TABLE not implemented for non-ELF targets"); MachineFunction &MF = DAG.getMachineFunction(); ARMFunctionInfo *AFI = MF.getInfo(); - unsigned ARMPCLabelIndex = AFI->createConstPoolEntryUId(); + unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); EVT PtrVT = getPointerTy(); DebugLoc dl = Op.getDebugLoc(); unsigned PCAdj = Subtarget->isThumb() ? 4 : 8; @@ -1945,12 +2085,20 @@ SDValue ARMTargetLowering::LowerGLOBAL_OFFSET_TABLE(SDValue Op, SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, 4); CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); SDValue Result = DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), CPAddr, - PseudoSourceValue::getConstantPool(), 0, + MachinePointerInfo::getConstantPool(), false, false, 0); SDValue PICLabel = DAG.getConstant(ARMPCLabelIndex, MVT::i32); return DAG.getNode(ARMISD::PIC_ADD, dl, PtrVT, Result, PICLabel); } +SDValue +ARMTargetLowering::LowerEH_SJLJ_DISPATCHSETUP(SDValue Op, SelectionDAG &DAG) + const { + DebugLoc dl = Op.getDebugLoc(); + return DAG.getNode(ARMISD::EH_SJLJ_DISPATCHSETUP, dl, MVT::Other, + Op.getOperand(0), Op.getOperand(1)); +} + SDValue ARMTargetLowering::LowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const { DebugLoc dl = Op.getDebugLoc(); @@ -1980,7 +2128,7 @@ ARMTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG, case Intrinsic::eh_sjlj_lsda: { MachineFunction &MF = DAG.getMachineFunction(); ARMFunctionInfo *AFI = MF.getInfo(); - unsigned ARMPCLabelIndex = AFI->createConstPoolEntryUId(); + unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); EVT PtrVT = getPointerTy(); DebugLoc dl = Op.getDebugLoc(); Reloc::Model RelocM = getTargetMachine().getRelocationModel(); @@ -1994,7 +2142,7 @@ ARMTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG, CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); SDValue Result = DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), CPAddr, - PseudoSourceValue::getConstantPool(), 0, + MachinePointerInfo::getConstantPool(), false, false, 0); if (RelocM == Reloc::PIC_) { @@ -2009,21 +2157,55 @@ ARMTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG, static SDValue LowerMEMBARRIER(SDValue Op, SelectionDAG &DAG, const ARMSubtarget *Subtarget) { DebugLoc dl = Op.getDebugLoc(); - SDValue Op5 = Op.getOperand(5); - unsigned isDeviceBarrier = cast(Op5)->getZExtValue(); - // Some subtargets which have dmb and dsb instructions can handle barriers - // directly. Some ARMv6 cpus can support them with the help of mcr - // instruction. Thumb1 and pre-v6 ARM mode use a libcall instead and should - // never get here. - unsigned Opc = isDeviceBarrier ? ARMISD::SYNCBARRIER : ARMISD::MEMBARRIER; - if (Subtarget->hasDataBarrier()) - return DAG.getNode(Opc, dl, MVT::Other, Op.getOperand(0)); - else { - assert(Subtarget->hasV6Ops() && !Subtarget->isThumb1Only() && + if (!Subtarget->hasDataBarrier()) { + // Some ARMv6 cpus can support data barriers with an mcr instruction. + // Thumb1 and pre-v6 ARM mode use a libcall instead and should never get + // here. + assert(Subtarget->hasV6Ops() && !Subtarget->isThumb() && "Unexpected ISD::MEMBARRIER encountered. Should be libcall!"); - return DAG.getNode(Opc, dl, MVT::Other, Op.getOperand(0), + return DAG.getNode(ARMISD::MEMBARRIER_MCR, dl, MVT::Other, Op.getOperand(0), DAG.getConstant(0, MVT::i32)); } + + SDValue Op5 = Op.getOperand(5); + bool isDeviceBarrier = cast(Op5)->getZExtValue() != 0; + unsigned isLL = cast(Op.getOperand(1))->getZExtValue(); + unsigned isLS = cast(Op.getOperand(2))->getZExtValue(); + bool isOnlyStoreBarrier = (isLL == 0 && isLS == 0); + + ARM_MB::MemBOpt DMBOpt; + if (isDeviceBarrier) + DMBOpt = isOnlyStoreBarrier ? ARM_MB::ST : ARM_MB::SY; + else + DMBOpt = isOnlyStoreBarrier ? ARM_MB::ISHST : ARM_MB::ISH; + return DAG.getNode(ARMISD::MEMBARRIER, dl, MVT::Other, Op.getOperand(0), + DAG.getConstant(DMBOpt, MVT::i32)); +} + +static SDValue LowerPREFETCH(SDValue Op, SelectionDAG &DAG, + const ARMSubtarget *Subtarget) { + // ARM pre v5TE and Thumb1 does not have preload instructions. + if (!(Subtarget->isThumb2() || + (!Subtarget->isThumb1Only() && Subtarget->hasV5TEOps()))) + // Just preserve the chain. + return Op.getOperand(0); + + DebugLoc dl = Op.getDebugLoc(); + unsigned isRead = ~cast(Op.getOperand(2))->getZExtValue() & 1; + if (!isRead && + (!Subtarget->hasV7Ops() || !Subtarget->hasMPExtension())) + // ARMv7 with MP extension has PLDW. + return Op.getOperand(0); + + if (Subtarget->isThumb()) + // Invert the bits. + isRead = ~isRead & 1; + unsigned isData = Subtarget->isThumb() ? 0 : 1; + + // Currently there is no intrinsic that matches pli. + return DAG.getNode(ARMISD::PRELOAD, dl, MVT::Other, Op.getOperand(0), + Op.getOperand(1), DAG.getConstant(isRead, MVT::i32), + DAG.getConstant(isData, MVT::i32)); } static SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) { @@ -2036,8 +2218,8 @@ static SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) { EVT PtrVT = DAG.getTargetLoweringInfo().getPointerTy(); SDValue FR = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), PtrVT); const Value *SV = cast(Op.getOperand(2))->getValue(); - return DAG.getStore(Op.getOperand(0), dl, FR, Op.getOperand(1), SV, 0, - false, false, 0); + return DAG.getStore(Op.getOperand(0), dl, FR, Op.getOperand(1), + MachinePointerInfo(SV), false, false, 0); } SDValue @@ -2054,7 +2236,7 @@ ARMTargetLowering::GetF64FormalArgument(CCValAssign &VA, CCValAssign &NextVA, RC = ARM::GPRRegisterClass; // Transform the arguments stored in physical registers into virtual ones. - unsigned Reg = MF.addLiveIn(VA.getLocReg(), RC); + unsigned Reg = MF.addLiveIn(VA.getLocReg(), RC, dl); SDValue ArgValue = DAG.getCopyFromReg(Root, dl, Reg, MVT::i32); SDValue ArgValue2; @@ -2065,10 +2247,10 @@ ARMTargetLowering::GetF64FormalArgument(CCValAssign &VA, CCValAssign &NextVA, // Create load node to retrieve arguments from the stack. SDValue FIN = DAG.getFrameIndex(FI, getPointerTy()); ArgValue2 = DAG.getLoad(MVT::i32, dl, Root, FIN, - PseudoSourceValue::getFixedStack(FI), 0, + MachinePointerInfo::getFixedStack(FI), false, false, 0); } else { - Reg = MF.addLiveIn(NextVA.getLocReg(), RC); + Reg = MF.addLiveIn(NextVA.getLocReg(), RC, dl); ArgValue2 = DAG.getCopyFromReg(Root, dl, Reg, MVT::i32); } @@ -2119,7 +2301,7 @@ ARMTargetLowering::LowerFormalArguments(SDValue Chain, int FI = MFI->CreateFixedObject(8, VA.getLocMemOffset(), true); SDValue FIN = DAG.getFrameIndex(FI, getPointerTy()); ArgValue2 = DAG.getLoad(MVT::f64, dl, Chain, FIN, - PseudoSourceValue::getFixedStack(FI), 0, + MachinePointerInfo::getFixedStack(FI), false, false, 0); } else { ArgValue2 = GetF64FormalArgument(VA, ArgLocs[++i], @@ -2149,7 +2331,7 @@ ARMTargetLowering::LowerFormalArguments(SDValue Chain, llvm_unreachable("RegVT not supported by FORMAL_ARGUMENTS Lowering"); // Transform the arguments in physical registers into virtual ones. - unsigned Reg = MF.addLiveIn(VA.getLocReg(), RC); + unsigned Reg = MF.addLiveIn(VA.getLocReg(), RC, dl); ArgValue = DAG.getCopyFromReg(Chain, dl, Reg, RegVT); } @@ -2160,7 +2342,7 @@ ARMTargetLowering::LowerFormalArguments(SDValue Chain, default: llvm_unreachable("Unknown loc info!"); case CCValAssign::Full: break; case CCValAssign::BCvt: - ArgValue = DAG.getNode(ISD::BIT_CONVERT, dl, VA.getValVT(), ArgValue); + ArgValue = DAG.getNode(ISD::BITCAST, dl, VA.getValVT(), ArgValue); break; case CCValAssign::SExt: ArgValue = DAG.getNode(ISD::AssertSext, dl, RegVT, ArgValue, @@ -2188,7 +2370,7 @@ ARMTargetLowering::LowerFormalArguments(SDValue Chain, // Create load nodes to retrieve arguments from the stack. SDValue FIN = DAG.getFrameIndex(FI, getPointerTy()); InVals.push_back(DAG.getLoad(VA.getValVT(), dl, Chain, FIN, - PseudoSourceValue::getFixedStack(FI), 0, + MachinePointerInfo::getFixedStack(FI), false, false, 0)); } } @@ -2202,7 +2384,7 @@ ARMTargetLowering::LowerFormalArguments(SDValue Chain, unsigned NumGPRs = CCInfo.getFirstUnallocated (GPRArgRegs, sizeof(GPRArgRegs) / sizeof(GPRArgRegs[0])); - unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment(); + unsigned Align = MF.getTarget().getFrameLowering()->getStackAlignment(); unsigned VARegSize = (4 - NumGPRs) * 4; unsigned VARegSaveSize = (VARegSize + Align - 1) & ~(Align - 1); unsigned ArgOffset = CCInfo.getNextStackOffset(); @@ -2214,7 +2396,7 @@ ARMTargetLowering::LowerFormalArguments(SDValue Chain, AFI->setVarArgsFrameIndex( MFI->CreateFixedObject(VARegSaveSize, ArgOffset + VARegSaveSize - VARegSize, - true)); + false)); SDValue FIN = DAG.getFrameIndex(AFI->getVarArgsFrameIndex(), getPointerTy()); @@ -2226,12 +2408,12 @@ ARMTargetLowering::LowerFormalArguments(SDValue Chain, else RC = ARM::GPRRegisterClass; - unsigned VReg = MF.addLiveIn(GPRArgRegs[NumGPRs], RC); + unsigned VReg = MF.addLiveIn(GPRArgRegs[NumGPRs], RC, dl); SDValue Val = DAG.getCopyFromReg(Chain, dl, VReg, MVT::i32); SDValue Store = DAG.getStore(Val.getValue(1), dl, Val, FIN, - PseudoSourceValue::getFixedStack(AFI->getVarArgsFrameIndex()), - 0, false, false, 0); + MachinePointerInfo::getFixedStack(AFI->getVarArgsFrameIndex()), + false, false, 0); MemOps.push_back(Store); FIN = DAG.getNode(ISD::ADD, dl, getPointerTy(), FIN, DAG.getConstant(4, getPointerTy())); @@ -2320,7 +2502,7 @@ ARMTargetLowering::getARMCmp(SDValue LHS, SDValue RHS, ISD::CondCode CC, break; } ARMcc = DAG.getConstant(CondCode, MVT::i32); - return DAG.getNode(CompareType, dl, MVT::Flag, LHS, RHS); + return DAG.getNode(CompareType, dl, MVT::Glue, LHS, RHS); } /// Returns a appropriate VFP CMP (fcmp{s|d}+fmstat) for the given operands. @@ -2329,10 +2511,10 @@ ARMTargetLowering::getVFPCmp(SDValue LHS, SDValue RHS, SelectionDAG &DAG, DebugLoc dl) const { SDValue Cmp; if (!isFloatingPointZero(RHS)) - Cmp = DAG.getNode(ARMISD::CMPFP, dl, MVT::Flag, LHS, RHS); + Cmp = DAG.getNode(ARMISD::CMPFP, dl, MVT::Glue, LHS, RHS); else - Cmp = DAG.getNode(ARMISD::CMPFPw0, dl, MVT::Flag, LHS); - return DAG.getNode(ARMISD::FMSTAT, dl, MVT::Flag, Cmp); + Cmp = DAG.getNode(ARMISD::CMPFPw0, dl, MVT::Glue, LHS); + return DAG.getNode(ARMISD::FMSTAT, dl, MVT::Glue, Cmp); } SDValue ARMTargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const { @@ -2444,8 +2626,7 @@ static SDValue bitcastf32Toi32(SDValue Op, SelectionDAG &DAG) { if (LoadSDNode *Ld = dyn_cast(Op)) return DAG.getLoad(MVT::i32, Op.getDebugLoc(), - Ld->getChain(), Ld->getBasePtr(), - Ld->getSrcValue(), Ld->getSrcValueOffset(), + Ld->getChain(), Ld->getBasePtr(), Ld->getPointerInfo(), Ld->isVolatile(), Ld->isNonTemporal(), Ld->getAlignment()); @@ -2464,7 +2645,7 @@ static void expandf64Toi32(SDValue Op, SelectionDAG &DAG, SDValue Ptr = Ld->getBasePtr(); RetVal1 = DAG.getLoad(MVT::i32, Op.getDebugLoc(), Ld->getChain(), Ptr, - Ld->getSrcValue(), Ld->getSrcValueOffset(), + Ld->getPointerInfo(), Ld->isVolatile(), Ld->isNonTemporal(), Ld->getAlignment()); @@ -2474,7 +2655,7 @@ static void expandf64Toi32(SDValue Op, SelectionDAG &DAG, PtrType, Ptr, DAG.getConstant(4, PtrType)); RetVal2 = DAG.getLoad(MVT::i32, Op.getDebugLoc(), Ld->getChain(), NewPtr, - Ld->getSrcValue(), Ld->getSrcValueOffset() + 4, + Ld->getPointerInfo().getWithOffset(4), Ld->isVolatile(), Ld->isNonTemporal(), NewAlign); return; @@ -2524,7 +2705,7 @@ ARMTargetLowering::OptimizeVFPBrcond(SDValue Op, SelectionDAG &DAG) const { expandf64Toi32(RHS, DAG, RHS1, RHS2); ARMCC::CondCodes CondCode = IntCCToARMCC(CC); ARMcc = DAG.getConstant(CondCode, MVT::i32); - SDVTList VTList = DAG.getVTList(MVT::Other, MVT::Flag); + SDVTList VTList = DAG.getVTList(MVT::Other, MVT::Glue); SDValue Ops[] = { Chain, ARMcc, LHS1, LHS2, RHS1, RHS2, Dest }; return DAG.getNode(ARMISD::BCC_i64, dl, VTList, Ops, 7); } @@ -2564,7 +2745,7 @@ SDValue ARMTargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const { SDValue ARMcc = DAG.getConstant(CondCode, MVT::i32); SDValue Cmp = getVFPCmp(LHS, RHS, DAG, dl); SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); - SDVTList VTList = DAG.getVTList(MVT::Other, MVT::Flag); + SDVTList VTList = DAG.getVTList(MVT::Other, MVT::Glue); SDValue Ops[] = { Chain, Dest, ARMcc, CCR, Cmp }; SDValue Res = DAG.getNode(ARMISD::BRCOND, dl, VTList, Ops, 5); if (CondCode2 != ARMCC::AL) { @@ -2599,14 +2780,14 @@ SDValue ARMTargetLowering::LowerBR_JT(SDValue Op, SelectionDAG &DAG) const { } if (getTargetMachine().getRelocationModel() == Reloc::PIC_) { Addr = DAG.getLoad((EVT)MVT::i32, dl, Chain, Addr, - PseudoSourceValue::getJumpTable(), 0, + MachinePointerInfo::getJumpTable(), false, false, 0); Chain = Addr.getValue(1); Addr = DAG.getNode(ISD::ADD, dl, PTy, Addr, Table); return DAG.getNode(ARMISD::BR_JT, dl, MVT::Other, Chain, Addr, JTI, UId); } else { Addr = DAG.getLoad(PTy, dl, Chain, Addr, - PseudoSourceValue::getJumpTable(), 0, false, false, 0); + MachinePointerInfo::getJumpTable(), false, false, 0); Chain = Addr.getValue(1); return DAG.getNode(ARMISD::BR_JT, dl, MVT::Other, Chain, Addr, JTI, UId); } @@ -2627,7 +2808,7 @@ static SDValue LowerFP_TO_INT(SDValue Op, SelectionDAG &DAG) { break; } Op = DAG.getNode(Opc, dl, MVT::f32, Op.getOperand(0)); - return DAG.getNode(ISD::BIT_CONVERT, dl, MVT::i32, Op); + return DAG.getNode(ISD::BITCAST, dl, MVT::i32, Op); } static SDValue LowerINT_TO_FP(SDValue Op, SelectionDAG &DAG) { @@ -2646,7 +2827,7 @@ static SDValue LowerINT_TO_FP(SDValue Op, SelectionDAG &DAG) { break; } - Op = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::f32, Op.getOperand(0)); + Op = DAG.getNode(ISD::BITCAST, dl, MVT::f32, Op.getOperand(0)); return DAG.getNode(Opc, dl, VT, Op); } @@ -2657,12 +2838,46 @@ SDValue ARMTargetLowering::LowerFCOPYSIGN(SDValue Op, SelectionDAG &DAG) const { DebugLoc dl = Op.getDebugLoc(); EVT VT = Op.getValueType(); EVT SrcVT = Tmp1.getValueType(); - SDValue AbsVal = DAG.getNode(ISD::FABS, dl, VT, Tmp0); - SDValue ARMcc = DAG.getConstant(ARMCC::LT, MVT::i32); - SDValue FP0 = DAG.getConstantFP(0.0, SrcVT); - SDValue Cmp = getVFPCmp(Tmp1, FP0, DAG, dl); + bool F2IisFast = Subtarget->isCortexA9() || + Tmp0.getOpcode() == ISD::BITCAST || Tmp0.getOpcode() == ARMISD::VMOVDRR; + + // Bitcast operand 1 to i32. + if (SrcVT == MVT::f64) + Tmp1 = DAG.getNode(ARMISD::VMOVRRD, dl, DAG.getVTList(MVT::i32, MVT::i32), + &Tmp1, 1).getValue(1); + Tmp1 = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Tmp1); + + // If float to int conversion isn't going to be super expensive, then simply + // or in the signbit. + if (F2IisFast) { + SDValue Mask1 = DAG.getConstant(0x80000000, MVT::i32); + SDValue Mask2 = DAG.getConstant(0x7fffffff, MVT::i32); + Tmp1 = DAG.getNode(ISD::AND, dl, MVT::i32, Tmp1, Mask1); + if (VT == MVT::f32) { + Tmp0 = DAG.getNode(ISD::AND, dl, MVT::i32, + DAG.getNode(ISD::BITCAST, dl, MVT::i32, Tmp0), Mask2); + return DAG.getNode(ISD::BITCAST, dl, MVT::f32, + DAG.getNode(ISD::OR, dl, MVT::i32, Tmp0, Tmp1)); + } + + // f64: Or the high part with signbit and then combine two parts. + Tmp0 = DAG.getNode(ARMISD::VMOVRRD, dl, DAG.getVTList(MVT::i32, MVT::i32), + &Tmp0, 1); + SDValue Lo = Tmp0.getValue(0); + SDValue Hi = DAG.getNode(ISD::AND, dl, MVT::i32, Tmp0.getValue(1), Mask2); + Hi = DAG.getNode(ISD::OR, dl, MVT::i32, Hi, Tmp1); + return DAG.getNode(ARMISD::VMOVDRR, dl, MVT::f64, Lo, Hi); + } + + // Remove the signbit of operand 0. + Tmp0 = DAG.getNode(ISD::FABS, dl, VT, Tmp0); + + // If operand 1 signbit is one, then negate operand 0. + SDValue ARMcc; + SDValue Cmp = getARMCmp(Tmp1, DAG.getConstant(0, MVT::i32), + ISD::SETLT, ARMcc, DAG, dl); SDValue CCR = DAG.getRegister(ARM::CPSR, MVT::i32); - return DAG.getNode(ARMISD::CNEG, dl, VT, AbsVal, AbsVal, ARMcc, CCR, Cmp); + return DAG.getNode(ARMISD::CNEG, dl, VT, Tmp0, Tmp0, ARMcc, CCR, Cmp); } SDValue ARMTargetLowering::LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const{ @@ -2678,11 +2893,11 @@ SDValue ARMTargetLowering::LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const{ SDValue Offset = DAG.getConstant(4, MVT::i32); return DAG.getLoad(VT, dl, DAG.getEntryNode(), DAG.getNode(ISD::ADD, dl, VT, FrameAddr, Offset), - NULL, 0, false, false, 0); + MachinePointerInfo(), false, false, 0); } // Return LR, which contains the return address. Mark it an implicit live-in. - unsigned Reg = MF.addLiveIn(ARM::LR, getRegClassFor(MVT::i32)); + unsigned Reg = MF.addLiveIn(ARM::LR, getRegClassFor(MVT::i32), dl); return DAG.getCopyFromReg(DAG.getEntryNode(), dl, Reg, VT); } @@ -2697,17 +2912,18 @@ SDValue ARMTargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const { ? ARM::R7 : ARM::R11; SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, FrameReg, VT); while (Depth--) - FrameAddr = DAG.getLoad(VT, dl, DAG.getEntryNode(), FrameAddr, NULL, 0, + FrameAddr = DAG.getLoad(VT, dl, DAG.getEntryNode(), FrameAddr, + MachinePointerInfo(), false, false, 0); return FrameAddr; } -/// ExpandBIT_CONVERT - If the target supports VFP, this function is called to +/// ExpandBITCAST - If the target supports VFP, this function is called to /// expand a bit convert where either the source or destination type is i64 to /// use a VMOVDRR or VMOVRRD node. This should not be done when the non-i64 /// operand type is illegal (e.g., v2f32 for a target that doesn't support /// vectors), since the legalizer won't know what to do with that. -static SDValue ExpandBIT_CONVERT(SDNode *N, SelectionDAG &DAG) { +static SDValue ExpandBITCAST(SDNode *N, SelectionDAG &DAG) { const TargetLowering &TLI = DAG.getTargetLoweringInfo(); DebugLoc dl = N->getDebugLoc(); SDValue Op = N->getOperand(0); @@ -2717,7 +2933,7 @@ static SDValue ExpandBIT_CONVERT(SDNode *N, SelectionDAG &DAG) { EVT SrcVT = Op.getValueType(); EVT DstVT = N->getValueType(0); assert((SrcVT == MVT::i64 || DstVT == MVT::i64) && - "ExpandBIT_CONVERT called for non-i64 type"); + "ExpandBITCAST called for non-i64 type"); // Turn i64->f64 into VMOVDRR. if (SrcVT == MVT::i64 && TLI.isTypeLegal(DstVT)) { @@ -2725,7 +2941,7 @@ static SDValue ExpandBIT_CONVERT(SDNode *N, SelectionDAG &DAG) { DAG.getConstant(0, MVT::i32)); SDValue Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, Op, DAG.getConstant(1, MVT::i32)); - return DAG.getNode(ISD::BIT_CONVERT, dl, DstVT, + return DAG.getNode(ISD::BITCAST, dl, DstVT, DAG.getNode(ARMISD::VMOVDRR, dl, MVT::f64, Lo, Hi)); } @@ -2752,7 +2968,7 @@ static SDValue getZeroVector(EVT VT, SelectionDAG &DAG, DebugLoc dl) { SDValue EncodedVal = DAG.getTargetConstant(0, MVT::i32); EVT VmovVT = VT.is128BitVector() ? MVT::v4i32 : MVT::v2i32; SDValue Vmov = DAG.getNode(ARMISD::VMOVIMM, dl, VmovVT, EncodedVal); - return DAG.getNode(ISD::BIT_CONVERT, dl, VT, Vmov); + return DAG.getNode(ISD::BITCAST, dl, VT, Vmov); } /// LowerShiftRightParts - Lower SRA_PARTS, which returns two @@ -2825,7 +3041,7 @@ SDValue ARMTargetLowering::LowerShiftLeftParts(SDValue Op, return DAG.getMergeValues(Ops, 2, dl); } -SDValue ARMTargetLowering::LowerFLT_ROUNDS_(SDValue Op, +SDValue ARMTargetLowering::LowerFLT_ROUNDS_(SDValue Op, SelectionDAG &DAG) const { // The rounding mode is in bits 23:22 of the FPSCR. // The ARM rounding mode value to FLT_ROUNDS mapping is 0->1, 1->2, 2->3, 3->0 @@ -2835,11 +3051,11 @@ SDValue ARMTargetLowering::LowerFLT_ROUNDS_(SDValue Op, SDValue FPSCR = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::i32, DAG.getConstant(Intrinsic::arm_get_fpscr, MVT::i32)); - SDValue FltRounds = DAG.getNode(ISD::ADD, dl, MVT::i32, FPSCR, + SDValue FltRounds = DAG.getNode(ISD::ADD, dl, MVT::i32, FPSCR, DAG.getConstant(1U << 22, MVT::i32)); SDValue RMODE = DAG.getNode(ISD::SRL, dl, MVT::i32, FltRounds, DAG.getConstant(22, MVT::i32)); - return DAG.getNode(ISD::AND, dl, MVT::i32, RMODE, + return DAG.getNode(ISD::AND, dl, MVT::i32, RMODE, DAG.getConstant(3, MVT::i32)); } @@ -2860,33 +3076,40 @@ static SDValue LowerShift(SDNode *N, SelectionDAG &DAG, EVT VT = N->getValueType(0); DebugLoc dl = N->getDebugLoc(); + if (!VT.isVector()) + return SDValue(); + // Lower vector shifts on NEON to use VSHL. - if (VT.isVector()) { - assert(ST->hasNEON() && "unexpected vector shift"); - - // Left shifts translate directly to the vshiftu intrinsic. - if (N->getOpcode() == ISD::SHL) - return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, VT, - DAG.getConstant(Intrinsic::arm_neon_vshiftu, MVT::i32), - N->getOperand(0), N->getOperand(1)); - - assert((N->getOpcode() == ISD::SRA || - N->getOpcode() == ISD::SRL) && "unexpected vector shift opcode"); - - // NEON uses the same intrinsics for both left and right shifts. For - // right shifts, the shift amounts are negative, so negate the vector of - // shift amounts. - EVT ShiftVT = N->getOperand(1).getValueType(); - SDValue NegatedCount = DAG.getNode(ISD::SUB, dl, ShiftVT, - getZeroVector(ShiftVT, DAG, dl), - N->getOperand(1)); - Intrinsic::ID vshiftInt = (N->getOpcode() == ISD::SRA ? - Intrinsic::arm_neon_vshifts : - Intrinsic::arm_neon_vshiftu); + assert(ST->hasNEON() && "unexpected vector shift"); + + // Left shifts translate directly to the vshiftu intrinsic. + if (N->getOpcode() == ISD::SHL) return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, VT, - DAG.getConstant(vshiftInt, MVT::i32), - N->getOperand(0), NegatedCount); - } + DAG.getConstant(Intrinsic::arm_neon_vshiftu, MVT::i32), + N->getOperand(0), N->getOperand(1)); + + assert((N->getOpcode() == ISD::SRA || + N->getOpcode() == ISD::SRL) && "unexpected vector shift opcode"); + + // NEON uses the same intrinsics for both left and right shifts. For + // right shifts, the shift amounts are negative, so negate the vector of + // shift amounts. + EVT ShiftVT = N->getOperand(1).getValueType(); + SDValue NegatedCount = DAG.getNode(ISD::SUB, dl, ShiftVT, + getZeroVector(ShiftVT, DAG, dl), + N->getOperand(1)); + Intrinsic::ID vshiftInt = (N->getOpcode() == ISD::SRA ? + Intrinsic::arm_neon_vshifts : + Intrinsic::arm_neon_vshiftu); + return DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, VT, + DAG.getConstant(vshiftInt, MVT::i32), + N->getOperand(0), NegatedCount); +} + +static SDValue Expand64BitShift(SDNode *N, SelectionDAG &DAG, + const ARMSubtarget *ST) { + EVT VT = N->getValueType(0); + DebugLoc dl = N->getDebugLoc(); // We can get here for a node like i32 = ISD::SHL i32, i64 if (VT != MVT::i64) @@ -2912,7 +3135,7 @@ static SDValue LowerShift(SDNode *N, SelectionDAG &DAG, // First, build a SRA_FLAG/SRL_FLAG op, which shifts the top part by one and // captures the result into a carry flag. unsigned Opc = N->getOpcode() == ISD::SRL ? ARMISD::SRL_FLAG:ARMISD::SRA_FLAG; - Hi = DAG.getNode(Opc, dl, DAG.getVTList(MVT::i32, MVT::Flag), &Hi, 1); + Hi = DAG.getNode(Opc, dl, DAG.getVTList(MVT::i32, MVT::Glue), &Hi, 1); // The low part is an ARMISD::RRX operand, which shifts the carry in. Lo = DAG.getNode(ARMISD::RRX, dl, MVT::i32, Lo, Hi.getValue(1)); @@ -2998,13 +3221,13 @@ static SDValue LowerVSETCC(SDValue Op, SelectionDAG &DAG) { AndOp = Op1; // Ignore bitconvert. - if (AndOp.getNode() && AndOp.getOpcode() == ISD::BIT_CONVERT) + if (AndOp.getNode() && AndOp.getOpcode() == ISD::BITCAST) AndOp = AndOp.getOperand(0); if (AndOp.getNode() && AndOp.getOpcode() == ISD::AND) { Opc = ARMISD::VTST; - Op0 = DAG.getNode(ISD::BIT_CONVERT, dl, VT, AndOp.getOperand(0)); - Op1 = DAG.getNode(ISD::BIT_CONVERT, dl, VT, AndOp.getOperand(1)); + Op0 = DAG.getNode(ISD::BITCAST, dl, VT, AndOp.getOperand(0)); + Op1 = DAG.getNode(ISD::BITCAST, dl, VT, AndOp.getOperand(1)); Invert = !Invert; } } @@ -3013,7 +3236,38 @@ static SDValue LowerVSETCC(SDValue Op, SelectionDAG &DAG) { if (Swap) std::swap(Op0, Op1); - SDValue Result = DAG.getNode(Opc, dl, VT, Op0, Op1); + // If one of the operands is a constant vector zero, attempt to fold the + // comparison to a specialized compare-against-zero form. + SDValue SingleOp; + if (ISD::isBuildVectorAllZeros(Op1.getNode())) + SingleOp = Op0; + else if (ISD::isBuildVectorAllZeros(Op0.getNode())) { + if (Opc == ARMISD::VCGE) + Opc = ARMISD::VCLEZ; + else if (Opc == ARMISD::VCGT) + Opc = ARMISD::VCLTZ; + SingleOp = Op1; + } + + SDValue Result; + if (SingleOp.getNode()) { + switch (Opc) { + case ARMISD::VCEQ: + Result = DAG.getNode(ARMISD::VCEQZ, dl, VT, SingleOp); break; + case ARMISD::VCGE: + Result = DAG.getNode(ARMISD::VCGEZ, dl, VT, SingleOp); break; + case ARMISD::VCLEZ: + Result = DAG.getNode(ARMISD::VCLEZ, dl, VT, SingleOp); break; + case ARMISD::VCGT: + Result = DAG.getNode(ARMISD::VCGTZ, dl, VT, SingleOp); break; + case ARMISD::VCLTZ: + Result = DAG.getNode(ARMISD::VCLTZ, dl, VT, SingleOp); break; + default: + Result = DAG.getNode(Opc, dl, VT, Op0, Op1); + } + } else { + Result = DAG.getNode(Opc, dl, VT, Op0, Op1); + } if (Invert) Result = DAG.getNOT(dl, Result, VT); @@ -3026,7 +3280,7 @@ static SDValue LowerVSETCC(SDValue Op, SelectionDAG &DAG) { /// operand (e.g., VMOV). If so, return the encoded value. static SDValue isNEONModifiedImm(uint64_t SplatBits, uint64_t SplatUndef, unsigned SplatBitSize, SelectionDAG &DAG, - EVT &VT, bool is128Bits, bool isVMOV) { + EVT &VT, bool is128Bits, NEONModImmType type) { unsigned OpCmode, Imm; // SplatBitSize is set to the smallest size that splats the vector, so a @@ -3039,7 +3293,7 @@ static SDValue isNEONModifiedImm(uint64_t SplatBits, uint64_t SplatUndef, switch (SplatBitSize) { case 8: - if (!isVMOV) + if (type != VMOVModImm) return SDValue(); // Any 1-byte value is OK. Op=0, Cmode=1110. assert((SplatBits & ~0xff) == 0 && "one byte splat value is too big"); @@ -3096,6 +3350,9 @@ static SDValue isNEONModifiedImm(uint64_t SplatBits, uint64_t SplatUndef, break; } + // cmode == 0b1100 and cmode == 0b1101 are not supported for VORR or VBIC + if (type == OtherModImm) return SDValue(); + if ((SplatBits & ~0xffff) == 0 && ((SplatBits | SplatUndef) & 0xff) == 0xff) { // Value = 0x0000nnff: Op=x, Cmode=1100. @@ -3122,7 +3379,7 @@ static SDValue isNEONModifiedImm(uint64_t SplatBits, uint64_t SplatUndef, return SDValue(); case 64: { - if (!isVMOV) + if (type != VMOVModImm) return SDValue(); // NEON has a 64-bit VMOV splat where each byte is either 0 or 0xff. uint64_t BitMask = 0xff; @@ -3376,8 +3633,8 @@ static SDValue IsSingleInstrConstant(SDValue N, SelectionDAG &DAG, // If this is a case we can't handle, return null and let the default // expansion code take care of it. -static SDValue LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG, - const ARMSubtarget *ST) { +SDValue ARMTargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG, + const ARMSubtarget *ST) const { BuildVectorSDNode *BVN = cast(Op.getNode()); DebugLoc dl = Op.getDebugLoc(); EVT VT = Op.getValueType(); @@ -3391,10 +3648,11 @@ static SDValue LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG, EVT VmovVT; SDValue Val = isNEONModifiedImm(SplatBits.getZExtValue(), SplatUndef.getZExtValue(), SplatBitSize, - DAG, VmovVT, VT.is128BitVector(), true); + DAG, VmovVT, VT.is128BitVector(), + VMOVModImm); if (Val.getNode()) { SDValue Vmov = DAG.getNode(ARMISD::VMOVIMM, dl, VmovVT, Val); - return DAG.getNode(ISD::BIT_CONVERT, dl, VT, Vmov); + return DAG.getNode(ISD::BITCAST, dl, VT, Vmov); } // Try an immediate VMVN. @@ -3402,10 +3660,11 @@ static SDValue LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG, ((1LL << SplatBitSize) - 1)); Val = isNEONModifiedImm(NegatedImm, SplatUndef.getZExtValue(), SplatBitSize, - DAG, VmovVT, VT.is128BitVector(), false); + DAG, VmovVT, VT.is128BitVector(), + VMVNModImm); if (Val.getNode()) { SDValue Vmov = DAG.getNode(ARMISD::VMVNIMM, dl, VmovVT, Val); - return DAG.getNode(ISD::BIT_CONVERT, dl, VT, Vmov); + return DAG.getNode(ISD::BITCAST, dl, VT, Vmov); } } } @@ -3439,26 +3698,25 @@ static SDValue LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG, unsigned EltSize = VT.getVectorElementType().getSizeInBits(); - if (EnableARMVDUPsplat) { - // Use VDUP for non-constant splats. For f32 constant splats, reduce to - // i32 and try again. - if (usesOnlyOneValue && EltSize <= 32) { - if (!isConstant) - return DAG.getNode(ARMISD::VDUP, dl, VT, Value); - if (VT.getVectorElementType().isFloatingPoint()) { - SmallVector Ops; - for (unsigned i = 0; i < NumElts; ++i) - Ops.push_back(DAG.getNode(ISD::BIT_CONVERT, dl, MVT::i32, - Op.getOperand(i))); - SDValue Val = DAG.getNode(ISD::BUILD_VECTOR, dl, MVT::v4i32, &Ops[0], - NumElts); - return DAG.getNode(ISD::BIT_CONVERT, dl, VT, - LowerBUILD_VECTOR(Val, DAG, ST)); - } - SDValue Val = IsSingleInstrConstant(Value, DAG, ST, dl); + // Use VDUP for non-constant splats. For f32 constant splats, reduce to + // i32 and try again. + if (usesOnlyOneValue && EltSize <= 32) { + if (!isConstant) + return DAG.getNode(ARMISD::VDUP, dl, VT, Value); + if (VT.getVectorElementType().isFloatingPoint()) { + SmallVector Ops; + for (unsigned i = 0; i < NumElts; ++i) + Ops.push_back(DAG.getNode(ISD::BITCAST, dl, MVT::i32, + Op.getOperand(i))); + EVT VecVT = EVT::getVectorVT(*DAG.getContext(), MVT::i32, NumElts); + SDValue Val = DAG.getNode(ISD::BUILD_VECTOR, dl, VecVT, &Ops[0], NumElts); + Val = LowerBUILD_VECTOR(Val, DAG, ST); if (Val.getNode()) - return DAG.getNode(ARMISD::VDUP, dl, VT, Val); + return DAG.getNode(ISD::BITCAST, dl, VT, Val); } + SDValue Val = IsSingleInstrConstant(Value, DAG, ST, dl); + if (Val.getNode()) + return DAG.getNode(ARMISD::VDUP, dl, VT, Val); } // If all elements are constants and the case above didn't get hit, fall back @@ -3467,10 +3725,11 @@ static SDValue LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG, if (isConstant) return SDValue(); - if (!EnableARMVDUPsplat) { - // Use VDUP for non-constant splats. - if (usesOnlyOneValue && EltSize <= 32) - return DAG.getNode(ARMISD::VDUP, dl, VT, Value); + // Empirical tests suggest this is rarely worth it for vectors of length <= 2. + if (NumElts >= 4) { + SDValue shuffle = ReconstructShuffle(Op, DAG); + if (shuffle != SDValue()) + return shuffle; } // Vectors with 32- or 64-bit elements can be built by directly assigning @@ -3483,14 +3742,144 @@ static SDValue LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG, EVT VecVT = EVT::getVectorVT(*DAG.getContext(), EltVT, NumElts); SmallVector Ops; for (unsigned i = 0; i < NumElts; ++i) - Ops.push_back(DAG.getNode(ISD::BIT_CONVERT, dl, EltVT, Op.getOperand(i))); + Ops.push_back(DAG.getNode(ISD::BITCAST, dl, EltVT, Op.getOperand(i))); SDValue Val = DAG.getNode(ARMISD::BUILD_VECTOR, dl, VecVT, &Ops[0],NumElts); - return DAG.getNode(ISD::BIT_CONVERT, dl, VT, Val); + return DAG.getNode(ISD::BITCAST, dl, VT, Val); } return SDValue(); } +// Gather data to see if the operation can be modelled as a +// shuffle in combination with VEXTs. +SDValue ARMTargetLowering::ReconstructShuffle(SDValue Op, + SelectionDAG &DAG) const { + DebugLoc dl = Op.getDebugLoc(); + EVT VT = Op.getValueType(); + unsigned NumElts = VT.getVectorNumElements(); + + SmallVector SourceVecs; + SmallVector MinElts; + SmallVector MaxElts; + + for (unsigned i = 0; i < NumElts; ++i) { + SDValue V = Op.getOperand(i); + if (V.getOpcode() == ISD::UNDEF) + continue; + else if (V.getOpcode() != ISD::EXTRACT_VECTOR_ELT) { + // A shuffle can only come from building a vector from various + // elements of other vectors. + return SDValue(); + } + + // Record this extraction against the appropriate vector if possible... + SDValue SourceVec = V.getOperand(0); + unsigned EltNo = cast(V.getOperand(1))->getZExtValue(); + bool FoundSource = false; + for (unsigned j = 0; j < SourceVecs.size(); ++j) { + if (SourceVecs[j] == SourceVec) { + if (MinElts[j] > EltNo) + MinElts[j] = EltNo; + if (MaxElts[j] < EltNo) + MaxElts[j] = EltNo; + FoundSource = true; + break; + } + } + + // Or record a new source if not... + if (!FoundSource) { + SourceVecs.push_back(SourceVec); + MinElts.push_back(EltNo); + MaxElts.push_back(EltNo); + } + } + + // Currently only do something sane when at most two source vectors + // involved. + if (SourceVecs.size() > 2) + return SDValue(); + + SDValue ShuffleSrcs[2] = {DAG.getUNDEF(VT), DAG.getUNDEF(VT) }; + int VEXTOffsets[2] = {0, 0}; + + // This loop extracts the usage patterns of the source vectors + // and prepares appropriate SDValues for a shuffle if possible. + for (unsigned i = 0; i < SourceVecs.size(); ++i) { + if (SourceVecs[i].getValueType() == VT) { + // No VEXT necessary + ShuffleSrcs[i] = SourceVecs[i]; + VEXTOffsets[i] = 0; + continue; + } else if (SourceVecs[i].getValueType().getVectorNumElements() < NumElts) { + // It probably isn't worth padding out a smaller vector just to + // break it down again in a shuffle. + return SDValue(); + } + + // Since only 64-bit and 128-bit vectors are legal on ARM and + // we've eliminated the other cases... + assert(SourceVecs[i].getValueType().getVectorNumElements() == 2*NumElts && + "unexpected vector sizes in ReconstructShuffle"); + + if (MaxElts[i] - MinElts[i] >= NumElts) { + // Span too large for a VEXT to cope + return SDValue(); + } + + if (MinElts[i] >= NumElts) { + // The extraction can just take the second half + VEXTOffsets[i] = NumElts; + ShuffleSrcs[i] = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VT, + SourceVecs[i], + DAG.getIntPtrConstant(NumElts)); + } else if (MaxElts[i] < NumElts) { + // The extraction can just take the first half + VEXTOffsets[i] = 0; + ShuffleSrcs[i] = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VT, + SourceVecs[i], + DAG.getIntPtrConstant(0)); + } else { + // An actual VEXT is needed + VEXTOffsets[i] = MinElts[i]; + SDValue VEXTSrc1 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VT, + SourceVecs[i], + DAG.getIntPtrConstant(0)); + SDValue VEXTSrc2 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VT, + SourceVecs[i], + DAG.getIntPtrConstant(NumElts)); + ShuffleSrcs[i] = DAG.getNode(ARMISD::VEXT, dl, VT, VEXTSrc1, VEXTSrc2, + DAG.getConstant(VEXTOffsets[i], MVT::i32)); + } + } + + SmallVector Mask; + + for (unsigned i = 0; i < NumElts; ++i) { + SDValue Entry = Op.getOperand(i); + if (Entry.getOpcode() == ISD::UNDEF) { + Mask.push_back(-1); + continue; + } + + SDValue ExtractVec = Entry.getOperand(0); + int ExtractElt = cast(Op.getOperand(i) + .getOperand(1))->getSExtValue(); + if (ExtractVec == SourceVecs[0]) { + Mask.push_back(ExtractElt - VEXTOffsets[0]); + } else { + Mask.push_back(ExtractElt + NumElts - VEXTOffsets[1]); + } + } + + // Final check before we try to produce nonsense... + if (isShuffleMaskLegal(Mask, VT)) + return DAG.getVectorShuffle(VT, dl, ShuffleSrcs[0], ShuffleSrcs[1], + &Mask[0]); + + return SDValue(); +} + /// isShuffleMaskLegal - Targets can use this to indicate that they only /// support *some* VECTOR_SHUFFLE operations, those with specific masks. /// By default, if a target supports the VECTOR_SHUFFLE node, all mask values @@ -3706,8 +4095,8 @@ static SDValue LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) { // registers are defined to use, and since i64 is not legal. EVT EltVT = EVT::getFloatingPointVT(EltSize); EVT VecVT = EVT::getVectorVT(*DAG.getContext(), EltVT, NumElts); - V1 = DAG.getNode(ISD::BIT_CONVERT, dl, VecVT, V1); - V2 = DAG.getNode(ISD::BIT_CONVERT, dl, VecVT, V2); + V1 = DAG.getNode(ISD::BITCAST, dl, VecVT, V1); + V2 = DAG.getNode(ISD::BITCAST, dl, VecVT, V2); SmallVector Ops; for (unsigned i = 0; i < NumElts; ++i) { if (ShuffleMask[i] < 0) @@ -3719,21 +4108,26 @@ static SDValue LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG) { MVT::i32))); } SDValue Val = DAG.getNode(ARMISD::BUILD_VECTOR, dl, VecVT, &Ops[0],NumElts); - return DAG.getNode(ISD::BIT_CONVERT, dl, VT, Val); + return DAG.getNode(ISD::BITCAST, dl, VT, Val); } return SDValue(); } static SDValue LowerEXTRACT_VECTOR_ELT(SDValue Op, SelectionDAG &DAG) { - EVT VT = Op.getValueType(); - DebugLoc dl = Op.getDebugLoc(); - SDValue Vec = Op.getOperand(0); + // EXTRACT_VECTOR_ELT is legal only for immediate indexes. SDValue Lane = Op.getOperand(1); - assert(VT == MVT::i32 && - Vec.getValueType().getVectorElementType().getSizeInBits() < 32 && - "unexpected type for custom-lowering vector extract"); - return DAG.getNode(ARMISD::VGETLANEu, dl, MVT::i32, Vec, Lane); + if (!isa(Lane)) + return SDValue(); + + SDValue Vec = Op.getOperand(0); + if (Op.getValueType() == MVT::i32 && + Vec.getValueType().getVectorElementType().getSizeInBits() < 32) { + DebugLoc dl = Op.getDebugLoc(); + return DAG.getNode(ARMISD::VGETLANEu, dl, MVT::i32, Vec, Lane); + } + + return Op; } static SDValue LowerCONCAT_VECTORS(SDValue Op, SelectionDAG &DAG) { @@ -3747,25 +4141,123 @@ static SDValue LowerCONCAT_VECTORS(SDValue Op, SelectionDAG &DAG) { SDValue Op1 = Op.getOperand(1); if (Op0.getOpcode() != ISD::UNDEF) Val = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, MVT::v2f64, Val, - DAG.getNode(ISD::BIT_CONVERT, dl, MVT::f64, Op0), + DAG.getNode(ISD::BITCAST, dl, MVT::f64, Op0), DAG.getIntPtrConstant(0)); if (Op1.getOpcode() != ISD::UNDEF) Val = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, MVT::v2f64, Val, - DAG.getNode(ISD::BIT_CONVERT, dl, MVT::f64, Op1), + DAG.getNode(ISD::BITCAST, dl, MVT::f64, Op1), DAG.getIntPtrConstant(1)); - return DAG.getNode(ISD::BIT_CONVERT, dl, Op.getValueType(), Val); + return DAG.getNode(ISD::BITCAST, dl, Op.getValueType(), Val); +} + +/// isExtendedBUILD_VECTOR - Check if N is a constant BUILD_VECTOR where each +/// element has been zero/sign-extended, depending on the isSigned parameter, +/// from an integer type half its size. +static bool isExtendedBUILD_VECTOR(SDNode *N, SelectionDAG &DAG, + bool isSigned) { + // A v2i64 BUILD_VECTOR will have been legalized to a BITCAST from v4i32. + EVT VT = N->getValueType(0); + if (VT == MVT::v2i64 && N->getOpcode() == ISD::BITCAST) { + SDNode *BVN = N->getOperand(0).getNode(); + if (BVN->getValueType(0) != MVT::v4i32 || + BVN->getOpcode() != ISD::BUILD_VECTOR) + return false; + unsigned LoElt = DAG.getTargetLoweringInfo().isBigEndian() ? 1 : 0; + unsigned HiElt = 1 - LoElt; + ConstantSDNode *Lo0 = dyn_cast(BVN->getOperand(LoElt)); + ConstantSDNode *Hi0 = dyn_cast(BVN->getOperand(HiElt)); + ConstantSDNode *Lo1 = dyn_cast(BVN->getOperand(LoElt+2)); + ConstantSDNode *Hi1 = dyn_cast(BVN->getOperand(HiElt+2)); + if (!Lo0 || !Hi0 || !Lo1 || !Hi1) + return false; + if (isSigned) { + if (Hi0->getSExtValue() == Lo0->getSExtValue() >> 32 && + Hi1->getSExtValue() == Lo1->getSExtValue() >> 32) + return true; + } else { + if (Hi0->isNullValue() && Hi1->isNullValue()) + return true; + } + return false; + } + + if (N->getOpcode() != ISD::BUILD_VECTOR) + return false; + + for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) { + SDNode *Elt = N->getOperand(i).getNode(); + if (ConstantSDNode *C = dyn_cast(Elt)) { + unsigned EltSize = VT.getVectorElementType().getSizeInBits(); + unsigned HalfSize = EltSize / 2; + if (isSigned) { + int64_t SExtVal = C->getSExtValue(); + if ((SExtVal >> HalfSize) != (SExtVal >> EltSize)) + return false; + } else { + if ((C->getZExtValue() >> HalfSize) != 0) + return false; + } + continue; + } + return false; + } + + return true; +} + +/// isSignExtended - Check if a node is a vector value that is sign-extended +/// or a constant BUILD_VECTOR with sign-extended elements. +static bool isSignExtended(SDNode *N, SelectionDAG &DAG) { + if (N->getOpcode() == ISD::SIGN_EXTEND || ISD::isSEXTLoad(N)) + return true; + if (isExtendedBUILD_VECTOR(N, DAG, true)) + return true; + return false; +} + +/// isZeroExtended - Check if a node is a vector value that is zero-extended +/// or a constant BUILD_VECTOR with zero-extended elements. +static bool isZeroExtended(SDNode *N, SelectionDAG &DAG) { + if (N->getOpcode() == ISD::ZERO_EXTEND || ISD::isZEXTLoad(N)) + return true; + if (isExtendedBUILD_VECTOR(N, DAG, false)) + return true; + return false; } -/// SkipExtension - For a node that is either a SIGN_EXTEND, ZERO_EXTEND, or -/// an extending load, return the unextended value. +/// SkipExtension - For a node that is a SIGN_EXTEND, ZERO_EXTEND, extending +/// load, or BUILD_VECTOR with extended elements, return the unextended value. static SDValue SkipExtension(SDNode *N, SelectionDAG &DAG) { if (N->getOpcode() == ISD::SIGN_EXTEND || N->getOpcode() == ISD::ZERO_EXTEND) return N->getOperand(0); - LoadSDNode *LD = cast(N); - return DAG.getLoad(LD->getMemoryVT(), N->getDebugLoc(), LD->getChain(), - LD->getBasePtr(), LD->getSrcValue(), - LD->getSrcValueOffset(), LD->isVolatile(), - LD->isNonTemporal(), LD->getAlignment()); + if (LoadSDNode *LD = dyn_cast(N)) + return DAG.getLoad(LD->getMemoryVT(), N->getDebugLoc(), LD->getChain(), + LD->getBasePtr(), LD->getPointerInfo(), LD->isVolatile(), + LD->isNonTemporal(), LD->getAlignment()); + // Otherwise, the value must be a BUILD_VECTOR. For v2i64, it will + // have been legalized as a BITCAST from v4i32. + if (N->getOpcode() == ISD::BITCAST) { + SDNode *BVN = N->getOperand(0).getNode(); + assert(BVN->getOpcode() == ISD::BUILD_VECTOR && + BVN->getValueType(0) == MVT::v4i32 && "expected v4i32 BUILD_VECTOR"); + unsigned LowElt = DAG.getTargetLoweringInfo().isBigEndian() ? 1 : 0; + return DAG.getNode(ISD::BUILD_VECTOR, N->getDebugLoc(), MVT::v2i32, + BVN->getOperand(LowElt), BVN->getOperand(LowElt+2)); + } + // Construct a new BUILD_VECTOR with elements truncated to half the size. + assert(N->getOpcode() == ISD::BUILD_VECTOR && "expected BUILD_VECTOR"); + EVT VT = N->getValueType(0); + unsigned EltSize = VT.getVectorElementType().getSizeInBits() / 2; + unsigned NumElts = VT.getVectorNumElements(); + MVT TruncVT = MVT::getIntegerVT(EltSize); + SmallVector Ops; + for (unsigned i = 0; i != NumElts; ++i) { + ConstantSDNode *C = cast(N->getOperand(i)); + const APInt &CInt = C->getAPIntValue(); + Ops.push_back(DAG.getConstant(CInt.trunc(EltSize), TruncVT)); + } + return DAG.getNode(ISD::BUILD_VECTOR, N->getDebugLoc(), + MVT::getVectorVT(TruncVT, NumElts), Ops.data(), NumElts); } static SDValue LowerMUL(SDValue Op, SelectionDAG &DAG) { @@ -3776,19 +4268,16 @@ static SDValue LowerMUL(SDValue Op, SelectionDAG &DAG) { SDNode *N0 = Op.getOperand(0).getNode(); SDNode *N1 = Op.getOperand(1).getNode(); unsigned NewOpc = 0; - if ((N0->getOpcode() == ISD::SIGN_EXTEND || ISD::isSEXTLoad(N0)) && - (N1->getOpcode() == ISD::SIGN_EXTEND || ISD::isSEXTLoad(N1))) { + if (isSignExtended(N0, DAG) && isSignExtended(N1, DAG)) NewOpc = ARMISD::VMULLs; - } else if ((N0->getOpcode() == ISD::ZERO_EXTEND || ISD::isZEXTLoad(N0)) && - (N1->getOpcode() == ISD::ZERO_EXTEND || ISD::isZEXTLoad(N1))) { + else if (isZeroExtended(N0, DAG) && isZeroExtended(N1, DAG)) NewOpc = ARMISD::VMULLu; - } else if (VT.getSimpleVT().SimpleTy == MVT::v2i64) { + else if (VT == MVT::v2i64) // Fall through to expand this. It is not legal. return SDValue(); - } else { + else // Other vector multiplications are legal. return Op; - } // Legalize to a VMULL instruction. DebugLoc DL = Op.getDebugLoc(); @@ -3801,6 +4290,181 @@ static SDValue LowerMUL(SDValue Op, SelectionDAG &DAG) { return DAG.getNode(NewOpc, DL, VT, Op0, Op1); } +static SDValue +LowerSDIV_v4i8(SDValue X, SDValue Y, DebugLoc dl, SelectionDAG &DAG) { + // Convert to float + // float4 xf = vcvt_f32_s32(vmovl_s16(a.lo)); + // float4 yf = vcvt_f32_s32(vmovl_s16(b.lo)); + X = DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::v4i32, X); + Y = DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::v4i32, Y); + X = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::v4f32, X); + Y = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::v4f32, Y); + // Get reciprocal estimate. + // float4 recip = vrecpeq_f32(yf); + Y = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::v4f32, + DAG.getConstant(Intrinsic::arm_neon_vrecpe, MVT::i32), Y); + // Because char has a smaller range than uchar, we can actually get away + // without any newton steps. This requires that we use a weird bias + // of 0xb000, however (again, this has been exhaustively tested). + // float4 result = as_float4(as_int4(xf*recip) + 0xb000); + X = DAG.getNode(ISD::FMUL, dl, MVT::v4f32, X, Y); + X = DAG.getNode(ISD::BITCAST, dl, MVT::v4i32, X); + Y = DAG.getConstant(0xb000, MVT::i32); + Y = DAG.getNode(ISD::BUILD_VECTOR, dl, MVT::v4i32, Y, Y, Y, Y); + X = DAG.getNode(ISD::ADD, dl, MVT::v4i32, X, Y); + X = DAG.getNode(ISD::BITCAST, dl, MVT::v4f32, X); + // Convert back to short. + X = DAG.getNode(ISD::FP_TO_SINT, dl, MVT::v4i32, X); + X = DAG.getNode(ISD::TRUNCATE, dl, MVT::v4i16, X); + return X; +} + +static SDValue +LowerSDIV_v4i16(SDValue N0, SDValue N1, DebugLoc dl, SelectionDAG &DAG) { + SDValue N2; + // Convert to float. + // float4 yf = vcvt_f32_s32(vmovl_s16(y)); + // float4 xf = vcvt_f32_s32(vmovl_s16(x)); + N0 = DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::v4i32, N0); + N1 = DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::v4i32, N1); + N0 = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::v4f32, N0); + N1 = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::v4f32, N1); + + // Use reciprocal estimate and one refinement step. + // float4 recip = vrecpeq_f32(yf); + // recip *= vrecpsq_f32(yf, recip); + N2 = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::v4f32, + DAG.getConstant(Intrinsic::arm_neon_vrecpe, MVT::i32), N1); + N1 = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::v4f32, + DAG.getConstant(Intrinsic::arm_neon_vrecps, MVT::i32), + N1, N2); + N2 = DAG.getNode(ISD::FMUL, dl, MVT::v4f32, N1, N2); + // Because short has a smaller range than ushort, we can actually get away + // with only a single newton step. This requires that we use a weird bias + // of 89, however (again, this has been exhaustively tested). + // float4 result = as_float4(as_int4(xf*recip) + 89); + N0 = DAG.getNode(ISD::FMUL, dl, MVT::v4f32, N0, N2); + N0 = DAG.getNode(ISD::BITCAST, dl, MVT::v4i32, N0); + N1 = DAG.getConstant(89, MVT::i32); + N1 = DAG.getNode(ISD::BUILD_VECTOR, dl, MVT::v4i32, N1, N1, N1, N1); + N0 = DAG.getNode(ISD::ADD, dl, MVT::v4i32, N0, N1); + N0 = DAG.getNode(ISD::BITCAST, dl, MVT::v4f32, N0); + // Convert back to integer and return. + // return vmovn_s32(vcvt_s32_f32(result)); + N0 = DAG.getNode(ISD::FP_TO_SINT, dl, MVT::v4i32, N0); + N0 = DAG.getNode(ISD::TRUNCATE, dl, MVT::v4i16, N0); + return N0; +} + +static SDValue LowerSDIV(SDValue Op, SelectionDAG &DAG) { + EVT VT = Op.getValueType(); + assert((VT == MVT::v4i16 || VT == MVT::v8i8) && + "unexpected type for custom-lowering ISD::SDIV"); + + DebugLoc dl = Op.getDebugLoc(); + SDValue N0 = Op.getOperand(0); + SDValue N1 = Op.getOperand(1); + SDValue N2, N3; + + if (VT == MVT::v8i8) { + N0 = DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::v8i16, N0); + N1 = DAG.getNode(ISD::SIGN_EXTEND, dl, MVT::v8i16, N1); + + N2 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N0, + DAG.getIntPtrConstant(4)); + N3 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N1, + DAG.getIntPtrConstant(4)); + N0 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N0, + DAG.getIntPtrConstant(0)); + N1 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N1, + DAG.getIntPtrConstant(0)); + + N0 = LowerSDIV_v4i8(N0, N1, dl, DAG); // v4i16 + N2 = LowerSDIV_v4i8(N2, N3, dl, DAG); // v4i16 + + N0 = DAG.getNode(ISD::CONCAT_VECTORS, dl, MVT::v8i16, N0, N2); + N0 = LowerCONCAT_VECTORS(N0, DAG); + + N0 = DAG.getNode(ISD::TRUNCATE, dl, MVT::v8i8, N0); + return N0; + } + return LowerSDIV_v4i16(N0, N1, dl, DAG); +} + +static SDValue LowerUDIV(SDValue Op, SelectionDAG &DAG) { + EVT VT = Op.getValueType(); + assert((VT == MVT::v4i16 || VT == MVT::v8i8) && + "unexpected type for custom-lowering ISD::UDIV"); + + DebugLoc dl = Op.getDebugLoc(); + SDValue N0 = Op.getOperand(0); + SDValue N1 = Op.getOperand(1); + SDValue N2, N3; + + if (VT == MVT::v8i8) { + N0 = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::v8i16, N0); + N1 = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::v8i16, N1); + + N2 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N0, + DAG.getIntPtrConstant(4)); + N3 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N1, + DAG.getIntPtrConstant(4)); + N0 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N0, + DAG.getIntPtrConstant(0)); + N1 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, MVT::v4i16, N1, + DAG.getIntPtrConstant(0)); + + N0 = LowerSDIV_v4i16(N0, N1, dl, DAG); // v4i16 + N2 = LowerSDIV_v4i16(N2, N3, dl, DAG); // v4i16 + + N0 = DAG.getNode(ISD::CONCAT_VECTORS, dl, MVT::v8i16, N0, N2); + N0 = LowerCONCAT_VECTORS(N0, DAG); + + N0 = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::v8i8, + DAG.getConstant(Intrinsic::arm_neon_vqmovnsu, MVT::i32), + N0); + return N0; + } + + // v4i16 sdiv ... Convert to float. + // float4 yf = vcvt_f32_s32(vmovl_u16(y)); + // float4 xf = vcvt_f32_s32(vmovl_u16(x)); + N0 = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::v4i32, N0); + N1 = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::v4i32, N1); + N0 = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::v4f32, N0); + N1 = DAG.getNode(ISD::SINT_TO_FP, dl, MVT::v4f32, N1); + + // Use reciprocal estimate and two refinement steps. + // float4 recip = vrecpeq_f32(yf); + // recip *= vrecpsq_f32(yf, recip); + // recip *= vrecpsq_f32(yf, recip); + N2 = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::v4f32, + DAG.getConstant(Intrinsic::arm_neon_vrecpe, MVT::i32), N1); + N1 = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::v4f32, + DAG.getConstant(Intrinsic::arm_neon_vrecps, MVT::i32), + N1, N2); + N2 = DAG.getNode(ISD::FMUL, dl, MVT::v4f32, N1, N2); + N1 = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, MVT::v4f32, + DAG.getConstant(Intrinsic::arm_neon_vrecps, MVT::i32), + N1, N2); + N2 = DAG.getNode(ISD::FMUL, dl, MVT::v4f32, N1, N2); + // Simply multiplying by the reciprocal estimate can leave us a few ulps + // too low, so we add 2 ulps (exhaustive testing shows that this is enough, + // and that it will never cause us to return an answer too large). + // float4 result = as_float4(as_int4(xf*recip) + 89); + N0 = DAG.getNode(ISD::FMUL, dl, MVT::v4f32, N0, N2); + N0 = DAG.getNode(ISD::BITCAST, dl, MVT::v4i32, N0); + N1 = DAG.getConstant(2, MVT::i32); + N1 = DAG.getNode(ISD::BUILD_VECTOR, dl, MVT::v4i32, N1, N1, N1, N1); + N0 = DAG.getNode(ISD::ADD, dl, MVT::v4i32, N0, N1); + N0 = DAG.getNode(ISD::BITCAST, dl, MVT::v4f32, N0); + // Convert back to integer and return. + // return vmovn_u32(vcvt_s32_f32(result)); + N0 = DAG.getNode(ISD::FP_TO_SINT, dl, MVT::v4i32, N0); + N0 = DAG.getNode(ISD::TRUNCATE, dl, MVT::v4i16, N0); + return N0; +} + SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { default: llvm_unreachable("Don't know how to custom lower this!"); @@ -3816,6 +4480,7 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { case ISD::BR_JT: return LowerBR_JT(Op, DAG); case ISD::VASTART: return LowerVASTART(Op, DAG); case ISD::MEMBARRIER: return LowerMEMBARRIER(Op, DAG, Subtarget); + case ISD::PREFETCH: return LowerPREFETCH(Op, DAG, Subtarget); case ISD::SINT_TO_FP: case ISD::UINT_TO_FP: return LowerINT_TO_FP(Op, DAG); case ISD::FP_TO_SINT: @@ -3826,9 +4491,10 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { case ISD::GLOBAL_OFFSET_TABLE: return LowerGLOBAL_OFFSET_TABLE(Op, DAG); case ISD::EH_SJLJ_SETJMP: return LowerEH_SJLJ_SETJMP(Op, DAG); case ISD::EH_SJLJ_LONGJMP: return LowerEH_SJLJ_LONGJMP(Op, DAG); + case ISD::EH_SJLJ_DISPATCHSETUP: return LowerEH_SJLJ_DISPATCHSETUP(Op, DAG); case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG, Subtarget); - case ISD::BIT_CONVERT: return ExpandBIT_CONVERT(Op.getNode(), DAG); + case ISD::BITCAST: return ExpandBITCAST(Op.getNode(), DAG); case ISD::SHL: case ISD::SRL: case ISD::SRA: return LowerShift(Op.getNode(), DAG, Subtarget); @@ -3843,6 +4509,8 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { case ISD::CONCAT_VECTORS: return LowerCONCAT_VECTORS(Op, DAG); case ISD::FLT_ROUNDS_: return LowerFLT_ROUNDS_(Op, DAG); case ISD::MUL: return LowerMUL(Op, DAG); + case ISD::SDIV: return LowerSDIV(Op, DAG); + case ISD::UDIV: return LowerUDIV(Op, DAG); } return SDValue(); } @@ -3857,12 +4525,12 @@ void ARMTargetLowering::ReplaceNodeResults(SDNode *N, default: llvm_unreachable("Don't know how to custom expand this!"); break; - case ISD::BIT_CONVERT: - Res = ExpandBIT_CONVERT(N, DAG); + case ISD::BITCAST: + Res = ExpandBITCAST(N, DAG); break; case ISD::SRL: case ISD::SRA: - Res = LowerShift(N, DAG, Subtarget); + Res = Expand64BitShift(N, DAG, Subtarget); break; } if (Res.getNode()) @@ -3892,7 +4560,7 @@ ARMTargetLowering::EmitAtomicCmpSwap(MachineInstr *MI, default: llvm_unreachable("unsupported size for AtomicCmpSwap!"); case 1: ldrOpc = isThumb2 ? ARM::t2LDREXB : ARM::LDREXB; - strOpc = isThumb2 ? ARM::t2LDREXB : ARM::STREXB; + strOpc = isThumb2 ? ARM::t2STREXB : ARM::STREXB; break; case 2: ldrOpc = isThumb2 ? ARM::t2LDREXH : ARM::LDREXH; @@ -4183,6 +4851,9 @@ ARMTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, case ARM::BCCi64: case ARM::BCCZi64: { + // If there is an unconditional branch to the other successor, remove it. + BB->erase(llvm::next(MachineBasicBlock::iterator(MI)), BB->end()); + // Compare both parts that make up the double comparison separately for // equality. bool RHSisZero = MI->getOpcode() == ARM::BCCZi64; @@ -4341,10 +5012,6 @@ static SDValue PerformMULCombine(SDNode *N, if (Subtarget->isThumb1Only()) return SDValue(); - if (DAG.getMachineFunction(). - getFunction()->hasFnAttr(Attribute::OptimizeForSize)) - return SDValue(); - if (DCI.isBeforeLegalize() || DCI.isCalledByLegalizer()) return SDValue(); @@ -4389,10 +5056,67 @@ static SDValue PerformMULCombine(SDNode *N, return SDValue(); } +static SDValue PerformANDCombine(SDNode *N, + TargetLowering::DAGCombinerInfo &DCI) { + // Attempt to use immediate-form VBIC + BuildVectorSDNode *BVN = dyn_cast(N->getOperand(1)); + DebugLoc dl = N->getDebugLoc(); + EVT VT = N->getValueType(0); + SelectionDAG &DAG = DCI.DAG; + + APInt SplatBits, SplatUndef; + unsigned SplatBitSize; + bool HasAnyUndefs; + if (BVN && + BVN->isConstantSplat(SplatBits, SplatUndef, SplatBitSize, HasAnyUndefs)) { + if (SplatBitSize <= 64) { + EVT VbicVT; + SDValue Val = isNEONModifiedImm((~SplatBits).getZExtValue(), + SplatUndef.getZExtValue(), SplatBitSize, + DAG, VbicVT, VT.is128BitVector(), + OtherModImm); + if (Val.getNode()) { + SDValue Input = + DAG.getNode(ISD::BITCAST, dl, VbicVT, N->getOperand(0)); + SDValue Vbic = DAG.getNode(ARMISD::VBICIMM, dl, VbicVT, Input, Val); + return DAG.getNode(ISD::BITCAST, dl, VT, Vbic); + } + } + } + + return SDValue(); +} + /// PerformORCombine - Target-specific dag combine xforms for ISD::OR static SDValue PerformORCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, const ARMSubtarget *Subtarget) { + // Attempt to use immediate-form VORR + BuildVectorSDNode *BVN = dyn_cast(N->getOperand(1)); + DebugLoc dl = N->getDebugLoc(); + EVT VT = N->getValueType(0); + SelectionDAG &DAG = DCI.DAG; + + APInt SplatBits, SplatUndef; + unsigned SplatBitSize; + bool HasAnyUndefs; + if (BVN && Subtarget->hasNEON() && + BVN->isConstantSplat(SplatBits, SplatUndef, SplatBitSize, HasAnyUndefs)) { + if (SplatBitSize <= 64) { + EVT VorrVT; + SDValue Val = isNEONModifiedImm(SplatBits.getZExtValue(), + SplatUndef.getZExtValue(), SplatBitSize, + DAG, VorrVT, VT.is128BitVector(), + OtherModImm); + if (Val.getNode()) { + SDValue Input = + DAG.getNode(ISD::BITCAST, dl, VorrVT, N->getOperand(0)); + SDValue Vorr = DAG.getNode(ARMISD::VORRIMM, dl, VorrVT, Input, Val); + return DAG.getNode(ISD::BITCAST, dl, VT, Vorr); + } + } + } + // Try to use the ARM/Thumb2 BFI (bitfield insert) instruction when // reasonable. @@ -4400,7 +5124,6 @@ static SDValue PerformORCombine(SDNode *N, if (Subtarget->isThumb1Only() || !Subtarget->hasV6T2Ops()) return SDValue(); - SelectionDAG &DAG = DCI.DAG; SDValue N0 = N->getOperand(0), N1 = N->getOperand(1); DebugLoc DL = N->getDebugLoc(); // 1) or (and A, mask), val => ARMbfi A, val, mask @@ -4415,40 +5138,46 @@ static SDValue PerformORCombine(SDNode *N, if (N0.getOpcode() != ISD::AND) return SDValue(); - EVT VT = N->getValueType(0); if (VT != MVT::i32) return SDValue(); + SDValue N00 = N0.getOperand(0); // The value and the mask need to be constants so we can verify this is // actually a bitfield set. If the mask is 0xffff, we can do better // via a movt instruction, so don't use BFI in that case. - ConstantSDNode *C = dyn_cast(N0.getOperand(1)); - if (!C) + SDValue MaskOp = N0.getOperand(1); + ConstantSDNode *MaskC = dyn_cast(MaskOp); + if (!MaskC) return SDValue(); - unsigned Mask = C->getZExtValue(); + unsigned Mask = MaskC->getZExtValue(); if (Mask == 0xffff) return SDValue(); SDValue Res; // Case (1): or (and A, mask), val => ARMbfi A, val, mask - if ((C = dyn_cast(N1))) { - unsigned Val = C->getZExtValue(); - if (!ARM::isBitFieldInvertedMask(Mask) || (Val & ~Mask) != Val) + ConstantSDNode *N1C = dyn_cast(N1); + if (N1C) { + unsigned Val = N1C->getZExtValue(); + if ((Val & ~Mask) != Val) return SDValue(); - Val >>= CountTrailingZeros_32(~Mask); - Res = DAG.getNode(ARMISD::BFI, DL, VT, N0.getOperand(0), - DAG.getConstant(Val, MVT::i32), - DAG.getConstant(Mask, MVT::i32)); + if (ARM::isBitFieldInvertedMask(Mask)) { + Val >>= CountTrailingZeros_32(~Mask); - // Do not add new nodes to DAG combiner worklist. - DCI.CombineTo(N, Res, false); + Res = DAG.getNode(ARMISD::BFI, DL, VT, N00, + DAG.getConstant(Val, MVT::i32), + DAG.getConstant(Mask, MVT::i32)); + + // Do not add new nodes to DAG combiner worklist. + DCI.CombineTo(N, Res, false); + return SDValue(); + } } else if (N1.getOpcode() == ISD::AND) { // case (2) or (and A, mask), (and B, mask2) => ARMbfi A, (lsr B, amt), mask - C = dyn_cast(N1.getOperand(1)); - if (!C) + ConstantSDNode *N11C = dyn_cast(N1.getOperand(1)); + if (!N11C) return SDValue(); - unsigned Mask2 = C->getZExtValue(); + unsigned Mask2 = N11C->getZExtValue(); if (ARM::isBitFieldInvertedMask(Mask) && ARM::isBitFieldInvertedMask(~Mask2) && @@ -4462,10 +5191,11 @@ static SDValue PerformORCombine(SDNode *N, unsigned lsb = CountTrailingZeros_32(Mask2); Res = DAG.getNode(ISD::SRL, DL, VT, N1.getOperand(0), DAG.getConstant(lsb, MVT::i32)); - Res = DAG.getNode(ARMISD::BFI, DL, VT, N0.getOperand(0), Res, + Res = DAG.getNode(ARMISD::BFI, DL, VT, N00, Res, DAG.getConstant(Mask, MVT::i32)); // Do not add new nodes to DAG combiner worklist. DCI.CombineTo(N, Res, false); + return SDValue(); } else if (ARM::isBitFieldInvertedMask(~Mask) && ARM::isBitFieldInvertedMask(Mask2) && (CountPopulation_32(~Mask) == CountPopulation_32(Mask2))) { @@ -4476,40 +5206,472 @@ static SDValue PerformORCombine(SDNode *N, return SDValue(); // 2b unsigned lsb = CountTrailingZeros_32(Mask); - Res = DAG.getNode(ISD::SRL, DL, VT, N0.getOperand(0), + Res = DAG.getNode(ISD::SRL, DL, VT, N00, DAG.getConstant(lsb, MVT::i32)); Res = DAG.getNode(ARMISD::BFI, DL, VT, N1.getOperand(0), Res, DAG.getConstant(Mask2, MVT::i32)); // Do not add new nodes to DAG combiner worklist. DCI.CombineTo(N, Res, false); + return SDValue(); } } + if (DAG.MaskedValueIsZero(N1, MaskC->getAPIntValue()) && + N00.getOpcode() == ISD::SHL && isa(N00.getOperand(1)) && + ARM::isBitFieldInvertedMask(~Mask)) { + // Case (3): or (and (shl A, #shamt), mask), B => ARMbfi B, A, ~mask + // where lsb(mask) == #shamt and masked bits of B are known zero. + SDValue ShAmt = N00.getOperand(1); + unsigned ShAmtC = cast(ShAmt)->getZExtValue(); + unsigned LSB = CountTrailingZeros_32(Mask); + if (ShAmtC != LSB) + return SDValue(); + + Res = DAG.getNode(ARMISD::BFI, DL, VT, N1, N00.getOperand(0), + DAG.getConstant(~Mask, MVT::i32)); + + // Do not add new nodes to DAG combiner worklist. + DCI.CombineTo(N, Res, false); + } + + return SDValue(); +} + +/// PerformBFICombine - (bfi A, (and B, C1), C2) -> (bfi A, B, C2) iff +/// C1 & C2 == C1. +static SDValue PerformBFICombine(SDNode *N, + TargetLowering::DAGCombinerInfo &DCI) { + SDValue N1 = N->getOperand(1); + if (N1.getOpcode() == ISD::AND) { + ConstantSDNode *N11C = dyn_cast(N1.getOperand(1)); + if (!N11C) + return SDValue(); + unsigned Mask = cast(N->getOperand(2))->getZExtValue(); + unsigned Mask2 = N11C->getZExtValue(); + if ((Mask & Mask2) == Mask2) + return DCI.DAG.getNode(ARMISD::BFI, N->getDebugLoc(), N->getValueType(0), + N->getOperand(0), N1.getOperand(0), + N->getOperand(2)); + } return SDValue(); } /// PerformVMOVRRDCombine - Target-specific dag combine xforms for /// ARMISD::VMOVRRD. static SDValue PerformVMOVRRDCombine(SDNode *N, - TargetLowering::DAGCombinerInfo &DCI) { - // fmrrd(fmdrr x, y) -> x,y + TargetLowering::DAGCombinerInfo &DCI) { + // vmovrrd(vmovdrr x, y) -> x,y SDValue InDouble = N->getOperand(0); if (InDouble.getOpcode() == ARMISD::VMOVDRR) return DCI.CombineTo(N, InDouble.getOperand(0), InDouble.getOperand(1)); return SDValue(); } +/// PerformVMOVDRRCombine - Target-specific dag combine xforms for +/// ARMISD::VMOVDRR. This is also used for BUILD_VECTORs with 2 operands. +static SDValue PerformVMOVDRRCombine(SDNode *N, SelectionDAG &DAG) { + // N=vmovrrd(X); vmovdrr(N:0, N:1) -> bit_convert(X) + SDValue Op0 = N->getOperand(0); + SDValue Op1 = N->getOperand(1); + if (Op0.getOpcode() == ISD::BITCAST) + Op0 = Op0.getOperand(0); + if (Op1.getOpcode() == ISD::BITCAST) + Op1 = Op1.getOperand(0); + if (Op0.getOpcode() == ARMISD::VMOVRRD && + Op0.getNode() == Op1.getNode() && + Op0.getResNo() == 0 && Op1.getResNo() == 1) + return DAG.getNode(ISD::BITCAST, N->getDebugLoc(), + N->getValueType(0), Op0.getOperand(0)); + return SDValue(); +} + +/// PerformSTORECombine - Target-specific dag combine xforms for +/// ISD::STORE. +static SDValue PerformSTORECombine(SDNode *N, + TargetLowering::DAGCombinerInfo &DCI) { + // Bitcast an i64 store extracted from a vector to f64. + // Otherwise, the i64 value will be legalized to a pair of i32 values. + StoreSDNode *St = cast(N); + SDValue StVal = St->getValue(); + if (!ISD::isNormalStore(St) || St->isVolatile() || + StVal.getValueType() != MVT::i64 || + StVal.getNode()->getOpcode() != ISD::EXTRACT_VECTOR_ELT) + return SDValue(); + + SelectionDAG &DAG = DCI.DAG; + DebugLoc dl = StVal.getDebugLoc(); + SDValue IntVec = StVal.getOperand(0); + EVT FloatVT = EVT::getVectorVT(*DAG.getContext(), MVT::f64, + IntVec.getValueType().getVectorNumElements()); + SDValue Vec = DAG.getNode(ISD::BITCAST, dl, FloatVT, IntVec); + SDValue ExtElt = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, MVT::f64, + Vec, StVal.getOperand(1)); + dl = N->getDebugLoc(); + SDValue V = DAG.getNode(ISD::BITCAST, dl, MVT::i64, ExtElt); + // Make the DAGCombiner fold the bitcasts. + DCI.AddToWorklist(Vec.getNode()); + DCI.AddToWorklist(ExtElt.getNode()); + DCI.AddToWorklist(V.getNode()); + return DAG.getStore(St->getChain(), dl, V, St->getBasePtr(), + St->getPointerInfo(), St->isVolatile(), + St->isNonTemporal(), St->getAlignment(), + St->getTBAAInfo()); +} + +/// hasNormalLoadOperand - Check if any of the operands of a BUILD_VECTOR node +/// are normal, non-volatile loads. If so, it is profitable to bitcast an +/// i64 vector to have f64 elements, since the value can then be loaded +/// directly into a VFP register. +static bool hasNormalLoadOperand(SDNode *N) { + unsigned NumElts = N->getValueType(0).getVectorNumElements(); + for (unsigned i = 0; i < NumElts; ++i) { + SDNode *Elt = N->getOperand(i).getNode(); + if (ISD::isNormalLoad(Elt) && !cast(Elt)->isVolatile()) + return true; + } + return false; +} + +/// PerformBUILD_VECTORCombine - Target-specific dag combine xforms for +/// ISD::BUILD_VECTOR. +static SDValue PerformBUILD_VECTORCombine(SDNode *N, + TargetLowering::DAGCombinerInfo &DCI){ + // build_vector(N=ARMISD::VMOVRRD(X), N:1) -> bit_convert(X): + // VMOVRRD is introduced when legalizing i64 types. It forces the i64 value + // into a pair of GPRs, which is fine when the value is used as a scalar, + // but if the i64 value is converted to a vector, we need to undo the VMOVRRD. + SelectionDAG &DAG = DCI.DAG; + if (N->getNumOperands() == 2) { + SDValue RV = PerformVMOVDRRCombine(N, DAG); + if (RV.getNode()) + return RV; + } + + // Load i64 elements as f64 values so that type legalization does not split + // them up into i32 values. + EVT VT = N->getValueType(0); + if (VT.getVectorElementType() != MVT::i64 || !hasNormalLoadOperand(N)) + return SDValue(); + DebugLoc dl = N->getDebugLoc(); + SmallVector Ops; + unsigned NumElts = VT.getVectorNumElements(); + for (unsigned i = 0; i < NumElts; ++i) { + SDValue V = DAG.getNode(ISD::BITCAST, dl, MVT::f64, N->getOperand(i)); + Ops.push_back(V); + // Make the DAGCombiner fold the bitcast. + DCI.AddToWorklist(V.getNode()); + } + EVT FloatVT = EVT::getVectorVT(*DAG.getContext(), MVT::f64, NumElts); + SDValue BV = DAG.getNode(ISD::BUILD_VECTOR, dl, FloatVT, Ops.data(), NumElts); + return DAG.getNode(ISD::BITCAST, dl, VT, BV); +} + +/// PerformInsertEltCombine - Target-specific dag combine xforms for +/// ISD::INSERT_VECTOR_ELT. +static SDValue PerformInsertEltCombine(SDNode *N, + TargetLowering::DAGCombinerInfo &DCI) { + // Bitcast an i64 load inserted into a vector to f64. + // Otherwise, the i64 value will be legalized to a pair of i32 values. + EVT VT = N->getValueType(0); + SDNode *Elt = N->getOperand(1).getNode(); + if (VT.getVectorElementType() != MVT::i64 || + !ISD::isNormalLoad(Elt) || cast(Elt)->isVolatile()) + return SDValue(); + + SelectionDAG &DAG = DCI.DAG; + DebugLoc dl = N->getDebugLoc(); + EVT FloatVT = EVT::getVectorVT(*DAG.getContext(), MVT::f64, + VT.getVectorNumElements()); + SDValue Vec = DAG.getNode(ISD::BITCAST, dl, FloatVT, N->getOperand(0)); + SDValue V = DAG.getNode(ISD::BITCAST, dl, MVT::f64, N->getOperand(1)); + // Make the DAGCombiner fold the bitcasts. + DCI.AddToWorklist(Vec.getNode()); + DCI.AddToWorklist(V.getNode()); + SDValue InsElt = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, FloatVT, + Vec, V, N->getOperand(2)); + return DAG.getNode(ISD::BITCAST, dl, VT, InsElt); +} + +/// PerformVECTOR_SHUFFLECombine - Target-specific dag combine xforms for +/// ISD::VECTOR_SHUFFLE. +static SDValue PerformVECTOR_SHUFFLECombine(SDNode *N, SelectionDAG &DAG) { + // The LLVM shufflevector instruction does not require the shuffle mask + // length to match the operand vector length, but ISD::VECTOR_SHUFFLE does + // have that requirement. When translating to ISD::VECTOR_SHUFFLE, if the + // operands do not match the mask length, they are extended by concatenating + // them with undef vectors. That is probably the right thing for other + // targets, but for NEON it is better to concatenate two double-register + // size vector operands into a single quad-register size vector. Do that + // transformation here: + // shuffle(concat(v1, undef), concat(v2, undef)) -> + // shuffle(concat(v1, v2), undef) + SDValue Op0 = N->getOperand(0); + SDValue Op1 = N->getOperand(1); + if (Op0.getOpcode() != ISD::CONCAT_VECTORS || + Op1.getOpcode() != ISD::CONCAT_VECTORS || + Op0.getNumOperands() != 2 || + Op1.getNumOperands() != 2) + return SDValue(); + SDValue Concat0Op1 = Op0.getOperand(1); + SDValue Concat1Op1 = Op1.getOperand(1); + if (Concat0Op1.getOpcode() != ISD::UNDEF || + Concat1Op1.getOpcode() != ISD::UNDEF) + return SDValue(); + // Skip the transformation if any of the types are illegal. + const TargetLowering &TLI = DAG.getTargetLoweringInfo(); + EVT VT = N->getValueType(0); + if (!TLI.isTypeLegal(VT) || + !TLI.isTypeLegal(Concat0Op1.getValueType()) || + !TLI.isTypeLegal(Concat1Op1.getValueType())) + return SDValue(); + + SDValue NewConcat = DAG.getNode(ISD::CONCAT_VECTORS, N->getDebugLoc(), VT, + Op0.getOperand(0), Op1.getOperand(0)); + // Translate the shuffle mask. + SmallVector NewMask; + unsigned NumElts = VT.getVectorNumElements(); + unsigned HalfElts = NumElts/2; + ShuffleVectorSDNode *SVN = cast(N); + for (unsigned n = 0; n < NumElts; ++n) { + int MaskElt = SVN->getMaskElt(n); + int NewElt = -1; + if (MaskElt < (int)HalfElts) + NewElt = MaskElt; + else if (MaskElt >= (int)NumElts && MaskElt < (int)(NumElts + HalfElts)) + NewElt = HalfElts + MaskElt - NumElts; + NewMask.push_back(NewElt); + } + return DAG.getVectorShuffle(VT, N->getDebugLoc(), NewConcat, + DAG.getUNDEF(VT), NewMask.data()); +} + +/// CombineBaseUpdate - Target-specific DAG combine function for VLDDUP and +/// NEON load/store intrinsics to merge base address updates. +static SDValue CombineBaseUpdate(SDNode *N, + TargetLowering::DAGCombinerInfo &DCI) { + if (DCI.isBeforeLegalize() || DCI.isCalledByLegalizer()) + return SDValue(); + + SelectionDAG &DAG = DCI.DAG; + bool isIntrinsic = (N->getOpcode() == ISD::INTRINSIC_VOID || + N->getOpcode() == ISD::INTRINSIC_W_CHAIN); + unsigned AddrOpIdx = (isIntrinsic ? 2 : 1); + SDValue Addr = N->getOperand(AddrOpIdx); + + // Search for a use of the address operand that is an increment. + for (SDNode::use_iterator UI = Addr.getNode()->use_begin(), + UE = Addr.getNode()->use_end(); UI != UE; ++UI) { + SDNode *User = *UI; + if (User->getOpcode() != ISD::ADD || + UI.getUse().getResNo() != Addr.getResNo()) + continue; + + // Check that the add is independent of the load/store. Otherwise, folding + // it would create a cycle. + if (User->isPredecessorOf(N) || N->isPredecessorOf(User)) + continue; + + // Find the new opcode for the updating load/store. + bool isLoad = true; + bool isLaneOp = false; + unsigned NewOpc = 0; + unsigned NumVecs = 0; + if (isIntrinsic) { + unsigned IntNo = cast(N->getOperand(1))->getZExtValue(); + switch (IntNo) { + default: assert(0 && "unexpected intrinsic for Neon base update"); + case Intrinsic::arm_neon_vld1: NewOpc = ARMISD::VLD1_UPD; + NumVecs = 1; break; + case Intrinsic::arm_neon_vld2: NewOpc = ARMISD::VLD2_UPD; + NumVecs = 2; break; + case Intrinsic::arm_neon_vld3: NewOpc = ARMISD::VLD3_UPD; + NumVecs = 3; break; + case Intrinsic::arm_neon_vld4: NewOpc = ARMISD::VLD4_UPD; + NumVecs = 4; break; + case Intrinsic::arm_neon_vld2lane: NewOpc = ARMISD::VLD2LN_UPD; + NumVecs = 2; isLaneOp = true; break; + case Intrinsic::arm_neon_vld3lane: NewOpc = ARMISD::VLD3LN_UPD; + NumVecs = 3; isLaneOp = true; break; + case Intrinsic::arm_neon_vld4lane: NewOpc = ARMISD::VLD4LN_UPD; + NumVecs = 4; isLaneOp = true; break; + case Intrinsic::arm_neon_vst1: NewOpc = ARMISD::VST1_UPD; + NumVecs = 1; isLoad = false; break; + case Intrinsic::arm_neon_vst2: NewOpc = ARMISD::VST2_UPD; + NumVecs = 2; isLoad = false; break; + case Intrinsic::arm_neon_vst3: NewOpc = ARMISD::VST3_UPD; + NumVecs = 3; isLoad = false; break; + case Intrinsic::arm_neon_vst4: NewOpc = ARMISD::VST4_UPD; + NumVecs = 4; isLoad = false; break; + case Intrinsic::arm_neon_vst2lane: NewOpc = ARMISD::VST2LN_UPD; + NumVecs = 2; isLoad = false; isLaneOp = true; break; + case Intrinsic::arm_neon_vst3lane: NewOpc = ARMISD::VST3LN_UPD; + NumVecs = 3; isLoad = false; isLaneOp = true; break; + case Intrinsic::arm_neon_vst4lane: NewOpc = ARMISD::VST4LN_UPD; + NumVecs = 4; isLoad = false; isLaneOp = true; break; + } + } else { + isLaneOp = true; + switch (N->getOpcode()) { + default: assert(0 && "unexpected opcode for Neon base update"); + case ARMISD::VLD2DUP: NewOpc = ARMISD::VLD2DUP_UPD; NumVecs = 2; break; + case ARMISD::VLD3DUP: NewOpc = ARMISD::VLD3DUP_UPD; NumVecs = 3; break; + case ARMISD::VLD4DUP: NewOpc = ARMISD::VLD4DUP_UPD; NumVecs = 4; break; + } + } + + // Find the size of memory referenced by the load/store. + EVT VecTy; + if (isLoad) + VecTy = N->getValueType(0); + else + VecTy = N->getOperand(AddrOpIdx+1).getValueType(); + unsigned NumBytes = NumVecs * VecTy.getSizeInBits() / 8; + if (isLaneOp) + NumBytes /= VecTy.getVectorNumElements(); + + // If the increment is a constant, it must match the memory ref size. + SDValue Inc = User->getOperand(User->getOperand(0) == Addr ? 1 : 0); + if (ConstantSDNode *CInc = dyn_cast(Inc.getNode())) { + uint64_t IncVal = CInc->getZExtValue(); + if (IncVal != NumBytes) + continue; + } else if (NumBytes >= 3 * 16) { + // VLD3/4 and VST3/4 for 128-bit vectors are implemented with two + // separate instructions that make it harder to use a non-constant update. + continue; + } + + // Create the new updating load/store node. + EVT Tys[6]; + unsigned NumResultVecs = (isLoad ? NumVecs : 0); + unsigned n; + for (n = 0; n < NumResultVecs; ++n) + Tys[n] = VecTy; + Tys[n++] = MVT::i32; + Tys[n] = MVT::Other; + SDVTList SDTys = DAG.getVTList(Tys, NumResultVecs+2); + SmallVector Ops; + Ops.push_back(N->getOperand(0)); // incoming chain + Ops.push_back(N->getOperand(AddrOpIdx)); + Ops.push_back(Inc); + for (unsigned i = AddrOpIdx + 1; i < N->getNumOperands(); ++i) { + Ops.push_back(N->getOperand(i)); + } + MemIntrinsicSDNode *MemInt = cast(N); + SDValue UpdN = DAG.getMemIntrinsicNode(NewOpc, N->getDebugLoc(), SDTys, + Ops.data(), Ops.size(), + MemInt->getMemoryVT(), + MemInt->getMemOperand()); + + // Update the uses. + std::vector NewResults; + for (unsigned i = 0; i < NumResultVecs; ++i) { + NewResults.push_back(SDValue(UpdN.getNode(), i)); + } + NewResults.push_back(SDValue(UpdN.getNode(), NumResultVecs+1)); // chain + DCI.CombineTo(N, NewResults); + DCI.CombineTo(User, SDValue(UpdN.getNode(), NumResultVecs)); + + break; + } + return SDValue(); +} + +/// CombineVLDDUP - For a VDUPLANE node N, check if its source operand is a +/// vldN-lane (N > 1) intrinsic, and if all the other uses of that intrinsic +/// are also VDUPLANEs. If so, combine them to a vldN-dup operation and +/// return true. +static bool CombineVLDDUP(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { + SelectionDAG &DAG = DCI.DAG; + EVT VT = N->getValueType(0); + // vldN-dup instructions only support 64-bit vectors for N > 1. + if (!VT.is64BitVector()) + return false; + + // Check if the VDUPLANE operand is a vldN-dup intrinsic. + SDNode *VLD = N->getOperand(0).getNode(); + if (VLD->getOpcode() != ISD::INTRINSIC_W_CHAIN) + return false; + unsigned NumVecs = 0; + unsigned NewOpc = 0; + unsigned IntNo = cast(VLD->getOperand(1))->getZExtValue(); + if (IntNo == Intrinsic::arm_neon_vld2lane) { + NumVecs = 2; + NewOpc = ARMISD::VLD2DUP; + } else if (IntNo == Intrinsic::arm_neon_vld3lane) { + NumVecs = 3; + NewOpc = ARMISD::VLD3DUP; + } else if (IntNo == Intrinsic::arm_neon_vld4lane) { + NumVecs = 4; + NewOpc = ARMISD::VLD4DUP; + } else { + return false; + } + + // First check that all the vldN-lane uses are VDUPLANEs and that the lane + // numbers match the load. + unsigned VLDLaneNo = + cast(VLD->getOperand(NumVecs+3))->getZExtValue(); + for (SDNode::use_iterator UI = VLD->use_begin(), UE = VLD->use_end(); + UI != UE; ++UI) { + // Ignore uses of the chain result. + if (UI.getUse().getResNo() == NumVecs) + continue; + SDNode *User = *UI; + if (User->getOpcode() != ARMISD::VDUPLANE || + VLDLaneNo != cast(User->getOperand(1))->getZExtValue()) + return false; + } + + // Create the vldN-dup node. + EVT Tys[5]; + unsigned n; + for (n = 0; n < NumVecs; ++n) + Tys[n] = VT; + Tys[n] = MVT::Other; + SDVTList SDTys = DAG.getVTList(Tys, NumVecs+1); + SDValue Ops[] = { VLD->getOperand(0), VLD->getOperand(2) }; + MemIntrinsicSDNode *VLDMemInt = cast(VLD); + SDValue VLDDup = DAG.getMemIntrinsicNode(NewOpc, VLD->getDebugLoc(), SDTys, + Ops, 2, VLDMemInt->getMemoryVT(), + VLDMemInt->getMemOperand()); + + // Update the uses. + for (SDNode::use_iterator UI = VLD->use_begin(), UE = VLD->use_end(); + UI != UE; ++UI) { + unsigned ResNo = UI.getUse().getResNo(); + // Ignore uses of the chain result. + if (ResNo == NumVecs) + continue; + SDNode *User = *UI; + DCI.CombineTo(User, SDValue(VLDDup.getNode(), ResNo)); + } + + // Now the vldN-lane intrinsic is dead except for its chain result. + // Update uses of the chain. + std::vector VLDDupResults; + for (unsigned n = 0; n < NumVecs; ++n) + VLDDupResults.push_back(SDValue(VLDDup.getNode(), n)); + VLDDupResults.push_back(SDValue(VLDDup.getNode(), NumVecs)); + DCI.CombineTo(VLD, VLDDupResults); + + return true; +} + /// PerformVDUPLANECombine - Target-specific dag combine xforms for /// ARMISD::VDUPLANE. static SDValue PerformVDUPLANECombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { - // If the source is already a VMOVIMM or VMVNIMM splat, the VDUPLANE is - // redundant. SDValue Op = N->getOperand(0); - EVT VT = N->getValueType(0); - // Ignore bit_converts. - while (Op.getOpcode() == ISD::BIT_CONVERT) + // If the source is a vldN-lane (N > 1) intrinsic, and all the other uses + // of that intrinsic are also VDUPLANEs, combine them to a vldN-dup operation. + if (CombineVLDDUP(N, DCI)) + return SDValue(N, 0); + + // If the source is already a VMOVIMM or VMVNIMM splat, the VDUPLANE is + // redundant. Ignore bit_converts for now; element sizes are checked below. + while (Op.getOpcode() == ISD::BITCAST) Op = Op.getOperand(0); if (Op.getOpcode() != ARMISD::VMOVIMM && Op.getOpcode() != ARMISD::VMVNIMM) return SDValue(); @@ -4521,11 +5683,11 @@ static SDValue PerformVDUPLANECombine(SDNode *N, unsigned EltBits; if (ARM_AM::decodeNEONModImm(Imm, EltBits) == 0) EltSize = 8; + EVT VT = N->getValueType(0); if (EltSize > VT.getVectorElementType().getSizeInBits()) return SDValue(); - SDValue Res = DCI.DAG.getNode(ISD::BIT_CONVERT, N->getDebugLoc(), VT, Op); - return DCI.CombineTo(N, Res, false); + return DCI.DAG.getNode(ISD::BITCAST, N->getDebugLoc(), VT, Op); } /// getVShiftImm - Check if this is a valid build_vector for the immediate @@ -4533,7 +5695,7 @@ static SDValue PerformVDUPLANECombine(SDNode *N, /// build_vector must have the same constant integer value. static bool getVShiftImm(SDValue Op, unsigned ElementBits, int64_t &Cnt) { // Ignore bit_converts. - while (Op.getOpcode() == ISD::BIT_CONVERT) + while (Op.getOpcode() == ISD::BITCAST) Op = Op.getOperand(0); BuildVectorSDNode *BVN = dyn_cast(Op.getNode()); APInt SplatBits, SplatUndef; @@ -4747,7 +5909,8 @@ static SDValue PerformShiftCombine(SDNode *N, SelectionDAG &DAG, EVT VT = N->getValueType(0); // Nothing to be done for scalar shifts. - if (! VT.isVector()) + const TargetLowering &TLI = DAG.getTargetLoweringInfo(); + if (!VT.isVector() || !TLI.isTypeLegal(VT)) return SDValue(); assert(ST->hasNEON() && "unexpected vector shift"); @@ -4793,7 +5956,8 @@ static SDValue PerformExtendCombine(SDNode *N, SelectionDAG &DAG, if (VT == MVT::i32 && (EltVT == MVT::i8 || EltVT == MVT::i16) && - TLI.isTypeLegal(Vec.getValueType())) { + TLI.isTypeLegal(Vec.getValueType()) && + isa(Lane)) { unsigned Opc = 0; switch (N->getOpcode()) { @@ -4906,7 +6070,14 @@ SDValue ARMTargetLowering::PerformDAGCombine(SDNode *N, case ISD::SUB: return PerformSUBCombine(N, DCI); case ISD::MUL: return PerformMULCombine(N, DCI, Subtarget); case ISD::OR: return PerformORCombine(N, DCI, Subtarget); + case ISD::AND: return PerformANDCombine(N, DCI); + case ARMISD::BFI: return PerformBFICombine(N, DCI); case ARMISD::VMOVRRD: return PerformVMOVRRDCombine(N, DCI); + case ARMISD::VMOVDRR: return PerformVMOVDRRCombine(N, DCI.DAG); + case ISD::STORE: return PerformSTORECombine(N, DCI); + case ISD::BUILD_VECTOR: return PerformBUILD_VECTORCombine(N, DCI); + case ISD::INSERT_VECTOR_ELT: return PerformInsertEltCombine(N, DCI); + case ISD::VECTOR_SHUFFLE: return PerformVECTOR_SHUFFLECombine(N, DCI.DAG); case ARMISD::VDUPLANE: return PerformVDUPLANECombine(N, DCI); case ISD::INTRINSIC_WO_CHAIN: return PerformIntrinsicCombine(N, DCI.DAG); case ISD::SHL: @@ -4916,20 +6087,42 @@ SDValue ARMTargetLowering::PerformDAGCombine(SDNode *N, case ISD::ZERO_EXTEND: case ISD::ANY_EXTEND: return PerformExtendCombine(N, DCI.DAG, Subtarget); case ISD::SELECT_CC: return PerformSELECT_CCCombine(N, DCI.DAG, Subtarget); + case ARMISD::VLD2DUP: + case ARMISD::VLD3DUP: + case ARMISD::VLD4DUP: + return CombineBaseUpdate(N, DCI); + case ISD::INTRINSIC_VOID: + case ISD::INTRINSIC_W_CHAIN: + switch (cast(N->getOperand(1))->getZExtValue()) { + case Intrinsic::arm_neon_vld1: + case Intrinsic::arm_neon_vld2: + case Intrinsic::arm_neon_vld3: + case Intrinsic::arm_neon_vld4: + case Intrinsic::arm_neon_vld2lane: + case Intrinsic::arm_neon_vld3lane: + case Intrinsic::arm_neon_vld4lane: + case Intrinsic::arm_neon_vst1: + case Intrinsic::arm_neon_vst2: + case Intrinsic::arm_neon_vst3: + case Intrinsic::arm_neon_vst4: + case Intrinsic::arm_neon_vst2lane: + case Intrinsic::arm_neon_vst3lane: + case Intrinsic::arm_neon_vst4lane: + return CombineBaseUpdate(N, DCI); + default: break; + } + break; } return SDValue(); } -bool ARMTargetLowering::allowsUnalignedMemoryAccesses(EVT VT) const { - if (!Subtarget->hasV6Ops()) - // Pre-v6 does not support unaligned mem access. - return false; +bool ARMTargetLowering::isDesirableToTransformToIntegerOp(unsigned Opc, + EVT VT) const { + return (VT == MVT::f32) && (Opc == ISD::LOAD || Opc == ISD::STORE); +} - // v6+ may or may not support unaligned mem access depending on the system - // configuration. - // FIXME: This is pretty conservative. Should we provide cmdline option to - // control the behaviour? - if (!Subtarget->isTargetDarwin()) +bool ARMTargetLowering::allowsUnalignedMemoryAccesses(EVT VT) const { + if (!Subtarget->allowsUnalignedMem()) return false; switch (VT.getSimpleVT().SimpleTy) { @@ -5143,7 +6336,7 @@ bool ARMTargetLowering::isLegalICmpImmediate(int64_t Imm) const { if (!Subtarget->isThumb()) return ARM_AM::getSOImmVal(Imm) != -1; if (Subtarget->isThumb2()) - return ARM_AM::getT2SOImmVal(Imm) != -1; + return ARM_AM::getT2SOImmVal(Imm) != -1; return Imm >= 0 && Imm <= 255; } @@ -5348,6 +6541,37 @@ void ARMTargetLowering::computeMaskedBitsForTargetNode(const SDValue Op, // ARM Inline Assembly Support //===----------------------------------------------------------------------===// +bool ARMTargetLowering::ExpandInlineAsm(CallInst *CI) const { + // Looking for "rev" which is V6+. + if (!Subtarget->hasV6Ops()) + return false; + + InlineAsm *IA = cast(CI->getCalledValue()); + std::string AsmStr = IA->getAsmString(); + SmallVector AsmPieces; + SplitString(AsmStr, AsmPieces, ";\n"); + + switch (AsmPieces.size()) { + default: return false; + case 1: + AsmStr = AsmPieces[0]; + AsmPieces.clear(); + SplitString(AsmStr, AsmPieces, " \t,"); + + // rev $0, $1 + if (AsmPieces.size() == 3 && + AsmPieces[0] == "rev" && AsmPieces[1] == "$0" && AsmPieces[2] == "$1" && + IA->getConstraintString().compare(0, 4, "=l,l") == 0) { + const IntegerType *Ty = dyn_cast(CI->getType()); + if (Ty && Ty->getBitWidth() == 32) + return IntrinsicLowering::LowerToByteSwap(CI); + } + break; + } + + return false; +} + /// getConstraintType - Given a constraint letter, return the type of /// constraint it is for this target. ARMTargetLowering::ConstraintType @@ -5362,6 +6586,40 @@ ARMTargetLowering::getConstraintType(const std::string &Constraint) const { return TargetLowering::getConstraintType(Constraint); } +/// Examine constraint type and operand type and determine a weight value. +/// This object must already have been set up with the operand type +/// and the current alternative constraint selected. +TargetLowering::ConstraintWeight +ARMTargetLowering::getSingleConstraintMatchWeight( + AsmOperandInfo &info, const char *constraint) const { + ConstraintWeight weight = CW_Invalid; + Value *CallOperandVal = info.CallOperandVal; + // If we don't have a value, we can't do a match, + // but allow it at the lowest weight. + if (CallOperandVal == NULL) + return CW_Default; + const Type *type = CallOperandVal->getType(); + // Look at the constraint type. + switch (*constraint) { + default: + weight = TargetLowering::getSingleConstraintMatchWeight(info, constraint); + break; + case 'l': + if (type->isIntegerTy()) { + if (Subtarget->isThumb()) + weight = CW_SpecificReg; + else + weight = CW_Register; + } + break; + case 'w': + if (type->isFloatingPointTy()) + weight = CW_Register; + break; + } + return weight; +} + std::pair ARMTargetLowering::getRegForInlineAsmConstraint(const std::string &Constraint, EVT VT) const { @@ -5664,3 +6922,63 @@ bool ARMTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const { return ARM::getVFPf64Imm(Imm) != -1; return false; } + +/// getTgtMemIntrinsic - Represent NEON load and store intrinsics as +/// MemIntrinsicNodes. The associated MachineMemOperands record the alignment +/// specified in the intrinsic calls. +bool ARMTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info, + const CallInst &I, + unsigned Intrinsic) const { + switch (Intrinsic) { + case Intrinsic::arm_neon_vld1: + case Intrinsic::arm_neon_vld2: + case Intrinsic::arm_neon_vld3: + case Intrinsic::arm_neon_vld4: + case Intrinsic::arm_neon_vld2lane: + case Intrinsic::arm_neon_vld3lane: + case Intrinsic::arm_neon_vld4lane: { + Info.opc = ISD::INTRINSIC_W_CHAIN; + // Conservatively set memVT to the entire set of vectors loaded. + uint64_t NumElts = getTargetData()->getTypeAllocSize(I.getType()) / 8; + Info.memVT = EVT::getVectorVT(I.getType()->getContext(), MVT::i64, NumElts); + Info.ptrVal = I.getArgOperand(0); + Info.offset = 0; + Value *AlignArg = I.getArgOperand(I.getNumArgOperands() - 1); + Info.align = cast(AlignArg)->getZExtValue(); + Info.vol = false; // volatile loads with NEON intrinsics not supported + Info.readMem = true; + Info.writeMem = false; + return true; + } + case Intrinsic::arm_neon_vst1: + case Intrinsic::arm_neon_vst2: + case Intrinsic::arm_neon_vst3: + case Intrinsic::arm_neon_vst4: + case Intrinsic::arm_neon_vst2lane: + case Intrinsic::arm_neon_vst3lane: + case Intrinsic::arm_neon_vst4lane: { + Info.opc = ISD::INTRINSIC_VOID; + // Conservatively set memVT to the entire set of vectors stored. + unsigned NumElts = 0; + for (unsigned ArgI = 1, ArgE = I.getNumArgOperands(); ArgI < ArgE; ++ArgI) { + const Type *ArgTy = I.getArgOperand(ArgI)->getType(); + if (!ArgTy->isVectorTy()) + break; + NumElts += getTargetData()->getTypeAllocSize(ArgTy) / 8; + } + Info.memVT = EVT::getVectorVT(I.getType()->getContext(), MVT::i64, NumElts); + Info.ptrVal = I.getArgOperand(0); + Info.offset = 0; + Value *AlignArg = I.getArgOperand(I.getNumArgOperands() - 1); + Info.align = cast(AlignArg)->getZExtValue(); + Info.vol = false; // volatile stores with NEON intrinsics not supported + Info.readMem = false; + Info.writeMem = true; + return true; + } + default: + break; + } + + return false; +} diff --git a/lib/Target/ARM/ARMISelLowering.h b/lib/Target/ARM/ARMISelLowering.h index ba9ea7f15e7b..dc400c485ec6 100644 --- a/lib/Target/ARM/ARMISelLowering.h +++ b/lib/Target/ARM/ARMISelLowering.h @@ -34,6 +34,10 @@ namespace llvm { Wrapper, // Wrapper - A wrapper node for TargetConstantPool, // TargetExternalSymbol, and TargetGlobalAddress. + WrapperDYN, // WrapperDYN - A wrapper node for TargetGlobalAddress in + // DYN mode. + WrapperPIC, // WrapperPIC - A wrapper node for TargetGlobalAddress in + // PIC mode. WrapperJT, // WrapperJT - A wrapper node for TargetJumpTable CALL, // Function call. @@ -47,8 +51,6 @@ namespace llvm { PIC_ADD, // Add with a PC operand and a PIC label. - AND, // ARM "and" instruction that sets the 's' flag in CPSR. - CMP, // ARM compare instructions. CMPZ, // ARM compare that sets only Z flag. CMPFP, // ARM VFP compare instruction, sets FPSCR. @@ -73,8 +75,9 @@ namespace llvm { VMOVRRD, // double to two gprs. VMOVDRR, // Two gprs to double. - EH_SJLJ_SETJMP, // SjLj exception handling setjmp. - EH_SJLJ_LONGJMP, // SjLj exception handling longjmp. + EH_SJLJ_SETJMP, // SjLj exception handling setjmp. + EH_SJLJ_LONGJMP, // SjLj exception handling longjmp. + EH_SJLJ_DISPATCHSETUP, // SjLj exception handling dispatch setup. TC_RETURN, // Tail call return pseudo. @@ -82,13 +85,20 @@ namespace llvm { DYN_ALLOC, // Dynamic allocation on the stack. - MEMBARRIER, // Memory barrier - SYNCBARRIER, // Memory sync barrier + MEMBARRIER, // Memory barrier (DMB) + MEMBARRIER_MCR, // Memory barrier (MCR) + + PRELOAD, // Preload VCEQ, // Vector compare equal. + VCEQZ, // Vector compare equal to zero. VCGE, // Vector compare greater than or equal. + VCGEZ, // Vector compare greater than or equal to zero. + VCLEZ, // Vector compare less than or equal to zero. VCGEU, // Vector compare unsigned greater than or equal. VCGT, // Vector compare greater than. + VCGTZ, // Vector compare greater than zero. + VCLTZ, // Vector compare less than zero. VCGTU, // Vector compare unsigned greater than. VTST, // Vector test bits. @@ -161,7 +171,38 @@ namespace llvm { FMIN, // Bit-field insert - BFI + BFI, + + // Vector OR with immediate + VORRIMM, + // Vector AND with NOT of immediate + VBICIMM, + + // Vector load N-element structure to all lanes: + VLD2DUP = ISD::FIRST_TARGET_MEMORY_OPCODE, + VLD3DUP, + VLD4DUP, + + // NEON loads with post-increment base updates: + VLD1_UPD, + VLD2_UPD, + VLD3_UPD, + VLD4_UPD, + VLD2LN_UPD, + VLD3LN_UPD, + VLD4LN_UPD, + VLD2DUP_UPD, + VLD3DUP_UPD, + VLD4DUP_UPD, + + // NEON stores with post-increment base updates: + VST1_UPD, + VST2_UPD, + VST3_UPD, + VST4_UPD, + VST2LN_UPD, + VST3LN_UPD, + VST4LN_UPD }; } @@ -193,14 +234,16 @@ namespace llvm { virtual void ReplaceNodeResults(SDNode *N, SmallVectorImpl&Results, SelectionDAG &DAG) const; - virtual SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const; - virtual const char *getTargetNodeName(unsigned Opcode) const; virtual MachineBasicBlock * EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *MBB) const; + virtual SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const; + + bool isDesirableToTransformToIntegerOp(unsigned Opc, EVT VT) const; + /// allowsUnalignedMemoryAccesses - Returns true if the target allows /// unaligned memory accesses. of the specified type. /// FIXME: Add getOptimalMemOpType to implement memcpy with NEON? @@ -241,7 +284,15 @@ namespace llvm { unsigned Depth) const; + virtual bool ExpandInlineAsm(CallInst *CI) const; + ConstraintType getConstraintType(const std::string &Constraint) const; + + /// Examine constraint string and operand type and determine a weight value. + /// The operand object must already have been set up with the operand type. + ConstraintWeight getSingleConstraintMatchWeight( + AsmOperandInfo &info, const char *constraint) const; + std::pair getRegForInlineAsmConstraint(const std::string &Constraint, EVT VT) const; @@ -290,6 +341,9 @@ namespace llvm { /// materialize the FP immediate as a load from a constant pool. virtual bool isFPImmLegal(const APFloat &Imm, EVT VT) const; + virtual bool getTgtMemIntrinsic(IntrinsicInfo &Info, + const CallInst &I, + unsigned Intrinsic) const; protected: std::pair findRepresentativeClass(EVT VT) const; @@ -301,6 +355,8 @@ namespace llvm { const TargetRegisterInfo *RegInfo; + const InstrItineraryData *Itins; + /// ARMPCLabelIndex - Keep track of the number of ARM PC labels created. /// unsigned ARMPCLabelIndex; @@ -329,6 +385,7 @@ namespace llvm { ISD::ArgFlagsTy Flags) const; SDValue LowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const; SDValue LowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerEH_SJLJ_DISPATCHSETUP(SDValue Op, SelectionDAG &DAG) const; SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG, const ARMSubtarget *Subtarget) const; SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; @@ -350,6 +407,10 @@ namespace llvm { SDValue LowerShiftRightParts(SDValue Op, SelectionDAG &DAG) const; SDValue LowerShiftLeftParts(SDValue Op, SelectionDAG &DAG) const; SDValue LowerFLT_ROUNDS_(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG, + const ARMSubtarget *ST) const; + + SDValue ReconstructShuffle(SDValue Op, SelectionDAG &DAG) const; SDValue LowerCallResult(SDValue Chain, SDValue InFlag, CallingConv::ID CallConv, bool isVarArg, @@ -393,6 +454,8 @@ namespace llvm { const SmallVectorImpl &OutVals, DebugLoc dl, SelectionDAG &DAG) const; + virtual bool isUsedByReturnOnly(SDNode *N) const; + SDValue getARMCmp(SDValue LHS, SDValue RHS, ISD::CondCode CC, SDValue &ARMcc, SelectionDAG &DAG, DebugLoc dl) const; SDValue getVFPCmp(SDValue LHS, SDValue RHS, @@ -410,6 +473,13 @@ namespace llvm { }; + enum NEONModImmType { + VMOVModImm, + VMVNModImm, + OtherModImm + }; + + namespace ARM { FastISel *createFastISel(FunctionLoweringInfo &funcInfo); } diff --git a/lib/Target/ARM/ARMInstrFormats.td b/lib/Target/ARM/ARMInstrFormats.td index 113cfffe61f9..765cba42d0bd 100644 --- a/lib/Target/ARM/ARMInstrFormats.td +++ b/lib/Target/ARM/ARMInstrFormats.td @@ -1,4 +1,4 @@ -//===- ARMInstrFormats.td - ARM Instruction Formats --*- tablegen -*---------=// +//===- ARMInstrFormats.td - ARM Instruction Formats ----------*- tablegen -*-=// // // The LLVM Compiler Infrastructure // @@ -71,7 +71,7 @@ def NVTBLFrm : Format<41>; // Misc flags. -// the instruction has a Rn register operand. +// The instruction has an Rn register operand. // UnaryDP - Indicates this is a unary data processing instruction, i.e. // it doesn't have a Rn operand. class UnaryDP { bit isUnaryDataProc = 1; } @@ -84,9 +84,10 @@ class Xform16Bit { bit canXformTo16Bit = 1; } // ARM Instruction flags. These need to match ARMBaseInstrInfo.h. // +// FIXME: Once the JIT is MC-ized, these can go away. // Addressing mode. -class AddrMode val> { - bits<4> Value = val; +class AddrMode val> { + bits<5> Value = val; } def AddrModeNone : AddrMode<0>; def AddrMode1 : AddrMode<1>; @@ -104,6 +105,7 @@ def AddrModeT2_i8 : AddrMode<12>; def AddrModeT2_so : AddrMode<13>; def AddrModeT2_pc : AddrMode<14>; def AddrModeT2_i8s4 : AddrMode<15>; +def AddrMode_i12 : AddrMode<16>; // Instruction size. class SizeFlagVal val> { @@ -134,7 +136,6 @@ def NeonDomain : Domain<2>; // Instructions in Neon domain only def VFPNeonDomain : Domain<3>; // Instructions in both VFP & Neon domains //===----------------------------------------------------------------------===// - // ARM special operands. // @@ -143,6 +144,39 @@ def CondCodeOperand : AsmOperandClass { let SuperClasses = []; } +def CCOutOperand : AsmOperandClass { + let Name = "CCOut"; + let SuperClasses = []; +} + +def MemBarrierOptOperand : AsmOperandClass { + let Name = "MemBarrierOpt"; + let SuperClasses = []; + let ParserMethod = "tryParseMemBarrierOptOperand"; +} + +def ProcIFlagsOperand : AsmOperandClass { + let Name = "ProcIFlags"; + let SuperClasses = []; + let ParserMethod = "tryParseProcIFlagsOperand"; +} + +def MSRMaskOperand : AsmOperandClass { + let Name = "MSRMask"; + let SuperClasses = []; + let ParserMethod = "tryParseMSRMaskOperand"; +} + +// ARM imod and iflag operands, used only by the CPS instruction. +def imod_op : Operand { + let PrintMethod = "printCPSIMod"; +} + +def iflags_op : Operand { + let PrintMethod = "printCPSIFlag"; + let ParserMatchClass = ProcIFlagsOperand; +} + // ARM Predicate operand. Default to 14 = always (AL). Second part is CC // register whose default is 0 (no register). def pred : PredicateOperand { + let EncoderMethod = "getCCOutOpValue"; let PrintMethod = "printSBitModifierOperand"; + let ParserMatchClass = CCOutOperand; } // Same as cc_out except it defaults to setting CPSR. def s_cc_out : OptionalDefOperand { + let EncoderMethod = "getCCOutOpValue"; let PrintMethod = "printSBitModifierOperand"; + let ParserMatchClass = CCOutOperand; } // ARM special operands for disassembly only. // +def setend_op : Operand { + let PrintMethod = "printSetendOperand"; +} def cps_opt : Operand { let PrintMethod = "printCPSOptionOperand"; @@ -170,6 +211,7 @@ def cps_opt : Operand { def msr_mask : Operand { let PrintMethod = "printMSRMaskOperand"; + let ParserMatchClass = MSRMaskOperand; } // A8.6.117, A8.6.118. Different instructions are generated for #0 and #-0. @@ -179,7 +221,6 @@ def neg_zero : Operand { } //===----------------------------------------------------------------------===// - // ARM Instruction templates. // @@ -198,14 +239,17 @@ class InstTemplate(f), "Pseudo"); + // The layout of TSFlags should be kept in sync with ARMBaseInstrInfo.h. - let TSFlags{3-0} = AM.Value; - let TSFlags{6-4} = SZ.Value; - let TSFlags{8-7} = IndexModeBits; - let TSFlags{14-9} = Form; - let TSFlags{15} = isUnaryDataProc; - let TSFlags{16} = canXformTo16Bit; - let TSFlags{18-17} = D.Value; + let TSFlags{4-0} = AM.Value; + let TSFlags{7-5} = SZ.Value; + let TSFlags{9-8} = IndexModeBits; + let TSFlags{15-10} = Form; + let TSFlags{16} = isUnaryDataProc; + let TSFlags{17} = canXformTo16Bit; + let TSFlags{19-18} = D.Value; let Constraints = cstr; let Itinerary = itin; @@ -225,25 +269,51 @@ class InstThumb : InstTemplate; -class PseudoInst pattern> +class PseudoInst pattern> + // FIXME: This really should derive from InstTemplate instead, as pseudos + // don't need encoding information. TableGen doesn't like that + // currently. Need to figure out why and fix it. : InstARM { let OutOperandList = oops; let InOperandList = iops; - let AsmString = asm; let Pattern = pattern; } +// PseudoInst that's ARM-mode only. +class ARMPseudoInst pattern> + : PseudoInst { + let SZ = sz; + list Predicates = [IsARM]; +} + +// PseudoInst that's Thumb-mode only. +class tPseudoInst pattern> + : PseudoInst { + let SZ = sz; + list Predicates = [IsThumb]; +} + +// PseudoInst that's Thumb2-mode only. +class t2PseudoInst pattern> + : PseudoInst { + let SZ = sz; + list Predicates = [IsThumb2]; +} // Almost all ARM instructions are predicable. class I pattern> : InstARM { + bits<4> p; + let Inst{31-28} = p; let OutOperandList = oops; let InOperandList = !con(iops, (ins pred:$p)); - let AsmString = !strconcat(opc, !strconcat("${p}", asm)); + let AsmString = !strconcat(opc, "${p}", asm); let Pattern = pattern; list Predicates = [IsARM]; } @@ -270,9 +340,14 @@ class sI pattern> : InstARM { + bits<4> p; // Predicate operand + bits<1> s; // condition-code set flag ('1' if the insn should set the flags) + let Inst{31-28} = p; + let Inst{20} = s; + let OutOperandList = oops; let InOperandList = !con(iops, (ins pred:$p, cc_out:$s)); - let AsmString = !strconcat(opc, !strconcat("${p}${s}", asm)); + let AsmString = !strconcat(opc, "${s}${p}", asm); let Pattern = pattern; list Predicates = [IsARM]; } @@ -319,10 +394,6 @@ class ABXI opcod, dag oops, dag iops, InstrItinClass itin, asm, "", pattern> { let Inst{27-24} = opcod; } -class ABXIx2 pattern> - : XI; // BR_JT instructions class JTI opcod, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : I { + bits<4> Rt; + bits<4> Rn; let Inst{27-23} = 0b00011; let Inst{22-21} = opcod; let Inst{20} = 1; + let Inst{19-16} = Rn; + let Inst{15-12} = Rt; let Inst{11-0} = 0b111110011111; } class AIstrex opcod, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : I { + bits<4> Rd; + bits<4> Rt; + bits<4> Rn; let Inst{27-23} = 0b00011; let Inst{22-21} = opcod; let Inst{20} = 0; + let Inst{19-16} = Rn; + let Inst{15-12} = Rd; let Inst{11-4} = 0b11111001; + let Inst{3-0} = Rt; +} +class AIswp pattern> + : AI { + bits<4> Rt; + bits<4> Rt2; + bits<4> Rn; + let Inst{27-23} = 0b00010; + let Inst{22} = b; + let Inst{21-20} = 0b00; + let Inst{19-16} = Rn; + let Inst{15-12} = Rt; + let Inst{11-4} = 0b00001001; + let Inst{3-0} = Rt2; } // addrmode1 instructions @@ -372,387 +466,125 @@ class AXI1 opcod, dag oops, dag iops, Format f, InstrItinClass itin, let Inst{24-21} = opcod; let Inst{27-26} = 0b00; } -class AI1x2 pattern> - : I; - - -// addrmode2 loads and stores -class AI2 pattern> - : I { - let Inst{27-26} = 0b01; -} // loads -class AI2ldw pattern> - : I { - let Inst{20} = 1; // L bit - let Inst{21} = 0; // W bit - let Inst{22} = 0; // B bit - let Inst{24} = 1; // P bit - let Inst{27-26} = 0b01; -} -class AXI2ldw pattern> - : XI { - let Inst{20} = 1; // L bit - let Inst{21} = 0; // W bit - let Inst{22} = 0; // B bit - let Inst{24} = 1; // P bit - let Inst{27-26} = 0b01; -} -class AI2ldb pattern> - : I { - let Inst{20} = 1; // L bit - let Inst{21} = 0; // W bit - let Inst{22} = 1; // B bit - let Inst{24} = 1; // P bit - let Inst{27-26} = 0b01; -} -class AXI2ldb pattern> - : XI { - let Inst{20} = 1; // L bit - let Inst{21} = 0; // W bit - let Inst{22} = 1; // B bit - let Inst{24} = 1; // P bit - let Inst{27-26} = 0b01; -} - -// stores -class AI2stw pattern> - : I { - let Inst{20} = 0; // L bit - let Inst{21} = 0; // W bit - let Inst{22} = 0; // B bit - let Inst{24} = 1; // P bit - let Inst{27-26} = 0b01; -} -class AXI2stw pattern> - : XI { - let Inst{20} = 0; // L bit - let Inst{21} = 0; // W bit - let Inst{22} = 0; // B bit - let Inst{24} = 1; // P bit - let Inst{27-26} = 0b01; -} -class AI2stb pattern> - : I { - let Inst{20} = 0; // L bit - let Inst{21} = 0; // W bit - let Inst{22} = 1; // B bit - let Inst{24} = 1; // P bit - let Inst{27-26} = 0b01; -} -class AXI2stb pattern> - : XI { - let Inst{20} = 0; // L bit - let Inst{21} = 0; // W bit - let Inst{22} = 1; // B bit - let Inst{24} = 1; // P bit - let Inst{27-26} = 0b01; -} -// Pre-indexed loads -class AI2ldwpr pattern> - : I { - let Inst{20} = 1; // L bit - let Inst{21} = 1; // W bit - let Inst{22} = 0; // B bit - let Inst{24} = 1; // P bit - let Inst{27-26} = 0b01; -} -class AI2ldbpr pattern> - : I { - let Inst{20} = 1; // L bit - let Inst{21} = 1; // W bit - let Inst{22} = 1; // B bit - let Inst{24} = 1; // P bit - let Inst{27-26} = 0b01; -} - -// Pre-indexed stores -class AI2stwpr pattern> - : I { - let Inst{20} = 0; // L bit - let Inst{21} = 1; // W bit - let Inst{22} = 0; // B bit - let Inst{24} = 1; // P bit - let Inst{27-26} = 0b01; -} -class AI2stbpr pattern> - : I op, bit isLd, bit isByte, dag oops, dag iops, AddrMode am, + Format f, InstrItinClass itin, string opc, string asm, + list pattern> + : I { + let Inst{27-25} = op; + let Inst{24} = 1; // 24 == P + // 23 == U + let Inst{22} = isByte; + let Inst{21} = 0; // 21 == W + let Inst{20} = isLd; +} +// Indexed load/stores +class AI2ldstidx pattern> + : I { - let Inst{20} = 0; // L bit - let Inst{21} = 1; // W bit - let Inst{22} = 1; // B bit - let Inst{24} = 1; // P bit - let Inst{27-26} = 0b01; -} - -// Post-indexed loads -class AI2ldwpo pattern> - : I { - let Inst{20} = 1; // L bit - let Inst{21} = 0; // W bit - let Inst{22} = 0; // B bit - let Inst{24} = 0; // P bit - let Inst{27-26} = 0b01; -} -class AI2ldbpo pattern> - : I { - let Inst{20} = 1; // L bit - let Inst{21} = 0; // W bit - let Inst{22} = 1; // B bit - let Inst{24} = 0; // P bit - let Inst{27-26} = 0b01; -} - -// Post-indexed stores -class AI2stwpo pattern> - : I { - let Inst{20} = 0; // L bit - let Inst{21} = 0; // W bit - let Inst{22} = 0; // B bit - let Inst{24} = 0; // P bit - let Inst{27-26} = 0b01; -} -class AI2stbpo pattern> - : I { - let Inst{20} = 0; // L bit - let Inst{21} = 0; // W bit - let Inst{22} = 1; // B bit - let Inst{24} = 0; // P bit + bits<4> Rt; let Inst{27-26} = 0b01; + let Inst{24} = isPre; // P bit + let Inst{22} = isByte; // B bit + let Inst{21} = isPre; // W bit + let Inst{20} = isLd; // L bit + let Inst{15-12} = Rt; +} +class AI2stridx pattern> + : AI2ldstidx<0, isByte, isPre, oops, iops, im, f, itin, opc, asm, cstr, + pattern> { + // AM2 store w/ two operands: (GPR, am2offset) + // {13} 1 == Rm, 0 == imm12 + // {12} isAdd + // {11-0} imm12/Rm + bits<14> offset; + bits<4> Rn; + let Inst{25} = offset{13}; + let Inst{23} = offset{12}; + let Inst{19-16} = Rn; + let Inst{11-0} = offset{11-0}; } // addrmode3 instructions -class AI3 pattern> - : I; -class AXI3 pattern> - : XI; - -// loads -class AI3ldh pattern> - : I { - let Inst{4} = 1; - let Inst{5} = 1; // H bit - let Inst{6} = 0; // S bit - let Inst{7} = 1; - let Inst{20} = 1; // L bit - let Inst{21} = 0; // W bit - let Inst{24} = 1; // P bit - let Inst{27-25} = 0b000; -} -class AXI3ldh pattern> - : XI { - let Inst{4} = 1; - let Inst{5} = 1; // H bit - let Inst{6} = 0; // S bit - let Inst{7} = 1; - let Inst{20} = 1; // L bit - let Inst{21} = 0; // W bit - let Inst{24} = 1; // P bit -} -class AI3ldsh pattern> +class AI3ld op, bit op20, dag oops, dag iops, Format f, + InstrItinClass itin, string opc, string asm, list pattern> : I { - let Inst{4} = 1; - let Inst{5} = 1; // H bit - let Inst{6} = 1; // S bit - let Inst{7} = 1; - let Inst{20} = 1; // L bit - let Inst{21} = 0; // W bit - let Inst{24} = 1; // P bit + bits<14> addr; + bits<4> Rt; let Inst{27-25} = 0b000; -} -class AXI3ldsh pattern> - : XI { - let Inst{4} = 1; - let Inst{5} = 1; // H bit - let Inst{6} = 1; // S bit - let Inst{7} = 1; - let Inst{20} = 1; // L bit - let Inst{21} = 0; // W bit - let Inst{24} = 1; // P bit -} -class AI3ldsb pattern> - : I { - let Inst{4} = 1; - let Inst{5} = 0; // H bit - let Inst{6} = 1; // S bit - let Inst{7} = 1; - let Inst{20} = 1; // L bit - let Inst{21} = 0; // W bit - let Inst{24} = 1; // P bit + let Inst{24} = 1; // P bit + let Inst{23} = addr{8}; // U bit + let Inst{22} = addr{13}; // 1 == imm8, 0 == Rm + let Inst{21} = 0; // W bit + let Inst{20} = op20; // L bit + let Inst{19-16} = addr{12-9}; // Rn + let Inst{15-12} = Rt; // Rt + let Inst{11-8} = addr{7-4}; // imm7_4/zero + let Inst{7-4} = op; + let Inst{3-0} = addr{3-0}; // imm3_0/Rm +} + +class AI3ldstidx op, bit op20, bit isLd, bit isPre, dag oops, dag iops, + IndexMode im, Format f, InstrItinClass itin, string opc, + string asm, string cstr, list pattern> + : I { + bits<4> Rt; let Inst{27-25} = 0b000; -} -class AXI3ldsb pattern> - : XI { - let Inst{4} = 1; - let Inst{5} = 0; // H bit - let Inst{6} = 1; // S bit - let Inst{7} = 1; - let Inst{20} = 1; // L bit - let Inst{21} = 0; // W bit - let Inst{24} = 1; // P bit -} -class AI3ldd pattern> - : I { - let Inst{4} = 1; - let Inst{5} = 0; // H bit - let Inst{6} = 1; // S bit - let Inst{7} = 1; - let Inst{20} = 0; // L bit - let Inst{21} = 0; // W bit - let Inst{24} = 1; // P bit + let Inst{24} = isPre; // P bit + let Inst{21} = isPre; // W bit + let Inst{20} = op20; // L bit + let Inst{15-12} = Rt; // Rt + let Inst{7-4} = op; +} +class AI3stridx op, bit isByte, bit isPre, dag oops, dag iops, + IndexMode im, Format f, InstrItinClass itin, string opc, + string asm, string cstr, list pattern> + : AI2ldstidx<0, isByte, isPre, oops, iops, im, f, itin, opc, asm, cstr, + pattern> { + // AM3 store w/ two operands: (GPR, am3offset) + bits<14> offset; + bits<4> Rt; + bits<4> Rn; let Inst{27-25} = 0b000; + let Inst{23} = offset{8}; + let Inst{22} = offset{9}; + let Inst{19-16} = Rn; + let Inst{15-12} = Rt; // Rt + let Inst{11-8} = offset{7-4}; // imm7_4/zero + let Inst{7-4} = op; + let Inst{3-0} = offset{3-0}; // imm3_0/Rm } // stores -class AI3sth op, dag oops, dag iops, Format f, InstrItinClass itin, string opc, string asm, list pattern> : I { - let Inst{4} = 1; - let Inst{5} = 1; // H bit - let Inst{6} = 0; // S bit - let Inst{7} = 1; - let Inst{20} = 0; // L bit - let Inst{21} = 0; // W bit - let Inst{24} = 1; // P bit - let Inst{27-25} = 0b000; -} -class AXI3sth pattern> - : XI { - let Inst{4} = 1; - let Inst{5} = 1; // H bit - let Inst{6} = 0; // S bit - let Inst{7} = 1; - let Inst{20} = 0; // L bit - let Inst{21} = 0; // W bit - let Inst{24} = 1; // P bit -} -class AI3std pattern> - : I { - let Inst{4} = 1; - let Inst{5} = 1; // H bit - let Inst{6} = 1; // S bit - let Inst{7} = 1; - let Inst{20} = 0; // L bit - let Inst{21} = 0; // W bit - let Inst{24} = 1; // P bit + bits<14> addr; + bits<4> Rt; let Inst{27-25} = 0b000; + let Inst{24} = 1; // P bit + let Inst{23} = addr{8}; // U bit + let Inst{22} = addr{13}; // 1 == imm8, 0 == Rm + let Inst{21} = 0; // W bit + let Inst{20} = 0; // L bit + let Inst{19-16} = addr{12-9}; // Rn + let Inst{15-12} = Rt; // Rt + let Inst{11-8} = addr{7-4}; // imm7_4/zero + let Inst{7-4} = op; + let Inst{3-0} = addr{3-0}; // imm3_0/Rm } -// Pre-indexed loads -class AI3ldhpr pattern> - : I { - let Inst{4} = 1; - let Inst{5} = 1; // H bit - let Inst{6} = 0; // S bit - let Inst{7} = 1; - let Inst{20} = 1; // L bit - let Inst{21} = 1; // W bit - let Inst{24} = 1; // P bit - let Inst{27-25} = 0b000; -} -class AI3ldshpr pattern> - : I { - let Inst{4} = 1; - let Inst{5} = 1; // H bit - let Inst{6} = 1; // S bit - let Inst{7} = 1; - let Inst{20} = 1; // L bit - let Inst{21} = 1; // W bit - let Inst{24} = 1; // P bit - let Inst{27-25} = 0b000; -} -class AI3ldsbpr pattern> - : I { - let Inst{4} = 1; - let Inst{5} = 0; // H bit - let Inst{6} = 1; // S bit - let Inst{7} = 1; - let Inst{20} = 1; // L bit - let Inst{21} = 1; // W bit - let Inst{24} = 1; // P bit - let Inst{27-25} = 0b000; -} -class AI3lddpr pattern> - : I { - let Inst{4} = 1; - let Inst{5} = 0; // H bit - let Inst{6} = 1; // S bit - let Inst{7} = 1; - let Inst{20} = 0; // L bit - let Inst{21} = 1; // W bit - let Inst{24} = 1; // P bit - let Inst{27-25} = 0b000; -} - - // Pre-indexed stores class AI3sthpr pattern> @@ -781,60 +613,6 @@ class AI3stdpr pattern> - : I { - let Inst{4} = 1; - let Inst{5} = 1; // H bit - let Inst{6} = 0; // S bit - let Inst{7} = 1; - let Inst{20} = 1; // L bit - let Inst{21} = 0; // W bit - let Inst{24} = 0; // P bit - let Inst{27-25} = 0b000; -} -class AI3ldshpo pattern> - : I { - let Inst{4} = 1; - let Inst{5} = 1; // H bit - let Inst{6} = 1; // S bit - let Inst{7} = 1; - let Inst{20} = 1; // L bit - let Inst{21} = 0; // W bit - let Inst{24} = 0; // P bit - let Inst{27-25} = 0b000; -} -class AI3ldsbpo pattern> - : I { - let Inst{4} = 1; - let Inst{5} = 0; // H bit - let Inst{6} = 1; // S bit - let Inst{7} = 1; - let Inst{20} = 1; // L bit - let Inst{21} = 0; // W bit - let Inst{24} = 0; // P bit - let Inst{27-25} = 0b000; -} -class AI3lddpo pattern> - : I { - let Inst{4} = 1; - let Inst{5} = 0; // H bit - let Inst{6} = 1; // S bit - let Inst{7} = 1; - let Inst{20} = 0; // L bit - let Inst{21} = 0; // W bit - let Inst{24} = 0; // P bit - let Inst{27-25} = 0b000; -} - // Post-indexed stores class AI3sthpo pattern> @@ -864,21 +642,17 @@ class AI3stdpo pattern> - : XI { - let Inst{20} = 1; // L bit - let Inst{22} = 0; // S bit +class AXI4 pattern> + : XI { + bits<4> p; + bits<16> regs; + bits<4> Rn; + let Inst{31-28} = p; let Inst{27-25} = 0b100; -} -class AXI4st pattern> - : XI { - let Inst{20} = 0; // L bit let Inst{22} = 0; // S bit - let Inst{27-25} = 0b100; + let Inst{19-16} = Rn; + let Inst{15-0} = regs; } // Unsigned multiply, multiply-accumulate instructions. @@ -899,24 +673,65 @@ class AsMul1I opcod, dag oops, dag iops, InstrItinClass itin, } // Most significant word multiply -class AMul2I opcod, dag oops, dag iops, InstrItinClass itin, - string opc, string asm, list pattern> +class AMul2I opcod, bits<4> opc7_4, dag oops, dag iops, + InstrItinClass itin, string opc, string asm, list pattern> : I { - let Inst{7-4} = 0b1001; + bits<4> Rd; + bits<4> Rn; + bits<4> Rm; + let Inst{7-4} = opc7_4; let Inst{20} = 1; let Inst{27-21} = opcod; + let Inst{19-16} = Rd; + let Inst{11-8} = Rm; + let Inst{3-0} = Rn; +} +// MSW multiple w/ Ra operand +class AMul2Ia opcod, bits<4> opc7_4, dag oops, dag iops, + InstrItinClass itin, string opc, string asm, list pattern> + : AMul2I { + bits<4> Ra; + let Inst{15-12} = Ra; } // SMUL / SMULW / SMLA / SMLAW -class AMulxyI opcod, dag oops, dag iops, InstrItinClass itin, - string opc, string asm, list pattern> +class AMulxyIbase opcod, bits<2> bit6_5, dag oops, dag iops, + InstrItinClass itin, string opc, string asm, list pattern> : I { + bits<4> Rn; + bits<4> Rm; let Inst{4} = 0; let Inst{7} = 1; let Inst{20} = 0; let Inst{27-21} = opcod; + let Inst{6-5} = bit6_5; + let Inst{11-8} = Rm; + let Inst{3-0} = Rn; +} +class AMulxyI opcod, bits<2> bit6_5, dag oops, dag iops, + InstrItinClass itin, string opc, string asm, list pattern> + : AMulxyIbase { + bits<4> Rd; + let Inst{19-16} = Rd; +} + +// AMulxyI with Ra operand +class AMulxyIa opcod, bits<2> bit6_5, dag oops, dag iops, + InstrItinClass itin, string opc, string asm, list pattern> + : AMulxyI { + bits<4> Ra; + let Inst{15-12} = Ra; +} +// SMLAL* +class AMulxyI64 opcod, bits<2> bit6_5, dag oops, dag iops, + InstrItinClass itin, string opc, string asm, list pattern> + : AMulxyIbase { + bits<4> RdLo; + bits<4> RdHi; + let Inst{19-16} = RdHi; + let Inst{15-12} = RdLo; } // Extend instructions. @@ -924,16 +739,47 @@ class AExtI opcod, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : I { + // All AExtI instructions have Rd and Rm register operands. + bits<4> Rd; + bits<4> Rm; + let Inst{15-12} = Rd; + let Inst{3-0} = Rm; let Inst{7-4} = 0b0111; + let Inst{9-8} = 0b00; let Inst{27-20} = opcod; } // Misc Arithmetic instructions. -class AMiscA1I opcod, dag oops, dag iops, InstrItinClass itin, - string opc, string asm, list pattern> +class AMiscA1I opcod, bits<4> opc7_4, dag oops, dag iops, + InstrItinClass itin, string opc, string asm, list pattern> : I { + bits<4> Rd; + bits<4> Rm; let Inst{27-20} = opcod; + let Inst{19-16} = 0b1111; + let Inst{15-12} = Rd; + let Inst{11-8} = 0b1111; + let Inst{7-4} = opc7_4; + let Inst{3-0} = Rm; +} + +// PKH instructions +class APKHI opcod, bit tb, dag oops, dag iops, InstrItinClass itin, + string opc, string asm, list pattern> + : I { + bits<4> Rd; + bits<4> Rn; + bits<4> Rm; + bits<8> sh; + let Inst{27-20} = opcod; + let Inst{19-16} = Rn; + let Inst{15-12} = Rd; + let Inst{11-7} = sh{7-3}; + let Inst{6} = tb; + let Inst{5-4} = 0b01; + let Inst{3-0} = Rm; } //===----------------------------------------------------------------------===// @@ -950,12 +796,9 @@ class ARMV6Pat : Pat { } //===----------------------------------------------------------------------===// -// // Thumb Instruction Format Definitions. // -// TI - Thumb instruction. - class ThumbI pattern> : InstThumb { @@ -966,6 +809,7 @@ class ThumbI Predicates = [IsThumb]; } +// TI - Thumb instruction. class TI pattern> : ThumbI; @@ -986,6 +830,13 @@ class TIx2 opcod1, bits<2> opcod2, bit opcod3, let Inst{12} = opcod3; } +// Move to/from coprocessor instructions +class T1Cop pattern> + : ThumbI, + Encoding, Requires<[IsThumb, HasV6]> { + let Inst{31-28} = 0b1110; +} + // BR_JT instructions class TJTI pattern> @@ -999,7 +850,7 @@ class Thumb1I Predicates = [IsThumb1Only]; + list Predicates = [IsThumb, IsThumb1Only]; } class T1I pattern> : Thumb1I; -class T1JTI pattern> - : Thumb1I; // Two-address instructions class T1It { let OutOperandList = !con(oops, (outs s_cc_out:$s)); let InOperandList = !con(iops, (ins pred:$p)); - let AsmString = !strconcat(opc, !strconcat("${s}${p}", asm)); + let AsmString = !strconcat(opc, "${s}${p}", asm); let Pattern = pattern; - list Predicates = [IsThumb1Only]; + list Predicates = [IsThumb, IsThumb1Only]; } class T1sI pattern> : Thumb1sI; + "$Rn = $Rdn", pattern>; // Thumb1 instruction that can be predicated. class Thumb1pI { let OutOperandList = oops; let InOperandList = !con(iops, (ins pred:$p)); - let AsmString = !strconcat(opc, !strconcat("${p}", asm)); + let AsmString = !strconcat(opc, "${p}", asm); let Pattern = pattern; - list Predicates = [IsThumb1Only]; + list Predicates = [IsThumb, IsThumb1Only]; } class T1pI pattern> : Thumb1pI; + "$Rn = $Rdn", pattern>; -class T1pI1 pattern> - : Thumb1pI; -class T1pI2 pattern> - : Thumb1pI; -class T1pI4 pattern> - : Thumb1pI; class T1pIs pattern> : Thumb1pI; @@ -1099,7 +938,7 @@ class T1DataProcessing opcode> : Encoding16 { // A6.2.3 Special data instructions and branch and exchange encoding. class T1Special opcode> : Encoding16 { let Inst{15-10} = 0b010001; - let Inst{9-6} = opcode; + let Inst{9-6} = opcode; } // A6.2.4 Load/store single data item encoding. @@ -1107,12 +946,37 @@ class T1LoadStore opA, bits<3> opB> : Encoding16 { let Inst{15-12} = opA; let Inst{11-9} = opB; } -class T1LdSt opB> : T1LoadStore<0b0101, opB>; -class T1LdSt4Imm opB> : T1LoadStore<0b0110, opB>; // Immediate, 4 bytes -class T1LdSt1Imm opB> : T1LoadStore<0b0111, opB>; // Immediate, 1 byte -class T1LdSt2Imm opB> : T1LoadStore<0b1000, opB>; // Immediate, 2 bytes class T1LdStSP opB> : T1LoadStore<0b1001, opB>; // SP relative +// Helper classes to encode Thumb1 loads and stores. For immediates, the +// following bits are used for "opA" (see A6.2.4): +// +// 0b0110 => Immediate, 4 bytes +// 0b1000 => Immediate, 2 bytes +// 0b0111 => Immediate, 1 byte +class T1pILdStEncode opcode, dag oops, dag iops, AddrMode am, + InstrItinClass itin, string opc, string asm, + list pattern> + : Thumb1pI, + T1LoadStore<0b0101, opcode> { + bits<3> Rt; + bits<8> addr; + let Inst{8-6} = addr{5-3}; // Rm + let Inst{5-3} = addr{2-0}; // Rn + let Inst{2-0} = Rt; +} +class T1pILdStEncodeImm opA, bit opB, dag oops, dag iops, AddrMode am, + InstrItinClass itin, string opc, string asm, + list pattern> + : Thumb1pI, + T1LoadStore { + bits<3> Rt; + bits<8> addr; + let Inst{10-6} = addr{7-3}; // imm5 + let Inst{5-3} = addr{2-0}; // Rn + let Inst{2-0} = Rt; +} + // A6.2.5 Miscellaneous 16-bit instructions encoding. class T1Misc opcode> : Encoding16 { let Inst{15-12} = 0b1011; @@ -1126,7 +990,7 @@ class Thumb2I { let OutOperandList = oops; let InOperandList = !con(iops, (ins pred:$p)); - let AsmString = !strconcat(opc, !strconcat("${p}", asm)); + let AsmString = !strconcat(opc, "${p}", asm); let Pattern = pattern; list Predicates = [IsThumb2]; } @@ -1134,16 +998,19 @@ class Thumb2I pattern> : InstARM { + bits<1> s; // condition-code set flag ('1' if the insn should set the flags) + let Inst{20} = s; + let OutOperandList = oops; let InOperandList = !con(iops, (ins pred:$p, cc_out:$s)); - let AsmString = !strconcat(opc, !strconcat("${s}${p}", asm)); + let AsmString = !strconcat(opc, "${s}${p}", asm); let Pattern = pattern; list Predicates = [IsThumb2]; } @@ -1168,7 +1035,7 @@ class ThumbXI Predicates = [IsThumb1Only]; + list Predicates = [IsThumb, IsThumb1Only]; } class T2I pattern> : Thumb2I; -class T2Ii8s4 pattern> : Thumb2I { - let Inst{31-27} = 0b11101; - let Inst{26-25} = 0b00; + bits<4> Rt; + bits<4> Rt2; + bits<13> addr; + let Inst{31-25} = 0b1110100; let Inst{24} = P; - let Inst{23} = ?; // The U bit. + let Inst{23} = addr{8}; let Inst{22} = 1; let Inst{21} = W; - let Inst{20} = load; + let Inst{20} = isLoad; + let Inst{19-16} = addr{12-9}; + let Inst{15-12} = Rt{3-0}; + let Inst{11-8} = Rt2{3-0}; + let Inst{7-0} = addr{7-0}; } class T2sI pattern> : Thumb2XI; -class T2Ix2 pattern> - : Thumb2I; +// Move to/from coprocessor instructions +class T2Cop pattern> + : T2XI, Requires<[IsThumb2, HasV6]> { + let Inst{31-28} = 0b1111; +} // Two-address instructions class T2XIt opcod, bit load, bit pre, : InstARM { let OutOperandList = oops; let InOperandList = !con(iops, (ins pred:$p)); - let AsmString = !strconcat(opc, !strconcat("${p}", asm)); + let AsmString = !strconcat(opc, "${p}", asm); let Pattern = pattern; list Predicates = [IsThumb2]; let Inst{31-27} = 0b11111; @@ -1240,29 +1115,25 @@ class T2Iidxldst opcod, bit load, bit pre, // (P, W) = (1, 1) Pre-indexed or (0, 1) Post-indexed let Inst{10} = pre; // The P bit. let Inst{8} = 1; // The W bit. -} -// Helper class for disassembly only -// A6.3.16 & A6.3.17 -// T2Imac - Thumb2 multiply [accumulate, and absolute difference] instructions. -class T2I_mac op22_20, bits<4> op7_4, dag oops, dag iops, - InstrItinClass itin, string opc, string asm, list pattern> - : T2I { - let Inst{31-27} = 0b11111; - let Inst{26-24} = 0b011; - let Inst{23} = long; - let Inst{22-20} = op22_20; - let Inst{7-4} = op7_4; + bits<9> addr; + let Inst{7-0} = addr{7-0}; + let Inst{9} = addr{8}; // Sign bit + + bits<4> Rt; + bits<4> Rn; + let Inst{15-12} = Rt{3-0}; + let Inst{19-16} = Rn{3-0}; } // Tv5Pat - Same as Pat<>, but requires V5T Thumb mode. class Tv5Pat : Pat { - list Predicates = [IsThumb1Only, HasV5T]; + list Predicates = [IsThumb, IsThumb1Only, HasV5T]; } // T1Pat - Same as Pat<>, but requires that the compiler be in Thumb1 mode. class T1Pat : Pat { - list Predicates = [IsThumb1Only]; + list Predicates = [IsThumb, IsThumb1Only]; } // T2Pat - Same as Pat<>, but requires that the compiler be in Thumb2 mode. @@ -1281,10 +1152,13 @@ class VFPI pattern> : InstARM { + bits<4> p; + let Inst{31-28} = p; let OutOperandList = oops; let InOperandList = !con(iops, (ins pred:$p)); - let AsmString = !strconcat(opc, !strconcat("${p}", asm)); + let AsmString = !strconcat(opc, "${p}", asm); let Pattern = pattern; + let PostEncoderMethod = "VFPThumb2PostEncoder"; list Predicates = [HasVFP2]; } @@ -1293,17 +1167,22 @@ class VFPXI pattern> : InstARM { + bits<4> p; + let Inst{31-28} = p; let OutOperandList = oops; let InOperandList = iops; let AsmString = asm; let Pattern = pattern; + let PostEncoderMethod = "VFPThumb2PostEncoder"; list Predicates = [HasVFP2]; } class VFPAI pattern> : VFPI; + opc, asm, "", pattern> { + let PostEncoderMethod = "VFPThumb2PostEncoder"; +} // ARM VFP addrmode5 loads and stores class ADI5 opcod1, bits<2> opcod2, dag oops, dag iops, @@ -1311,12 +1190,24 @@ class ADI5 opcod1, bits<2> opcod2, dag oops, dag iops, string opc, string asm, list pattern> : VFPI { + // Instruction operands. + bits<5> Dd; + bits<13> addr; + + // Encode instruction operands. + let Inst{23} = addr{8}; // U (add = (U == '1')) + let Inst{22} = Dd{4}; + let Inst{19-16} = addr{12-9}; // Rn + let Inst{15-12} = Dd{3-0}; + let Inst{7-0} = addr{7-0}; // imm8 + // TODO: Mark the instructions with the appropriate subtarget info. let Inst{27-24} = opcod1; let Inst{21-20} = opcod2; - let Inst{11-8} = 0b1011; + let Inst{11-9} = 0b101; + let Inst{8} = 1; // Double precision - // 64-bit loads & stores operate on both NEON and VFP pipelines. + // Loads & stores operate on both NEON and VFP pipelines. let D = VFPNeonDomain; } @@ -1325,10 +1216,36 @@ class ASI5 opcod1, bits<2> opcod2, dag oops, dag iops, string opc, string asm, list pattern> : VFPI { + // Instruction operands. + bits<5> Sd; + bits<13> addr; + + // Encode instruction operands. + let Inst{23} = addr{8}; // U (add = (U == '1')) + let Inst{22} = Sd{0}; + let Inst{19-16} = addr{12-9}; // Rn + let Inst{15-12} = Sd{4-1}; + let Inst{7-0} = addr{7-0}; // imm8 + // TODO: Mark the instructions with the appropriate subtarget info. let Inst{27-24} = opcod1; let Inst{21-20} = opcod2; - let Inst{11-8} = 0b1010; + let Inst{11-9} = 0b101; + let Inst{8} = 0; // Single precision + + // Loads & stores operate on both NEON and VFP pipelines. + let D = VFPNeonDomain; +} + +// VFP Load / store multiple pseudo instructions. +class PseudoVFPLdStM pattern> + : InstARM { + let OutOperandList = oops; + let InOperandList = !con(iops, (ins pred:$p)); + let Pattern = pattern; + list Predicates = [HasVFP2]; } // Load / store multiple @@ -1336,21 +1253,40 @@ class AXDI4 pattern> : VFPXI { + // Instruction operands. + bits<4> Rn; + bits<13> regs; + + // Encode instruction operands. + let Inst{19-16} = Rn; + let Inst{22} = regs{12}; + let Inst{15-12} = regs{11-8}; + let Inst{7-0} = regs{7-0}; + // TODO: Mark the instructions with the appropriate subtarget info. let Inst{27-25} = 0b110; - let Inst{11-8} = 0b1011; - - // 64-bit loads & stores operate on both NEON and VFP pipelines. - let D = VFPNeonDomain; + let Inst{11-9} = 0b101; + let Inst{8} = 1; // Double precision } class AXSI4 pattern> : VFPXI { + // Instruction operands. + bits<4> Rn; + bits<13> regs; + + // Encode instruction operands. + let Inst{19-16} = Rn; + let Inst{22} = regs{8}; + let Inst{15-12} = regs{12-9}; + let Inst{7-0} = regs{7-0}; + // TODO: Mark the instructions with the appropriate subtarget info. let Inst{27-25} = 0b110; - let Inst{11-8} = 0b1010; + let Inst{11-9} = 0b101; + let Inst{8} = 0; // Single precision } // Double precision, unary @@ -1358,10 +1294,21 @@ class ADuI opcod1, bits<2> opcod2, bits<4> opcod3, bits<2> opcod4, bit opcod5, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : VFPAI { + // Instruction operands. + bits<5> Dd; + bits<5> Dm; + + // Encode instruction operands. + let Inst{3-0} = Dm{3-0}; + let Inst{5} = Dm{4}; + let Inst{15-12} = Dd{3-0}; + let Inst{22} = Dd{4}; + let Inst{27-23} = opcod1; let Inst{21-20} = opcod2; let Inst{19-16} = opcod3; - let Inst{11-8} = 0b1011; + let Inst{11-9} = 0b101; + let Inst{8} = 1; // Double precision let Inst{7-6} = opcod4; let Inst{4} = opcod5; } @@ -1371,24 +1318,25 @@ class ADbI opcod1, bits<2> opcod2, bit op6, bit op4, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : VFPAI { - let Inst{27-23} = opcod1; - let Inst{21-20} = opcod2; - let Inst{11-8} = 0b1011; - let Inst{6} = op6; - let Inst{4} = op4; -} + // Instruction operands. + bits<5> Dd; + bits<5> Dn; + bits<5> Dm; + + // Encode instruction operands. + let Inst{3-0} = Dm{3-0}; + let Inst{5} = Dm{4}; + let Inst{19-16} = Dn{3-0}; + let Inst{7} = Dn{4}; + let Inst{15-12} = Dd{3-0}; + let Inst{22} = Dd{4}; -// Double precision, binary, VML[AS] (for additional predicate) -class ADbI_vmlX opcod1, bits<2> opcod2, bit op6, bit op4, dag oops, - dag iops, InstrItinClass itin, string opc, string asm, - list pattern> - : VFPAI { let Inst{27-23} = opcod1; let Inst{21-20} = opcod2; - let Inst{11-8} = 0b1011; + let Inst{11-9} = 0b101; + let Inst{8} = 1; // Double precision let Inst{6} = op6; let Inst{4} = op4; - list Predicates = [HasVFP2, UseVMLx]; } // Single precision, unary @@ -1396,16 +1344,27 @@ class ASuI opcod1, bits<2> opcod2, bits<4> opcod3, bits<2> opcod4, bit opcod5, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : VFPAI { + // Instruction operands. + bits<5> Sd; + bits<5> Sm; + + // Encode instruction operands. + let Inst{3-0} = Sm{4-1}; + let Inst{5} = Sm{0}; + let Inst{15-12} = Sd{4-1}; + let Inst{22} = Sd{0}; + let Inst{27-23} = opcod1; let Inst{21-20} = opcod2; let Inst{19-16} = opcod3; - let Inst{11-8} = 0b1010; + let Inst{11-9} = 0b101; + let Inst{8} = 0; // Single precision let Inst{7-6} = opcod4; let Inst{4} = opcod5; } -// Single precision unary, if no NEON -// Same as ASuI except not available if NEON is enabled +// Single precision unary, if no NEON. Same as ASuI except not available if +// NEON is enabled. class ASuIn opcod1, bits<2> opcod2, bits<4> opcod3, bits<2> opcod4, bit opcod5, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> @@ -1418,20 +1377,47 @@ class ASuIn opcod1, bits<2> opcod2, bits<4> opcod3, bits<2> opcod4, class ASbI opcod1, bits<2> opcod2, bit op6, bit op4, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : VFPAI { + // Instruction operands. + bits<5> Sd; + bits<5> Sn; + bits<5> Sm; + + // Encode instruction operands. + let Inst{3-0} = Sm{4-1}; + let Inst{5} = Sm{0}; + let Inst{19-16} = Sn{4-1}; + let Inst{7} = Sn{0}; + let Inst{15-12} = Sd{4-1}; + let Inst{22} = Sd{0}; + let Inst{27-23} = opcod1; let Inst{21-20} = opcod2; - let Inst{11-8} = 0b1010; + let Inst{11-9} = 0b101; + let Inst{8} = 0; // Single precision let Inst{6} = op6; let Inst{4} = op4; } -// Single precision binary, if no NEON -// Same as ASbI except not available if NEON is enabled +// Single precision binary, if no NEON. Same as ASbI except not available if +// NEON is enabled. class ASbIn opcod1, bits<2> opcod2, bit op6, bit op4, dag oops, dag iops, InstrItinClass itin, string opc, string asm, list pattern> : ASbI { list Predicates = [HasVFP2,DontUseNEONForFP]; + + // Instruction operands. + bits<5> Sd; + bits<5> Sn; + bits<5> Sm; + + // Encode instruction operands. + let Inst{3-0} = Sm{4-1}; + let Inst{5} = Sm{0}; + let Inst{19-16} = Sn{4-1}; + let Inst{7} = Sn{0}; + let Inst{15-12} = Sd{4-1}; + let Inst{22} = Sd{0}; } // VFP conversion instructions @@ -1502,9 +1488,7 @@ class NeonI { let OutOperandList = oops; let InOperandList = !con(iops, (ins pred:$p)); - let AsmString = !strconcat( - !strconcat(!strconcat(opc, "${p}"), !strconcat(".", dt)), - !strconcat("\t", asm)); + let AsmString = !strconcat(opc, "${p}", ".", dt, "\t", asm); let Pattern = pattern; list Predicates = [HasNEON]; } @@ -1516,7 +1500,7 @@ class NeonXI { let OutOperandList = oops; let InOperandList = !con(iops, (ins pred:$p)); - let AsmString = !strconcat(!strconcat(opc, "${p}"), !strconcat("\t", asm)); + let AsmString = !strconcat(opc, "${p}", "\t", asm); let Pattern = pattern; list Predicates = [HasNEON]; } @@ -1531,6 +1515,25 @@ class NLdSt op21_20, bits<4> op11_8, bits<4> op7_4, let Inst{21-20} = op21_20; let Inst{11-8} = op11_8; let Inst{7-4} = op7_4; + + let PostEncoderMethod = "NEONThumb2LoadStorePostEncoder"; + + bits<5> Vd; + bits<6> Rn; + bits<4> Rm; + + let Inst{22} = Vd{4}; + let Inst{15-12} = Vd{3-0}; + let Inst{19-16} = Rn{3-0}; + let Inst{3-0} = Rm{3-0}; +} + +class NLdStLn op21_20, bits<4> op11_8, bits<4> op7_4, + dag oops, dag iops, InstrItinClass itin, + string opc, string dt, string asm, string cstr, list pattern> + : NLdSt { + bits<3> lane; } class PseudoNLdSt @@ -1541,11 +1544,22 @@ class PseudoNLdSt list Predicates = [HasNEON]; } +class PseudoNeonI pattern> + : InstARM { + let OutOperandList = oops; + let InOperandList = !con(iops, (ins pred:$p)); + let Pattern = pattern; + list Predicates = [HasNEON]; +} + class NDataI pattern> : NeonI { let Inst{31-25} = 0b1111001; + let PostEncoderMethod = "NEONThumb2DataIPostEncoder"; } class NDataXI { let Inst{31-25} = 0b1111001; + let PostEncoderMethod = "NEONThumb2DataIPostEncoder"; } // NEON "one register and a modified immediate" format. @@ -1569,6 +1584,16 @@ class N1ModImm op21_19, bits<4> op11_8, bit op7, bit op6, let Inst{6} = op6; let Inst{5} = op5; let Inst{4} = op4; + + // Instruction operands. + bits<5> Vd; + bits<13> SIMM; + + let Inst{15-12} = Vd{3-0}; + let Inst{22} = Vd{4}; + let Inst{24} = SIMM{7}; + let Inst{18-16} = SIMM{6-4}; + let Inst{3-0} = SIMM{3-0}; } // NEON 2 vector register format. @@ -1584,6 +1609,15 @@ class N2V op24_23, bits<2> op21_20, bits<2> op19_18, bits<2> op17_16, let Inst{11-7} = op11_7; let Inst{6} = op6; let Inst{4} = op4; + + // Instruction operands. + bits<5> Vd; + bits<5> Vm; + + let Inst{15-12} = Vd{3-0}; + let Inst{22} = Vd{4}; + let Inst{3-0} = Vm{3-0}; + let Inst{5} = Vm{4}; } // Same as N2V except it doesn't have a datatype suffix. @@ -1599,6 +1633,15 @@ class N2VX op24_23, bits<2> op21_20, bits<2> op19_18, bits<2> op17_16, let Inst{11-7} = op11_7; let Inst{6} = op6; let Inst{4} = op4; + + // Instruction operands. + bits<5> Vd; + bits<5> Vm; + + let Inst{15-12} = Vd{3-0}; + let Inst{22} = Vd{4}; + let Inst{3-0} = Vm{3-0}; + let Inst{5} = Vm{4}; } // NEON 2 vector register with immediate. @@ -1612,6 +1655,17 @@ class N2VImm op11_8, bit op7, bit op6, bit op4, let Inst{7} = op7; let Inst{6} = op6; let Inst{4} = op4; + + // Instruction operands. + bits<5> Vd; + bits<5> Vm; + bits<6> SIMM; + + let Inst{15-12} = Vd{3-0}; + let Inst{22} = Vd{4}; + let Inst{3-0} = Vm{3-0}; + let Inst{5} = Vm{4}; + let Inst{21-16} = SIMM{5-0}; } // NEON 3 vector register format. @@ -1625,6 +1679,18 @@ class N3V op21_20, bits<4> op11_8, bit op6, bit op4, let Inst{11-8} = op11_8; let Inst{6} = op6; let Inst{4} = op4; + + // Instruction operands. + bits<5> Vd; + bits<5> Vn; + bits<5> Vm; + + let Inst{15-12} = Vd{3-0}; + let Inst{22} = Vd{4}; + let Inst{19-16} = Vn{3-0}; + let Inst{7} = Vn{4}; + let Inst{3-0} = Vm{3-0}; + let Inst{5} = Vm{4}; } // Same as N3V except it doesn't have a data type suffix. @@ -1639,13 +1705,25 @@ class N3VX op21_20, bits<4> op11_8, bit op6, let Inst{11-8} = op11_8; let Inst{6} = op6; let Inst{4} = op4; + + // Instruction operands. + bits<5> Vd; + bits<5> Vn; + bits<5> Vm; + + let Inst{15-12} = Vd{3-0}; + let Inst{22} = Vd{4}; + let Inst{19-16} = Vn{3-0}; + let Inst{7} = Vn{4}; + let Inst{3-0} = Vm{3-0}; + let Inst{5} = Vm{4}; } // NEON VMOVs between scalar and core registers. class NVLaneOp opcod1, bits<4> opcod2, bits<2> opcod3, dag oops, dag iops, Format f, InstrItinClass itin, string opc, string dt, string asm, list pattern> - : InstARM { let Inst{27-20} = opcod1; let Inst{11-8} = opcod2; @@ -1654,11 +1732,21 @@ class NVLaneOp opcod1, bits<4> opcod2, bits<2> opcod3, let OutOperandList = oops; let InOperandList = !con(iops, (ins pred:$p)); - let AsmString = !strconcat( - !strconcat(!strconcat(opc, "${p}"), !strconcat(".", dt)), - !strconcat("\t", asm)); + let AsmString = !strconcat(opc, "${p}", ".", dt, "\t", asm); let Pattern = pattern; list Predicates = [HasNEON]; + + let PostEncoderMethod = "NEONThumb2DupPostEncoder"; + + bits<5> V; + bits<4> R; + bits<4> p; + bits<4> lane; + + let Inst{31-28} = p{3-0}; + let Inst{7} = V{4}; + let Inst{19-16} = V{3-0}; + let Inst{15-12} = R{3-0}; } class NVGetLane opcod1, bits<4> opcod2, bits<2> opcod3, dag oops, dag iops, InstrItinClass itin, @@ -1687,6 +1775,15 @@ class NVDupLane op19_16, bit op6, dag oops, dag iops, let Inst{11-7} = 0b11000; let Inst{6} = op6; let Inst{4} = 0; + + bits<5> Vd; + bits<5> Vm; + bits<4> lane; + + let Inst{22} = Vd{4}; + let Inst{15-12} = Vd{3-0}; + let Inst{5} = Vm{4}; + let Inst{3-0} = Vm{3-0}; } // NEONFPPat - Same as Pat<>, but requires that the compiler be using NEON diff --git a/lib/Target/ARM/ARMInstrInfo.cpp b/lib/Target/ARM/ARMInstrInfo.cpp index ba228ffac8ed..6f48d967f919 100644 --- a/lib/Target/ARM/ARMInstrInfo.cpp +++ b/lib/Target/ARM/ARMInstrInfo.cpp @@ -33,13 +33,13 @@ unsigned ARMInstrInfo::getUnindexedOpcode(unsigned Opc) const { default: break; case ARM::LDR_PRE: case ARM::LDR_POST: - return ARM::LDR; + return ARM::LDRi12; case ARM::LDRH_PRE: case ARM::LDRH_POST: return ARM::LDRH; case ARM::LDRB_PRE: case ARM::LDRB_POST: - return ARM::LDRB; + return ARM::LDRBi12; case ARM::LDRSH_PRE: case ARM::LDRSH_POST: return ARM::LDRSH; @@ -48,39 +48,14 @@ unsigned ARMInstrInfo::getUnindexedOpcode(unsigned Opc) const { return ARM::LDRSB; case ARM::STR_PRE: case ARM::STR_POST: - return ARM::STR; + return ARM::STRi12; case ARM::STRH_PRE: case ARM::STRH_POST: return ARM::STRH; case ARM::STRB_PRE: case ARM::STRB_POST: - return ARM::STRB; + return ARM::STRBi12; } return 0; } - -void ARMInstrInfo:: -reMaterialize(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, - unsigned DestReg, unsigned SubIdx, const MachineInstr *Orig, - const TargetRegisterInfo &TRI) const { - DebugLoc dl = Orig->getDebugLoc(); - unsigned Opcode = Orig->getOpcode(); - switch (Opcode) { - default: - break; - case ARM::MOVi2pieces: { - RI.emitLoadConstPool(MBB, I, dl, - DestReg, SubIdx, - Orig->getOperand(1).getImm(), - (ARMCC::CondCodes)Orig->getOperand(2).getImm(), - Orig->getOperand(3).getReg()); - MachineInstr *NewMI = prior(I); - NewMI->getOperand(0).setSubReg(SubIdx); - return; - } - } - - return ARMBaseInstrInfo::reMaterialize(MBB, I, DestReg, SubIdx, Orig, TRI); -} - diff --git a/lib/Target/ARM/ARMInstrInfo.h b/lib/Target/ARM/ARMInstrInfo.h index 4563ffea7b9c..f2c7bdc31be9 100644 --- a/lib/Target/ARM/ARMInstrInfo.h +++ b/lib/Target/ARM/ARMInstrInfo.h @@ -32,11 +32,6 @@ public: // if there is not such an opcode. unsigned getUnindexedOpcode(unsigned Opc) const; - void reMaterialize(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, - unsigned DestReg, unsigned SubIdx, - const MachineInstr *Orig, - const TargetRegisterInfo &TRI) const; - /// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As /// such, whenever a client has an instance of instruction info, it should /// always be able to get register info as well (through this method). diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index e66f9b9ad0ac..c827ce3da97c 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -58,10 +58,9 @@ def SDT_ARMEH_SJLJ_Setjmp : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisPtrTy<1>, SDTCisInt<2>]>; def SDT_ARMEH_SJLJ_Longjmp: SDTypeProfile<0, 2, [SDTCisPtrTy<0>, SDTCisInt<1>]>; -def SDT_ARMMEMBARRIER : SDTypeProfile<0, 0, []>; -def SDT_ARMSYNCBARRIER : SDTypeProfile<0, 0, []>; -def SDT_ARMMEMBARRIERMCR : SDTypeProfile<0, 1, [SDTCisInt<0>]>; -def SDT_ARMSYNCBARRIERMCR : SDTypeProfile<0, 1, [SDTCisInt<0>]>; +def SDT_ARMEH_SJLJ_DispatchSetup: SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>; + +def SDT_ARMMEMBARRIER : SDTypeProfile<0, 1, [SDTCisInt<0>]>; def SDT_ARMTCRET : SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>; @@ -70,33 +69,35 @@ def SDT_ARMBFI : SDTypeProfile<1, 3, [SDTCisVT<0, i32>, SDTCisVT<1, i32>, // Node definitions. def ARMWrapper : SDNode<"ARMISD::Wrapper", SDTIntUnaryOp>; +def ARMWrapperDYN : SDNode<"ARMISD::WrapperDYN", SDTIntUnaryOp>; +def ARMWrapperPIC : SDNode<"ARMISD::WrapperPIC", SDTIntUnaryOp>; def ARMWrapperJT : SDNode<"ARMISD::WrapperJT", SDTIntBinOp>; def ARMcallseq_start : SDNode<"ISD::CALLSEQ_START", SDT_ARMCallSeqStart, - [SDNPHasChain, SDNPOutFlag]>; + [SDNPHasChain, SDNPOutGlue]>; def ARMcallseq_end : SDNode<"ISD::CALLSEQ_END", SDT_ARMCallSeqEnd, - [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>; + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; def ARMcall : SDNode<"ARMISD::CALL", SDT_ARMcall, - [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, SDNPVariadic]>; def ARMcall_pred : SDNode<"ARMISD::CALL_PRED", SDT_ARMcall, - [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, SDNPVariadic]>; def ARMcall_nolink : SDNode<"ARMISD::CALL_NOLINK", SDT_ARMcall, - [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, SDNPVariadic]>; def ARMretflag : SDNode<"ARMISD::RET_FLAG", SDTNone, - [SDNPHasChain, SDNPOptInFlag]>; + [SDNPHasChain, SDNPOptInGlue]>; def ARMcmov : SDNode<"ARMISD::CMOV", SDT_ARMCMov, - [SDNPInFlag]>; + [SDNPInGlue]>; def ARMcneg : SDNode<"ARMISD::CNEG", SDT_ARMCMov, - [SDNPInFlag]>; + [SDNPInGlue]>; def ARMbrcond : SDNode<"ARMISD::BRCOND", SDT_ARMBrcond, - [SDNPHasChain, SDNPInFlag, SDNPOutFlag]>; + [SDNPHasChain, SDNPInGlue, SDNPOutGlue]>; def ARMbrjt : SDNode<"ARMISD::BR_JT", SDT_ARMBrJT, [SDNPHasChain]>; @@ -106,40 +107,38 @@ def ARMbr2jt : SDNode<"ARMISD::BR2_JT", SDT_ARMBr2JT, def ARMBcci64 : SDNode<"ARMISD::BCC_i64", SDT_ARMBCC_i64, [SDNPHasChain]>; -def ARMand : SDNode<"ARMISD::AND", SDT_ARMAnd, - [SDNPOutFlag]>; - def ARMcmp : SDNode<"ARMISD::CMP", SDT_ARMCmp, - [SDNPOutFlag]>; + [SDNPOutGlue]>; def ARMcmpZ : SDNode<"ARMISD::CMPZ", SDT_ARMCmp, - [SDNPOutFlag, SDNPCommutative]>; + [SDNPOutGlue, SDNPCommutative]>; def ARMpic_add : SDNode<"ARMISD::PIC_ADD", SDT_ARMPICAdd>; -def ARMsrl_flag : SDNode<"ARMISD::SRL_FLAG", SDTIntUnaryOp, [SDNPOutFlag]>; -def ARMsra_flag : SDNode<"ARMISD::SRA_FLAG", SDTIntUnaryOp, [SDNPOutFlag]>; -def ARMrrx : SDNode<"ARMISD::RRX" , SDTIntUnaryOp, [SDNPInFlag ]>; +def ARMsrl_flag : SDNode<"ARMISD::SRL_FLAG", SDTIntUnaryOp, [SDNPOutGlue]>; +def ARMsra_flag : SDNode<"ARMISD::SRA_FLAG", SDTIntUnaryOp, [SDNPOutGlue]>; +def ARMrrx : SDNode<"ARMISD::RRX" , SDTIntUnaryOp, [SDNPInGlue ]>; def ARMthread_pointer: SDNode<"ARMISD::THREAD_POINTER", SDT_ARMThreadPointer>; def ARMeh_sjlj_setjmp: SDNode<"ARMISD::EH_SJLJ_SETJMP", SDT_ARMEH_SJLJ_Setjmp, [SDNPHasChain]>; def ARMeh_sjlj_longjmp: SDNode<"ARMISD::EH_SJLJ_LONGJMP", - SDT_ARMEH_SJLJ_Longjmp, [SDNPHasChain]>; + SDT_ARMEH_SJLJ_Longjmp, [SDNPHasChain]>; +def ARMeh_sjlj_dispatchsetup: SDNode<"ARMISD::EH_SJLJ_DISPATCHSETUP", + SDT_ARMEH_SJLJ_DispatchSetup, [SDNPHasChain]>; + def ARMMemBarrier : SDNode<"ARMISD::MEMBARRIER", SDT_ARMMEMBARRIER, [SDNPHasChain]>; -def ARMSyncBarrier : SDNode<"ARMISD::SYNCBARRIER", SDT_ARMMEMBARRIER, - [SDNPHasChain]>; -def ARMMemBarrierMCR : SDNode<"ARMISD::MEMBARRIER", SDT_ARMMEMBARRIERMCR, - [SDNPHasChain]>; -def ARMSyncBarrierMCR : SDNode<"ARMISD::SYNCBARRIER", SDT_ARMMEMBARRIERMCR, +def ARMMemBarrierMCR : SDNode<"ARMISD::MEMBARRIER_MCR", SDT_ARMMEMBARRIER, [SDNPHasChain]>; +def ARMPreload : SDNode<"ARMISD::PRELOAD", SDTPrefetch, + [SDNPHasChain, SDNPMayLoad, SDNPMayStore]>; def ARMrbit : SDNode<"ARMISD::RBIT", SDTIntUnaryOp>; -def ARMtcret : SDNode<"ARMISD::TC_RETURN", SDT_ARMTCRET, - [SDNPHasChain, SDNPOptInFlag, SDNPVariadic]>; +def ARMtcret : SDNode<"ARMISD::TC_RETURN", SDT_ARMTCRET, + [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; def ARMbfi : SDNode<"ARMISD::BFI", SDT_ARMBFI>; @@ -147,34 +146,40 @@ def ARMbfi : SDNode<"ARMISD::BFI", SDT_ARMBFI>; //===----------------------------------------------------------------------===// // ARM Instruction Predicate Definitions. // -def HasV4T : Predicate<"Subtarget->hasV4TOps()">; +def HasV4T : Predicate<"Subtarget->hasV4TOps()">, AssemblerPredicate; def NoV4T : Predicate<"!Subtarget->hasV4TOps()">; def HasV5T : Predicate<"Subtarget->hasV5TOps()">; -def HasV5TE : Predicate<"Subtarget->hasV5TEOps()">; -def HasV6 : Predicate<"Subtarget->hasV6Ops()">; -def HasV6T2 : Predicate<"Subtarget->hasV6T2Ops()">; +def HasV5TE : Predicate<"Subtarget->hasV5TEOps()">, AssemblerPredicate; +def HasV6 : Predicate<"Subtarget->hasV6Ops()">, AssemblerPredicate; +def NoV6 : Predicate<"!Subtarget->hasV6Ops()">; +def HasV6T2 : Predicate<"Subtarget->hasV6T2Ops()">, AssemblerPredicate; def NoV6T2 : Predicate<"!Subtarget->hasV6T2Ops()">; -def HasV7 : Predicate<"Subtarget->hasV7Ops()">; +def HasV7 : Predicate<"Subtarget->hasV7Ops()">, AssemblerPredicate; def NoVFP : Predicate<"!Subtarget->hasVFP2()">; -def HasVFP2 : Predicate<"Subtarget->hasVFP2()">; -def HasVFP3 : Predicate<"Subtarget->hasVFP3()">; -def HasNEON : Predicate<"Subtarget->hasNEON()">; -def HasDivide : Predicate<"Subtarget->hasDivide()">; -def HasT2ExtractPack : Predicate<"Subtarget->hasT2ExtractPack()">; -def HasDB : Predicate<"Subtarget->hasDataBarrier()">; +def HasVFP2 : Predicate<"Subtarget->hasVFP2()">, AssemblerPredicate; +def HasVFP3 : Predicate<"Subtarget->hasVFP3()">, AssemblerPredicate; +def HasNEON : Predicate<"Subtarget->hasNEON()">, AssemblerPredicate; +def HasFP16 : Predicate<"Subtarget->hasFP16()">, AssemblerPredicate; +def HasDivide : Predicate<"Subtarget->hasDivide()">, AssemblerPredicate; +def HasT2ExtractPack : Predicate<"Subtarget->hasT2ExtractPack()">, + AssemblerPredicate; +def HasDB : Predicate<"Subtarget->hasDataBarrier()">, + AssemblerPredicate; +def HasMP : Predicate<"Subtarget->hasMPExtension()">, + AssemblerPredicate; def UseNEONForFP : Predicate<"Subtarget->useNEONForSinglePrecisionFP()">; def DontUseNEONForFP : Predicate<"!Subtarget->useNEONForSinglePrecisionFP()">; -def IsThumb : Predicate<"Subtarget->isThumb()">; +def IsThumb : Predicate<"Subtarget->isThumb()">, AssemblerPredicate; def IsThumb1Only : Predicate<"Subtarget->isThumb1Only()">; -def IsThumb2 : Predicate<"Subtarget->isThumb2()">; -def IsARM : Predicate<"!Subtarget->isThumb()">; +def IsThumb2 : Predicate<"Subtarget->isThumb2()">, AssemblerPredicate; +def IsARM : Predicate<"!Subtarget->isThumb()">, AssemblerPredicate; def IsDarwin : Predicate<"Subtarget->isTargetDarwin()">; def IsNotDarwin : Predicate<"!Subtarget->isTargetDarwin()">; // FIXME: Eventually this will be just "hasV6T2Ops". def UseMovt : Predicate<"Subtarget->useMovt()">; def DontUseMovt : Predicate<"!Subtarget->useMovt()">; -def UseVMLx : Predicate<"Subtarget->useVMLx()">; +def UseFPVMLx : Predicate<"Subtarget->useFPVMLx()">; //===----------------------------------------------------------------------===// // ARM Flag Definitions. @@ -199,12 +204,6 @@ def so_imm_not_XFORM : SDNodeXFormgetTargetConstant(~(int)N->getZExtValue(), MVT::i32); }]>; -// rot_imm predicate - True if the 32-bit immediate is equal to 8, 16, or 24. -def rot_imm : PatLeaf<(i32 imm), [{ - int32_t v = (int32_t)N->getZExtValue(); - return v == 8 || v == 16 || v == 24; -}]>; - /// imm1_15 predicate - True if the 32-bit immediate is in the range [1,15]. def imm1_15 : PatLeaf<(i32 imm), [{ return (int32_t)N->getZExtValue() >= 1 && (int32_t)N->getZExtValue() < 16; @@ -217,12 +216,12 @@ def imm16_31 : PatLeaf<(i32 imm), [{ def so_imm_neg : PatLeaf<(imm), [{ - return ARM_AM::getSOImmVal(-(int)N->getZExtValue()) != -1; + return ARM_AM::getSOImmVal(-(uint32_t)N->getZExtValue()) != -1; }], so_imm_neg_XFORM>; def so_imm_not : PatLeaf<(imm), [{ - return ARM_AM::getSOImmVal(~(int)N->getZExtValue()) != -1; + return ARM_AM::getSOImmVal(~(uint32_t)N->getZExtValue()) != -1; }], so_imm_not_XFORM>; // sext_16_node predicate - True if the SDNode is sign-extended 16 or more bits. @@ -230,15 +229,6 @@ def sext_16_node : PatLeaf<(i32 GPR:$a), [{ return CurDAG->ComputeNumSignBits(SDValue(N,0)) >= 17; }]>; -/// bf_inv_mask_imm predicate - An AND mask to clear an arbitrary width bitfield -/// e.g., 0xf000ffff -def bf_inv_mask_imm : Operand, - PatLeaf<(imm), [{ - return ARM::isBitFieldInvertedMask(N->getZExtValue()); -}] > { - let PrintMethod = "printBitfieldInvMaskImmOperand"; -} - /// Split a 32-bit immediate into two 16 bit parts. def hi16 : SDNodeXFormgetTargetConstant((uint32_t)N->getZExtValue() >> 16, MVT::i32); @@ -273,28 +263,103 @@ def sube_live_carry : PatFrag<(ops node:$LHS, node:$RHS), (sube node:$LHS, node:$RHS), [{return N->hasAnyUseOfValue(1);}]>; +// An 'and' node with a single use. +def and_su : PatFrag<(ops node:$lhs, node:$rhs), (and node:$lhs, node:$rhs), [{ + return N->hasOneUse(); +}]>; + +// An 'xor' node with a single use. +def xor_su : PatFrag<(ops node:$lhs, node:$rhs), (xor node:$lhs, node:$rhs), [{ + return N->hasOneUse(); +}]>; + +// An 'fmul' node with a single use. +def fmul_su : PatFrag<(ops node:$lhs, node:$rhs), (fmul node:$lhs, node:$rhs),[{ + return N->hasOneUse(); +}]>; + +// An 'fadd' node which checks for single non-hazardous use. +def fadd_mlx : PatFrag<(ops node:$lhs, node:$rhs),(fadd node:$lhs, node:$rhs),[{ + return hasNoVMLxHazardUse(N); +}]>; + +// An 'fsub' node which checks for single non-hazardous use. +def fsub_mlx : PatFrag<(ops node:$lhs, node:$rhs),(fsub node:$lhs, node:$rhs),[{ + return hasNoVMLxHazardUse(N); +}]>; + //===----------------------------------------------------------------------===// // Operand Definitions. // // Branch target. -def brtarget : Operand; +// FIXME: rename brtarget to t2_brtarget +def brtarget : Operand { + let EncoderMethod = "getBranchTargetOpValue"; +} + +// FIXME: get rid of this one? +def uncondbrtarget : Operand { + let EncoderMethod = "getUnconditionalBranchTargetOpValue"; +} + +// Branch target for ARM. Handles conditional/unconditional +def br_target : Operand { + let EncoderMethod = "getARMBranchTargetOpValue"; +} + +// Call target. +// FIXME: rename bltarget to t2_bl_target? +def bltarget : Operand { + // Encoded the same as branch targets. + let EncoderMethod = "getBranchTargetOpValue"; +} + +// Call target for ARM. Handles conditional/unconditional +// FIXME: rename bl_target to t2_bltarget? +def bl_target : Operand { + // Encoded the same as branch targets. + let EncoderMethod = "getARMBranchTargetOpValue"; +} + // A list of registers separated by comma. Used by load/store multiple. +def RegListAsmOperand : AsmOperandClass { + let Name = "RegList"; + let SuperClasses = []; +} + +def DPRRegListAsmOperand : AsmOperandClass { + let Name = "DPRRegList"; + let SuperClasses = []; +} + +def SPRRegListAsmOperand : AsmOperandClass { + let Name = "SPRRegList"; + let SuperClasses = []; +} + def reglist : Operand { + let EncoderMethod = "getRegisterListOpValue"; + let ParserMatchClass = RegListAsmOperand; let PrintMethod = "printRegisterList"; } -// An operand for the CONSTPOOL_ENTRY pseudo-instruction. -def cpinst_operand : Operand { - let PrintMethod = "printCPInstOperand"; +def dpr_reglist : Operand { + let EncoderMethod = "getRegisterListOpValue"; + let ParserMatchClass = DPRRegListAsmOperand; + let PrintMethod = "printRegisterList"; } -def jtblock_operand : Operand { - let PrintMethod = "printJTBlockOperand"; +def spr_reglist : Operand { + let EncoderMethod = "getRegisterListOpValue"; + let ParserMatchClass = SPRRegListAsmOperand; + let PrintMethod = "printRegisterList"; } -def jt2block_operand : Operand { - let PrintMethod = "printJT2BlockOperand"; + +// An operand for the CONSTPOOL_ENTRY pseudo-instruction. +def cpinst_operand : Operand { + let PrintMethod = "printCPInstOperand"; } // Local PC labels. @@ -302,6 +367,22 @@ def pclabel : Operand { let PrintMethod = "printPCLabel"; } +// ADR instruction labels. +def adrlabel : Operand { + let EncoderMethod = "getAdrLabelOpValue"; +} + +def neon_vcvt_imm32 : Operand { + let EncoderMethod = "getNEONVcvtImm32OpValue"; +} + +// rot_imm: An integer that encodes a rotate amount. Must be 8, 16, or 24. +def rot_imm : Operand, PatLeaf<(i32 imm), [{ + int32_t v = (int32_t)N->getZExtValue(); + return v == 8 || v == 16 || v == 24; }]> { + let EncoderMethod = "getRotImmOpValue"; +} + // shift_imm: An integer that encodes a shift amount and the type of shift // (currently either asr or lsl) using the same encoding used for the // immediates in so_reg operands. @@ -313,73 +394,120 @@ def shift_imm : Operand { def so_reg : Operand, // reg reg imm ComplexPattern { + let EncoderMethod = "getSORegOpValue"; + let PrintMethod = "printSORegOperand"; + let MIOperandInfo = (ops GPR, GPR, i32imm); +} +def shift_so_reg : Operand, // reg reg imm + ComplexPattern { + let EncoderMethod = "getSORegOpValue"; let PrintMethod = "printSORegOperand"; let MIOperandInfo = (ops GPR, GPR, i32imm); } // so_imm - Match a 32-bit shifter_operand immediate operand, which is an -// 8-bit immediate rotated by an arbitrary number of bits. so_imm values are -// represented in the imm field in the same 12-bit form that they are encoded -// into so_imm instructions: the 8-bit immediate is the least significant bits -// [bits 0-7], the 4-bit shift amount is the next 4 bits [bits 8-11]. +// 8-bit immediate rotated by an arbitrary number of bits. def so_imm : Operand, PatLeaf<(imm), [{ return Pred_so_imm(N); }]> { + let EncoderMethod = "getSOImmOpValue"; let PrintMethod = "printSOImmOperand"; } // Break so_imm's up into two pieces. This handles immediates with up to 16 // bits set in them. This uses so_imm2part to match and so_imm2part_[12] to // get the first/second pieces. -def so_imm2part : Operand, - PatLeaf<(imm), [{ +def so_imm2part : PatLeaf<(imm), [{ return ARM_AM::isSOImmTwoPartVal((unsigned)N->getZExtValue()); - }]> { - let PrintMethod = "printSOImm2PartOperand"; -} +}]>; -def so_imm2part_1 : SDNodeXFormgetZExtValue()); - return CurDAG->getTargetConstant(V, MVT::i32); +/// arm_i32imm - True for +V6T2, or true only if so_imm2part is true. +/// +def arm_i32imm : PatLeaf<(imm), [{ + if (Subtarget->hasV6T2Ops()) + return true; + return ARM_AM::isSOImmTwoPartVal((unsigned)N->getZExtValue()); }]>; -def so_imm2part_2 : SDNodeXFormgetZExtValue()); - return CurDAG->getTargetConstant(V, MVT::i32); +/// imm0_31 predicate - True if the 32-bit immediate is in the range [0,31]. +def imm0_31 : Operand, PatLeaf<(imm), [{ + return (int32_t)N->getZExtValue() < 32; }]>; -def so_neg_imm2part : Operand, PatLeaf<(imm), [{ - return ARM_AM::isSOImmTwoPartVal(-(int)N->getZExtValue()); - }]> { - let PrintMethod = "printSOImm2PartOperand"; +/// imm0_31_m1 - Matches and prints like imm0_31, but encodes as 'value - 1'. +def imm0_31_m1 : Operand, PatLeaf<(imm), [{ + return (int32_t)N->getZExtValue() < 32; +}]> { + let EncoderMethod = "getImmMinusOneOpValue"; } -def so_neg_imm2part_1 : SDNodeXFormgetZExtValue()); - return CurDAG->getTargetConstant(V, MVT::i32); -}]>; +// i32imm_hilo16 - For movt/movw - sets the MC Encoder method. +// The imm is split into imm{15-12}, imm{11-0} +// +def i32imm_hilo16 : Operand { + let EncoderMethod = "getHiLo16ImmOpValue"; +} -def so_neg_imm2part_2 : SDNodeXFormgetZExtValue()); - return CurDAG->getTargetConstant(V, MVT::i32); -}]>; +/// bf_inv_mask_imm predicate - An AND mask to clear an arbitrary width bitfield +/// e.g., 0xf000ffff +def bf_inv_mask_imm : Operand, + PatLeaf<(imm), [{ + return ARM::isBitFieldInvertedMask(N->getZExtValue()); +}] > { + let EncoderMethod = "getBitfieldInvertedMaskOpValue"; + let PrintMethod = "printBitfieldInvMaskImmOperand"; +} -/// imm0_31 predicate - True if the 32-bit immediate is in the range [0,31]. -def imm0_31 : Operand, PatLeaf<(imm), [{ - return (int32_t)N->getZExtValue() < 32; +/// lsb_pos_imm - position of the lsb bit, used by BFI4p and t2BFI4p +def lsb_pos_imm : Operand, PatLeaf<(imm), [{ + return isInt<5>(N->getSExtValue()); }]>; +/// width_imm - number of bits to be copied, used by BFI4p and t2BFI4p +def width_imm : Operand, PatLeaf<(imm), [{ + return N->getSExtValue() > 0 && N->getSExtValue() <= 32; +}] > { + let EncoderMethod = "getMsbOpValue"; +} + // Define ARM specific addressing modes. -// addrmode2 := reg +/- reg shop imm + +// addrmode_imm12 := reg +/- imm12 +// +def addrmode_imm12 : Operand, + ComplexPattern { + // 12-bit immediate operand. Note that instructions using this encode + // #0 and #-0 differently. We flag #-0 as the magic value INT32_MIN. All other + // immediate values are as normal. + + let EncoderMethod = "getAddrModeImm12OpValue"; + let PrintMethod = "printAddrModeImm12Operand"; + let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); +} +// ldst_so_reg := reg +/- reg shop imm +// +def ldst_so_reg : Operand, + ComplexPattern { + let EncoderMethod = "getLdStSORegOpValue"; + // FIXME: Simplify the printer + let PrintMethod = "printAddrMode2Operand"; + let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$offsimm); +} + // addrmode2 := reg +/- imm12 +// := reg +/- reg shop imm // def addrmode2 : Operand, ComplexPattern { + let EncoderMethod = "getAddrMode2OpValue"; let PrintMethod = "printAddrMode2Operand"; let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$offsimm); } def am2offset : Operand, - ComplexPattern { + ComplexPattern { + let EncoderMethod = "getAddrMode2OffsetOpValue"; let PrintMethod = "printAddrMode2OffsetOperand"; let MIOperandInfo = (ops GPR, i32imm); } @@ -389,22 +517,29 @@ def am2offset : Operand, // def addrmode3 : Operand, ComplexPattern { + let EncoderMethod = "getAddrMode3OpValue"; let PrintMethod = "printAddrMode3Operand"; let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$offsimm); } def am3offset : Operand, - ComplexPattern { + ComplexPattern { + let EncoderMethod = "getAddrMode3OffsetOpValue"; let PrintMethod = "printAddrMode3OffsetOperand"; let MIOperandInfo = (ops GPR, i32imm); } -// addrmode4 := reg, +// ldstm_mode := {ia, ib, da, db} // -def addrmode4 : Operand, - ComplexPattern { - let PrintMethod = "printAddrMode4Operand"; - let MIOperandInfo = (ops GPR:$addr, i32imm); +def ldstm_mode : OptionalDefOperand { + let EncoderMethod = "getLdStmModeOpValue"; + let PrintMethod = "printLdStmModeOperand"; +} + +def MemMode5AsmOperand : AsmOperandClass { + let Name = "MemMode5"; + let SuperClasses = []; } // addrmode5 := reg +/- imm8*4 @@ -413,19 +548,32 @@ def addrmode5 : Operand, ComplexPattern { let PrintMethod = "printAddrMode5Operand"; let MIOperandInfo = (ops GPR:$base, i32imm); + let ParserMatchClass = MemMode5AsmOperand; + let EncoderMethod = "getAddrMode5OpValue"; } -// addrmode6 := reg with optional writeback +// addrmode6 := reg with optional alignment // def addrmode6 : Operand, - ComplexPattern { + ComplexPattern{ let PrintMethod = "printAddrMode6Operand"; let MIOperandInfo = (ops GPR:$addr, i32imm); + let EncoderMethod = "getAddrMode6AddressOpValue"; } def am6offset : Operand { let PrintMethod = "printAddrMode6OffsetOperand"; let MIOperandInfo = (ops GPR); + let EncoderMethod = "getAddrMode6OffsetOpValue"; +} + +// Special version of addrmode6 to handle alignment encoding for VLD-dup +// instructions, specifically VLD4-dup. +def addrmode6dup : Operand, + ComplexPattern{ + let PrintMethod = "printAddrMode6Operand"; + let MIOperandInfo = (ops GPR:$addr, i32imm); + let EncoderMethod = "getAddrMode6DupAddressOpValue"; } // addrmodepc := pc + reg @@ -440,6 +588,28 @@ def nohash_imm : Operand { let PrintMethod = "printNoHashImmediate"; } +def CoprocNumAsmOperand : AsmOperandClass { + let Name = "CoprocNum"; + let SuperClasses = []; + let ParserMethod = "tryParseCoprocNumOperand"; +} + +def CoprocRegAsmOperand : AsmOperandClass { + let Name = "CoprocReg"; + let SuperClasses = []; + let ParserMethod = "tryParseCoprocRegOperand"; +} + +def p_imm : Operand { + let PrintMethod = "printPImmediate"; + let ParserMatchClass = CoprocNumAsmOperand; +} + +def c_imm : Operand { + let PrintMethod = "printCImmediate"; + let ParserMatchClass = CoprocRegAsmOperand; +} + //===----------------------------------------------------------------------===// include "ARMInstrFormats.td" @@ -450,55 +620,93 @@ include "ARMInstrFormats.td" /// AsI1_bin_irs - Defines a set of (op r, {so_imm|r|so_reg}) patterns for a /// binop that produces a value. -multiclass AsI1_bin_irs opcod, string opc, PatFrag opnode, - bit Commutable = 0> { +multiclass AsI1_bin_irs opcod, string opc, + InstrItinClass iii, InstrItinClass iir, InstrItinClass iis, + PatFrag opnode, bit Commutable = 0> { // The register-immediate version is re-materializable. This is useful // in particular for taking the address of a local. let isReMaterializable = 1 in { - def ri : AsI1 { + def ri : AsI1 { + bits<4> Rd; + bits<4> Rn; + bits<12> imm; let Inst{25} = 1; + let Inst{19-16} = Rn; + let Inst{15-12} = Rd; + let Inst{11-0} = imm; } } - def rr : AsI1 { - let Inst{11-4} = 0b00000000; + def rr : AsI1 { + bits<4> Rd; + bits<4> Rn; + bits<4> Rm; let Inst{25} = 0; let isCommutable = Commutable; + let Inst{19-16} = Rn; + let Inst{15-12} = Rd; + let Inst{11-4} = 0b00000000; + let Inst{3-0} = Rm; } - def rs : AsI1 { + def rs : AsI1 { + bits<4> Rd; + bits<4> Rn; + bits<12> shift; let Inst{25} = 0; + let Inst{19-16} = Rn; + let Inst{15-12} = Rd; + let Inst{11-0} = shift; } } /// AI1_bin_s_irs - Similar to AsI1_bin_irs except it sets the 's' bit so the /// instruction modifies the CPSR register. -let Defs = [CPSR] in { -multiclass AI1_bin_s_irs opcod, string opc, PatFrag opnode, - bit Commutable = 0> { - def ri : AI1 { - let Inst{20} = 1; +let isCodeGenOnly = 1, Defs = [CPSR] in { +multiclass AI1_bin_s_irs opcod, string opc, + InstrItinClass iii, InstrItinClass iir, InstrItinClass iis, + PatFrag opnode, bit Commutable = 0> { + def ri : AI1 { + bits<4> Rd; + bits<4> Rn; + bits<12> imm; let Inst{25} = 1; + let Inst{20} = 1; + let Inst{19-16} = Rn; + let Inst{15-12} = Rd; + let Inst{11-0} = imm; } - def rr : AI1 { + def rr : AI1 { + bits<4> Rd; + bits<4> Rn; + bits<4> Rm; let isCommutable = Commutable; - let Inst{11-4} = 0b00000000; - let Inst{20} = 1; let Inst{25} = 0; - } - def rs : AI1 { let Inst{20} = 1; + let Inst{19-16} = Rn; + let Inst{15-12} = Rd; + let Inst{11-4} = 0b00000000; + let Inst{3-0} = Rm; + } + def rs : AI1 { + bits<4> Rd; + bits<4> Rn; + bits<12> shift; let Inst{25} = 0; + let Inst{20} = 1; + let Inst{19-16} = Rn; + let Inst{15-12} = Rd; + let Inst{11-0} = shift; } } } @@ -507,146 +715,233 @@ multiclass AI1_bin_s_irs opcod, string opc, PatFrag opnode, /// patterns. Similar to AsI1_bin_irs except the instruction does not produce /// a explicit result, only implicitly set CPSR. let isCompare = 1, Defs = [CPSR] in { -multiclass AI1_cmp_irs opcod, string opc, PatFrag opnode, - bit Commutable = 0> { - def ri : AI1 { - let Inst{20} = 1; +multiclass AI1_cmp_irs opcod, string opc, + InstrItinClass iii, InstrItinClass iir, InstrItinClass iis, + PatFrag opnode, bit Commutable = 0> { + def ri : AI1 { + bits<4> Rn; + bits<12> imm; let Inst{25} = 1; - } - def rr : AI1 { - let Inst{11-4} = 0b00000000; let Inst{20} = 1; - let Inst{25} = 0; - let isCommutable = Commutable; + let Inst{19-16} = Rn; + let Inst{15-12} = 0b0000; + let Inst{11-0} = imm; } - def rs : AI1 { + def rr : AI1 { + bits<4> Rn; + bits<4> Rm; + let isCommutable = Commutable; + let Inst{25} = 0; let Inst{20} = 1; + let Inst{19-16} = Rn; + let Inst{15-12} = 0b0000; + let Inst{11-4} = 0b00000000; + let Inst{3-0} = Rm; + } + def rs : AI1 { + bits<4> Rn; + bits<12> shift; let Inst{25} = 0; + let Inst{20} = 1; + let Inst{19-16} = Rn; + let Inst{15-12} = 0b0000; + let Inst{11-0} = shift; } } } -/// AI_unary_rrot - A unary operation with two forms: one whose operand is a +/// AI_ext_rrot - A unary operation with two forms: one whose operand is a /// register and one whose operand is a register rotated by 8/16/24. /// FIXME: Remove the 'r' variant. Its rot_imm is zero. -multiclass AI_unary_rrot opcod, string opc, PatFrag opnode> { - def r : AExtI, +multiclass AI_ext_rrot opcod, string opc, PatFrag opnode> { + def r : AExtI, Requires<[IsARM, HasV6]> { - let Inst{11-10} = 0b00; + bits<4> Rd; + bits<4> Rm; let Inst{19-16} = 0b1111; + let Inst{15-12} = Rd; + let Inst{11-10} = 0b00; + let Inst{3-0} = Rm; } - def r_rot : AExtI, + def r_rot : AExtI, Requires<[IsARM, HasV6]> { + bits<4> Rd; + bits<4> Rm; + bits<2> rot; let Inst{19-16} = 0b1111; + let Inst{15-12} = Rd; + let Inst{11-10} = rot; + let Inst{3-0} = Rm; } } -multiclass AI_unary_rrot_np opcod, string opc> { - def r : AExtI opcod, string opc> { + def r : AExtI, Requires<[IsARM, HasV6]> { - let Inst{11-10} = 0b00; let Inst{19-16} = 0b1111; + let Inst{11-10} = 0b00; } - def r_rot : AExtI, Requires<[IsARM, HasV6]> { + bits<2> rot; let Inst{19-16} = 0b1111; + let Inst{11-10} = rot; } } -/// AI_bin_rrot - A binary operation with two forms: one whose operand is a +/// AI_exta_rrot - A binary operation with two forms: one whose operand is a /// register and one whose operand is a register rotated by 8/16/24. -multiclass AI_bin_rrot opcod, string opc, PatFrag opnode> { - def rr : AExtI, +multiclass AI_exta_rrot opcod, string opc, PatFrag opnode> { + def rr : AExtI, Requires<[IsARM, HasV6]> { + bits<4> Rd; + bits<4> Rm; + bits<4> Rn; + let Inst{19-16} = Rn; + let Inst{15-12} = Rd; let Inst{11-10} = 0b00; + let Inst{9-4} = 0b000111; + let Inst{3-0} = Rm; + } + def rr_rot : AExtI, + Requires<[IsARM, HasV6]> { + bits<4> Rd; + bits<4> Rm; + bits<4> Rn; + bits<2> rot; + let Inst{19-16} = Rn; + let Inst{15-12} = Rd; + let Inst{11-10} = rot; + let Inst{9-4} = 0b000111; + let Inst{3-0} = Rm; } - def rr_rot : AExtI, - Requires<[IsARM, HasV6]>; } // For disassembly only. -multiclass AI_bin_rrot_np opcod, string opc> { - def rr : AExtI opcod, string opc> { + def rr : AExtI, Requires<[IsARM, HasV6]> { let Inst{11-10} = 0b00; } - def rr_rot : AExtI, - Requires<[IsARM, HasV6]>; + Requires<[IsARM, HasV6]> { + bits<4> Rn; + bits<2> rot; + let Inst{19-16} = Rn; + let Inst{11-10} = rot; + } } /// AI1_adde_sube_irs - Define instructions and patterns for adde and sube. let Uses = [CPSR] in { multiclass AI1_adde_sube_irs opcod, string opc, PatFrag opnode, bit Commutable = 0> { - def ri : AsI1, + def ri : AsI1, Requires<[IsARM]> { + bits<4> Rd; + bits<4> Rn; + bits<12> imm; let Inst{25} = 1; + let Inst{15-12} = Rd; + let Inst{19-16} = Rn; + let Inst{11-0} = imm; } - def rr : AsI1, + def rr : AsI1, Requires<[IsARM]> { - let isCommutable = Commutable; + bits<4> Rd; + bits<4> Rn; + bits<4> Rm; let Inst{11-4} = 0b00000000; let Inst{25} = 0; + let isCommutable = Commutable; + let Inst{3-0} = Rm; + let Inst{15-12} = Rd; + let Inst{19-16} = Rn; } - def rs : AsI1, + def rs : AsI1, Requires<[IsARM]> { + bits<4> Rd; + bits<4> Rn; + bits<12> shift; let Inst{25} = 0; + let Inst{11-0} = shift; + let Inst{15-12} = Rd; + let Inst{19-16} = Rn; } } // Carry setting variants -let Defs = [CPSR] in { +let isCodeGenOnly = 1, Defs = [CPSR] in { multiclass AI1_adde_sube_s_irs opcod, string opc, PatFrag opnode, bit Commutable = 0> { - def Sri : AXI1, + def Sri : AXI1, Requires<[IsARM]> { + bits<4> Rd; + bits<4> Rn; + bits<12> imm; + let Inst{15-12} = Rd; + let Inst{19-16} = Rn; + let Inst{11-0} = imm; let Inst{20} = 1; let Inst{25} = 1; } - def Srr : AXI1, + def Srr : AXI1, Requires<[IsARM]> { + bits<4> Rd; + bits<4> Rn; + bits<4> Rm; let Inst{11-4} = 0b00000000; + let isCommutable = Commutable; + let Inst{3-0} = Rm; + let Inst{15-12} = Rd; + let Inst{19-16} = Rn; let Inst{20} = 1; let Inst{25} = 0; } - def Srs : AXI1, + def Srs : AXI1, Requires<[IsARM]> { + bits<4> Rd; + bits<4> Rn; + bits<12> shift; + let Inst{11-0} = shift; + let Inst{15-12} = Rd; + let Inst{19-16} = Rn; let Inst{20} = 1; let Inst{25} = 0; } @@ -654,6 +949,62 @@ multiclass AI1_adde_sube_s_irs opcod, string opc, PatFrag opnode, } } +let canFoldAsLoad = 1, isReMaterializable = 1 in { +multiclass AI_ldr1 { + // Note: We use the complex addrmode_imm12 rather than just an input + // GPR and a constrained immediate so that we can use this to match + // frame index references and avoid matching constant pool references. + def i12: AI2ldst<0b010, 1, isByte, (outs GPR:$Rt), (ins addrmode_imm12:$addr), + AddrMode_i12, LdFrm, iii, opc, "\t$Rt, $addr", + [(set GPR:$Rt, (opnode addrmode_imm12:$addr))]> { + bits<4> Rt; + bits<17> addr; + let Inst{23} = addr{12}; // U (add = ('U' == 1)) + let Inst{19-16} = addr{16-13}; // Rn + let Inst{15-12} = Rt; + let Inst{11-0} = addr{11-0}; // imm12 + } + def rs : AI2ldst<0b011, 1, isByte, (outs GPR:$Rt), (ins ldst_so_reg:$shift), + AddrModeNone, LdFrm, iir, opc, "\t$Rt, $shift", + [(set GPR:$Rt, (opnode ldst_so_reg:$shift))]> { + bits<4> Rt; + bits<17> shift; + let Inst{23} = shift{12}; // U (add = ('U' == 1)) + let Inst{19-16} = shift{16-13}; // Rn + let Inst{15-12} = Rt; + let Inst{11-0} = shift{11-0}; + } +} +} + +multiclass AI_str1 { + // Note: We use the complex addrmode_imm12 rather than just an input + // GPR and a constrained immediate so that we can use this to match + // frame index references and avoid matching constant pool references. + def i12 : AI2ldst<0b010, 0, isByte, (outs), + (ins GPR:$Rt, addrmode_imm12:$addr), + AddrMode_i12, StFrm, iii, opc, "\t$Rt, $addr", + [(opnode GPR:$Rt, addrmode_imm12:$addr)]> { + bits<4> Rt; + bits<17> addr; + let Inst{23} = addr{12}; // U (add = ('U' == 1)) + let Inst{19-16} = addr{16-13}; // Rn + let Inst{15-12} = Rt; + let Inst{11-0} = addr{11-0}; // imm12 + } + def rs : AI2ldst<0b011, 0, isByte, (outs), (ins GPR:$Rt, ldst_so_reg:$shift), + AddrModeNone, StFrm, iir, opc, "\t$Rt, $shift", + [(opnode GPR:$Rt, ldst_so_reg:$shift)]> { + bits<4> Rt; + bits<17> shift; + let Inst{23} = shift{12}; // U (add = ('U' == 1)) + let Inst{19-16} = shift{16-13}; // Rn + let Inst{15-12} = Rt; + let Inst{11-0} = shift{11-0}; + } +} //===----------------------------------------------------------------------===// // Instructions //===----------------------------------------------------------------------===// @@ -669,8 +1020,7 @@ multiclass AI1_adde_sube_s_irs opcod, string opc, PatFrag opnode, let neverHasSideEffects = 1, isNotDuplicable = 1 in def CONSTPOOL_ENTRY : PseudoInst<(outs), (ins cpinst_operand:$instid, cpinst_operand:$cpidx, - i32imm:$size), NoItinerary, - "${instid:label} ${cpidx:cpentry}", []>; + i32imm:$size), NoItinerary, []>; // FIXME: Marking these as hasSideEffects is necessary to prevent machine DCE // from removing one half of the matched pairs. That breaks PEI, which assumes @@ -678,12 +1028,10 @@ PseudoInst<(outs), (ins cpinst_operand:$instid, cpinst_operand:$cpidx, let Defs = [SP], Uses = [SP], hasSideEffects = 1 in { def ADJCALLSTACKUP : PseudoInst<(outs), (ins i32imm:$amt1, i32imm:$amt2, pred:$p), NoItinerary, - "${:comment} ADJCALLSTACKUP $amt1", [(ARMcallseq_end timm:$amt1, timm:$amt2)]>; def ADJCALLSTACKDOWN : PseudoInst<(outs), (ins i32imm:$amt, pred:$p), NoItinerary, - "${:comment} ADJCALLSTACKDOWN $amt", [(ARMcallseq_start timm:$amt)]>; } @@ -691,6 +1039,7 @@ def NOP : AI<(outs), (ins), MiscFrm, NoItinerary, "nop", "", [/* For disassembly only; pattern left blank */]>, Requires<[IsARM, HasV6T2]> { let Inst{27-16} = 0b001100100000; + let Inst{15-8} = 0b11110000; let Inst{7-0} = 0b00000000; } @@ -698,6 +1047,7 @@ def YIELD : AI<(outs), (ins), MiscFrm, NoItinerary, "yield", "", [/* For disassembly only; pattern left blank */]>, Requires<[IsARM, HasV6T2]> { let Inst{27-16} = 0b001100100000; + let Inst{15-8} = 0b11110000; let Inst{7-0} = 0b00000001; } @@ -705,6 +1055,7 @@ def WFE : AI<(outs), (ins), MiscFrm, NoItinerary, "wfe", "", [/* For disassembly only; pattern left blank */]>, Requires<[IsARM, HasV6T2]> { let Inst{27-16} = 0b001100100000; + let Inst{15-8} = 0b11110000; let Inst{7-0} = 0b00000010; } @@ -712,6 +1063,7 @@ def WFI : AI<(outs), (ins), MiscFrm, NoItinerary, "wfi", "", [/* For disassembly only; pattern left blank */]>, Requires<[IsARM, HasV6T2]> { let Inst{27-16} = 0b001100100000; + let Inst{15-8} = 0b11110000; let Inst{7-0} = 0b00000011; } @@ -719,14 +1071,22 @@ def SEL : AI<(outs GPR:$dst), (ins GPR:$a, GPR:$b), DPFrm, NoItinerary, "sel", "\t$dst, $a, $b", [/* For disassembly only; pattern left blank */]>, Requires<[IsARM, HasV6]> { + bits<4> Rd; + bits<4> Rn; + bits<4> Rm; + let Inst{3-0} = Rm; + let Inst{15-12} = Rd; + let Inst{19-16} = Rn; let Inst{27-20} = 0b01101000; let Inst{7-4} = 0b1011; + let Inst{11-8} = 0b1111; } def SEV : AI<(outs), (ins), MiscFrm, NoItinerary, "sev", "", [/* For disassembly only; pattern left blank */]>, Requires<[IsARM, HasV6T2]> { let Inst{27-16} = 0b001100100000; + let Inst{15-8} = 0b11110000; let Inst{7-0} = 0b00000100; } @@ -735,154 +1095,174 @@ def SEV : AI<(outs), (ins), MiscFrm, NoItinerary, "sev", "", def BKPT : AI<(outs), (ins i32imm:$val), MiscFrm, NoItinerary, "bkpt", "\t$val", [/* For disassembly only; pattern left blank */]>, Requires<[IsARM]> { + bits<16> val; + let Inst{3-0} = val{3-0}; + let Inst{19-8} = val{15-4}; let Inst{27-20} = 0b00010010; let Inst{7-4} = 0b0111; } -// Change Processor State is a system instruction -- for disassembly only. -// The singleton $opt operand contains the following information: -// opt{4-0} = mode from Inst{4-0} -// opt{5} = changemode from Inst{17} -// opt{8-6} = AIF from Inst{8-6} -// opt{10-9} = imod from Inst{19-18} with 0b10 as enable and 0b11 as disable -def CPS : AXI<(outs), (ins cps_opt:$opt), MiscFrm, NoItinerary, "cps$opt", - [/* For disassembly only; pattern left blank */]>, - Requires<[IsARM]> { +// Change Processor State is a system instruction -- for disassembly and +// parsing only. +// FIXME: Since the asm parser has currently no clean way to handle optional +// operands, create 3 versions of the same instruction. Once there's a clean +// framework to represent optional operands, change this behavior. +class CPS + : AXI<(outs), iops, MiscFrm, NoItinerary, !strconcat("cps", asm_ops), + [/* For disassembly only; pattern left blank */]>, Requires<[IsARM]> { + bits<2> imod; + bits<3> iflags; + bits<5> mode; + bit M; + let Inst{31-28} = 0b1111; let Inst{27-20} = 0b00010000; - let Inst{16} = 0; - let Inst{5} = 0; + let Inst{19-18} = imod; + let Inst{17} = M; // Enabled if mode is set; + let Inst{16} = 0; + let Inst{8-6} = iflags; + let Inst{5} = 0; + let Inst{4-0} = mode; } +let M = 1 in + def CPS3p : CPS<(ins imod_op:$imod, iflags_op:$iflags, i32imm:$mode), + "$imod\t$iflags, $mode">; +let mode = 0, M = 0 in + def CPS2p : CPS<(ins imod_op:$imod, iflags_op:$iflags), "$imod\t$iflags">; + +let imod = 0, iflags = 0, M = 1 in + def CPS1p : CPS<(ins i32imm:$mode), "\t$mode">; + // Preload signals the memory system of possible future data/instruction access. // These are for disassembly only. -// -// A8.6.117, A8.6.118. Different instructions are generated for #0 and #-0. -// The neg_zero operand translates -0 to -1, -1 to -2, ..., etc. -multiclass APreLoad { +multiclass APreLoad read, bits<1> data, string opc> { - def i : AXI<(outs), (ins GPR:$base, neg_zero:$imm), MiscFrm, NoItinerary, - !strconcat(opc, "\t[$base, $imm]"), []> { + def i12 : AXI<(outs), (ins addrmode_imm12:$addr), MiscFrm, IIC_Preload, + !strconcat(opc, "\t$addr"), + [(ARMPreload addrmode_imm12:$addr, (i32 read), (i32 data))]> { + bits<4> Rt; + bits<17> addr; let Inst{31-26} = 0b111101; let Inst{25} = 0; // 0 for immediate form let Inst{24} = data; + let Inst{23} = addr{12}; // U (add = ('U' == 1)) let Inst{22} = read; let Inst{21-20} = 0b01; + let Inst{19-16} = addr{16-13}; // Rn + let Inst{15-12} = 0b1111; + let Inst{11-0} = addr{11-0}; // imm12 } - def r : AXI<(outs), (ins addrmode2:$addr), MiscFrm, NoItinerary, - !strconcat(opc, "\t$addr"), []> { + def rs : AXI<(outs), (ins ldst_so_reg:$shift), MiscFrm, IIC_Preload, + !strconcat(opc, "\t$shift"), + [(ARMPreload ldst_so_reg:$shift, (i32 read), (i32 data))]> { + bits<17> shift; let Inst{31-26} = 0b111101; let Inst{25} = 1; // 1 for register form let Inst{24} = data; + let Inst{23} = shift{12}; // U (add = ('U' == 1)) let Inst{22} = read; let Inst{21-20} = 0b01; - let Inst{4} = 0; + let Inst{19-16} = shift{16-13}; // Rn + let Inst{15-12} = 0b1111; + let Inst{11-0} = shift{11-0}; } } -defm PLD : APreLoad<1, 1, "pld">; -defm PLDW : APreLoad<1, 0, "pldw">; -defm PLI : APreLoad<0, 1, "pli">; - -def SETENDBE : AXI<(outs),(ins), MiscFrm, NoItinerary, "setend\tbe", - [/* For disassembly only; pattern left blank */]>, - Requires<[IsARM]> { - let Inst{31-28} = 0b1111; - let Inst{27-20} = 0b00010000; - let Inst{16} = 1; - let Inst{9} = 1; - let Inst{7-4} = 0b0000; -} +defm PLD : APreLoad<1, 1, "pld">, Requires<[IsARM]>; +defm PLDW : APreLoad<0, 1, "pldw">, Requires<[IsARM,HasV7,HasMP]>; +defm PLI : APreLoad<1, 0, "pli">, Requires<[IsARM,HasV7]>; -def SETENDLE : AXI<(outs),(ins), MiscFrm, NoItinerary, "setend\tle", - [/* For disassembly only; pattern left blank */]>, +def SETEND : AXI<(outs),(ins setend_op:$end), MiscFrm, NoItinerary, + "setend\t$end", + [/* For disassembly only; pattern left blank */]>, Requires<[IsARM]> { - let Inst{31-28} = 0b1111; - let Inst{27-20} = 0b00010000; - let Inst{16} = 1; - let Inst{9} = 0; - let Inst{7-4} = 0b0000; + bits<1> end; + let Inst{31-10} = 0b1111000100000001000000; + let Inst{9} = end; + let Inst{8-0} = 0; } def DBG : AI<(outs), (ins i32imm:$opt), MiscFrm, NoItinerary, "dbg", "\t$opt", [/* For disassembly only; pattern left blank */]>, Requires<[IsARM, HasV7]> { - let Inst{27-16} = 0b001100100000; - let Inst{7-4} = 0b1111; + bits<4> opt; + let Inst{27-4} = 0b001100100000111100001111; + let Inst{3-0} = opt; } // A5.4 Permanently UNDEFINED instructions. -// FIXME: Temporary emitted as raw bytes until this pseudo-op will be added to -// binutils let isBarrier = 1, isTerminator = 1 in -def TRAP : AXI<(outs), (ins), MiscFrm, NoItinerary, - ".long 0xe7ffdefe ${:comment} trap", [(trap)]>, +def TRAP : AXI<(outs), (ins), MiscFrm, NoItinerary, + "trap", [(trap)]>, Requires<[IsARM]> { - let Inst{27-25} = 0b011; - let Inst{24-20} = 0b11111; - let Inst{7-5} = 0b111; - let Inst{4} = 0b1; + let Inst = 0xe7ffdefe; } // Address computation and loads and stores in PIC mode. let isNotDuplicable = 1 in { -def PICADD : AXI1<0b0100, (outs GPR:$dst), (ins GPR:$a, pclabel:$cp, pred:$p), - Pseudo, IIC_iALUr, "\n$cp:\n\tadd$p\t$dst, pc, $a", - [(set GPR:$dst, (ARMpic_add GPR:$a, imm:$cp))]>; +def PICADD : ARMPseudoInst<(outs GPR:$dst), (ins GPR:$a, pclabel:$cp, pred:$p), + Size4Bytes, IIC_iALUr, + [(set GPR:$dst, (ARMpic_add GPR:$a, imm:$cp))]>; let AddedComplexity = 10 in { -def PICLDR : AXI2ldw<(outs GPR:$dst), (ins addrmodepc:$addr, pred:$p), - Pseudo, IIC_iLoadr, "\n${addr:label}:\n\tldr$p\t$dst, $addr", - [(set GPR:$dst, (load addrmodepc:$addr))]>; +def PICLDR : ARMPseudoInst<(outs GPR:$dst), (ins addrmodepc:$addr, pred:$p), + Size4Bytes, IIC_iLoad_r, + [(set GPR:$dst, (load addrmodepc:$addr))]>; -def PICLDRH : AXI3ldh<(outs GPR:$dst), (ins addrmodepc:$addr, pred:$p), - Pseudo, IIC_iLoadr, "\n${addr:label}:\n\tldrh${p}\t$dst, $addr", - [(set GPR:$dst, (zextloadi16 addrmodepc:$addr))]>; +def PICLDRH : ARMPseudoInst<(outs GPR:$Rt), (ins addrmodepc:$addr, pred:$p), + Size4Bytes, IIC_iLoad_bh_r, + [(set GPR:$Rt, (zextloadi16 addrmodepc:$addr))]>; -def PICLDRB : AXI2ldb<(outs GPR:$dst), (ins addrmodepc:$addr, pred:$p), - Pseudo, IIC_iLoadr, "\n${addr:label}:\n\tldrb${p}\t$dst, $addr", - [(set GPR:$dst, (zextloadi8 addrmodepc:$addr))]>; +def PICLDRB : ARMPseudoInst<(outs GPR:$Rt), (ins addrmodepc:$addr, pred:$p), + Size4Bytes, IIC_iLoad_bh_r, + [(set GPR:$Rt, (zextloadi8 addrmodepc:$addr))]>; -def PICLDRSH : AXI3ldsh<(outs GPR:$dst), (ins addrmodepc:$addr, pred:$p), - Pseudo, IIC_iLoadr, "\n${addr:label}:\n\tldrsh${p}\t$dst, $addr", - [(set GPR:$dst, (sextloadi16 addrmodepc:$addr))]>; +def PICLDRSH : ARMPseudoInst<(outs GPR:$Rt), (ins addrmodepc:$addr, pred:$p), + Size4Bytes, IIC_iLoad_bh_r, + [(set GPR:$Rt, (sextloadi16 addrmodepc:$addr))]>; -def PICLDRSB : AXI3ldsb<(outs GPR:$dst), (ins addrmodepc:$addr, pred:$p), - Pseudo, IIC_iLoadr, "\n${addr:label}:\n\tldrsb${p}\t$dst, $addr", - [(set GPR:$dst, (sextloadi8 addrmodepc:$addr))]>; +def PICLDRSB : ARMPseudoInst<(outs GPR:$Rt), (ins addrmodepc:$addr, pred:$p), + Size4Bytes, IIC_iLoad_bh_r, + [(set GPR:$Rt, (sextloadi8 addrmodepc:$addr))]>; } let AddedComplexity = 10 in { -def PICSTR : AXI2stw<(outs), (ins GPR:$src, addrmodepc:$addr, pred:$p), - Pseudo, IIC_iStorer, "\n${addr:label}:\n\tstr$p\t$src, $addr", - [(store GPR:$src, addrmodepc:$addr)]>; +def PICSTR : ARMPseudoInst<(outs), (ins GPR:$src, addrmodepc:$addr, pred:$p), + Size4Bytes, IIC_iStore_r, [(store GPR:$src, addrmodepc:$addr)]>; -def PICSTRH : AXI3sth<(outs), (ins GPR:$src, addrmodepc:$addr, pred:$p), - Pseudo, IIC_iStorer, "\n${addr:label}:\n\tstrh${p}\t$src, $addr", - [(truncstorei16 GPR:$src, addrmodepc:$addr)]>; +def PICSTRH : ARMPseudoInst<(outs), (ins GPR:$src, addrmodepc:$addr, pred:$p), + Size4Bytes, IIC_iStore_bh_r, [(truncstorei16 GPR:$src, + addrmodepc:$addr)]>; -def PICSTRB : AXI2stb<(outs), (ins GPR:$src, addrmodepc:$addr, pred:$p), - Pseudo, IIC_iStorer, "\n${addr:label}:\n\tstrb${p}\t$src, $addr", - [(truncstorei8 GPR:$src, addrmodepc:$addr)]>; +def PICSTRB : ARMPseudoInst<(outs), (ins GPR:$src, addrmodepc:$addr, pred:$p), + Size4Bytes, IIC_iStore_bh_r, [(truncstorei8 GPR:$src, addrmodepc:$addr)]>; } } // isNotDuplicable = 1 // LEApcrel - Load a pc-relative address into a register without offending the // assembler. -let neverHasSideEffects = 1 in { -let isReMaterializable = 1 in -def LEApcrel : AXI1<0x0, (outs GPR:$dst), (ins i32imm:$label, pred:$p), - Pseudo, IIC_iALUi, - "adr$p\t$dst, #$label", []>; - -} // neverHasSideEffects -def LEApcrelJT : AXI1<0x0, (outs GPR:$dst), - (ins i32imm:$label, nohash_imm:$id, pred:$p), - Pseudo, IIC_iALUi, - "adr$p\t$dst, #${label}_${id}", []> { - let Inst{25} = 1; +let neverHasSideEffects = 1, isReMaterializable = 1 in +// The 'adr' mnemonic encodes differently if the label is before or after +// the instruction. The {24-21} opcode bits are set by the fixup, as we don't +// know until then which form of the instruction will be used. +def ADR : AI1<0, (outs GPR:$Rd), (ins adrlabel:$label), + MiscFrm, IIC_iALUi, "adr", "\t$Rd, #$label", []> { + bits<4> Rd; + bits<12> label; + let Inst{27-25} = 0b001; + let Inst{20} = 0; + let Inst{19-16} = 0b1111; + let Inst{15-12} = Rd; + let Inst{11-0} = label; } +def LEApcrel : ARMPseudoInst<(outs GPR:$Rd), (ins i32imm:$label, pred:$p), + Size4Bytes, IIC_iALUi, []>; + +def LEApcrelJT : ARMPseudoInst<(outs GPR:$Rd), + (ins i32imm:$label, nohash_imm:$id, pred:$p), + Size4Bytes, IIC_iALUi, []>; //===----------------------------------------------------------------------===// // Control Flow Instructions. @@ -893,159 +1273,139 @@ let isReturn = 1, isTerminator = 1, isBarrier = 1 in { def BX_RET : AI<(outs), (ins), BrMiscFrm, IIC_Br, "bx", "\tlr", [(ARMretflag)]>, Requires<[IsARM, HasV4T]> { - let Inst{3-0} = 0b1110; - let Inst{7-4} = 0b0001; - let Inst{19-8} = 0b111111111111; - let Inst{27-20} = 0b00010010; + let Inst{27-0} = 0b0001001011111111111100011110; } // ARMV4 only - def MOVPCLR : AI<(outs), (ins), BrMiscFrm, IIC_Br, + def MOVPCLR : AI<(outs), (ins), BrMiscFrm, IIC_Br, "mov", "\tpc, lr", [(ARMretflag)]>, Requires<[IsARM, NoV4T]> { - let Inst{11-0} = 0b000000001110; - let Inst{15-12} = 0b1111; - let Inst{19-16} = 0b0000; - let Inst{27-20} = 0b00011010; + let Inst{27-0} = 0b0001101000001111000000001110; } } // Indirect branches let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in { // ARMV4T and above - def BRIND : AXI<(outs), (ins GPR:$dst), BrMiscFrm, IIC_Br, "bx\t$dst", + def BX : AXI<(outs), (ins GPR:$dst), BrMiscFrm, IIC_Br, "bx\t$dst", [(brind GPR:$dst)]>, Requires<[IsARM, HasV4T]> { - let Inst{7-4} = 0b0001; - let Inst{19-8} = 0b111111111111; - let Inst{27-20} = 0b00010010; - let Inst{31-28} = 0b1110; + bits<4> dst; + let Inst{31-4} = 0b1110000100101111111111110001; + let Inst{3-0} = dst; } // ARMV4 only - def MOVPCRX : AXI<(outs), (ins GPR:$dst), BrMiscFrm, IIC_Br, "mov\tpc, $dst", - [(brind GPR:$dst)]>, - Requires<[IsARM, NoV4T]> { - let Inst{11-4} = 0b00000000; - let Inst{15-12} = 0b1111; - let Inst{19-16} = 0b0000; - let Inst{27-20} = 0b00011010; - let Inst{31-28} = 0b1110; - } + // FIXME: We would really like to define this as a vanilla ARMPat like: + // ARMPat<(brind GPR:$dst), (MOVr PC, GPR:$dst)> + // With that, however, we can't set isBranch, isTerminator, etc.. + def MOVPCRX : ARMPseudoInst<(outs), (ins GPR:$dst), + Size4Bytes, IIC_Br, [(brind GPR:$dst)]>, + Requires<[IsARM, NoV4T]>; } -// FIXME: remove when we have a way to marking a MI with these properties. -// FIXME: Should pc be an implicit operand like PICADD, etc? -let isReturn = 1, isTerminator = 1, isBarrier = 1, mayLoad = 1, - hasExtraDefRegAllocReq = 1 in - def LDM_RET : AXI4ld<(outs GPR:$wb), (ins addrmode4:$addr, pred:$p, - reglist:$dsts, variable_ops), - IndexModeUpd, LdStMulFrm, IIC_Br, - "ldm${addr:submode}${p}\t$addr!, $dsts", - "$addr.addr = $wb", []>; - -// On non-Darwin platforms R9 is callee-saved. +// All calls clobber the non-callee saved registers. SP is marked as +// a use to prevent stack-pointer assignments that appear immediately +// before calls from potentially appearing dead. let isCall = 1, + // On non-Darwin platforms R9 is callee-saved. Defs = [R0, R1, R2, R3, R12, LR, D0, D1, D2, D3, D4, D5, D6, D7, D16, D17, D18, D19, D20, D21, D22, D23, - D24, D25, D26, D27, D28, D29, D30, D31, CPSR, FPSCR] in { - def BL : ABXI<0b1011, (outs), (ins i32imm:$func, variable_ops), - IIC_Br, "bl\t${func:call}", + D24, D25, D26, D27, D28, D29, D30, D31, CPSR, FPSCR], + Uses = [SP] in { + def BL : ABXI<0b1011, (outs), (ins bl_target:$func, variable_ops), + IIC_Br, "bl\t$func", [(ARMcall tglobaladdr:$func)]>, Requires<[IsARM, IsNotDarwin]> { let Inst{31-28} = 0b1110; + bits<24> func; + let Inst{23-0} = func; } - def BL_pred : ABI<0b1011, (outs), (ins i32imm:$func, variable_ops), - IIC_Br, "bl", "\t${func:call}", + def BL_pred : ABI<0b1011, (outs), (ins bl_target:$func, variable_ops), + IIC_Br, "bl", "\t$func", [(ARMcall_pred tglobaladdr:$func)]>, - Requires<[IsARM, IsNotDarwin]>; + Requires<[IsARM, IsNotDarwin]> { + bits<24> func; + let Inst{23-0} = func; + } // ARMv5T and above def BLX : AXI<(outs), (ins GPR:$func, variable_ops), BrMiscFrm, IIC_Br, "blx\t$func", [(ARMcall GPR:$func)]>, Requires<[IsARM, HasV5T, IsNotDarwin]> { - let Inst{7-4} = 0b0011; - let Inst{19-8} = 0b111111111111; - let Inst{27-20} = 0b00010010; + bits<4> func; + let Inst{31-4} = 0b1110000100101111111111110011; + let Inst{3-0} = func; } // ARMv4T // Note: Restrict $func to the tGPR regclass to prevent it being in LR. - def BX : ABXIx2<(outs), (ins tGPR:$func, variable_ops), - IIC_Br, "mov\tlr, pc\n\tbx\t$func", - [(ARMcall_nolink tGPR:$func)]>, - Requires<[IsARM, HasV4T, IsNotDarwin]> { - let Inst{7-4} = 0b0001; - let Inst{19-8} = 0b111111111111; - let Inst{27-20} = 0b00010010; - } + def BX_CALL : ARMPseudoInst<(outs), (ins tGPR:$func, variable_ops), + Size8Bytes, IIC_Br, [(ARMcall_nolink tGPR:$func)]>, + Requires<[IsARM, HasV4T, IsNotDarwin]>; // ARMv4 - def BMOVPCRX : ABXIx2<(outs), (ins tGPR:$func, variable_ops), - IIC_Br, "mov\tlr, pc\n\tmov\tpc, $func", - [(ARMcall_nolink tGPR:$func)]>, - Requires<[IsARM, NoV4T, IsNotDarwin]> { - let Inst{11-4} = 0b00000000; - let Inst{15-12} = 0b1111; - let Inst{19-16} = 0b0000; - let Inst{27-20} = 0b00011010; - } + def BMOVPCRX_CALL : ARMPseudoInst<(outs), (ins tGPR:$func, variable_ops), + Size8Bytes, IIC_Br, [(ARMcall_nolink tGPR:$func)]>, + Requires<[IsARM, NoV4T, IsNotDarwin]>; } -// On Darwin R9 is call-clobbered. let isCall = 1, + // On Darwin R9 is call-clobbered. + // R7 is marked as a use to prevent frame-pointer assignments from being + // moved above / below calls. Defs = [R0, R1, R2, R3, R9, R12, LR, D0, D1, D2, D3, D4, D5, D6, D7, D16, D17, D18, D19, D20, D21, D22, D23, - D24, D25, D26, D27, D28, D29, D30, D31, CPSR, FPSCR] in { - def BLr9 : ABXI<0b1011, (outs), (ins i32imm:$func, variable_ops), - IIC_Br, "bl\t${func:call}", + D24, D25, D26, D27, D28, D29, D30, D31, CPSR, FPSCR], + Uses = [R7, SP] in { + def BLr9 : ABXI<0b1011, (outs), (ins bltarget:$func, variable_ops), + IIC_Br, "bl\t$func", [(ARMcall tglobaladdr:$func)]>, Requires<[IsARM, IsDarwin]> { let Inst{31-28} = 0b1110; + bits<24> func; + let Inst{23-0} = func; } - def BLr9_pred : ABI<0b1011, (outs), (ins i32imm:$func, variable_ops), - IIC_Br, "bl", "\t${func:call}", + def BLr9_pred : ABI<0b1011, (outs), (ins bltarget:$func, variable_ops), + IIC_Br, "bl", "\t$func", [(ARMcall_pred tglobaladdr:$func)]>, - Requires<[IsARM, IsDarwin]>; + Requires<[IsARM, IsDarwin]> { + bits<24> func; + let Inst{23-0} = func; + } // ARMv5T and above def BLXr9 : AXI<(outs), (ins GPR:$func, variable_ops), BrMiscFrm, IIC_Br, "blx\t$func", [(ARMcall GPR:$func)]>, Requires<[IsARM, HasV5T, IsDarwin]> { - let Inst{7-4} = 0b0011; - let Inst{19-8} = 0b111111111111; - let Inst{27-20} = 0b00010010; + bits<4> func; + let Inst{31-4} = 0b1110000100101111111111110011; + let Inst{3-0} = func; } // ARMv4T // Note: Restrict $func to the tGPR regclass to prevent it being in LR. - def BXr9 : ABXIx2<(outs), (ins tGPR:$func, variable_ops), - IIC_Br, "mov\tlr, pc\n\tbx\t$func", - [(ARMcall_nolink tGPR:$func)]>, - Requires<[IsARM, HasV4T, IsDarwin]> { - let Inst{7-4} = 0b0001; - let Inst{19-8} = 0b111111111111; - let Inst{27-20} = 0b00010010; - } + def BXr9_CALL : ARMPseudoInst<(outs), (ins tGPR:$func, variable_ops), + Size8Bytes, IIC_Br, [(ARMcall_nolink tGPR:$func)]>, + Requires<[IsARM, HasV4T, IsDarwin]>; // ARMv4 - def BMOVPCRXr9 : ABXIx2<(outs), (ins tGPR:$func, variable_ops), - IIC_Br, "mov\tlr, pc\n\tmov\tpc, $func", - [(ARMcall_nolink tGPR:$func)]>, - Requires<[IsARM, NoV4T, IsDarwin]> { - let Inst{11-4} = 0b00000000; - let Inst{15-12} = 0b1111; - let Inst{19-16} = 0b0000; - let Inst{27-20} = 0b00011010; - } + def BMOVPCRXr9_CALL : ARMPseudoInst<(outs), (ins tGPR:$func, variable_ops), + Size8Bytes, IIC_Br, [(ARMcall_nolink tGPR:$func)]>, + Requires<[IsARM, NoV4T, IsDarwin]>; } // Tail calls. +// FIXME: These should probably be xformed into the non-TC versions of the +// instructions as part of MC lowering. +// FIXME: These seem to be used for both Thumb and ARM instruction selection. +// Thumb should have its own version since the instruction is actually +// different, even though the mnemonic is the same. let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in { // Darwin versions. let Defs = [R0, R1, R2, R3, R9, R12, @@ -1053,29 +1413,26 @@ let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in { D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, D30, D31, PC], Uses = [SP] in { - def TCRETURNdi : AInoP<(outs), (ins i32imm:$dst, variable_ops), - Pseudo, IIC_Br, - "@TC_RETURN","\t$dst", []>, Requires<[IsDarwin]>; + def TCRETURNdi : PseudoInst<(outs), (ins i32imm:$dst, variable_ops), + IIC_Br, []>, Requires<[IsDarwin]>; - def TCRETURNri : AInoP<(outs), (ins tcGPR:$dst, variable_ops), - Pseudo, IIC_Br, - "@TC_RETURN","\t$dst", []>, Requires<[IsDarwin]>; + def TCRETURNri : PseudoInst<(outs), (ins tcGPR:$dst, variable_ops), + IIC_Br, []>, Requires<[IsDarwin]>; def TAILJMPd : ABXI<0b1010, (outs), (ins brtarget:$dst, variable_ops), IIC_Br, "b\t$dst @ TAILCALL", - []>, Requires<[IsDarwin]>; + []>, Requires<[IsARM, IsDarwin]>; def TAILJMPdt: ABXI<0b1010, (outs), (ins brtarget:$dst, variable_ops), IIC_Br, "b.w\t$dst @ TAILCALL", - []>, Requires<[IsDarwin]>; + []>, Requires<[IsThumb, IsDarwin]>; def TAILJMPr : AXI<(outs), (ins tcGPR:$dst, variable_ops), BrMiscFrm, IIC_Br, "bx\t$dst @ TAILCALL", []>, Requires<[IsDarwin]> { - let Inst{7-4} = 0b0001; - let Inst{19-8} = 0b111111111111; - let Inst{27-20} = 0b00010010; - let Inst{31-28} = 0b1110; + bits<4> dst; + let Inst{31-4} = 0b1110000100101111111111110001; + let Inst{3-0} = dst; } } @@ -1085,13 +1442,11 @@ let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in { D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, D30, D31, PC], Uses = [SP] in { - def TCRETURNdiND : AInoP<(outs), (ins i32imm:$dst, variable_ops), - Pseudo, IIC_Br, - "@TC_RETURN","\t$dst", []>, Requires<[IsNotDarwin]>; + def TCRETURNdiND : PseudoInst<(outs), (ins i32imm:$dst, variable_ops), + IIC_Br, []>, Requires<[IsNotDarwin]>; - def TCRETURNriND : AInoP<(outs), (ins tcGPR:$dst, variable_ops), - Pseudo, IIC_Br, - "@TC_RETURN","\t$dst", []>, Requires<[IsNotDarwin]>; + def TCRETURNriND : PseudoInst<(outs), (ins tcGPR:$dst, variable_ops), + IIC_Br, []>, Requires<[IsNotDarwin]>; def TAILJMPdND : ABXI<0b1010, (outs), (ins brtarget:$dst, variable_ops), IIC_Br, "b\t$dst @ TAILCALL", @@ -1104,10 +1459,9 @@ let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in { def TAILJMPrND : AXI<(outs), (ins tcGPR:$dst, variable_ops), BrMiscFrm, IIC_Br, "bx\t$dst @ TAILCALL", []>, Requires<[IsNotDarwin]> { - let Inst{7-4} = 0b0001; - let Inst{19-8} = 0b111111111111; - let Inst{27-20} = 0b00010010; - let Inst{31-28} = 0b1110; + bits<4> dst; + let Inst{31-4} = 0b1110000100101111111111110001; + let Inst{3-0} = dst; } } } @@ -1117,48 +1471,40 @@ let isBranch = 1, isTerminator = 1 in { let isBarrier = 1 in { let isPredicable = 1 in def B : ABXI<0b1010, (outs), (ins brtarget:$target), IIC_Br, - "b\t$target", [(br bb:$target)]>; + "b\t$target", [(br bb:$target)]> { + bits<24> target; + let Inst{31-28} = 0b1110; + let Inst{23-0} = target; + } - let isNotDuplicable = 1, isIndirectBranch = 1 in { - def BR_JTr : JTI<(outs), (ins GPR:$target, jtblock_operand:$jt, i32imm:$id), - IIC_Br, "mov\tpc, $target$jt", - [(ARMbrjt GPR:$target, tjumptable:$jt, imm:$id)]> { - let Inst{11-4} = 0b00000000; - let Inst{15-12} = 0b1111; - let Inst{20} = 0; // S Bit - let Inst{24-21} = 0b1101; - let Inst{27-25} = 0b000; - } - def BR_JTm : JTI<(outs), - (ins addrmode2:$target, jtblock_operand:$jt, i32imm:$id), - IIC_Br, "ldr\tpc, $target$jt", - [(ARMbrjt (i32 (load addrmode2:$target)), tjumptable:$jt, - imm:$id)]> { - let Inst{15-12} = 0b1111; - let Inst{20} = 1; // L bit - let Inst{21} = 0; // W bit - let Inst{22} = 0; // B bit - let Inst{24} = 1; // P bit - let Inst{27-25} = 0b011; - } - def BR_JTadd : JTI<(outs), - (ins GPR:$target, GPR:$idx, jtblock_operand:$jt, i32imm:$id), - IIC_Br, "add\tpc, $target, $idx$jt", - [(ARMbrjt (add GPR:$target, GPR:$idx), tjumptable:$jt, - imm:$id)]> { - let Inst{15-12} = 0b1111; - let Inst{20} = 0; // S bit - let Inst{24-21} = 0b0100; - let Inst{27-25} = 0b000; - } - } // isNotDuplicable = 1, isIndirectBranch = 1 + let isNotDuplicable = 1, isIndirectBranch = 1 in { + def BR_JTr : ARMPseudoInst<(outs), + (ins GPR:$target, i32imm:$jt, i32imm:$id), + SizeSpecial, IIC_Br, + [(ARMbrjt GPR:$target, tjumptable:$jt, imm:$id)]>; + // FIXME: This shouldn't use the generic "addrmode2," but rather be split + // into i12 and rs suffixed versions. + def BR_JTm : ARMPseudoInst<(outs), + (ins addrmode2:$target, i32imm:$jt, i32imm:$id), + SizeSpecial, IIC_Br, + [(ARMbrjt (i32 (load addrmode2:$target)), tjumptable:$jt, + imm:$id)]>; + def BR_JTadd : ARMPseudoInst<(outs), + (ins GPR:$target, GPR:$idx, i32imm:$jt, i32imm:$id), + SizeSpecial, IIC_Br, + [(ARMbrjt (add GPR:$target, GPR:$idx), tjumptable:$jt, + imm:$id)]>; + } // isNotDuplicable = 1, isIndirectBranch = 1 } // isBarrier = 1 // FIXME: should be able to write a pattern for ARMBrcond, but can't use // a two-value operand where a dag node expects two operands. :( - def Bcc : ABI<0b1010, (outs), (ins brtarget:$target), + def Bcc : ABI<0b1010, (outs), (ins br_target:$target), IIC_Br, "b", "\t$target", - [/*(ARMbrcond bb:$target, imm:$cc, CCR:$ccr)*/]>; + [/*(ARMbrcond bb:$target, imm:$cc, CCR:$ccr)*/]> { + bits<24> target; + let Inst{23-0} = target; + } } // Branch and Exchange Jazelle -- for disassembly only @@ -1172,271 +1518,303 @@ def BXJ : ABI<0b0001, (outs), (ins GPR:$func), NoItinerary, "bxj", "\t$func", // Secure Monitor Call is a system instruction -- for disassembly only def SMC : ABI<0b0001, (outs), (ins i32imm:$opt), NoItinerary, "smc", "\t$opt", [/* For disassembly only; pattern left blank */]> { - let Inst{23-20} = 0b0110; - let Inst{7-4} = 0b0111; + bits<4> opt; + let Inst{23-4} = 0b01100000000000000111; + let Inst{3-0} = opt; } // Supervisor Call (Software Interrupt) -- for disassembly only -let isCall = 1 in { +let isCall = 1, Uses = [SP] in { def SVC : ABI<0b1111, (outs), (ins i32imm:$svc), IIC_Br, "svc", "\t$svc", - [/* For disassembly only; pattern left blank */]>; + [/* For disassembly only; pattern left blank */]> { + bits<24> svc; + let Inst{23-0} = svc; +} } // Store Return State is a system instruction -- for disassembly only -def SRSW : ABXI<{1,0,0,?}, (outs), (ins addrmode4:$addr, i32imm:$mode), - NoItinerary, "srs${addr:submode}\tsp!, $mode", +let isCodeGenOnly = 1 in { // FIXME: This should not use submode! +def SRSW : ABXI<{1,0,0,?}, (outs), (ins ldstm_mode:$amode, i32imm:$mode), + NoItinerary, "srs${amode}\tsp!, $mode", [/* For disassembly only; pattern left blank */]> { let Inst{31-28} = 0b1111; let Inst{22-20} = 0b110; // W = 1 } -def SRS : ABXI<{1,0,0,?}, (outs), (ins addrmode4:$addr, i32imm:$mode), - NoItinerary, "srs${addr:submode}\tsp, $mode", +def SRS : ABXI<{1,0,0,?}, (outs), (ins ldstm_mode:$amode, i32imm:$mode), + NoItinerary, "srs${amode}\tsp, $mode", [/* For disassembly only; pattern left blank */]> { let Inst{31-28} = 0b1111; let Inst{22-20} = 0b100; // W = 0 } // Return From Exception is a system instruction -- for disassembly only -def RFEW : ABXI<{1,0,0,?}, (outs), (ins addrmode4:$addr, GPR:$base), - NoItinerary, "rfe${addr:submode}\t$base!", +def RFEW : ABXI<{1,0,0,?}, (outs), (ins ldstm_mode:$amode, GPR:$base), + NoItinerary, "rfe${amode}\t$base!", [/* For disassembly only; pattern left blank */]> { let Inst{31-28} = 0b1111; let Inst{22-20} = 0b011; // W = 1 } -def RFE : ABXI<{1,0,0,?}, (outs), (ins addrmode4:$addr, GPR:$base), - NoItinerary, "rfe${addr:submode}\t$base", +def RFE : ABXI<{1,0,0,?}, (outs), (ins ldstm_mode:$amode, GPR:$base), + NoItinerary, "rfe${amode}\t$base", [/* For disassembly only; pattern left blank */]> { let Inst{31-28} = 0b1111; let Inst{22-20} = 0b001; // W = 0 } +} // isCodeGenOnly = 1 //===----------------------------------------------------------------------===// // Load / store Instructions. // // Load -let canFoldAsLoad = 1, isReMaterializable = 1 in -def LDR : AI2ldw<(outs GPR:$dst), (ins addrmode2:$addr), LdFrm, IIC_iLoadr, - "ldr", "\t$dst, $addr", - [(set GPR:$dst, (load addrmode2:$addr))]>; + + +defm LDR : AI_ldr1<0, "ldr", IIC_iLoad_r, IIC_iLoad_si, + UnOpFrag<(load node:$Src)>>; +defm LDRB : AI_ldr1<1, "ldrb", IIC_iLoad_bh_r, IIC_iLoad_bh_si, + UnOpFrag<(zextloadi8 node:$Src)>>; +defm STR : AI_str1<0, "str", IIC_iStore_r, IIC_iStore_si, + BinOpFrag<(store node:$LHS, node:$RHS)>>; +defm STRB : AI_str1<1, "strb", IIC_iStore_bh_r, IIC_iStore_bh_si, + BinOpFrag<(truncstorei8 node:$LHS, node:$RHS)>>; // Special LDR for loads from non-pc-relative constpools. let canFoldAsLoad = 1, mayLoad = 1, neverHasSideEffects = 1, isReMaterializable = 1 in -def LDRcp : AI2ldw<(outs GPR:$dst), (ins addrmode2:$addr), LdFrm, IIC_iLoadr, - "ldr", "\t$dst, $addr", []>; +def LDRcp : AI2ldst<0b010, 1, 0, (outs GPR:$Rt), (ins addrmode_imm12:$addr), + AddrMode_i12, LdFrm, IIC_iLoad_r, "ldr", "\t$Rt, $addr", + []> { + bits<4> Rt; + bits<17> addr; + let Inst{23} = addr{12}; // U (add = ('U' == 1)) + let Inst{19-16} = 0b1111; + let Inst{15-12} = Rt; + let Inst{11-0} = addr{11-0}; // imm12 +} // Loads with zero extension -def LDRH : AI3ldh<(outs GPR:$dst), (ins addrmode3:$addr), LdMiscFrm, - IIC_iLoadr, "ldrh", "\t$dst, $addr", - [(set GPR:$dst, (zextloadi16 addrmode3:$addr))]>; - -def LDRB : AI2ldb<(outs GPR:$dst), (ins addrmode2:$addr), LdFrm, - IIC_iLoadr, "ldrb", "\t$dst, $addr", - [(set GPR:$dst, (zextloadi8 addrmode2:$addr))]>; +def LDRH : AI3ld<0b1011, 1, (outs GPR:$Rt), (ins addrmode3:$addr), LdMiscFrm, + IIC_iLoad_bh_r, "ldrh", "\t$Rt, $addr", + [(set GPR:$Rt, (zextloadi16 addrmode3:$addr))]>; // Loads with sign extension -def LDRSH : AI3ldsh<(outs GPR:$dst), (ins addrmode3:$addr), LdMiscFrm, - IIC_iLoadr, "ldrsh", "\t$dst, $addr", - [(set GPR:$dst, (sextloadi16 addrmode3:$addr))]>; - -def LDRSB : AI3ldsb<(outs GPR:$dst), (ins addrmode3:$addr), LdMiscFrm, - IIC_iLoadr, "ldrsb", "\t$dst, $addr", - [(set GPR:$dst, (sextloadi8 addrmode3:$addr))]>; - -let mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1 in { +def LDRSH : AI3ld<0b1111, 1, (outs GPR:$Rt), (ins addrmode3:$addr), LdMiscFrm, + IIC_iLoad_bh_r, "ldrsh", "\t$Rt, $addr", + [(set GPR:$Rt, (sextloadi16 addrmode3:$addr))]>; + +def LDRSB : AI3ld<0b1101, 1, (outs GPR:$Rt), (ins addrmode3:$addr), LdMiscFrm, + IIC_iLoad_bh_r, "ldrsb", "\t$Rt, $addr", + [(set GPR:$Rt, (sextloadi8 addrmode3:$addr))]>; + +let mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1, + isCodeGenOnly = 1 in { // $dst2 doesn't exist in asmstring? +// FIXME: $dst2 isn't in the asm string as it's implied by $Rd (dst2 = Rd+1) +// how to represent that such that tblgen is happy and we don't +// mark this codegen only? // Load doubleword -def LDRD : AI3ldd<(outs GPR:$dst1, GPR:$dst2), (ins addrmode3:$addr), LdMiscFrm, - IIC_iLoadr, "ldrd", "\t$dst1, $addr", +def LDRD : AI3ld<0b1101, 0, (outs GPR:$Rd, GPR:$dst2), + (ins addrmode3:$addr), LdMiscFrm, + IIC_iLoad_d_r, "ldrd", "\t$Rd, $addr", []>, Requires<[IsARM, HasV5TE]>; +} // Indexed loads -def LDR_PRE : AI2ldwpr<(outs GPR:$dst, GPR:$base_wb), - (ins addrmode2:$addr), LdFrm, IIC_iLoadru, - "ldr", "\t$dst, $addr!", "$addr.base = $base_wb", []>; - -def LDR_POST : AI2ldwpo<(outs GPR:$dst, GPR:$base_wb), - (ins GPR:$base, am2offset:$offset), LdFrm, IIC_iLoadru, - "ldr", "\t$dst, [$base], $offset", "$base = $base_wb", []>; - -def LDRH_PRE : AI3ldhpr<(outs GPR:$dst, GPR:$base_wb), - (ins addrmode3:$addr), LdMiscFrm, IIC_iLoadru, - "ldrh", "\t$dst, $addr!", "$addr.base = $base_wb", []>; - -def LDRH_POST : AI3ldhpo<(outs GPR:$dst, GPR:$base_wb), - (ins GPR:$base,am3offset:$offset), LdMiscFrm, IIC_iLoadru, - "ldrh", "\t$dst, [$base], $offset", "$base = $base_wb", []>; - -def LDRB_PRE : AI2ldbpr<(outs GPR:$dst, GPR:$base_wb), - (ins addrmode2:$addr), LdFrm, IIC_iLoadru, - "ldrb", "\t$dst, $addr!", "$addr.base = $base_wb", []>; - -def LDRB_POST : AI2ldbpo<(outs GPR:$dst, GPR:$base_wb), - (ins GPR:$base,am2offset:$offset), LdFrm, IIC_iLoadru, - "ldrb", "\t$dst, [$base], $offset", "$base = $base_wb", []>; - -def LDRSH_PRE : AI3ldshpr<(outs GPR:$dst, GPR:$base_wb), - (ins addrmode3:$addr), LdMiscFrm, IIC_iLoadru, - "ldrsh", "\t$dst, $addr!", "$addr.base = $base_wb", []>; - -def LDRSH_POST: AI3ldshpo<(outs GPR:$dst, GPR:$base_wb), - (ins GPR:$base,am3offset:$offset), LdMiscFrm, IIC_iLoadru, - "ldrsh", "\t$dst, [$base], $offset", "$base = $base_wb", []>; - -def LDRSB_PRE : AI3ldsbpr<(outs GPR:$dst, GPR:$base_wb), - (ins addrmode3:$addr), LdMiscFrm, IIC_iLoadru, - "ldrsb", "\t$dst, $addr!", "$addr.base = $base_wb", []>; - -def LDRSB_POST: AI3ldsbpo<(outs GPR:$dst, GPR:$base_wb), - (ins GPR:$base,am3offset:$offset), LdMiscFrm, IIC_iLoadru, - "ldrsb", "\t$dst, [$base], $offset", "$base = $base_wb", []>; +multiclass AI2_ldridx { + def _PRE : AI2ldstidx<1, isByte, 1, (outs GPR:$Rt, GPR:$Rn_wb), + (ins addrmode2:$addr), IndexModePre, LdFrm, itin, + opc, "\t$Rt, $addr!", "$addr.base = $Rn_wb", []> { + // {17-14} Rn + // {13} 1 == Rm, 0 == imm12 + // {12} isAdd + // {11-0} imm12/Rm + bits<18> addr; + let Inst{25} = addr{13}; + let Inst{23} = addr{12}; + let Inst{19-16} = addr{17-14}; + let Inst{11-0} = addr{11-0}; + } + def _POST : AI2ldstidx<1, isByte, 0, (outs GPR:$Rt, GPR:$Rn_wb), + (ins GPR:$Rn, am2offset:$offset), + IndexModePost, LdFrm, itin, + opc, "\t$Rt, [$Rn], $offset", "$Rn = $Rn_wb", []> { + // {13} 1 == Rm, 0 == imm12 + // {12} isAdd + // {11-0} imm12/Rm + bits<14> offset; + bits<4> Rn; + let Inst{25} = offset{13}; + let Inst{23} = offset{12}; + let Inst{19-16} = Rn; + let Inst{11-0} = offset{11-0}; + } +} -// For disassembly only -def LDRD_PRE : AI3lddpr<(outs GPR:$dst1, GPR:$dst2, GPR:$base_wb), - (ins addrmode3:$addr), LdMiscFrm, IIC_iLoadr, - "ldrd", "\t$dst1, $dst2, $addr!", "$addr.base = $base_wb", []>, - Requires<[IsARM, HasV5TE]>; +let mayLoad = 1, neverHasSideEffects = 1 in { +defm LDR : AI2_ldridx<0, "ldr", IIC_iLoad_ru>; +defm LDRB : AI2_ldridx<1, "ldrb", IIC_iLoad_bh_ru>; +} -// For disassembly only -def LDRD_POST : AI3lddpo<(outs GPR:$dst1, GPR:$dst2, GPR:$base_wb), - (ins GPR:$base,am3offset:$offset), LdMiscFrm, IIC_iLoadr, - "ldrd", "\t$dst1, $dst2, [$base], $offset", "$base = $base_wb", []>, - Requires<[IsARM, HasV5TE]>; +multiclass AI3_ldridx op, bit op20, string opc, InstrItinClass itin> { + def _PRE : AI3ldstidx { + bits<14> addr; + let Inst{23} = addr{8}; // U bit + let Inst{22} = addr{13}; // 1 == imm8, 0 == Rm + let Inst{19-16} = addr{12-9}; // Rn + let Inst{11-8} = addr{7-4}; // imm7_4/zero + let Inst{3-0} = addr{3-0}; // imm3_0/Rm + } + def _POST : AI3ldstidx { + bits<10> offset; + bits<4> Rn; + let Inst{23} = offset{8}; // U bit + let Inst{22} = offset{9}; // 1 == imm8, 0 == Rm + let Inst{19-16} = Rn; + let Inst{11-8} = offset{7-4}; // imm7_4/zero + let Inst{3-0} = offset{3-0}; // imm3_0/Rm + } +} -} // mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1 +let mayLoad = 1, neverHasSideEffects = 1 in { +defm LDRH : AI3_ldridx<0b1011, 1, "ldrh", IIC_iLoad_bh_ru>; +defm LDRSH : AI3_ldridx<0b1111, 1, "ldrsh", IIC_iLoad_bh_ru>; +defm LDRSB : AI3_ldridx<0b1101, 1, "ldrsb", IIC_iLoad_bh_ru>; +let hasExtraDefRegAllocReq = 1, isCodeGenOnly = 1 in +defm LDRD : AI3_ldridx<0b1101, 0, "ldrd", IIC_iLoad_d_ru>; +} // mayLoad = 1, neverHasSideEffects = 1 // LDRT, LDRBT, LDRSBT, LDRHT, LDRSHT are for disassembly only. - -def LDRT : AI2ldwpo<(outs GPR:$dst, GPR:$base_wb), - (ins GPR:$base, am2offset:$offset), LdFrm, IIC_iLoadru, +let mayLoad = 1, neverHasSideEffects = 1 in { +def LDRT : AI2ldstidx<1, 0, 0, (outs GPR:$dst, GPR:$base_wb), + (ins GPR:$base, am2offset:$offset), IndexModeNone, + LdFrm, IIC_iLoad_ru, "ldrt", "\t$dst, [$base], $offset", "$base = $base_wb", []> { let Inst{21} = 1; // overwrite } - -def LDRBT : AI2ldbpo<(outs GPR:$dst, GPR:$base_wb), - (ins GPR:$base,am2offset:$offset), LdFrm, IIC_iLoadru, +def LDRBT : AI2ldstidx<1, 1, 0, (outs GPR:$dst, GPR:$base_wb), + (ins GPR:$base, am2offset:$offset), IndexModeNone, + LdFrm, IIC_iLoad_bh_ru, "ldrbt", "\t$dst, [$base], $offset", "$base = $base_wb", []> { let Inst{21} = 1; // overwrite } - -def LDRSBT : AI3ldsbpo<(outs GPR:$dst, GPR:$base_wb), - (ins GPR:$base,am3offset:$offset), LdMiscFrm, IIC_iLoadru, +def LDRSBT : AI3ldstidx<0b1101, 1, 1, 0, (outs GPR:$dst, GPR:$base_wb), + (ins GPR:$base, am3offset:$offset), IndexModePost, + LdMiscFrm, IIC_iLoad_bh_ru, "ldrsbt", "\t$dst, [$base], $offset", "$base = $base_wb", []> { let Inst{21} = 1; // overwrite } - -def LDRHT : AI3ldhpo<(outs GPR:$dst, GPR:$base_wb), - (ins GPR:$base, am3offset:$offset), LdMiscFrm, IIC_iLoadru, - "ldrht", "\t$dst, [$base], $offset", "$base = $base_wb", []> { +def LDRHT : AI3ldstidx<0b1011, 1, 1, 0, (outs GPR:$dst, GPR:$base_wb), + (ins GPR:$base, am3offset:$offset), IndexModePost, + LdMiscFrm, IIC_iLoad_bh_ru, + "ldrht", "\t$dst, [$base], $offset", "$base = $base_wb", []> { let Inst{21} = 1; // overwrite } - -def LDRSHT : AI3ldshpo<(outs GPR:$dst, GPR:$base_wb), - (ins GPR:$base,am3offset:$offset), LdMiscFrm, IIC_iLoadru, +def LDRSHT : AI3ldstidx<0b1111, 1, 1, 0, (outs GPR:$dst, GPR:$base_wb), + (ins GPR:$base, am3offset:$offset), IndexModePost, + LdMiscFrm, IIC_iLoad_bh_ru, "ldrsht", "\t$dst, [$base], $offset", "$base = $base_wb", []> { let Inst{21} = 1; // overwrite } +} // Store -def STR : AI2stw<(outs), (ins GPR:$src, addrmode2:$addr), StFrm, IIC_iStorer, - "str", "\t$src, $addr", - [(store GPR:$src, addrmode2:$addr)]>; // Stores with truncate -def STRH : AI3sth<(outs), (ins GPR:$src, addrmode3:$addr), StMiscFrm, - IIC_iStorer, "strh", "\t$src, $addr", - [(truncstorei16 GPR:$src, addrmode3:$addr)]>; - -def STRB : AI2stb<(outs), (ins GPR:$src, addrmode2:$addr), StFrm, IIC_iStorer, - "strb", "\t$src, $addr", - [(truncstorei8 GPR:$src, addrmode2:$addr)]>; +def STRH : AI3str<0b1011, (outs), (ins GPR:$Rt, addrmode3:$addr), StMiscFrm, + IIC_iStore_bh_r, "strh", "\t$Rt, $addr", + [(truncstorei16 GPR:$Rt, addrmode3:$addr)]>; // Store doubleword -let mayStore = 1, neverHasSideEffects = 1, hasExtraSrcRegAllocReq = 1 in -def STRD : AI3std<(outs), (ins GPR:$src1, GPR:$src2, addrmode3:$addr), - StMiscFrm, IIC_iStorer, +let mayStore = 1, neverHasSideEffects = 1, hasExtraSrcRegAllocReq = 1, + isCodeGenOnly = 1 in // $src2 doesn't exist in asm string +def STRD : AI3str<0b1111, (outs), (ins GPR:$src1, GPR:$src2, addrmode3:$addr), + StMiscFrm, IIC_iStore_d_r, "strd", "\t$src1, $addr", []>, Requires<[IsARM, HasV5TE]>; // Indexed stores -def STR_PRE : AI2stwpr<(outs GPR:$base_wb), - (ins GPR:$src, GPR:$base, am2offset:$offset), - StFrm, IIC_iStoreru, - "str", "\t$src, [$base, $offset]!", "$base = $base_wb", - [(set GPR:$base_wb, - (pre_store GPR:$src, GPR:$base, am2offset:$offset))]>; - -def STR_POST : AI2stwpo<(outs GPR:$base_wb), - (ins GPR:$src, GPR:$base,am2offset:$offset), - StFrm, IIC_iStoreru, - "str", "\t$src, [$base], $offset", "$base = $base_wb", - [(set GPR:$base_wb, - (post_store GPR:$src, GPR:$base, am2offset:$offset))]>; - -def STRH_PRE : AI3sthpr<(outs GPR:$base_wb), - (ins GPR:$src, GPR:$base,am3offset:$offset), - StMiscFrm, IIC_iStoreru, - "strh", "\t$src, [$base, $offset]!", "$base = $base_wb", - [(set GPR:$base_wb, - (pre_truncsti16 GPR:$src, GPR:$base,am3offset:$offset))]>; - -def STRH_POST: AI3sthpo<(outs GPR:$base_wb), - (ins GPR:$src, GPR:$base,am3offset:$offset), - StMiscFrm, IIC_iStoreru, - "strh", "\t$src, [$base], $offset", "$base = $base_wb", - [(set GPR:$base_wb, (post_truncsti16 GPR:$src, - GPR:$base, am3offset:$offset))]>; - -def STRB_PRE : AI2stbpr<(outs GPR:$base_wb), - (ins GPR:$src, GPR:$base,am2offset:$offset), - StFrm, IIC_iStoreru, - "strb", "\t$src, [$base, $offset]!", "$base = $base_wb", - [(set GPR:$base_wb, (pre_truncsti8 GPR:$src, - GPR:$base, am2offset:$offset))]>; - -def STRB_POST: AI2stbpo<(outs GPR:$base_wb), - (ins GPR:$src, GPR:$base,am2offset:$offset), - StFrm, IIC_iStoreru, - "strb", "\t$src, [$base], $offset", "$base = $base_wb", - [(set GPR:$base_wb, (post_truncsti8 GPR:$src, - GPR:$base, am2offset:$offset))]>; +def STR_PRE : AI2stridx<0, 1, (outs GPR:$Rn_wb), + (ins GPR:$Rt, GPR:$Rn, am2offset:$offset), + IndexModePre, StFrm, IIC_iStore_ru, + "str", "\t$Rt, [$Rn, $offset]!", "$Rn = $Rn_wb", + [(set GPR:$Rn_wb, + (pre_store GPR:$Rt, GPR:$Rn, am2offset:$offset))]>; + +def STR_POST : AI2stridx<0, 0, (outs GPR:$Rn_wb), + (ins GPR:$Rt, GPR:$Rn, am2offset:$offset), + IndexModePost, StFrm, IIC_iStore_ru, + "str", "\t$Rt, [$Rn], $offset", "$Rn = $Rn_wb", + [(set GPR:$Rn_wb, + (post_store GPR:$Rt, GPR:$Rn, am2offset:$offset))]>; + +def STRB_PRE : AI2stridx<1, 1, (outs GPR:$Rn_wb), + (ins GPR:$Rt, GPR:$Rn, am2offset:$offset), + IndexModePre, StFrm, IIC_iStore_bh_ru, + "strb", "\t$Rt, [$Rn, $offset]!", "$Rn = $Rn_wb", + [(set GPR:$Rn_wb, (pre_truncsti8 GPR:$Rt, + GPR:$Rn, am2offset:$offset))]>; +def STRB_POST: AI2stridx<1, 0, (outs GPR:$Rn_wb), + (ins GPR:$Rt, GPR:$Rn, am2offset:$offset), + IndexModePost, StFrm, IIC_iStore_bh_ru, + "strb", "\t$Rt, [$Rn], $offset", "$Rn = $Rn_wb", + [(set GPR:$Rn_wb, (post_truncsti8 GPR:$Rt, + GPR:$Rn, am2offset:$offset))]>; + +def STRH_PRE : AI3stridx<0b1011, 0, 1, (outs GPR:$Rn_wb), + (ins GPR:$Rt, GPR:$Rn, am3offset:$offset), + IndexModePre, StMiscFrm, IIC_iStore_ru, + "strh", "\t$Rt, [$Rn, $offset]!", "$Rn = $Rn_wb", + [(set GPR:$Rn_wb, + (pre_truncsti16 GPR:$Rt, GPR:$Rn, am3offset:$offset))]>; + +def STRH_POST: AI3stridx<0b1011, 0, 0, (outs GPR:$Rn_wb), + (ins GPR:$Rt, GPR:$Rn, am3offset:$offset), + IndexModePost, StMiscFrm, IIC_iStore_bh_ru, + "strh", "\t$Rt, [$Rn], $offset", "$Rn = $Rn_wb", + [(set GPR:$Rn_wb, (post_truncsti16 GPR:$Rt, + GPR:$Rn, am3offset:$offset))]>; // For disassembly only def STRD_PRE : AI3stdpr<(outs GPR:$base_wb), (ins GPR:$src1, GPR:$src2, GPR:$base, am3offset:$offset), - StMiscFrm, IIC_iStoreru, + StMiscFrm, IIC_iStore_d_ru, "strd", "\t$src1, $src2, [$base, $offset]!", "$base = $base_wb", []>; // For disassembly only def STRD_POST: AI3stdpo<(outs GPR:$base_wb), (ins GPR:$src1, GPR:$src2, GPR:$base, am3offset:$offset), - StMiscFrm, IIC_iStoreru, + StMiscFrm, IIC_iStore_d_ru, "strd", "\t$src1, $src2, [$base], $offset", "$base = $base_wb", []>; // STRT, STRBT, and STRHT are for disassembly only. -def STRT : AI2stwpo<(outs GPR:$base_wb), - (ins GPR:$src, GPR:$base,am2offset:$offset), - StFrm, IIC_iStoreru, - "strt", "\t$src, [$base], $offset", "$base = $base_wb", +def STRT : AI2stridx<0, 0, (outs GPR:$Rn_wb), + (ins GPR:$Rt, GPR:$Rn,am2offset:$offset), + IndexModeNone, StFrm, IIC_iStore_ru, + "strt", "\t$Rt, [$Rn], $offset", "$Rn = $Rn_wb", [/* For disassembly only; pattern left blank */]> { let Inst{21} = 1; // overwrite } -def STRBT : AI2stbpo<(outs GPR:$base_wb), - (ins GPR:$src, GPR:$base,am2offset:$offset), - StFrm, IIC_iStoreru, - "strbt", "\t$src, [$base], $offset", "$base = $base_wb", +def STRBT : AI2stridx<1, 0, (outs GPR:$Rn_wb), + (ins GPR:$Rt, GPR:$Rn, am2offset:$offset), + IndexModeNone, StFrm, IIC_iStore_bh_ru, + "strbt", "\t$Rt, [$Rn], $offset", "$Rn = $Rn_wb", [/* For disassembly only; pattern left blank */]> { let Inst{21} = 1; // overwrite } def STRHT: AI3sthpo<(outs GPR:$base_wb), (ins GPR:$src, GPR:$base,am3offset:$offset), - StMiscFrm, IIC_iStoreru, + StMiscFrm, IIC_iStore_bh_ru, "strht", "\t$src, [$base], $offset", "$base = $base_wb", [/* For disassembly only; pattern left blank */]> { let Inst{21} = 1; // overwrite @@ -1446,103 +1824,212 @@ def STRHT: AI3sthpo<(outs GPR:$base_wb), // Load / store multiple Instructions. // -let mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1 in { -def LDM : AXI4ld<(outs), (ins addrmode4:$addr, pred:$p, - reglist:$dsts, variable_ops), - IndexModeNone, LdStMulFrm, IIC_iLoadm, - "ldm${addr:submode}${p}\t$addr, $dsts", "", []>; - -def LDM_UPD : AXI4ld<(outs GPR:$wb), (ins addrmode4:$addr, pred:$p, - reglist:$dsts, variable_ops), - IndexModeUpd, LdStMulFrm, IIC_iLoadm, - "ldm${addr:submode}${p}\t$addr!, $dsts", - "$addr.addr = $wb", []>; -} // mayLoad, neverHasSideEffects, hasExtraDefRegAllocReq - -let mayStore = 1, neverHasSideEffects = 1, hasExtraSrcRegAllocReq = 1 in { -def STM : AXI4st<(outs), (ins addrmode4:$addr, pred:$p, - reglist:$srcs, variable_ops), - IndexModeNone, LdStMulFrm, IIC_iStorem, - "stm${addr:submode}${p}\t$addr, $srcs", "", []>; - -def STM_UPD : AXI4st<(outs GPR:$wb), (ins addrmode4:$addr, pred:$p, - reglist:$srcs, variable_ops), - IndexModeUpd, LdStMulFrm, IIC_iStorem, - "stm${addr:submode}${p}\t$addr!, $srcs", - "$addr.addr = $wb", []>; -} // mayStore, neverHasSideEffects, hasExtraSrcRegAllocReq +multiclass arm_ldst_mult { + def IA : + AXI4<(outs), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), + IndexModeNone, f, itin, + !strconcat(asm, "ia${p}\t$Rn, $regs"), "", []> { + let Inst{24-23} = 0b01; // Increment After + let Inst{21} = 0; // No writeback + let Inst{20} = L_bit; + } + def IA_UPD : + AXI4<(outs GPR:$wb), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), + IndexModeUpd, f, itin_upd, + !strconcat(asm, "ia${p}\t$Rn!, $regs"), "$Rn = $wb", []> { + let Inst{24-23} = 0b01; // Increment After + let Inst{21} = 1; // Writeback + let Inst{20} = L_bit; + } + def DA : + AXI4<(outs), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), + IndexModeNone, f, itin, + !strconcat(asm, "da${p}\t$Rn, $regs"), "", []> { + let Inst{24-23} = 0b00; // Decrement After + let Inst{21} = 0; // No writeback + let Inst{20} = L_bit; + } + def DA_UPD : + AXI4<(outs GPR:$wb), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), + IndexModeUpd, f, itin_upd, + !strconcat(asm, "da${p}\t$Rn!, $regs"), "$Rn = $wb", []> { + let Inst{24-23} = 0b00; // Decrement After + let Inst{21} = 1; // Writeback + let Inst{20} = L_bit; + } + def DB : + AXI4<(outs), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), + IndexModeNone, f, itin, + !strconcat(asm, "db${p}\t$Rn, $regs"), "", []> { + let Inst{24-23} = 0b10; // Decrement Before + let Inst{21} = 0; // No writeback + let Inst{20} = L_bit; + } + def DB_UPD : + AXI4<(outs GPR:$wb), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), + IndexModeUpd, f, itin_upd, + !strconcat(asm, "db${p}\t$Rn!, $regs"), "$Rn = $wb", []> { + let Inst{24-23} = 0b10; // Decrement Before + let Inst{21} = 1; // Writeback + let Inst{20} = L_bit; + } + def IB : + AXI4<(outs), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), + IndexModeNone, f, itin, + !strconcat(asm, "ib${p}\t$Rn, $regs"), "", []> { + let Inst{24-23} = 0b11; // Increment Before + let Inst{21} = 0; // No writeback + let Inst{20} = L_bit; + } + def IB_UPD : + AXI4<(outs GPR:$wb), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops), + IndexModeUpd, f, itin_upd, + !strconcat(asm, "ib${p}\t$Rn!, $regs"), "$Rn = $wb", []> { + let Inst{24-23} = 0b11; // Increment Before + let Inst{21} = 1; // Writeback + let Inst{20} = L_bit; + } +} + +let neverHasSideEffects = 1 in { + +let mayLoad = 1, hasExtraDefRegAllocReq = 1 in +defm LDM : arm_ldst_mult<"ldm", 1, LdStMulFrm, IIC_iLoad_m, IIC_iLoad_mu>; + +let mayStore = 1, hasExtraSrcRegAllocReq = 1 in +defm STM : arm_ldst_mult<"stm", 0, LdStMulFrm, IIC_iStore_m, IIC_iStore_mu>; + +} // neverHasSideEffects + +// Load / Store Multiple Mnemonic Aliases +def : MnemonicAlias<"ldm", "ldmia">; +def : MnemonicAlias<"stm", "stmia">; + +// FIXME: remove when we have a way to marking a MI with these properties. +// FIXME: Should pc be an implicit operand like PICADD, etc? +let isReturn = 1, isTerminator = 1, isBarrier = 1, mayLoad = 1, + hasExtraDefRegAllocReq = 1, isCodeGenOnly = 1 in +// FIXME: Should be a pseudo-instruction. +def LDMIA_RET : AXI4<(outs GPR:$wb), (ins GPR:$Rn, pred:$p, + reglist:$regs, variable_ops), + IndexModeUpd, LdStMulFrm, IIC_iLoad_mBr, + "ldmia${p}\t$Rn!, $regs", + "$Rn = $wb", []> { + let Inst{24-23} = 0b01; // Increment After + let Inst{21} = 1; // Writeback + let Inst{20} = 1; // Load +} //===----------------------------------------------------------------------===// // Move Instructions. // let neverHasSideEffects = 1 in -def MOVr : AsI1<0b1101, (outs GPR:$dst), (ins GPR:$src), DPFrm, IIC_iMOVr, - "mov", "\t$dst, $src", []>, UnaryDP { +def MOVr : AsI1<0b1101, (outs GPR:$Rd), (ins GPR:$Rm), DPFrm, IIC_iMOVr, + "mov", "\t$Rd, $Rm", []>, UnaryDP { + bits<4> Rd; + bits<4> Rm; + let Inst{11-4} = 0b00000000; let Inst{25} = 0; + let Inst{3-0} = Rm; + let Inst{15-12} = Rd; } // A version for the smaller set of tail call registers. let neverHasSideEffects = 1 in -def MOVr_TC : AsI1<0b1101, (outs tcGPR:$dst), (ins tcGPR:$src), DPFrm, - IIC_iMOVr, "mov", "\t$dst, $src", []>, UnaryDP { +def MOVr_TC : AsI1<0b1101, (outs tcGPR:$Rd), (ins tcGPR:$Rm), DPFrm, + IIC_iMOVr, "mov", "\t$Rd, $Rm", []>, UnaryDP { + bits<4> Rd; + bits<4> Rm; + let Inst{11-4} = 0b00000000; let Inst{25} = 0; + let Inst{3-0} = Rm; + let Inst{15-12} = Rd; } -def MOVs : AsI1<0b1101, (outs GPR:$dst), (ins so_reg:$src), +def MOVs : AsI1<0b1101, (outs GPR:$Rd), (ins shift_so_reg:$src), DPSoRegFrm, IIC_iMOVsr, - "mov", "\t$dst, $src", [(set GPR:$dst, so_reg:$src)]>, UnaryDP { + "mov", "\t$Rd, $src", [(set GPR:$Rd, shift_so_reg:$src)]>, + UnaryDP { + bits<4> Rd; + bits<12> src; + let Inst{15-12} = Rd; + let Inst{11-0} = src; let Inst{25} = 0; } -let isReMaterializable = 1, isAsCheapAsAMove = 1 in -def MOVi : AsI1<0b1101, (outs GPR:$dst), (ins so_imm:$src), DPFrm, IIC_iMOVi, - "mov", "\t$dst, $src", [(set GPR:$dst, so_imm:$src)]>, UnaryDP { +let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in +def MOVi : AsI1<0b1101, (outs GPR:$Rd), (ins so_imm:$imm), DPFrm, IIC_iMOVi, + "mov", "\t$Rd, $imm", [(set GPR:$Rd, so_imm:$imm)]>, UnaryDP { + bits<4> Rd; + bits<12> imm; let Inst{25} = 1; + let Inst{15-12} = Rd; + let Inst{19-16} = 0b0000; + let Inst{11-0} = imm; } -let isReMaterializable = 1, isAsCheapAsAMove = 1 in -def MOVi16 : AI1<0b1000, (outs GPR:$dst), (ins i32imm:$src), +let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in +def MOVi16 : AI1<0b1000, (outs GPR:$Rd), (ins i32imm_hilo16:$imm), DPFrm, IIC_iMOVi, - "movw", "\t$dst, $src", - [(set GPR:$dst, imm0_65535:$src)]>, + "movw", "\t$Rd, $imm", + [(set GPR:$Rd, imm0_65535:$imm)]>, Requires<[IsARM, HasV6T2]>, UnaryDP { + bits<4> Rd; + bits<16> imm; + let Inst{15-12} = Rd; + let Inst{11-0} = imm{11-0}; + let Inst{19-16} = imm{15-12}; let Inst{20} = 0; let Inst{25} = 1; } -let Constraints = "$src = $dst" in -def MOVTi16 : AI1<0b1010, (outs GPR:$dst), (ins GPR:$src, i32imm:$imm), +def MOVi16_ga_pcrel : PseudoInst<(outs GPR:$Rd), + (ins i32imm:$addr, pclabel:$id), IIC_iMOVi, []>; + +let Constraints = "$src = $Rd" in { +def MOVTi16 : AI1<0b1010, (outs GPR:$Rd), (ins GPR:$src, i32imm_hilo16:$imm), DPFrm, IIC_iMOVi, - "movt", "\t$dst, $imm", - [(set GPR:$dst, + "movt", "\t$Rd, $imm", + [(set GPR:$Rd, (or (and GPR:$src, 0xffff), lo16AllZero:$imm))]>, UnaryDP, Requires<[IsARM, HasV6T2]> { + bits<4> Rd; + bits<16> imm; + let Inst{15-12} = Rd; + let Inst{11-0} = imm{11-0}; + let Inst{19-16} = imm{15-12}; let Inst{20} = 0; let Inst{25} = 1; } +def MOVTi16_ga_pcrel : PseudoInst<(outs GPR:$Rd), + (ins GPR:$src, i32imm:$addr, pclabel:$id), IIC_iMOVi, []>; + +} // Constraints + def : ARMPat<(or GPR:$src, 0xffff0000), (MOVTi16 GPR:$src, 0xffff)>, Requires<[IsARM, HasV6T2]>; let Uses = [CPSR] in -def MOVrx : AsI1<0b1101, (outs GPR:$dst), (ins GPR:$src), Pseudo, IIC_iMOVsi, - "mov", "\t$dst, $src, rrx", - [(set GPR:$dst, (ARMrrx GPR:$src))]>, UnaryDP; +def RRX: PseudoInst<(outs GPR:$Rd), (ins GPR:$Rm), IIC_iMOVsi, + [(set GPR:$Rd, (ARMrrx GPR:$Rm))]>, UnaryDP, + Requires<[IsARM]>; // These aren't really mov instructions, but we have to define them this way // due to flag operands. let Defs = [CPSR] in { -def MOVsrl_flag : AI1<0b1101, (outs GPR:$dst), (ins GPR:$src), Pseudo, - IIC_iMOVsi, "movs", "\t$dst, $src, lsr #1", - [(set GPR:$dst, (ARMsrl_flag GPR:$src))]>, UnaryDP; -def MOVsra_flag : AI1<0b1101, (outs GPR:$dst), (ins GPR:$src), Pseudo, - IIC_iMOVsi, "movs", "\t$dst, $src, asr #1", - [(set GPR:$dst, (ARMsra_flag GPR:$src))]>, UnaryDP; +def MOVsrl_flag : PseudoInst<(outs GPR:$dst), (ins GPR:$src), IIC_iMOVsi, + [(set GPR:$dst, (ARMsrl_flag GPR:$src))]>, UnaryDP, + Requires<[IsARM]>; +def MOVsra_flag : PseudoInst<(outs GPR:$dst), (ins GPR:$src), IIC_iMOVsi, + [(set GPR:$dst, (ARMsra_flag GPR:$src))]>, UnaryDP, + Requires<[IsARM]>; } //===----------------------------------------------------------------------===// @@ -1551,31 +2038,31 @@ def MOVsra_flag : AI1<0b1101, (outs GPR:$dst), (ins GPR:$src), Pseudo, // Sign extenders -defm SXTB : AI_unary_rrot<0b01101010, - "sxtb", UnOpFrag<(sext_inreg node:$Src, i8)>>; -defm SXTH : AI_unary_rrot<0b01101011, - "sxth", UnOpFrag<(sext_inreg node:$Src, i16)>>; +defm SXTB : AI_ext_rrot<0b01101010, + "sxtb", UnOpFrag<(sext_inreg node:$Src, i8)>>; +defm SXTH : AI_ext_rrot<0b01101011, + "sxth", UnOpFrag<(sext_inreg node:$Src, i16)>>; -defm SXTAB : AI_bin_rrot<0b01101010, +defm SXTAB : AI_exta_rrot<0b01101010, "sxtab", BinOpFrag<(add node:$LHS, (sext_inreg node:$RHS, i8))>>; -defm SXTAH : AI_bin_rrot<0b01101011, +defm SXTAH : AI_exta_rrot<0b01101011, "sxtah", BinOpFrag<(add node:$LHS, (sext_inreg node:$RHS,i16))>>; // For disassembly only -defm SXTB16 : AI_unary_rrot_np<0b01101000, "sxtb16">; +defm SXTB16 : AI_ext_rrot_np<0b01101000, "sxtb16">; // For disassembly only -defm SXTAB16 : AI_bin_rrot_np<0b01101000, "sxtab16">; +defm SXTAB16 : AI_exta_rrot_np<0b01101000, "sxtab16">; // Zero extenders let AddedComplexity = 16 in { -defm UXTB : AI_unary_rrot<0b01101110, - "uxtb" , UnOpFrag<(and node:$Src, 0x000000FF)>>; -defm UXTH : AI_unary_rrot<0b01101111, - "uxth" , UnOpFrag<(and node:$Src, 0x0000FFFF)>>; -defm UXTB16 : AI_unary_rrot<0b01101100, - "uxtb16", UnOpFrag<(and node:$Src, 0x00FF00FF)>>; +defm UXTB : AI_ext_rrot<0b01101110, + "uxtb" , UnOpFrag<(and node:$Src, 0x000000FF)>>; +defm UXTH : AI_ext_rrot<0b01101111, + "uxth" , UnOpFrag<(and node:$Src, 0x0000FFFF)>>; +defm UXTB16 : AI_ext_rrot<0b01101100, + "uxtb16", UnOpFrag<(and node:$Src, 0x00FF00FF)>>; // FIXME: This pattern incorrectly assumes the shl operator is a rotate. // The transformation should probably be done as a combiner action @@ -1586,33 +2073,49 @@ defm UXTB16 : AI_unary_rrot<0b01101100, def : ARMV6Pat<(and (srl GPR:$Src, (i32 8)), 0xFF00FF), (UXTB16r_rot GPR:$Src, 8)>; -defm UXTAB : AI_bin_rrot<0b01101110, "uxtab", +defm UXTAB : AI_exta_rrot<0b01101110, "uxtab", BinOpFrag<(add node:$LHS, (and node:$RHS, 0x00FF))>>; -defm UXTAH : AI_bin_rrot<0b01101111, "uxtah", +defm UXTAH : AI_exta_rrot<0b01101111, "uxtah", BinOpFrag<(add node:$LHS, (and node:$RHS, 0xFFFF))>>; } // This isn't safe in general, the add is two 16-bit units, not a 32-bit add. // For disassembly only -defm UXTAB16 : AI_bin_rrot_np<0b01101100, "uxtab16">; +defm UXTAB16 : AI_exta_rrot_np<0b01101100, "uxtab16">; -def SBFX : I<(outs GPR:$dst), - (ins GPR:$src, imm0_31:$lsb, imm0_31:$width), - AddrMode1, Size4Bytes, IndexModeNone, DPFrm, IIC_iALUi, - "sbfx", "\t$dst, $src, $lsb, $width", "", []>, +def SBFX : I<(outs GPR:$Rd), + (ins GPR:$Rn, imm0_31:$lsb, imm0_31_m1:$width), + AddrMode1, Size4Bytes, IndexModeNone, DPFrm, IIC_iUNAsi, + "sbfx", "\t$Rd, $Rn, $lsb, $width", "", []>, Requires<[IsARM, HasV6T2]> { + bits<4> Rd; + bits<4> Rn; + bits<5> lsb; + bits<5> width; let Inst{27-21} = 0b0111101; let Inst{6-4} = 0b101; + let Inst{20-16} = width; + let Inst{15-12} = Rd; + let Inst{11-7} = lsb; + let Inst{3-0} = Rn; } -def UBFX : I<(outs GPR:$dst), - (ins GPR:$src, imm0_31:$lsb, imm0_31:$width), - AddrMode1, Size4Bytes, IndexModeNone, DPFrm, IIC_iALUi, - "ubfx", "\t$dst, $src, $lsb, $width", "", []>, +def UBFX : I<(outs GPR:$Rd), + (ins GPR:$Rn, imm0_31:$lsb, imm0_31_m1:$width), + AddrMode1, Size4Bytes, IndexModeNone, DPFrm, IIC_iUNAsi, + "ubfx", "\t$Rd, $Rn, $lsb, $width", "", []>, Requires<[IsARM, HasV6T2]> { + bits<4> Rd; + bits<4> Rn; + bits<5> lsb; + bits<5> width; let Inst{27-21} = 0b0111111; let Inst{6-4} = 0b101; + let Inst{20-16} = width; + let Inst{15-12} = Rd; + let Inst{11-7} = lsb; + let Inst{3-0} = Rn; } //===----------------------------------------------------------------------===// @@ -1620,100 +2123,166 @@ def UBFX : I<(outs GPR:$dst), // defm ADD : AsI1_bin_irs<0b0100, "add", + IIC_iALUi, IIC_iALUr, IIC_iALUsr, BinOpFrag<(add node:$LHS, node:$RHS)>, 1>; defm SUB : AsI1_bin_irs<0b0010, "sub", + IIC_iALUi, IIC_iALUr, IIC_iALUsr, BinOpFrag<(sub node:$LHS, node:$RHS)>>; // ADD and SUB with 's' bit set. defm ADDS : AI1_bin_s_irs<0b0100, "adds", + IIC_iALUi, IIC_iALUr, IIC_iALUsr, BinOpFrag<(addc node:$LHS, node:$RHS)>, 1>; defm SUBS : AI1_bin_s_irs<0b0010, "subs", + IIC_iALUi, IIC_iALUr, IIC_iALUsr, BinOpFrag<(subc node:$LHS, node:$RHS)>>; defm ADC : AI1_adde_sube_irs<0b0101, "adc", BinOpFrag<(adde_dead_carry node:$LHS, node:$RHS)>, 1>; defm SBC : AI1_adde_sube_irs<0b0110, "sbc", BinOpFrag<(sube_dead_carry node:$LHS, node:$RHS)>>; + +// ADC and SUBC with 's' bit set. defm ADCS : AI1_adde_sube_s_irs<0b0101, "adcs", BinOpFrag<(adde_live_carry node:$LHS, node:$RHS)>, 1>; defm SBCS : AI1_adde_sube_s_irs<0b0110, "sbcs", BinOpFrag<(sube_live_carry node:$LHS, node:$RHS) >>; -def RSBri : AsI1<0b0011, (outs GPR:$dst), (ins GPR:$a, so_imm:$b), DPFrm, - IIC_iALUi, "rsb", "\t$dst, $a, $b", - [(set GPR:$dst, (sub so_imm:$b, GPR:$a))]> { - let Inst{25} = 1; +def RSBri : AsI1<0b0011, (outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm), DPFrm, + IIC_iALUi, "rsb", "\t$Rd, $Rn, $imm", + [(set GPR:$Rd, (sub so_imm:$imm, GPR:$Rn))]> { + bits<4> Rd; + bits<4> Rn; + bits<12> imm; + let Inst{25} = 1; + let Inst{15-12} = Rd; + let Inst{19-16} = Rn; + let Inst{11-0} = imm; } // The reg/reg form is only defined for the disassembler; for codegen it is // equivalent to SUBrr. -def RSBrr : AsI1<0b0011, (outs GPR:$dst), (ins GPR:$a, GPR:$b), DPFrm, - IIC_iALUr, "rsb", "\t$dst, $a, $b", +def RSBrr : AsI1<0b0011, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), DPFrm, + IIC_iALUr, "rsb", "\t$Rd, $Rn, $Rm", [/* For disassembly only; pattern left blank */]> { - let Inst{25} = 0; - let Inst{11-4} = 0b00000000; + bits<4> Rd; + bits<4> Rn; + bits<4> Rm; + let Inst{11-4} = 0b00000000; + let Inst{25} = 0; + let Inst{3-0} = Rm; + let Inst{15-12} = Rd; + let Inst{19-16} = Rn; } -def RSBrs : AsI1<0b0011, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), DPSoRegFrm, - IIC_iALUsr, "rsb", "\t$dst, $a, $b", - [(set GPR:$dst, (sub so_reg:$b, GPR:$a))]> { - let Inst{25} = 0; +def RSBrs : AsI1<0b0011, (outs GPR:$Rd), (ins GPR:$Rn, so_reg:$shift), + DPSoRegFrm, IIC_iALUsr, "rsb", "\t$Rd, $Rn, $shift", + [(set GPR:$Rd, (sub so_reg:$shift, GPR:$Rn))]> { + bits<4> Rd; + bits<4> Rn; + bits<12> shift; + let Inst{25} = 0; + let Inst{11-0} = shift; + let Inst{15-12} = Rd; + let Inst{19-16} = Rn; } // RSB with 's' bit set. -let Defs = [CPSR] in { -def RSBSri : AI1<0b0011, (outs GPR:$dst), (ins GPR:$a, so_imm:$b), DPFrm, - IIC_iALUi, "rsbs", "\t$dst, $a, $b", - [(set GPR:$dst, (subc so_imm:$b, GPR:$a))]> { - let Inst{20} = 1; - let Inst{25} = 1; -} -def RSBSrs : AI1<0b0011, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), DPSoRegFrm, - IIC_iALUsr, "rsbs", "\t$dst, $a, $b", - [(set GPR:$dst, (subc so_reg:$b, GPR:$a))]> { - let Inst{20} = 1; - let Inst{25} = 0; +let isCodeGenOnly = 1, Defs = [CPSR] in { +def RSBSri : AI1<0b0011, (outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm), DPFrm, + IIC_iALUi, "rsbs", "\t$Rd, $Rn, $imm", + [(set GPR:$Rd, (subc so_imm:$imm, GPR:$Rn))]> { + bits<4> Rd; + bits<4> Rn; + bits<12> imm; + let Inst{25} = 1; + let Inst{20} = 1; + let Inst{15-12} = Rd; + let Inst{19-16} = Rn; + let Inst{11-0} = imm; +} +def RSBSrs : AI1<0b0011, (outs GPR:$Rd), (ins GPR:$Rn, so_reg:$shift), + DPSoRegFrm, IIC_iALUsr, "rsbs", "\t$Rd, $Rn, $shift", + [(set GPR:$Rd, (subc so_reg:$shift, GPR:$Rn))]> { + bits<4> Rd; + bits<4> Rn; + bits<12> shift; + let Inst{25} = 0; + let Inst{20} = 1; + let Inst{11-0} = shift; + let Inst{15-12} = Rd; + let Inst{19-16} = Rn; } } let Uses = [CPSR] in { -def RSCri : AsI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_imm:$b), - DPFrm, IIC_iALUi, "rsc", "\t$dst, $a, $b", - [(set GPR:$dst, (sube_dead_carry so_imm:$b, GPR:$a))]>, +def RSCri : AsI1<0b0111, (outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm), + DPFrm, IIC_iALUi, "rsc", "\t$Rd, $Rn, $imm", + [(set GPR:$Rd, (sube_dead_carry so_imm:$imm, GPR:$Rn))]>, Requires<[IsARM]> { - let Inst{25} = 1; + bits<4> Rd; + bits<4> Rn; + bits<12> imm; + let Inst{25} = 1; + let Inst{15-12} = Rd; + let Inst{19-16} = Rn; + let Inst{11-0} = imm; } // The reg/reg form is only defined for the disassembler; for codegen it is // equivalent to SUBrr. -def RSCrr : AsI1<0b0111, (outs GPR:$dst), (ins GPR:$a, GPR:$b), - DPFrm, IIC_iALUr, "rsc", "\t$dst, $a, $b", +def RSCrr : AsI1<0b0111, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), + DPFrm, IIC_iALUr, "rsc", "\t$Rd, $Rn, $Rm", [/* For disassembly only; pattern left blank */]> { - let Inst{25} = 0; - let Inst{11-4} = 0b00000000; + bits<4> Rd; + bits<4> Rn; + bits<4> Rm; + let Inst{11-4} = 0b00000000; + let Inst{25} = 0; + let Inst{3-0} = Rm; + let Inst{15-12} = Rd; + let Inst{19-16} = Rn; } -def RSCrs : AsI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), - DPSoRegFrm, IIC_iALUsr, "rsc", "\t$dst, $a, $b", - [(set GPR:$dst, (sube_dead_carry so_reg:$b, GPR:$a))]>, +def RSCrs : AsI1<0b0111, (outs GPR:$Rd), (ins GPR:$Rn, so_reg:$shift), + DPSoRegFrm, IIC_iALUsr, "rsc", "\t$Rd, $Rn, $shift", + [(set GPR:$Rd, (sube_dead_carry so_reg:$shift, GPR:$Rn))]>, Requires<[IsARM]> { - let Inst{25} = 0; + bits<4> Rd; + bits<4> Rn; + bits<12> shift; + let Inst{25} = 0; + let Inst{11-0} = shift; + let Inst{15-12} = Rd; + let Inst{19-16} = Rn; } } // FIXME: Allow these to be predicated. -let Defs = [CPSR], Uses = [CPSR] in { -def RSCSri : AXI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_imm:$b), - DPFrm, IIC_iALUi, "rscs\t$dst, $a, $b", - [(set GPR:$dst, (sube_dead_carry so_imm:$b, GPR:$a))]>, +let isCodeGenOnly = 1, Defs = [CPSR], Uses = [CPSR] in { +def RSCSri : AXI1<0b0111, (outs GPR:$Rd), (ins GPR:$Rn, so_imm:$imm), + DPFrm, IIC_iALUi, "rscs\t$Rd, $Rn, $imm", + [(set GPR:$Rd, (sube_dead_carry so_imm:$imm, GPR:$Rn))]>, Requires<[IsARM]> { - let Inst{20} = 1; - let Inst{25} = 1; + bits<4> Rd; + bits<4> Rn; + bits<12> imm; + let Inst{25} = 1; + let Inst{20} = 1; + let Inst{15-12} = Rd; + let Inst{19-16} = Rn; + let Inst{11-0} = imm; } -def RSCSrs : AXI1<0b0111, (outs GPR:$dst), (ins GPR:$a, so_reg:$b), - DPSoRegFrm, IIC_iALUsr, "rscs\t$dst, $a, $b", - [(set GPR:$dst, (sube_dead_carry so_reg:$b, GPR:$a))]>, +def RSCSrs : AXI1<0b0111, (outs GPR:$Rd), (ins GPR:$Rn, so_reg:$shift), + DPSoRegFrm, IIC_iALUsr, "rscs\t$Rd, $Rn, $shift", + [(set GPR:$Rd, (sube_dead_carry so_reg:$shift, GPR:$Rn))]>, Requires<[IsARM]> { - let Inst{20} = 1; - let Inst{25} = 0; + bits<4> Rd; + bits<4> Rn; + bits<12> shift; + let Inst{25} = 0; + let Inst{20} = 1; + let Inst{11-0} = shift; + let Inst{15-12} = Rd; + let Inst{19-16} = Rn; } } @@ -1740,111 +2309,166 @@ def : ARMPat<(adde GPR:$src, so_imm_not:$imm), // ARM Arithmetic Instruction -- for disassembly only // GPR:$dst = GPR:$a op GPR:$b -class AAI op27_20, bits<4> op7_4, string opc, - list pattern = [/* For disassembly only; pattern left blank */]> - : AI<(outs GPR:$dst), (ins GPR:$a, GPR:$b), DPFrm, IIC_iALUr, - opc, "\t$dst, $a, $b", pattern> { +class AAI op27_20, bits<8> op11_4, string opc, + list pattern = [/* For disassembly only; pattern left blank */], + dag iops = (ins GPR:$Rn, GPR:$Rm), string asm = "\t$Rd, $Rn, $Rm"> + : AI<(outs GPR:$Rd), iops, DPFrm, IIC_iALUr, opc, asm, pattern> { + bits<4> Rn; + bits<4> Rd; + bits<4> Rm; let Inst{27-20} = op27_20; - let Inst{7-4} = op7_4; + let Inst{11-4} = op11_4; + let Inst{19-16} = Rn; + let Inst{15-12} = Rd; + let Inst{3-0} = Rm; } // Saturating add/subtract -- for disassembly only -def QADD : AAI<0b00010000, 0b0101, "qadd", - [(set GPR:$dst, (int_arm_qadd GPR:$a, GPR:$b))]>; -def QADD16 : AAI<0b01100010, 0b0001, "qadd16">; -def QADD8 : AAI<0b01100010, 0b1001, "qadd8">; -def QASX : AAI<0b01100010, 0b0011, "qasx">; -def QDADD : AAI<0b00010100, 0b0101, "qdadd">; -def QDSUB : AAI<0b00010110, 0b0101, "qdsub">; -def QSAX : AAI<0b01100010, 0b0101, "qsax">; -def QSUB : AAI<0b00010010, 0b0101, "qsub", - [(set GPR:$dst, (int_arm_qsub GPR:$a, GPR:$b))]>; -def QSUB16 : AAI<0b01100010, 0b0111, "qsub16">; -def QSUB8 : AAI<0b01100010, 0b1111, "qsub8">; -def UQADD16 : AAI<0b01100110, 0b0001, "uqadd16">; -def UQADD8 : AAI<0b01100110, 0b1001, "uqadd8">; -def UQASX : AAI<0b01100110, 0b0011, "uqasx">; -def UQSAX : AAI<0b01100110, 0b0101, "uqsax">; -def UQSUB16 : AAI<0b01100110, 0b0111, "uqsub16">; -def UQSUB8 : AAI<0b01100110, 0b1111, "uqsub8">; +def QADD : AAI<0b00010000, 0b00000101, "qadd", + [(set GPR:$Rd, (int_arm_qadd GPR:$Rm, GPR:$Rn))], + (ins GPR:$Rm, GPR:$Rn), "\t$Rd, $Rm, $Rn">; +def QSUB : AAI<0b00010010, 0b00000101, "qsub", + [(set GPR:$Rd, (int_arm_qsub GPR:$Rm, GPR:$Rn))], + (ins GPR:$Rm, GPR:$Rn), "\t$Rd, $Rm, $Rn">; +def QDADD : AAI<0b00010100, 0b00000101, "qdadd", [], (ins GPR:$Rm, GPR:$Rn), + "\t$Rd, $Rm, $Rn">; +def QDSUB : AAI<0b00010110, 0b00000101, "qdsub", [], (ins GPR:$Rm, GPR:$Rn), + "\t$Rd, $Rm, $Rn">; + +def QADD16 : AAI<0b01100010, 0b11110001, "qadd16">; +def QADD8 : AAI<0b01100010, 0b11111001, "qadd8">; +def QASX : AAI<0b01100010, 0b11110011, "qasx">; +def QSAX : AAI<0b01100010, 0b11110101, "qsax">; +def QSUB16 : AAI<0b01100010, 0b11110111, "qsub16">; +def QSUB8 : AAI<0b01100010, 0b11111111, "qsub8">; +def UQADD16 : AAI<0b01100110, 0b11110001, "uqadd16">; +def UQADD8 : AAI<0b01100110, 0b11111001, "uqadd8">; +def UQASX : AAI<0b01100110, 0b11110011, "uqasx">; +def UQSAX : AAI<0b01100110, 0b11110101, "uqsax">; +def UQSUB16 : AAI<0b01100110, 0b11110111, "uqsub16">; +def UQSUB8 : AAI<0b01100110, 0b11111111, "uqsub8">; // Signed/Unsigned add/subtract -- for disassembly only -def SASX : AAI<0b01100001, 0b0011, "sasx">; -def SADD16 : AAI<0b01100001, 0b0001, "sadd16">; -def SADD8 : AAI<0b01100001, 0b1001, "sadd8">; -def SSAX : AAI<0b01100001, 0b0101, "ssax">; -def SSUB16 : AAI<0b01100001, 0b0111, "ssub16">; -def SSUB8 : AAI<0b01100001, 0b1111, "ssub8">; -def UASX : AAI<0b01100101, 0b0011, "uasx">; -def UADD16 : AAI<0b01100101, 0b0001, "uadd16">; -def UADD8 : AAI<0b01100101, 0b1001, "uadd8">; -def USAX : AAI<0b01100101, 0b0101, "usax">; -def USUB16 : AAI<0b01100101, 0b0111, "usub16">; -def USUB8 : AAI<0b01100101, 0b1111, "usub8">; +def SASX : AAI<0b01100001, 0b11110011, "sasx">; +def SADD16 : AAI<0b01100001, 0b11110001, "sadd16">; +def SADD8 : AAI<0b01100001, 0b11111001, "sadd8">; +def SSAX : AAI<0b01100001, 0b11110101, "ssax">; +def SSUB16 : AAI<0b01100001, 0b11110111, "ssub16">; +def SSUB8 : AAI<0b01100001, 0b11111111, "ssub8">; +def UASX : AAI<0b01100101, 0b11110011, "uasx">; +def UADD16 : AAI<0b01100101, 0b11110001, "uadd16">; +def UADD8 : AAI<0b01100101, 0b11111001, "uadd8">; +def USAX : AAI<0b01100101, 0b11110101, "usax">; +def USUB16 : AAI<0b01100101, 0b11110111, "usub16">; +def USUB8 : AAI<0b01100101, 0b11111111, "usub8">; // Signed/Unsigned halving add/subtract -- for disassembly only -def SHASX : AAI<0b01100011, 0b0011, "shasx">; -def SHADD16 : AAI<0b01100011, 0b0001, "shadd16">; -def SHADD8 : AAI<0b01100011, 0b1001, "shadd8">; -def SHSAX : AAI<0b01100011, 0b0101, "shsax">; -def SHSUB16 : AAI<0b01100011, 0b0111, "shsub16">; -def SHSUB8 : AAI<0b01100011, 0b1111, "shsub8">; -def UHASX : AAI<0b01100111, 0b0011, "uhasx">; -def UHADD16 : AAI<0b01100111, 0b0001, "uhadd16">; -def UHADD8 : AAI<0b01100111, 0b1001, "uhadd8">; -def UHSAX : AAI<0b01100111, 0b0101, "uhsax">; -def UHSUB16 : AAI<0b01100111, 0b0111, "uhsub16">; -def UHSUB8 : AAI<0b01100111, 0b1111, "uhsub8">; +def SHASX : AAI<0b01100011, 0b11110011, "shasx">; +def SHADD16 : AAI<0b01100011, 0b11110001, "shadd16">; +def SHADD8 : AAI<0b01100011, 0b11111001, "shadd8">; +def SHSAX : AAI<0b01100011, 0b11110101, "shsax">; +def SHSUB16 : AAI<0b01100011, 0b11110111, "shsub16">; +def SHSUB8 : AAI<0b01100011, 0b11111111, "shsub8">; +def UHASX : AAI<0b01100111, 0b11110011, "uhasx">; +def UHADD16 : AAI<0b01100111, 0b11110001, "uhadd16">; +def UHADD8 : AAI<0b01100111, 0b11111001, "uhadd8">; +def UHSAX : AAI<0b01100111, 0b11110101, "uhsax">; +def UHSUB16 : AAI<0b01100111, 0b11110111, "uhsub16">; +def UHSUB8 : AAI<0b01100111, 0b11111111, "uhsub8">; // Unsigned Sum of Absolute Differences [and Accumulate] -- for disassembly only -def USAD8 : AI<(outs GPR:$dst), (ins GPR:$a, GPR:$b), +def USAD8 : AI<(outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), MulFrm /* for convenience */, NoItinerary, "usad8", - "\t$dst, $a, $b", []>, + "\t$Rd, $Rn, $Rm", []>, Requires<[IsARM, HasV6]> { + bits<4> Rd; + bits<4> Rn; + bits<4> Rm; let Inst{27-20} = 0b01111000; let Inst{15-12} = 0b1111; let Inst{7-4} = 0b0001; + let Inst{19-16} = Rd; + let Inst{11-8} = Rm; + let Inst{3-0} = Rn; } -def USADA8 : AI<(outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), +def USADA8 : AI<(outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm, GPR:$Ra), MulFrm /* for convenience */, NoItinerary, "usada8", - "\t$dst, $a, $b, $acc", []>, + "\t$Rd, $Rn, $Rm, $Ra", []>, Requires<[IsARM, HasV6]> { + bits<4> Rd; + bits<4> Rn; + bits<4> Rm; + bits<4> Ra; let Inst{27-20} = 0b01111000; let Inst{7-4} = 0b0001; + let Inst{19-16} = Rd; + let Inst{15-12} = Ra; + let Inst{11-8} = Rm; + let Inst{3-0} = Rn; } // Signed/Unsigned saturate -- for disassembly only -def SSAT : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a, shift_imm:$sh), - SatFrm, NoItinerary, "ssat", "\t$dst, $bit_pos, $a$sh", +def SSAT : AI<(outs GPR:$Rd), (ins i32imm:$sat_imm, GPR:$a, shift_imm:$sh), + SatFrm, NoItinerary, "ssat", "\t$Rd, $sat_imm, $a$sh", [/* For disassembly only; pattern left blank */]> { + bits<4> Rd; + bits<5> sat_imm; + bits<4> Rn; + bits<8> sh; let Inst{27-21} = 0b0110101; let Inst{5-4} = 0b01; + let Inst{20-16} = sat_imm; + let Inst{15-12} = Rd; + let Inst{11-7} = sh{7-3}; + let Inst{6} = sh{0}; + let Inst{3-0} = Rn; } -def SSAT16 : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a), SatFrm, - NoItinerary, "ssat16", "\t$dst, $bit_pos, $a", +def SSAT16 : AI<(outs GPR:$Rd), (ins i32imm:$sat_imm, GPR:$Rn), SatFrm, + NoItinerary, "ssat16", "\t$Rd, $sat_imm, $Rn", [/* For disassembly only; pattern left blank */]> { + bits<4> Rd; + bits<4> sat_imm; + bits<4> Rn; let Inst{27-20} = 0b01101010; - let Inst{7-4} = 0b0011; + let Inst{11-4} = 0b11110011; + let Inst{15-12} = Rd; + let Inst{19-16} = sat_imm; + let Inst{3-0} = Rn; } -def USAT : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a, shift_imm:$sh), - SatFrm, NoItinerary, "usat", "\t$dst, $bit_pos, $a$sh", +def USAT : AI<(outs GPR:$Rd), (ins i32imm:$sat_imm, GPR:$a, shift_imm:$sh), + SatFrm, NoItinerary, "usat", "\t$Rd, $sat_imm, $a$sh", [/* For disassembly only; pattern left blank */]> { + bits<4> Rd; + bits<5> sat_imm; + bits<4> Rn; + bits<8> sh; let Inst{27-21} = 0b0110111; let Inst{5-4} = 0b01; + let Inst{15-12} = Rd; + let Inst{11-7} = sh{7-3}; + let Inst{6} = sh{0}; + let Inst{20-16} = sat_imm; + let Inst{3-0} = Rn; } -def USAT16 : AI<(outs GPR:$dst), (ins i32imm:$bit_pos, GPR:$a), SatFrm, - NoItinerary, "usat16", "\t$dst, $bit_pos, $a", +def USAT16 : AI<(outs GPR:$Rd), (ins i32imm:$sat_imm, GPR:$a), SatFrm, + NoItinerary, "usat16", "\t$Rd, $sat_imm, $a", [/* For disassembly only; pattern left blank */]> { + bits<4> Rd; + bits<4> sat_imm; + bits<4> Rn; let Inst{27-20} = 0b01101110; - let Inst{7-4} = 0b0011; + let Inst{11-4} = 0b11110011; + let Inst{15-12} = Rd; + let Inst{19-16} = sat_imm; + let Inst{3-0} = Rn; } def : ARMV6Pat<(int_arm_ssat GPR:$a, imm:$pos), (SSAT imm:$pos, GPR:$a, 0)>; @@ -1855,52 +2479,100 @@ def : ARMV6Pat<(int_arm_usat GPR:$a, imm:$pos), (USAT imm:$pos, GPR:$a, 0)>; // defm AND : AsI1_bin_irs<0b0000, "and", + IIC_iBITi, IIC_iBITr, IIC_iBITsr, BinOpFrag<(and node:$LHS, node:$RHS)>, 1>; -defm ANDS : AI1_bin_s_irs<0b0000, "and", - BinOpFrag<(ARMand node:$LHS, node:$RHS)>, 1>; defm ORR : AsI1_bin_irs<0b1100, "orr", + IIC_iBITi, IIC_iBITr, IIC_iBITsr, BinOpFrag<(or node:$LHS, node:$RHS)>, 1>; defm EOR : AsI1_bin_irs<0b0001, "eor", + IIC_iBITi, IIC_iBITr, IIC_iBITsr, BinOpFrag<(xor node:$LHS, node:$RHS)>, 1>; defm BIC : AsI1_bin_irs<0b1110, "bic", + IIC_iBITi, IIC_iBITr, IIC_iBITsr, BinOpFrag<(and node:$LHS, (not node:$RHS))>>; -def BFC : I<(outs GPR:$dst), (ins GPR:$src, bf_inv_mask_imm:$imm), +def BFC : I<(outs GPR:$Rd), (ins GPR:$src, bf_inv_mask_imm:$imm), AddrMode1, Size4Bytes, IndexModeNone, DPFrm, IIC_iUNAsi, - "bfc", "\t$dst, $imm", "$src = $dst", - [(set GPR:$dst, (and GPR:$src, bf_inv_mask_imm:$imm))]>, + "bfc", "\t$Rd, $imm", "$src = $Rd", + [(set GPR:$Rd, (and GPR:$src, bf_inv_mask_imm:$imm))]>, Requires<[IsARM, HasV6T2]> { + bits<4> Rd; + bits<10> imm; let Inst{27-21} = 0b0111110; let Inst{6-0} = 0b0011111; + let Inst{15-12} = Rd; + let Inst{11-7} = imm{4-0}; // lsb + let Inst{20-16} = imm{9-5}; // width } // A8.6.18 BFI - Bitfield insert (Encoding A1) -def BFI : I<(outs GPR:$dst), (ins GPR:$src, GPR:$val, bf_inv_mask_imm:$imm), +def BFI : I<(outs GPR:$Rd), (ins GPR:$src, GPR:$Rn, bf_inv_mask_imm:$imm), AddrMode1, Size4Bytes, IndexModeNone, DPFrm, IIC_iUNAsi, - "bfi", "\t$dst, $val, $imm", "$src = $dst", - [(set GPR:$dst, (ARMbfi GPR:$src, GPR:$val, + "bfi", "\t$Rd, $Rn, $imm", "$src = $Rd", + [(set GPR:$Rd, (ARMbfi GPR:$src, GPR:$Rn, bf_inv_mask_imm:$imm))]>, Requires<[IsARM, HasV6T2]> { + bits<4> Rd; + bits<4> Rn; + bits<10> imm; + let Inst{27-21} = 0b0111110; + let Inst{6-4} = 0b001; // Rn: Inst{3-0} != 15 + let Inst{15-12} = Rd; + let Inst{11-7} = imm{4-0}; // lsb + let Inst{20-16} = imm{9-5}; // width + let Inst{3-0} = Rn; +} + +// GNU as only supports this form of bfi (w/ 4 arguments) +let isAsmParserOnly = 1 in +def BFI4p : I<(outs GPR:$Rd), (ins GPR:$src, GPR:$Rn, + lsb_pos_imm:$lsb, width_imm:$width), + AddrMode1, Size4Bytes, IndexModeNone, DPFrm, IIC_iUNAsi, + "bfi", "\t$Rd, $Rn, $lsb, $width", "$src = $Rd", + []>, Requires<[IsARM, HasV6T2]> { + bits<4> Rd; + bits<4> Rn; + bits<5> lsb; + bits<5> width; let Inst{27-21} = 0b0111110; let Inst{6-4} = 0b001; // Rn: Inst{3-0} != 15 + let Inst{15-12} = Rd; + let Inst{11-7} = lsb; + let Inst{20-16} = width; // Custom encoder => lsb+width-1 + let Inst{3-0} = Rn; } -def MVNr : AsI1<0b1111, (outs GPR:$dst), (ins GPR:$src), DPFrm, IIC_iMOVr, - "mvn", "\t$dst, $src", - [(set GPR:$dst, (not GPR:$src))]>, UnaryDP { +def MVNr : AsI1<0b1111, (outs GPR:$Rd), (ins GPR:$Rm), DPFrm, IIC_iMVNr, + "mvn", "\t$Rd, $Rm", + [(set GPR:$Rd, (not GPR:$Rm))]>, UnaryDP { + bits<4> Rd; + bits<4> Rm; let Inst{25} = 0; + let Inst{19-16} = 0b0000; let Inst{11-4} = 0b00000000; -} -def MVNs : AsI1<0b1111, (outs GPR:$dst), (ins so_reg:$src), DPSoRegFrm, - IIC_iMOVsr, "mvn", "\t$dst, $src", - [(set GPR:$dst, (not so_reg:$src))]>, UnaryDP { + let Inst{15-12} = Rd; + let Inst{3-0} = Rm; +} +def MVNs : AsI1<0b1111, (outs GPR:$Rd), (ins so_reg:$shift), DPSoRegFrm, + IIC_iMVNsr, "mvn", "\t$Rd, $shift", + [(set GPR:$Rd, (not so_reg:$shift))]>, UnaryDP { + bits<4> Rd; + bits<12> shift; let Inst{25} = 0; -} -let isReMaterializable = 1, isAsCheapAsAMove = 1 in -def MVNi : AsI1<0b1111, (outs GPR:$dst), (ins so_imm:$imm), DPFrm, - IIC_iMOVi, "mvn", "\t$dst, $imm", - [(set GPR:$dst, so_imm_not:$imm)]>,UnaryDP { - let Inst{25} = 1; + let Inst{19-16} = 0b0000; + let Inst{15-12} = Rd; + let Inst{11-0} = shift; +} +let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveImm = 1 in +def MVNi : AsI1<0b1111, (outs GPR:$Rd), (ins so_imm:$imm), DPFrm, + IIC_iMVNi, "mvn", "\t$Rd, $imm", + [(set GPR:$Rd, so_imm_not:$imm)]>,UnaryDP { + bits<4> Rd; + bits<12> imm; + let Inst{25} = 1; + let Inst{19-16} = 0b0000; + let Inst{15-12} = Rd; + let Inst{11-0} = imm; } def : ARMPat<(and GPR:$src, so_imm_not:$imm), @@ -1909,247 +2581,299 @@ def : ARMPat<(and GPR:$src, so_imm_not:$imm), //===----------------------------------------------------------------------===// // Multiply Instructions. // +class AsMul1I32 opcod, dag oops, dag iops, InstrItinClass itin, + string opc, string asm, list pattern> + : AsMul1I { + bits<4> Rd; + bits<4> Rm; + bits<4> Rn; + let Inst{19-16} = Rd; + let Inst{11-8} = Rm; + let Inst{3-0} = Rn; +} +class AsMul1I64 opcod, dag oops, dag iops, InstrItinClass itin, + string opc, string asm, list pattern> + : AsMul1I { + bits<4> RdLo; + bits<4> RdHi; + bits<4> Rm; + bits<4> Rn; + let Inst{19-16} = RdHi; + let Inst{15-12} = RdLo; + let Inst{11-8} = Rm; + let Inst{3-0} = Rn; +} -let isCommutable = 1 in -def MUL : AsMul1I<0b0000000, (outs GPR:$dst), (ins GPR:$a, GPR:$b), - IIC_iMUL32, "mul", "\t$dst, $a, $b", - [(set GPR:$dst, (mul GPR:$a, GPR:$b))]>; - -def MLA : AsMul1I<0b0000001, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), - IIC_iMAC32, "mla", "\t$dst, $a, $b, $c", - [(set GPR:$dst, (add (mul GPR:$a, GPR:$b), GPR:$c))]>; - -def MLS : AMul1I<0b0000011, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), - IIC_iMAC32, "mls", "\t$dst, $a, $b, $c", - [(set GPR:$dst, (sub GPR:$c, (mul GPR:$a, GPR:$b)))]>, - Requires<[IsARM, HasV6T2]>; +let isCommutable = 1 in { +let Constraints = "@earlyclobber $Rd" in +def MULv5: ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm, + pred:$p, cc_out:$s), + Size4Bytes, IIC_iMUL32, + [(set GPR:$Rd, (mul GPR:$Rn, GPR:$Rm))]>, + Requires<[IsARM, NoV6]>; + +def MUL : AsMul1I32<0b0000000, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), + IIC_iMUL32, "mul", "\t$Rd, $Rn, $Rm", + [(set GPR:$Rd, (mul GPR:$Rn, GPR:$Rm))]>, + Requires<[IsARM, HasV6]>; +} + +let Constraints = "@earlyclobber $Rd" in +def MLAv5: ARMPseudoInst<(outs GPR:$Rd), + (ins GPR:$Rn, GPR:$Rm, GPR:$Ra, pred:$p, cc_out:$s), + Size4Bytes, IIC_iMAC32, + [(set GPR:$Rd, (add (mul GPR:$Rn, GPR:$Rm), GPR:$Ra))]>, + Requires<[IsARM, NoV6]> { + bits<4> Ra; + let Inst{15-12} = Ra; +} +def MLA : AsMul1I32<0b0000001, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm, GPR:$Ra), + IIC_iMAC32, "mla", "\t$Rd, $Rn, $Rm, $Ra", + [(set GPR:$Rd, (add (mul GPR:$Rn, GPR:$Rm), GPR:$Ra))]>, + Requires<[IsARM, HasV6]> { + bits<4> Ra; + let Inst{15-12} = Ra; +} + +def MLS : AMul1I<0b0000011, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm, GPR:$Ra), + IIC_iMAC32, "mls", "\t$Rd, $Rn, $Rm, $Ra", + [(set GPR:$Rd, (sub GPR:$Ra, (mul GPR:$Rn, GPR:$Rm)))]>, + Requires<[IsARM, HasV6T2]> { + bits<4> Rd; + bits<4> Rm; + bits<4> Rn; + bits<4> Ra; + let Inst{19-16} = Rd; + let Inst{15-12} = Ra; + let Inst{11-8} = Rm; + let Inst{3-0} = Rn; +} // Extra precision multiplies with low / high results + let neverHasSideEffects = 1 in { let isCommutable = 1 in { -def SMULL : AsMul1I<0b0000110, (outs GPR:$ldst, GPR:$hdst), - (ins GPR:$a, GPR:$b), IIC_iMUL64, - "smull", "\t$ldst, $hdst, $a, $b", []>; +let Constraints = "@earlyclobber $RdLo,@earlyclobber $RdHi" in { +def SMULLv5 : ARMPseudoInst<(outs GPR:$RdLo, GPR:$RdHi), + (ins GPR:$Rn, GPR:$Rm, pred:$p, cc_out:$s), + Size4Bytes, IIC_iMUL64, []>, + Requires<[IsARM, NoV6]>; -def UMULL : AsMul1I<0b0000100, (outs GPR:$ldst, GPR:$hdst), - (ins GPR:$a, GPR:$b), IIC_iMUL64, - "umull", "\t$ldst, $hdst, $a, $b", []>; +def UMULLv5 : ARMPseudoInst<(outs GPR:$RdLo, GPR:$RdHi), + (ins GPR:$Rn, GPR:$Rm, pred:$p, cc_out:$s), + Size4Bytes, IIC_iMUL64, []>, + Requires<[IsARM, NoV6]>; } -// Multiply + accumulate -def SMLAL : AsMul1I<0b0000111, (outs GPR:$ldst, GPR:$hdst), - (ins GPR:$a, GPR:$b), IIC_iMAC64, - "smlal", "\t$ldst, $hdst, $a, $b", []>; +def SMULL : AsMul1I64<0b0000110, (outs GPR:$RdLo, GPR:$RdHi), + (ins GPR:$Rn, GPR:$Rm), IIC_iMUL64, + "smull", "\t$RdLo, $RdHi, $Rn, $Rm", []>, + Requires<[IsARM, HasV6]>; -def UMLAL : AsMul1I<0b0000101, (outs GPR:$ldst, GPR:$hdst), - (ins GPR:$a, GPR:$b), IIC_iMAC64, - "umlal", "\t$ldst, $hdst, $a, $b", []>; +def UMULL : AsMul1I64<0b0000100, (outs GPR:$RdLo, GPR:$RdHi), + (ins GPR:$Rn, GPR:$Rm), IIC_iMUL64, + "umull", "\t$RdLo, $RdHi, $Rn, $Rm", []>, + Requires<[IsARM, HasV6]>; +} -def UMAAL : AMul1I <0b0000010, (outs GPR:$ldst, GPR:$hdst), - (ins GPR:$a, GPR:$b), IIC_iMAC64, - "umaal", "\t$ldst, $hdst, $a, $b", []>, +// Multiply + accumulate +let Constraints = "@earlyclobber $RdLo,@earlyclobber $RdHi" in { +def SMLALv5 : ARMPseudoInst<(outs GPR:$RdLo, GPR:$RdHi), + (ins GPR:$Rn, GPR:$Rm, pred:$p, cc_out:$s), + Size4Bytes, IIC_iMAC64, []>, + Requires<[IsARM, NoV6]>; +def UMLALv5 : ARMPseudoInst<(outs GPR:$RdLo, GPR:$RdHi), + (ins GPR:$Rn, GPR:$Rm, pred:$p, cc_out:$s), + Size4Bytes, IIC_iMAC64, []>, + Requires<[IsARM, NoV6]>; +def UMAALv5 : ARMPseudoInst<(outs GPR:$RdLo, GPR:$RdHi), + (ins GPR:$Rn, GPR:$Rm, pred:$p, cc_out:$s), + Size4Bytes, IIC_iMAC64, []>, + Requires<[IsARM, NoV6]>; + +} + +def SMLAL : AsMul1I64<0b0000111, (outs GPR:$RdLo, GPR:$RdHi), + (ins GPR:$Rn, GPR:$Rm), IIC_iMAC64, + "smlal", "\t$RdLo, $RdHi, $Rn, $Rm", []>, + Requires<[IsARM, HasV6]>; +def UMLAL : AsMul1I64<0b0000101, (outs GPR:$RdLo, GPR:$RdHi), + (ins GPR:$Rn, GPR:$Rm), IIC_iMAC64, + "umlal", "\t$RdLo, $RdHi, $Rn, $Rm", []>, Requires<[IsARM, HasV6]>; + +def UMAAL : AMul1I <0b0000010, (outs GPR:$RdLo, GPR:$RdHi), + (ins GPR:$Rn, GPR:$Rm), IIC_iMAC64, + "umaal", "\t$RdLo, $RdHi, $Rn, $Rm", []>, + Requires<[IsARM, HasV6]> { + bits<4> RdLo; + bits<4> RdHi; + bits<4> Rm; + bits<4> Rn; + let Inst{19-16} = RdLo; + let Inst{15-12} = RdHi; + let Inst{11-8} = Rm; + let Inst{3-0} = Rn; +} } // neverHasSideEffects // Most significant word multiply -def SMMUL : AMul2I <0b0111010, (outs GPR:$dst), (ins GPR:$a, GPR:$b), - IIC_iMUL32, "smmul", "\t$dst, $a, $b", - [(set GPR:$dst, (mulhs GPR:$a, GPR:$b))]>, +def SMMUL : AMul2I <0b0111010, 0b0001, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), + IIC_iMUL32, "smmul", "\t$Rd, $Rn, $Rm", + [(set GPR:$Rd, (mulhs GPR:$Rn, GPR:$Rm))]>, Requires<[IsARM, HasV6]> { - let Inst{7-4} = 0b0001; let Inst{15-12} = 0b1111; } -def SMMULR : AMul2I <0b0111010, (outs GPR:$dst), (ins GPR:$a, GPR:$b), - IIC_iMUL32, "smmulr", "\t$dst, $a, $b", +def SMMULR : AMul2I <0b0111010, 0b0011, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), + IIC_iMUL32, "smmulr", "\t$Rd, $Rn, $Rm", [/* For disassembly only; pattern left blank */]>, Requires<[IsARM, HasV6]> { - let Inst{7-4} = 0b0011; // R = 1 let Inst{15-12} = 0b1111; } -def SMMLA : AMul2I <0b0111010, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), - IIC_iMAC32, "smmla", "\t$dst, $a, $b, $c", - [(set GPR:$dst, (add (mulhs GPR:$a, GPR:$b), GPR:$c))]>, - Requires<[IsARM, HasV6]> { - let Inst{7-4} = 0b0001; -} +def SMMLA : AMul2Ia <0b0111010, 0b0001, (outs GPR:$Rd), + (ins GPR:$Rn, GPR:$Rm, GPR:$Ra), + IIC_iMAC32, "smmla", "\t$Rd, $Rn, $Rm, $Ra", + [(set GPR:$Rd, (add (mulhs GPR:$Rn, GPR:$Rm), GPR:$Ra))]>, + Requires<[IsARM, HasV6]>; -def SMMLAR : AMul2I <0b0111010, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), - IIC_iMAC32, "smmlar", "\t$dst, $a, $b, $c", +def SMMLAR : AMul2Ia <0b0111010, 0b0011, (outs GPR:$Rd), + (ins GPR:$Rn, GPR:$Rm, GPR:$Ra), + IIC_iMAC32, "smmlar", "\t$Rd, $Rn, $Rm, $Ra", [/* For disassembly only; pattern left blank */]>, - Requires<[IsARM, HasV6]> { - let Inst{7-4} = 0b0011; // R = 1 -} + Requires<[IsARM, HasV6]>; -def SMMLS : AMul2I <0b0111010, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), - IIC_iMAC32, "smmls", "\t$dst, $a, $b, $c", - [(set GPR:$dst, (sub GPR:$c, (mulhs GPR:$a, GPR:$b)))]>, - Requires<[IsARM, HasV6]> { - let Inst{7-4} = 0b1101; -} +def SMMLS : AMul2Ia <0b0111010, 0b1101, (outs GPR:$Rd), + (ins GPR:$Rn, GPR:$Rm, GPR:$Ra), + IIC_iMAC32, "smmls", "\t$Rd, $Rn, $Rm, $Ra", + [(set GPR:$Rd, (sub GPR:$Ra, (mulhs GPR:$Rn, GPR:$Rm)))]>, + Requires<[IsARM, HasV6]>; -def SMMLSR : AMul2I <0b0111010, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$c), - IIC_iMAC32, "smmlsr", "\t$dst, $a, $b, $c", +def SMMLSR : AMul2Ia <0b0111010, 0b1111, (outs GPR:$Rd), + (ins GPR:$Rn, GPR:$Rm, GPR:$Ra), + IIC_iMAC32, "smmlsr", "\t$Rd, $Rn, $Rm, $Ra", [/* For disassembly only; pattern left blank */]>, - Requires<[IsARM, HasV6]> { - let Inst{7-4} = 0b1111; // R = 1 -} + Requires<[IsARM, HasV6]>; multiclass AI_smul { - def BB : AMulxyI<0b0001011, (outs GPR:$dst), (ins GPR:$a, GPR:$b), - IIC_iMUL32, !strconcat(opc, "bb"), "\t$dst, $a, $b", - [(set GPR:$dst, (opnode (sext_inreg GPR:$a, i16), - (sext_inreg GPR:$b, i16)))]>, - Requires<[IsARM, HasV5TE]> { - let Inst{5} = 0; - let Inst{6} = 0; - } - - def BT : AMulxyI<0b0001011, (outs GPR:$dst), (ins GPR:$a, GPR:$b), - IIC_iMUL32, !strconcat(opc, "bt"), "\t$dst, $a, $b", - [(set GPR:$dst, (opnode (sext_inreg GPR:$a, i16), - (sra GPR:$b, (i32 16))))]>, - Requires<[IsARM, HasV5TE]> { - let Inst{5} = 0; - let Inst{6} = 1; - } - - def TB : AMulxyI<0b0001011, (outs GPR:$dst), (ins GPR:$a, GPR:$b), - IIC_iMUL32, !strconcat(opc, "tb"), "\t$dst, $a, $b", - [(set GPR:$dst, (opnode (sra GPR:$a, (i32 16)), - (sext_inreg GPR:$b, i16)))]>, - Requires<[IsARM, HasV5TE]> { - let Inst{5} = 1; - let Inst{6} = 0; - } - - def TT : AMulxyI<0b0001011, (outs GPR:$dst), (ins GPR:$a, GPR:$b), - IIC_iMUL32, !strconcat(opc, "tt"), "\t$dst, $a, $b", - [(set GPR:$dst, (opnode (sra GPR:$a, (i32 16)), - (sra GPR:$b, (i32 16))))]>, - Requires<[IsARM, HasV5TE]> { - let Inst{5} = 1; - let Inst{6} = 1; - } - - def WB : AMulxyI<0b0001001, (outs GPR:$dst), (ins GPR:$a, GPR:$b), - IIC_iMUL16, !strconcat(opc, "wb"), "\t$dst, $a, $b", - [(set GPR:$dst, (sra (opnode GPR:$a, - (sext_inreg GPR:$b, i16)), (i32 16)))]>, - Requires<[IsARM, HasV5TE]> { - let Inst{5} = 1; - let Inst{6} = 0; - } - - def WT : AMulxyI<0b0001001, (outs GPR:$dst), (ins GPR:$a, GPR:$b), - IIC_iMUL16, !strconcat(opc, "wt"), "\t$dst, $a, $b", - [(set GPR:$dst, (sra (opnode GPR:$a, - (sra GPR:$b, (i32 16))), (i32 16)))]>, - Requires<[IsARM, HasV5TE]> { - let Inst{5} = 1; - let Inst{6} = 1; - } + def BB : AMulxyI<0b0001011, 0b00, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), + IIC_iMUL16, !strconcat(opc, "bb"), "\t$Rd, $Rn, $Rm", + [(set GPR:$Rd, (opnode (sext_inreg GPR:$Rn, i16), + (sext_inreg GPR:$Rm, i16)))]>, + Requires<[IsARM, HasV5TE]>; + + def BT : AMulxyI<0b0001011, 0b10, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), + IIC_iMUL16, !strconcat(opc, "bt"), "\t$Rd, $Rn, $Rm", + [(set GPR:$Rd, (opnode (sext_inreg GPR:$Rn, i16), + (sra GPR:$Rm, (i32 16))))]>, + Requires<[IsARM, HasV5TE]>; + + def TB : AMulxyI<0b0001011, 0b01, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), + IIC_iMUL16, !strconcat(opc, "tb"), "\t$Rd, $Rn, $Rm", + [(set GPR:$Rd, (opnode (sra GPR:$Rn, (i32 16)), + (sext_inreg GPR:$Rm, i16)))]>, + Requires<[IsARM, HasV5TE]>; + + def TT : AMulxyI<0b0001011, 0b11, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), + IIC_iMUL16, !strconcat(opc, "tt"), "\t$Rd, $Rn, $Rm", + [(set GPR:$Rd, (opnode (sra GPR:$Rn, (i32 16)), + (sra GPR:$Rm, (i32 16))))]>, + Requires<[IsARM, HasV5TE]>; + + def WB : AMulxyI<0b0001001, 0b01, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), + IIC_iMUL16, !strconcat(opc, "wb"), "\t$Rd, $Rn, $Rm", + [(set GPR:$Rd, (sra (opnode GPR:$Rn, + (sext_inreg GPR:$Rm, i16)), (i32 16)))]>, + Requires<[IsARM, HasV5TE]>; + + def WT : AMulxyI<0b0001001, 0b11, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), + IIC_iMUL16, !strconcat(opc, "wt"), "\t$Rd, $Rn, $Rm", + [(set GPR:$Rd, (sra (opnode GPR:$Rn, + (sra GPR:$Rm, (i32 16))), (i32 16)))]>, + Requires<[IsARM, HasV5TE]>; } multiclass AI_smla { - def BB : AMulxyI<0b0001000, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), - IIC_iMAC16, !strconcat(opc, "bb"), "\t$dst, $a, $b, $acc", - [(set GPR:$dst, (add GPR:$acc, - (opnode (sext_inreg GPR:$a, i16), - (sext_inreg GPR:$b, i16))))]>, - Requires<[IsARM, HasV5TE]> { - let Inst{5} = 0; - let Inst{6} = 0; - } - - def BT : AMulxyI<0b0001000, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), - IIC_iMAC16, !strconcat(opc, "bt"), "\t$dst, $a, $b, $acc", - [(set GPR:$dst, (add GPR:$acc, (opnode (sext_inreg GPR:$a, i16), - (sra GPR:$b, (i32 16)))))]>, - Requires<[IsARM, HasV5TE]> { - let Inst{5} = 0; - let Inst{6} = 1; - } - - def TB : AMulxyI<0b0001000, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), - IIC_iMAC16, !strconcat(opc, "tb"), "\t$dst, $a, $b, $acc", - [(set GPR:$dst, (add GPR:$acc, (opnode (sra GPR:$a, (i32 16)), - (sext_inreg GPR:$b, i16))))]>, - Requires<[IsARM, HasV5TE]> { - let Inst{5} = 1; - let Inst{6} = 0; - } - - def TT : AMulxyI<0b0001000, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), - IIC_iMAC16, !strconcat(opc, "tt"), "\t$dst, $a, $b, $acc", - [(set GPR:$dst, (add GPR:$acc, (opnode (sra GPR:$a, (i32 16)), - (sra GPR:$b, (i32 16)))))]>, - Requires<[IsARM, HasV5TE]> { - let Inst{5} = 1; - let Inst{6} = 1; - } - - def WB : AMulxyI<0b0001001, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), - IIC_iMAC16, !strconcat(opc, "wb"), "\t$dst, $a, $b, $acc", - [(set GPR:$dst, (add GPR:$acc, (sra (opnode GPR:$a, - (sext_inreg GPR:$b, i16)), (i32 16))))]>, - Requires<[IsARM, HasV5TE]> { - let Inst{5} = 0; - let Inst{6} = 0; - } - - def WT : AMulxyI<0b0001001, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), - IIC_iMAC16, !strconcat(opc, "wt"), "\t$dst, $a, $b, $acc", - [(set GPR:$dst, (add GPR:$acc, (sra (opnode GPR:$a, - (sra GPR:$b, (i32 16))), (i32 16))))]>, - Requires<[IsARM, HasV5TE]> { - let Inst{5} = 0; - let Inst{6} = 1; - } + def BB : AMulxyIa<0b0001000, 0b00, (outs GPR:$Rd), + (ins GPR:$Rn, GPR:$Rm, GPR:$Ra), + IIC_iMAC16, !strconcat(opc, "bb"), "\t$Rd, $Rn, $Rm, $Ra", + [(set GPR:$Rd, (add GPR:$Ra, + (opnode (sext_inreg GPR:$Rn, i16), + (sext_inreg GPR:$Rm, i16))))]>, + Requires<[IsARM, HasV5TE]>; + + def BT : AMulxyIa<0b0001000, 0b10, (outs GPR:$Rd), + (ins GPR:$Rn, GPR:$Rm, GPR:$Ra), + IIC_iMAC16, !strconcat(opc, "bt"), "\t$Rd, $Rn, $Rm, $Ra", + [(set GPR:$Rd, (add GPR:$Ra, (opnode (sext_inreg GPR:$Rn, i16), + (sra GPR:$Rm, (i32 16)))))]>, + Requires<[IsARM, HasV5TE]>; + + def TB : AMulxyIa<0b0001000, 0b01, (outs GPR:$Rd), + (ins GPR:$Rn, GPR:$Rm, GPR:$Ra), + IIC_iMAC16, !strconcat(opc, "tb"), "\t$Rd, $Rn, $Rm, $Ra", + [(set GPR:$Rd, (add GPR:$Ra, (opnode (sra GPR:$Rn, (i32 16)), + (sext_inreg GPR:$Rm, i16))))]>, + Requires<[IsARM, HasV5TE]>; + + def TT : AMulxyIa<0b0001000, 0b11, (outs GPR:$Rd), + (ins GPR:$Rn, GPR:$Rm, GPR:$Ra), + IIC_iMAC16, !strconcat(opc, "tt"), "\t$Rd, $Rn, $Rm, $Ra", + [(set GPR:$Rd, (add GPR:$Ra, (opnode (sra GPR:$Rn, (i32 16)), + (sra GPR:$Rm, (i32 16)))))]>, + Requires<[IsARM, HasV5TE]>; + + def WB : AMulxyIa<0b0001001, 0b00, (outs GPR:$Rd), + (ins GPR:$Rn, GPR:$Rm, GPR:$Ra), + IIC_iMAC16, !strconcat(opc, "wb"), "\t$Rd, $Rn, $Rm, $Ra", + [(set GPR:$Rd, (add GPR:$Ra, (sra (opnode GPR:$Rn, + (sext_inreg GPR:$Rm, i16)), (i32 16))))]>, + Requires<[IsARM, HasV5TE]>; + + def WT : AMulxyIa<0b0001001, 0b10, (outs GPR:$Rd), + (ins GPR:$Rn, GPR:$Rm, GPR:$Ra), + IIC_iMAC16, !strconcat(opc, "wt"), "\t$Rd, $Rn, $Rm, $Ra", + [(set GPR:$Rd, (add GPR:$Ra, (sra (opnode GPR:$Rn, + (sra GPR:$Rm, (i32 16))), (i32 16))))]>, + Requires<[IsARM, HasV5TE]>; } defm SMUL : AI_smul<"smul", BinOpFrag<(mul node:$LHS, node:$RHS)>>; defm SMLA : AI_smla<"smla", BinOpFrag<(mul node:$LHS, node:$RHS)>>; // Halfword multiply accumulate long: SMLAL -- for disassembly only -def SMLALBB : AMulxyI<0b0001010,(outs GPR:$ldst,GPR:$hdst),(ins GPR:$a,GPR:$b), - IIC_iMAC64, "smlalbb", "\t$ldst, $hdst, $a, $b", +def SMLALBB : AMulxyI64<0b0001010, 0b00, (outs GPR:$RdLo, GPR:$RdHi), + (ins GPR:$Rn, GPR:$Rm), + IIC_iMAC64, "smlalbb", "\t$RdLo, $RdHi, $Rn, $Rm", [/* For disassembly only; pattern left blank */]>, - Requires<[IsARM, HasV5TE]> { - let Inst{5} = 0; - let Inst{6} = 0; -} + Requires<[IsARM, HasV5TE]>; -def SMLALBT : AMulxyI<0b0001010,(outs GPR:$ldst,GPR:$hdst),(ins GPR:$a,GPR:$b), - IIC_iMAC64, "smlalbt", "\t$ldst, $hdst, $a, $b", +def SMLALBT : AMulxyI64<0b0001010, 0b10, (outs GPR:$RdLo, GPR:$RdHi), + (ins GPR:$Rn, GPR:$Rm), + IIC_iMAC64, "smlalbt", "\t$RdLo, $RdHi, $Rn, $Rm", [/* For disassembly only; pattern left blank */]>, - Requires<[IsARM, HasV5TE]> { - let Inst{5} = 0; - let Inst{6} = 1; -} + Requires<[IsARM, HasV5TE]>; -def SMLALTB : AMulxyI<0b0001010,(outs GPR:$ldst,GPR:$hdst),(ins GPR:$a,GPR:$b), - IIC_iMAC64, "smlaltb", "\t$ldst, $hdst, $a, $b", +def SMLALTB : AMulxyI64<0b0001010, 0b01, (outs GPR:$RdLo, GPR:$RdHi), + (ins GPR:$Rn, GPR:$Rm), + IIC_iMAC64, "smlaltb", "\t$RdLo, $RdHi, $Rn, $Rm", [/* For disassembly only; pattern left blank */]>, - Requires<[IsARM, HasV5TE]> { - let Inst{5} = 1; - let Inst{6} = 0; -} + Requires<[IsARM, HasV5TE]>; -def SMLALTT : AMulxyI<0b0001010,(outs GPR:$ldst,GPR:$hdst),(ins GPR:$a,GPR:$b), - IIC_iMAC64, "smlaltt", "\t$ldst, $hdst, $a, $b", +def SMLALTT : AMulxyI64<0b0001010, 0b11, (outs GPR:$RdLo, GPR:$RdHi), + (ins GPR:$Rn, GPR:$Rm), + IIC_iMAC64, "smlaltt", "\t$RdLo, $RdHi, $Rn, $Rm", [/* For disassembly only; pattern left blank */]>, - Requires<[IsARM, HasV5TE]> { - let Inst{5} = 1; - let Inst{6} = 1; -} + Requires<[IsARM, HasV5TE]>; // Helper class for AI_smld -- for disassembly only -class AMulDualI +class AMulDualIbase : AI, Requires<[IsARM, HasV6]> { + bits<4> Rn; + bits<4> Rm; let Inst{4} = 1; let Inst{5} = swap; let Inst{6} = sub; @@ -2157,21 +2881,46 @@ class AMulDualI + : AMulDualIbase { + bits<4> Rd; + let Inst{15-12} = 0b1111; + let Inst{19-16} = Rd; +} +class AMulDualIa + : AMulDualIbase { + bits<4> Ra; + let Inst{15-12} = Ra; +} +class AMulDualI64 + : AMulDualIbase { + bits<4> RdLo; + bits<4> RdHi; + let Inst{19-16} = RdHi; + let Inst{15-12} = RdLo; } multiclass AI_smld { - def D : AMulDualI<0, sub, 0, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), - NoItinerary, !strconcat(opc, "d"), "\t$dst, $a, $b, $acc">; + def D : AMulDualIa<0, sub, 0, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm, GPR:$Ra), + NoItinerary, !strconcat(opc, "d"), "\t$Rd, $Rn, $Rm, $Ra">; - def DX : AMulDualI<0, sub, 1, (outs GPR:$dst), (ins GPR:$a, GPR:$b, GPR:$acc), - NoItinerary, !strconcat(opc, "dx"), "\t$dst, $a, $b, $acc">; + def DX: AMulDualIa<0, sub, 1, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm, GPR:$Ra), + NoItinerary, !strconcat(opc, "dx"), "\t$Rd, $Rn, $Rm, $Ra">; - def LD : AMulDualI<1, sub, 0, (outs GPR:$ldst,GPR:$hdst), (ins GPR:$a,GPR:$b), - NoItinerary, !strconcat(opc, "ld"), "\t$ldst, $hdst, $a, $b">; + def LD: AMulDualI64<1, sub, 0, (outs GPR:$RdLo,GPR:$RdHi), + (ins GPR:$Rn, GPR:$Rm), NoItinerary, + !strconcat(opc, "ld"), "\t$RdLo, $RdHi, $Rn, $Rm">; - def LDX : AMulDualI<1, sub, 1, (outs GPR:$ldst,GPR:$hdst),(ins GPR:$a,GPR:$b), - NoItinerary, !strconcat(opc, "ldx"),"\t$ldst, $hdst, $a, $b">; + def LDX : AMulDualI64<1, sub, 1, (outs GPR:$RdLo,GPR:$RdHi), + (ins GPR:$Rn, GPR:$Rm), NoItinerary, + !strconcat(opc, "ldx"),"\t$RdLo, $RdHi, $Rn, $Rm">; } @@ -2180,16 +2929,10 @@ defm SMLS : AI_smld<1, "smls">; multiclass AI_sdml { - def D : AMulDualI<0, sub, 0, (outs GPR:$dst), (ins GPR:$a, GPR:$b), - NoItinerary, !strconcat(opc, "d"), "\t$dst, $a, $b"> { - let Inst{15-12} = 0b1111; - } - - def DX : AMulDualI<0, sub, 1, (outs GPR:$dst), (ins GPR:$a, GPR:$b), - NoItinerary, !strconcat(opc, "dx"), "\t$dst, $a, $b"> { - let Inst{15-12} = 0b1111; - } - + def D : AMulDualI<0, sub, 0, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), + NoItinerary, !strconcat(opc, "d"), "\t$Rd, $Rn, $Rm">; + def DX : AMulDualI<0, sub, 1, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), + NoItinerary, !strconcat(opc, "dx"), "\t$Rd, $Rn, $Rm">; } defm SMUA : AI_sdml<0, "smua">; @@ -2199,55 +2942,35 @@ defm SMUS : AI_sdml<1, "smus">; // Misc. Arithmetic Instructions. // -def CLZ : AMiscA1I<0b000010110, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr, - "clz", "\t$dst, $src", - [(set GPR:$dst, (ctlz GPR:$src))]>, Requires<[IsARM, HasV5T]> { - let Inst{7-4} = 0b0001; - let Inst{11-8} = 0b1111; - let Inst{19-16} = 0b1111; -} - -def RBIT : AMiscA1I<0b01101111, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr, - "rbit", "\t$dst, $src", - [(set GPR:$dst, (ARMrbit GPR:$src))]>, - Requires<[IsARM, HasV6T2]> { - let Inst{7-4} = 0b0011; - let Inst{11-8} = 0b1111; - let Inst{19-16} = 0b1111; -} - -def REV : AMiscA1I<0b01101011, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr, - "rev", "\t$dst, $src", - [(set GPR:$dst, (bswap GPR:$src))]>, Requires<[IsARM, HasV6]> { - let Inst{7-4} = 0b0011; - let Inst{11-8} = 0b1111; - let Inst{19-16} = 0b1111; -} - -def REV16 : AMiscA1I<0b01101011, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr, - "rev16", "\t$dst, $src", - [(set GPR:$dst, - (or (and (srl GPR:$src, (i32 8)), 0xFF), - (or (and (shl GPR:$src, (i32 8)), 0xFF00), - (or (and (srl GPR:$src, (i32 8)), 0xFF0000), - (and (shl GPR:$src, (i32 8)), 0xFF000000)))))]>, - Requires<[IsARM, HasV6]> { - let Inst{7-4} = 0b1011; - let Inst{11-8} = 0b1111; - let Inst{19-16} = 0b1111; -} - -def REVSH : AMiscA1I<0b01101111, (outs GPR:$dst), (ins GPR:$src), IIC_iUNAr, - "revsh", "\t$dst, $src", - [(set GPR:$dst, +def CLZ : AMiscA1I<0b000010110, 0b0001, (outs GPR:$Rd), (ins GPR:$Rm), + IIC_iUNAr, "clz", "\t$Rd, $Rm", + [(set GPR:$Rd, (ctlz GPR:$Rm))]>, Requires<[IsARM, HasV5T]>; + +def RBIT : AMiscA1I<0b01101111, 0b0011, (outs GPR:$Rd), (ins GPR:$Rm), + IIC_iUNAr, "rbit", "\t$Rd, $Rm", + [(set GPR:$Rd, (ARMrbit GPR:$Rm))]>, + Requires<[IsARM, HasV6T2]>; + +def REV : AMiscA1I<0b01101011, 0b0011, (outs GPR:$Rd), (ins GPR:$Rm), + IIC_iUNAr, "rev", "\t$Rd, $Rm", + [(set GPR:$Rd, (bswap GPR:$Rm))]>, Requires<[IsARM, HasV6]>; + +def REV16 : AMiscA1I<0b01101011, 0b1011, (outs GPR:$Rd), (ins GPR:$Rm), + IIC_iUNAr, "rev16", "\t$Rd, $Rm", + [(set GPR:$Rd, + (or (and (srl GPR:$Rm, (i32 8)), 0xFF), + (or (and (shl GPR:$Rm, (i32 8)), 0xFF00), + (or (and (srl GPR:$Rm, (i32 8)), 0xFF0000), + (and (shl GPR:$Rm, (i32 8)), 0xFF000000)))))]>, + Requires<[IsARM, HasV6]>; + +def REVSH : AMiscA1I<0b01101111, 0b1011, (outs GPR:$Rd), (ins GPR:$Rm), + IIC_iUNAr, "revsh", "\t$Rd, $Rm", + [(set GPR:$Rd, (sext_inreg - (or (srl (and GPR:$src, 0xFF00), (i32 8)), - (shl GPR:$src, (i32 8))), i16))]>, - Requires<[IsARM, HasV6]> { - let Inst{7-4} = 0b1011; - let Inst{11-8} = 0b1111; - let Inst{19-16} = 0b1111; -} + (or (srl (and GPR:$Rm, 0xFF00), (i32 8)), + (shl GPR:$Rm, (i32 8))), i16))]>, + Requires<[IsARM, HasV6]>; def lsl_shift_imm : SDNodeXFormgetZExtValue()); @@ -2258,21 +2981,19 @@ def lsl_amt : PatLeaf<(i32 imm), [{ return (N->getZExtValue() < 32); }], lsl_shift_imm>; -def PKHBT : AMiscA1I<0b01101000, (outs GPR:$dst), - (ins GPR:$src1, GPR:$src2, shift_imm:$sh), - IIC_iALUsi, "pkhbt", "\t$dst, $src1, $src2$sh", - [(set GPR:$dst, (or (and GPR:$src1, 0xFFFF), - (and (shl GPR:$src2, lsl_amt:$sh), - 0xFFFF0000)))]>, - Requires<[IsARM, HasV6]> { - let Inst{6-4} = 0b001; -} +def PKHBT : APKHI<0b01101000, 0, (outs GPR:$Rd), + (ins GPR:$Rn, GPR:$Rm, shift_imm:$sh), + IIC_iALUsi, "pkhbt", "\t$Rd, $Rn, $Rm$sh", + [(set GPR:$Rd, (or (and GPR:$Rn, 0xFFFF), + (and (shl GPR:$Rm, lsl_amt:$sh), + 0xFFFF0000)))]>, + Requires<[IsARM, HasV6]>; // Alternate cases for PKHBT where identities eliminate some nodes. -def : ARMV6Pat<(or (and GPR:$src1, 0xFFFF), (and GPR:$src2, 0xFFFF0000)), - (PKHBT GPR:$src1, GPR:$src2, 0)>; -def : ARMV6Pat<(or (and GPR:$src1, 0xFFFF), (shl GPR:$src2, imm16_31:$sh)), - (PKHBT GPR:$src1, GPR:$src2, (lsl_shift_imm imm16_31:$sh))>; +def : ARMV6Pat<(or (and GPR:$Rn, 0xFFFF), (and GPR:$Rm, 0xFFFF0000)), + (PKHBT GPR:$Rn, GPR:$Rm, 0)>; +def : ARMV6Pat<(or (and GPR:$Rn, 0xFFFF), (shl GPR:$Rm, imm16_31:$sh)), + (PKHBT GPR:$Rn, GPR:$Rm, (lsl_shift_imm imm16_31:$sh))>; def asr_shift_imm : SDNodeXFormgetZExtValue()); @@ -2285,15 +3006,13 @@ def asr_amt : PatLeaf<(i32 imm), [{ // Note: Shifts of 1-15 bits will be transformed to srl instead of sra and // will match the pattern below. -def PKHTB : AMiscA1I<0b01101000, (outs GPR:$dst), - (ins GPR:$src1, GPR:$src2, shift_imm:$sh), - IIC_iALUsi, "pkhtb", "\t$dst, $src1, $src2$sh", - [(set GPR:$dst, (or (and GPR:$src1, 0xFFFF0000), - (and (sra GPR:$src2, asr_amt:$sh), - 0xFFFF)))]>, - Requires<[IsARM, HasV6]> { - let Inst{6-4} = 0b101; -} +def PKHTB : APKHI<0b01101000, 1, (outs GPR:$Rd), + (ins GPR:$Rn, GPR:$Rm, shift_imm:$sh), + IIC_iBITsi, "pkhtb", "\t$Rd, $Rn, $Rm$sh", + [(set GPR:$Rd, (or (and GPR:$Rn, 0xFFFF0000), + (and (sra GPR:$Rm, asr_amt:$sh), + 0xFFFF)))]>, + Requires<[IsARM, HasV6]>; // Alternate cases for PKHTB where identities eliminate some nodes. Note that // a shift amount of 0 is *not legal* here, it is PKHBT instead. @@ -2308,10 +3027,19 @@ def : ARMV6Pat<(or (and GPR:$src1, 0xFFFF0000), // defm CMP : AI1_cmp_irs<0b1010, "cmp", + IIC_iCMPi, IIC_iCMPr, IIC_iCMPsr, BinOpFrag<(ARMcmp node:$LHS, node:$RHS)>>; -// FIXME: There seems to be a (potential) hardware bug with the CMN instruction -// and comparison with 0. These two pieces of code should give identical +// ARMcmpZ can re-use the above instruction definitions. +def : ARMPat<(ARMcmpZ GPR:$src, so_imm:$imm), + (CMPri GPR:$src, so_imm:$imm)>; +def : ARMPat<(ARMcmpZ GPR:$src, GPR:$rhs), + (CMPrr GPR:$src, GPR:$rhs)>; +def : ARMPat<(ARMcmpZ GPR:$src, so_reg:$rhs), + (CMPrs GPR:$src, so_reg:$rhs)>; + +// FIXME: We have to be careful when using the CMN instruction and comparison +// with 0. One would expect these two pieces of code should give identical // results: // // rsbs r1, r1, 0 @@ -2321,7 +3049,7 @@ defm CMP : AI1_cmp_irs<0b1010, "cmp", // mov r0, #1 // // and: -// +// // cmn r0, r1 // mov r0, #0 // it ls @@ -2336,20 +3064,16 @@ defm CMP : AI1_cmp_irs<0b1010, "cmp", // never a "carry" when this AddWithCarry is performed (because the "carry bit" // parameter to AddWithCarry is defined as 0). // -// The AddWithCarry in the CMP case seems to be relying upon the identity: -// -// ~x + 1 = -x -// -// However when x is 0 and unsigned, this doesn't hold: +// When x is 0 and unsigned: // // x = 0 // ~x = 0xFFFF FFFF // ~x + 1 = 0x1 0000 0000 // (-x = 0) != (0x1 0000 0000 = ~x + 1) // -// Therefore, we should disable *all* versions of CMN, especially when comparing -// against zero, until we can limit when the CMN instruction is used (when we -// know that the RHS is not 0) or when we have a hardware fix for this. +// Therefore, we should disable CMN when comparing against zero, until we can +// limit when the CMN instruction is used (when we know that the RHS is not 0 or +// when it's a comparison which doesn't look at the 'carry' flag). // // (See the ARM docs for the "AddWithCarry" pseudo-code.) // @@ -2360,13 +3084,14 @@ defm CMP : AI1_cmp_irs<0b1010, "cmp", // Note that TST/TEQ don't set all the same flags that CMP does! defm TST : AI1_cmp_irs<0b1000, "tst", - BinOpFrag<(ARMcmpZ (and node:$LHS, node:$RHS), 0)>, 1>; + IIC_iTSTi, IIC_iTSTr, IIC_iTSTsr, + BinOpFrag<(ARMcmpZ (and_su node:$LHS, node:$RHS), 0)>, 1>; defm TEQ : AI1_cmp_irs<0b1001, "teq", - BinOpFrag<(ARMcmpZ (xor node:$LHS, node:$RHS), 0)>, 1>; + IIC_iTSTi, IIC_iTSTr, IIC_iTSTsr, + BinOpFrag<(ARMcmpZ (xor_su node:$LHS, node:$RHS), 0)>, 1>; -defm CMPz : AI1_cmp_irs<0b1010, "cmp", - BinOpFrag<(ARMcmpZ node:$LHS, node:$RHS)>>; defm CMNz : AI1_cmp_irs<0b1011, "cmn", + IIC_iCMPi, IIC_iCMPr, IIC_iCMPsr, BinOpFrag<(ARMcmpZ node:$LHS,(ineg node:$RHS))>>; //def : ARMPat<(ARMcmp GPR:$src, so_imm_neg:$imm), @@ -2381,13 +3106,10 @@ let usesCustomInserter = 1, isBranch = 1, isTerminator = 1, def BCCi64 : PseudoInst<(outs), (ins i32imm:$cc, GPR:$lhs1, GPR:$lhs2, GPR:$rhs1, GPR:$rhs2, brtarget:$dst), IIC_Br, - "${:comment} B\t$dst GPR:$lhs1, GPR:$lhs2, GPR:$rhs1, GPR:$rhs2, imm:$cc", [(ARMBcci64 imm:$cc, GPR:$lhs1, GPR:$lhs2, GPR:$rhs1, GPR:$rhs2, bb:$dst)]>; def BCCZi64 : PseudoInst<(outs), - (ins i32imm:$cc, GPR:$lhs1, GPR:$lhs2, brtarget:$dst), - IIC_Br, - "${:comment} B\t$dst GPR:$lhs1, GPR:$lhs2, 0, 0, imm:$cc", + (ins i32imm:$cc, GPR:$lhs1, GPR:$lhs2, brtarget:$dst), IIC_Br, [(ARMBcci64 imm:$cc, GPR:$lhs1, GPR:$lhs2, 0, 0, bb:$dst)]>; } // usesCustomInserter @@ -2395,29 +3117,87 @@ def BCCZi64 : PseudoInst<(outs), // Conditional moves // FIXME: should be able to write a pattern for ARMcmov, but can't use // a two-value operand where a dag node expects two operands. :( +// FIXME: These should all be pseudo-instructions that get expanded to +// the normal MOV instructions. That would fix the dependency on +// special casing them in tblgen. let neverHasSideEffects = 1 in { -def MOVCCr : AI1<0b1101, (outs GPR:$dst), (ins GPR:$false, GPR:$true), DPFrm, - IIC_iCMOVr, "mov", "\t$dst, $true", - [/*(set GPR:$dst, (ARMcmov GPR:$false, GPR:$true, imm:$cc, CCR:$ccr))*/]>, - RegConstraint<"$false = $dst">, UnaryDP { - let Inst{11-4} = 0b00000000; +def MOVCCr : AI1<0b1101, (outs GPR:$Rd), (ins GPR:$false, GPR:$Rm), DPFrm, + IIC_iCMOVr, "mov", "\t$Rd, $Rm", + [/*(set GPR:$Rd, (ARMcmov GPR:$false, GPR:$Rm, imm:$cc, CCR:$ccr))*/]>, + RegConstraint<"$false = $Rd">, UnaryDP { + bits<4> Rd; + bits<4> Rm; let Inst{25} = 0; + let Inst{20} = 0; + let Inst{15-12} = Rd; + let Inst{11-4} = 0b00000000; + let Inst{3-0} = Rm; } -def MOVCCs : AI1<0b1101, (outs GPR:$dst), - (ins GPR:$false, so_reg:$true), DPSoRegFrm, IIC_iCMOVsr, - "mov", "\t$dst, $true", - [/*(set GPR:$dst, (ARMcmov GPR:$false, so_reg:$true, imm:$cc, CCR:$ccr))*/]>, - RegConstraint<"$false = $dst">, UnaryDP { +def MOVCCs : AI1<0b1101, (outs GPR:$Rd), + (ins GPR:$false, so_reg:$shift), DPSoRegFrm, IIC_iCMOVsr, + "mov", "\t$Rd, $shift", + [/*(set GPR:$Rd, (ARMcmov GPR:$false, so_reg:$shift, imm:$cc, CCR:$ccr))*/]>, + RegConstraint<"$false = $Rd">, UnaryDP { + bits<4> Rd; + bits<12> shift; let Inst{25} = 0; + let Inst{20} = 0; + let Inst{19-16} = 0; + let Inst{15-12} = Rd; + let Inst{11-0} = shift; } -def MOVCCi : AI1<0b1101, (outs GPR:$dst), - (ins GPR:$false, so_imm:$true), DPFrm, IIC_iCMOVi, - "mov", "\t$dst, $true", - [/*(set GPR:$dst, (ARMcmov GPR:$false, so_imm:$true, imm:$cc, CCR:$ccr))*/]>, - RegConstraint<"$false = $dst">, UnaryDP { +let isMoveImm = 1 in +def MOVCCi16 : AI1<0b1000, (outs GPR:$Rd), (ins GPR:$false, i32imm_hilo16:$imm), + DPFrm, IIC_iMOVi, + "movw", "\t$Rd, $imm", + []>, + RegConstraint<"$false = $Rd">, Requires<[IsARM, HasV6T2]>, + UnaryDP { + bits<4> Rd; + bits<16> imm; + let Inst{25} = 1; + let Inst{20} = 0; + let Inst{19-16} = imm{15-12}; + let Inst{15-12} = Rd; + let Inst{11-0} = imm{11-0}; +} + +let isMoveImm = 1 in +def MOVCCi : AI1<0b1101, (outs GPR:$Rd), + (ins GPR:$false, so_imm:$imm), DPFrm, IIC_iCMOVi, + "mov", "\t$Rd, $imm", + [/*(set GPR:$Rd, (ARMcmov GPR:$false, so_imm:$imm, imm:$cc, CCR:$ccr))*/]>, + RegConstraint<"$false = $Rd">, UnaryDP { + bits<4> Rd; + bits<12> imm; let Inst{25} = 1; + let Inst{20} = 0; + let Inst{19-16} = 0b0000; + let Inst{15-12} = Rd; + let Inst{11-0} = imm; +} + +// Two instruction predicate mov immediate. +let isMoveImm = 1 in +def MOVCCi32imm : PseudoInst<(outs GPR:$Rd), + (ins GPR:$false, i32imm:$src, pred:$p), + IIC_iCMOVix2, []>, RegConstraint<"$false = $Rd">; + +let isMoveImm = 1 in +def MVNCCi : AI1<0b1111, (outs GPR:$Rd), + (ins GPR:$false, so_imm:$imm), DPFrm, IIC_iCMOVi, + "mvn", "\t$Rd, $imm", + [/*(set GPR:$Rd, (ARMcmov GPR:$false, so_imm_not:$imm, imm:$cc, CCR:$ccr))*/]>, + RegConstraint<"$false = $Rd">, UnaryDP { + bits<4> Rd; + bits<12> imm; + let Inst{25} = 1; + let Inst{20} = 0; + let Inst{19-16} = 0b0000; + let Inst{15-12} = Rd; + let Inst{11-0} = imm; } } // neverHasSideEffects @@ -2425,64 +3205,41 @@ def MOVCCi : AI1<0b1101, (outs GPR:$dst), // Atomic operations intrinsics // +def memb_opt : Operand { + let PrintMethod = "printMemBOption"; + let ParserMatchClass = MemBarrierOptOperand; +} + // memory barriers protect the atomic sequences let hasSideEffects = 1 in { -def DMBsy : AInoP<(outs), (ins), MiscFrm, NoItinerary, "dmb", "", - [(ARMMemBarrier)]>, Requires<[IsARM, HasDB]> { +def DMB : AInoP<(outs), (ins memb_opt:$opt), MiscFrm, NoItinerary, + "dmb", "\t$opt", [(ARMMemBarrier (i32 imm:$opt))]>, + Requires<[IsARM, HasDB]> { + bits<4> opt; let Inst{31-4} = 0xf57ff05; - // FIXME: add support for options other than a full system DMB - // See DMB disassembly-only variants below. - let Inst{3-0} = 0b1111; -} - -def DSBsy : AInoP<(outs), (ins), MiscFrm, NoItinerary, "dsb", "", - [(ARMSyncBarrier)]>, Requires<[IsARM, HasDB]> { - let Inst{31-4} = 0xf57ff04; - // FIXME: add support for options other than a full system DSB - // See DSB disassembly-only variants below. - let Inst{3-0} = 0b1111; + let Inst{3-0} = opt; } def DMB_MCR : AInoP<(outs), (ins GPR:$zero), MiscFrm, NoItinerary, "mcr", "\tp15, 0, $zero, c7, c10, 5", [(ARMMemBarrierMCR GPR:$zero)]>, Requires<[IsARM, HasV6]> { - // FIXME: add support for options other than a full system DMB // FIXME: add encoding } - -def DSB_MCR : AInoP<(outs), (ins GPR:$zero), MiscFrm, NoItinerary, - "mcr", "\tp15, 0, $zero, c7, c10, 4", - [(ARMSyncBarrierMCR GPR:$zero)]>, - Requires<[IsARM, HasV6]> { - // FIXME: add support for options other than a full system DSB - // FIXME: add encoding -} -} - -// Memory Barrier Operations Variants -- for disassembly only - -def memb_opt : Operand { - let PrintMethod = "printMemBOption"; } -class AMBI op7_4, string opc> - : AInoP<(outs), (ins memb_opt:$opt), MiscFrm, NoItinerary, opc, "\t$opt", - [/* For disassembly only; pattern left blank */]>, - Requires<[IsARM, HasDB]> { - let Inst{31-8} = 0xf57ff0; - let Inst{7-4} = op7_4; +def DSB : AInoP<(outs), (ins memb_opt:$opt), MiscFrm, NoItinerary, + "dsb", "\t$opt", + [/* For disassembly only; pattern left blank */]>, + Requires<[IsARM, HasDB]> { + bits<4> opt; + let Inst{31-4} = 0xf57ff04; + let Inst{3-0} = opt; } -// These DMB variants are for disassembly only. -def DMBvar : AMBI<0b0101, "dmb">; - -// These DSB variants are for disassembly only. -def DSBvar : AMBI<0b0100, "dsb">; - // ISB has only full system option -- for disassembly only -def ISBsy : AInoP<(outs), (ins), MiscFrm, NoItinerary, "isb", "", []>, - Requires<[IsARM, HasDB]> { +def ISB : AInoP<(outs), (ins), MiscFrm, NoItinerary, "isb", "", []>, + Requires<[IsARM, HasDB]> { let Inst{31-4} = 0xf57ff06; let Inst{3-0} = 0b1111; } @@ -2491,138 +3248,114 @@ let usesCustomInserter = 1 in { let Uses = [CPSR] in { def ATOMIC_LOAD_ADD_I8 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary, - "${:comment} ATOMIC_LOAD_ADD_I8 PSEUDO!", [(set GPR:$dst, (atomic_load_add_8 GPR:$ptr, GPR:$incr))]>; def ATOMIC_LOAD_SUB_I8 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary, - "${:comment} ATOMIC_LOAD_SUB_I8 PSEUDO!", [(set GPR:$dst, (atomic_load_sub_8 GPR:$ptr, GPR:$incr))]>; def ATOMIC_LOAD_AND_I8 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary, - "${:comment} ATOMIC_LOAD_AND_I8 PSEUDO!", [(set GPR:$dst, (atomic_load_and_8 GPR:$ptr, GPR:$incr))]>; def ATOMIC_LOAD_OR_I8 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary, - "${:comment} ATOMIC_LOAD_OR_I8 PSEUDO!", [(set GPR:$dst, (atomic_load_or_8 GPR:$ptr, GPR:$incr))]>; def ATOMIC_LOAD_XOR_I8 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary, - "${:comment} ATOMIC_LOAD_XOR_I8 PSEUDO!", [(set GPR:$dst, (atomic_load_xor_8 GPR:$ptr, GPR:$incr))]>; def ATOMIC_LOAD_NAND_I8 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary, - "${:comment} ATOMIC_LOAD_NAND_I8 PSEUDO!", [(set GPR:$dst, (atomic_load_nand_8 GPR:$ptr, GPR:$incr))]>; def ATOMIC_LOAD_ADD_I16 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary, - "${:comment} ATOMIC_LOAD_ADD_I16 PSEUDO!", [(set GPR:$dst, (atomic_load_add_16 GPR:$ptr, GPR:$incr))]>; def ATOMIC_LOAD_SUB_I16 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary, - "${:comment} ATOMIC_LOAD_SUB_I16 PSEUDO!", [(set GPR:$dst, (atomic_load_sub_16 GPR:$ptr, GPR:$incr))]>; def ATOMIC_LOAD_AND_I16 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary, - "${:comment} ATOMIC_LOAD_AND_I16 PSEUDO!", [(set GPR:$dst, (atomic_load_and_16 GPR:$ptr, GPR:$incr))]>; def ATOMIC_LOAD_OR_I16 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary, - "${:comment} ATOMIC_LOAD_OR_I16 PSEUDO!", [(set GPR:$dst, (atomic_load_or_16 GPR:$ptr, GPR:$incr))]>; def ATOMIC_LOAD_XOR_I16 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary, - "${:comment} ATOMIC_LOAD_XOR_I16 PSEUDO!", [(set GPR:$dst, (atomic_load_xor_16 GPR:$ptr, GPR:$incr))]>; def ATOMIC_LOAD_NAND_I16 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary, - "${:comment} ATOMIC_LOAD_NAND_I16 PSEUDO!", [(set GPR:$dst, (atomic_load_nand_16 GPR:$ptr, GPR:$incr))]>; def ATOMIC_LOAD_ADD_I32 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary, - "${:comment} ATOMIC_LOAD_ADD_I32 PSEUDO!", [(set GPR:$dst, (atomic_load_add_32 GPR:$ptr, GPR:$incr))]>; def ATOMIC_LOAD_SUB_I32 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary, - "${:comment} ATOMIC_LOAD_SUB_I32 PSEUDO!", [(set GPR:$dst, (atomic_load_sub_32 GPR:$ptr, GPR:$incr))]>; def ATOMIC_LOAD_AND_I32 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary, - "${:comment} ATOMIC_LOAD_AND_I32 PSEUDO!", [(set GPR:$dst, (atomic_load_and_32 GPR:$ptr, GPR:$incr))]>; def ATOMIC_LOAD_OR_I32 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary, - "${:comment} ATOMIC_LOAD_OR_I32 PSEUDO!", [(set GPR:$dst, (atomic_load_or_32 GPR:$ptr, GPR:$incr))]>; def ATOMIC_LOAD_XOR_I32 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary, - "${:comment} ATOMIC_LOAD_XOR_I32 PSEUDO!", [(set GPR:$dst, (atomic_load_xor_32 GPR:$ptr, GPR:$incr))]>; def ATOMIC_LOAD_NAND_I32 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary, - "${:comment} ATOMIC_LOAD_NAND_I32 PSEUDO!", [(set GPR:$dst, (atomic_load_nand_32 GPR:$ptr, GPR:$incr))]>; def ATOMIC_SWAP_I8 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$new), NoItinerary, - "${:comment} ATOMIC_SWAP_I8 PSEUDO!", [(set GPR:$dst, (atomic_swap_8 GPR:$ptr, GPR:$new))]>; def ATOMIC_SWAP_I16 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$new), NoItinerary, - "${:comment} ATOMIC_SWAP_I16 PSEUDO!", [(set GPR:$dst, (atomic_swap_16 GPR:$ptr, GPR:$new))]>; def ATOMIC_SWAP_I32 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$new), NoItinerary, - "${:comment} ATOMIC_SWAP_I32 PSEUDO!", [(set GPR:$dst, (atomic_swap_32 GPR:$ptr, GPR:$new))]>; def ATOMIC_CMP_SWAP_I8 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$old, GPR:$new), NoItinerary, - "${:comment} ATOMIC_CMP_SWAP_I8 PSEUDO!", [(set GPR:$dst, (atomic_cmp_swap_8 GPR:$ptr, GPR:$old, GPR:$new))]>; def ATOMIC_CMP_SWAP_I16 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$old, GPR:$new), NoItinerary, - "${:comment} ATOMIC_CMP_SWAP_I16 PSEUDO!", [(set GPR:$dst, (atomic_cmp_swap_16 GPR:$ptr, GPR:$old, GPR:$new))]>; def ATOMIC_CMP_SWAP_I32 : PseudoInst< (outs GPR:$dst), (ins GPR:$ptr, GPR:$old, GPR:$new), NoItinerary, - "${:comment} ATOMIC_CMP_SWAP_I32 PSEUDO!", [(set GPR:$dst, (atomic_cmp_swap_32 GPR:$ptr, GPR:$old, GPR:$new))]>; } } let mayLoad = 1 in { -def LDREXB : AIldrex<0b10, (outs GPR:$dest), (ins GPR:$ptr), NoItinerary, - "ldrexb", "\t$dest, [$ptr]", +def LDREXB : AIldrex<0b10, (outs GPR:$Rt), (ins GPR:$Rn), NoItinerary, + "ldrexb", "\t$Rt, [$Rn]", []>; -def LDREXH : AIldrex<0b11, (outs GPR:$dest), (ins GPR:$ptr), NoItinerary, - "ldrexh", "\t$dest, [$ptr]", +def LDREXH : AIldrex<0b11, (outs GPR:$Rt), (ins GPR:$Rn), NoItinerary, + "ldrexh", "\t$Rt, [$Rn]", []>; -def LDREX : AIldrex<0b00, (outs GPR:$dest), (ins GPR:$ptr), NoItinerary, - "ldrex", "\t$dest, [$ptr]", +def LDREX : AIldrex<0b00, (outs GPR:$Rt), (ins GPR:$Rn), NoItinerary, + "ldrex", "\t$Rt, [$Rn]", []>; -def LDREXD : AIldrex<0b01, (outs GPR:$dest, GPR:$dest2), (ins GPR:$ptr), +def LDREXD : AIldrex<0b01, (outs GPR:$Rt, GPR:$Rt2), (ins GPR:$Rn), NoItinerary, - "ldrexd", "\t$dest, $dest2, [$ptr]", + "ldrexd", "\t$Rt, $Rt2, [$Rn]", []>; } -let mayStore = 1, Constraints = "@earlyclobber $success" in { -def STREXB : AIstrex<0b10, (outs GPR:$success), (ins GPR:$src, GPR:$ptr), +let mayStore = 1, Constraints = "@earlyclobber $Rd" in { +def STREXB : AIstrex<0b10, (outs GPR:$Rd), (ins GPR:$src, GPR:$Rn), NoItinerary, - "strexb", "\t$success, $src, [$ptr]", + "strexb", "\t$Rd, $src, [$Rn]", []>; -def STREXH : AIstrex<0b11, (outs GPR:$success), (ins GPR:$src, GPR:$ptr), +def STREXH : AIstrex<0b11, (outs GPR:$Rd), (ins GPR:$Rt, GPR:$Rn), NoItinerary, - "strexh", "\t$success, $src, [$ptr]", + "strexh", "\t$Rd, $Rt, [$Rn]", []>; -def STREX : AIstrex<0b00, (outs GPR:$success), (ins GPR:$src, GPR:$ptr), +def STREX : AIstrex<0b00, (outs GPR:$Rd), (ins GPR:$Rt, GPR:$Rn), NoItinerary, - "strex", "\t$success, $src, [$ptr]", + "strex", "\t$Rd, $Rt, [$Rn]", []>; -def STREXD : AIstrex<0b01, (outs GPR:$success), - (ins GPR:$src, GPR:$src2, GPR:$ptr), +def STREXD : AIstrex<0b01, (outs GPR:$Rd), + (ins GPR:$Rt, GPR:$Rt2, GPR:$Rn), NoItinerary, - "strexd", "\t$success, $src, $src2, [$ptr]", + "strexd", "\t$Rd, $Rt, $Rt2, [$Rn]", []>; } @@ -2630,29 +3363,15 @@ def STREXD : AIstrex<0b01, (outs GPR:$success), def CLREX : AXI<(outs), (ins), MiscFrm, NoItinerary, "clrex", [/* For disassembly only; pattern left blank */]>, Requires<[IsARM, HasV7]> { - let Inst{31-20} = 0xf57; - let Inst{7-4} = 0b0001; + let Inst{31-0} = 0b11110101011111111111000000011111; } // SWP/SWPB are deprecated in V6/V7 and for disassembly only. let mayLoad = 1 in { -def SWP : AI<(outs GPR:$dst), (ins GPR:$src, GPR:$ptr), LdStExFrm, NoItinerary, - "swp", "\t$dst, $src, [$ptr]", - [/* For disassembly only; pattern left blank */]> { - let Inst{27-23} = 0b00010; - let Inst{22} = 0; // B = 0 - let Inst{21-20} = 0b00; - let Inst{7-4} = 0b1001; -} - -def SWPB : AI<(outs GPR:$dst), (ins GPR:$src, GPR:$ptr), LdStExFrm, NoItinerary, - "swpb", "\t$dst, $src, [$ptr]", - [/* For disassembly only; pattern left blank */]> { - let Inst{27-23} = 0b00010; - let Inst{22} = 1; // B = 1 - let Inst{21-20} = 0b00; - let Inst{7-4} = 0b1001; -} +def SWP : AIswp<0, (outs GPR:$Rt), (ins GPR:$Rt2, GPR:$Rn), "swp", + [/* For disassembly only; pattern left blank */]>; +def SWPB : AIswp<1, (outs GPR:$Rt), (ins GPR:$Rt2, GPR:$Rn), "swpb", + [/* For disassembly only; pattern left blank */]>; } //===----------------------------------------------------------------------===// @@ -2660,10 +3379,11 @@ def SWPB : AI<(outs GPR:$dst), (ins GPR:$src, GPR:$ptr), LdStExFrm, NoItinerary, // // __aeabi_read_tp preserves the registers r1-r3. +// This is a pseudo inst so that we can get the encoding right, +// complete with fixup for the aeabi_read_tp function. let isCall = 1, - Defs = [R0, R12, LR, CPSR] in { - def TPsoft : ABXI<0b1011, (outs), (ins), IIC_Br, - "bl\t__aeabi_read_tp", + Defs = [R0, R12, LR, CPSR], Uses = [SP] in { + def TPsoft : PseudoInst<(outs), (ins), IIC_Br, [(set R0, ARMthread_pointer)]>; } @@ -2680,19 +3400,16 @@ let isCall = 1, // doing so, we also cause the prologue/epilogue code to actively preserve // all of the callee-saved resgisters, which is exactly what we want. // A constant value is passed in $val, and we use the location as a scratch. +// +// These are pseudo-instructions and are lowered to individual MC-insts, so +// no encoding information is necessary. let Defs = [ R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR, D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15, D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, D30, D31 ], hasSideEffects = 1, isBarrier = 1 in { - def Int_eh_sjlj_setjmp : XI<(outs), (ins GPR:$src, GPR:$val), - AddrModeNone, SizeSpecial, IndexModeNone, - Pseudo, NoItinerary, - "add\t$val, pc, #8\t${:comment} eh_setjmp begin\n\t" - "str\t$val, [$src, #+4]\n\t" - "mov\tr0, #0\n\t" - "add\tpc, pc, #0\n\t" - "mov\tr0, #1 ${:comment} eh_setjmp end", "", + def Int_eh_sjlj_setjmp : PseudoInst<(outs), (ins GPR:$src, GPR:$val), + NoItinerary, [(set R0, (ARMeh_sjlj_setjmp GPR:$src, GPR:$val))]>, Requires<[IsARM, HasVFP2]>; } @@ -2700,14 +3417,8 @@ let Defs = let Defs = [ R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR ], hasSideEffects = 1, isBarrier = 1 in { - def Int_eh_sjlj_setjmp_nofp : XI<(outs), (ins GPR:$src, GPR:$val), - AddrModeNone, SizeSpecial, IndexModeNone, - Pseudo, NoItinerary, - "add\t$val, pc, #8\n ${:comment} eh_setjmp begin\n\t" - "str\t$val, [$src, #+4]\n\t" - "mov\tr0, #0\n\t" - "add\tpc, pc, #0\n\t" - "mov\tr0, #1 ${:comment} eh_setjmp end", "", + def Int_eh_sjlj_setjmp_nofp : PseudoInst<(outs), (ins GPR:$src, GPR:$val), + NoItinerary, [(set R0, (ARMeh_sjlj_setjmp GPR:$src, GPR:$val))]>, Requires<[IsARM, NoVFP]>; } @@ -2715,53 +3426,58 @@ let Defs = // FIXME: Non-Darwin version(s) let isBarrier = 1, hasSideEffects = 1, isTerminator = 1, Defs = [ R7, LR, SP ] in { -def Int_eh_sjlj_longjmp : XI<(outs), (ins GPR:$src, GPR:$scratch), - AddrModeNone, SizeSpecial, IndexModeNone, - Pseudo, NoItinerary, - "ldr\tsp, [$src, #8]\n\t" - "ldr\t$scratch, [$src, #4]\n\t" - "ldr\tr7, [$src]\n\t" - "bx\t$scratch", "", +def Int_eh_sjlj_longjmp : PseudoInst<(outs), (ins GPR:$src, GPR:$scratch), + NoItinerary, [(ARMeh_sjlj_longjmp GPR:$src, GPR:$scratch)]>, Requires<[IsARM, IsDarwin]>; } +// eh.sjlj.dispatchsetup pseudo-instruction. +// This pseudo is used for ARM, Thumb1 and Thumb2. Any differences are +// handled when the pseudo is expanded (which happens before any passes +// that need the instruction size). +let isBarrier = 1, hasSideEffects = 1 in +def Int_eh_sjlj_dispatchsetup : + PseudoInst<(outs), (ins GPR:$src), NoItinerary, + [(ARMeh_sjlj_dispatchsetup GPR:$src)]>, + Requires<[IsDarwin]>; + //===----------------------------------------------------------------------===// // Non-Instruction Patterns // // Large immediate handling. -// Two piece so_imms. -let isReMaterializable = 1 in -def MOVi2pieces : AI1x2<(outs GPR:$dst), (ins so_imm2part:$src), - Pseudo, IIC_iMOVi, - "mov", "\t$dst, $src", - [(set GPR:$dst, so_imm2part:$src)]>, - Requires<[IsARM, NoV6T2]>; - -def : ARMPat<(or GPR:$LHS, so_imm2part:$RHS), - (ORRri (ORRri GPR:$LHS, (so_imm2part_1 imm:$RHS)), - (so_imm2part_2 imm:$RHS))>; -def : ARMPat<(xor GPR:$LHS, so_imm2part:$RHS), - (EORri (EORri GPR:$LHS, (so_imm2part_1 imm:$RHS)), - (so_imm2part_2 imm:$RHS))>; -def : ARMPat<(add GPR:$LHS, so_imm2part:$RHS), - (ADDri (ADDri GPR:$LHS, (so_imm2part_1 imm:$RHS)), - (so_imm2part_2 imm:$RHS))>; -def : ARMPat<(add GPR:$LHS, so_neg_imm2part:$RHS), - (SUBri (SUBri GPR:$LHS, (so_neg_imm2part_1 imm:$RHS)), - (so_neg_imm2part_2 imm:$RHS))>; - -// 32-bit immediate using movw + movt. +// 32-bit immediate using two piece so_imms or movw + movt. // This is a single pseudo instruction, the benefit is that it can be remat'd // as a single unit instead of having to handle reg inputs. // FIXME: Remove this when we can do generalized remat. -let isReMaterializable = 1 in -def MOVi32imm : AI1x2<(outs GPR:$dst), (ins i32imm:$src), Pseudo, IIC_iMOVi, - "movw", "\t$dst, ${src:lo16}\n\tmovt${p}\t$dst, ${src:hi16}", - [(set GPR:$dst, (i32 imm:$src))]>, - Requires<[IsARM, HasV6T2]>; +let isReMaterializable = 1, isMoveImm = 1 in +def MOVi32imm : PseudoInst<(outs GPR:$dst), (ins i32imm:$src), IIC_iMOVix2, + [(set GPR:$dst, (arm_i32imm:$src))]>, + Requires<[IsARM]>; + +// Pseudo instruction that combines movw + movt + add pc (if PIC). +// It also makes it possible to rematerialize the instructions. +// FIXME: Remove this when we can do generalized remat and when machine licm +// can properly the instructions. +let isReMaterializable = 1 in { +def MOV_ga_pcrel : PseudoInst<(outs GPR:$dst), (ins i32imm:$addr), + IIC_iMOVix2addpc, + [(set GPR:$dst, (ARMWrapperPIC tglobaladdr:$addr))]>, + Requires<[IsARM, UseMovt]>; + +def MOV_ga_dyn : PseudoInst<(outs GPR:$dst), (ins i32imm:$addr), + IIC_iMOVix2, + [(set GPR:$dst, (ARMWrapperDYN tglobaladdr:$addr))]>, + Requires<[IsARM, UseMovt]>; + +let AddedComplexity = 10 in +def MOV_ga_pcrel_ldr : PseudoInst<(outs GPR:$dst), (ins i32imm:$addr), + IIC_iMOVix2ld, + [(set GPR:$dst, (load (ARMWrapperPIC tglobaladdr:$addr)))]>, + Requires<[IsARM, UseMovt]>; +} // isReMaterializable // ConstantPool, GlobalAddress, and JumpTable def : ARMPat<(ARMWrapper tglobaladdr :$dst), (LEApcrel tglobaladdr :$dst)>, @@ -2800,11 +3516,15 @@ def : ARMPat<(ARMcall texternalsym:$func), (BLr9 texternalsym:$func)>, Requires<[IsARM, IsDarwin]>; // zextload i1 -> zextload i8 -def : ARMPat<(zextloadi1 addrmode2:$addr), (LDRB addrmode2:$addr)>; +def : ARMPat<(zextloadi1 addrmode_imm12:$addr), (LDRBi12 addrmode_imm12:$addr)>; +def : ARMPat<(zextloadi1 ldst_so_reg:$addr), (LDRBrs ldst_so_reg:$addr)>; // extload -> zextload -def : ARMPat<(extloadi1 addrmode2:$addr), (LDRB addrmode2:$addr)>; -def : ARMPat<(extloadi8 addrmode2:$addr), (LDRB addrmode2:$addr)>; +def : ARMPat<(extloadi1 addrmode_imm12:$addr), (LDRBi12 addrmode_imm12:$addr)>; +def : ARMPat<(extloadi1 ldst_so_reg:$addr), (LDRBrs ldst_so_reg:$addr)>; +def : ARMPat<(extloadi8 addrmode_imm12:$addr), (LDRBi12 addrmode_imm12:$addr)>; +def : ARMPat<(extloadi8 ldst_so_reg:$addr), (LDRBrs ldst_so_reg:$addr)>; + def : ARMPat<(extloadi16 addrmode3:$addr), (LDRH addrmode3:$addr)>; def : ARMPat<(extloadi8 addrmodepc:$addr), (PICLDRB addrmodepc:$addr)>; @@ -2889,19 +3609,45 @@ include "ARMInstrNEON.td" // Coprocessor Instructions. For disassembly only. // -def CDP : ABI<0b1110, (outs), (ins nohash_imm:$cop, i32imm:$opc1, - nohash_imm:$CRd, nohash_imm:$CRn, nohash_imm:$CRm, i32imm:$opc2), - NoItinerary, "cdp", "\tp$cop, $opc1, cr$CRd, cr$CRn, cr$CRm, $opc2", - [/* For disassembly only; pattern left blank */]> { - let Inst{4} = 0; -} - -def CDP2 : ABXI<0b1110, (outs), (ins nohash_imm:$cop, i32imm:$opc1, - nohash_imm:$CRd, nohash_imm:$CRn, nohash_imm:$CRm, i32imm:$opc2), - NoItinerary, "cdp2\tp$cop, $opc1, cr$CRd, cr$CRn, cr$CRm, $opc2", +def CDP : ABI<0b1110, (outs), (ins p_imm:$cop, i32imm:$opc1, + c_imm:$CRd, c_imm:$CRn, c_imm:$CRm, i32imm:$opc2), + NoItinerary, "cdp", "\t$cop, $opc1, $CRd, $CRn, $CRm, $opc2", + [/* For disassembly only; pattern left blank */]> { + bits<4> opc1; + bits<4> CRn; + bits<4> CRd; + bits<4> cop; + bits<3> opc2; + bits<4> CRm; + + let Inst{3-0} = CRm; + let Inst{4} = 0; + let Inst{7-5} = opc2; + let Inst{11-8} = cop; + let Inst{15-12} = CRd; + let Inst{19-16} = CRn; + let Inst{23-20} = opc1; +} + +def CDP2 : ABXI<0b1110, (outs), (ins p_imm:$cop, i32imm:$opc1, + c_imm:$CRd, c_imm:$CRn, c_imm:$CRm, i32imm:$opc2), + NoItinerary, "cdp2\t$cop, $opc1, $CRd, $CRn, $CRm, $opc2", [/* For disassembly only; pattern left blank */]> { let Inst{31-28} = 0b1111; - let Inst{4} = 0; + bits<4> opc1; + bits<4> CRn; + bits<4> CRd; + bits<4> cop; + bits<3> opc2; + bits<4> CRm; + + let Inst{3-0} = CRm; + let Inst{4} = 0; + let Inst{7-5} = opc2; + let Inst{11-8} = cop; + let Inst{15-12} = CRd; + let Inst{19-16} = CRn; + let Inst{23-20} = opc1; } class ACI @@ -3000,110 +3746,164 @@ defm LDC2 : LdStCop<0b1111, 1, "ldc2">; defm STC : LdStCop<{?,?,?,?}, 0, "stc">; defm STC2 : LdStCop<0b1111, 0, "stc2">; -def MCR : ABI<0b1110, (outs), (ins nohash_imm:$cop, i32imm:$opc1, - GPR:$Rt, nohash_imm:$CRn, nohash_imm:$CRm, i32imm:$opc2), - NoItinerary, "mcr", "\tp$cop, $opc1, $Rt, cr$CRn, cr$CRm, $opc2", - [/* For disassembly only; pattern left blank */]> { - let Inst{20} = 0; - let Inst{4} = 1; -} - -def MCR2 : ABXI<0b1110, (outs), (ins nohash_imm:$cop, i32imm:$opc1, - GPR:$Rt, nohash_imm:$CRn, nohash_imm:$CRm, i32imm:$opc2), - NoItinerary, "mcr2\tp$cop, $opc1, $Rt, cr$CRn, cr$CRm, $opc2", - [/* For disassembly only; pattern left blank */]> { - let Inst{31-28} = 0b1111; - let Inst{20} = 0; - let Inst{4} = 1; -} +//===----------------------------------------------------------------------===// +// Move between coprocessor and ARM core register -- for disassembly only +// -def MRC : ABI<0b1110, (outs), (ins nohash_imm:$cop, i32imm:$opc1, - GPR:$Rt, nohash_imm:$CRn, nohash_imm:$CRm, i32imm:$opc2), - NoItinerary, "mrc", "\tp$cop, $opc1, $Rt, cr$CRn, cr$CRm, $opc2", - [/* For disassembly only; pattern left blank */]> { - let Inst{20} = 1; +class MovRCopro + : ABI<0b1110, (outs), (ins p_imm:$cop, i32imm:$opc1, + GPR:$Rt, c_imm:$CRn, c_imm:$CRm, i32imm:$opc2), + NoItinerary, opc, "\t$cop, $opc1, $Rt, $CRn, $CRm, $opc2", + [/* For disassembly only; pattern left blank */]> { + let Inst{20} = direction; let Inst{4} = 1; -} -def MRC2 : ABXI<0b1110, (outs), (ins nohash_imm:$cop, i32imm:$opc1, - GPR:$Rt, nohash_imm:$CRn, nohash_imm:$CRm, i32imm:$opc2), - NoItinerary, "mrc2\tp$cop, $opc1, $Rt, cr$CRn, cr$CRm, $opc2", - [/* For disassembly only; pattern left blank */]> { + bits<4> Rt; + bits<4> cop; + bits<3> opc1; + bits<3> opc2; + bits<4> CRm; + bits<4> CRn; + + let Inst{15-12} = Rt; + let Inst{11-8} = cop; + let Inst{23-21} = opc1; + let Inst{7-5} = opc2; + let Inst{3-0} = CRm; + let Inst{19-16} = CRn; +} + +def MCR : MovRCopro<"mcr", 0 /* from ARM core register to coprocessor */>; +def MRC : MovRCopro<"mrc", 1 /* from coprocessor to ARM core register */>; + +class MovRCopro2 + : ABXI<0b1110, (outs), (ins p_imm:$cop, i32imm:$opc1, + GPR:$Rt, c_imm:$CRn, c_imm:$CRm, i32imm:$opc2), + NoItinerary, !strconcat(opc, "\t$cop, $opc1, $Rt, $CRn, $CRm, $opc2"), + [/* For disassembly only; pattern left blank */]> { let Inst{31-28} = 0b1111; - let Inst{20} = 1; + let Inst{20} = direction; let Inst{4} = 1; -} -def MCRR : ABI<0b1100, (outs), (ins nohash_imm:$cop, i32imm:$opc, - GPR:$Rt, GPR:$Rt2, nohash_imm:$CRm), - NoItinerary, "mcrr", "\tp$cop, $opc, $Rt, $Rt2, cr$CRm", - [/* For disassembly only; pattern left blank */]> { - let Inst{23-20} = 0b0100; -} - -def MCRR2 : ABXI<0b1100, (outs), (ins nohash_imm:$cop, i32imm:$opc, - GPR:$Rt, GPR:$Rt2, nohash_imm:$CRm), - NoItinerary, "mcrr2\tp$cop, $opc, $Rt, $Rt2, cr$CRm", - [/* For disassembly only; pattern left blank */]> { + bits<4> Rt; + bits<4> cop; + bits<3> opc1; + bits<3> opc2; + bits<4> CRm; + bits<4> CRn; + + let Inst{15-12} = Rt; + let Inst{11-8} = cop; + let Inst{23-21} = opc1; + let Inst{7-5} = opc2; + let Inst{3-0} = CRm; + let Inst{19-16} = CRn; +} + +def MCR2 : MovRCopro2<"mcr2", 0 /* from ARM core register to coprocessor */>; +def MRC2 : MovRCopro2<"mrc2", 1 /* from coprocessor to ARM core register */>; + +class MovRRCopro + : ABI<0b1100, (outs), (ins p_imm:$cop, i32imm:$opc1, + GPR:$Rt, GPR:$Rt2, c_imm:$CRm), + NoItinerary, opc, "\t$cop, $opc1, $Rt, $Rt2, $CRm", + [/* For disassembly only; pattern left blank */]> { + let Inst{23-21} = 0b010; + let Inst{20} = direction; + + bits<4> Rt; + bits<4> Rt2; + bits<4> cop; + bits<4> opc1; + bits<4> CRm; + + let Inst{15-12} = Rt; + let Inst{19-16} = Rt2; + let Inst{11-8} = cop; + let Inst{7-4} = opc1; + let Inst{3-0} = CRm; +} + +def MCRR : MovRRCopro<"mcrr", 0 /* from ARM core register to coprocessor */>; +def MRRC : MovRRCopro<"mrrc", 1 /* from coprocessor to ARM core register */>; + +class MovRRCopro2 + : ABXI<0b1100, (outs), (ins p_imm:$cop, i32imm:$opc1, + GPR:$Rt, GPR:$Rt2, c_imm:$CRm), + NoItinerary, !strconcat(opc, "\t$cop, $opc1, $Rt, $Rt2, $CRm"), + [/* For disassembly only; pattern left blank */]> { let Inst{31-28} = 0b1111; - let Inst{23-20} = 0b0100; -} + let Inst{23-21} = 0b010; + let Inst{20} = direction; -def MRRC : ABI<0b1100, (outs), (ins nohash_imm:$cop, i32imm:$opc, - GPR:$Rt, GPR:$Rt2, nohash_imm:$CRm), - NoItinerary, "mrrc", "\tp$cop, $opc, $Rt, $Rt2, cr$CRm", - [/* For disassembly only; pattern left blank */]> { - let Inst{23-20} = 0b0101; -} + bits<4> Rt; + bits<4> Rt2; + bits<4> cop; + bits<4> opc1; + bits<4> CRm; -def MRRC2 : ABXI<0b1100, (outs), (ins nohash_imm:$cop, i32imm:$opc, - GPR:$Rt, GPR:$Rt2, nohash_imm:$CRm), - NoItinerary, "mrrc2\tp$cop, $opc, $Rt, $Rt2, cr$CRm", - [/* For disassembly only; pattern left blank */]> { - let Inst{31-28} = 0b1111; - let Inst{23-20} = 0b0101; + let Inst{15-12} = Rt; + let Inst{19-16} = Rt2; + let Inst{11-8} = cop; + let Inst{7-4} = opc1; + let Inst{3-0} = CRm; } +def MCRR2 : MovRRCopro2<"mcrr2", 0 /* from ARM core register to coprocessor */>; +def MRRC2 : MovRRCopro2<"mrrc2", 1 /* from coprocessor to ARM core register */>; + //===----------------------------------------------------------------------===// // Move between special register and ARM core register -- for disassembly only // -def MRS : ABI<0b0001,(outs GPR:$dst),(ins), NoItinerary, "mrs", "\t$dst, cpsr", +// Move to ARM core register from Special Register +def MRS : ABI<0b0001, (outs GPR:$Rd), (ins), NoItinerary, "mrs", "\t$Rd, cpsr", [/* For disassembly only; pattern left blank */]> { - let Inst{23-20} = 0b0000; + bits<4> Rd; + let Inst{23-16} = 0b00001111; + let Inst{15-12} = Rd; let Inst{7-4} = 0b0000; } -def MRSsys : ABI<0b0001,(outs GPR:$dst),(ins), NoItinerary,"mrs","\t$dst, spsr", +def MRSsys : ABI<0b0001, (outs GPR:$Rd), (ins), NoItinerary,"mrs","\t$Rd, spsr", [/* For disassembly only; pattern left blank */]> { - let Inst{23-20} = 0b0100; + bits<4> Rd; + let Inst{23-16} = 0b01001111; + let Inst{15-12} = Rd; let Inst{7-4} = 0b0000; } -def MSR : ABI<0b0001, (outs), (ins GPR:$src, msr_mask:$mask), NoItinerary, - "msr", "\tcpsr$mask, $src", +// Move from ARM core register to Special Register +// +// No need to have both system and application versions, the encodings are the +// same and the assembly parser has no way to distinguish between them. The mask +// operand contains the special register (R Bit) in bit 4 and bits 3-0 contains +// the mask with the fields to be accessed in the special register. +def MSR : ABI<0b0001, (outs), (ins msr_mask:$mask, GPR:$Rn), NoItinerary, + "msr", "\t$mask, $Rn", [/* For disassembly only; pattern left blank */]> { - let Inst{23-20} = 0b0010; - let Inst{7-4} = 0b0000; -} + bits<5> mask; + bits<4> Rn; -def MSRi : ABI<0b0011, (outs), (ins so_imm:$a, msr_mask:$mask), NoItinerary, - "msr", "\tcpsr$mask, $a", - [/* For disassembly only; pattern left blank */]> { - let Inst{23-20} = 0b0010; - let Inst{7-4} = 0b0000; + let Inst{23} = 0; + let Inst{22} = mask{4}; // R bit + let Inst{21-20} = 0b10; + let Inst{19-16} = mask{3-0}; + let Inst{15-12} = 0b1111; + let Inst{11-4} = 0b00000000; + let Inst{3-0} = Rn; } -def MSRsys : ABI<0b0001, (outs), (ins GPR:$src, msr_mask:$mask), NoItinerary, - "msr", "\tspsr$mask, $src", - [/* For disassembly only; pattern left blank */]> { - let Inst{23-20} = 0b0110; - let Inst{7-4} = 0b0000; -} +def MSRi : ABI<0b0011, (outs), (ins msr_mask:$mask, so_imm:$a), NoItinerary, + "msr", "\t$mask, $a", + [/* For disassembly only; pattern left blank */]> { + bits<5> mask; + bits<12> a; -def MSRsysi : ABI<0b0011, (outs), (ins so_imm:$a, msr_mask:$mask), NoItinerary, - "msr", "\tspsr$mask, $a", - [/* For disassembly only; pattern left blank */]> { - let Inst{23-20} = 0b0110; - let Inst{7-4} = 0b0000; + let Inst{23} = 0; + let Inst{22} = mask{4}; // R bit + let Inst{21-20} = 0b10; + let Inst{19-16} = mask{3-0}; + let Inst{15-12} = 0b1111; + let Inst{11-0} = a; } diff --git a/lib/Target/ARM/ARMInstrNEON.td b/lib/Target/ARM/ARMInstrNEON.td index 4d2f1169061f..1e2e5504e662 100644 --- a/lib/Target/ARM/ARMInstrNEON.td +++ b/lib/Target/ARM/ARMInstrNEON.td @@ -16,11 +16,17 @@ //===----------------------------------------------------------------------===// def SDTARMVCMP : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisSameAs<1, 2>]>; +def SDTARMVCMPZ : SDTypeProfile<1, 1, []>; def NEONvceq : SDNode<"ARMISD::VCEQ", SDTARMVCMP>; +def NEONvceqz : SDNode<"ARMISD::VCEQZ", SDTARMVCMPZ>; def NEONvcge : SDNode<"ARMISD::VCGE", SDTARMVCMP>; +def NEONvcgez : SDNode<"ARMISD::VCGEZ", SDTARMVCMPZ>; +def NEONvclez : SDNode<"ARMISD::VCLEZ", SDTARMVCMPZ>; def NEONvcgeu : SDNode<"ARMISD::VCGEU", SDTARMVCMP>; def NEONvcgt : SDNode<"ARMISD::VCGT", SDTARMVCMP>; +def NEONvcgtz : SDNode<"ARMISD::VCGTZ", SDTARMVCMPZ>; +def NEONvcltz : SDNode<"ARMISD::VCLTZ", SDTARMVCMPZ>; def NEONvcgtu : SDNode<"ARMISD::VCGTU", SDTARMVCMP>; def NEONvtst : SDNode<"ARMISD::VTST", SDTARMVCMP>; @@ -69,6 +75,11 @@ def SDTARMVMOVIMM : SDTypeProfile<1, 1, [SDTCisVec<0>, SDTCisVT<1, i32>]>; def NEONvmovImm : SDNode<"ARMISD::VMOVIMM", SDTARMVMOVIMM>; def NEONvmvnImm : SDNode<"ARMISD::VMVNIMM", SDTARMVMOVIMM>; +def SDTARMVORRIMM : SDTypeProfile<1, 2, [SDTCisVec<0>, SDTCisSameAs<0, 1>, + SDTCisVT<2, i32>]>; +def NEONvorrImm : SDNode<"ARMISD::VORRIMM", SDTARMVORRIMM>; +def NEONvbicImm : SDNode<"ARMISD::VBICIMM", SDTARMVORRIMM>; + def NEONvdup : SDNode<"ARMISD::VDUP", SDTypeProfile<1, 1, [SDTCisVec<0>]>>; // VDUPLANE can produce a quad-register result from a double-register source, @@ -129,830 +140,1506 @@ def nModImm : Operand { // NEON load / store instructions //===----------------------------------------------------------------------===// -// Use vldmia to load a Q register as a D register pair. -// This is equivalent to VLDMD except that it has a Q register operand -// instead of a pair of D registers. -def VLDMQ - : AXDI4<(outs QPR:$dst), (ins addrmode4:$addr, pred:$p), - IndexModeNone, IIC_fpLoadm, - "vldm${addr:submode}${p}\t$addr, ${dst:dregpair}", "", - [(set QPR:$dst, (v2f64 (load addrmode4:$addr)))]>; - -let mayLoad = 1, neverHasSideEffects = 1 in { -// Use vld1 to load a Q register as a D register pair. -// This alternative to VLDMQ allows an alignment to be specified. -// This is equivalent to VLD1q64 except that it has a Q register operand. -def VLD1q - : NLdSt<0,0b10,0b1010,0b1100, (outs QPR:$dst), (ins addrmode6:$addr), - IIC_VLD1, "vld1", "64", "${dst:dregpair}, $addr", "", []>; -} // mayLoad = 1, neverHasSideEffects = 1 - -// Use vstmia to store a Q register as a D register pair. -// This is equivalent to VSTMD except that it has a Q register operand -// instead of a pair of D registers. -def VSTMQ - : AXDI4<(outs), (ins QPR:$src, addrmode4:$addr, pred:$p), - IndexModeNone, IIC_fpStorem, - "vstm${addr:submode}${p}\t$addr, ${src:dregpair}", "", - [(store (v2f64 QPR:$src), addrmode4:$addr)]>; - -let mayStore = 1, neverHasSideEffects = 1 in { -// Use vst1 to store a Q register as a D register pair. -// This alternative to VSTMQ allows an alignment to be specified. -// This is equivalent to VST1q64 except that it has a Q register operand. -def VST1q - : NLdSt<0,0b00,0b1010,0b1100, (outs), (ins addrmode6:$addr, QPR:$src), - IIC_VST, "vst1", "64", "${src:dregpair}, $addr", "", []>; -} // mayStore = 1, neverHasSideEffects = 1 - -let mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1 in { +// Use VLDM to load a Q register as a D register pair. +// This is a pseudo instruction that is expanded to VLDMD after reg alloc. +def VLDMQIA + : PseudoVFPLdStM<(outs QPR:$dst), (ins GPR:$Rn), + IIC_fpLoad_m, "", + [(set QPR:$dst, (v2f64 (load GPR:$Rn)))]>; +def VLDMQDB + : PseudoVFPLdStM<(outs QPR:$dst), (ins GPR:$Rn), + IIC_fpLoad_m, "", + [(set QPR:$dst, (v2f64 (load GPR:$Rn)))]>; + +// Use VSTM to store a Q register as a D register pair. +// This is a pseudo instruction that is expanded to VSTMD after reg alloc. +def VSTMQIA + : PseudoVFPLdStM<(outs), (ins QPR:$src, GPR:$Rn), + IIC_fpStore_m, "", + [(store (v2f64 QPR:$src), GPR:$Rn)]>; +def VSTMQDB + : PseudoVFPLdStM<(outs), (ins QPR:$src, GPR:$Rn), + IIC_fpStore_m, "", + [(store (v2f64 QPR:$src), GPR:$Rn)]>; // Classes for VLD* pseudo-instructions with multi-register operands. // These are expanded to real instructions after register allocation. -class VLDQPseudo - : PseudoNLdSt<(outs QPR:$dst), (ins addrmode6:$addr), IIC_VST, "">; -class VLDQWBPseudo +class VLDQPseudo + : PseudoNLdSt<(outs QPR:$dst), (ins addrmode6:$addr), itin, "">; +class VLDQWBPseudo : PseudoNLdSt<(outs QPR:$dst, GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset), IIC_VST, + (ins addrmode6:$addr, am6offset:$offset), itin, "$addr.addr = $wb">; -class VLDQQPseudo - : PseudoNLdSt<(outs QQPR:$dst), (ins addrmode6:$addr), IIC_VST, "">; -class VLDQQWBPseudo +class VLDQQPseudo + : PseudoNLdSt<(outs QQPR:$dst), (ins addrmode6:$addr), itin, "">; +class VLDQQWBPseudo : PseudoNLdSt<(outs QQPR:$dst, GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset), IIC_VST, + (ins addrmode6:$addr, am6offset:$offset), itin, "$addr.addr = $wb">; -class VLDQQQQWBPseudo +class VLDQQQQPseudo + : PseudoNLdSt<(outs QQQQPR:$dst), (ins addrmode6:$addr, QQQQPR:$src), itin,"">; +class VLDQQQQWBPseudo : PseudoNLdSt<(outs QQQQPR:$dst, GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset, QQQQPR:$src), IIC_VST, + (ins addrmode6:$addr, am6offset:$offset, QQQQPR:$src), itin, "$addr.addr = $wb, $src = $dst">; +let mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1 in { + // VLD1 : Vector Load (multiple single elements) class VLD1D op7_4, string Dt> - : NLdSt<0,0b10,0b0111,op7_4, (outs DPR:$dst), - (ins addrmode6:$addr), IIC_VLD1, - "vld1", Dt, "\\{$dst\\}, $addr", "", []>; + : NLdSt<0,0b10,0b0111,op7_4, (outs DPR:$Vd), + (ins addrmode6:$Rn), IIC_VLD1, + "vld1", Dt, "\\{$Vd\\}, $Rn", "", []> { + let Rm = 0b1111; + let Inst{4} = Rn{4}; +} class VLD1Q op7_4, string Dt> - : NLdSt<0,0b10,0b1010,op7_4, (outs DPR:$dst1, DPR:$dst2), - (ins addrmode6:$addr), IIC_VLD1, - "vld1", Dt, "\\{$dst1, $dst2\\}, $addr", "", []>; + : NLdSt<0,0b10,0b1010,op7_4, (outs DPR:$Vd, DPR:$dst2), + (ins addrmode6:$Rn), IIC_VLD1x2, + "vld1", Dt, "\\{$Vd, $dst2\\}, $Rn", "", []> { + let Rm = 0b1111; + let Inst{5-4} = Rn{5-4}; +} -def VLD1d8 : VLD1D<0b0000, "8">; -def VLD1d16 : VLD1D<0b0100, "16">; -def VLD1d32 : VLD1D<0b1000, "32">; -def VLD1d64 : VLD1D<0b1100, "64">; +def VLD1d8 : VLD1D<{0,0,0,?}, "8">; +def VLD1d16 : VLD1D<{0,1,0,?}, "16">; +def VLD1d32 : VLD1D<{1,0,0,?}, "32">; +def VLD1d64 : VLD1D<{1,1,0,?}, "64">; -def VLD1q8 : VLD1Q<0b0000, "8">; -def VLD1q16 : VLD1Q<0b0100, "16">; -def VLD1q32 : VLD1Q<0b1000, "32">; -def VLD1q64 : VLD1Q<0b1100, "64">; +def VLD1q8 : VLD1Q<{0,0,?,?}, "8">; +def VLD1q16 : VLD1Q<{0,1,?,?}, "16">; +def VLD1q32 : VLD1Q<{1,0,?,?}, "32">; +def VLD1q64 : VLD1Q<{1,1,?,?}, "64">; -def VLD1q8Pseudo : VLDQPseudo; -def VLD1q16Pseudo : VLDQPseudo; -def VLD1q32Pseudo : VLDQPseudo; -def VLD1q64Pseudo : VLDQPseudo; +def VLD1q8Pseudo : VLDQPseudo; +def VLD1q16Pseudo : VLDQPseudo; +def VLD1q32Pseudo : VLDQPseudo; +def VLD1q64Pseudo : VLDQPseudo; // ...with address register writeback: class VLD1DWB op7_4, string Dt> - : NLdSt<0,0b10,0b0111,op7_4, (outs DPR:$dst, GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset), IIC_VLD1, - "vld1", Dt, "\\{$dst\\}, $addr$offset", - "$addr.addr = $wb", []>; + : NLdSt<0,0b10,0b0111,op7_4, (outs DPR:$Vd, GPR:$wb), + (ins addrmode6:$Rn, am6offset:$Rm), IIC_VLD1u, + "vld1", Dt, "\\{$Vd\\}, $Rn$Rm", + "$Rn.addr = $wb", []> { + let Inst{4} = Rn{4}; +} class VLD1QWB op7_4, string Dt> - : NLdSt<0,0b10,0b1010,op7_4, (outs QPR:$dst, GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset), IIC_VLD1, - "vld1", Dt, "${dst:dregpair}, $addr$offset", - "$addr.addr = $wb", []>; - -def VLD1d8_UPD : VLD1DWB<0b0000, "8">; -def VLD1d16_UPD : VLD1DWB<0b0100, "16">; -def VLD1d32_UPD : VLD1DWB<0b1000, "32">; -def VLD1d64_UPD : VLD1DWB<0b1100, "64">; - -def VLD1q8_UPD : VLD1QWB<0b0000, "8">; -def VLD1q16_UPD : VLD1QWB<0b0100, "16">; -def VLD1q32_UPD : VLD1QWB<0b1000, "32">; -def VLD1q64_UPD : VLD1QWB<0b1100, "64">; - -def VLD1q8Pseudo_UPD : VLDQWBPseudo; -def VLD1q16Pseudo_UPD : VLDQWBPseudo; -def VLD1q32Pseudo_UPD : VLDQWBPseudo; -def VLD1q64Pseudo_UPD : VLDQWBPseudo; + : NLdSt<0,0b10,0b1010,op7_4, (outs DPR:$Vd, DPR:$dst2, GPR:$wb), + (ins addrmode6:$Rn, am6offset:$Rm), IIC_VLD1x2u, + "vld1", Dt, "\\{$Vd, $dst2\\}, $Rn$Rm", + "$Rn.addr = $wb", []> { + let Inst{5-4} = Rn{5-4}; +} + +def VLD1d8_UPD : VLD1DWB<{0,0,0,?}, "8">; +def VLD1d16_UPD : VLD1DWB<{0,1,0,?}, "16">; +def VLD1d32_UPD : VLD1DWB<{1,0,0,?}, "32">; +def VLD1d64_UPD : VLD1DWB<{1,1,0,?}, "64">; + +def VLD1q8_UPD : VLD1QWB<{0,0,?,?}, "8">; +def VLD1q16_UPD : VLD1QWB<{0,1,?,?}, "16">; +def VLD1q32_UPD : VLD1QWB<{1,0,?,?}, "32">; +def VLD1q64_UPD : VLD1QWB<{1,1,?,?}, "64">; + +def VLD1q8Pseudo_UPD : VLDQWBPseudo; +def VLD1q16Pseudo_UPD : VLDQWBPseudo; +def VLD1q32Pseudo_UPD : VLDQWBPseudo; +def VLD1q64Pseudo_UPD : VLDQWBPseudo; // ...with 3 registers (some of these are only for the disassembler): class VLD1D3 op7_4, string Dt> - : NLdSt<0,0b10,0b0110,op7_4, (outs DPR:$dst1, DPR:$dst2, DPR:$dst3), - (ins addrmode6:$addr), IIC_VLD1, "vld1", Dt, - "\\{$dst1, $dst2, $dst3\\}, $addr", "", []>; + : NLdSt<0,0b10,0b0110,op7_4, (outs DPR:$Vd, DPR:$dst2, DPR:$dst3), + (ins addrmode6:$Rn), IIC_VLD1x3, "vld1", Dt, + "\\{$Vd, $dst2, $dst3\\}, $Rn", "", []> { + let Rm = 0b1111; + let Inst{4} = Rn{4}; +} class VLD1D3WB op7_4, string Dt> - : NLdSt<0,0b10,0b0110,op7_4, (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset), IIC_VLD1, "vld1", Dt, - "\\{$dst1, $dst2, $dst3\\}, $addr$offset", "$addr.addr = $wb", []>; + : NLdSt<0,0b10,0b0110,op7_4, (outs DPR:$Vd, DPR:$dst2, DPR:$dst3, GPR:$wb), + (ins addrmode6:$Rn, am6offset:$Rm), IIC_VLD1x3u, "vld1", Dt, + "\\{$Vd, $dst2, $dst3\\}, $Rn$Rm", "$Rn.addr = $wb", []> { + let Inst{4} = Rn{4}; +} -def VLD1d8T : VLD1D3<0b0000, "8">; -def VLD1d16T : VLD1D3<0b0100, "16">; -def VLD1d32T : VLD1D3<0b1000, "32">; -def VLD1d64T : VLD1D3<0b1100, "64">; +def VLD1d8T : VLD1D3<{0,0,0,?}, "8">; +def VLD1d16T : VLD1D3<{0,1,0,?}, "16">; +def VLD1d32T : VLD1D3<{1,0,0,?}, "32">; +def VLD1d64T : VLD1D3<{1,1,0,?}, "64">; -def VLD1d8T_UPD : VLD1D3WB<0b0000, "8">; -def VLD1d16T_UPD : VLD1D3WB<0b0100, "16">; -def VLD1d32T_UPD : VLD1D3WB<0b1000, "32">; -def VLD1d64T_UPD : VLD1D3WB<0b1100, "64">; +def VLD1d8T_UPD : VLD1D3WB<{0,0,0,?}, "8">; +def VLD1d16T_UPD : VLD1D3WB<{0,1,0,?}, "16">; +def VLD1d32T_UPD : VLD1D3WB<{1,0,0,?}, "32">; +def VLD1d64T_UPD : VLD1D3WB<{1,1,0,?}, "64">; -def VLD1d64TPseudo : VLDQQPseudo; -def VLD1d64TPseudo_UPD : VLDQQWBPseudo; +def VLD1d64TPseudo : VLDQQPseudo; +def VLD1d64TPseudo_UPD : VLDQQWBPseudo; // ...with 4 registers (some of these are only for the disassembler): class VLD1D4 op7_4, string Dt> - : NLdSt<0,0b10,0b0010,op7_4,(outs DPR:$dst1, DPR:$dst2, DPR:$dst3, DPR:$dst4), - (ins addrmode6:$addr), IIC_VLD1, "vld1", Dt, - "\\{$dst1, $dst2, $dst3, $dst4\\}, $addr", "", []>; + : NLdSt<0,0b10,0b0010,op7_4,(outs DPR:$Vd, DPR:$dst2, DPR:$dst3, DPR:$dst4), + (ins addrmode6:$Rn), IIC_VLD1x4, "vld1", Dt, + "\\{$Vd, $dst2, $dst3, $dst4\\}, $Rn", "", []> { + let Rm = 0b1111; + let Inst{5-4} = Rn{5-4}; +} class VLD1D4WB op7_4, string Dt> : NLdSt<0,0b10,0b0010,op7_4, - (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, DPR:$dst4, GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset), IIC_VLD1, "vld1", Dt, - "\\{$dst1, $dst2, $dst3, $dst4\\}, $addr$offset", "$addr.addr = $wb", - []>; + (outs DPR:$Vd, DPR:$dst2, DPR:$dst3, DPR:$dst4, GPR:$wb), + (ins addrmode6:$Rn, am6offset:$Rm), IIC_VLD1x4u, "vld1", Dt, + "\\{$Vd, $dst2, $dst3, $dst4\\}, $Rn$Rm", "$Rn.addr = $wb", + []> { + let Inst{5-4} = Rn{5-4}; +} -def VLD1d8Q : VLD1D4<0b0000, "8">; -def VLD1d16Q : VLD1D4<0b0100, "16">; -def VLD1d32Q : VLD1D4<0b1000, "32">; -def VLD1d64Q : VLD1D4<0b1100, "64">; +def VLD1d8Q : VLD1D4<{0,0,?,?}, "8">; +def VLD1d16Q : VLD1D4<{0,1,?,?}, "16">; +def VLD1d32Q : VLD1D4<{1,0,?,?}, "32">; +def VLD1d64Q : VLD1D4<{1,1,?,?}, "64">; -def VLD1d8Q_UPD : VLD1D4WB<0b0000, "8">; -def VLD1d16Q_UPD : VLD1D4WB<0b0100, "16">; -def VLD1d32Q_UPD : VLD1D4WB<0b1000, "32">; -def VLD1d64Q_UPD : VLD1D4WB<0b1100, "64">; +def VLD1d8Q_UPD : VLD1D4WB<{0,0,?,?}, "8">; +def VLD1d16Q_UPD : VLD1D4WB<{0,1,?,?}, "16">; +def VLD1d32Q_UPD : VLD1D4WB<{1,0,?,?}, "32">; +def VLD1d64Q_UPD : VLD1D4WB<{1,1,?,?}, "64">; -def VLD1d64QPseudo : VLDQQPseudo; -def VLD1d64QPseudo_UPD : VLDQQWBPseudo; +def VLD1d64QPseudo : VLDQQPseudo; +def VLD1d64QPseudo_UPD : VLDQQWBPseudo; // VLD2 : Vector Load (multiple 2-element structures) class VLD2D op11_8, bits<4> op7_4, string Dt> - : NLdSt<0, 0b10, op11_8, op7_4, (outs DPR:$dst1, DPR:$dst2), - (ins addrmode6:$addr), IIC_VLD2, - "vld2", Dt, "\\{$dst1, $dst2\\}, $addr", "", []>; + : NLdSt<0, 0b10, op11_8, op7_4, (outs DPR:$Vd, DPR:$dst2), + (ins addrmode6:$Rn), IIC_VLD2, + "vld2", Dt, "\\{$Vd, $dst2\\}, $Rn", "", []> { + let Rm = 0b1111; + let Inst{5-4} = Rn{5-4}; +} class VLD2Q op7_4, string Dt> : NLdSt<0, 0b10, 0b0011, op7_4, - (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, DPR:$dst4), - (ins addrmode6:$addr), IIC_VLD2, - "vld2", Dt, "\\{$dst1, $dst2, $dst3, $dst4\\}, $addr", "", []>; + (outs DPR:$Vd, DPR:$dst2, DPR:$dst3, DPR:$dst4), + (ins addrmode6:$Rn), IIC_VLD2x2, + "vld2", Dt, "\\{$Vd, $dst2, $dst3, $dst4\\}, $Rn", "", []> { + let Rm = 0b1111; + let Inst{5-4} = Rn{5-4}; +} -def VLD2d8 : VLD2D<0b1000, 0b0000, "8">; -def VLD2d16 : VLD2D<0b1000, 0b0100, "16">; -def VLD2d32 : VLD2D<0b1000, 0b1000, "32">; +def VLD2d8 : VLD2D<0b1000, {0,0,?,?}, "8">; +def VLD2d16 : VLD2D<0b1000, {0,1,?,?}, "16">; +def VLD2d32 : VLD2D<0b1000, {1,0,?,?}, "32">; -def VLD2q8 : VLD2Q<0b0000, "8">; -def VLD2q16 : VLD2Q<0b0100, "16">; -def VLD2q32 : VLD2Q<0b1000, "32">; +def VLD2q8 : VLD2Q<{0,0,?,?}, "8">; +def VLD2q16 : VLD2Q<{0,1,?,?}, "16">; +def VLD2q32 : VLD2Q<{1,0,?,?}, "32">; -def VLD2d8Pseudo : VLDQPseudo; -def VLD2d16Pseudo : VLDQPseudo; -def VLD2d32Pseudo : VLDQPseudo; +def VLD2d8Pseudo : VLDQPseudo; +def VLD2d16Pseudo : VLDQPseudo; +def VLD2d32Pseudo : VLDQPseudo; -def VLD2q8Pseudo : VLDQQPseudo; -def VLD2q16Pseudo : VLDQQPseudo; -def VLD2q32Pseudo : VLDQQPseudo; +def VLD2q8Pseudo : VLDQQPseudo; +def VLD2q16Pseudo : VLDQQPseudo; +def VLD2q32Pseudo : VLDQQPseudo; // ...with address register writeback: class VLD2DWB op11_8, bits<4> op7_4, string Dt> - : NLdSt<0, 0b10, op11_8, op7_4, (outs DPR:$dst1, DPR:$dst2, GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset), IIC_VLD2, - "vld2", Dt, "\\{$dst1, $dst2\\}, $addr$offset", - "$addr.addr = $wb", []>; + : NLdSt<0, 0b10, op11_8, op7_4, (outs DPR:$Vd, DPR:$dst2, GPR:$wb), + (ins addrmode6:$Rn, am6offset:$Rm), IIC_VLD2u, + "vld2", Dt, "\\{$Vd, $dst2\\}, $Rn$Rm", + "$Rn.addr = $wb", []> { + let Inst{5-4} = Rn{5-4}; +} class VLD2QWB op7_4, string Dt> : NLdSt<0, 0b10, 0b0011, op7_4, - (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, DPR:$dst4, GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset), IIC_VLD2, - "vld2", Dt, "\\{$dst1, $dst2, $dst3, $dst4\\}, $addr$offset", - "$addr.addr = $wb", []>; + (outs DPR:$Vd, DPR:$dst2, DPR:$dst3, DPR:$dst4, GPR:$wb), + (ins addrmode6:$Rn, am6offset:$Rm), IIC_VLD2x2u, + "vld2", Dt, "\\{$Vd, $dst2, $dst3, $dst4\\}, $Rn$Rm", + "$Rn.addr = $wb", []> { + let Inst{5-4} = Rn{5-4}; +} -def VLD2d8_UPD : VLD2DWB<0b1000, 0b0000, "8">; -def VLD2d16_UPD : VLD2DWB<0b1000, 0b0100, "16">; -def VLD2d32_UPD : VLD2DWB<0b1000, 0b1000, "32">; +def VLD2d8_UPD : VLD2DWB<0b1000, {0,0,?,?}, "8">; +def VLD2d16_UPD : VLD2DWB<0b1000, {0,1,?,?}, "16">; +def VLD2d32_UPD : VLD2DWB<0b1000, {1,0,?,?}, "32">; -def VLD2q8_UPD : VLD2QWB<0b0000, "8">; -def VLD2q16_UPD : VLD2QWB<0b0100, "16">; -def VLD2q32_UPD : VLD2QWB<0b1000, "32">; +def VLD2q8_UPD : VLD2QWB<{0,0,?,?}, "8">; +def VLD2q16_UPD : VLD2QWB<{0,1,?,?}, "16">; +def VLD2q32_UPD : VLD2QWB<{1,0,?,?}, "32">; -def VLD2d8Pseudo_UPD : VLDQWBPseudo; -def VLD2d16Pseudo_UPD : VLDQWBPseudo; -def VLD2d32Pseudo_UPD : VLDQWBPseudo; +def VLD2d8Pseudo_UPD : VLDQWBPseudo; +def VLD2d16Pseudo_UPD : VLDQWBPseudo; +def VLD2d32Pseudo_UPD : VLDQWBPseudo; -def VLD2q8Pseudo_UPD : VLDQQWBPseudo; -def VLD2q16Pseudo_UPD : VLDQQWBPseudo; -def VLD2q32Pseudo_UPD : VLDQQWBPseudo; +def VLD2q8Pseudo_UPD : VLDQQWBPseudo; +def VLD2q16Pseudo_UPD : VLDQQWBPseudo; +def VLD2q32Pseudo_UPD : VLDQQWBPseudo; // ...with double-spaced registers (for disassembly only): -def VLD2b8 : VLD2D<0b1001, 0b0000, "8">; -def VLD2b16 : VLD2D<0b1001, 0b0100, "16">; -def VLD2b32 : VLD2D<0b1001, 0b1000, "32">; -def VLD2b8_UPD : VLD2DWB<0b1001, 0b0000, "8">; -def VLD2b16_UPD : VLD2DWB<0b1001, 0b0100, "16">; -def VLD2b32_UPD : VLD2DWB<0b1001, 0b1000, "32">; +def VLD2b8 : VLD2D<0b1001, {0,0,?,?}, "8">; +def VLD2b16 : VLD2D<0b1001, {0,1,?,?}, "16">; +def VLD2b32 : VLD2D<0b1001, {1,0,?,?}, "32">; +def VLD2b8_UPD : VLD2DWB<0b1001, {0,0,?,?}, "8">; +def VLD2b16_UPD : VLD2DWB<0b1001, {0,1,?,?}, "16">; +def VLD2b32_UPD : VLD2DWB<0b1001, {1,0,?,?}, "32">; // VLD3 : Vector Load (multiple 3-element structures) class VLD3D op11_8, bits<4> op7_4, string Dt> - : NLdSt<0, 0b10, op11_8, op7_4, (outs DPR:$dst1, DPR:$dst2, DPR:$dst3), - (ins addrmode6:$addr), IIC_VLD3, - "vld3", Dt, "\\{$dst1, $dst2, $dst3\\}, $addr", "", []>; + : NLdSt<0, 0b10, op11_8, op7_4, (outs DPR:$Vd, DPR:$dst2, DPR:$dst3), + (ins addrmode6:$Rn), IIC_VLD3, + "vld3", Dt, "\\{$Vd, $dst2, $dst3\\}, $Rn", "", []> { + let Rm = 0b1111; + let Inst{4} = Rn{4}; +} -def VLD3d8 : VLD3D<0b0100, 0b0000, "8">; -def VLD3d16 : VLD3D<0b0100, 0b0100, "16">; -def VLD3d32 : VLD3D<0b0100, 0b1000, "32">; +def VLD3d8 : VLD3D<0b0100, {0,0,0,?}, "8">; +def VLD3d16 : VLD3D<0b0100, {0,1,0,?}, "16">; +def VLD3d32 : VLD3D<0b0100, {1,0,0,?}, "32">; -def VLD3d8Pseudo : VLDQQPseudo; -def VLD3d16Pseudo : VLDQQPseudo; -def VLD3d32Pseudo : VLDQQPseudo; +def VLD3d8Pseudo : VLDQQPseudo; +def VLD3d16Pseudo : VLDQQPseudo; +def VLD3d32Pseudo : VLDQQPseudo; // ...with address register writeback: class VLD3DWB op11_8, bits<4> op7_4, string Dt> : NLdSt<0, 0b10, op11_8, op7_4, - (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset), IIC_VLD3, - "vld3", Dt, "\\{$dst1, $dst2, $dst3\\}, $addr$offset", - "$addr.addr = $wb", []>; - -def VLD3d8_UPD : VLD3DWB<0b0100, 0b0000, "8">; -def VLD3d16_UPD : VLD3DWB<0b0100, 0b0100, "16">; -def VLD3d32_UPD : VLD3DWB<0b0100, 0b1000, "32">; - -def VLD3d8Pseudo_UPD : VLDQQWBPseudo; -def VLD3d16Pseudo_UPD : VLDQQWBPseudo; -def VLD3d32Pseudo_UPD : VLDQQWBPseudo; - -// ...with double-spaced registers (non-updating versions for disassembly only): -def VLD3q8 : VLD3D<0b0101, 0b0000, "8">; -def VLD3q16 : VLD3D<0b0101, 0b0100, "16">; -def VLD3q32 : VLD3D<0b0101, 0b1000, "32">; -def VLD3q8_UPD : VLD3DWB<0b0101, 0b0000, "8">; -def VLD3q16_UPD : VLD3DWB<0b0101, 0b0100, "16">; -def VLD3q32_UPD : VLD3DWB<0b0101, 0b1000, "32">; - -def VLD3q8Pseudo_UPD : VLDQQQQWBPseudo; -def VLD3q16Pseudo_UPD : VLDQQQQWBPseudo; -def VLD3q32Pseudo_UPD : VLDQQQQWBPseudo; + (outs DPR:$Vd, DPR:$dst2, DPR:$dst3, GPR:$wb), + (ins addrmode6:$Rn, am6offset:$Rm), IIC_VLD3u, + "vld3", Dt, "\\{$Vd, $dst2, $dst3\\}, $Rn$Rm", + "$Rn.addr = $wb", []> { + let Inst{4} = Rn{4}; +} + +def VLD3d8_UPD : VLD3DWB<0b0100, {0,0,0,?}, "8">; +def VLD3d16_UPD : VLD3DWB<0b0100, {0,1,0,?}, "16">; +def VLD3d32_UPD : VLD3DWB<0b0100, {1,0,0,?}, "32">; + +def VLD3d8Pseudo_UPD : VLDQQWBPseudo; +def VLD3d16Pseudo_UPD : VLDQQWBPseudo; +def VLD3d32Pseudo_UPD : VLDQQWBPseudo; + +// ...with double-spaced registers: +def VLD3q8 : VLD3D<0b0101, {0,0,0,?}, "8">; +def VLD3q16 : VLD3D<0b0101, {0,1,0,?}, "16">; +def VLD3q32 : VLD3D<0b0101, {1,0,0,?}, "32">; +def VLD3q8_UPD : VLD3DWB<0b0101, {0,0,0,?}, "8">; +def VLD3q16_UPD : VLD3DWB<0b0101, {0,1,0,?}, "16">; +def VLD3q32_UPD : VLD3DWB<0b0101, {1,0,0,?}, "32">; + +def VLD3q8Pseudo_UPD : VLDQQQQWBPseudo; +def VLD3q16Pseudo_UPD : VLDQQQQWBPseudo; +def VLD3q32Pseudo_UPD : VLDQQQQWBPseudo; // ...alternate versions to be allocated odd register numbers: -def VLD3q8oddPseudo_UPD : VLDQQQQWBPseudo; -def VLD3q16oddPseudo_UPD : VLDQQQQWBPseudo; -def VLD3q32oddPseudo_UPD : VLDQQQQWBPseudo; +def VLD3q8oddPseudo : VLDQQQQPseudo; +def VLD3q16oddPseudo : VLDQQQQPseudo; +def VLD3q32oddPseudo : VLDQQQQPseudo; + +def VLD3q8oddPseudo_UPD : VLDQQQQWBPseudo; +def VLD3q16oddPseudo_UPD : VLDQQQQWBPseudo; +def VLD3q32oddPseudo_UPD : VLDQQQQWBPseudo; // VLD4 : Vector Load (multiple 4-element structures) class VLD4D op11_8, bits<4> op7_4, string Dt> : NLdSt<0, 0b10, op11_8, op7_4, - (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, DPR:$dst4), - (ins addrmode6:$addr), IIC_VLD4, - "vld4", Dt, "\\{$dst1, $dst2, $dst3, $dst4\\}, $addr", "", []>; + (outs DPR:$Vd, DPR:$dst2, DPR:$dst3, DPR:$dst4), + (ins addrmode6:$Rn), IIC_VLD4, + "vld4", Dt, "\\{$Vd, $dst2, $dst3, $dst4\\}, $Rn", "", []> { + let Rm = 0b1111; + let Inst{5-4} = Rn{5-4}; +} -def VLD4d8 : VLD4D<0b0000, 0b0000, "8">; -def VLD4d16 : VLD4D<0b0000, 0b0100, "16">; -def VLD4d32 : VLD4D<0b0000, 0b1000, "32">; +def VLD4d8 : VLD4D<0b0000, {0,0,?,?}, "8">; +def VLD4d16 : VLD4D<0b0000, {0,1,?,?}, "16">; +def VLD4d32 : VLD4D<0b0000, {1,0,?,?}, "32">; -def VLD4d8Pseudo : VLDQQPseudo; -def VLD4d16Pseudo : VLDQQPseudo; -def VLD4d32Pseudo : VLDQQPseudo; +def VLD4d8Pseudo : VLDQQPseudo; +def VLD4d16Pseudo : VLDQQPseudo; +def VLD4d32Pseudo : VLDQQPseudo; // ...with address register writeback: class VLD4DWB op11_8, bits<4> op7_4, string Dt> : NLdSt<0, 0b10, op11_8, op7_4, - (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, DPR:$dst4, GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset), IIC_VLD4, - "vld4", Dt, "\\{$dst1, $dst2, $dst3, $dst4\\}, $addr$offset", - "$addr.addr = $wb", []>; - -def VLD4d8_UPD : VLD4DWB<0b0000, 0b0000, "8">; -def VLD4d16_UPD : VLD4DWB<0b0000, 0b0100, "16">; -def VLD4d32_UPD : VLD4DWB<0b0000, 0b1000, "32">; - -def VLD4d8Pseudo_UPD : VLDQQWBPseudo; -def VLD4d16Pseudo_UPD : VLDQQWBPseudo; -def VLD4d32Pseudo_UPD : VLDQQWBPseudo; - -// ...with double-spaced registers (non-updating versions for disassembly only): -def VLD4q8 : VLD4D<0b0001, 0b0000, "8">; -def VLD4q16 : VLD4D<0b0001, 0b0100, "16">; -def VLD4q32 : VLD4D<0b0001, 0b1000, "32">; -def VLD4q8_UPD : VLD4DWB<0b0001, 0b0000, "8">; -def VLD4q16_UPD : VLD4DWB<0b0001, 0b0100, "16">; -def VLD4q32_UPD : VLD4DWB<0b0001, 0b1000, "32">; - -def VLD4q8Pseudo_UPD : VLDQQQQWBPseudo; -def VLD4q16Pseudo_UPD : VLDQQQQWBPseudo; -def VLD4q32Pseudo_UPD : VLDQQQQWBPseudo; + (outs DPR:$Vd, DPR:$dst2, DPR:$dst3, DPR:$dst4, GPR:$wb), + (ins addrmode6:$Rn, am6offset:$Rm), IIC_VLD4u, + "vld4", Dt, "\\{$Vd, $dst2, $dst3, $dst4\\}, $Rn$Rm", + "$Rn.addr = $wb", []> { + let Inst{5-4} = Rn{5-4}; +} + +def VLD4d8_UPD : VLD4DWB<0b0000, {0,0,?,?}, "8">; +def VLD4d16_UPD : VLD4DWB<0b0000, {0,1,?,?}, "16">; +def VLD4d32_UPD : VLD4DWB<0b0000, {1,0,?,?}, "32">; + +def VLD4d8Pseudo_UPD : VLDQQWBPseudo; +def VLD4d16Pseudo_UPD : VLDQQWBPseudo; +def VLD4d32Pseudo_UPD : VLDQQWBPseudo; + +// ...with double-spaced registers: +def VLD4q8 : VLD4D<0b0001, {0,0,?,?}, "8">; +def VLD4q16 : VLD4D<0b0001, {0,1,?,?}, "16">; +def VLD4q32 : VLD4D<0b0001, {1,0,?,?}, "32">; +def VLD4q8_UPD : VLD4DWB<0b0001, {0,0,?,?}, "8">; +def VLD4q16_UPD : VLD4DWB<0b0001, {0,1,?,?}, "16">; +def VLD4q32_UPD : VLD4DWB<0b0001, {1,0,?,?}, "32">; + +def VLD4q8Pseudo_UPD : VLDQQQQWBPseudo; +def VLD4q16Pseudo_UPD : VLDQQQQWBPseudo; +def VLD4q32Pseudo_UPD : VLDQQQQWBPseudo; // ...alternate versions to be allocated odd register numbers: -def VLD4q8oddPseudo_UPD : VLDQQQQWBPseudo; -def VLD4q16oddPseudo_UPD : VLDQQQQWBPseudo; -def VLD4q32oddPseudo_UPD : VLDQQQQWBPseudo; +def VLD4q8oddPseudo : VLDQQQQPseudo; +def VLD4q16oddPseudo : VLDQQQQPseudo; +def VLD4q32oddPseudo : VLDQQQQPseudo; + +def VLD4q8oddPseudo_UPD : VLDQQQQWBPseudo; +def VLD4q16oddPseudo_UPD : VLDQQQQWBPseudo; +def VLD4q32oddPseudo_UPD : VLDQQQQWBPseudo; + +} // mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1 + +// Classes for VLD*LN pseudo-instructions with multi-register operands. +// These are expanded to real instructions after register allocation. +class VLDQLNPseudo + : PseudoNLdSt<(outs QPR:$dst), + (ins addrmode6:$addr, QPR:$src, nohash_imm:$lane), + itin, "$src = $dst">; +class VLDQLNWBPseudo + : PseudoNLdSt<(outs QPR:$dst, GPR:$wb), + (ins addrmode6:$addr, am6offset:$offset, QPR:$src, + nohash_imm:$lane), itin, "$addr.addr = $wb, $src = $dst">; +class VLDQQLNPseudo + : PseudoNLdSt<(outs QQPR:$dst), + (ins addrmode6:$addr, QQPR:$src, nohash_imm:$lane), + itin, "$src = $dst">; +class VLDQQLNWBPseudo + : PseudoNLdSt<(outs QQPR:$dst, GPR:$wb), + (ins addrmode6:$addr, am6offset:$offset, QQPR:$src, + nohash_imm:$lane), itin, "$addr.addr = $wb, $src = $dst">; +class VLDQQQQLNPseudo + : PseudoNLdSt<(outs QQQQPR:$dst), + (ins addrmode6:$addr, QQQQPR:$src, nohash_imm:$lane), + itin, "$src = $dst">; +class VLDQQQQLNWBPseudo + : PseudoNLdSt<(outs QQQQPR:$dst, GPR:$wb), + (ins addrmode6:$addr, am6offset:$offset, QQQQPR:$src, + nohash_imm:$lane), itin, "$addr.addr = $wb, $src = $dst">; // VLD1LN : Vector Load (single element to one lane) -// FIXME: Not yet implemented. +class VLD1LN op11_8, bits<4> op7_4, string Dt, ValueType Ty, + PatFrag LoadOp> + : NLdStLn<1, 0b10, op11_8, op7_4, (outs DPR:$Vd), + (ins addrmode6:$Rn, DPR:$src, nohash_imm:$lane), + IIC_VLD1ln, "vld1", Dt, "\\{$Vd[$lane]\\}, $Rn", + "$src = $Vd", + [(set DPR:$Vd, (vector_insert (Ty DPR:$src), + (i32 (LoadOp addrmode6:$Rn)), + imm:$lane))]> { + let Rm = 0b1111; +} +class VLD1QLNPseudo : VLDQLNPseudo { + let Pattern = [(set QPR:$dst, (vector_insert (Ty QPR:$src), + (i32 (LoadOp addrmode6:$addr)), + imm:$lane))]; +} + +def VLD1LNd8 : VLD1LN<0b0000, {?,?,?,0}, "8", v8i8, extloadi8> { + let Inst{7-5} = lane{2-0}; +} +def VLD1LNd16 : VLD1LN<0b0100, {?,?,0,?}, "16", v4i16, extloadi16> { + let Inst{7-6} = lane{1-0}; + let Inst{4} = Rn{4}; +} +def VLD1LNd32 : VLD1LN<0b1000, {?,0,?,?}, "32", v2i32, load> { + let Inst{7} = lane{0}; + let Inst{5} = Rn{4}; + let Inst{4} = Rn{4}; +} + +def VLD1LNq8Pseudo : VLD1QLNPseudo; +def VLD1LNq16Pseudo : VLD1QLNPseudo; +def VLD1LNq32Pseudo : VLD1QLNPseudo; + +def : Pat<(vector_insert (v2f32 DPR:$src), + (f32 (load addrmode6:$addr)), imm:$lane), + (VLD1LNd32 addrmode6:$addr, DPR:$src, imm:$lane)>; +def : Pat<(vector_insert (v4f32 QPR:$src), + (f32 (load addrmode6:$addr)), imm:$lane), + (VLD1LNq32Pseudo addrmode6:$addr, QPR:$src, imm:$lane)>; + +let mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1 in { + +// ...with address register writeback: +class VLD1LNWB op11_8, bits<4> op7_4, string Dt> + : NLdStLn<1, 0b10, op11_8, op7_4, (outs DPR:$Vd, GPR:$wb), + (ins addrmode6:$Rn, am6offset:$Rm, + DPR:$src, nohash_imm:$lane), IIC_VLD1lnu, "vld1", Dt, + "\\{$Vd[$lane]\\}, $Rn$Rm", + "$src = $Vd, $Rn.addr = $wb", []>; + +def VLD1LNd8_UPD : VLD1LNWB<0b0000, {?,?,?,0}, "8"> { + let Inst{7-5} = lane{2-0}; +} +def VLD1LNd16_UPD : VLD1LNWB<0b0100, {?,?,0,?}, "16"> { + let Inst{7-6} = lane{1-0}; + let Inst{4} = Rn{4}; +} +def VLD1LNd32_UPD : VLD1LNWB<0b1000, {?,0,?,?}, "32"> { + let Inst{7} = lane{0}; + let Inst{5} = Rn{4}; + let Inst{4} = Rn{4}; +} + +def VLD1LNq8Pseudo_UPD : VLDQLNWBPseudo; +def VLD1LNq16Pseudo_UPD : VLDQLNWBPseudo; +def VLD1LNq32Pseudo_UPD : VLDQLNWBPseudo; // VLD2LN : Vector Load (single 2-element structure to one lane) class VLD2LN op11_8, bits<4> op7_4, string Dt> - : NLdSt<1, 0b10, op11_8, op7_4, (outs DPR:$dst1, DPR:$dst2), - (ins addrmode6:$addr, DPR:$src1, DPR:$src2, nohash_imm:$lane), - IIC_VLD2, "vld2", Dt, "\\{$dst1[$lane], $dst2[$lane]\\}, $addr", - "$src1 = $dst1, $src2 = $dst2", []>; + : NLdStLn<1, 0b10, op11_8, op7_4, (outs DPR:$Vd, DPR:$dst2), + (ins addrmode6:$Rn, DPR:$src1, DPR:$src2, nohash_imm:$lane), + IIC_VLD2ln, "vld2", Dt, "\\{$Vd[$lane], $dst2[$lane]\\}, $Rn", + "$src1 = $Vd, $src2 = $dst2", []> { + let Rm = 0b1111; + let Inst{4} = Rn{4}; +} + +def VLD2LNd8 : VLD2LN<0b0001, {?,?,?,?}, "8"> { + let Inst{7-5} = lane{2-0}; +} +def VLD2LNd16 : VLD2LN<0b0101, {?,?,0,?}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VLD2LNd32 : VLD2LN<0b1001, {?,0,0,?}, "32"> { + let Inst{7} = lane{0}; +} -def VLD2LNd8 : VLD2LN<0b0001, {?,?,?,?}, "8">; -def VLD2LNd16 : VLD2LN<0b0101, {?,?,0,?}, "16">; -def VLD2LNd32 : VLD2LN<0b1001, {?,0,?,?}, "32">; +def VLD2LNd8Pseudo : VLDQLNPseudo; +def VLD2LNd16Pseudo : VLDQLNPseudo; +def VLD2LNd32Pseudo : VLDQLNPseudo; // ...with double-spaced registers: -def VLD2LNq16 : VLD2LN<0b0101, {?,?,1,?}, "16">; -def VLD2LNq32 : VLD2LN<0b1001, {?,1,?,?}, "32">; +def VLD2LNq16 : VLD2LN<0b0101, {?,?,1,?}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VLD2LNq32 : VLD2LN<0b1001, {?,1,0,?}, "32"> { + let Inst{7} = lane{0}; +} -// ...alternate versions to be allocated odd register numbers: -def VLD2LNq16odd : VLD2LN<0b0101, {?,?,1,?}, "16">; -def VLD2LNq32odd : VLD2LN<0b1001, {?,1,?,?}, "32">; +def VLD2LNq16Pseudo : VLDQQLNPseudo; +def VLD2LNq32Pseudo : VLDQQLNPseudo; // ...with address register writeback: class VLD2LNWB op11_8, bits<4> op7_4, string Dt> - : NLdSt<1, 0b10, op11_8, op7_4, (outs DPR:$dst1, DPR:$dst2, GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset, - DPR:$src1, DPR:$src2, nohash_imm:$lane), IIC_VLD2, "vld2", Dt, - "\\{$dst1[$lane], $dst2[$lane]\\}, $addr$offset", - "$src1 = $dst1, $src2 = $dst2, $addr.addr = $wb", []>; + : NLdStLn<1, 0b10, op11_8, op7_4, (outs DPR:$Vd, DPR:$dst2, GPR:$wb), + (ins addrmode6:$Rn, am6offset:$Rm, + DPR:$src1, DPR:$src2, nohash_imm:$lane), IIC_VLD2lnu, "vld2", Dt, + "\\{$Vd[$lane], $dst2[$lane]\\}, $Rn$Rm", + "$src1 = $Vd, $src2 = $dst2, $Rn.addr = $wb", []> { + let Inst{4} = Rn{4}; +} -def VLD2LNd8_UPD : VLD2LNWB<0b0001, {?,?,?,?}, "8">; -def VLD2LNd16_UPD : VLD2LNWB<0b0101, {?,?,0,?}, "16">; -def VLD2LNd32_UPD : VLD2LNWB<0b1001, {?,0,?,?}, "32">; +def VLD2LNd8_UPD : VLD2LNWB<0b0001, {?,?,?,?}, "8"> { + let Inst{7-5} = lane{2-0}; +} +def VLD2LNd16_UPD : VLD2LNWB<0b0101, {?,?,0,?}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VLD2LNd32_UPD : VLD2LNWB<0b1001, {?,0,0,?}, "32"> { + let Inst{7} = lane{0}; +} -def VLD2LNq16_UPD : VLD2LNWB<0b0101, {?,?,1,?}, "16">; -def VLD2LNq32_UPD : VLD2LNWB<0b1001, {?,1,?,?}, "32">; +def VLD2LNd8Pseudo_UPD : VLDQLNWBPseudo; +def VLD2LNd16Pseudo_UPD : VLDQLNWBPseudo; +def VLD2LNd32Pseudo_UPD : VLDQLNWBPseudo; + +def VLD2LNq16_UPD : VLD2LNWB<0b0101, {?,?,1,?}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VLD2LNq32_UPD : VLD2LNWB<0b1001, {?,1,0,?}, "32"> { + let Inst{7} = lane{0}; +} + +def VLD2LNq16Pseudo_UPD : VLDQQLNWBPseudo; +def VLD2LNq32Pseudo_UPD : VLDQQLNWBPseudo; // VLD3LN : Vector Load (single 3-element structure to one lane) class VLD3LN op11_8, bits<4> op7_4, string Dt> - : NLdSt<1, 0b10, op11_8, op7_4, (outs DPR:$dst1, DPR:$dst2, DPR:$dst3), - (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3, - nohash_imm:$lane), IIC_VLD3, "vld3", Dt, - "\\{$dst1[$lane], $dst2[$lane], $dst3[$lane]\\}, $addr", - "$src1 = $dst1, $src2 = $dst2, $src3 = $dst3", []>; + : NLdStLn<1, 0b10, op11_8, op7_4, (outs DPR:$Vd, DPR:$dst2, DPR:$dst3), + (ins addrmode6:$Rn, DPR:$src1, DPR:$src2, DPR:$src3, + nohash_imm:$lane), IIC_VLD3ln, "vld3", Dt, + "\\{$Vd[$lane], $dst2[$lane], $dst3[$lane]\\}, $Rn", + "$src1 = $Vd, $src2 = $dst2, $src3 = $dst3", []> { + let Rm = 0b1111; +} + +def VLD3LNd8 : VLD3LN<0b0010, {?,?,?,0}, "8"> { + let Inst{7-5} = lane{2-0}; +} +def VLD3LNd16 : VLD3LN<0b0110, {?,?,0,0}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VLD3LNd32 : VLD3LN<0b1010, {?,0,0,0}, "32"> { + let Inst{7} = lane{0}; +} -def VLD3LNd8 : VLD3LN<0b0010, {?,?,?,0}, "8">; -def VLD3LNd16 : VLD3LN<0b0110, {?,?,0,0}, "16">; -def VLD3LNd32 : VLD3LN<0b1010, {?,0,0,0}, "32">; +def VLD3LNd8Pseudo : VLDQQLNPseudo; +def VLD3LNd16Pseudo : VLDQQLNPseudo; +def VLD3LNd32Pseudo : VLDQQLNPseudo; // ...with double-spaced registers: -def VLD3LNq16 : VLD3LN<0b0110, {?,?,1,0}, "16">; -def VLD3LNq32 : VLD3LN<0b1010, {?,1,0,0}, "32">; +def VLD3LNq16 : VLD3LN<0b0110, {?,?,1,0}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VLD3LNq32 : VLD3LN<0b1010, {?,1,0,0}, "32"> { + let Inst{7} = lane{0}; +} -// ...alternate versions to be allocated odd register numbers: -def VLD3LNq16odd : VLD3LN<0b0110, {?,?,1,0}, "16">; -def VLD3LNq32odd : VLD3LN<0b1010, {?,1,0,0}, "32">; +def VLD3LNq16Pseudo : VLDQQQQLNPseudo; +def VLD3LNq32Pseudo : VLDQQQQLNPseudo; // ...with address register writeback: class VLD3LNWB op11_8, bits<4> op7_4, string Dt> - : NLdSt<1, 0b10, op11_8, op7_4, - (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset, + : NLdStLn<1, 0b10, op11_8, op7_4, + (outs DPR:$Vd, DPR:$dst2, DPR:$dst3, GPR:$wb), + (ins addrmode6:$Rn, am6offset:$Rm, DPR:$src1, DPR:$src2, DPR:$src3, nohash_imm:$lane), - IIC_VLD3, "vld3", Dt, - "\\{$dst1[$lane], $dst2[$lane], $dst3[$lane]\\}, $addr$offset", - "$src1 = $dst1, $src2 = $dst2, $src3 = $dst3, $addr.addr = $wb", + IIC_VLD3lnu, "vld3", Dt, + "\\{$Vd[$lane], $dst2[$lane], $dst3[$lane]\\}, $Rn$Rm", + "$src1 = $Vd, $src2 = $dst2, $src3 = $dst3, $Rn.addr = $wb", []>; -def VLD3LNd8_UPD : VLD3LNWB<0b0010, {?,?,?,0}, "8">; -def VLD3LNd16_UPD : VLD3LNWB<0b0110, {?,?,0,0}, "16">; -def VLD3LNd32_UPD : VLD3LNWB<0b1010, {?,0,0,0}, "32">; +def VLD3LNd8_UPD : VLD3LNWB<0b0010, {?,?,?,0}, "8"> { + let Inst{7-5} = lane{2-0}; +} +def VLD3LNd16_UPD : VLD3LNWB<0b0110, {?,?,0,0}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VLD3LNd32_UPD : VLD3LNWB<0b1010, {?,0,0,0}, "32"> { + let Inst{7} = lane{0}; +} + +def VLD3LNd8Pseudo_UPD : VLDQQLNWBPseudo; +def VLD3LNd16Pseudo_UPD : VLDQQLNWBPseudo; +def VLD3LNd32Pseudo_UPD : VLDQQLNWBPseudo; + +def VLD3LNq16_UPD : VLD3LNWB<0b0110, {?,?,1,0}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VLD3LNq32_UPD : VLD3LNWB<0b1010, {?,1,0,0}, "32"> { + let Inst{7} = lane{0}; +} -def VLD3LNq16_UPD : VLD3LNWB<0b0110, {?,?,1,0}, "16">; -def VLD3LNq32_UPD : VLD3LNWB<0b1010, {?,1,0,0}, "32">; +def VLD3LNq16Pseudo_UPD : VLDQQQQLNWBPseudo; +def VLD3LNq32Pseudo_UPD : VLDQQQQLNWBPseudo; // VLD4LN : Vector Load (single 4-element structure to one lane) class VLD4LN op11_8, bits<4> op7_4, string Dt> - : NLdSt<1, 0b10, op11_8, op7_4, - (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, DPR:$dst4), - (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3, DPR:$src4, - nohash_imm:$lane), IIC_VLD4, "vld4", Dt, - "\\{$dst1[$lane], $dst2[$lane], $dst3[$lane], $dst4[$lane]\\}, $addr", - "$src1 = $dst1, $src2 = $dst2, $src3 = $dst3, $src4 = $dst4", []>; + : NLdStLn<1, 0b10, op11_8, op7_4, + (outs DPR:$Vd, DPR:$dst2, DPR:$dst3, DPR:$dst4), + (ins addrmode6:$Rn, DPR:$src1, DPR:$src2, DPR:$src3, DPR:$src4, + nohash_imm:$lane), IIC_VLD4ln, "vld4", Dt, + "\\{$Vd[$lane], $dst2[$lane], $dst3[$lane], $dst4[$lane]\\}, $Rn", + "$src1 = $Vd, $src2 = $dst2, $src3 = $dst3, $src4 = $dst4", []> { + let Rm = 0b1111; + let Inst{4} = Rn{4}; +} -def VLD4LNd8 : VLD4LN<0b0011, {?,?,?,?}, "8">; -def VLD4LNd16 : VLD4LN<0b0111, {?,?,0,?}, "16">; -def VLD4LNd32 : VLD4LN<0b1011, {?,0,?,?}, "32">; +def VLD4LNd8 : VLD4LN<0b0011, {?,?,?,?}, "8"> { + let Inst{7-5} = lane{2-0}; +} +def VLD4LNd16 : VLD4LN<0b0111, {?,?,0,?}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VLD4LNd32 : VLD4LN<0b1011, {?,0,?,?}, "32"> { + let Inst{7} = lane{0}; + let Inst{5} = Rn{5}; +} + +def VLD4LNd8Pseudo : VLDQQLNPseudo; +def VLD4LNd16Pseudo : VLDQQLNPseudo; +def VLD4LNd32Pseudo : VLDQQLNPseudo; // ...with double-spaced registers: -def VLD4LNq16 : VLD4LN<0b0111, {?,?,1,?}, "16">; -def VLD4LNq32 : VLD4LN<0b1011, {?,1,?,?}, "32">; +def VLD4LNq16 : VLD4LN<0b0111, {?,?,1,?}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VLD4LNq32 : VLD4LN<0b1011, {?,1,?,?}, "32"> { + let Inst{7} = lane{0}; + let Inst{5} = Rn{5}; +} -// ...alternate versions to be allocated odd register numbers: -def VLD4LNq16odd : VLD4LN<0b0111, {?,?,1,?}, "16">; -def VLD4LNq32odd : VLD4LN<0b1011, {?,1,?,?}, "32">; +def VLD4LNq16Pseudo : VLDQQQQLNPseudo; +def VLD4LNq32Pseudo : VLDQQQQLNPseudo; // ...with address register writeback: class VLD4LNWB op11_8, bits<4> op7_4, string Dt> - : NLdSt<1, 0b10, op11_8, op7_4, - (outs DPR:$dst1, DPR:$dst2, DPR:$dst3, DPR:$dst4, GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset, + : NLdStLn<1, 0b10, op11_8, op7_4, + (outs DPR:$Vd, DPR:$dst2, DPR:$dst3, DPR:$dst4, GPR:$wb), + (ins addrmode6:$Rn, am6offset:$Rm, DPR:$src1, DPR:$src2, DPR:$src3, DPR:$src4, nohash_imm:$lane), - IIC_VLD4, "vld4", Dt, -"\\{$dst1[$lane], $dst2[$lane], $dst3[$lane], $dst4[$lane]\\}, $addr$offset", -"$src1 = $dst1, $src2 = $dst2, $src3 = $dst3, $src4 = $dst4, $addr.addr = $wb", - []>; + IIC_VLD4lnu, "vld4", Dt, +"\\{$Vd[$lane], $dst2[$lane], $dst3[$lane], $dst4[$lane]\\}, $Rn$Rm", +"$src1 = $Vd, $src2 = $dst2, $src3 = $dst3, $src4 = $dst4, $Rn.addr = $wb", + []> { + let Inst{4} = Rn{4}; +} + +def VLD4LNd8_UPD : VLD4LNWB<0b0011, {?,?,?,?}, "8"> { + let Inst{7-5} = lane{2-0}; +} +def VLD4LNd16_UPD : VLD4LNWB<0b0111, {?,?,0,?}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VLD4LNd32_UPD : VLD4LNWB<0b1011, {?,0,?,?}, "32"> { + let Inst{7} = lane{0}; + let Inst{5} = Rn{5}; +} + +def VLD4LNd8Pseudo_UPD : VLDQQLNWBPseudo; +def VLD4LNd16Pseudo_UPD : VLDQQLNWBPseudo; +def VLD4LNd32Pseudo_UPD : VLDQQLNWBPseudo; -def VLD4LNd8_UPD : VLD4LNWB<0b0011, {?,?,?,?}, "8">; -def VLD4LNd16_UPD : VLD4LNWB<0b0111, {?,?,0,?}, "16">; -def VLD4LNd32_UPD : VLD4LNWB<0b1011, {?,0,?,?}, "32">; +def VLD4LNq16_UPD : VLD4LNWB<0b0111, {?,?,1,?}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VLD4LNq32_UPD : VLD4LNWB<0b1011, {?,1,?,?}, "32"> { + let Inst{7} = lane{0}; + let Inst{5} = Rn{5}; +} -def VLD4LNq16_UPD : VLD4LNWB<0b0111, {?,?,1,?}, "16">; -def VLD4LNq32_UPD : VLD4LNWB<0b1011, {?,1,?,?}, "32">; +def VLD4LNq16Pseudo_UPD : VLDQQQQLNWBPseudo; +def VLD4LNq32Pseudo_UPD : VLDQQQQLNWBPseudo; + +} // mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1 // VLD1DUP : Vector Load (single element to all lanes) +class VLD1DUP op7_4, string Dt, ValueType Ty, PatFrag LoadOp> + : NLdSt<1, 0b10, 0b1100, op7_4, (outs DPR:$Vd), (ins addrmode6dup:$Rn), + IIC_VLD1dup, "vld1", Dt, "\\{$Vd[]\\}, $Rn", "", + [(set DPR:$Vd, (Ty (NEONvdup (i32 (LoadOp addrmode6dup:$Rn)))))]> { + let Rm = 0b1111; + let Inst{4} = Rn{4}; +} +class VLD1QDUPPseudo : VLDQPseudo { + let Pattern = [(set QPR:$dst, + (Ty (NEONvdup (i32 (LoadOp addrmode6dup:$addr)))))]; +} + +def VLD1DUPd8 : VLD1DUP<{0,0,0,?}, "8", v8i8, extloadi8>; +def VLD1DUPd16 : VLD1DUP<{0,1,0,?}, "16", v4i16, extloadi16>; +def VLD1DUPd32 : VLD1DUP<{1,0,0,?}, "32", v2i32, load>; + +def VLD1DUPq8Pseudo : VLD1QDUPPseudo; +def VLD1DUPq16Pseudo : VLD1QDUPPseudo; +def VLD1DUPq32Pseudo : VLD1QDUPPseudo; + +def : Pat<(v2f32 (NEONvdup (f32 (load addrmode6dup:$addr)))), + (VLD1DUPd32 addrmode6:$addr)>; +def : Pat<(v4f32 (NEONvdup (f32 (load addrmode6dup:$addr)))), + (VLD1DUPq32Pseudo addrmode6:$addr)>; + +let mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1 in { + +class VLD1QDUP op7_4, string Dt> + : NLdSt<1, 0b10, 0b1100, op7_4, (outs DPR:$Vd, DPR:$dst2), + (ins addrmode6dup:$Rn), IIC_VLD1dup, + "vld1", Dt, "\\{$Vd[], $dst2[]\\}, $Rn", "", []> { + let Rm = 0b1111; + let Inst{4} = Rn{4}; +} + +def VLD1DUPq8 : VLD1QDUP<{0,0,1,0}, "8">; +def VLD1DUPq16 : VLD1QDUP<{0,1,1,?}, "16">; +def VLD1DUPq32 : VLD1QDUP<{1,0,1,?}, "32">; + +// ...with address register writeback: +class VLD1DUPWB op7_4, string Dt> + : NLdSt<1, 0b10, 0b1100, op7_4, (outs DPR:$Vd, GPR:$wb), + (ins addrmode6dup:$Rn, am6offset:$Rm), IIC_VLD1dupu, + "vld1", Dt, "\\{$Vd[]\\}, $Rn$Rm", "$Rn.addr = $wb", []> { + let Inst{4} = Rn{4}; +} +class VLD1QDUPWB op7_4, string Dt> + : NLdSt<1, 0b10, 0b1100, op7_4, (outs DPR:$Vd, DPR:$dst2, GPR:$wb), + (ins addrmode6dup:$Rn, am6offset:$Rm), IIC_VLD1dupu, + "vld1", Dt, "\\{$Vd[], $dst2[]\\}, $Rn$Rm", "$Rn.addr = $wb", []> { + let Inst{4} = Rn{4}; +} + +def VLD1DUPd8_UPD : VLD1DUPWB<{0,0,0,0}, "8">; +def VLD1DUPd16_UPD : VLD1DUPWB<{0,1,0,?}, "16">; +def VLD1DUPd32_UPD : VLD1DUPWB<{1,0,0,?}, "32">; + +def VLD1DUPq8_UPD : VLD1QDUPWB<{0,0,1,0}, "8">; +def VLD1DUPq16_UPD : VLD1QDUPWB<{0,1,1,?}, "16">; +def VLD1DUPq32_UPD : VLD1QDUPWB<{1,0,1,?}, "32">; + +def VLD1DUPq8Pseudo_UPD : VLDQWBPseudo; +def VLD1DUPq16Pseudo_UPD : VLDQWBPseudo; +def VLD1DUPq32Pseudo_UPD : VLDQWBPseudo; + // VLD2DUP : Vector Load (single 2-element structure to all lanes) +class VLD2DUP op7_4, string Dt> + : NLdSt<1, 0b10, 0b1101, op7_4, (outs DPR:$Vd, DPR:$dst2), + (ins addrmode6dup:$Rn), IIC_VLD2dup, + "vld2", Dt, "\\{$Vd[], $dst2[]\\}, $Rn", "", []> { + let Rm = 0b1111; + let Inst{4} = Rn{4}; +} + +def VLD2DUPd8 : VLD2DUP<{0,0,0,?}, "8">; +def VLD2DUPd16 : VLD2DUP<{0,1,0,?}, "16">; +def VLD2DUPd32 : VLD2DUP<{1,0,0,?}, "32">; + +def VLD2DUPd8Pseudo : VLDQPseudo; +def VLD2DUPd16Pseudo : VLDQPseudo; +def VLD2DUPd32Pseudo : VLDQPseudo; + +// ...with double-spaced registers (not used for codegen): +def VLD2DUPd8x2 : VLD2DUP<{0,0,1,?}, "8">; +def VLD2DUPd16x2 : VLD2DUP<{0,1,1,?}, "16">; +def VLD2DUPd32x2 : VLD2DUP<{1,0,1,?}, "32">; + +// ...with address register writeback: +class VLD2DUPWB op7_4, string Dt> + : NLdSt<1, 0b10, 0b1101, op7_4, (outs DPR:$Vd, DPR:$dst2, GPR:$wb), + (ins addrmode6dup:$Rn, am6offset:$Rm), IIC_VLD2dupu, + "vld2", Dt, "\\{$Vd[], $dst2[]\\}, $Rn$Rm", "$Rn.addr = $wb", []> { + let Inst{4} = Rn{4}; +} + +def VLD2DUPd8_UPD : VLD2DUPWB<{0,0,0,0}, "8">; +def VLD2DUPd16_UPD : VLD2DUPWB<{0,1,0,?}, "16">; +def VLD2DUPd32_UPD : VLD2DUPWB<{1,0,0,?}, "32">; + +def VLD2DUPd8x2_UPD : VLD2DUPWB<{0,0,1,0}, "8">; +def VLD2DUPd16x2_UPD : VLD2DUPWB<{0,1,1,?}, "16">; +def VLD2DUPd32x2_UPD : VLD2DUPWB<{1,0,1,?}, "32">; + +def VLD2DUPd8Pseudo_UPD : VLDQWBPseudo; +def VLD2DUPd16Pseudo_UPD : VLDQWBPseudo; +def VLD2DUPd32Pseudo_UPD : VLDQWBPseudo; + // VLD3DUP : Vector Load (single 3-element structure to all lanes) +class VLD3DUP op7_4, string Dt> + : NLdSt<1, 0b10, 0b1110, op7_4, (outs DPR:$Vd, DPR:$dst2, DPR:$dst3), + (ins addrmode6dup:$Rn), IIC_VLD3dup, + "vld3", Dt, "\\{$Vd[], $dst2[], $dst3[]\\}, $Rn", "", []> { + let Rm = 0b1111; + let Inst{4} = Rn{4}; +} + +def VLD3DUPd8 : VLD3DUP<{0,0,0,?}, "8">; +def VLD3DUPd16 : VLD3DUP<{0,1,0,?}, "16">; +def VLD3DUPd32 : VLD3DUP<{1,0,0,?}, "32">; + +def VLD3DUPd8Pseudo : VLDQQPseudo; +def VLD3DUPd16Pseudo : VLDQQPseudo; +def VLD3DUPd32Pseudo : VLDQQPseudo; + +// ...with double-spaced registers (not used for codegen): +def VLD3DUPd8x2 : VLD3DUP<{0,0,1,?}, "8">; +def VLD3DUPd16x2 : VLD3DUP<{0,1,1,?}, "16">; +def VLD3DUPd32x2 : VLD3DUP<{1,0,1,?}, "32">; + +// ...with address register writeback: +class VLD3DUPWB op7_4, string Dt> + : NLdSt<1, 0b10, 0b1110, op7_4, (outs DPR:$Vd, DPR:$dst2, DPR:$dst3, GPR:$wb), + (ins addrmode6dup:$Rn, am6offset:$Rm), IIC_VLD3dupu, + "vld3", Dt, "\\{$Vd[], $dst2[], $dst3[]\\}, $Rn$Rm", + "$Rn.addr = $wb", []> { + let Inst{4} = Rn{4}; +} + +def VLD3DUPd8_UPD : VLD3DUPWB<{0,0,0,0}, "8">; +def VLD3DUPd16_UPD : VLD3DUPWB<{0,1,0,?}, "16">; +def VLD3DUPd32_UPD : VLD3DUPWB<{1,0,0,?}, "32">; + +def VLD3DUPd8x2_UPD : VLD3DUPWB<{0,0,1,0}, "8">; +def VLD3DUPd16x2_UPD : VLD3DUPWB<{0,1,1,?}, "16">; +def VLD3DUPd32x2_UPD : VLD3DUPWB<{1,0,1,?}, "32">; + +def VLD3DUPd8Pseudo_UPD : VLDQQWBPseudo; +def VLD3DUPd16Pseudo_UPD : VLDQQWBPseudo; +def VLD3DUPd32Pseudo_UPD : VLDQQWBPseudo; + // VLD4DUP : Vector Load (single 4-element structure to all lanes) -// FIXME: Not yet implemented. +class VLD4DUP op7_4, string Dt> + : NLdSt<1, 0b10, 0b1111, op7_4, + (outs DPR:$Vd, DPR:$dst2, DPR:$dst3, DPR:$dst4), + (ins addrmode6dup:$Rn), IIC_VLD4dup, + "vld4", Dt, "\\{$Vd[], $dst2[], $dst3[], $dst4[]\\}, $Rn", "", []> { + let Rm = 0b1111; + let Inst{4} = Rn{4}; +} + +def VLD4DUPd8 : VLD4DUP<{0,0,0,?}, "8">; +def VLD4DUPd16 : VLD4DUP<{0,1,0,?}, "16">; +def VLD4DUPd32 : VLD4DUP<{1,?,0,?}, "32"> { let Inst{6} = Rn{5}; } + +def VLD4DUPd8Pseudo : VLDQQPseudo; +def VLD4DUPd16Pseudo : VLDQQPseudo; +def VLD4DUPd32Pseudo : VLDQQPseudo; + +// ...with double-spaced registers (not used for codegen): +def VLD4DUPd8x2 : VLD4DUP<{0,0,1,?}, "8">; +def VLD4DUPd16x2 : VLD4DUP<{0,1,1,?}, "16">; +def VLD4DUPd32x2 : VLD4DUP<{1,?,1,?}, "32"> { let Inst{6} = Rn{5}; } + +// ...with address register writeback: +class VLD4DUPWB op7_4, string Dt> + : NLdSt<1, 0b10, 0b1111, op7_4, + (outs DPR:$Vd, DPR:$dst2, DPR:$dst3, DPR:$dst4, GPR:$wb), + (ins addrmode6dup:$Rn, am6offset:$Rm), IIC_VLD4dupu, + "vld4", Dt, "\\{$Vd[], $dst2[], $dst3[], $dst4[]\\}, $Rn$Rm", + "$Rn.addr = $wb", []> { + let Inst{4} = Rn{4}; +} + +def VLD4DUPd8_UPD : VLD4DUPWB<{0,0,0,0}, "8">; +def VLD4DUPd16_UPD : VLD4DUPWB<{0,1,0,?}, "16">; +def VLD4DUPd32_UPD : VLD4DUPWB<{1,?,0,?}, "32"> { let Inst{6} = Rn{5}; } + +def VLD4DUPd8x2_UPD : VLD4DUPWB<{0,0,1,0}, "8">; +def VLD4DUPd16x2_UPD : VLD4DUPWB<{0,1,1,?}, "16">; +def VLD4DUPd32x2_UPD : VLD4DUPWB<{1,?,1,?}, "32"> { let Inst{6} = Rn{5}; } + +def VLD4DUPd8Pseudo_UPD : VLDQQWBPseudo; +def VLD4DUPd16Pseudo_UPD : VLDQQWBPseudo; +def VLD4DUPd32Pseudo_UPD : VLDQQWBPseudo; + } // mayLoad = 1, neverHasSideEffects = 1, hasExtraDefRegAllocReq = 1 let mayStore = 1, neverHasSideEffects = 1, hasExtraSrcRegAllocReq = 1 in { // Classes for VST* pseudo-instructions with multi-register operands. // These are expanded to real instructions after register allocation. -class VSTQPseudo - : PseudoNLdSt<(outs), (ins addrmode6:$addr, QPR:$src), IIC_VST, "">; -class VSTQWBPseudo +class VSTQPseudo + : PseudoNLdSt<(outs), (ins addrmode6:$addr, QPR:$src), itin, "">; +class VSTQWBPseudo : PseudoNLdSt<(outs GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset, QPR:$src), IIC_VST, + (ins addrmode6:$addr, am6offset:$offset, QPR:$src), itin, "$addr.addr = $wb">; -class VSTQQPseudo - : PseudoNLdSt<(outs), (ins addrmode6:$addr, QQPR:$src), IIC_VST, "">; -class VSTQQWBPseudo +class VSTQQPseudo + : PseudoNLdSt<(outs), (ins addrmode6:$addr, QQPR:$src), itin, "">; +class VSTQQWBPseudo : PseudoNLdSt<(outs GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset, QQPR:$src), IIC_VST, + (ins addrmode6:$addr, am6offset:$offset, QQPR:$src), itin, "$addr.addr = $wb">; -class VSTQQQQWBPseudo +class VSTQQQQPseudo + : PseudoNLdSt<(outs), (ins addrmode6:$addr, QQQQPR:$src), itin, "">; +class VSTQQQQWBPseudo : PseudoNLdSt<(outs GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset, QQQQPR:$src), IIC_VST, + (ins addrmode6:$addr, am6offset:$offset, QQQQPR:$src), itin, "$addr.addr = $wb">; // VST1 : Vector Store (multiple single elements) class VST1D op7_4, string Dt> - : NLdSt<0,0b00,0b0111,op7_4, (outs), (ins addrmode6:$addr, DPR:$src), IIC_VST, - "vst1", Dt, "\\{$src\\}, $addr", "", []>; + : NLdSt<0,0b00,0b0111,op7_4, (outs), (ins addrmode6:$Rn, DPR:$Vd), + IIC_VST1, "vst1", Dt, "\\{$Vd\\}, $Rn", "", []> { + let Rm = 0b1111; + let Inst{4} = Rn{4}; +} class VST1Q op7_4, string Dt> : NLdSt<0,0b00,0b1010,op7_4, (outs), - (ins addrmode6:$addr, DPR:$src1, DPR:$src2), IIC_VST, - "vst1", Dt, "\\{$src1, $src2\\}, $addr", "", []>; + (ins addrmode6:$Rn, DPR:$Vd, DPR:$src2), IIC_VST1x2, + "vst1", Dt, "\\{$Vd, $src2\\}, $Rn", "", []> { + let Rm = 0b1111; + let Inst{5-4} = Rn{5-4}; +} -def VST1d8 : VST1D<0b0000, "8">; -def VST1d16 : VST1D<0b0100, "16">; -def VST1d32 : VST1D<0b1000, "32">; -def VST1d64 : VST1D<0b1100, "64">; +def VST1d8 : VST1D<{0,0,0,?}, "8">; +def VST1d16 : VST1D<{0,1,0,?}, "16">; +def VST1d32 : VST1D<{1,0,0,?}, "32">; +def VST1d64 : VST1D<{1,1,0,?}, "64">; -def VST1q8 : VST1Q<0b0000, "8">; -def VST1q16 : VST1Q<0b0100, "16">; -def VST1q32 : VST1Q<0b1000, "32">; -def VST1q64 : VST1Q<0b1100, "64">; +def VST1q8 : VST1Q<{0,0,?,?}, "8">; +def VST1q16 : VST1Q<{0,1,?,?}, "16">; +def VST1q32 : VST1Q<{1,0,?,?}, "32">; +def VST1q64 : VST1Q<{1,1,?,?}, "64">; -def VST1q8Pseudo : VSTQPseudo; -def VST1q16Pseudo : VSTQPseudo; -def VST1q32Pseudo : VSTQPseudo; -def VST1q64Pseudo : VSTQPseudo; +def VST1q8Pseudo : VSTQPseudo; +def VST1q16Pseudo : VSTQPseudo; +def VST1q32Pseudo : VSTQPseudo; +def VST1q64Pseudo : VSTQPseudo; // ...with address register writeback: class VST1DWB op7_4, string Dt> : NLdSt<0, 0b00, 0b0111, op7_4, (outs GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset, DPR:$src), IIC_VST, - "vst1", Dt, "\\{$src\\}, $addr$offset", "$addr.addr = $wb", []>; + (ins addrmode6:$Rn, am6offset:$Rm, DPR:$Vd), IIC_VST1u, + "vst1", Dt, "\\{$Vd\\}, $Rn$Rm", "$Rn.addr = $wb", []> { + let Inst{4} = Rn{4}; +} class VST1QWB op7_4, string Dt> : NLdSt<0, 0b00, 0b1010, op7_4, (outs GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset, QPR:$src), IIC_VST, - "vst1", Dt, "${src:dregpair}, $addr$offset", "$addr.addr = $wb", []>; + (ins addrmode6:$Rn, am6offset:$Rm, DPR:$Vd, DPR:$src2), + IIC_VST1x2u, "vst1", Dt, "\\{$Vd, $src2\\}, $Rn$Rm", + "$Rn.addr = $wb", []> { + let Inst{5-4} = Rn{5-4}; +} -def VST1d8_UPD : VST1DWB<0b0000, "8">; -def VST1d16_UPD : VST1DWB<0b0100, "16">; -def VST1d32_UPD : VST1DWB<0b1000, "32">; -def VST1d64_UPD : VST1DWB<0b1100, "64">; +def VST1d8_UPD : VST1DWB<{0,0,0,?}, "8">; +def VST1d16_UPD : VST1DWB<{0,1,0,?}, "16">; +def VST1d32_UPD : VST1DWB<{1,0,0,?}, "32">; +def VST1d64_UPD : VST1DWB<{1,1,0,?}, "64">; -def VST1q8_UPD : VST1QWB<0b0000, "8">; -def VST1q16_UPD : VST1QWB<0b0100, "16">; -def VST1q32_UPD : VST1QWB<0b1000, "32">; -def VST1q64_UPD : VST1QWB<0b1100, "64">; +def VST1q8_UPD : VST1QWB<{0,0,?,?}, "8">; +def VST1q16_UPD : VST1QWB<{0,1,?,?}, "16">; +def VST1q32_UPD : VST1QWB<{1,0,?,?}, "32">; +def VST1q64_UPD : VST1QWB<{1,1,?,?}, "64">; -def VST1q8Pseudo_UPD : VSTQWBPseudo; -def VST1q16Pseudo_UPD : VSTQWBPseudo; -def VST1q32Pseudo_UPD : VSTQWBPseudo; -def VST1q64Pseudo_UPD : VSTQWBPseudo; +def VST1q8Pseudo_UPD : VSTQWBPseudo; +def VST1q16Pseudo_UPD : VSTQWBPseudo; +def VST1q32Pseudo_UPD : VSTQWBPseudo; +def VST1q64Pseudo_UPD : VSTQWBPseudo; // ...with 3 registers (some of these are only for the disassembler): class VST1D3 op7_4, string Dt> : NLdSt<0, 0b00, 0b0110, op7_4, (outs), - (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3), - IIC_VST, "vst1", Dt, "\\{$src1, $src2, $src3\\}, $addr", "", []>; + (ins addrmode6:$Rn, DPR:$Vd, DPR:$src2, DPR:$src3), + IIC_VST1x3, "vst1", Dt, "\\{$Vd, $src2, $src3\\}, $Rn", "", []> { + let Rm = 0b1111; + let Inst{4} = Rn{4}; +} class VST1D3WB op7_4, string Dt> : NLdSt<0, 0b00, 0b0110, op7_4, (outs GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset, - DPR:$src1, DPR:$src2, DPR:$src3), - IIC_VST, "vst1", Dt, "\\{$src1, $src2, $src3\\}, $addr$offset", - "$addr.addr = $wb", []>; + (ins addrmode6:$Rn, am6offset:$Rm, + DPR:$Vd, DPR:$src2, DPR:$src3), + IIC_VST1x3u, "vst1", Dt, "\\{$Vd, $src2, $src3\\}, $Rn$Rm", + "$Rn.addr = $wb", []> { + let Inst{4} = Rn{4}; +} -def VST1d8T : VST1D3<0b0000, "8">; -def VST1d16T : VST1D3<0b0100, "16">; -def VST1d32T : VST1D3<0b1000, "32">; -def VST1d64T : VST1D3<0b1100, "64">; +def VST1d8T : VST1D3<{0,0,0,?}, "8">; +def VST1d16T : VST1D3<{0,1,0,?}, "16">; +def VST1d32T : VST1D3<{1,0,0,?}, "32">; +def VST1d64T : VST1D3<{1,1,0,?}, "64">; -def VST1d8T_UPD : VST1D3WB<0b0000, "8">; -def VST1d16T_UPD : VST1D3WB<0b0100, "16">; -def VST1d32T_UPD : VST1D3WB<0b1000, "32">; -def VST1d64T_UPD : VST1D3WB<0b1100, "64">; +def VST1d8T_UPD : VST1D3WB<{0,0,0,?}, "8">; +def VST1d16T_UPD : VST1D3WB<{0,1,0,?}, "16">; +def VST1d32T_UPD : VST1D3WB<{1,0,0,?}, "32">; +def VST1d64T_UPD : VST1D3WB<{1,1,0,?}, "64">; -def VST1d64TPseudo : VSTQQPseudo; -def VST1d64TPseudo_UPD : VSTQQWBPseudo; +def VST1d64TPseudo : VSTQQPseudo; +def VST1d64TPseudo_UPD : VSTQQWBPseudo; // ...with 4 registers (some of these are only for the disassembler): class VST1D4 op7_4, string Dt> : NLdSt<0, 0b00, 0b0010, op7_4, (outs), - (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3, DPR:$src4), - IIC_VST, "vst1", Dt, "\\{$src1, $src2, $src3, $src4\\}, $addr", "", - []>; + (ins addrmode6:$Rn, DPR:$Vd, DPR:$src2, DPR:$src3, DPR:$src4), + IIC_VST1x4, "vst1", Dt, "\\{$Vd, $src2, $src3, $src4\\}, $Rn", "", + []> { + let Rm = 0b1111; + let Inst{5-4} = Rn{5-4}; +} class VST1D4WB op7_4, string Dt> : NLdSt<0, 0b00, 0b0010, op7_4, (outs GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset, - DPR:$src1, DPR:$src2, DPR:$src3, DPR:$src4), - IIC_VST, "vst1", Dt, "\\{$src1, $src2, $src3, $src4\\}, $addr$offset", - "$addr.addr = $wb", []>; + (ins addrmode6:$Rn, am6offset:$Rm, + DPR:$Vd, DPR:$src2, DPR:$src3, DPR:$src4), IIC_VST1x4u, + "vst1", Dt, "\\{$Vd, $src2, $src3, $src4\\}, $Rn$Rm", + "$Rn.addr = $wb", []> { + let Inst{5-4} = Rn{5-4}; +} -def VST1d8Q : VST1D4<0b0000, "8">; -def VST1d16Q : VST1D4<0b0100, "16">; -def VST1d32Q : VST1D4<0b1000, "32">; -def VST1d64Q : VST1D4<0b1100, "64">; +def VST1d8Q : VST1D4<{0,0,?,?}, "8">; +def VST1d16Q : VST1D4<{0,1,?,?}, "16">; +def VST1d32Q : VST1D4<{1,0,?,?}, "32">; +def VST1d64Q : VST1D4<{1,1,?,?}, "64">; -def VST1d8Q_UPD : VST1D4WB<0b0000, "8">; -def VST1d16Q_UPD : VST1D4WB<0b0100, "16">; -def VST1d32Q_UPD : VST1D4WB<0b1000, "32">; -def VST1d64Q_UPD : VST1D4WB<0b1100, "64">; +def VST1d8Q_UPD : VST1D4WB<{0,0,?,?}, "8">; +def VST1d16Q_UPD : VST1D4WB<{0,1,?,?}, "16">; +def VST1d32Q_UPD : VST1D4WB<{1,0,?,?}, "32">; +def VST1d64Q_UPD : VST1D4WB<{1,1,?,?}, "64">; -def VST1d64QPseudo : VSTQQPseudo; -def VST1d64QPseudo_UPD : VSTQQWBPseudo; +def VST1d64QPseudo : VSTQQPseudo; +def VST1d64QPseudo_UPD : VSTQQWBPseudo; // VST2 : Vector Store (multiple 2-element structures) class VST2D op11_8, bits<4> op7_4, string Dt> : NLdSt<0, 0b00, op11_8, op7_4, (outs), - (ins addrmode6:$addr, DPR:$src1, DPR:$src2), - IIC_VST, "vst2", Dt, "\\{$src1, $src2\\}, $addr", "", []>; + (ins addrmode6:$Rn, DPR:$Vd, DPR:$src2), + IIC_VST2, "vst2", Dt, "\\{$Vd, $src2\\}, $Rn", "", []> { + let Rm = 0b1111; + let Inst{5-4} = Rn{5-4}; +} class VST2Q op7_4, string Dt> : NLdSt<0, 0b00, 0b0011, op7_4, (outs), - (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3, DPR:$src4), - IIC_VST, "vst2", Dt, "\\{$src1, $src2, $src3, $src4\\}, $addr", - "", []>; + (ins addrmode6:$Rn, DPR:$Vd, DPR:$src2, DPR:$src3, DPR:$src4), + IIC_VST2x2, "vst2", Dt, "\\{$Vd, $src2, $src3, $src4\\}, $Rn", + "", []> { + let Rm = 0b1111; + let Inst{5-4} = Rn{5-4}; +} -def VST2d8 : VST2D<0b1000, 0b0000, "8">; -def VST2d16 : VST2D<0b1000, 0b0100, "16">; -def VST2d32 : VST2D<0b1000, 0b1000, "32">; +def VST2d8 : VST2D<0b1000, {0,0,?,?}, "8">; +def VST2d16 : VST2D<0b1000, {0,1,?,?}, "16">; +def VST2d32 : VST2D<0b1000, {1,0,?,?}, "32">; -def VST2q8 : VST2Q<0b0000, "8">; -def VST2q16 : VST2Q<0b0100, "16">; -def VST2q32 : VST2Q<0b1000, "32">; +def VST2q8 : VST2Q<{0,0,?,?}, "8">; +def VST2q16 : VST2Q<{0,1,?,?}, "16">; +def VST2q32 : VST2Q<{1,0,?,?}, "32">; -def VST2d8Pseudo : VSTQPseudo; -def VST2d16Pseudo : VSTQPseudo; -def VST2d32Pseudo : VSTQPseudo; +def VST2d8Pseudo : VSTQPseudo; +def VST2d16Pseudo : VSTQPseudo; +def VST2d32Pseudo : VSTQPseudo; -def VST2q8Pseudo : VSTQQPseudo; -def VST2q16Pseudo : VSTQQPseudo; -def VST2q32Pseudo : VSTQQPseudo; +def VST2q8Pseudo : VSTQQPseudo; +def VST2q16Pseudo : VSTQQPseudo; +def VST2q32Pseudo : VSTQQPseudo; // ...with address register writeback: class VST2DWB op11_8, bits<4> op7_4, string Dt> : NLdSt<0, 0b00, op11_8, op7_4, (outs GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset, DPR:$src1, DPR:$src2), - IIC_VST, "vst2", Dt, "\\{$src1, $src2\\}, $addr$offset", - "$addr.addr = $wb", []>; + (ins addrmode6:$Rn, am6offset:$Rm, DPR:$Vd, DPR:$src2), + IIC_VST2u, "vst2", Dt, "\\{$Vd, $src2\\}, $Rn$Rm", + "$Rn.addr = $wb", []> { + let Inst{5-4} = Rn{5-4}; +} class VST2QWB op7_4, string Dt> : NLdSt<0, 0b00, 0b0011, op7_4, (outs GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset, - DPR:$src1, DPR:$src2, DPR:$src3, DPR:$src4), - IIC_VST, "vst2", Dt, "\\{$src1, $src2, $src3, $src4\\}, $addr$offset", - "$addr.addr = $wb", []>; + (ins addrmode6:$Rn, am6offset:$Rm, + DPR:$Vd, DPR:$src2, DPR:$src3, DPR:$src4), IIC_VST2x2u, + "vst2", Dt, "\\{$Vd, $src2, $src3, $src4\\}, $Rn$Rm", + "$Rn.addr = $wb", []> { + let Inst{5-4} = Rn{5-4}; +} -def VST2d8_UPD : VST2DWB<0b1000, 0b0000, "8">; -def VST2d16_UPD : VST2DWB<0b1000, 0b0100, "16">; -def VST2d32_UPD : VST2DWB<0b1000, 0b1000, "32">; +def VST2d8_UPD : VST2DWB<0b1000, {0,0,?,?}, "8">; +def VST2d16_UPD : VST2DWB<0b1000, {0,1,?,?}, "16">; +def VST2d32_UPD : VST2DWB<0b1000, {1,0,?,?}, "32">; -def VST2q8_UPD : VST2QWB<0b0000, "8">; -def VST2q16_UPD : VST2QWB<0b0100, "16">; -def VST2q32_UPD : VST2QWB<0b1000, "32">; +def VST2q8_UPD : VST2QWB<{0,0,?,?}, "8">; +def VST2q16_UPD : VST2QWB<{0,1,?,?}, "16">; +def VST2q32_UPD : VST2QWB<{1,0,?,?}, "32">; -def VST2d8Pseudo_UPD : VSTQWBPseudo; -def VST2d16Pseudo_UPD : VSTQWBPseudo; -def VST2d32Pseudo_UPD : VSTQWBPseudo; +def VST2d8Pseudo_UPD : VSTQWBPseudo; +def VST2d16Pseudo_UPD : VSTQWBPseudo; +def VST2d32Pseudo_UPD : VSTQWBPseudo; -def VST2q8Pseudo_UPD : VSTQQWBPseudo; -def VST2q16Pseudo_UPD : VSTQQWBPseudo; -def VST2q32Pseudo_UPD : VSTQQWBPseudo; +def VST2q8Pseudo_UPD : VSTQQWBPseudo; +def VST2q16Pseudo_UPD : VSTQQWBPseudo; +def VST2q32Pseudo_UPD : VSTQQWBPseudo; // ...with double-spaced registers (for disassembly only): -def VST2b8 : VST2D<0b1001, 0b0000, "8">; -def VST2b16 : VST2D<0b1001, 0b0100, "16">; -def VST2b32 : VST2D<0b1001, 0b1000, "32">; -def VST2b8_UPD : VST2DWB<0b1001, 0b0000, "8">; -def VST2b16_UPD : VST2DWB<0b1001, 0b0100, "16">; -def VST2b32_UPD : VST2DWB<0b1001, 0b1000, "32">; +def VST2b8 : VST2D<0b1001, {0,0,?,?}, "8">; +def VST2b16 : VST2D<0b1001, {0,1,?,?}, "16">; +def VST2b32 : VST2D<0b1001, {1,0,?,?}, "32">; +def VST2b8_UPD : VST2DWB<0b1001, {0,0,?,?}, "8">; +def VST2b16_UPD : VST2DWB<0b1001, {0,1,?,?}, "16">; +def VST2b32_UPD : VST2DWB<0b1001, {1,0,?,?}, "32">; // VST3 : Vector Store (multiple 3-element structures) class VST3D op11_8, bits<4> op7_4, string Dt> : NLdSt<0, 0b00, op11_8, op7_4, (outs), - (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3), IIC_VST, - "vst3", Dt, "\\{$src1, $src2, $src3\\}, $addr", "", []>; + (ins addrmode6:$Rn, DPR:$Vd, DPR:$src2, DPR:$src3), IIC_VST3, + "vst3", Dt, "\\{$Vd, $src2, $src3\\}, $Rn", "", []> { + let Rm = 0b1111; + let Inst{4} = Rn{4}; +} -def VST3d8 : VST3D<0b0100, 0b0000, "8">; -def VST3d16 : VST3D<0b0100, 0b0100, "16">; -def VST3d32 : VST3D<0b0100, 0b1000, "32">; +def VST3d8 : VST3D<0b0100, {0,0,0,?}, "8">; +def VST3d16 : VST3D<0b0100, {0,1,0,?}, "16">; +def VST3d32 : VST3D<0b0100, {1,0,0,?}, "32">; -def VST3d8Pseudo : VSTQQPseudo; -def VST3d16Pseudo : VSTQQPseudo; -def VST3d32Pseudo : VSTQQPseudo; +def VST3d8Pseudo : VSTQQPseudo; +def VST3d16Pseudo : VSTQQPseudo; +def VST3d32Pseudo : VSTQQPseudo; // ...with address register writeback: class VST3DWB op11_8, bits<4> op7_4, string Dt> : NLdSt<0, 0b00, op11_8, op7_4, (outs GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset, - DPR:$src1, DPR:$src2, DPR:$src3), IIC_VST, - "vst3", Dt, "\\{$src1, $src2, $src3\\}, $addr$offset", - "$addr.addr = $wb", []>; - -def VST3d8_UPD : VST3DWB<0b0100, 0b0000, "8">; -def VST3d16_UPD : VST3DWB<0b0100, 0b0100, "16">; -def VST3d32_UPD : VST3DWB<0b0100, 0b1000, "32">; - -def VST3d8Pseudo_UPD : VSTQQWBPseudo; -def VST3d16Pseudo_UPD : VSTQQWBPseudo; -def VST3d32Pseudo_UPD : VSTQQWBPseudo; - -// ...with double-spaced registers (non-updating versions for disassembly only): -def VST3q8 : VST3D<0b0101, 0b0000, "8">; -def VST3q16 : VST3D<0b0101, 0b0100, "16">; -def VST3q32 : VST3D<0b0101, 0b1000, "32">; -def VST3q8_UPD : VST3DWB<0b0101, 0b0000, "8">; -def VST3q16_UPD : VST3DWB<0b0101, 0b0100, "16">; -def VST3q32_UPD : VST3DWB<0b0101, 0b1000, "32">; - -def VST3q8Pseudo_UPD : VSTQQQQWBPseudo; -def VST3q16Pseudo_UPD : VSTQQQQWBPseudo; -def VST3q32Pseudo_UPD : VSTQQQQWBPseudo; + (ins addrmode6:$Rn, am6offset:$Rm, + DPR:$Vd, DPR:$src2, DPR:$src3), IIC_VST3u, + "vst3", Dt, "\\{$Vd, $src2, $src3\\}, $Rn$Rm", + "$Rn.addr = $wb", []> { + let Inst{4} = Rn{4}; +} + +def VST3d8_UPD : VST3DWB<0b0100, {0,0,0,?}, "8">; +def VST3d16_UPD : VST3DWB<0b0100, {0,1,0,?}, "16">; +def VST3d32_UPD : VST3DWB<0b0100, {1,0,0,?}, "32">; + +def VST3d8Pseudo_UPD : VSTQQWBPseudo; +def VST3d16Pseudo_UPD : VSTQQWBPseudo; +def VST3d32Pseudo_UPD : VSTQQWBPseudo; + +// ...with double-spaced registers: +def VST3q8 : VST3D<0b0101, {0,0,0,?}, "8">; +def VST3q16 : VST3D<0b0101, {0,1,0,?}, "16">; +def VST3q32 : VST3D<0b0101, {1,0,0,?}, "32">; +def VST3q8_UPD : VST3DWB<0b0101, {0,0,0,?}, "8">; +def VST3q16_UPD : VST3DWB<0b0101, {0,1,0,?}, "16">; +def VST3q32_UPD : VST3DWB<0b0101, {1,0,0,?}, "32">; + +def VST3q8Pseudo_UPD : VSTQQQQWBPseudo; +def VST3q16Pseudo_UPD : VSTQQQQWBPseudo; +def VST3q32Pseudo_UPD : VSTQQQQWBPseudo; // ...alternate versions to be allocated odd register numbers: -def VST3q8oddPseudo_UPD : VSTQQQQWBPseudo; -def VST3q16oddPseudo_UPD : VSTQQQQWBPseudo; -def VST3q32oddPseudo_UPD : VSTQQQQWBPseudo; +def VST3q8oddPseudo : VSTQQQQPseudo; +def VST3q16oddPseudo : VSTQQQQPseudo; +def VST3q32oddPseudo : VSTQQQQPseudo; + +def VST3q8oddPseudo_UPD : VSTQQQQWBPseudo; +def VST3q16oddPseudo_UPD : VSTQQQQWBPseudo; +def VST3q32oddPseudo_UPD : VSTQQQQWBPseudo; // VST4 : Vector Store (multiple 4-element structures) class VST4D op11_8, bits<4> op7_4, string Dt> : NLdSt<0, 0b00, op11_8, op7_4, (outs), - (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3, DPR:$src4), - IIC_VST, "vst4", Dt, "\\{$src1, $src2, $src3, $src4\\}, $addr", - "", []>; + (ins addrmode6:$Rn, DPR:$Vd, DPR:$src2, DPR:$src3, DPR:$src4), + IIC_VST4, "vst4", Dt, "\\{$Vd, $src2, $src3, $src4\\}, $Rn", + "", []> { + let Rm = 0b1111; + let Inst{5-4} = Rn{5-4}; +} -def VST4d8 : VST4D<0b0000, 0b0000, "8">; -def VST4d16 : VST4D<0b0000, 0b0100, "16">; -def VST4d32 : VST4D<0b0000, 0b1000, "32">; +def VST4d8 : VST4D<0b0000, {0,0,?,?}, "8">; +def VST4d16 : VST4D<0b0000, {0,1,?,?}, "16">; +def VST4d32 : VST4D<0b0000, {1,0,?,?}, "32">; -def VST4d8Pseudo : VSTQQPseudo; -def VST4d16Pseudo : VSTQQPseudo; -def VST4d32Pseudo : VSTQQPseudo; +def VST4d8Pseudo : VSTQQPseudo; +def VST4d16Pseudo : VSTQQPseudo; +def VST4d32Pseudo : VSTQQPseudo; // ...with address register writeback: class VST4DWB op11_8, bits<4> op7_4, string Dt> : NLdSt<0, 0b00, op11_8, op7_4, (outs GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset, - DPR:$src1, DPR:$src2, DPR:$src3, DPR:$src4), IIC_VST, - "vst4", Dt, "\\{$src1, $src2, $src3, $src4\\}, $addr$offset", - "$addr.addr = $wb", []>; - -def VST4d8_UPD : VST4DWB<0b0000, 0b0000, "8">; -def VST4d16_UPD : VST4DWB<0b0000, 0b0100, "16">; -def VST4d32_UPD : VST4DWB<0b0000, 0b1000, "32">; - -def VST4d8Pseudo_UPD : VSTQQWBPseudo; -def VST4d16Pseudo_UPD : VSTQQWBPseudo; -def VST4d32Pseudo_UPD : VSTQQWBPseudo; - -// ...with double-spaced registers (non-updating versions for disassembly only): -def VST4q8 : VST4D<0b0001, 0b0000, "8">; -def VST4q16 : VST4D<0b0001, 0b0100, "16">; -def VST4q32 : VST4D<0b0001, 0b1000, "32">; -def VST4q8_UPD : VST4DWB<0b0001, 0b0000, "8">; -def VST4q16_UPD : VST4DWB<0b0001, 0b0100, "16">; -def VST4q32_UPD : VST4DWB<0b0001, 0b1000, "32">; - -def VST4q8Pseudo_UPD : VSTQQQQWBPseudo; -def VST4q16Pseudo_UPD : VSTQQQQWBPseudo; -def VST4q32Pseudo_UPD : VSTQQQQWBPseudo; + (ins addrmode6:$Rn, am6offset:$Rm, + DPR:$Vd, DPR:$src2, DPR:$src3, DPR:$src4), IIC_VST4u, + "vst4", Dt, "\\{$Vd, $src2, $src3, $src4\\}, $Rn$Rm", + "$Rn.addr = $wb", []> { + let Inst{5-4} = Rn{5-4}; +} + +def VST4d8_UPD : VST4DWB<0b0000, {0,0,?,?}, "8">; +def VST4d16_UPD : VST4DWB<0b0000, {0,1,?,?}, "16">; +def VST4d32_UPD : VST4DWB<0b0000, {1,0,?,?}, "32">; + +def VST4d8Pseudo_UPD : VSTQQWBPseudo; +def VST4d16Pseudo_UPD : VSTQQWBPseudo; +def VST4d32Pseudo_UPD : VSTQQWBPseudo; + +// ...with double-spaced registers: +def VST4q8 : VST4D<0b0001, {0,0,?,?}, "8">; +def VST4q16 : VST4D<0b0001, {0,1,?,?}, "16">; +def VST4q32 : VST4D<0b0001, {1,0,?,?}, "32">; +def VST4q8_UPD : VST4DWB<0b0001, {0,0,?,?}, "8">; +def VST4q16_UPD : VST4DWB<0b0001, {0,1,?,?}, "16">; +def VST4q32_UPD : VST4DWB<0b0001, {1,0,?,?}, "32">; + +def VST4q8Pseudo_UPD : VSTQQQQWBPseudo; +def VST4q16Pseudo_UPD : VSTQQQQWBPseudo; +def VST4q32Pseudo_UPD : VSTQQQQWBPseudo; // ...alternate versions to be allocated odd register numbers: -def VST4q8oddPseudo_UPD : VSTQQQQWBPseudo; -def VST4q16oddPseudo_UPD : VSTQQQQWBPseudo; -def VST4q32oddPseudo_UPD : VSTQQQQWBPseudo; +def VST4q8oddPseudo : VSTQQQQPseudo; +def VST4q16oddPseudo : VSTQQQQPseudo; +def VST4q32oddPseudo : VSTQQQQPseudo; + +def VST4q8oddPseudo_UPD : VSTQQQQWBPseudo; +def VST4q16oddPseudo_UPD : VSTQQQQWBPseudo; +def VST4q32oddPseudo_UPD : VSTQQQQWBPseudo; + +} // mayStore = 1, neverHasSideEffects = 1, hasExtraSrcRegAllocReq = 1 + +// Classes for VST*LN pseudo-instructions with multi-register operands. +// These are expanded to real instructions after register allocation. +class VSTQLNPseudo + : PseudoNLdSt<(outs), (ins addrmode6:$addr, QPR:$src, nohash_imm:$lane), + itin, "">; +class VSTQLNWBPseudo + : PseudoNLdSt<(outs GPR:$wb), + (ins addrmode6:$addr, am6offset:$offset, QPR:$src, + nohash_imm:$lane), itin, "$addr.addr = $wb">; +class VSTQQLNPseudo + : PseudoNLdSt<(outs), (ins addrmode6:$addr, QQPR:$src, nohash_imm:$lane), + itin, "">; +class VSTQQLNWBPseudo + : PseudoNLdSt<(outs GPR:$wb), + (ins addrmode6:$addr, am6offset:$offset, QQPR:$src, + nohash_imm:$lane), itin, "$addr.addr = $wb">; +class VSTQQQQLNPseudo + : PseudoNLdSt<(outs), (ins addrmode6:$addr, QQQQPR:$src, nohash_imm:$lane), + itin, "">; +class VSTQQQQLNWBPseudo + : PseudoNLdSt<(outs GPR:$wb), + (ins addrmode6:$addr, am6offset:$offset, QQQQPR:$src, + nohash_imm:$lane), itin, "$addr.addr = $wb">; // VST1LN : Vector Store (single element from one lane) -// FIXME: Not yet implemented. +class VST1LN op11_8, bits<4> op7_4, string Dt, ValueType Ty, + PatFrag StoreOp, SDNode ExtractOp> + : NLdStLn<1, 0b00, op11_8, op7_4, (outs), + (ins addrmode6:$Rn, DPR:$Vd, nohash_imm:$lane), + IIC_VST1ln, "vst1", Dt, "\\{$Vd[$lane]\\}, $Rn", "", + [(StoreOp (ExtractOp (Ty DPR:$Vd), imm:$lane), addrmode6:$Rn)]> { + let Rm = 0b1111; +} +class VST1QLNPseudo + : VSTQLNPseudo { + let Pattern = [(StoreOp (ExtractOp (Ty QPR:$src), imm:$lane), + addrmode6:$addr)]; +} + +def VST1LNd8 : VST1LN<0b0000, {?,?,?,0}, "8", v8i8, truncstorei8, + NEONvgetlaneu> { + let Inst{7-5} = lane{2-0}; +} +def VST1LNd16 : VST1LN<0b0100, {?,?,0,?}, "16", v4i16, truncstorei16, + NEONvgetlaneu> { + let Inst{7-6} = lane{1-0}; + let Inst{4} = Rn{5}; +} +def VST1LNd32 : VST1LN<0b1000, {?,0,?,?}, "32", v2i32, store, extractelt> { + let Inst{7} = lane{0}; + let Inst{5-4} = Rn{5-4}; +} + +def VST1LNq8Pseudo : VST1QLNPseudo; +def VST1LNq16Pseudo : VST1QLNPseudo; +def VST1LNq32Pseudo : VST1QLNPseudo; + +def : Pat<(store (extractelt (v2f32 DPR:$src), imm:$lane), addrmode6:$addr), + (VST1LNd32 addrmode6:$addr, DPR:$src, imm:$lane)>; +def : Pat<(store (extractelt (v4f32 QPR:$src), imm:$lane), addrmode6:$addr), + (VST1LNq32Pseudo addrmode6:$addr, QPR:$src, imm:$lane)>; + +let mayStore = 1, neverHasSideEffects = 1, hasExtraSrcRegAllocReq = 1 in { + +// ...with address register writeback: +class VST1LNWB op11_8, bits<4> op7_4, string Dt> + : NLdStLn<1, 0b00, op11_8, op7_4, (outs GPR:$wb), + (ins addrmode6:$Rn, am6offset:$Rm, + DPR:$Vd, nohash_imm:$lane), IIC_VST1lnu, "vst1", Dt, + "\\{$Vd[$lane]\\}, $Rn$Rm", + "$Rn.addr = $wb", []>; + +def VST1LNd8_UPD : VST1LNWB<0b0000, {?,?,?,0}, "8"> { + let Inst{7-5} = lane{2-0}; +} +def VST1LNd16_UPD : VST1LNWB<0b0100, {?,?,0,?}, "16"> { + let Inst{7-6} = lane{1-0}; + let Inst{4} = Rn{5}; +} +def VST1LNd32_UPD : VST1LNWB<0b1000, {?,0,?,?}, "32"> { + let Inst{7} = lane{0}; + let Inst{5-4} = Rn{5-4}; +} + +def VST1LNq8Pseudo_UPD : VSTQLNWBPseudo; +def VST1LNq16Pseudo_UPD : VSTQLNWBPseudo; +def VST1LNq32Pseudo_UPD : VSTQLNWBPseudo; // VST2LN : Vector Store (single 2-element structure from one lane) class VST2LN op11_8, bits<4> op7_4, string Dt> - : NLdSt<1, 0b00, op11_8, op7_4, (outs), - (ins addrmode6:$addr, DPR:$src1, DPR:$src2, nohash_imm:$lane), - IIC_VST, "vst2", Dt, "\\{$src1[$lane], $src2[$lane]\\}, $addr", - "", []>; + : NLdStLn<1, 0b00, op11_8, op7_4, (outs), + (ins addrmode6:$Rn, DPR:$Vd, DPR:$src2, nohash_imm:$lane), + IIC_VST2ln, "vst2", Dt, "\\{$Vd[$lane], $src2[$lane]\\}, $Rn", + "", []> { + let Rm = 0b1111; + let Inst{4} = Rn{4}; +} + +def VST2LNd8 : VST2LN<0b0001, {?,?,?,?}, "8"> { + let Inst{7-5} = lane{2-0}; +} +def VST2LNd16 : VST2LN<0b0101, {?,?,0,?}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VST2LNd32 : VST2LN<0b1001, {?,0,0,?}, "32"> { + let Inst{7} = lane{0}; +} -def VST2LNd8 : VST2LN<0b0001, {?,?,?,?}, "8">; -def VST2LNd16 : VST2LN<0b0101, {?,?,0,?}, "16">; -def VST2LNd32 : VST2LN<0b1001, {?,0,?,?}, "32">; +def VST2LNd8Pseudo : VSTQLNPseudo; +def VST2LNd16Pseudo : VSTQLNPseudo; +def VST2LNd32Pseudo : VSTQLNPseudo; // ...with double-spaced registers: -def VST2LNq16 : VST2LN<0b0101, {?,?,1,?}, "16">; -def VST2LNq32 : VST2LN<0b1001, {?,1,?,?}, "32">; +def VST2LNq16 : VST2LN<0b0101, {?,?,1,?}, "16"> { + let Inst{7-6} = lane{1-0}; + let Inst{4} = Rn{4}; +} +def VST2LNq32 : VST2LN<0b1001, {?,1,0,?}, "32"> { + let Inst{7} = lane{0}; + let Inst{4} = Rn{4}; +} -// ...alternate versions to be allocated odd register numbers: -def VST2LNq16odd : VST2LN<0b0101, {?,?,1,?}, "16">; -def VST2LNq32odd : VST2LN<0b1001, {?,1,?,?}, "32">; +def VST2LNq16Pseudo : VSTQQLNPseudo; +def VST2LNq32Pseudo : VSTQQLNPseudo; // ...with address register writeback: class VST2LNWB op11_8, bits<4> op7_4, string Dt> - : NLdSt<1, 0b00, op11_8, op7_4, (outs GPR:$wb), + : NLdStLn<1, 0b00, op11_8, op7_4, (outs GPR:$wb), (ins addrmode6:$addr, am6offset:$offset, - DPR:$src1, DPR:$src2, nohash_imm:$lane), IIC_VST, "vst2", Dt, + DPR:$src1, DPR:$src2, nohash_imm:$lane), IIC_VST2lnu, "vst2", Dt, "\\{$src1[$lane], $src2[$lane]\\}, $addr$offset", - "$addr.addr = $wb", []>; + "$addr.addr = $wb", []> { + let Inst{4} = Rn{4}; +} + +def VST2LNd8_UPD : VST2LNWB<0b0001, {?,?,?,?}, "8"> { + let Inst{7-5} = lane{2-0}; +} +def VST2LNd16_UPD : VST2LNWB<0b0101, {?,?,0,?}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VST2LNd32_UPD : VST2LNWB<0b1001, {?,0,0,?}, "32"> { + let Inst{7} = lane{0}; +} + +def VST2LNd8Pseudo_UPD : VSTQLNWBPseudo; +def VST2LNd16Pseudo_UPD : VSTQLNWBPseudo; +def VST2LNd32Pseudo_UPD : VSTQLNWBPseudo; -def VST2LNd8_UPD : VST2LNWB<0b0001, {?,?,?,?}, "8">; -def VST2LNd16_UPD : VST2LNWB<0b0101, {?,?,0,?}, "16">; -def VST2LNd32_UPD : VST2LNWB<0b1001, {?,0,?,?}, "32">; +def VST2LNq16_UPD : VST2LNWB<0b0101, {?,?,1,?}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VST2LNq32_UPD : VST2LNWB<0b1001, {?,1,0,?}, "32"> { + let Inst{7} = lane{0}; +} -def VST2LNq16_UPD : VST2LNWB<0b0101, {?,?,1,?}, "16">; -def VST2LNq32_UPD : VST2LNWB<0b1001, {?,1,?,?}, "32">; +def VST2LNq16Pseudo_UPD : VSTQQLNWBPseudo; +def VST2LNq32Pseudo_UPD : VSTQQLNWBPseudo; // VST3LN : Vector Store (single 3-element structure from one lane) class VST3LN op11_8, bits<4> op7_4, string Dt> - : NLdSt<1, 0b00, op11_8, op7_4, (outs), - (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3, - nohash_imm:$lane), IIC_VST, "vst3", Dt, - "\\{$src1[$lane], $src2[$lane], $src3[$lane]\\}, $addr", "", []>; + : NLdStLn<1, 0b00, op11_8, op7_4, (outs), + (ins addrmode6:$Rn, DPR:$Vd, DPR:$src2, DPR:$src3, + nohash_imm:$lane), IIC_VST3ln, "vst3", Dt, + "\\{$Vd[$lane], $src2[$lane], $src3[$lane]\\}, $Rn", "", []> { + let Rm = 0b1111; +} -def VST3LNd8 : VST3LN<0b0010, {?,?,?,0}, "8">; -def VST3LNd16 : VST3LN<0b0110, {?,?,0,0}, "16">; -def VST3LNd32 : VST3LN<0b1010, {?,0,0,0}, "32">; +def VST3LNd8 : VST3LN<0b0010, {?,?,?,0}, "8"> { + let Inst{7-5} = lane{2-0}; +} +def VST3LNd16 : VST3LN<0b0110, {?,?,0,0}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VST3LNd32 : VST3LN<0b1010, {?,0,0,0}, "32"> { + let Inst{7} = lane{0}; +} + +def VST3LNd8Pseudo : VSTQQLNPseudo; +def VST3LNd16Pseudo : VSTQQLNPseudo; +def VST3LNd32Pseudo : VSTQQLNPseudo; // ...with double-spaced registers: -def VST3LNq16 : VST3LN<0b0110, {?,?,1,0}, "16">; -def VST3LNq32 : VST3LN<0b1010, {?,1,0,0}, "32">; +def VST3LNq16 : VST3LN<0b0110, {?,?,1,0}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VST3LNq32 : VST3LN<0b1010, {?,1,0,0}, "32"> { + let Inst{7} = lane{0}; +} -// ...alternate versions to be allocated odd register numbers: -def VST3LNq16odd : VST3LN<0b0110, {?,?,1,0}, "16">; -def VST3LNq32odd : VST3LN<0b1010, {?,1,0,0}, "32">; +def VST3LNq16Pseudo : VSTQQQQLNPseudo; +def VST3LNq32Pseudo : VSTQQQQLNPseudo; // ...with address register writeback: class VST3LNWB op11_8, bits<4> op7_4, string Dt> - : NLdSt<1, 0b00, op11_8, op7_4, (outs GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset, - DPR:$src1, DPR:$src2, DPR:$src3, nohash_imm:$lane), - IIC_VST, "vst3", Dt, - "\\{$src1[$lane], $src2[$lane], $src3[$lane]\\}, $addr$offset", - "$addr.addr = $wb", []>; + : NLdStLn<1, 0b00, op11_8, op7_4, (outs GPR:$wb), + (ins addrmode6:$Rn, am6offset:$Rm, + DPR:$Vd, DPR:$src2, DPR:$src3, nohash_imm:$lane), + IIC_VST3lnu, "vst3", Dt, + "\\{$Vd[$lane], $src2[$lane], $src3[$lane]\\}, $Rn$Rm", + "$Rn.addr = $wb", []>; + +def VST3LNd8_UPD : VST3LNWB<0b0010, {?,?,?,0}, "8"> { + let Inst{7-5} = lane{2-0}; +} +def VST3LNd16_UPD : VST3LNWB<0b0110, {?,?,0,0}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VST3LNd32_UPD : VST3LNWB<0b1010, {?,0,0,0}, "32"> { + let Inst{7} = lane{0}; +} + +def VST3LNd8Pseudo_UPD : VSTQQLNWBPseudo; +def VST3LNd16Pseudo_UPD : VSTQQLNWBPseudo; +def VST3LNd32Pseudo_UPD : VSTQQLNWBPseudo; -def VST3LNd8_UPD : VST3LNWB<0b0010, {?,?,?,0}, "8">; -def VST3LNd16_UPD : VST3LNWB<0b0110, {?,?,0,0}, "16">; -def VST3LNd32_UPD : VST3LNWB<0b1010, {?,0,0,0}, "32">; +def VST3LNq16_UPD : VST3LNWB<0b0110, {?,?,1,0}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VST3LNq32_UPD : VST3LNWB<0b1010, {?,1,0,0}, "32"> { + let Inst{7} = lane{0}; +} -def VST3LNq16_UPD : VST3LNWB<0b0110, {?,?,1,0}, "16">; -def VST3LNq32_UPD : VST3LNWB<0b1010, {?,1,0,0}, "32">; +def VST3LNq16Pseudo_UPD : VSTQQQQLNWBPseudo; +def VST3LNq32Pseudo_UPD : VSTQQQQLNWBPseudo; // VST4LN : Vector Store (single 4-element structure from one lane) class VST4LN op11_8, bits<4> op7_4, string Dt> - : NLdSt<1, 0b00, op11_8, op7_4, (outs), - (ins addrmode6:$addr, DPR:$src1, DPR:$src2, DPR:$src3, DPR:$src4, - nohash_imm:$lane), IIC_VST, "vst4", Dt, - "\\{$src1[$lane], $src2[$lane], $src3[$lane], $src4[$lane]\\}, $addr", - "", []>; + : NLdStLn<1, 0b00, op11_8, op7_4, (outs), + (ins addrmode6:$Rn, DPR:$Vd, DPR:$src2, DPR:$src3, DPR:$src4, + nohash_imm:$lane), IIC_VST4ln, "vst4", Dt, + "\\{$Vd[$lane], $src2[$lane], $src3[$lane], $src4[$lane]\\}, $Rn", + "", []> { + let Rm = 0b1111; + let Inst{4} = Rn{4}; +} + +def VST4LNd8 : VST4LN<0b0011, {?,?,?,?}, "8"> { + let Inst{7-5} = lane{2-0}; +} +def VST4LNd16 : VST4LN<0b0111, {?,?,0,?}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VST4LNd32 : VST4LN<0b1011, {?,0,?,?}, "32"> { + let Inst{7} = lane{0}; + let Inst{5} = Rn{5}; +} -def VST4LNd8 : VST4LN<0b0011, {?,?,?,?}, "8">; -def VST4LNd16 : VST4LN<0b0111, {?,?,0,?}, "16">; -def VST4LNd32 : VST4LN<0b1011, {?,0,?,?}, "32">; +def VST4LNd8Pseudo : VSTQQLNPseudo; +def VST4LNd16Pseudo : VSTQQLNPseudo; +def VST4LNd32Pseudo : VSTQQLNPseudo; // ...with double-spaced registers: -def VST4LNq16 : VST4LN<0b0111, {?,?,1,?}, "16">; -def VST4LNq32 : VST4LN<0b1011, {?,1,?,?}, "32">; +def VST4LNq16 : VST4LN<0b0111, {?,?,1,?}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VST4LNq32 : VST4LN<0b1011, {?,1,?,?}, "32"> { + let Inst{7} = lane{0}; + let Inst{5} = Rn{5}; +} -// ...alternate versions to be allocated odd register numbers: -def VST4LNq16odd : VST4LN<0b0111, {?,?,1,?}, "16">; -def VST4LNq32odd : VST4LN<0b1011, {?,1,?,?}, "32">; +def VST4LNq16Pseudo : VSTQQQQLNPseudo; +def VST4LNq32Pseudo : VSTQQQQLNPseudo; // ...with address register writeback: class VST4LNWB op11_8, bits<4> op7_4, string Dt> - : NLdSt<1, 0b00, op11_8, op7_4, (outs GPR:$wb), - (ins addrmode6:$addr, am6offset:$offset, - DPR:$src1, DPR:$src2, DPR:$src3, DPR:$src4, nohash_imm:$lane), - IIC_VST, "vst4", Dt, - "\\{$src1[$lane], $src2[$lane], $src3[$lane], $src4[$lane]\\}, $addr$offset", - "$addr.addr = $wb", []>; + : NLdStLn<1, 0b00, op11_8, op7_4, (outs GPR:$wb), + (ins addrmode6:$Rn, am6offset:$Rm, + DPR:$Vd, DPR:$src2, DPR:$src3, DPR:$src4, nohash_imm:$lane), + IIC_VST4lnu, "vst4", Dt, + "\\{$Vd[$lane], $src2[$lane], $src3[$lane], $src4[$lane]\\}, $Rn$Rm", + "$Rn.addr = $wb", []> { + let Inst{4} = Rn{4}; +} -def VST4LNd8_UPD : VST4LNWB<0b0011, {?,?,?,?}, "8">; -def VST4LNd16_UPD : VST4LNWB<0b0111, {?,?,0,?}, "16">; -def VST4LNd32_UPD : VST4LNWB<0b1011, {?,0,?,?}, "32">; +def VST4LNd8_UPD : VST4LNWB<0b0011, {?,?,?,?}, "8"> { + let Inst{7-5} = lane{2-0}; +} +def VST4LNd16_UPD : VST4LNWB<0b0111, {?,?,0,?}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VST4LNd32_UPD : VST4LNWB<0b1011, {?,0,?,?}, "32"> { + let Inst{7} = lane{0}; + let Inst{5} = Rn{5}; +} + +def VST4LNd8Pseudo_UPD : VSTQQLNWBPseudo; +def VST4LNd16Pseudo_UPD : VSTQQLNWBPseudo; +def VST4LNd32Pseudo_UPD : VSTQQLNWBPseudo; + +def VST4LNq16_UPD : VST4LNWB<0b0111, {?,?,1,?}, "16"> { + let Inst{7-6} = lane{1-0}; +} +def VST4LNq32_UPD : VST4LNWB<0b1011, {?,1,?,?}, "32"> { + let Inst{7} = lane{0}; + let Inst{5} = Rn{5}; +} -def VST4LNq16_UPD : VST4LNWB<0b0111, {?,?,1,?}, "16">; -def VST4LNq32_UPD : VST4LNWB<0b1011, {?,1,?,?}, "32">; +def VST4LNq16Pseudo_UPD : VSTQQQQLNWBPseudo; +def VST4LNq32Pseudo_UPD : VSTQQQQLNWBPseudo; } // mayStore = 1, neverHasSideEffects = 1, hasExtraSrcRegAllocReq = 1 @@ -1000,98 +1687,92 @@ def SubReg_i32_lane : SDNodeXForm op24_23, bits<2> op21_20, bits<2> op19_18, - bits<2> op17_16, bits<5> op11_7, bit op4, string OpcodeStr, - string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode> - : N2V; +// Basic 2-register operations: double- and quad-register. class N2VD op24_23, bits<2> op21_20, bits<2> op19_18, bits<2> op17_16, bits<5> op11_7, bit op4, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode> - : N2V; + : N2V; class N2VQ op24_23, bits<2> op21_20, bits<2> op19_18, bits<2> op17_16, bits<5> op11_7, bit op4, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode> - : N2V; + : N2V; // Basic 2-register intrinsics, both double- and quad-register. class N2VDInt op24_23, bits<2> op21_20, bits<2> op19_18, bits<2> op17_16, bits<5> op11_7, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> - : N2V; + : N2V; class N2VQInt op24_23, bits<2> op21_20, bits<2> op19_18, bits<2> op17_16, bits<5> op11_7, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> - : N2V; + : N2V; // Narrow 2-register operations. class N2VN op24_23, bits<2> op21_20, bits<2> op19_18, bits<2> op17_16, bits<5> op11_7, bit op6, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, ValueType TyD, ValueType TyQ, SDNode OpNode> - : N2V; + : N2V; // Narrow 2-register intrinsics. class N2VNInt op24_23, bits<2> op21_20, bits<2> op19_18, bits<2> op17_16, bits<5> op11_7, bit op6, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, ValueType TyD, ValueType TyQ, Intrinsic IntOp> - : N2V; + : N2V; // Long 2-register operations (currently only used for VMOVL). class N2VL op24_23, bits<2> op21_20, bits<2> op19_18, bits<2> op17_16, bits<5> op11_7, bit op6, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, ValueType TyQ, ValueType TyD, SDNode OpNode> - : N2V; + : N2V; + +// Long 2-register intrinsics. +class N2VLInt op24_23, bits<2> op21_20, bits<2> op19_18, + bits<2> op17_16, bits<5> op11_7, bit op6, bit op4, + InstrItinClass itin, string OpcodeStr, string Dt, + ValueType TyQ, ValueType TyD, Intrinsic IntOp> + : N2V; // 2-register shuffles (VTRN/VZIP/VUZP), both double- and quad-register. class N2VDShuffle op19_18, bits<5> op11_7, string OpcodeStr, string Dt> - : N2V<0b11, 0b11, op19_18, 0b10, op11_7, 0, 0, (outs DPR:$dst1, DPR:$dst2), - (ins DPR:$src1, DPR:$src2), IIC_VPERMD, - OpcodeStr, Dt, "$dst1, $dst2", - "$src1 = $dst1, $src2 = $dst2", []>; + : N2V<0b11, 0b11, op19_18, 0b10, op11_7, 0, 0, (outs DPR:$Vd, DPR:$Vm), + (ins DPR:$src1, DPR:$src2), IIC_VPERMD, + OpcodeStr, Dt, "$Vd, $Vm", + "$src1 = $Vd, $src2 = $Vm", []>; class N2VQShuffle op19_18, bits<5> op11_7, InstrItinClass itin, string OpcodeStr, string Dt> - : N2V<0b11, 0b11, op19_18, 0b10, op11_7, 1, 0, (outs QPR:$dst1, QPR:$dst2), - (ins QPR:$src1, QPR:$src2), itin, OpcodeStr, Dt, "$dst1, $dst2", - "$src1 = $dst1, $src2 = $dst2", []>; - -// Basic 3-register operations: single-, double- and quad-register. -class N3VS op21_20, bits<4> op11_8, bit op4, - string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, - SDNode OpNode, bit Commutable> - : N3V { - let isCommutable = Commutable; -} + : N2V<0b11, 0b11, op19_18, 0b10, op11_7, 1, 0, (outs QPR:$Vd, QPR:$Vm), + (ins QPR:$src1, QPR:$src2), itin, OpcodeStr, Dt, "$Vd, $Vm", + "$src1 = $Vd, $src2 = $Vm", []>; +// Basic 3-register operations: double- and quad-register. class N3VD op21_20, bits<4> op11_8, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode, bit Commutable> : N3V { + (outs DPR:$Vd), (ins DPR:$Vn, DPR:$Vm), N3RegFrm, itin, + OpcodeStr, Dt, "$Vd, $Vn, $Vm", "", + [(set DPR:$Vd, (ResTy (OpNode (OpTy DPR:$Vn), (OpTy DPR:$Vm))))]> { let isCommutable = Commutable; } // Same as N3VD but no data type. @@ -1100,31 +1781,31 @@ class N3VDX op21_20, bits<4> op11_8, bit op4, ValueType ResTy, ValueType OpTy, SDNode OpNode, bit Commutable> : N3VX{ + (outs DPR:$Vd), (ins DPR:$Vn, DPR:$Vm), N3RegFrm, itin, + OpcodeStr, "$Vd, $Vn, $Vm", "", + [(set DPR:$Vd, (ResTy (OpNode (OpTy DPR:$Vn), (OpTy DPR:$Vm))))]>{ let isCommutable = Commutable; } -class N3VDSL op21_20, bits<4> op11_8, +class N3VDSL op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, SDNode ShOp> : N3V<0, 1, op21_20, op11_8, 1, 0, - (outs DPR:$dst), (ins DPR:$src1, DPR_VFP2:$src2, nohash_imm:$lane), - NVMulSLFrm, itin, OpcodeStr, Dt, "$dst, $src1, $src2[$lane]", "", - [(set (Ty DPR:$dst), - (Ty (ShOp (Ty DPR:$src1), - (Ty (NEONvduplane (Ty DPR_VFP2:$src2),imm:$lane)))))]> { + (outs DPR:$Vd), (ins DPR:$Vn, DPR_VFP2:$Vm, nohash_imm:$lane), + NVMulSLFrm, itin, OpcodeStr, Dt, "$Vd, $Vn, $Vm[$lane]", "", + [(set (Ty DPR:$Vd), + (Ty (ShOp (Ty DPR:$Vn), + (Ty (NEONvduplane (Ty DPR_VFP2:$Vm),imm:$lane)))))]> { let isCommutable = 0; } -class N3VDSL16 op21_20, bits<4> op11_8, +class N3VDSL16 op21_20, bits<4> op11_8, string OpcodeStr, string Dt, ValueType Ty, SDNode ShOp> : N3V<0, 1, op21_20, op11_8, 1, 0, - (outs DPR:$dst), (ins DPR:$src1, DPR_8:$src2, nohash_imm:$lane), - NVMulSLFrm, IIC_VMULi16D, OpcodeStr, Dt,"$dst, $src1, $src2[$lane]","", - [(set (Ty DPR:$dst), - (Ty (ShOp (Ty DPR:$src1), - (Ty (NEONvduplane (Ty DPR_8:$src2), imm:$lane)))))]> { + (outs DPR:$Vd), (ins DPR:$Vn, DPR_8:$Vm, nohash_imm:$lane), + NVMulSLFrm, IIC_VMULi16D, OpcodeStr, Dt,"$Vd, $Vn, $Vm[$lane]","", + [(set (Ty DPR:$Vd), + (Ty (ShOp (Ty DPR:$Vn), + (Ty (NEONvduplane (Ty DPR_8:$Vm), imm:$lane)))))]> { let isCommutable = 0; } @@ -1132,40 +1813,40 @@ class N3VQ op21_20, bits<4> op11_8, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode, bit Commutable> : N3V { + (outs QPR:$Vd), (ins QPR:$Vn, QPR:$Vm), N3RegFrm, itin, + OpcodeStr, Dt, "$Vd, $Vn, $Vm", "", + [(set QPR:$Vd, (ResTy (OpNode (OpTy QPR:$Vn), (OpTy QPR:$Vm))))]> { let isCommutable = Commutable; } class N3VQX op21_20, bits<4> op11_8, bit op4, InstrItinClass itin, string OpcodeStr, ValueType ResTy, ValueType OpTy, SDNode OpNode, bit Commutable> : N3VX{ + (outs QPR:$Vd), (ins QPR:$Vn, QPR:$Vm), N3RegFrm, itin, + OpcodeStr, "$Vd, $Vn, $Vm", "", + [(set QPR:$Vd, (ResTy (OpNode (OpTy QPR:$Vn), (OpTy QPR:$Vm))))]>{ let isCommutable = Commutable; } -class N3VQSL op21_20, bits<4> op11_8, +class N3VQSL op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, SDNode ShOp> : N3V<1, 1, op21_20, op11_8, 1, 0, - (outs QPR:$dst), (ins QPR:$src1, DPR_VFP2:$src2, nohash_imm:$lane), - NVMulSLFrm, itin, OpcodeStr, Dt, "$dst, $src1, $src2[$lane]", "", - [(set (ResTy QPR:$dst), - (ResTy (ShOp (ResTy QPR:$src1), - (ResTy (NEONvduplane (OpTy DPR_VFP2:$src2), + (outs QPR:$Vd), (ins QPR:$Vn, DPR_VFP2:$Vm, nohash_imm:$lane), + NVMulSLFrm, itin, OpcodeStr, Dt, "$Vd, $Vn, $Vm[$lane]", "", + [(set (ResTy QPR:$Vd), + (ResTy (ShOp (ResTy QPR:$Vn), + (ResTy (NEONvduplane (OpTy DPR_VFP2:$Vm), imm:$lane)))))]> { let isCommutable = 0; } class N3VQSL16 op21_20, bits<4> op11_8, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, SDNode ShOp> : N3V<1, 1, op21_20, op11_8, 1, 0, - (outs QPR:$dst), (ins QPR:$src1, DPR_8:$src2, nohash_imm:$lane), - NVMulSLFrm, IIC_VMULi16Q, OpcodeStr, Dt,"$dst, $src1, $src2[$lane]","", - [(set (ResTy QPR:$dst), - (ResTy (ShOp (ResTy QPR:$src1), - (ResTy (NEONvduplane (OpTy DPR_8:$src2), + (outs QPR:$Vd), (ins QPR:$Vn, DPR_8:$Vm, nohash_imm:$lane), + NVMulSLFrm, IIC_VMULi16Q, OpcodeStr, Dt,"$Vd, $Vn, $Vm[$lane]","", + [(set (ResTy QPR:$Vd), + (ResTy (ShOp (ResTy QPR:$Vn), + (ResTy (NEONvduplane (OpTy DPR_8:$Vm), imm:$lane)))))]> { let isCommutable = 0; } @@ -1175,30 +1856,39 @@ class N3VDInt op21_20, bits<4> op11_8, bit op4, Format f, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp, bit Commutable> : N3V { + (outs DPR:$Vd), (ins DPR:$Vn, DPR:$Vm), f, itin, + OpcodeStr, Dt, "$Vd, $Vn, $Vm", "", + [(set DPR:$Vd, (ResTy (IntOp (OpTy DPR:$Vn), (OpTy DPR:$Vm))))]> { let isCommutable = Commutable; } -class N3VDIntSL op21_20, bits<4> op11_8, InstrItinClass itin, +class N3VDIntSL op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, Intrinsic IntOp> : N3V<0, 1, op21_20, op11_8, 1, 0, - (outs DPR:$dst), (ins DPR:$src1, DPR_VFP2:$src2, nohash_imm:$lane), - NVMulSLFrm, itin, OpcodeStr, Dt, "$dst, $src1, $src2[$lane]", "", - [(set (Ty DPR:$dst), - (Ty (IntOp (Ty DPR:$src1), - (Ty (NEONvduplane (Ty DPR_VFP2:$src2), + (outs DPR:$Vd), (ins DPR:$Vn, DPR_VFP2:$Vm, nohash_imm:$lane), + NVMulSLFrm, itin, OpcodeStr, Dt, "$Vd, $Vn, $Vm[$lane]", "", + [(set (Ty DPR:$Vd), + (Ty (IntOp (Ty DPR:$Vn), + (Ty (NEONvduplane (Ty DPR_VFP2:$Vm), imm:$lane)))))]> { let isCommutable = 0; } class N3VDIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, Intrinsic IntOp> : N3V<0, 1, op21_20, op11_8, 1, 0, - (outs DPR:$dst), (ins DPR:$src1, DPR_8:$src2, nohash_imm:$lane), - NVMulSLFrm, itin, OpcodeStr, Dt, "$dst, $src1, $src2[$lane]", "", - [(set (Ty DPR:$dst), - (Ty (IntOp (Ty DPR:$src1), - (Ty (NEONvduplane (Ty DPR_8:$src2), imm:$lane)))))]> { + (outs DPR:$Vd), (ins DPR:$Vn, DPR_8:$Vm, nohash_imm:$lane), + NVMulSLFrm, itin, OpcodeStr, Dt, "$Vd, $Vn, $Vm[$lane]", "", + [(set (Ty DPR:$Vd), + (Ty (IntOp (Ty DPR:$Vn), + (Ty (NEONvduplane (Ty DPR_8:$Vm), imm:$lane)))))]> { + let isCommutable = 0; +} +class N3VDIntSh op21_20, bits<4> op11_8, bit op4, + Format f, InstrItinClass itin, string OpcodeStr, string Dt, + ValueType ResTy, ValueType OpTy, Intrinsic IntOp> + : N3V { let isCommutable = 0; } @@ -1206,20 +1896,20 @@ class N3VQInt op21_20, bits<4> op11_8, bit op4, Format f, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp, bit Commutable> : N3V { + (outs QPR:$Vd), (ins QPR:$Vn, QPR:$Vm), f, itin, + OpcodeStr, Dt, "$Vd, $Vn, $Vm", "", + [(set QPR:$Vd, (ResTy (IntOp (OpTy QPR:$Vn), (OpTy QPR:$Vm))))]> { let isCommutable = Commutable; } -class N3VQIntSL op21_20, bits<4> op11_8, InstrItinClass itin, +class N3VQIntSL op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> : N3V<1, 1, op21_20, op11_8, 1, 0, - (outs QPR:$dst), (ins QPR:$src1, DPR_VFP2:$src2, nohash_imm:$lane), - NVMulSLFrm, itin, OpcodeStr, Dt, "$dst, $src1, $src2[$lane]", "", - [(set (ResTy QPR:$dst), - (ResTy (IntOp (ResTy QPR:$src1), - (ResTy (NEONvduplane (OpTy DPR_VFP2:$src2), + (outs QPR:$Vd), (ins QPR:$Vn, DPR_VFP2:$Vm, nohash_imm:$lane), + NVMulSLFrm, itin, OpcodeStr, Dt, "$Vd, $Vn, $Vm[$lane]", "", + [(set (ResTy QPR:$Vd), + (ResTy (IntOp (ResTy QPR:$Vn), + (ResTy (NEONvduplane (OpTy DPR_VFP2:$Vm), imm:$lane)))))]> { let isCommutable = 0; } @@ -1227,93 +1917,95 @@ class N3VQIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> : N3V<1, 1, op21_20, op11_8, 1, 0, - (outs QPR:$dst), (ins QPR:$src1, DPR_8:$src2, nohash_imm:$lane), - NVMulSLFrm, itin, OpcodeStr, Dt, "$dst, $src1, $src2[$lane]", "", - [(set (ResTy QPR:$dst), - (ResTy (IntOp (ResTy QPR:$src1), - (ResTy (NEONvduplane (OpTy DPR_8:$src2), + (outs QPR:$Vd), (ins QPR:$Vn, DPR_8:$Vm, nohash_imm:$lane), + NVMulSLFrm, itin, OpcodeStr, Dt, "$Vd, $Vn, $Vm[$lane]", "", + [(set (ResTy QPR:$Vd), + (ResTy (IntOp (ResTy QPR:$Vn), + (ResTy (NEONvduplane (OpTy DPR_8:$Vm), imm:$lane)))))]> { let isCommutable = 0; } +class N3VQIntSh op21_20, bits<4> op11_8, bit op4, + Format f, InstrItinClass itin, string OpcodeStr, string Dt, + ValueType ResTy, ValueType OpTy, Intrinsic IntOp> + : N3V { + let isCommutable = 0; +} -// Multiply-Add/Sub operations: single-, double- and quad-register. -class N3VSMulOp op21_20, bits<4> op11_8, bit op4, - InstrItinClass itin, string OpcodeStr, string Dt, - ValueType Ty, SDNode MulOp, SDNode OpNode> - : N3V; - +// Multiply-Add/Sub operations: double- and quad-register. class N3VDMulOp op21_20, bits<4> op11_8, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, - ValueType Ty, SDNode MulOp, SDNode OpNode> + ValueType Ty, SDPatternOperator MulOp, SDPatternOperator OpNode> : N3V; + (outs DPR:$Vd), (ins DPR:$src1, DPR:$Vn, DPR:$Vm), N3RegFrm, itin, + OpcodeStr, Dt, "$Vd, $Vn, $Vm", "$src1 = $Vd", + [(set DPR:$Vd, (Ty (OpNode DPR:$src1, + (Ty (MulOp DPR:$Vn, DPR:$Vm)))))]>; + class N3VDMulOpSL op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, - ValueType Ty, SDNode MulOp, SDNode ShOp> + ValueType Ty, SDPatternOperator MulOp, SDPatternOperator ShOp> : N3V<0, 1, op21_20, op11_8, 1, 0, - (outs DPR:$dst), - (ins DPR:$src1, DPR:$src2, DPR_VFP2:$src3, nohash_imm:$lane), + (outs DPR:$Vd), + (ins DPR:$src1, DPR:$Vn, DPR_VFP2:$Vm, nohash_imm:$lane), NVMulSLFrm, itin, - OpcodeStr, Dt, "$dst, $src2, $src3[$lane]", "$src1 = $dst", - [(set (Ty DPR:$dst), + OpcodeStr, Dt, "$Vd, $Vn, $Vm[$lane]", "$src1 = $Vd", + [(set (Ty DPR:$Vd), (Ty (ShOp (Ty DPR:$src1), - (Ty (MulOp DPR:$src2, - (Ty (NEONvduplane (Ty DPR_VFP2:$src3), + (Ty (MulOp DPR:$Vn, + (Ty (NEONvduplane (Ty DPR_VFP2:$Vm), imm:$lane)))))))]>; class N3VDMulOpSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, SDNode MulOp, SDNode ShOp> : N3V<0, 1, op21_20, op11_8, 1, 0, - (outs DPR:$dst), - (ins DPR:$src1, DPR:$src2, DPR_8:$src3, nohash_imm:$lane), + (outs DPR:$Vd), + (ins DPR:$src1, DPR:$Vn, DPR_8:$Vm, nohash_imm:$lane), NVMulSLFrm, itin, - OpcodeStr, Dt, "$dst, $src2, $src3[$lane]", "$src1 = $dst", - [(set (Ty DPR:$dst), + OpcodeStr, Dt, "$Vd, $Vn, $Vm[$lane]", "$src1 = $Vd", + [(set (Ty DPR:$Vd), (Ty (ShOp (Ty DPR:$src1), - (Ty (MulOp DPR:$src2, - (Ty (NEONvduplane (Ty DPR_8:$src3), + (Ty (MulOp DPR:$Vn, + (Ty (NEONvduplane (Ty DPR_8:$Vm), imm:$lane)))))))]>; class N3VQMulOp op21_20, bits<4> op11_8, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, - SDNode MulOp, SDNode OpNode> + SDPatternOperator MulOp, SDPatternOperator OpNode> : N3V; + (outs QPR:$Vd), (ins QPR:$src1, QPR:$Vn, QPR:$Vm), N3RegFrm, itin, + OpcodeStr, Dt, "$Vd, $Vn, $Vm", "$src1 = $Vd", + [(set QPR:$Vd, (Ty (OpNode QPR:$src1, + (Ty (MulOp QPR:$Vn, QPR:$Vm)))))]>; class N3VQMulOpSL op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, - SDNode MulOp, SDNode ShOp> + SDPatternOperator MulOp, SDPatternOperator ShOp> : N3V<1, 1, op21_20, op11_8, 1, 0, - (outs QPR:$dst), - (ins QPR:$src1, QPR:$src2, DPR_VFP2:$src3, nohash_imm:$lane), + (outs QPR:$Vd), + (ins QPR:$src1, QPR:$Vn, DPR_VFP2:$Vm, nohash_imm:$lane), NVMulSLFrm, itin, - OpcodeStr, Dt, "$dst, $src2, $src3[$lane]", "$src1 = $dst", - [(set (ResTy QPR:$dst), + OpcodeStr, Dt, "$Vd, $Vn, $Vm[$lane]", "$src1 = $Vd", + [(set (ResTy QPR:$Vd), (ResTy (ShOp (ResTy QPR:$src1), - (ResTy (MulOp QPR:$src2, - (ResTy (NEONvduplane (OpTy DPR_VFP2:$src3), + (ResTy (MulOp QPR:$Vn, + (ResTy (NEONvduplane (OpTy DPR_VFP2:$Vm), imm:$lane)))))))]>; class N3VQMulOpSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, SDNode MulOp, SDNode ShOp> : N3V<1, 1, op21_20, op11_8, 1, 0, - (outs QPR:$dst), - (ins QPR:$src1, QPR:$src2, DPR_8:$src3, nohash_imm:$lane), + (outs QPR:$Vd), + (ins QPR:$src1, QPR:$Vn, DPR_8:$Vm, nohash_imm:$lane), NVMulSLFrm, itin, - OpcodeStr, Dt, "$dst, $src2, $src3[$lane]", "$src1 = $dst", - [(set (ResTy QPR:$dst), + OpcodeStr, Dt, "$Vd, $Vn, $Vm[$lane]", "$src1 = $Vd", + [(set (ResTy QPR:$Vd), (ResTy (ShOp (ResTy QPR:$src1), - (ResTy (MulOp QPR:$src2, - (ResTy (NEONvduplane (OpTy DPR_8:$src3), + (ResTy (MulOp QPR:$Vn, + (ResTy (NEONvduplane (OpTy DPR_8:$Vm), imm:$lane)))))))]>; // Neon Intrinsic-Op instructions (VABA): double- and quad-register. @@ -1321,18 +2013,18 @@ class N3VDIntOp op21_20, bits<4> op11_8, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, Intrinsic IntOp, SDNode OpNode> : N3V; + (outs DPR:$Vd), (ins DPR:$src1, DPR:$Vn, DPR:$Vm), N3RegFrm, itin, + OpcodeStr, Dt, "$Vd, $Vn, $Vm", "$src1 = $Vd", + [(set DPR:$Vd, (Ty (OpNode DPR:$src1, + (Ty (IntOp (Ty DPR:$Vn), (Ty DPR:$Vm))))))]>; class N3VQIntOp op21_20, bits<4> op11_8, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, Intrinsic IntOp, SDNode OpNode> : N3V; + (outs QPR:$Vd), (ins QPR:$src1, QPR:$Vn, QPR:$Vm), N3RegFrm, itin, + OpcodeStr, Dt, "$Vd, $Vn, $Vm", "$src1 = $Vd", + [(set QPR:$Vd, (Ty (OpNode QPR:$src1, + (Ty (IntOp (Ty QPR:$Vn), (Ty QPR:$Vm))))))]>; // Neon 3-argument intrinsics, both double- and quad-register. // The destination register is also used as the first source operand register. @@ -1340,52 +2032,52 @@ class N3VDInt3 op21_20, bits<4> op11_8, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> : N3V; + (outs DPR:$Vd), (ins DPR:$src1, DPR:$Vn, DPR:$Vm), N3RegFrm, itin, + OpcodeStr, Dt, "$Vd, $Vn, $Vm", "$src1 = $Vd", + [(set DPR:$Vd, (ResTy (IntOp (OpTy DPR:$src1), + (OpTy DPR:$Vn), (OpTy DPR:$Vm))))]>; class N3VQInt3 op21_20, bits<4> op11_8, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> : N3V; + (outs QPR:$Vd), (ins QPR:$src1, QPR:$Vn, QPR:$Vm), N3RegFrm, itin, + OpcodeStr, Dt, "$Vd, $Vn, $Vm", "$src1 = $Vd", + [(set QPR:$Vd, (ResTy (IntOp (OpTy QPR:$src1), + (OpTy QPR:$Vn), (OpTy QPR:$Vm))))]>; // Long Multiply-Add/Sub operations. class N3VLMulOp op21_20, bits<4> op11_8, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, ValueType TyQ, ValueType TyD, SDNode MulOp, SDNode OpNode> : N3V; + (outs QPR:$Vd), (ins QPR:$src1, DPR:$Vn, DPR:$Vm), N3RegFrm, itin, + OpcodeStr, Dt, "$Vd, $Vn, $Vm", "$src1 = $Vd", + [(set QPR:$Vd, (OpNode (TyQ QPR:$src1), + (TyQ (MulOp (TyD DPR:$Vn), + (TyD DPR:$Vm)))))]>; class N3VLMulOpSL op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType TyQ, ValueType TyD, SDNode MulOp, SDNode OpNode> - : N3V; class N3VLMulOpSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType TyQ, ValueType TyD, SDNode MulOp, SDNode OpNode> - : N3V; // Long Intrinsic-Op vector operations with explicit extend (VABAL). @@ -1394,11 +2086,11 @@ class N3VLIntExtOp op21_20, bits<4> op11_8, bit op4, ValueType TyQ, ValueType TyD, Intrinsic IntOp, SDNode ExtOp, SDNode OpNode> : N3V; + (outs QPR:$Vd), (ins QPR:$src1, DPR:$Vn, DPR:$Vm), N3RegFrm, itin, + OpcodeStr, Dt, "$Vd, $Vn, $Vm", "$src1 = $Vd", + [(set QPR:$Vd, (OpNode (TyQ QPR:$src1), + (TyQ (ExtOp (TyD (IntOp (TyD DPR:$Vn), + (TyD DPR:$Vm)))))))]>; // Neon Long 3-argument intrinsic. The destination register is // a quad-register and is also used as the first source operand register. @@ -1406,35 +2098,35 @@ class N3VLInt3 op21_20, bits<4> op11_8, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, ValueType TyQ, ValueType TyD, Intrinsic IntOp> : N3V; + (outs QPR:$Vd), (ins QPR:$src1, DPR:$Vn, DPR:$Vm), N3RegFrm, itin, + OpcodeStr, Dt, "$Vd, $Vn, $Vm", "$src1 = $Vd", + [(set QPR:$Vd, + (TyQ (IntOp (TyQ QPR:$src1), (TyD DPR:$Vn), (TyD DPR:$Vm))))]>; class N3VLInt3SL op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> : N3V; class N3VLInt3SL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> : N3V; // Narrowing 3-register intrinsics. @@ -1442,9 +2134,9 @@ class N3VNInt op21_20, bits<4> op11_8, bit op4, string OpcodeStr, string Dt, ValueType TyD, ValueType TyQ, Intrinsic IntOp, bit Commutable> : N3V { + (outs DPR:$Vd), (ins QPR:$Vn, QPR:$Vm), N3RegFrm, IIC_VBINi4D, + OpcodeStr, Dt, "$Vd, $Vn, $Vm", "", + [(set DPR:$Vd, (TyD (IntOp (TyQ QPR:$Vn), (TyQ QPR:$Vm))))]> { let isCommutable = Commutable; } @@ -1453,29 +2145,29 @@ class N3VL op21_20, bits<4> op11_8, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, ValueType TyQ, ValueType TyD, SDNode OpNode, bit Commutable> : N3V { + (outs QPR:$Vd), (ins DPR:$Vn, DPR:$Vm), N3RegFrm, itin, + OpcodeStr, Dt, "$Vd, $Vn, $Vm", "", + [(set QPR:$Vd, (TyQ (OpNode (TyD DPR:$Vn), (TyD DPR:$Vm))))]> { let isCommutable = Commutable; } class N3VLSL op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType TyQ, ValueType TyD, SDNode OpNode> : N3V; + (outs QPR:$Vd), (ins DPR:$Vn, DPR_VFP2:$Vm, nohash_imm:$lane), + NVMulSLFrm, itin, OpcodeStr, Dt, "$Vd, $Vn, $Vm[$lane]", "", + [(set QPR:$Vd, + (TyQ (OpNode (TyD DPR:$Vn), + (TyD (NEONvduplane (TyD DPR_VFP2:$Vm),imm:$lane)))))]>; class N3VLSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType TyQ, ValueType TyD, SDNode OpNode> : N3V; + (outs QPR:$Vd), (ins DPR:$Vn, DPR_8:$Vm, nohash_imm:$lane), + NVMulSLFrm, itin, OpcodeStr, Dt, "$Vd, $Vn, $Vm[$lane]", "", + [(set QPR:$Vd, + (TyQ (OpNode (TyD DPR:$Vn), + (TyD (NEONvduplane (TyD DPR_8:$Vm), imm:$lane)))))]>; // Long 3-register operations with explicitly extended operands. class N3VLExt op21_20, bits<4> op11_8, bit op4, @@ -1483,10 +2175,10 @@ class N3VLExt op21_20, bits<4> op11_8, bit op4, ValueType TyQ, ValueType TyD, SDNode OpNode, SDNode ExtOp, bit Commutable> : N3V { + (outs QPR:$Vd), (ins DPR:$Vn, DPR:$Vm), N3RegFrm, itin, + OpcodeStr, Dt, "$Vd, $Vn, $Vm", "", + [(set QPR:$Vd, (OpNode (TyQ (ExtOp (TyD DPR:$Vn))), + (TyQ (ExtOp (TyD DPR:$Vm)))))]> { let isCommutable = Commutable; } @@ -1496,10 +2188,10 @@ class N3VLIntExt op21_20, bits<4> op11_8, bit op4, ValueType TyQ, ValueType TyD, Intrinsic IntOp, SDNode ExtOp, bit Commutable> : N3V { + (outs QPR:$Vd), (ins DPR:$Vn, DPR:$Vm), N3RegFrm, itin, + OpcodeStr, Dt, "$Vd, $Vn, $Vm", "", + [(set QPR:$Vd, (TyQ (ExtOp (TyD (IntOp (TyD DPR:$Vn), + (TyD DPR:$Vm))))))]> { let isCommutable = Commutable; } @@ -1508,30 +2200,30 @@ class N3VLInt op21_20, bits<4> op11_8, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, ValueType TyQ, ValueType TyD, Intrinsic IntOp, bit Commutable> : N3V { + (outs QPR:$Vd), (ins DPR:$Vn, DPR:$Vm), N3RegFrm, itin, + OpcodeStr, Dt, "$Vd, $Vn, $Vm", "", + [(set QPR:$Vd, (TyQ (IntOp (TyD DPR:$Vn), (TyD DPR:$Vm))))]> { let isCommutable = Commutable; } class N3VLIntSL op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> : N3V; class N3VLIntSL16 op21_20, bits<4> op11_8, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> : N3V; // Wide 3-register operations. @@ -1539,10 +2231,10 @@ class N3VW op21_20, bits<4> op11_8, bit op4, string OpcodeStr, string Dt, ValueType TyQ, ValueType TyD, SDNode OpNode, SDNode ExtOp, bit Commutable> : N3V { + (outs QPR:$Vd), (ins QPR:$Vn, DPR:$Vm), N3RegFrm, IIC_VSUBiD, + OpcodeStr, Dt, "$Vd, $Vn, $Vm", "", + [(set QPR:$Vd, (OpNode (TyQ QPR:$Vn), + (TyQ (ExtOp (TyD DPR:$Vm)))))]> { let isCommutable = Commutable; } @@ -1551,16 +2243,16 @@ class N2VDPLInt op24_23, bits<2> op21_20, bits<2> op19_18, bits<2> op17_16, bits<5> op11_7, bit op4, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> - : N2V; + : N2V; class N2VQPLInt op24_23, bits<2> op21_20, bits<2> op19_18, bits<2> op17_16, bits<5> op11_7, bit op4, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> - : N2V; + : N2V; // Pairwise long 2-register accumulate intrinsics, // both double- and quad-register. @@ -1570,17 +2262,17 @@ class N2VDPLInt2 op24_23, bits<2> op21_20, bits<2> op19_18, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> : N2V; + (outs DPR:$Vd), (ins DPR:$src1, DPR:$Vm), IIC_VPALiD, + OpcodeStr, Dt, "$Vd, $Vm", "$src1 = $Vd", + [(set DPR:$Vd, (ResTy (IntOp (ResTy DPR:$src1), (OpTy DPR:$Vm))))]>; class N2VQPLInt2 op24_23, bits<2> op21_20, bits<2> op19_18, bits<2> op17_16, bits<5> op11_7, bit op4, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> : N2V; + (outs QPR:$Vd), (ins QPR:$src1, QPR:$Vm), IIC_VPALiQ, + OpcodeStr, Dt, "$Vd, $Vm", "$src1 = $Vd", + [(set QPR:$Vd, (ResTy (IntOp (ResTy QPR:$src1), (OpTy QPR:$Vm))))]>; // Shift by immediate, // both double- and quad-register. @@ -1588,25 +2280,25 @@ class N2VDSh op11_8, bit op7, bit op4, Format f, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, SDNode OpNode> : N2VImm; + (outs DPR:$Vd), (ins DPR:$Vm, i32imm:$SIMM), f, itin, + OpcodeStr, Dt, "$Vd, $Vm, $SIMM", "", + [(set DPR:$Vd, (Ty (OpNode (Ty DPR:$Vm), (i32 imm:$SIMM))))]>; class N2VQSh op11_8, bit op7, bit op4, Format f, InstrItinClass itin, string OpcodeStr, string Dt, ValueType Ty, SDNode OpNode> : N2VImm; + (outs QPR:$Vd), (ins QPR:$Vm, i32imm:$SIMM), f, itin, + OpcodeStr, Dt, "$Vd, $Vm, $SIMM", "", + [(set QPR:$Vd, (Ty (OpNode (Ty QPR:$Vm), (i32 imm:$SIMM))))]>; // Long shift by immediate. class N2VLSh op11_8, bit op7, bit op6, bit op4, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode> : N2VImm; // Narrow shift by immediate. @@ -1614,42 +2306,42 @@ class N2VNSh op11_8, bit op7, bit op6, bit op4, InstrItinClass itin, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, SDNode OpNode> : N2VImm; // Shift right by immediate and accumulate, // both double- and quad-register. class N2VDShAdd op11_8, bit op7, bit op4, string OpcodeStr, string Dt, ValueType Ty, SDNode ShOp> - : N2VImm; + : N2VImm; class N2VQShAdd op11_8, bit op7, bit op4, string OpcodeStr, string Dt, ValueType Ty, SDNode ShOp> - : N2VImm; + : N2VImm; // Shift by immediate and insert, // both double- and quad-register. class N2VDShIns op11_8, bit op7, bit op4, Format f, string OpcodeStr, string Dt, ValueType Ty,SDNode ShOp> - : N2VImm; + : N2VImm; class N2VQShIns op11_8, bit op7, bit op4, Format f, string OpcodeStr, string Dt, ValueType Ty,SDNode ShOp> - : N2VImm; + : N2VImm; // Convert, with fractional bits immediate, // both double- and quad-register. @@ -1657,16 +2349,16 @@ class N2VCvtD op11_8, bit op7, bit op4, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> : N2VImm; + (outs DPR:$Vd), (ins DPR:$Vm, neon_vcvt_imm32:$SIMM), NVCVTFrm, + IIC_VUNAD, OpcodeStr, Dt, "$Vd, $Vm, $SIMM", "", + [(set DPR:$Vd, (ResTy (IntOp (OpTy DPR:$Vm), (i32 imm:$SIMM))))]>; class N2VCvtQ op11_8, bit op7, bit op4, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy, Intrinsic IntOp> : N2VImm; + (outs QPR:$Vd), (ins QPR:$Vm, neon_vcvt_imm32:$SIMM), NVCVTFrm, + IIC_VUNAQ, OpcodeStr, Dt, "$Vd, $Vm, $SIMM", "", + [(set QPR:$Vd, (ResTy (IntOp (OpTy QPR:$Vm), (i32 imm:$SIMM))))]>; //===----------------------------------------------------------------------===// // Multiclasses @@ -1678,45 +2370,127 @@ class N2VCvtQ op11_8, bit op7, bit op4, // S = single int (32 bit) elements // D = double int (64 bit) elements -// Neon 2-register vector operations -- for disassembly only. +// Neon 2-register vector operations and intrinsics. -// First with only element sizes of 8, 16 and 32 bits: +// Neon 2-register comparisons. +// source operand element sizes of 8, 16 and 32 bits: multiclass N2V_QHS_cmp op24_23, bits<2> op21_20, bits<2> op17_16, bits<5> op11_7, bit op4, string opc, string Dt, - string asm> { + string asm, SDNode OpNode> { // 64-bit vector types. def v8i8 : N2V; + (outs DPR:$Vd), (ins DPR:$Vm), NoItinerary, + opc, !strconcat(Dt, "8"), asm, "", + [(set DPR:$Vd, (v8i8 (OpNode (v8i8 DPR:$Vm))))]>; def v4i16 : N2V; + (outs DPR:$Vd), (ins DPR:$Vm), NoItinerary, + opc, !strconcat(Dt, "16"), asm, "", + [(set DPR:$Vd, (v4i16 (OpNode (v4i16 DPR:$Vm))))]>; def v2i32 : N2V; + (outs DPR:$Vd), (ins DPR:$Vm), NoItinerary, + opc, !strconcat(Dt, "32"), asm, "", + [(set DPR:$Vd, (v2i32 (OpNode (v2i32 DPR:$Vm))))]>; def v2f32 : N2V { + (outs DPR:$Vd), (ins DPR:$Vm), NoItinerary, + opc, "f32", asm, "", + [(set DPR:$Vd, (v2i32 (OpNode (v2f32 DPR:$Vm))))]> { let Inst{10} = 1; // overwrite F = 1 } // 128-bit vector types. def v16i8 : N2V; + (outs QPR:$Vd), (ins QPR:$Vm), NoItinerary, + opc, !strconcat(Dt, "8"), asm, "", + [(set QPR:$Vd, (v16i8 (OpNode (v16i8 QPR:$Vm))))]>; def v8i16 : N2V; + (outs QPR:$Vd), (ins QPR:$Vm), NoItinerary, + opc, !strconcat(Dt, "16"), asm, "", + [(set QPR:$Vd, (v8i16 (OpNode (v8i16 QPR:$Vm))))]>; def v4i32 : N2V; + (outs QPR:$Vd), (ins QPR:$Vm), NoItinerary, + opc, !strconcat(Dt, "32"), asm, "", + [(set QPR:$Vd, (v4i32 (OpNode (v4i32 QPR:$Vm))))]>; def v4f32 : N2V { + (outs QPR:$Vd), (ins QPR:$Vm), NoItinerary, + opc, "f32", asm, "", + [(set QPR:$Vd, (v4i32 (OpNode (v4f32 QPR:$Vm))))]> { let Inst{10} = 1; // overwrite F = 1 } } + +// Neon 2-register vector intrinsics, +// element sizes of 8, 16 and 32 bits: +multiclass N2VInt_QHS op24_23, bits<2> op21_20, bits<2> op17_16, + bits<5> op11_7, bit op4, + InstrItinClass itinD, InstrItinClass itinQ, + string OpcodeStr, string Dt, Intrinsic IntOp> { + // 64-bit vector types. + def v8i8 : N2VDInt; + def v4i16 : N2VDInt; + def v2i32 : N2VDInt; + + // 128-bit vector types. + def v16i8 : N2VQInt; + def v8i16 : N2VQInt; + def v4i32 : N2VQInt; +} + + +// Neon Narrowing 2-register vector operations, +// source operand element sizes of 16, 32 and 64 bits: +multiclass N2VN_HSD op24_23, bits<2> op21_20, bits<2> op17_16, + bits<5> op11_7, bit op6, bit op4, + InstrItinClass itin, string OpcodeStr, string Dt, + SDNode OpNode> { + def v8i8 : N2VN; + def v4i16 : N2VN; + def v2i32 : N2VN; +} + +// Neon Narrowing 2-register vector intrinsics, +// source operand element sizes of 16, 32 and 64 bits: +multiclass N2VNInt_HSD op24_23, bits<2> op21_20, bits<2> op17_16, + bits<5> op11_7, bit op6, bit op4, + InstrItinClass itin, string OpcodeStr, string Dt, + Intrinsic IntOp> { + def v8i8 : N2VNInt; + def v4i16 : N2VNInt; + def v2i32 : N2VNInt; +} + + +// Neon Lengthening 2-register vector intrinsic (currently specific to VMOVL). +// source operand element sizes of 16, 32 and 64 bits: +multiclass N2VL_QHS op24_23, bits<5> op11_7, bit op6, bit op4, + string OpcodeStr, string Dt, SDNode OpNode> { + def v8i16 : N2VL; + def v4i32 : N2VL; + def v2i64 : N2VL; +} + + // Neon 3-register vector operations. // First with only element sizes of 8, 16 and 32 bits: @@ -1726,7 +2500,7 @@ multiclass N3V_QHS op11_8, bit op4, string OpcodeStr, string Dt, SDNode OpNode, bit Commutable = 0> { // 64-bit vector types. - def v8i8 : N3VD; def v4i16 : N3VD op11_8, bit op4, } -// Neon Narrowing 2-register vector operations, -// source operand element sizes of 16, 32 and 64 bits: -multiclass N2VN_HSD op24_23, bits<2> op21_20, bits<2> op17_16, - bits<5> op11_7, bit op6, bit op4, - InstrItinClass itin, string OpcodeStr, string Dt, - SDNode OpNode> { - def v8i8 : N2VN; - def v4i16 : N2VN; - def v2i32 : N2VN; -} - -// Neon Narrowing 2-register vector intrinsics, -// source operand element sizes of 16, 32 and 64 bits: -multiclass N2VNInt_HSD op24_23, bits<2> op21_20, bits<2> op17_16, - bits<5> op11_7, bit op6, bit op4, - InstrItinClass itin, string OpcodeStr, string Dt, - Intrinsic IntOp> { - def v8i8 : N2VNInt; - def v4i16 : N2VNInt; - def v2i32 : N2VNInt; -} - - -// Neon Lengthening 2-register vector intrinsic (currently specific to VMOVL). -// source operand element sizes of 16, 32 and 64 bits: -multiclass N2VL_QHS op24_23, bits<5> op11_7, bit op6, bit op4, - string OpcodeStr, string Dt, SDNode OpNode> { - def v8i16 : N2VL; - def v4i32 : N2VL; - def v2i64 : N2VL; -} - - // Neon 3-register vector intrinsics. // First with only element sizes of 16 and 32 bits: @@ -1847,8 +2573,29 @@ multiclass N3VInt_HS op11_8, bit op4, Format f, OpcodeStr, !strconcat(Dt, "32"), v4i32, v4i32, IntOp, Commutable>; } +multiclass N3VInt_HSSh op11_8, bit op4, Format f, + InstrItinClass itinD16, InstrItinClass itinD32, + InstrItinClass itinQ16, InstrItinClass itinQ32, + string OpcodeStr, string Dt, + Intrinsic IntOp> { + // 64-bit vector types. + def v4i16 : N3VDIntSh; + def v2i32 : N3VDIntSh; + + // 128-bit vector types. + def v8i16 : N3VQIntSh; + def v4i32 : N3VQIntSh; +} -multiclass N3VIntSL_HS op11_8, +multiclass N3VIntSL_HS op11_8, InstrItinClass itinD16, InstrItinClass itinD32, InstrItinClass itinQ16, InstrItinClass itinQ32, string OpcodeStr, string Dt, Intrinsic IntOp> { @@ -1877,6 +2624,21 @@ multiclass N3VInt_QHS op11_8, bit op4, Format f, OpcodeStr, !strconcat(Dt, "8"), v16i8, v16i8, IntOp, Commutable>; } +multiclass N3VInt_QHSSh op11_8, bit op4, Format f, + InstrItinClass itinD16, InstrItinClass itinD32, + InstrItinClass itinQ16, InstrItinClass itinQ32, + string OpcodeStr, string Dt, + Intrinsic IntOp> + : N3VInt_HSSh { + def v8i8 : N3VDIntSh; + def v16i8 : N3VQIntSh; +} + // ....then also with element size of 64 bits: multiclass N3VInt_QHSD op11_8, bit op4, Format f, @@ -1893,6 +2655,20 @@ multiclass N3VInt_QHSD op11_8, bit op4, Format f, OpcodeStr, !strconcat(Dt, "64"), v2i64, v2i64, IntOp, Commutable>; } +multiclass N3VInt_QHSDSh op11_8, bit op4, Format f, + InstrItinClass itinD16, InstrItinClass itinD32, + InstrItinClass itinQ16, InstrItinClass itinQ32, + string OpcodeStr, string Dt, + Intrinsic IntOp> + : N3VInt_QHSSh { + def v1i64 : N3VDIntSh; + def v2i64 : N3VQIntSh; +} // Neon Narrowing 3-register vector intrinsics, // source operand element sizes of 16, 32 and 64 bits: @@ -1920,7 +2696,7 @@ multiclass N3VL_QHS op11_8, bit op4, def v8i16 : N3VL; - def v4i32 : N3VL; def v2i64 : N3VL op11_8, bit op4, def v8i16 : N3VLExt; - def v4i32 : N3VLExt; def v2i64 : N3VLExt op11_8, bit op4, InstrItinClass itin16, InstrItinClass itin32, string OpcodeStr, string Dt, Intrinsic IntOp, bit Commutable = 0> { - def v4i32 : N3VLInt; def v2i64 : N3VLInt op11_8, bit op4, multiclass N3VLIntSL_HS op11_8, InstrItinClass itin, string OpcodeStr, string Dt, Intrinsic IntOp> { - def v4i16 : N3VLIntSL16; def v2i32 : N3VLIntSL; @@ -1995,7 +2771,7 @@ multiclass N3VLIntExt_QHS op11_8, bit op4, def v8i16 : N3VLIntExt; - def v4i32 : N3VLIntExt; def v2i64 : N3VLIntExt op11_8, bit op4, OpcodeStr, !strconcat(Dt, "32"), v4i32, mul, OpNode>; } -multiclass N3VMulOpSL_HS op11_8, +multiclass N3VMulOpSL_HS op11_8, InstrItinClass itinD16, InstrItinClass itinD32, InstrItinClass itinQ16, InstrItinClass itinQ32, string OpcodeStr, string Dt, SDNode ShOp> { @@ -2174,30 +2950,6 @@ multiclass N3VLIntExtOp_QHS op11_8, bit op4, } -// Neon 2-register vector intrinsics, -// element sizes of 8, 16 and 32 bits: -multiclass N2VInt_QHS op24_23, bits<2> op21_20, bits<2> op17_16, - bits<5> op11_7, bit op4, - InstrItinClass itinD, InstrItinClass itinQ, - string OpcodeStr, string Dt, Intrinsic IntOp> { - // 64-bit vector types. - def v8i8 : N2VDInt; - def v4i16 : N2VDInt; - def v2i32 : N2VDInt; - - // 128-bit vector types. - def v16i8 : N2VQInt; - def v8i16 : N2VQInt; - def v4i32 : N2VQInt; -} - - // Neon Pairwise long 2-register intrinsics, // element sizes of 8, 16 and 32 bits: multiclass N2VPLInt_QHS op24_23, bits<2> op21_20, bits<2> op17_16, @@ -2461,9 +3213,9 @@ def VMULpd : N3VDInt<1, 0, 0b00, 0b1001, 1, N3RegFrm, IIC_VMULi16D, "vmul", "p8", v8i8, v8i8, int_arm_neon_vmulp, 1>; def VMULpq : N3VQInt<1, 0, 0b00, 0b1001, 1, N3RegFrm, IIC_VMULi16Q, "vmul", "p8", v16i8, v16i8, int_arm_neon_vmulp, 1>; -def VMULfd : N3VD<1, 0, 0b00, 0b1101, 1, IIC_VBIND, "vmul", "f32", +def VMULfd : N3VD<1, 0, 0b00, 0b1101, 1, IIC_VFMULD, "vmul", "f32", v2f32, v2f32, fmul, 1>; -def VMULfq : N3VQ<1, 0, 0b00, 0b1101, 1, IIC_VBINQ, "vmul", "f32", +def VMULfq : N3VQ<1, 0, 0b00, 0b1101, 1, IIC_VFMULQ, "vmul", "f32", v4f32, v4f32, fmul, 1>; defm VMULsl : N3VSL_HS<0b1000, "vmul", "i", mul>; def VMULslfd : N3VDSL<0b10, 0b1001, IIC_VBIND, "vmul", "f32", v2f32, fmul>; @@ -2491,7 +3243,7 @@ def : Pat<(v4f32 (fmul (v4f32 QPR:$src1), // VQDMULH : Vector Saturating Doubling Multiply Returning High Half defm VQDMULH : N3VInt_HS<0, 0, 0b1011, 0, N3RegFrm, IIC_VMULi16D, IIC_VMULi32D, - IIC_VMULi16Q, IIC_VMULi32Q, + IIC_VMULi16Q, IIC_VMULi32Q, "vqdmulh", "s", int_arm_neon_vqdmulh, 1>; defm VQDMULHsl: N3VIntSL_HS<0b1100, IIC_VMULi16D, IIC_VMULi32D, IIC_VMULi16Q, IIC_VMULi32Q, @@ -2555,15 +3307,19 @@ defm VQDMULLsl: N3VLIntSL_HS<0, 0b1011, IIC_VMULi16D, defm VMLA : N3VMulOp_QHS<0, 0, 0b1001, 0, IIC_VMACi16D, IIC_VMACi32D, IIC_VMACi16Q, IIC_VMACi32Q, "vmla", "i", add>; def VMLAfd : N3VDMulOp<0, 0, 0b00, 0b1101, 1, IIC_VMACD, "vmla", "f32", - v2f32, fmul, fadd>; + v2f32, fmul_su, fadd_mlx>, + Requires<[HasNEON, UseFPVMLx]>; def VMLAfq : N3VQMulOp<0, 0, 0b00, 0b1101, 1, IIC_VMACQ, "vmla", "f32", - v4f32, fmul, fadd>; + v4f32, fmul_su, fadd_mlx>, + Requires<[HasNEON, UseFPVMLx]>; defm VMLAsl : N3VMulOpSL_HS<0b0000, IIC_VMACi16D, IIC_VMACi32D, IIC_VMACi16Q, IIC_VMACi32Q, "vmla", "i", add>; def VMLAslfd : N3VDMulOpSL<0b10, 0b0001, IIC_VMACD, "vmla", "f32", - v2f32, fmul, fadd>; + v2f32, fmul_su, fadd_mlx>, + Requires<[HasNEON, UseFPVMLx]>; def VMLAslfq : N3VQMulOpSL<0b10, 0b0001, IIC_VMACQ, "vmla", "f32", - v4f32, v2f32, fmul, fadd>; + v4f32, v2f32, fmul_su, fadd_mlx>, + Requires<[HasNEON, UseFPVMLx]>; def : Pat<(v8i16 (add (v8i16 QPR:$src1), (mul (v8i16 QPR:$src2), @@ -2581,14 +3337,15 @@ def : Pat<(v4i32 (add (v4i32 QPR:$src1), (DSubReg_i32_reg imm:$lane))), (SubReg_i32_lane imm:$lane)))>; -def : Pat<(v4f32 (fadd (v4f32 QPR:$src1), - (fmul (v4f32 QPR:$src2), +def : Pat<(v4f32 (fadd_mlx (v4f32 QPR:$src1), + (fmul_su (v4f32 QPR:$src2), (v4f32 (NEONvduplane (v4f32 QPR:$src3), imm:$lane))))), (v4f32 (VMLAslfq (v4f32 QPR:$src1), (v4f32 QPR:$src2), (v2f32 (EXTRACT_SUBREG QPR:$src3, (DSubReg_i32_reg imm:$lane))), - (SubReg_i32_lane imm:$lane)))>; + (SubReg_i32_lane imm:$lane)))>, + Requires<[HasNEON, UseFPVMLx]>; // VMLAL : Vector Multiply Accumulate Long (Q += D * D) defm VMLALs : N3VLMulOp_QHS<0,1,0b1000,0, IIC_VMACi16D, IIC_VMACi32D, @@ -2608,15 +3365,19 @@ defm VQDMLALsl: N3VLInt3SL_HS<0, 0b0011, "vqdmlal", "s", int_arm_neon_vqdmlal>; defm VMLS : N3VMulOp_QHS<1, 0, 0b1001, 0, IIC_VMACi16D, IIC_VMACi32D, IIC_VMACi16Q, IIC_VMACi32Q, "vmls", "i", sub>; def VMLSfd : N3VDMulOp<0, 0, 0b10, 0b1101, 1, IIC_VMACD, "vmls", "f32", - v2f32, fmul, fsub>; + v2f32, fmul_su, fsub_mlx>, + Requires<[HasNEON, UseFPVMLx]>; def VMLSfq : N3VQMulOp<0, 0, 0b10, 0b1101, 1, IIC_VMACQ, "vmls", "f32", - v4f32, fmul, fsub>; + v4f32, fmul_su, fsub_mlx>, + Requires<[HasNEON, UseFPVMLx]>; defm VMLSsl : N3VMulOpSL_HS<0b0100, IIC_VMACi16D, IIC_VMACi32D, IIC_VMACi16Q, IIC_VMACi32Q, "vmls", "i", sub>; def VMLSslfd : N3VDMulOpSL<0b10, 0b0101, IIC_VMACD, "vmls", "f32", - v2f32, fmul, fsub>; + v2f32, fmul_su, fsub_mlx>, + Requires<[HasNEON, UseFPVMLx]>; def VMLSslfq : N3VQMulOpSL<0b10, 0b0101, IIC_VMACQ, "vmls", "f32", - v4f32, v2f32, fmul, fsub>; + v4f32, v2f32, fmul_su, fsub_mlx>, + Requires<[HasNEON, UseFPVMLx]>; def : Pat<(v8i16 (sub (v8i16 QPR:$src1), (mul (v8i16 QPR:$src2), @@ -2634,13 +3395,14 @@ def : Pat<(v4i32 (sub (v4i32 QPR:$src1), (DSubReg_i32_reg imm:$lane))), (SubReg_i32_lane imm:$lane)))>; -def : Pat<(v4f32 (fsub (v4f32 QPR:$src1), - (fmul (v4f32 QPR:$src2), +def : Pat<(v4f32 (fsub_mlx (v4f32 QPR:$src1), + (fmul_su (v4f32 QPR:$src2), (v4f32 (NEONvduplane (v4f32 QPR:$src3), imm:$lane))))), (v4f32 (VMLSslfq (v4f32 QPR:$src1), (v4f32 QPR:$src2), (v2f32 (EXTRACT_SUBREG QPR:$src3, (DSubReg_i32_reg imm:$lane))), - (SubReg_i32_lane imm:$lane)))>; + (SubReg_i32_lane imm:$lane)))>, + Requires<[HasNEON, UseFPVMLx]>; // VMLSL : Vector Multiply Subtract Long (Q -= D * D) defm VMLSLs : N3VLMulOp_QHS<0,1,0b1010,0, IIC_VMACi16D, IIC_VMACi32D, @@ -2703,25 +3465,24 @@ def VCEQfd : N3VD<0,0,0b00,0b1110,0, IIC_VBIND, "vceq", "f32", v2i32, v2f32, NEONvceq, 1>; def VCEQfq : N3VQ<0,0,0b00,0b1110,0, IIC_VBINQ, "vceq", "f32", v4i32, v4f32, NEONvceq, 1>; -// For disassembly only. + defm VCEQz : N2V_QHS_cmp<0b11, 0b11, 0b01, 0b00010, 0, "vceq", "i", - "$dst, $src, #0">; + "$Vd, $Vm, #0", NEONvceqz>; // VCGE : Vector Compare Greater Than or Equal defm VCGEs : N3V_QHS<0, 0, 0b0011, 1, IIC_VSUBi4D, IIC_VSUBi4D, IIC_VSUBi4Q, IIC_VSUBi4Q, "vcge", "s", NEONvcge, 0>; -defm VCGEu : N3V_QHS<1, 0, 0b0011, 1, IIC_VSUBi4D, IIC_VSUBi4D, IIC_VSUBi4Q, +defm VCGEu : N3V_QHS<1, 0, 0b0011, 1, IIC_VSUBi4D, IIC_VSUBi4D, IIC_VSUBi4Q, IIC_VSUBi4Q, "vcge", "u", NEONvcgeu, 0>; def VCGEfd : N3VD<1,0,0b00,0b1110,0, IIC_VBIND, "vcge", "f32", v2i32, v2f32, NEONvcge, 0>; def VCGEfq : N3VQ<1,0,0b00,0b1110,0, IIC_VBINQ, "vcge", "f32", v4i32, v4f32, NEONvcge, 0>; -// For disassembly only. + defm VCGEz : N2V_QHS_cmp<0b11, 0b11, 0b01, 0b00001, 0, "vcge", "s", - "$dst, $src, #0">; -// For disassembly only. + "$Vd, $Vm, #0", NEONvcgez>; defm VCLEz : N2V_QHS_cmp<0b11, 0b11, 0b01, 0b00011, 0, "vcle", "s", - "$dst, $src, #0">; + "$Vd, $Vm, #0", NEONvclez>; // VCGT : Vector Compare Greater Than defm VCGTs : N3V_QHS<0, 0, 0b0011, 0, IIC_VSUBi4D, IIC_VSUBi4D, IIC_VSUBi4Q, @@ -2732,12 +3493,11 @@ def VCGTfd : N3VD<1,0,0b10,0b1110,0, IIC_VBIND, "vcgt", "f32", v2i32, v2f32, NEONvcgt, 0>; def VCGTfq : N3VQ<1,0,0b10,0b1110,0, IIC_VBINQ, "vcgt", "f32", v4i32, v4f32, NEONvcgt, 0>; -// For disassembly only. + defm VCGTz : N2V_QHS_cmp<0b11, 0b11, 0b01, 0b00000, 0, "vcgt", "s", - "$dst, $src, #0">; -// For disassembly only. + "$Vd, $Vm, #0", NEONvcgtz>; defm VCLTz : N2V_QHS_cmp<0b11, 0b11, 0b01, 0b00100, 0, "vclt", "s", - "$dst, $src, #0">; + "$Vd, $Vm, #0", NEONvcltz>; // VACGE : Vector Absolute Compare Greater Than or Equal (aka VCAGE) def VACGEd : N3VDInt<1, 0, 0b00, 0b1110, 1, N3RegFrm, IIC_VBIND, "vacge", @@ -2750,7 +3510,7 @@ def VACGTd : N3VDInt<1, 0, 0b10, 0b1110, 1, N3RegFrm, IIC_VBIND, "vacgt", def VACGTq : N3VQInt<1, 0, 0b10, 0b1110, 1, N3RegFrm, IIC_VBINQ, "vacgt", "f32", v4i32, v4f32, int_arm_neon_vacgtq, 0>; // VTST : Vector Test Bits -defm VTST : N3V_QHS<0, 0, 0b1000, 1, IIC_VBINi4D, IIC_VBINi4D, IIC_VBINi4Q, +defm VTST : N3V_QHS<0, 0, 0b1000, 1, IIC_VBINi4D, IIC_VBINi4D, IIC_VBINi4Q, IIC_VBINi4Q, "vtst", "", NEONvtst, 1>; // Vector Bitwise Operations. @@ -2779,104 +3539,190 @@ def VORRd : N3VDX<0, 0, 0b10, 0b0001, 1, IIC_VBINiD, "vorr", def VORRq : N3VQX<0, 0, 0b10, 0b0001, 1, IIC_VBINiQ, "vorr", v4i32, v4i32, or, 1>; +def VORRiv4i16 : N1ModImm<1, 0b000, {1,0,?,1}, 0, 0, 0, 1, + (outs DPR:$Vd), (ins nModImm:$SIMM, DPR:$src), + IIC_VMOVImm, + "vorr", "i16", "$Vd, $SIMM", "$src = $Vd", + [(set DPR:$Vd, + (v4i16 (NEONvorrImm DPR:$src, timm:$SIMM)))]> { + let Inst{9} = SIMM{9}; +} + +def VORRiv2i32 : N1ModImm<1, 0b000, {0,?,?,1}, 0, 0, 0, 1, + (outs DPR:$Vd), (ins nModImm:$SIMM, DPR:$src), + IIC_VMOVImm, + "vorr", "i32", "$Vd, $SIMM", "$src = $Vd", + [(set DPR:$Vd, + (v2i32 (NEONvorrImm DPR:$src, timm:$SIMM)))]> { + let Inst{10-9} = SIMM{10-9}; +} + +def VORRiv8i16 : N1ModImm<1, 0b000, {1,0,?,1}, 0, 1, 0, 1, + (outs QPR:$Vd), (ins nModImm:$SIMM, QPR:$src), + IIC_VMOVImm, + "vorr", "i16", "$Vd, $SIMM", "$src = $Vd", + [(set QPR:$Vd, + (v8i16 (NEONvorrImm QPR:$src, timm:$SIMM)))]> { + let Inst{9} = SIMM{9}; +} + +def VORRiv4i32 : N1ModImm<1, 0b000, {0,?,?,1}, 0, 1, 0, 1, + (outs QPR:$Vd), (ins nModImm:$SIMM, QPR:$src), + IIC_VMOVImm, + "vorr", "i32", "$Vd, $SIMM", "$src = $Vd", + [(set QPR:$Vd, + (v4i32 (NEONvorrImm QPR:$src, timm:$SIMM)))]> { + let Inst{10-9} = SIMM{10-9}; +} + + // VBIC : Vector Bitwise Bit Clear (AND NOT) -def VBICd : N3VX<0, 0, 0b01, 0b0001, 0, 1, (outs DPR:$dst), - (ins DPR:$src1, DPR:$src2), N3RegFrm, IIC_VBINiD, - "vbic", "$dst, $src1, $src2", "", - [(set DPR:$dst, (v2i32 (and DPR:$src1, - (vnotd DPR:$src2))))]>; -def VBICq : N3VX<0, 0, 0b01, 0b0001, 1, 1, (outs QPR:$dst), - (ins QPR:$src1, QPR:$src2), N3RegFrm, IIC_VBINiQ, - "vbic", "$dst, $src1, $src2", "", - [(set QPR:$dst, (v4i32 (and QPR:$src1, - (vnotq QPR:$src2))))]>; +def VBICd : N3VX<0, 0, 0b01, 0b0001, 0, 1, (outs DPR:$Vd), + (ins DPR:$Vn, DPR:$Vm), N3RegFrm, IIC_VBINiD, + "vbic", "$Vd, $Vn, $Vm", "", + [(set DPR:$Vd, (v2i32 (and DPR:$Vn, + (vnotd DPR:$Vm))))]>; +def VBICq : N3VX<0, 0, 0b01, 0b0001, 1, 1, (outs QPR:$Vd), + (ins QPR:$Vn, QPR:$Vm), N3RegFrm, IIC_VBINiQ, + "vbic", "$Vd, $Vn, $Vm", "", + [(set QPR:$Vd, (v4i32 (and QPR:$Vn, + (vnotq QPR:$Vm))))]>; + +def VBICiv4i16 : N1ModImm<1, 0b000, {1,0,?,1}, 0, 0, 1, 1, + (outs DPR:$Vd), (ins nModImm:$SIMM, DPR:$src), + IIC_VMOVImm, + "vbic", "i16", "$Vd, $SIMM", "$src = $Vd", + [(set DPR:$Vd, + (v4i16 (NEONvbicImm DPR:$src, timm:$SIMM)))]> { + let Inst{9} = SIMM{9}; +} + +def VBICiv2i32 : N1ModImm<1, 0b000, {0,?,?,1}, 0, 0, 1, 1, + (outs DPR:$Vd), (ins nModImm:$SIMM, DPR:$src), + IIC_VMOVImm, + "vbic", "i32", "$Vd, $SIMM", "$src = $Vd", + [(set DPR:$Vd, + (v2i32 (NEONvbicImm DPR:$src, timm:$SIMM)))]> { + let Inst{10-9} = SIMM{10-9}; +} + +def VBICiv8i16 : N1ModImm<1, 0b000, {1,0,?,1}, 0, 1, 1, 1, + (outs QPR:$Vd), (ins nModImm:$SIMM, QPR:$src), + IIC_VMOVImm, + "vbic", "i16", "$Vd, $SIMM", "$src = $Vd", + [(set QPR:$Vd, + (v8i16 (NEONvbicImm QPR:$src, timm:$SIMM)))]> { + let Inst{9} = SIMM{9}; +} + +def VBICiv4i32 : N1ModImm<1, 0b000, {0,?,?,1}, 0, 1, 1, 1, + (outs QPR:$Vd), (ins nModImm:$SIMM, QPR:$src), + IIC_VMOVImm, + "vbic", "i32", "$Vd, $SIMM", "$src = $Vd", + [(set QPR:$Vd, + (v4i32 (NEONvbicImm QPR:$src, timm:$SIMM)))]> { + let Inst{10-9} = SIMM{10-9}; +} // VORN : Vector Bitwise OR NOT -def VORNd : N3VX<0, 0, 0b11, 0b0001, 0, 1, (outs DPR:$dst), - (ins DPR:$src1, DPR:$src2), N3RegFrm, IIC_VBINiD, - "vorn", "$dst, $src1, $src2", "", - [(set DPR:$dst, (v2i32 (or DPR:$src1, - (vnotd DPR:$src2))))]>; -def VORNq : N3VX<0, 0, 0b11, 0b0001, 1, 1, (outs QPR:$dst), - (ins QPR:$src1, QPR:$src2), N3RegFrm, IIC_VBINiQ, - "vorn", "$dst, $src1, $src2", "", - [(set QPR:$dst, (v4i32 (or QPR:$src1, - (vnotq QPR:$src2))))]>; +def VORNd : N3VX<0, 0, 0b11, 0b0001, 0, 1, (outs DPR:$Vd), + (ins DPR:$Vn, DPR:$Vm), N3RegFrm, IIC_VBINiD, + "vorn", "$Vd, $Vn, $Vm", "", + [(set DPR:$Vd, (v2i32 (or DPR:$Vn, + (vnotd DPR:$Vm))))]>; +def VORNq : N3VX<0, 0, 0b11, 0b0001, 1, 1, (outs QPR:$Vd), + (ins QPR:$Vn, QPR:$Vm), N3RegFrm, IIC_VBINiQ, + "vorn", "$Vd, $Vn, $Vm", "", + [(set QPR:$Vd, (v4i32 (or QPR:$Vn, + (vnotq QPR:$Vm))))]>; // VMVN : Vector Bitwise NOT (Immediate) let isReMaterializable = 1 in { -def VMVNv4i16 : N1ModImm<1, 0b000, {1,0,?,0}, 0, 0, 1, 1, (outs DPR:$dst), + +def VMVNv4i16 : N1ModImm<1, 0b000, {1,0,?,0}, 0, 0, 1, 1, (outs DPR:$Vd), (ins nModImm:$SIMM), IIC_VMOVImm, - "vmvn", "i16", "$dst, $SIMM", "", - [(set DPR:$dst, (v4i16 (NEONvmvnImm timm:$SIMM)))]>; -def VMVNv8i16 : N1ModImm<1, 0b000, {1,0,?,0}, 0, 1, 1, 1, (outs QPR:$dst), + "vmvn", "i16", "$Vd, $SIMM", "", + [(set DPR:$Vd, (v4i16 (NEONvmvnImm timm:$SIMM)))]> { + let Inst{9} = SIMM{9}; +} + +def VMVNv8i16 : N1ModImm<1, 0b000, {1,0,?,0}, 0, 1, 1, 1, (outs QPR:$Vd), (ins nModImm:$SIMM), IIC_VMOVImm, - "vmvn", "i16", "$dst, $SIMM", "", - [(set QPR:$dst, (v8i16 (NEONvmvnImm timm:$SIMM)))]>; + "vmvn", "i16", "$Vd, $SIMM", "", + [(set QPR:$Vd, (v8i16 (NEONvmvnImm timm:$SIMM)))]> { + let Inst{9} = SIMM{9}; +} -def VMVNv2i32 : N1ModImm<1, 0b000, {?,?,?,?}, 0, 0, 1, 1, (outs DPR:$dst), +def VMVNv2i32 : N1ModImm<1, 0b000, {?,?,?,?}, 0, 0, 1, 1, (outs DPR:$Vd), (ins nModImm:$SIMM), IIC_VMOVImm, - "vmvn", "i32", "$dst, $SIMM", "", - [(set DPR:$dst, (v2i32 (NEONvmvnImm timm:$SIMM)))]>; -def VMVNv4i32 : N1ModImm<1, 0b000, {?,?,?,?}, 0, 1, 1, 1, (outs QPR:$dst), + "vmvn", "i32", "$Vd, $SIMM", "", + [(set DPR:$Vd, (v2i32 (NEONvmvnImm timm:$SIMM)))]> { + let Inst{11-8} = SIMM{11-8}; +} + +def VMVNv4i32 : N1ModImm<1, 0b000, {?,?,?,?}, 0, 1, 1, 1, (outs QPR:$Vd), (ins nModImm:$SIMM), IIC_VMOVImm, - "vmvn", "i32", "$dst, $SIMM", "", - [(set QPR:$dst, (v4i32 (NEONvmvnImm timm:$SIMM)))]>; + "vmvn", "i32", "$Vd, $SIMM", "", + [(set QPR:$Vd, (v4i32 (NEONvmvnImm timm:$SIMM)))]> { + let Inst{11-8} = SIMM{11-8}; +} } // VMVN : Vector Bitwise NOT def VMVNd : N2VX<0b11, 0b11, 0b00, 0b00, 0b01011, 0, 0, - (outs DPR:$dst), (ins DPR:$src), IIC_VSUBiD, - "vmvn", "$dst, $src", "", - [(set DPR:$dst, (v2i32 (vnotd DPR:$src)))]>; + (outs DPR:$Vd), (ins DPR:$Vm), IIC_VSUBiD, + "vmvn", "$Vd, $Vm", "", + [(set DPR:$Vd, (v2i32 (vnotd DPR:$Vm)))]>; def VMVNq : N2VX<0b11, 0b11, 0b00, 0b00, 0b01011, 1, 0, - (outs QPR:$dst), (ins QPR:$src), IIC_VSUBiD, - "vmvn", "$dst, $src", "", - [(set QPR:$dst, (v4i32 (vnotq QPR:$src)))]>; + (outs QPR:$Vd), (ins QPR:$Vm), IIC_VSUBiD, + "vmvn", "$Vd, $Vm", "", + [(set QPR:$Vd, (v4i32 (vnotq QPR:$Vm)))]>; def : Pat<(v2i32 (vnotd DPR:$src)), (VMVNd DPR:$src)>; def : Pat<(v4i32 (vnotq QPR:$src)), (VMVNq QPR:$src)>; // VBSL : Vector Bitwise Select -def VBSLd : N3VX<1, 0, 0b01, 0b0001, 0, 1, (outs DPR:$dst), - (ins DPR:$src1, DPR:$src2, DPR:$src3), +def VBSLd : N3VX<1, 0, 0b01, 0b0001, 0, 1, (outs DPR:$Vd), + (ins DPR:$src1, DPR:$Vn, DPR:$Vm), N3RegFrm, IIC_VCNTiD, - "vbsl", "$dst, $src2, $src3", "$src1 = $dst", - [(set DPR:$dst, - (v2i32 (or (and DPR:$src2, DPR:$src1), - (and DPR:$src3, (vnotd DPR:$src1)))))]>; -def VBSLq : N3VX<1, 0, 0b01, 0b0001, 1, 1, (outs QPR:$dst), - (ins QPR:$src1, QPR:$src2, QPR:$src3), + "vbsl", "$Vd, $Vn, $Vm", "$src1 = $Vd", + [(set DPR:$Vd, + (v2i32 (or (and DPR:$Vn, DPR:$src1), + (and DPR:$Vm, (vnotd DPR:$src1)))))]>; +def VBSLq : N3VX<1, 0, 0b01, 0b0001, 1, 1, (outs QPR:$Vd), + (ins QPR:$src1, QPR:$Vn, QPR:$Vm), N3RegFrm, IIC_VCNTiQ, - "vbsl", "$dst, $src2, $src3", "$src1 = $dst", - [(set QPR:$dst, - (v4i32 (or (and QPR:$src2, QPR:$src1), - (and QPR:$src3, (vnotq QPR:$src1)))))]>; + "vbsl", "$Vd, $Vn, $Vm", "$src1 = $Vd", + [(set QPR:$Vd, + (v4i32 (or (and QPR:$Vn, QPR:$src1), + (and QPR:$Vm, (vnotq QPR:$src1)))))]>; // VBIF : Vector Bitwise Insert if False // like VBSL but with: "vbif $dst, $src3, $src1", "$src2 = $dst", +// FIXME: This instruction's encoding MAY NOT BE correct. def VBIFd : N3VX<1, 0, 0b11, 0b0001, 0, 1, - (outs DPR:$dst), (ins DPR:$src1, DPR:$src2, DPR:$src3), + (outs DPR:$Vd), (ins DPR:$src1, DPR:$Vn, DPR:$Vm), N3RegFrm, IIC_VBINiD, - "vbif", "$dst, $src2, $src3", "$src1 = $dst", + "vbif", "$Vd, $Vn, $Vm", "$src1 = $Vd", [/* For disassembly only; pattern left blank */]>; def VBIFq : N3VX<1, 0, 0b11, 0b0001, 1, 1, - (outs QPR:$dst), (ins QPR:$src1, QPR:$src2, QPR:$src3), + (outs QPR:$Vd), (ins QPR:$src1, QPR:$Vn, QPR:$Vm), N3RegFrm, IIC_VBINiQ, - "vbif", "$dst, $src2, $src3", "$src1 = $dst", + "vbif", "$Vd, $Vn, $Vm", "$src1 = $Vd", [/* For disassembly only; pattern left blank */]>; // VBIT : Vector Bitwise Insert if True // like VBSL but with: "vbit $dst, $src2, $src1", "$src3 = $dst", +// FIXME: This instruction's encoding MAY NOT BE correct. def VBITd : N3VX<1, 0, 0b10, 0b0001, 0, 1, - (outs DPR:$dst), (ins DPR:$src1, DPR:$src2, DPR:$src3), + (outs DPR:$Vd), (ins DPR:$src1, DPR:$Vn, DPR:$Vm), N3RegFrm, IIC_VBINiD, - "vbit", "$dst, $src2, $src3", "$src1 = $dst", + "vbit", "$Vd, $Vn, $Vm", "$src1 = $Vd", [/* For disassembly only; pattern left blank */]>; def VBITq : N3VX<1, 0, 0b10, 0b0001, 1, 1, - (outs QPR:$dst), (ins QPR:$src1, QPR:$src2, QPR:$src3), + (outs QPR:$Vd), (ins QPR:$src1, QPR:$Vn, QPR:$Vm), N3RegFrm, IIC_VBINiQ, - "vbit", "$dst, $src2, $src3", "$src1 = $dst", + "vbit", "$Vd, $Vn, $Vm", "$src1 = $Vd", [/* For disassembly only; pattern left blank */]>; // VBIT/VBIF are not yet implemented. The TwoAddress pass will not go looking @@ -2957,8 +3803,8 @@ def VPADDi16 : N3VDInt<0, 0, 0b01, 0b1011, 1, N3RegFrm, IIC_VSHLiD, def VPADDi32 : N3VDInt<0, 0, 0b10, 0b1011, 1, N3RegFrm, IIC_VSHLiD, "vpadd", "i32", v2i32, v2i32, int_arm_neon_vpadd, 0>; -def VPADDf : N3VDInt<1, 0, 0b00, 0b1101, 0, N3RegFrm, - IIC_VBIND, "vpadd", "f32", +def VPADDf : N3VDInt<1, 0, 0b00, 0b1101, 0, N3RegFrm, + IIC_VPBIND, "vpadd", "f32", v2f32, v2f32, int_arm_neon_vpadd, 0>; // VPADDL : Vector Pairwise Add Long @@ -2986,7 +3832,7 @@ def VPMAXu16 : N3VDInt<1, 0, 0b01, 0b1010, 0, N3RegFrm, IIC_VSUBi4D, "vpmax", "u16", v4i16, v4i16, int_arm_neon_vpmaxu, 0>; def VPMAXu32 : N3VDInt<1, 0, 0b10, 0b1010, 0, N3RegFrm, IIC_VSUBi4D, "vpmax", "u32", v2i32, v2i32, int_arm_neon_vpmaxu, 0>; -def VPMAXf : N3VDInt<1, 0, 0b00, 0b1111, 0, N3RegFrm, IIC_VSUBi4D, "vpmax", +def VPMAXf : N3VDInt<1, 0, 0b00, 0b1111, 0, N3RegFrm, IIC_VPBIND, "vpmax", "f32", v2f32, v2f32, int_arm_neon_vpmaxs, 0>; // VPMIN : Vector Pairwise Minimum @@ -3002,16 +3848,16 @@ def VPMINu16 : N3VDInt<1, 0, 0b01, 0b1010, 1, N3RegFrm, IIC_VSUBi4D, "vpmin", "u16", v4i16, v4i16, int_arm_neon_vpminu, 0>; def VPMINu32 : N3VDInt<1, 0, 0b10, 0b1010, 1, N3RegFrm, IIC_VSUBi4D, "vpmin", "u32", v2i32, v2i32, int_arm_neon_vpminu, 0>; -def VPMINf : N3VDInt<1, 0, 0b10, 0b1111, 0, N3RegFrm, IIC_VSUBi4D, "vpmin", +def VPMINf : N3VDInt<1, 0, 0b10, 0b1111, 0, N3RegFrm, IIC_VPBIND, "vpmin", "f32", v2f32, v2f32, int_arm_neon_vpmins, 0>; // Vector Reciprocal and Reciprocal Square Root Estimate and Step. // VRECPE : Vector Reciprocal Estimate -def VRECPEd : N2VDInt<0b11, 0b11, 0b10, 0b11, 0b01000, 0, +def VRECPEd : N2VDInt<0b11, 0b11, 0b10, 0b11, 0b01000, 0, IIC_VUNAD, "vrecpe", "u32", v2i32, v2i32, int_arm_neon_vrecpe>; -def VRECPEq : N2VQInt<0b11, 0b11, 0b10, 0b11, 0b01000, 0, +def VRECPEq : N2VQInt<0b11, 0b11, 0b10, 0b11, 0b01000, 0, IIC_VUNAQ, "vrecpe", "u32", v4i32, v4i32, int_arm_neon_vrecpe>; def VRECPEfd : N2VDInt<0b11, 0b11, 0b10, 0b11, 0b01010, 0, @@ -3039,7 +3885,7 @@ def VRSQRTEq : N2VQInt<0b11, 0b11, 0b10, 0b11, 0b01001, 0, def VRSQRTEfd : N2VDInt<0b11, 0b11, 0b10, 0b11, 0b01011, 0, IIC_VUNAD, "vrsqrte", "f32", v2f32, v2f32, int_arm_neon_vrsqrte>; -def VRSQRTEfq : N2VQInt<0b11, 0b11, 0b10, 0b11, 0b01011, 0, +def VRSQRTEfq : N2VQInt<0b11, 0b11, 0b10, 0b11, 0b01011, 0, IIC_VUNAQ, "vrsqrte", "f32", v4f32, v4f32, int_arm_neon_vrsqrte>; @@ -3054,12 +3900,12 @@ def VRSQRTSfq : N3VQInt<0, 0, 0b10, 0b1111, 1, N3RegFrm, // Vector Shifts. // VSHL : Vector Shift -defm VSHLs : N3VInt_QHSD<0, 0, 0b0100, 0, N3RegVShFrm, +defm VSHLs : N3VInt_QHSDSh<0, 0, 0b0100, 0, N3RegVShFrm, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, IIC_VSHLiQ, - "vshl", "s", int_arm_neon_vshifts, 0>; -defm VSHLu : N3VInt_QHSD<1, 0, 0b0100, 0, N3RegVShFrm, + "vshl", "s", int_arm_neon_vshifts>; +defm VSHLu : N3VInt_QHSDSh<1, 0, 0b0100, 0, N3RegVShFrm, IIC_VSHLiD, IIC_VSHLiD, IIC_VSHLiQ, IIC_VSHLiQ, - "vshl", "u", int_arm_neon_vshiftu, 0>; + "vshl", "u", int_arm_neon_vshiftu>; // VSHL : Vector Shift Left (Immediate) defm VSHLi : N2VSh_QHSD<0, 1, 0b0101, 1, IIC_VSHLiD, "vshl", "i", NEONvshl, N2RegVShLFrm>; @@ -3093,12 +3939,12 @@ defm VSHRN : N2VNSh_HSD<0,1,0b1000,0,0,1, IIC_VSHLiD, "vshrn", "i", NEONvshrn>; // VRSHL : Vector Rounding Shift -defm VRSHLs : N3VInt_QHSD<0, 0, 0b0101, 0, N3RegVShFrm, +defm VRSHLs : N3VInt_QHSDSh<0, 0, 0b0101, 0, N3RegVShFrm, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, IIC_VSHLi4Q, - "vrshl", "s", int_arm_neon_vrshifts, 0>; -defm VRSHLu : N3VInt_QHSD<1, 0, 0b0101, 0, N3RegVShFrm, + "vrshl", "s", int_arm_neon_vrshifts>; +defm VRSHLu : N3VInt_QHSDSh<1, 0, 0b0101, 0, N3RegVShFrm, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, IIC_VSHLi4Q, - "vrshl", "u", int_arm_neon_vrshiftu, 0>; + "vrshl", "u", int_arm_neon_vrshiftu>; // VRSHR : Vector Rounding Shift Right defm VRSHRs : N2VSh_QHSD<0,1,0b0010,1, IIC_VSHLi4D, "vrshr", "s", NEONvrshrs, N2RegVShRFrm>; @@ -3110,12 +3956,12 @@ defm VRSHRN : N2VNSh_HSD<0, 1, 0b1000, 0, 1, 1, IIC_VSHLi4D, "vrshrn", "i", NEONvrshrn>; // VQSHL : Vector Saturating Shift -defm VQSHLs : N3VInt_QHSD<0, 0, 0b0100, 1, N3RegVShFrm, +defm VQSHLs : N3VInt_QHSDSh<0, 0, 0b0100, 1, N3RegVShFrm, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, IIC_VSHLi4Q, - "vqshl", "s", int_arm_neon_vqshifts, 0>; -defm VQSHLu : N3VInt_QHSD<1, 0, 0b0100, 1, N3RegVShFrm, + "vqshl", "s", int_arm_neon_vqshifts>; +defm VQSHLu : N3VInt_QHSDSh<1, 0, 0b0100, 1, N3RegVShFrm, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, IIC_VSHLi4Q, - "vqshl", "u", int_arm_neon_vqshiftu, 0>; + "vqshl", "u", int_arm_neon_vqshiftu>; // VQSHL : Vector Saturating Shift Left (Immediate) defm VQSHLsi : N2VSh_QHSD<0,1,0b0111,1, IIC_VSHLi4D, "vqshl", "s",NEONvqshls, N2RegVShLFrm>; @@ -3136,12 +3982,12 @@ defm VQSHRUN : N2VNSh_HSD<1, 1, 0b1000, 0, 0, 1, IIC_VSHLi4D, "vqshrun", "s", NEONvqshrnsu>; // VQRSHL : Vector Saturating Rounding Shift -defm VQRSHLs : N3VInt_QHSD<0, 0, 0b0101, 1, N3RegVShFrm, +defm VQRSHLs : N3VInt_QHSDSh<0, 0, 0b0101, 1, N3RegVShFrm, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, IIC_VSHLi4Q, - "vqrshl", "s", int_arm_neon_vqrshifts, 0>; -defm VQRSHLu : N3VInt_QHSD<1, 0, 0b0101, 1, N3RegVShFrm, + "vqrshl", "s", int_arm_neon_vqrshifts>; +defm VQRSHLu : N3VInt_QHSDSh<1, 0, 0b0101, 1, N3RegVShFrm, IIC_VSHLi4D, IIC_VSHLi4D, IIC_VSHLi4Q, IIC_VSHLi4Q, - "vqrshl", "u", int_arm_neon_vqrshiftu, 0>; + "vqrshl", "u", int_arm_neon_vqrshiftu>; // VQRSHRN : Vector Saturating Rounding Shift Right and Narrow defm VQRSHRNs : N2VNSh_HSD<0, 1, 0b1001, 0, 1, 1, IIC_VSHLi4D, "vqrshrn", "s", @@ -3168,7 +4014,7 @@ defm VSRI : N2VShIns_QHSD<1, 1, 0b0100, 1, "vsri", NEONvsri, N2RegVShRFrm>; // Vector Absolute and Saturating Absolute. // VABS : Vector Absolute Value -defm VABS : N2VInt_QHS<0b11, 0b11, 0b01, 0b00110, 0, +defm VABS : N2VInt_QHS<0b11, 0b11, 0b01, 0b00110, 0, IIC_VUNAiD, IIC_VUNAiQ, "vabs", "s", int_arm_neon_vabs>; def VABSfd : N2VDInt<0b11, 0b11, 0b10, 0b01, 0b01110, 0, @@ -3179,7 +4025,7 @@ def VABSfq : N2VQInt<0b11, 0b11, 0b10, 0b01, 0b01110, 0, v4f32, v4f32, int_arm_neon_vabs>; // VQABS : Vector Saturating Absolute Value -defm VQABS : N2VInt_QHS<0b11, 0b11, 0b00, 0b01110, 0, +defm VQABS : N2VInt_QHS<0b11, 0b11, 0b00, 0b01110, 0, IIC_VQUNAiD, IIC_VQUNAiQ, "vqabs", "s", int_arm_neon_vqabs>; @@ -3191,13 +4037,13 @@ def vnegq : PatFrag<(ops node:$in), (sub (bitconvert (v4i32 NEONimmAllZerosV)), node:$in)>; class VNEGD size, string OpcodeStr, string Dt, ValueType Ty> - : N2V<0b11, 0b11, size, 0b01, 0b00111, 0, 0, (outs DPR:$dst), (ins DPR:$src), - IIC_VSHLiD, OpcodeStr, Dt, "$dst, $src", "", - [(set DPR:$dst, (Ty (vnegd DPR:$src)))]>; + : N2V<0b11, 0b11, size, 0b01, 0b00111, 0, 0, (outs DPR:$Vd), (ins DPR:$Vm), + IIC_VSHLiD, OpcodeStr, Dt, "$Vd, $Vm", "", + [(set DPR:$Vd, (Ty (vnegd DPR:$Vm)))]>; class VNEGQ size, string OpcodeStr, string Dt, ValueType Ty> - : N2V<0b11, 0b11, size, 0b01, 0b00111, 1, 0, (outs QPR:$dst), (ins QPR:$src), - IIC_VSHLiD, OpcodeStr, Dt, "$dst, $src", "", - [(set QPR:$dst, (Ty (vnegq QPR:$src)))]>; + : N2V<0b11, 0b11, size, 0b01, 0b00111, 1, 0, (outs QPR:$Vd), (ins QPR:$Vm), + IIC_VSHLiQ, OpcodeStr, Dt, "$Vd, $Vm", "", + [(set QPR:$Vd, (Ty (vnegq QPR:$Vm)))]>; // VNEG : Vector Negate (integer) def VNEGs8d : VNEGD<0b00, "vneg", "s8", v8i8>; @@ -3209,13 +4055,13 @@ def VNEGs32q : VNEGQ<0b10, "vneg", "s32", v4i32>; // VNEG : Vector Negate (floating-point) def VNEGfd : N2V<0b11, 0b11, 0b10, 0b01, 0b01111, 0, 0, - (outs DPR:$dst), (ins DPR:$src), IIC_VUNAD, - "vneg", "f32", "$dst, $src", "", - [(set DPR:$dst, (v2f32 (fneg DPR:$src)))]>; + (outs DPR:$Vd), (ins DPR:$Vm), IIC_VUNAD, + "vneg", "f32", "$Vd, $Vm", "", + [(set DPR:$Vd, (v2f32 (fneg DPR:$Vm)))]>; def VNEGf32q : N2V<0b11, 0b11, 0b10, 0b01, 0b01111, 1, 0, - (outs QPR:$dst), (ins QPR:$src), IIC_VUNAQ, - "vneg", "f32", "$dst, $src", "", - [(set QPR:$dst, (v4f32 (fneg QPR:$src)))]>; + (outs QPR:$Vd), (ins QPR:$Vm), IIC_VUNAQ, + "vneg", "f32", "$Vd, $Vm", "", + [(set QPR:$Vd, (v4f32 (fneg QPR:$Vm)))]>; def : Pat<(v8i8 (vnegd DPR:$src)), (VNEGs8d DPR:$src)>; def : Pat<(v4i16 (vnegd DPR:$src)), (VNEGs16d DPR:$src)>; @@ -3225,22 +4071,22 @@ def : Pat<(v8i16 (vnegq QPR:$src)), (VNEGs16q QPR:$src)>; def : Pat<(v4i32 (vnegq QPR:$src)), (VNEGs32q QPR:$src)>; // VQNEG : Vector Saturating Negate -defm VQNEG : N2VInt_QHS<0b11, 0b11, 0b00, 0b01111, 0, +defm VQNEG : N2VInt_QHS<0b11, 0b11, 0b00, 0b01111, 0, IIC_VQUNAiD, IIC_VQUNAiQ, "vqneg", "s", int_arm_neon_vqneg>; // Vector Bit Counting Operations. // VCLS : Vector Count Leading Sign Bits -defm VCLS : N2VInt_QHS<0b11, 0b11, 0b00, 0b01000, 0, +defm VCLS : N2VInt_QHS<0b11, 0b11, 0b00, 0b01000, 0, IIC_VCNTiD, IIC_VCNTiQ, "vcls", "s", int_arm_neon_vcls>; // VCLZ : Vector Count Leading Zeros -defm VCLZ : N2VInt_QHS<0b11, 0b11, 0b00, 0b01001, 0, +defm VCLZ : N2VInt_QHS<0b11, 0b11, 0b00, 0b01001, 0, IIC_VCNTiD, IIC_VCNTiQ, "vclz", "i", int_arm_neon_vclz>; // VCNT : Vector Count One Bits -def VCNTd : N2VDInt<0b11, 0b11, 0b00, 0b00, 0b01010, 0, +def VCNTd : N2VDInt<0b11, 0b11, 0b00, 0b00, 0b01010, 0, IIC_VCNTiD, "vcnt", "8", v8i8, v8i8, int_arm_neon_vcnt>; def VCNTq : N2VQInt<0b11, 0b11, 0b00, 0b00, 0b01010, 0, @@ -3249,98 +4095,126 @@ def VCNTq : N2VQInt<0b11, 0b11, 0b00, 0b00, 0b01010, 0, // Vector Swap -- for disassembly only. def VSWPd : N2VX<0b11, 0b11, 0b00, 0b10, 0b00000, 0, 0, - (outs DPR:$dst), (ins DPR:$src), NoItinerary, - "vswp", "$dst, $src", "", []>; + (outs DPR:$Vd), (ins DPR:$Vm), NoItinerary, + "vswp", "$Vd, $Vm", "", []>; def VSWPq : N2VX<0b11, 0b11, 0b00, 0b10, 0b00000, 1, 0, - (outs QPR:$dst), (ins QPR:$src), NoItinerary, - "vswp", "$dst, $src", "", []>; + (outs QPR:$Vd), (ins QPR:$Vm), NoItinerary, + "vswp", "$Vd, $Vm", "", []>; // Vector Move Operations. // VMOV : Vector Move (Register) let neverHasSideEffects = 1 in { -def VMOVDneon: N3VX<0, 0, 0b10, 0b0001, 0, 1, (outs DPR:$dst), (ins DPR:$src), - N3RegFrm, IIC_VMOVD, "vmov", "$dst, $src", "", []>; -def VMOVQ : N3VX<0, 0, 0b10, 0b0001, 1, 1, (outs QPR:$dst), (ins QPR:$src), - N3RegFrm, IIC_VMOVD, "vmov", "$dst, $src", "", []>; +def VMOVDneon: N3VX<0, 0, 0b10, 0b0001, 0, 1, (outs DPR:$Vd), (ins DPR:$Vm), + N3RegFrm, IIC_VMOV, "vmov", "$Vd, $Vm", "", []> { + let Vn{4-0} = Vm{4-0}; +} +def VMOVQ : N3VX<0, 0, 0b10, 0b0001, 1, 1, (outs QPR:$Vd), (ins QPR:$Vm), + N3RegFrm, IIC_VMOV, "vmov", "$Vd, $Vm", "", []> { + let Vn{4-0} = Vm{4-0}; +} // Pseudo vector move instructions for QQ and QQQQ registers. This should // be expanded after register allocation is completed. def VMOVQQ : PseudoInst<(outs QQPR:$dst), (ins QQPR:$src), - NoItinerary, "${:comment} vmov\t$dst, $src", []>; + NoItinerary, []>; def VMOVQQQQ : PseudoInst<(outs QQQQPR:$dst), (ins QQQQPR:$src), - NoItinerary, "${:comment} vmov\t$dst, $src", []>; + NoItinerary, []>; } // neverHasSideEffects // VMOV : Vector Move (Immediate) let isReMaterializable = 1 in { -def VMOVv8i8 : N1ModImm<1, 0b000, 0b1110, 0, 0, 0, 1, (outs DPR:$dst), +def VMOVv8i8 : N1ModImm<1, 0b000, 0b1110, 0, 0, 0, 1, (outs DPR:$Vd), (ins nModImm:$SIMM), IIC_VMOVImm, - "vmov", "i8", "$dst, $SIMM", "", - [(set DPR:$dst, (v8i8 (NEONvmovImm timm:$SIMM)))]>; -def VMOVv16i8 : N1ModImm<1, 0b000, 0b1110, 0, 1, 0, 1, (outs QPR:$dst), + "vmov", "i8", "$Vd, $SIMM", "", + [(set DPR:$Vd, (v8i8 (NEONvmovImm timm:$SIMM)))]>; +def VMOVv16i8 : N1ModImm<1, 0b000, 0b1110, 0, 1, 0, 1, (outs QPR:$Vd), (ins nModImm:$SIMM), IIC_VMOVImm, - "vmov", "i8", "$dst, $SIMM", "", - [(set QPR:$dst, (v16i8 (NEONvmovImm timm:$SIMM)))]>; + "vmov", "i8", "$Vd, $SIMM", "", + [(set QPR:$Vd, (v16i8 (NEONvmovImm timm:$SIMM)))]>; -def VMOVv4i16 : N1ModImm<1, 0b000, {1,0,?,0}, 0, 0, 0, 1, (outs DPR:$dst), +def VMOVv4i16 : N1ModImm<1, 0b000, {1,0,?,0}, 0, 0, 0, 1, (outs DPR:$Vd), (ins nModImm:$SIMM), IIC_VMOVImm, - "vmov", "i16", "$dst, $SIMM", "", - [(set DPR:$dst, (v4i16 (NEONvmovImm timm:$SIMM)))]>; -def VMOVv8i16 : N1ModImm<1, 0b000, {1,0,?,0}, 0, 1, 0, 1, (outs QPR:$dst), + "vmov", "i16", "$Vd, $SIMM", "", + [(set DPR:$Vd, (v4i16 (NEONvmovImm timm:$SIMM)))]> { + let Inst{9} = SIMM{9}; +} + +def VMOVv8i16 : N1ModImm<1, 0b000, {1,0,?,0}, 0, 1, 0, 1, (outs QPR:$Vd), (ins nModImm:$SIMM), IIC_VMOVImm, - "vmov", "i16", "$dst, $SIMM", "", - [(set QPR:$dst, (v8i16 (NEONvmovImm timm:$SIMM)))]>; + "vmov", "i16", "$Vd, $SIMM", "", + [(set QPR:$Vd, (v8i16 (NEONvmovImm timm:$SIMM)))]> { + let Inst{9} = SIMM{9}; +} -def VMOVv2i32 : N1ModImm<1, 0b000, {?,?,?,?}, 0, 0, 0, 1, (outs DPR:$dst), +def VMOVv2i32 : N1ModImm<1, 0b000, {?,?,?,?}, 0, 0, 0, 1, (outs DPR:$Vd), (ins nModImm:$SIMM), IIC_VMOVImm, - "vmov", "i32", "$dst, $SIMM", "", - [(set DPR:$dst, (v2i32 (NEONvmovImm timm:$SIMM)))]>; -def VMOVv4i32 : N1ModImm<1, 0b000, {?,?,?,?}, 0, 1, 0, 1, (outs QPR:$dst), + "vmov", "i32", "$Vd, $SIMM", "", + [(set DPR:$Vd, (v2i32 (NEONvmovImm timm:$SIMM)))]> { + let Inst{11-8} = SIMM{11-8}; +} + +def VMOVv4i32 : N1ModImm<1, 0b000, {?,?,?,?}, 0, 1, 0, 1, (outs QPR:$Vd), (ins nModImm:$SIMM), IIC_VMOVImm, - "vmov", "i32", "$dst, $SIMM", "", - [(set QPR:$dst, (v4i32 (NEONvmovImm timm:$SIMM)))]>; + "vmov", "i32", "$Vd, $SIMM", "", + [(set QPR:$Vd, (v4i32 (NEONvmovImm timm:$SIMM)))]> { + let Inst{11-8} = SIMM{11-8}; +} -def VMOVv1i64 : N1ModImm<1, 0b000, 0b1110, 0, 0, 1, 1, (outs DPR:$dst), +def VMOVv1i64 : N1ModImm<1, 0b000, 0b1110, 0, 0, 1, 1, (outs DPR:$Vd), (ins nModImm:$SIMM), IIC_VMOVImm, - "vmov", "i64", "$dst, $SIMM", "", - [(set DPR:$dst, (v1i64 (NEONvmovImm timm:$SIMM)))]>; -def VMOVv2i64 : N1ModImm<1, 0b000, 0b1110, 0, 1, 1, 1, (outs QPR:$dst), + "vmov", "i64", "$Vd, $SIMM", "", + [(set DPR:$Vd, (v1i64 (NEONvmovImm timm:$SIMM)))]>; +def VMOVv2i64 : N1ModImm<1, 0b000, 0b1110, 0, 1, 1, 1, (outs QPR:$Vd), (ins nModImm:$SIMM), IIC_VMOVImm, - "vmov", "i64", "$dst, $SIMM", "", - [(set QPR:$dst, (v2i64 (NEONvmovImm timm:$SIMM)))]>; + "vmov", "i64", "$Vd, $SIMM", "", + [(set QPR:$Vd, (v2i64 (NEONvmovImm timm:$SIMM)))]>; } // isReMaterializable // VMOV : Vector Get Lane (move scalar to ARM core register) def VGETLNs8 : NVGetLane<{1,1,1,0,0,1,?,1}, 0b1011, {?,?}, - (outs GPR:$dst), (ins DPR:$src, nohash_imm:$lane), - IIC_VMOVSI, "vmov", "s8", "$dst, $src[$lane]", - [(set GPR:$dst, (NEONvgetlanes (v8i8 DPR:$src), - imm:$lane))]>; + (outs GPR:$R), (ins DPR:$V, nohash_imm:$lane), + IIC_VMOVSI, "vmov", "s8", "$R, $V[$lane]", + [(set GPR:$R, (NEONvgetlanes (v8i8 DPR:$V), + imm:$lane))]> { + let Inst{21} = lane{2}; + let Inst{6-5} = lane{1-0}; +} def VGETLNs16 : NVGetLane<{1,1,1,0,0,0,?,1}, 0b1011, {?,1}, - (outs GPR:$dst), (ins DPR:$src, nohash_imm:$lane), - IIC_VMOVSI, "vmov", "s16", "$dst, $src[$lane]", - [(set GPR:$dst, (NEONvgetlanes (v4i16 DPR:$src), - imm:$lane))]>; + (outs GPR:$R), (ins DPR:$V, nohash_imm:$lane), + IIC_VMOVSI, "vmov", "s16", "$R, $V[$lane]", + [(set GPR:$R, (NEONvgetlanes (v4i16 DPR:$V), + imm:$lane))]> { + let Inst{21} = lane{1}; + let Inst{6} = lane{0}; +} def VGETLNu8 : NVGetLane<{1,1,1,0,1,1,?,1}, 0b1011, {?,?}, - (outs GPR:$dst), (ins DPR:$src, nohash_imm:$lane), - IIC_VMOVSI, "vmov", "u8", "$dst, $src[$lane]", - [(set GPR:$dst, (NEONvgetlaneu (v8i8 DPR:$src), - imm:$lane))]>; + (outs GPR:$R), (ins DPR:$V, nohash_imm:$lane), + IIC_VMOVSI, "vmov", "u8", "$R, $V[$lane]", + [(set GPR:$R, (NEONvgetlaneu (v8i8 DPR:$V), + imm:$lane))]> { + let Inst{21} = lane{2}; + let Inst{6-5} = lane{1-0}; +} def VGETLNu16 : NVGetLane<{1,1,1,0,1,0,?,1}, 0b1011, {?,1}, - (outs GPR:$dst), (ins DPR:$src, nohash_imm:$lane), - IIC_VMOVSI, "vmov", "u16", "$dst, $src[$lane]", - [(set GPR:$dst, (NEONvgetlaneu (v4i16 DPR:$src), - imm:$lane))]>; + (outs GPR:$R), (ins DPR:$V, nohash_imm:$lane), + IIC_VMOVSI, "vmov", "u16", "$R, $V[$lane]", + [(set GPR:$R, (NEONvgetlaneu (v4i16 DPR:$V), + imm:$lane))]> { + let Inst{21} = lane{1}; + let Inst{6} = lane{0}; +} def VGETLNi32 : NVGetLane<{1,1,1,0,0,0,?,1}, 0b1011, 0b00, - (outs GPR:$dst), (ins DPR:$src, nohash_imm:$lane), - IIC_VMOVSI, "vmov", "32", "$dst, $src[$lane]", - [(set GPR:$dst, (extractelt (v2i32 DPR:$src), - imm:$lane))]>; + (outs GPR:$R), (ins DPR:$V, nohash_imm:$lane), + IIC_VMOVSI, "vmov", "32", "$R, $V[$lane]", + [(set GPR:$R, (extractelt (v2i32 DPR:$V), + imm:$lane))]> { + let Inst{21} = lane{0}; +} // def VGETLNf32: see FMRDH and FMRDL in ARMInstrVFP.td def : Pat<(NEONvgetlanes (v16i8 QPR:$src), imm:$lane), (VGETLNs8 (v8i8 (EXTRACT_SUBREG QPR:$src, @@ -3376,37 +4250,45 @@ def : Pat<(extractelt (v2f64 QPR:$src1), imm:$src2), // VMOV : Vector Set Lane (move ARM core register to scalar) -let Constraints = "$src1 = $dst" in { -def VSETLNi8 : NVSetLane<{1,1,1,0,0,1,?,0}, 0b1011, {?,?}, (outs DPR:$dst), - (ins DPR:$src1, GPR:$src2, nohash_imm:$lane), - IIC_VMOVISL, "vmov", "8", "$dst[$lane], $src2", - [(set DPR:$dst, (vector_insert (v8i8 DPR:$src1), - GPR:$src2, imm:$lane))]>; -def VSETLNi16 : NVSetLane<{1,1,1,0,0,0,?,0}, 0b1011, {?,1}, (outs DPR:$dst), - (ins DPR:$src1, GPR:$src2, nohash_imm:$lane), - IIC_VMOVISL, "vmov", "16", "$dst[$lane], $src2", - [(set DPR:$dst, (vector_insert (v4i16 DPR:$src1), - GPR:$src2, imm:$lane))]>; -def VSETLNi32 : NVSetLane<{1,1,1,0,0,0,?,0}, 0b1011, 0b00, (outs DPR:$dst), - (ins DPR:$src1, GPR:$src2, nohash_imm:$lane), - IIC_VMOVISL, "vmov", "32", "$dst[$lane], $src2", - [(set DPR:$dst, (insertelt (v2i32 DPR:$src1), - GPR:$src2, imm:$lane))]>; +let Constraints = "$src1 = $V" in { +def VSETLNi8 : NVSetLane<{1,1,1,0,0,1,?,0}, 0b1011, {?,?}, (outs DPR:$V), + (ins DPR:$src1, GPR:$R, nohash_imm:$lane), + IIC_VMOVISL, "vmov", "8", "$V[$lane], $R", + [(set DPR:$V, (vector_insert (v8i8 DPR:$src1), + GPR:$R, imm:$lane))]> { + let Inst{21} = lane{2}; + let Inst{6-5} = lane{1-0}; +} +def VSETLNi16 : NVSetLane<{1,1,1,0,0,0,?,0}, 0b1011, {?,1}, (outs DPR:$V), + (ins DPR:$src1, GPR:$R, nohash_imm:$lane), + IIC_VMOVISL, "vmov", "16", "$V[$lane], $R", + [(set DPR:$V, (vector_insert (v4i16 DPR:$src1), + GPR:$R, imm:$lane))]> { + let Inst{21} = lane{1}; + let Inst{6} = lane{0}; +} +def VSETLNi32 : NVSetLane<{1,1,1,0,0,0,?,0}, 0b1011, 0b00, (outs DPR:$V), + (ins DPR:$src1, GPR:$R, nohash_imm:$lane), + IIC_VMOVISL, "vmov", "32", "$V[$lane], $R", + [(set DPR:$V, (insertelt (v2i32 DPR:$src1), + GPR:$R, imm:$lane))]> { + let Inst{21} = lane{0}; +} } def : Pat<(vector_insert (v16i8 QPR:$src1), GPR:$src2, imm:$lane), - (v16i8 (INSERT_SUBREG QPR:$src1, + (v16i8 (INSERT_SUBREG QPR:$src1, (v8i8 (VSETLNi8 (v8i8 (EXTRACT_SUBREG QPR:$src1, (DSubReg_i8_reg imm:$lane))), GPR:$src2, (SubReg_i8_lane imm:$lane))), (DSubReg_i8_reg imm:$lane)))>; def : Pat<(vector_insert (v8i16 QPR:$src1), GPR:$src2, imm:$lane), - (v8i16 (INSERT_SUBREG QPR:$src1, + (v8i16 (INSERT_SUBREG QPR:$src1, (v4i16 (VSETLNi16 (v4i16 (EXTRACT_SUBREG QPR:$src1, (DSubReg_i16_reg imm:$lane))), GPR:$src2, (SubReg_i16_lane imm:$lane))), (DSubReg_i16_reg imm:$lane)))>; def : Pat<(insertelt (v4i32 QPR:$src1), GPR:$src2, imm:$lane), - (v4i32 (INSERT_SUBREG QPR:$src1, + (v4i32 (INSERT_SUBREG QPR:$src1, (v2i32 (VSETLNi32 (v2i32 (EXTRACT_SUBREG QPR:$src1, (DSubReg_i32_reg imm:$lane))), GPR:$src2, (SubReg_i32_lane imm:$lane))), @@ -3454,13 +4336,13 @@ def : Pat<(v4i32 (scalar_to_vector GPR:$src)), // VDUP : Vector Duplicate (from ARM core register to all elements) class VDUPD opcod1, bits<2> opcod3, string Dt, ValueType Ty> - : NVDup; + : NVDup; class VDUPQ opcod1, bits<2> opcod3, string Dt, ValueType Ty> - : NVDup; + : NVDup; def VDUP8d : VDUPD<0b11101100, 0b00, "8", v8i8>; def VDUP16d : VDUPD<0b11101000, 0b01, "16", v4i16>; @@ -3469,40 +4351,56 @@ def VDUP8q : VDUPQ<0b11101110, 0b00, "8", v16i8>; def VDUP16q : VDUPQ<0b11101010, 0b01, "16", v8i16>; def VDUP32q : VDUPQ<0b11101010, 0b00, "32", v4i32>; -def VDUPfd : NVDup<0b11101000, 0b1011, 0b00, (outs DPR:$dst), (ins GPR:$src), - IIC_VMOVIS, "vdup", "32", "$dst, $src", - [(set DPR:$dst, (v2f32 (NEONvdup - (f32 (bitconvert GPR:$src)))))]>; -def VDUPfq : NVDup<0b11101010, 0b1011, 0b00, (outs QPR:$dst), (ins GPR:$src), - IIC_VMOVIS, "vdup", "32", "$dst, $src", - [(set QPR:$dst, (v4f32 (NEONvdup - (f32 (bitconvert GPR:$src)))))]>; +def VDUPfd : NVDup<0b11101000, 0b1011, 0b00, (outs DPR:$V), (ins GPR:$R), + IIC_VMOVIS, "vdup", "32", "$V, $R", + [(set DPR:$V, (v2f32 (NEONvdup + (f32 (bitconvert GPR:$R)))))]>; +def VDUPfq : NVDup<0b11101010, 0b1011, 0b00, (outs QPR:$V), (ins GPR:$R), + IIC_VMOVIS, "vdup", "32", "$V, $R", + [(set QPR:$V, (v4f32 (NEONvdup + (f32 (bitconvert GPR:$R)))))]>; // VDUP : Vector Duplicate Lane (from scalar to all elements) class VDUPLND op19_16, string OpcodeStr, string Dt, ValueType Ty> - : NVDupLane; + : NVDupLane; class VDUPLNQ op19_16, string OpcodeStr, string Dt, ValueType ResTy, ValueType OpTy> - : NVDupLane; // Inst{19-16} is partially specified depending on the element size. -def VDUPLN8d : VDUPLND<{?,?,?,1}, "vdup", "8", v8i8>; -def VDUPLN16d : VDUPLND<{?,?,1,0}, "vdup", "16", v4i16>; -def VDUPLN32d : VDUPLND<{?,1,0,0}, "vdup", "32", v2i32>; -def VDUPLNfd : VDUPLND<{?,1,0,0}, "vdup", "32", v2f32>; -def VDUPLN8q : VDUPLNQ<{?,?,?,1}, "vdup", "8", v16i8, v8i8>; -def VDUPLN16q : VDUPLNQ<{?,?,1,0}, "vdup", "16", v8i16, v4i16>; -def VDUPLN32q : VDUPLNQ<{?,1,0,0}, "vdup", "32", v4i32, v2i32>; -def VDUPLNfq : VDUPLNQ<{?,1,0,0}, "vdup", "32", v4f32, v2f32>; +def VDUPLN8d : VDUPLND<{?,?,?,1}, "vdup", "8", v8i8> { + let Inst{19-17} = lane{2-0}; +} +def VDUPLN16d : VDUPLND<{?,?,1,0}, "vdup", "16", v4i16> { + let Inst{19-18} = lane{1-0}; +} +def VDUPLN32d : VDUPLND<{?,1,0,0}, "vdup", "32", v2i32> { + let Inst{19} = lane{0}; +} +def VDUPLNfd : VDUPLND<{?,1,0,0}, "vdup", "32", v2f32> { + let Inst{19} = lane{0}; +} +def VDUPLN8q : VDUPLNQ<{?,?,?,1}, "vdup", "8", v16i8, v8i8> { + let Inst{19-17} = lane{2-0}; +} +def VDUPLN16q : VDUPLNQ<{?,?,1,0}, "vdup", "16", v8i16, v4i16> { + let Inst{19-18} = lane{1-0}; +} +def VDUPLN32q : VDUPLNQ<{?,1,0,0}, "vdup", "32", v4i32, v2i32> { + let Inst{19} = lane{0}; +} +def VDUPLNfq : VDUPLNQ<{?,1,0,0}, "vdup", "32", v4f32, v2f32> { + let Inst{19} = lane{0}; +} def : Pat<(v16i8 (NEONvduplane (v16i8 QPR:$src), imm:$lane)), (v16i8 (VDUPLN8q (v8i8 (EXTRACT_SUBREG QPR:$src, @@ -3521,18 +4419,13 @@ def : Pat<(v4f32 (NEONvduplane (v4f32 QPR:$src), imm:$lane)), (DSubReg_i32_reg imm:$lane))), (SubReg_i32_lane imm:$lane)))>; -def VDUPfdf : N2V<0b11, 0b11, {?,1}, {0,0}, 0b11000, 0, 0, - (outs DPR:$dst), (ins SPR:$src), - IIC_VMOVD, "vdup", "32", "$dst, ${src:lane}", "", +def VDUPfdf : PseudoNeonI<(outs DPR:$dst), (ins SPR:$src), IIC_VMOVD, "", [(set DPR:$dst, (v2f32 (NEONvdup (f32 SPR:$src))))]>; - -def VDUPfqf : N2V<0b11, 0b11, {?,1}, {0,0}, 0b11000, 1, 0, - (outs QPR:$dst), (ins SPR:$src), - IIC_VMOVD, "vdup", "32", "$dst, ${src:lane}", "", +def VDUPfqf : PseudoNeonI<(outs QPR:$dst), (ins SPR:$src), IIC_VMOVD, "", [(set QPR:$dst, (v4f32 (NEONvdup (f32 SPR:$src))))]>; // VMOVN : Vector Narrowing Move -defm VMOVN : N2VN_HSD<0b11,0b11,0b10,0b00100,0,0, IIC_VMOVD, +defm VMOVN : N2VN_HSD<0b11,0b11,0b10,0b00100,0,0, IIC_VMOVN, "vmovn", "i", trunc>; // VQMOVN : Vector Saturating Narrowing Move defm VQMOVNs : N2VNInt_HSD<0b11,0b11,0b10,0b00101,0,0, IIC_VQUNAiD, @@ -3585,20 +4478,30 @@ def VCVTxs2fq : N2VCvtQ<0, 1, 0b1110, 0, 1, "vcvt", "f32.s32", def VCVTxu2fq : N2VCvtQ<1, 1, 0b1110, 0, 1, "vcvt", "f32.u32", v4f32, v4i32, int_arm_neon_vcvtfxu2fp>; +// VCVT : Vector Convert Between Half-Precision and Single-Precision. +def VCVTf2h : N2VNInt<0b11, 0b11, 0b01, 0b10, 0b01100, 0, 0, + IIC_VUNAQ, "vcvt", "f16.f32", + v4i16, v4f32, int_arm_neon_vcvtfp2hf>, + Requires<[HasNEON, HasFP16]>; +def VCVTh2f : N2VLInt<0b11, 0b11, 0b01, 0b10, 0b01110, 0, 0, + IIC_VUNAQ, "vcvt", "f32.f16", + v4f32, v4i16, int_arm_neon_vcvthf2fp>, + Requires<[HasNEON, HasFP16]>; + // Vector Reverse. // VREV64 : Vector Reverse elements within 64-bit doublewords class VREV64D op19_18, string OpcodeStr, string Dt, ValueType Ty> - : N2V<0b11, 0b11, op19_18, 0b00, 0b00000, 0, 0, (outs DPR:$dst), - (ins DPR:$src), IIC_VMOVD, - OpcodeStr, Dt, "$dst, $src", "", - [(set DPR:$dst, (Ty (NEONvrev64 (Ty DPR:$src))))]>; + : N2V<0b11, 0b11, op19_18, 0b00, 0b00000, 0, 0, (outs DPR:$Vd), + (ins DPR:$Vm), IIC_VMOVD, + OpcodeStr, Dt, "$Vd, $Vm", "", + [(set DPR:$Vd, (Ty (NEONvrev64 (Ty DPR:$Vm))))]>; class VREV64Q op19_18, string OpcodeStr, string Dt, ValueType Ty> - : N2V<0b11, 0b11, op19_18, 0b00, 0b00000, 1, 0, (outs QPR:$dst), - (ins QPR:$src), IIC_VMOVD, - OpcodeStr, Dt, "$dst, $src", "", - [(set QPR:$dst, (Ty (NEONvrev64 (Ty QPR:$src))))]>; + : N2V<0b11, 0b11, op19_18, 0b00, 0b00000, 1, 0, (outs QPR:$Vd), + (ins QPR:$Vm), IIC_VMOVQ, + OpcodeStr, Dt, "$Vd, $Vm", "", + [(set QPR:$Vd, (Ty (NEONvrev64 (Ty QPR:$Vm))))]>; def VREV64d8 : VREV64D<0b00, "vrev64", "8", v8i8>; def VREV64d16 : VREV64D<0b01, "vrev64", "16", v4i16>; @@ -3613,15 +4516,15 @@ def VREV64qf : VREV64Q<0b10, "vrev64", "32", v4f32>; // VREV32 : Vector Reverse elements within 32-bit words class VREV32D op19_18, string OpcodeStr, string Dt, ValueType Ty> - : N2V<0b11, 0b11, op19_18, 0b00, 0b00001, 0, 0, (outs DPR:$dst), - (ins DPR:$src), IIC_VMOVD, - OpcodeStr, Dt, "$dst, $src", "", - [(set DPR:$dst, (Ty (NEONvrev32 (Ty DPR:$src))))]>; + : N2V<0b11, 0b11, op19_18, 0b00, 0b00001, 0, 0, (outs DPR:$Vd), + (ins DPR:$Vm), IIC_VMOVD, + OpcodeStr, Dt, "$Vd, $Vm", "", + [(set DPR:$Vd, (Ty (NEONvrev32 (Ty DPR:$Vm))))]>; class VREV32Q op19_18, string OpcodeStr, string Dt, ValueType Ty> - : N2V<0b11, 0b11, op19_18, 0b00, 0b00001, 1, 0, (outs QPR:$dst), - (ins QPR:$src), IIC_VMOVD, - OpcodeStr, Dt, "$dst, $src", "", - [(set QPR:$dst, (Ty (NEONvrev32 (Ty QPR:$src))))]>; + : N2V<0b11, 0b11, op19_18, 0b00, 0b00001, 1, 0, (outs QPR:$Vd), + (ins QPR:$Vm), IIC_VMOVQ, + OpcodeStr, Dt, "$Vd, $Vm", "", + [(set QPR:$Vd, (Ty (NEONvrev32 (Ty QPR:$Vm))))]>; def VREV32d8 : VREV32D<0b00, "vrev32", "8", v8i8>; def VREV32d16 : VREV32D<0b01, "vrev32", "16", v4i16>; @@ -3632,46 +4535,91 @@ def VREV32q16 : VREV32Q<0b01, "vrev32", "16", v8i16>; // VREV16 : Vector Reverse elements within 16-bit halfwords class VREV16D op19_18, string OpcodeStr, string Dt, ValueType Ty> - : N2V<0b11, 0b11, op19_18, 0b00, 0b00010, 0, 0, (outs DPR:$dst), - (ins DPR:$src), IIC_VMOVD, - OpcodeStr, Dt, "$dst, $src", "", - [(set DPR:$dst, (Ty (NEONvrev16 (Ty DPR:$src))))]>; + : N2V<0b11, 0b11, op19_18, 0b00, 0b00010, 0, 0, (outs DPR:$Vd), + (ins DPR:$Vm), IIC_VMOVD, + OpcodeStr, Dt, "$Vd, $Vm", "", + [(set DPR:$Vd, (Ty (NEONvrev16 (Ty DPR:$Vm))))]>; class VREV16Q op19_18, string OpcodeStr, string Dt, ValueType Ty> - : N2V<0b11, 0b11, op19_18, 0b00, 0b00010, 1, 0, (outs QPR:$dst), - (ins QPR:$src), IIC_VMOVD, - OpcodeStr, Dt, "$dst, $src", "", - [(set QPR:$dst, (Ty (NEONvrev16 (Ty QPR:$src))))]>; + : N2V<0b11, 0b11, op19_18, 0b00, 0b00010, 1, 0, (outs QPR:$Vd), + (ins QPR:$Vm), IIC_VMOVQ, + OpcodeStr, Dt, "$Vd, $Vm", "", + [(set QPR:$Vd, (Ty (NEONvrev16 (Ty QPR:$Vm))))]>; def VREV16d8 : VREV16D<0b00, "vrev16", "8", v8i8>; def VREV16q8 : VREV16Q<0b00, "vrev16", "8", v16i8>; // Other Vector Shuffles. +// Aligned extractions: really just dropping registers + +class AlignedVEXTq + : Pat<(DestTy (vector_extract_subvec (SrcTy QPR:$src), (i32 imm:$start))), + (EXTRACT_SUBREG (SrcTy QPR:$src), (LaneCVT imm:$start))>; + +def : AlignedVEXTq; + +def : AlignedVEXTq; + +def : AlignedVEXTq; + +def : AlignedVEXTq; + +def : AlignedVEXTq; + + // VEXT : Vector Extract class VEXTd - : N3V<0,1,0b11,{?,?,?,?},0,0, (outs DPR:$dst), - (ins DPR:$lhs, DPR:$rhs, i32imm:$index), NVExtFrm, - IIC_VEXTD, OpcodeStr, Dt, "$dst, $lhs, $rhs, $index", "", - [(set DPR:$dst, (Ty (NEONvext (Ty DPR:$lhs), - (Ty DPR:$rhs), imm:$index)))]>; + : N3V<0,1,0b11,{?,?,?,?},0,0, (outs DPR:$Vd), + (ins DPR:$Vn, DPR:$Vm, i32imm:$index), NVExtFrm, + IIC_VEXTD, OpcodeStr, Dt, "$Vd, $Vn, $Vm, $index", "", + [(set DPR:$Vd, (Ty (NEONvext (Ty DPR:$Vn), + (Ty DPR:$Vm), imm:$index)))]> { + bits<4> index; + let Inst{11-8} = index{3-0}; +} class VEXTq - : N3V<0,1,0b11,{?,?,?,?},1,0, (outs QPR:$dst), - (ins QPR:$lhs, QPR:$rhs, i32imm:$index), NVExtFrm, - IIC_VEXTQ, OpcodeStr, Dt, "$dst, $lhs, $rhs, $index", "", - [(set QPR:$dst, (Ty (NEONvext (Ty QPR:$lhs), - (Ty QPR:$rhs), imm:$index)))]>; - -def VEXTd8 : VEXTd<"vext", "8", v8i8>; -def VEXTd16 : VEXTd<"vext", "16", v4i16>; -def VEXTd32 : VEXTd<"vext", "32", v2i32>; -def VEXTdf : VEXTd<"vext", "32", v2f32>; - -def VEXTq8 : VEXTq<"vext", "8", v16i8>; -def VEXTq16 : VEXTq<"vext", "16", v8i16>; -def VEXTq32 : VEXTq<"vext", "32", v4i32>; -def VEXTqf : VEXTq<"vext", "32", v4f32>; + : N3V<0,1,0b11,{?,?,?,?},1,0, (outs QPR:$Vd), + (ins QPR:$Vn, QPR:$Vm, i32imm:$index), NVExtFrm, + IIC_VEXTQ, OpcodeStr, Dt, "$Vd, $Vn, $Vm, $index", "", + [(set QPR:$Vd, (Ty (NEONvext (Ty QPR:$Vn), + (Ty QPR:$Vm), imm:$index)))]> { + bits<4> index; + let Inst{11-8} = index{3-0}; +} + +def VEXTd8 : VEXTd<"vext", "8", v8i8> { + let Inst{11-8} = index{3-0}; +} +def VEXTd16 : VEXTd<"vext", "16", v4i16> { + let Inst{11-9} = index{2-0}; + let Inst{8} = 0b0; +} +def VEXTd32 : VEXTd<"vext", "32", v2i32> { + let Inst{11-10} = index{1-0}; + let Inst{9-8} = 0b00; +} +def VEXTdf : VEXTd<"vext", "32", v2f32> { + let Inst{11} = index{0}; + let Inst{10-8} = 0b000; +} + +def VEXTq8 : VEXTq<"vext", "8", v16i8> { + let Inst{11-8} = index{3-0}; +} +def VEXTq16 : VEXTq<"vext", "16", v8i16> { + let Inst{11-9} = index{2-0}; + let Inst{8} = 0b0; +} +def VEXTq32 : VEXTq<"vext", "32", v4i32> { + let Inst{11-10} = index{1-0}; + let Inst{9-8} = 0b00; +} +def VEXTqf : VEXTq<"vext", "32", v4f32> { + let Inst{11} = index{0}; + let Inst{10-8} = 0b000; +} // VTRN : Vector Transpose @@ -3707,160 +4655,120 @@ def VZIPq32 : N2VQShuffle<0b10, 0b00011, IIC_VPERMQ3, "vzip", "32">; // VTBL : Vector Table Lookup def VTBL1 - : N3V<1,1,0b11,0b1000,0,0, (outs DPR:$dst), - (ins DPR:$tbl1, DPR:$src), NVTBLFrm, IIC_VTB1, - "vtbl", "8", "$dst, \\{$tbl1\\}, $src", "", - [(set DPR:$dst, (v8i8 (int_arm_neon_vtbl1 DPR:$tbl1, DPR:$src)))]>; + : N3V<1,1,0b11,0b1000,0,0, (outs DPR:$Vd), + (ins DPR:$Vn, DPR:$Vm), NVTBLFrm, IIC_VTB1, + "vtbl", "8", "$Vd, \\{$Vn\\}, $Vm", "", + [(set DPR:$Vd, (v8i8 (int_arm_neon_vtbl1 DPR:$Vn, DPR:$Vm)))]>; let hasExtraSrcRegAllocReq = 1 in { def VTBL2 - : N3V<1,1,0b11,0b1001,0,0, (outs DPR:$dst), - (ins DPR:$tbl1, DPR:$tbl2, DPR:$src), NVTBLFrm, IIC_VTB2, - "vtbl", "8", "$dst, \\{$tbl1, $tbl2\\}, $src", "", []>; + : N3V<1,1,0b11,0b1001,0,0, (outs DPR:$Vd), + (ins DPR:$Vn, DPR:$tbl2, DPR:$Vm), NVTBLFrm, IIC_VTB2, + "vtbl", "8", "$Vd, \\{$Vn, $tbl2\\}, $Vm", "", []>; def VTBL3 - : N3V<1,1,0b11,0b1010,0,0, (outs DPR:$dst), - (ins DPR:$tbl1, DPR:$tbl2, DPR:$tbl3, DPR:$src), NVTBLFrm, IIC_VTB3, - "vtbl", "8", "$dst, \\{$tbl1, $tbl2, $tbl3\\}, $src", "", []>; + : N3V<1,1,0b11,0b1010,0,0, (outs DPR:$Vd), + (ins DPR:$Vn, DPR:$tbl2, DPR:$tbl3, DPR:$Vm), NVTBLFrm, IIC_VTB3, + "vtbl", "8", "$Vd, \\{$Vn, $tbl2, $tbl3\\}, $Vm", "", []>; def VTBL4 - : N3V<1,1,0b11,0b1011,0,0, (outs DPR:$dst), - (ins DPR:$tbl1, DPR:$tbl2, DPR:$tbl3, DPR:$tbl4, DPR:$src), + : N3V<1,1,0b11,0b1011,0,0, (outs DPR:$Vd), + (ins DPR:$Vn, DPR:$tbl2, DPR:$tbl3, DPR:$tbl4, DPR:$Vm), NVTBLFrm, IIC_VTB4, - "vtbl", "8", "$dst, \\{$tbl1, $tbl2, $tbl3, $tbl4\\}, $src", "", []>; + "vtbl", "8", "$Vd, \\{$Vn, $tbl2, $tbl3, $tbl4\\}, $Vm", "", []>; } // hasExtraSrcRegAllocReq = 1 +def VTBL2Pseudo + : PseudoNeonI<(outs DPR:$dst), (ins QPR:$tbl, DPR:$src), IIC_VTB2, "", []>; +def VTBL3Pseudo + : PseudoNeonI<(outs DPR:$dst), (ins QQPR:$tbl, DPR:$src), IIC_VTB3, "", []>; +def VTBL4Pseudo + : PseudoNeonI<(outs DPR:$dst), (ins QQPR:$tbl, DPR:$src), IIC_VTB4, "", []>; + // VTBX : Vector Table Extension def VTBX1 - : N3V<1,1,0b11,0b1000,1,0, (outs DPR:$dst), - (ins DPR:$orig, DPR:$tbl1, DPR:$src), NVTBLFrm, IIC_VTBX1, - "vtbx", "8", "$dst, \\{$tbl1\\}, $src", "$orig = $dst", - [(set DPR:$dst, (v8i8 (int_arm_neon_vtbx1 - DPR:$orig, DPR:$tbl1, DPR:$src)))]>; + : N3V<1,1,0b11,0b1000,1,0, (outs DPR:$Vd), + (ins DPR:$orig, DPR:$Vn, DPR:$Vm), NVTBLFrm, IIC_VTBX1, + "vtbx", "8", "$Vd, \\{$Vn\\}, $Vm", "$orig = $Vd", + [(set DPR:$Vd, (v8i8 (int_arm_neon_vtbx1 + DPR:$orig, DPR:$Vn, DPR:$Vm)))]>; let hasExtraSrcRegAllocReq = 1 in { def VTBX2 - : N3V<1,1,0b11,0b1001,1,0, (outs DPR:$dst), - (ins DPR:$orig, DPR:$tbl1, DPR:$tbl2, DPR:$src), NVTBLFrm, IIC_VTBX2, - "vtbx", "8", "$dst, \\{$tbl1, $tbl2\\}, $src", "$orig = $dst", []>; + : N3V<1,1,0b11,0b1001,1,0, (outs DPR:$Vd), + (ins DPR:$orig, DPR:$Vn, DPR:$tbl2, DPR:$Vm), NVTBLFrm, IIC_VTBX2, + "vtbx", "8", "$Vd, \\{$Vn, $tbl2\\}, $Vm", "$orig = $Vd", []>; def VTBX3 - : N3V<1,1,0b11,0b1010,1,0, (outs DPR:$dst), - (ins DPR:$orig, DPR:$tbl1, DPR:$tbl2, DPR:$tbl3, DPR:$src), + : N3V<1,1,0b11,0b1010,1,0, (outs DPR:$Vd), + (ins DPR:$orig, DPR:$Vn, DPR:$tbl2, DPR:$tbl3, DPR:$Vm), NVTBLFrm, IIC_VTBX3, - "vtbx", "8", "$dst, \\{$tbl1, $tbl2, $tbl3\\}, $src", - "$orig = $dst", []>; + "vtbx", "8", "$Vd, \\{$Vn, $tbl2, $tbl3\\}, $Vm", + "$orig = $Vd", []>; def VTBX4 - : N3V<1,1,0b11,0b1011,1,0, (outs DPR:$dst), (ins DPR:$orig, DPR:$tbl1, - DPR:$tbl2, DPR:$tbl3, DPR:$tbl4, DPR:$src), NVTBLFrm, IIC_VTBX4, - "vtbx", "8", "$dst, \\{$tbl1, $tbl2, $tbl3, $tbl4\\}, $src", - "$orig = $dst", []>; + : N3V<1,1,0b11,0b1011,1,0, (outs DPR:$Vd), (ins DPR:$orig, DPR:$Vn, + DPR:$tbl2, DPR:$tbl3, DPR:$tbl4, DPR:$Vm), NVTBLFrm, IIC_VTBX4, + "vtbx", "8", "$Vd, \\{$Vn, $tbl2, $tbl3, $tbl4\\}, $Vm", + "$orig = $Vd", []>; } // hasExtraSrcRegAllocReq = 1 +def VTBX2Pseudo + : PseudoNeonI<(outs DPR:$dst), (ins DPR:$orig, QPR:$tbl, DPR:$src), + IIC_VTBX2, "$orig = $dst", []>; +def VTBX3Pseudo + : PseudoNeonI<(outs DPR:$dst), (ins DPR:$orig, QQPR:$tbl, DPR:$src), + IIC_VTBX3, "$orig = $dst", []>; +def VTBX4Pseudo + : PseudoNeonI<(outs DPR:$dst), (ins DPR:$orig, QQPR:$tbl, DPR:$src), + IIC_VTBX4, "$orig = $dst", []>; + //===----------------------------------------------------------------------===// // NEON instructions for single-precision FP math //===----------------------------------------------------------------------===// -class N2VSPat - : NEONFPPat<(ResTy (OpNode SPR:$a)), - (EXTRACT_SUBREG (OpTy (Inst (INSERT_SUBREG (OpTy (IMPLICIT_DEF)), - SPR:$a, ssub_0))), - ssub_0)>; +class N2VSPat + : NEONFPPat<(f32 (OpNode SPR:$a)), + (EXTRACT_SUBREG + (v2f32 (COPY_TO_REGCLASS (Inst + (INSERT_SUBREG + (v2f32 (COPY_TO_REGCLASS (v2f32 (IMPLICIT_DEF)), DPR_VFP2)), + SPR:$a, ssub_0)), DPR_VFP2)), ssub_0)>; class N3VSPat : NEONFPPat<(f32 (OpNode SPR:$a, SPR:$b)), - (EXTRACT_SUBREG (v2f32 - (Inst (INSERT_SUBREG (v2f32 (IMPLICIT_DEF)), - SPR:$a, ssub_0), - (INSERT_SUBREG (v2f32 (IMPLICIT_DEF)), - SPR:$b, ssub_0))), - ssub_0)>; + (EXTRACT_SUBREG + (v2f32 (COPY_TO_REGCLASS (Inst + (INSERT_SUBREG + (v2f32 (COPY_TO_REGCLASS (v2f32 (IMPLICIT_DEF)), DPR_VFP2)), + SPR:$a, ssub_0), + (INSERT_SUBREG + (v2f32 (COPY_TO_REGCLASS (v2f32 (IMPLICIT_DEF)), DPR_VFP2)), + SPR:$b, ssub_0)), DPR_VFP2)), ssub_0)>; class N3VSMulOpPat : NEONFPPat<(f32 (OpNode SPR:$acc, (f32 (MulNode SPR:$a, SPR:$b)))), - (EXTRACT_SUBREG (Inst (INSERT_SUBREG (v2f32 (IMPLICIT_DEF)), - SPR:$acc, ssub_0), - (INSERT_SUBREG (v2f32 (IMPLICIT_DEF)), - SPR:$a, ssub_0), - (INSERT_SUBREG (v2f32 (IMPLICIT_DEF)), - SPR:$b, ssub_0)), - ssub_0)>; - -// These need separate instructions because they must use DPR_VFP2 register -// class which have SPR sub-registers. - -// Vector Add Operations used for single-precision FP -let neverHasSideEffects = 1 in -def VADDfd_sfp : N3VS<0,0,0b00,0b1101,0, "vadd", "f32", v2f32, v2f32, fadd, 1>; -def : N3VSPat; - -// Vector Sub Operations used for single-precision FP -let neverHasSideEffects = 1 in -def VSUBfd_sfp : N3VS<0,0,0b10,0b1101,0, "vsub", "f32", v2f32, v2f32, fsub, 0>; -def : N3VSPat; - -// Vector Multiply Operations used for single-precision FP -let neverHasSideEffects = 1 in -def VMULfd_sfp : N3VS<1,0,0b00,0b1101,1, "vmul", "f32", v2f32, v2f32, fmul, 1>; -def : N3VSPat; - -// Vector Multiply-Accumulate/Subtract used for single-precision FP -// vml[as].f32 can cause 4-8 cycle stalls in following ASIMD instructions, so -// we want to avoid them for now. e.g., alternating vmla/vadd instructions. - -//let neverHasSideEffects = 1 in -//def VMLAfd_sfp : N3VSMulOp<0,0,0b00,0b1101,1, IIC_VMACD, "vmla", "f32", -// v2f32, fmul, fadd>; -//def : N3VSMulOpPat; - -//let neverHasSideEffects = 1 in -//def VMLSfd_sfp : N3VSMulOp<0,0,0b10,0b1101,1, IIC_VMACD, "vmls", "f32", -// v2f32, fmul, fsub>; -//def : N3VSMulOpPat; - -// Vector Absolute used for single-precision FP -let neverHasSideEffects = 1 in -def VABSfd_sfp : N2V<0b11, 0b11, 0b10, 0b01, 0b01110, 0, 0, - (outs DPR_VFP2:$dst), (ins DPR_VFP2:$src), IIC_VUNAD, - "vabs", "f32", "$dst, $src", "", []>; -def : N2VSPat; - -// Vector Negate used for single-precision FP -let neverHasSideEffects = 1 in -def VNEGfd_sfp : N2V<0b11, 0b11, 0b10, 0b01, 0b01111, 0, 0, - (outs DPR_VFP2:$dst), (ins DPR_VFP2:$src), IIC_VUNAD, - "vneg", "f32", "$dst, $src", "", []>; -def : N2VSPat; - -// Vector Maximum used for single-precision FP -let neverHasSideEffects = 1 in -def VMAXfd_sfp : N3V<0, 0, 0b00, 0b1111, 0, 0, (outs DPR_VFP2:$dst), - (ins DPR_VFP2:$src1, DPR_VFP2:$src2), N3RegFrm, IIC_VBIND, - "vmax", "f32", "$dst, $src1, $src2", "", []>; -def : N3VSPat; - -// Vector Minimum used for single-precision FP -let neverHasSideEffects = 1 in -def VMINfd_sfp : N3V<0, 0, 0b00, 0b1111, 0, 0, (outs DPR_VFP2:$dst), - (ins DPR_VFP2:$src1, DPR_VFP2:$src2), N3RegFrm, IIC_VBIND, - "vmin", "f32", "$dst, $src1, $src2", "", []>; -def : N3VSPat; - -// Vector Convert between single-precision FP and integer -let neverHasSideEffects = 1 in -def VCVTf2sd_sfp : N2VS<0b11, 0b11, 0b10, 0b11, 0b01110, 0, "vcvt", "s32.f32", - v2i32, v2f32, fp_to_sint>; -def : N2VSPat; - -let neverHasSideEffects = 1 in -def VCVTf2ud_sfp : N2VS<0b11, 0b11, 0b10, 0b11, 0b01111, 0, "vcvt", "u32.f32", - v2i32, v2f32, fp_to_uint>; -def : N2VSPat; - -let neverHasSideEffects = 1 in -def VCVTs2fd_sfp : N2VS<0b11, 0b11, 0b10, 0b11, 0b01100, 0, "vcvt", "f32.s32", - v2f32, v2i32, sint_to_fp>; -def : N2VSPat; - -let neverHasSideEffects = 1 in -def VCVTu2fd_sfp : N2VS<0b11, 0b11, 0b10, 0b11, 0b01101, 0, "vcvt", "f32.u32", - v2f32, v2i32, uint_to_fp>; -def : N2VSPat; + (EXTRACT_SUBREG + (v2f32 (COPY_TO_REGCLASS (Inst + (INSERT_SUBREG + (v2f32 (COPY_TO_REGCLASS (v2f32 (IMPLICIT_DEF)), DPR_VFP2)), + SPR:$acc, ssub_0), + (INSERT_SUBREG + (v2f32 (COPY_TO_REGCLASS (v2f32 (IMPLICIT_DEF)), DPR_VFP2)), + SPR:$a, ssub_0), + (INSERT_SUBREG + (v2f32 (COPY_TO_REGCLASS (v2f32 (IMPLICIT_DEF)), DPR_VFP2)), + SPR:$b, ssub_0)), DPR_VFP2)), ssub_0)>; + +def : N3VSPat; +def : N3VSPat; +def : N3VSPat; +def : N3VSMulOpPat, + Requires<[HasNEON, UseNEONForFP, UseFPVMLx]>; +def : N3VSMulOpPat, + Requires<[HasNEON, UseNEONForFP, UseFPVMLx]>; +def : N2VSPat; +def : N2VSPat; +def : N3VSPat; +def : N3VSPat; +def : N2VSPat; +def : N2VSPat; +def : N2VSPat; +def : N2VSPat; //===----------------------------------------------------------------------===// // Non-Instruction Patterns diff --git a/lib/Target/ARM/ARMInstrThumb.td b/lib/Target/ARM/ARMInstrThumb.td index a13ff1232749..826ef46bcdb5 100644 --- a/lib/Target/ARM/ARMInstrThumb.td +++ b/lib/Target/ARM/ARMInstrThumb.td @@ -1,4 +1,4 @@ -//===- ARMInstrThumb.td - Thumb support for ARM ---------------------------===// +//===- ARMInstrThumb.td - Thumb support for ARM ------------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // @@ -16,7 +16,7 @@ // def ARMtcall : SDNode<"ARMISD::tCALL", SDT_ARMcall, - [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, SDNPVariadic]>; def imm_neg_XFORM : SDNodeXFormgetTargetConstant(~((uint32_t)N->getZExtValue()), MVT::i32); }]>; - /// imm0_7 predicate - True if the 32-bit immediate is in the range [0,7]. def imm0_7 : PatLeaf<(i32 imm), [{ return (uint32_t)N->getZExtValue() < 8; @@ -50,9 +49,9 @@ def imm8_255_neg : PatLeaf<(i32 imm), [{ return Val >= 8 && Val < 256; }], imm_neg_XFORM>; -// Break imm's up into two pieces: an immediate + a left shift. -// This uses thumb_immshifted to match and thumb_immshifted_val and -// thumb_immshifted_shamt to get the val/shift pieces. +// Break imm's up into two pieces: an immediate + a left shift. This uses +// thumb_immshifted to match and thumb_immshifted_val and thumb_immshifted_shamt +// to get the val/shift pieces. def thumb_immshifted : PatLeaf<(imm), [{ return ARM_AM::isThumbImmShiftedVal((unsigned)N->getZExtValue()); }]>; @@ -67,6 +66,11 @@ def thumb_immshifted_shamt : SDNodeXFormgetTargetConstant(V, MVT::i32); }]>; +// ADR instruction labels. +def t_adrlabel : Operand { + let EncoderMethod = "getThumbAdrLabelOpValue"; +} + // Scaled 4 immediate. def t_imm_s4 : Operand { let PrintMethod = "printThumbS4ImmOperand"; @@ -74,47 +78,114 @@ def t_imm_s4 : Operand { // Define Thumb specific addressing modes. +def t_brtarget : Operand { + let EncoderMethod = "getThumbBRTargetOpValue"; +} + +def t_bcctarget : Operand { + let EncoderMethod = "getThumbBCCTargetOpValue"; +} + +def t_cbtarget : Operand { + let EncoderMethod = "getThumbCBTargetOpValue"; +} + +def t_bltarget : Operand { + let EncoderMethod = "getThumbBLTargetOpValue"; +} + +def t_blxtarget : Operand { + let EncoderMethod = "getThumbBLXTargetOpValue"; +} + +def MemModeRegThumbAsmOperand : AsmOperandClass { + let Name = "MemModeRegThumb"; + let SuperClasses = []; +} + +def MemModeImmThumbAsmOperand : AsmOperandClass { + let Name = "MemModeImmThumb"; + let SuperClasses = []; +} + // t_addrmode_rr := reg + reg // def t_addrmode_rr : Operand, ComplexPattern { + let EncoderMethod = "getThumbAddrModeRegRegOpValue"; let PrintMethod = "printThumbAddrModeRROperand"; let MIOperandInfo = (ops tGPR:$base, tGPR:$offsreg); } -// t_addrmode_s4 := reg + reg -// reg + imm5 * 4 +// t_addrmode_rrs := reg + reg // -def t_addrmode_s4 : Operand, - ComplexPattern { - let PrintMethod = "printThumbAddrModeS4Operand"; - let MIOperandInfo = (ops tGPR:$base, i32imm:$offsimm, tGPR:$offsreg); +def t_addrmode_rrs1 : Operand, + ComplexPattern { + let EncoderMethod = "getThumbAddrModeRegRegOpValue"; + let PrintMethod = "printThumbAddrModeRROperand"; + let MIOperandInfo = (ops tGPR:$base, tGPR:$offsreg); + let ParserMatchClass = MemModeRegThumbAsmOperand; +} +def t_addrmode_rrs2 : Operand, + ComplexPattern { + let EncoderMethod = "getThumbAddrModeRegRegOpValue"; + let PrintMethod = "printThumbAddrModeRROperand"; + let MIOperandInfo = (ops tGPR:$base, tGPR:$offsreg); + let ParserMatchClass = MemModeRegThumbAsmOperand; +} +def t_addrmode_rrs4 : Operand, + ComplexPattern { + let EncoderMethod = "getThumbAddrModeRegRegOpValue"; + let PrintMethod = "printThumbAddrModeRROperand"; + let MIOperandInfo = (ops tGPR:$base, tGPR:$offsreg); + let ParserMatchClass = MemModeRegThumbAsmOperand; +} + +// t_addrmode_is4 := reg + imm5 * 4 +// +def t_addrmode_is4 : Operand, + ComplexPattern { + let EncoderMethod = "getAddrModeISOpValue"; + let PrintMethod = "printThumbAddrModeImm5S4Operand"; + let MIOperandInfo = (ops tGPR:$base, i32imm:$offsimm); + let ParserMatchClass = MemModeImmThumbAsmOperand; } -// t_addrmode_s2 := reg + reg -// reg + imm5 * 2 +// t_addrmode_is2 := reg + imm5 * 2 // -def t_addrmode_s2 : Operand, - ComplexPattern { - let PrintMethod = "printThumbAddrModeS2Operand"; - let MIOperandInfo = (ops tGPR:$base, i32imm:$offsimm, tGPR:$offsreg); +def t_addrmode_is2 : Operand, + ComplexPattern { + let EncoderMethod = "getAddrModeISOpValue"; + let PrintMethod = "printThumbAddrModeImm5S2Operand"; + let MIOperandInfo = (ops tGPR:$base, i32imm:$offsimm); + let ParserMatchClass = MemModeImmThumbAsmOperand; } -// t_addrmode_s1 := reg + reg -// reg + imm5 +// t_addrmode_is1 := reg + imm5 // -def t_addrmode_s1 : Operand, - ComplexPattern { - let PrintMethod = "printThumbAddrModeS1Operand"; - let MIOperandInfo = (ops tGPR:$base, i32imm:$offsimm, tGPR:$offsreg); +def t_addrmode_is1 : Operand, + ComplexPattern { + let EncoderMethod = "getAddrModeISOpValue"; + let PrintMethod = "printThumbAddrModeImm5S1Operand"; + let MIOperandInfo = (ops tGPR:$base, i32imm:$offsimm); + let ParserMatchClass = MemModeImmThumbAsmOperand; } // t_addrmode_sp := sp + imm8 * 4 // def t_addrmode_sp : Operand, ComplexPattern { + let EncoderMethod = "getAddrModeThumbSPOpValue"; let PrintMethod = "printThumbAddrModeSPOperand"; let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); + let ParserMatchClass = MemModeImmThumbAsmOperand; +} + +// t_addrmode_pc :=
  • -loop-rotateRotate Loops
    -loop-unrollUnroll loops
    -loop-unswitchUnswitch loops
    -loopsimplifyCanonicalize natural loops
    -loop-simplifyCanonicalize natural loops
    -loweratomicLower atomic intrinsics
    -lowerinvokeLower invoke and unwind, for unwindless code generators
    -lowersetjmpLower Set Jump
    ") +rf.write(str(sys.argv[1])) +rf.write("|") +rf.write(str(nf1_arg_count)) +rf.write("") +rf.write(str(nf1_matching_arg_count)) +rf.write("") +rf.write(str(nf1_notmatching_arg_count)) +rf.write("") +rf.write(str(nf1_missing_arg_count)) +rf.write("|") +rf.write(str(f1_arg_count)) +rf.write("") +rf.write(str(f1_matching_arg_count)) +rf.write("") +rf.write(str(f1_notmatching_arg_count)) +rf.write("") +rf.write(str(f1_missing_arg_count)) +rf.write("\n") +rf.close() diff --git a/utils/FileCheck/CMakeLists.txt b/utils/FileCheck/CMakeLists.txt index 8fee03fb57b0..54db453e70e8 100644 --- a/utils/FileCheck/CMakeLists.txt +++ b/utils/FileCheck/CMakeLists.txt @@ -2,7 +2,7 @@ add_executable(FileCheck FileCheck.cpp ) -target_link_libraries(FileCheck LLVMSupport LLVMSystem) +target_link_libraries(FileCheck LLVMSupport) if( MINGW ) target_link_libraries(FileCheck imagehlp psapi) endif( MINGW ) diff --git a/utils/FileCheck/FileCheck.cpp b/utils/FileCheck/FileCheck.cpp index cd76d4404308..5d4cb0c0c5f0 100644 --- a/utils/FileCheck/FileCheck.cpp +++ b/utils/FileCheck/FileCheck.cpp @@ -16,13 +16,15 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/OwningPtr.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Regex.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Signals.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/system_error.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" #include @@ -50,6 +52,10 @@ NoCanonicalizeWhiteSpace("strict-whitespace", class Pattern { SMLoc PatternLoc; + /// MatchEOF - When set, this pattern only matches the end of file. This is + /// used for trailing CHECK-NOTs. + bool MatchEOF; + /// FixedStr - If non-empty, this pattern is a fixed string match with the /// specified fixed string. StringRef FixedStr; @@ -71,7 +77,7 @@ class Pattern { public: - Pattern() { } + Pattern(bool matchEOF = false) : MatchEOF(matchEOF) { } bool ParsePattern(StringRef PatternStr, SourceMgr &SM); @@ -271,6 +277,12 @@ bool Pattern::AddRegExToRegEx(StringRef RegexStr, unsigned &CurParen, /// there is a match, the size of the matched string is returned in MatchLen. size_t Pattern::Match(StringRef Buffer, size_t &MatchLen, StringMap &VariableTable) const { + // If this is the EOF pattern, match it immediately. + if (MatchEOF) { + MatchLen = 0; + return Buffer.size(); + } + // If this is a fixed string pattern, just match it now. if (!FixedStr.empty()) { MatchLen = FixedStr.size(); @@ -446,6 +458,11 @@ static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB) { for (const char *Ptr = MB->getBufferStart(), *End = MB->getBufferEnd(); Ptr != End; ++Ptr) { + // Eliminate trailing dosish \r. + if (Ptr <= End - 2 && Ptr[0] == '\r' && Ptr[1] == '\n') { + continue; + } + // If C is not a horizontal whitespace, skip it. if (*Ptr != ' ' && *Ptr != '\t') { NewFile.push_back(*Ptr); @@ -473,14 +490,14 @@ static MemoryBuffer *CanonicalizeInputFile(MemoryBuffer *MB) { static bool ReadCheckFile(SourceMgr &SM, std::vector &CheckStrings) { // Open the check file, and tell SourceMgr about it. - std::string ErrorStr; - MemoryBuffer *F = - MemoryBuffer::getFileOrSTDIN(CheckFilename.c_str(), &ErrorStr); - if (F == 0) { + OwningPtr File; + if (error_code ec = + MemoryBuffer::getFileOrSTDIN(CheckFilename.c_str(), File)) { errs() << "Could not open check file '" << CheckFilename << "': " - << ErrorStr << '\n'; + << ec.message() << '\n'; return true; } + MemoryBuffer *F = File.take(); // If we want to canonicalize whitespace, strip excess whitespace from the // buffer containing the CHECK lines. @@ -565,18 +582,20 @@ static bool ReadCheckFile(SourceMgr &SM, std::swap(NotMatches, CheckStrings.back().NotStrings); } + // Add an EOF pattern for any trailing CHECK-NOTs. + if (!NotMatches.empty()) { + CheckStrings.push_back(CheckString(Pattern(true), + SMLoc::getFromPointer(Buffer.data()), + false)); + std::swap(NotMatches, CheckStrings.back().NotStrings); + } + if (CheckStrings.empty()) { errs() << "error: no check strings found with prefix '" << CheckPrefix << ":'\n"; return true; } - if (!NotMatches.empty()) { - errs() << "error: '" << CheckPrefix - << "-NOT:' not supported after last check line.\n"; - return true; - } - return false; } @@ -631,15 +650,20 @@ int main(int argc, char **argv) { return 2; // Open the file to check and add it to SourceMgr. - std::string ErrorStr; - MemoryBuffer *F = - MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), &ErrorStr); - if (F == 0) { + OwningPtr File; + if (error_code ec = + MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), File)) { errs() << "Could not open input file '" << InputFilename << "': " - << ErrorStr << '\n'; + << ec.message() << '\n'; return true; } + MemoryBuffer *F = File.take(); + if (F->getBufferSize() == 0) { + errs() << "FileCheck error: '" << InputFilename << "' is empty.\n"; + return 1; + } + // Remove duplicate spaces in the input file if requested. if (!NoCanonicalizeWhiteSpace) F = CanonicalizeInputFile(F); @@ -662,10 +686,11 @@ int main(int argc, char **argv) { // Find StrNo in the file. size_t MatchLen = 0; - Buffer = Buffer.substr(CheckStr.Pat.Match(Buffer, MatchLen, VariableTable)); + size_t MatchPos = CheckStr.Pat.Match(Buffer, MatchLen, VariableTable); + Buffer = Buffer.substr(MatchPos); // If we didn't find a match, reject the input. - if (Buffer.empty()) { + if (MatchPos == StringRef::npos) { PrintCheckFailed(SM, CheckStr, SearchFrom, VariableTable); return 1; } diff --git a/utils/FileCheck/Makefile b/utils/FileCheck/Makefile index f1af5b649e7a..268b7bc919a1 100644 --- a/utils/FileCheck/Makefile +++ b/utils/FileCheck/Makefile @@ -1,15 +1,15 @@ ##===- utils/FileCheck/Makefile ----------------------------*- Makefile -*-===## -# +# # The LLVM Compiler Infrastructure # # This file is distributed under the University of Illinois Open Source # License. See LICENSE.TXT for details. -# +# ##===----------------------------------------------------------------------===## LEVEL = ../.. TOOLNAME = FileCheck -USEDLIBS = LLVMSupport.a LLVMSystem.a +USEDLIBS = LLVMSupport.a # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS = 1 diff --git a/utils/FileUpdate/CMakeLists.txt b/utils/FileUpdate/CMakeLists.txt index bacbd16b90f9..5dda49e0e4c5 100644 --- a/utils/FileUpdate/CMakeLists.txt +++ b/utils/FileUpdate/CMakeLists.txt @@ -2,7 +2,7 @@ add_executable(FileUpdate FileUpdate.cpp ) -target_link_libraries(FileUpdate LLVMSupport LLVMSystem) +target_link_libraries(FileUpdate LLVMSupport) if( MINGW ) target_link_libraries(FileUpdate imagehlp psapi) endif( MINGW ) diff --git a/utils/FileUpdate/FileUpdate.cpp b/utils/FileUpdate/FileUpdate.cpp index 2cf366fa55f8..3ea1e4f306ee 100644 --- a/utils/FileUpdate/FileUpdate.cpp +++ b/utils/FileUpdate/FileUpdate.cpp @@ -15,9 +15,11 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/ADT/OwningPtr.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/System/Signals.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/system_error.h" using namespace llvm; static cl::opt @@ -42,17 +44,16 @@ int main(int argc, char **argv) { } // Get the input data. - std::string ErrorStr; - MemoryBuffer *In = - MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), &ErrorStr); - if (In == 0) { + OwningPtr In; + if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), In)) { errs() << argv[0] << ": error: Unable to get input '" - << InputFilename << "': " << ErrorStr << '\n'; + << InputFilename << "': " << ec.message() << '\n'; return 1; } // Get the output data. - MemoryBuffer *Out = MemoryBuffer::getFile(OutputFilename.c_str(), &ErrorStr); + OwningPtr Out; + MemoryBuffer::getFile(OutputFilename.c_str(), Out); // If the output exists and the contents match, we are done. if (Out && In->getBufferSize() == Out->getBufferSize() && @@ -64,12 +65,11 @@ int main(int argc, char **argv) { return 0; } - delete Out; - // Otherwise, overwrite the output. if (!Quiet) errs() << argv[0] << ": Updating '" << OutputFilename << "', contents changed.\n"; + std::string ErrorStr; tool_output_file OutStream(OutputFilename.c_str(), ErrorStr, raw_fd_ostream::F_Binary); if (!ErrorStr.empty()) { diff --git a/utils/FileUpdate/Makefile b/utils/FileUpdate/Makefile index 5b545c207297..1e6c0a838c27 100644 --- a/utils/FileUpdate/Makefile +++ b/utils/FileUpdate/Makefile @@ -1,15 +1,15 @@ ##===- utils/FileUpdate/Makefile ---------------------------*- Makefile -*-===## -# +# # The LLVM Compiler Infrastructure # # This file is distributed under the University of Illinois Open Source # License. See LICENSE.TXT for details. -# +# ##===----------------------------------------------------------------------===## LEVEL = ../.. TOOLNAME = FileUpdate -USEDLIBS = LLVMSupport.a LLVMSystem.a +USEDLIBS = LLVMSupport.a # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS = 1 diff --git a/utils/GenLibDeps.pl b/utils/GenLibDeps.pl index f1f7e72bc1a5..ca852adfcc0d 100755 --- a/utils/GenLibDeps.pl +++ b/utils/GenLibDeps.pl @@ -107,7 +107,6 @@ if ($PEROBJ) { $libpath =~ s/^TransformUtils/Transforms\/Utils/; $libpath =~ s/^ipa/Analysis\/IPA/; $libpath =~ s/^ipo/Transforms\/IPO/; - $libpath =~ s/^pic16passes/Target\/PIC16\/PIC16Passes/; $libpath = "lib/".$libpath."/"; open DEFS, "$nmPath -sg $Directory/$lib|"; while () { @@ -150,7 +149,6 @@ if ($PEROBJ) { $libpath =~ s/^TransformUtils/Transforms\/Utils/; $libpath =~ s/^ipa/Analysis\/IPA/; $libpath =~ s/^ipo/Transforms\/IPO/; - $libpath =~ s/^pic16passes/Target\/PIC16\/PIC16Passes/; $libpath = "lib/".$libpath."/"; open UDEFS, "$nmPath -Aup $Directory/$lib|"; while () { diff --git a/utils/GetRepositoryPath b/utils/GetRepositoryPath new file mode 100755 index 000000000000..326231c9e5d4 --- /dev/null +++ b/utils/GetRepositoryPath @@ -0,0 +1,27 @@ +#!/bin/sh + +usage() { + echo "usage: $0 " + echo " Prints the source control repository path of the given source" + echo " directory, the exact format of the revision string depends on the" + echo " source control system. If the source control system isn't known," + echo " the output is empty and the exit code is 1." + exit 1 +} + +if [ $# != 1 ] || [ ! -d $1 ]; then + usage; +fi + +cd $1 +if [ -d .svn ]; then + svn info | grep 'URL:' | cut -d: -f2- +elif [ -d .git/svn ]; then + git svn info | grep 'URL:' | cut -d: -f2- +elif [ -d .git ]; then + git remote -v | grep 'fetch' | awk '{ print $2 }' +else + exit 1; +fi + +exit 0 diff --git a/utils/GetSourceVersion b/utils/GetSourceVersion index b25f2f97736b..cbed7daf5b61 100755 --- a/utils/GetSourceVersion +++ b/utils/GetSourceVersion @@ -1,12 +1,12 @@ #!/bin/sh usage() { - echo "usage: $0 " - echo " Prints the source control revision of the given source directory," - echo " the exact format of the revision string depends on the source " - echo " control system. If the source control system isn't known, the output" - echo " is empty and the exit code is 1." - exit 1 + echo "usage: $0 " + echo " Prints the source control revision of the given source directory," + echo " the exact format of the revision string depends on the source " + echo " control system. If the source control system isn't known, the output" + echo " is empty and the exit code is 1." + exit 1 } if [ $# != 1 ] || [ ! -d $1 ]; then @@ -15,13 +15,13 @@ fi cd $1 if [ -d .svn ]; then - svnversion + svnversion | sed -e "s#\([0-9]*\)[A-Z]*#\1#" elif [ -d .git/svn ]; then - git svn info | grep 'Revision:' | cut -d: -f2- + git svn info | grep 'Revision:' | cut -d: -f2- elif [ -d .git ]; then - git log -1 --pretty=format:%H + git log -1 --pretty=format:%H else - exit 1; + exit 1; fi exit 0 diff --git a/utils/KillTheDoctor/CMakeLists.txt b/utils/KillTheDoctor/CMakeLists.txt new file mode 100644 index 000000000000..99c671e74af9 --- /dev/null +++ b/utils/KillTheDoctor/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(KillTheDoctor + KillTheDoctor.cpp + ) + +target_link_libraries(KillTheDoctor LLVMSupport) diff --git a/utils/KillTheDoctor/KillTheDoctor.cpp b/utils/KillTheDoctor/KillTheDoctor.cpp new file mode 100644 index 000000000000..7a89dd379b70 --- /dev/null +++ b/utils/KillTheDoctor/KillTheDoctor.cpp @@ -0,0 +1,596 @@ +//===- KillTheDoctor - Prevent Dr. Watson from stopping tests ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This program provides an extremely hacky way to stop Dr. Watson from starting +// due to unhandled exceptions in child processes. +// +// This simply starts the program named in the first positional argument with +// the arguments following it under a debugger. All this debugger does is catch +// any unhandled exceptions thrown in the child process and close the program +// (and hopefully tells someone about it). +// +// This also provides another really hacky method to prevent assert dialog boxes +// from popping up. When --no-user32 is passed, if any process loads user32.dll, +// we assume it is trying to call MessageBoxEx and terminate it. The proper way +// to do this would be to actually set a break point, but there's quite a bit +// of code involved to get the address of MessageBoxEx in the remote process's +// address space due to Address space layout randomization (ASLR). This can be +// added if it's ever actually needed. +// +// If the subprocess exits for any reason other than successful termination, -1 +// is returned. If the process exits normally the value it returned is returned. +// +// I hate Windows. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/type_traits.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/system_error.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace llvm; + +#undef max + +namespace { + cl::opt ProgramToRun(cl::Positional, + cl::desc("")); + cl::list Argv(cl::ConsumeAfter, + cl::desc("...")); + cl::opt TraceExecution("x", + cl::desc("Print detailed output about what is being run to stderr.")); + cl::opt Timeout("t", cl::init(0), + cl::desc("Set maximum runtime in seconds. Defaults to infinite.")); + cl::opt NoUser32("no-user32", + cl::desc("Terminate process if it loads user32.dll.")); + + StringRef ToolName; + + template + class ScopedHandle { + typedef typename HandleType::handle_type handle_type; + + handle_type Handle; + + public: + ScopedHandle() + : Handle(HandleType::GetInvalidHandle()) {} + + explicit ScopedHandle(handle_type handle) + : Handle(handle) {} + + ~ScopedHandle() { + HandleType::Destruct(Handle); + } + + ScopedHandle& operator=(handle_type handle) { + // Cleanup current handle. + if (!HandleType::isValid(Handle)) + HandleType::Destruct(Handle); + Handle = handle; + return *this; + } + + operator bool() const { + return HandleType::isValid(Handle); + } + + operator handle_type() { + return Handle; + } + }; + + // This implements the most common handle in the Windows API. + struct CommonHandle { + typedef HANDLE handle_type; + + static handle_type GetInvalidHandle() { + return INVALID_HANDLE_VALUE; + } + + static void Destruct(handle_type Handle) { + ::CloseHandle(Handle); + } + + static bool isValid(handle_type Handle) { + return Handle != GetInvalidHandle(); + } + }; + + struct FileMappingHandle { + typedef HANDLE handle_type; + + static handle_type GetInvalidHandle() { + return NULL; + } + + static void Destruct(handle_type Handle) { + ::CloseHandle(Handle); + } + + static bool isValid(handle_type Handle) { + return Handle != GetInvalidHandle(); + } + }; + + struct MappedViewOfFileHandle { + typedef LPVOID handle_type; + + static handle_type GetInvalidHandle() { + return NULL; + } + + static void Destruct(handle_type Handle) { + ::UnmapViewOfFile(Handle); + } + + static bool isValid(handle_type Handle) { + return Handle != GetInvalidHandle(); + } + }; + + struct ProcessHandle : CommonHandle {}; + struct ThreadHandle : CommonHandle {}; + struct TokenHandle : CommonHandle {}; + struct FileHandle : CommonHandle {}; + + typedef ScopedHandle FileMappingScopedHandle; + typedef ScopedHandle MappedViewOfFileScopedHandle; + typedef ScopedHandle ProcessScopedHandle; + typedef ScopedHandle ThreadScopedHandle; + typedef ScopedHandle TokenScopedHandle; + typedef ScopedHandle FileScopedHandle; +} + +static error_code GetFileNameFromHandle(HANDLE FileHandle, + std::string& Name) { + char Filename[MAX_PATH+1]; + bool Sucess = false; + Name.clear(); + + // Get the file size. + LARGE_INTEGER FileSize; + Sucess = ::GetFileSizeEx(FileHandle, &FileSize); + + if (!Sucess) + return windows_error(::GetLastError()); + + // Create a file mapping object. + FileMappingScopedHandle FileMapping( + ::CreateFileMappingA(FileHandle, + NULL, + PAGE_READONLY, + 0, + 1, + NULL)); + + if (!FileMapping) + return windows_error(::GetLastError()); + + // Create a file mapping to get the file name. + MappedViewOfFileScopedHandle MappedFile( + ::MapViewOfFile(FileMapping, FILE_MAP_READ, 0, 0, 1)); + + if (!MappedFile) + return windows_error(::GetLastError()); + + Sucess = ::GetMappedFileNameA(::GetCurrentProcess(), + MappedFile, + Filename, + array_lengthof(Filename) - 1); + + if (!Sucess) + return windows_error(::GetLastError()); + else { + Name = Filename; + return windows_error::success; + } +} + +static std::string QuoteProgramPathIfNeeded(StringRef Command) { + if (Command.find_first_of(' ') == StringRef::npos) + return Command; + else { + std::string ret; + ret.reserve(Command.size() + 3); + ret.push_back('"'); + ret.append(Command.begin(), Command.end()); + ret.push_back('"'); + return ret; + } +} + +/// @brief Find program using shell lookup rules. +/// @param Program This is either an absolute path, relative path, or simple a +/// program name. Look in PATH for any programs that match. If no +/// extension is present, try all extensions in PATHEXT. +/// @return If ec == errc::success, The absolute path to the program. Otherwise +/// the return value is undefined. +static std::string FindProgram(const std::string &Program, error_code &ec) { + char PathName[MAX_PATH + 1]; + typedef SmallVector pathext_t; + pathext_t pathext; + // Check for the program without an extension (in case it already has one). + pathext.push_back(""); + SplitString(std::getenv("PATHEXT"), pathext, ";"); + + for (pathext_t::iterator i = pathext.begin(), e = pathext.end(); i != e; ++i){ + SmallString<5> ext; + for (std::size_t ii = 0, e = i->size(); ii != e; ++ii) + ext.push_back(::tolower((*i)[ii])); + LPCSTR Extension = NULL; + if (ext.size() && ext[0] == '.') + Extension = ext.c_str(); + DWORD length = ::SearchPathA(NULL, + Program.c_str(), + Extension, + array_lengthof(PathName), + PathName, + NULL); + if (length == 0) + ec = windows_error(::GetLastError()); + else if (length > array_lengthof(PathName)) { + // This may have been the file, return with error. + ec = windows_error::buffer_overflow; + break; + } else { + // We found the path! Return it. + ec = windows_error::success; + break; + } + } + + // Make sure PathName is valid. + PathName[MAX_PATH] = 0; + return PathName; +} + +static error_code EnableDebugPrivileges() { + HANDLE TokenHandle; + BOOL success = ::OpenProcessToken(::GetCurrentProcess(), + TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, + &TokenHandle); + if (!success) + return windows_error(::GetLastError()); + + TokenScopedHandle Token(TokenHandle); + TOKEN_PRIVILEGES TokenPrivileges; + LUID LocallyUniqueID; + + success = ::LookupPrivilegeValueA(NULL, + SE_DEBUG_NAME, + &LocallyUniqueID); + if (!success) + return windows_error(::GetLastError()); + + TokenPrivileges.PrivilegeCount = 1; + TokenPrivileges.Privileges[0].Luid = LocallyUniqueID; + TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + success = ::AdjustTokenPrivileges(Token, + FALSE, + &TokenPrivileges, + sizeof(TOKEN_PRIVILEGES), + NULL, + NULL); + // The value of success is basically useless. Either way we are just returning + // the value of ::GetLastError(). + return windows_error(::GetLastError()); +} + +static StringRef ExceptionCodeToString(DWORD ExceptionCode) { + switch(ExceptionCode) { + case EXCEPTION_ACCESS_VIOLATION: return "EXCEPTION_ACCESS_VIOLATION"; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED"; + case EXCEPTION_BREAKPOINT: return "EXCEPTION_BREAKPOINT"; + case EXCEPTION_DATATYPE_MISALIGNMENT: + return "EXCEPTION_DATATYPE_MISALIGNMENT"; + case EXCEPTION_FLT_DENORMAL_OPERAND: return "EXCEPTION_FLT_DENORMAL_OPERAND"; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: return "EXCEPTION_FLT_DIVIDE_BY_ZERO"; + case EXCEPTION_FLT_INEXACT_RESULT: return "EXCEPTION_FLT_INEXACT_RESULT"; + case EXCEPTION_FLT_INVALID_OPERATION: + return "EXCEPTION_FLT_INVALID_OPERATION"; + case EXCEPTION_FLT_OVERFLOW: return "EXCEPTION_FLT_OVERFLOW"; + case EXCEPTION_FLT_STACK_CHECK: return "EXCEPTION_FLT_STACK_CHECK"; + case EXCEPTION_FLT_UNDERFLOW: return "EXCEPTION_FLT_UNDERFLOW"; + case EXCEPTION_ILLEGAL_INSTRUCTION: return "EXCEPTION_ILLEGAL_INSTRUCTION"; + case EXCEPTION_IN_PAGE_ERROR: return "EXCEPTION_IN_PAGE_ERROR"; + case EXCEPTION_INT_DIVIDE_BY_ZERO: return "EXCEPTION_INT_DIVIDE_BY_ZERO"; + case EXCEPTION_INT_OVERFLOW: return "EXCEPTION_INT_OVERFLOW"; + case EXCEPTION_INVALID_DISPOSITION: return "EXCEPTION_INVALID_DISPOSITION"; + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + return "EXCEPTION_NONCONTINUABLE_EXCEPTION"; + case EXCEPTION_PRIV_INSTRUCTION: return "EXCEPTION_PRIV_INSTRUCTION"; + case EXCEPTION_SINGLE_STEP: return "EXCEPTION_SINGLE_STEP"; + case EXCEPTION_STACK_OVERFLOW: return "EXCEPTION_STACK_OVERFLOW"; + default: return ""; + } +} + +int main(int argc, char **argv) { + // Print a stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + + ToolName = argv[0]; + + cl::ParseCommandLineOptions(argc, argv, "Dr. Watson Assassin.\n"); + if (ProgramToRun.size() == 0) { + cl::PrintHelpMessage(); + return -1; + } + + if (Timeout > std::numeric_limits::max() / 1000) { + errs() << ToolName << ": Timeout value too large, must be less than: " + << std::numeric_limits::max() / 1000 + << '\n'; + return -1; + } + + std::string CommandLine(ProgramToRun); + + error_code ec; + ProgramToRun = FindProgram(ProgramToRun, ec); + if (ec) { + errs() << ToolName << ": Failed to find program: '" << CommandLine + << "': " << ec.message() << '\n'; + return -1; + } + + if (TraceExecution) + errs() << ToolName << ": Found Program: " << ProgramToRun << '\n'; + + for (std::vector::iterator i = Argv.begin(), + e = Argv.end(); + i != e; ++i) { + CommandLine.push_back(' '); + CommandLine.append(*i); + } + + if (TraceExecution) + errs() << ToolName << ": Program Image Path: " << ProgramToRun << '\n' + << ToolName << ": Command Line: " << CommandLine << '\n'; + + STARTUPINFO StartupInfo; + PROCESS_INFORMATION ProcessInfo; + std::memset(&StartupInfo, 0, sizeof(StartupInfo)); + StartupInfo.cb = sizeof(StartupInfo); + std::memset(&ProcessInfo, 0, sizeof(ProcessInfo)); + + // Set error mode to not display any message boxes. The child process inherits + // this. + ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); + ::_set_error_mode(_OUT_TO_STDERR); + + BOOL success = ::CreateProcessA(ProgramToRun.c_str(), + LPSTR(CommandLine.c_str()), + NULL, + NULL, + FALSE, + DEBUG_PROCESS, + NULL, + NULL, + &StartupInfo, + &ProcessInfo); + if (!success) { + errs() << ToolName << ": Failed to run program: '" << ProgramToRun + << "': " << error_code(windows_error(::GetLastError())).message() + << '\n'; + return -1; + } + + // Make sure ::CloseHandle is called on exit. + std::map ProcessIDToHandle; + + DEBUG_EVENT DebugEvent; + std::memset(&DebugEvent, 0, sizeof(DebugEvent)); + DWORD dwContinueStatus = DBG_CONTINUE; + + // Run the program under the debugger until either it exits, or throws an + // exception. + if (TraceExecution) + errs() << ToolName << ": Debugging...\n"; + + while(true) { + DWORD TimeLeft = INFINITE; + if (Timeout > 0) { + FILETIME CreationTime, ExitTime, KernelTime, UserTime; + ULARGE_INTEGER a, b; + success = ::GetProcessTimes(ProcessInfo.hProcess, + &CreationTime, + &ExitTime, + &KernelTime, + &UserTime); + if (!success) { + ec = windows_error(::GetLastError()); + + errs() << ToolName << ": Failed to get process times: " + << ec.message() << '\n'; + return -1; + } + a.LowPart = KernelTime.dwLowDateTime; + a.HighPart = KernelTime.dwHighDateTime; + b.LowPart = UserTime.dwLowDateTime; + b.HighPart = UserTime.dwHighDateTime; + // Convert 100-nanosecond units to milliseconds. + uint64_t TotalTimeMiliseconds = (a.QuadPart + b.QuadPart) / 10000; + // Handle the case where the process has been running for more than 49 + // days. + if (TotalTimeMiliseconds > std::numeric_limits::max()) { + errs() << ToolName << ": Timeout Failed: Process has been running for" + "more than 49 days.\n"; + return -1; + } + + // We check with > instead of using Timeleft because if + // TotalTimeMiliseconds is greater than Timeout * 1000, TimeLeft would + // underflow. + if (TotalTimeMiliseconds > (Timeout * 1000)) { + errs() << ToolName << ": Process timed out.\n"; + ::TerminateProcess(ProcessInfo.hProcess, -1); + // Otherwise other stuff starts failing... + return -1; + } + + TimeLeft = (Timeout * 1000) - static_cast(TotalTimeMiliseconds); + } + success = WaitForDebugEvent(&DebugEvent, TimeLeft); + + if (!success) { + ec = windows_error(::GetLastError()); + + if (ec == errc::timed_out) { + errs() << ToolName << ": Process timed out.\n"; + ::TerminateProcess(ProcessInfo.hProcess, -1); + // Otherwise other stuff starts failing... + return -1; + } + + errs() << ToolName << ": Failed to wait for debug event in program: '" + << ProgramToRun << "': " << ec.message() << '\n'; + return -1; + } + + switch(DebugEvent.dwDebugEventCode) { + case CREATE_PROCESS_DEBUG_EVENT: + // Make sure we remove the handle on exit. + if (TraceExecution) + errs() << ToolName << ": Debug Event: CREATE_PROCESS_DEBUG_EVENT\n"; + ProcessIDToHandle[DebugEvent.dwProcessId] = + DebugEvent.u.CreateProcessInfo.hProcess; + ::CloseHandle(DebugEvent.u.CreateProcessInfo.hFile); + break; + case EXIT_PROCESS_DEBUG_EVENT: { + if (TraceExecution) + errs() << ToolName << ": Debug Event: EXIT_PROCESS_DEBUG_EVENT\n"; + + // If this is the process we originally created, exit with its exit + // code. + if (DebugEvent.dwProcessId == ProcessInfo.dwProcessId) + return DebugEvent.u.ExitProcess.dwExitCode; + + // Otherwise cleanup any resources we have for it. + std::map::iterator ExitingProcess = + ProcessIDToHandle.find(DebugEvent.dwProcessId); + if (ExitingProcess == ProcessIDToHandle.end()) { + errs() << ToolName << ": Got unknown process id!\n"; + return -1; + } + ::CloseHandle(ExitingProcess->second); + ProcessIDToHandle.erase(ExitingProcess); + } + break; + case CREATE_THREAD_DEBUG_EVENT: + ::CloseHandle(DebugEvent.u.CreateThread.hThread); + break; + case LOAD_DLL_DEBUG_EVENT: { + // Cleanup the file handle. + FileScopedHandle DLLFile(DebugEvent.u.LoadDll.hFile); + std::string DLLName; + ec = GetFileNameFromHandle(DLLFile, DLLName); + if (ec) { + DLLName = " : "; + DLLName += ec.message(); + } + if (TraceExecution) { + errs() << ToolName << ": Debug Event: LOAD_DLL_DEBUG_EVENT\n"; + errs().indent(ToolName.size()) << ": DLL Name : " << DLLName << '\n'; + } + + if (NoUser32 && sys::path::stem(DLLName) == "user32") { + // Program is loading user32.dll, in the applications we are testing, + // this only happens if an assert has fired. By now the message has + // already been printed, so simply close the program. + errs() << ToolName << ": user32.dll loaded!\n"; + errs().indent(ToolName.size()) + << ": This probably means that assert was called. Closing " + "program to prevent message box from popping up.\n"; + dwContinueStatus = DBG_CONTINUE; + ::TerminateProcess(ProcessIDToHandle[DebugEvent.dwProcessId], -1); + return -1; + } + } + break; + case EXCEPTION_DEBUG_EVENT: { + // Close the application if this exception will not be handled by the + // child application. + if (TraceExecution) + errs() << ToolName << ": Debug Event: EXCEPTION_DEBUG_EVENT\n"; + + EXCEPTION_DEBUG_INFO &Exception = DebugEvent.u.Exception; + if (Exception.dwFirstChance > 0) { + if (TraceExecution) { + errs().indent(ToolName.size()) << ": Debug Info : "; + errs() << "First chance exception at " + << Exception.ExceptionRecord.ExceptionAddress + << ", exception code: " + << ExceptionCodeToString( + Exception.ExceptionRecord.ExceptionCode) + << " (" << Exception.ExceptionRecord.ExceptionCode << ")\n"; + } + dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED; + } else { + errs() << ToolName << ": Unhandled exception in: " << ProgramToRun + << "!\n"; + errs().indent(ToolName.size()) << ": location: "; + errs() << Exception.ExceptionRecord.ExceptionAddress + << ", exception code: " + << ExceptionCodeToString( + Exception.ExceptionRecord.ExceptionCode) + << " (" << Exception.ExceptionRecord.ExceptionCode + << ")\n"; + dwContinueStatus = DBG_CONTINUE; + ::TerminateProcess(ProcessIDToHandle[DebugEvent.dwProcessId], -1); + return -1; + } + } + break; + default: + // Do nothing. + if (TraceExecution) + errs() << ToolName << ": Debug Event: \n"; + break; + } + + success = ContinueDebugEvent(DebugEvent.dwProcessId, + DebugEvent.dwThreadId, + dwContinueStatus); + if (!success) { + ec = windows_error(::GetLastError()); + errs() << ToolName << ": Failed to continue debugging program: '" + << ProgramToRun << "': " << ec.message() << '\n'; + return -1; + } + + dwContinueStatus = DBG_CONTINUE; + } + + assert(0 && "Fell out of debug loop. This shouldn't be possible!"); + return -1; +} diff --git a/utils/Makefile b/utils/Makefile index 1a4dcca8c5ee..9d4dc5c2f90b 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -15,7 +15,7 @@ EXTRA_DIST := cgiplotNLT.pl check-each-file codegen-diff countloc.sh \ DSAclean.py DSAextract.py emacs findsym.pl GenLibDeps.pl \ getsrcs.sh importNLT.pl llvmdo llvmgrep llvm-native-gcc \ llvm-native-gxx makellvm NightlyTest.gnuplot NightlyTest.pl \ - NightlyTestTemplate.html NLT.schema OldenDataRecover.pl \ + NightlyTestTemplate.html NLT.schema \ parseNLT.pl plotNLT.pl profile.pl \ webNLT.pl vim diff --git a/utils/OldenDataRecover.pl b/utils/OldenDataRecover.pl deleted file mode 100644 index 767839488b34..000000000000 --- a/utils/OldenDataRecover.pl +++ /dev/null @@ -1,37 +0,0 @@ -#this script is intended to help recover the running graphs when -#the nightly tester decides to eat them. - -#zgrep -E "(=========)|(TEST-RESULT-llc-time)" *-Olden-tests.txt* |perl this > file -#zgrep -E "(=========)|(TEST-RESULT-compile.*bc)" *-Olden-tests.tx* |perl this >file - -while (<>) { - if (/(\d*-\d*-\d*)-.*=========.*\/(.*)\' Program/) { -# print "$1 $2\n"; - $curP = $2; - $curD = $1; - $dates{$1} = 1; - } elsif (/(\d*-\d*-\d*)-.*TEST-RESULT-.*: program (\d*\.\d*)/) { -# print "$1 $2\n"; - if ($curD eq $1) { - $$data{$curD}{$curP} = $2; - } - } elsif (/(\d*-\d*-\d*)-.*TEST-RESULT-.*: (\d*)/) { -# print "$1 $2\n"; - if ($curD eq $1) { - $$data{$curD}{$curP} = $2; - } - } -} -@progs = ("bh", "em3d", "mst", "power", "tsp", "bisort", "health", "perimeter", "treeadd", "voronoi"); - -foreach $date (sort keys %dates) { - print "$date: "; - foreach $prog (@progs) { - if ($$data{$date}{$prog}) { - print " $$data{$date}{$prog}"; - } else { - print " 0"; - } - } - print "\n"; -} diff --git a/utils/PerfectShuffle/PerfectShuffle.cpp b/utils/PerfectShuffle/PerfectShuffle.cpp index b94a7d326d19..98f8f4cc0cab 100644 --- a/utils/PerfectShuffle/PerfectShuffle.cpp +++ b/utils/PerfectShuffle/PerfectShuffle.cpp @@ -15,6 +15,7 @@ //===----------------------------------------------------------------------===// #include +#include #include #include #include @@ -400,7 +401,7 @@ int main() { // LHS, and 13 bits of RHS = 32 bits. unsigned Val = (CostSat << 30) | (OpNum << 26) | (LHS << 13) | RHS; - std::cout << " " << Val << "U,\t// "; + std::cout << " " << std::setw(10) << Val << "U, // "; PrintMask(i, std::cout); std::cout << ": Cost " << ShufTab[i].Cost; std::cout << " " << (ShufTab[i].Op ? ShufTab[i].Op->getName() : "copy"); diff --git a/utils/TableGen/ARMDecoderEmitter.cpp b/utils/TableGen/ARMDecoderEmitter.cpp index 03b01f6bdb74..a8de7452ea06 100644 --- a/utils/TableGen/ARMDecoderEmitter.cpp +++ b/utils/TableGen/ARMDecoderEmitter.cpp @@ -221,7 +221,7 @@ typedef enum { #define BIT_WIDTH 32 // Forward declaration. -class FilterChooser; +class ARMFilterChooser; // Representation of the instruction to work on. typedef bit_value_t insn_t[BIT_WIDTH]; @@ -240,7 +240,7 @@ typedef bit_value_t insn_t[BIT_WIDTH]; /// the Filter/FilterChooser combo does not know how to distinguish among the /// Opcodes assigned. /// -/// An example of a conflcit is +/// An example of a conflict is /// /// Conflict: /// 111101000.00........00010000.... @@ -262,9 +262,9 @@ typedef bit_value_t insn_t[BIT_WIDTH]; /// decoder could try to decode the even/odd register numbering and assign to /// VST4q8a or VST4q8b, but for the time being, the decoder chooses the "a" /// version and return the Opcode since the two have the same Asm format string. -class Filter { +class ARMFilter { protected: - FilterChooser *Owner; // points to the FilterChooser who owns this filter + ARMFilterChooser *Owner; // points to the FilterChooser who owns this filter unsigned StartBit; // the starting bit position unsigned NumBits; // number of bits to filter bool Mixed; // a mixed region contains both set and unset bits @@ -276,7 +276,7 @@ protected: std::vector VariableInstructions; // Map of well-known segment value to its delegate. - std::map FilterChooserMap; + std::map FilterChooserMap; // Number of instructions which fall under FilteredInstructions category. unsigned NumFiltered; @@ -296,16 +296,17 @@ public: } // Return the filter chooser for the group of instructions without constant // segment values. - FilterChooser &getVariableFC() { + ARMFilterChooser &getVariableFC() { assert(NumFiltered == 1); assert(FilterChooserMap.size() == 1); return *(FilterChooserMap.find((unsigned)-1)->second); } - Filter(const Filter &f); - Filter(FilterChooser &owner, unsigned startBit, unsigned numBits, bool mixed); + ARMFilter(const ARMFilter &f); + ARMFilter(ARMFilterChooser &owner, unsigned startBit, unsigned numBits, + bool mixed); - ~Filter(); + ~ARMFilter(); // Divides the decoding task into sub tasks and delegates them to the // inferior FilterChooser's. @@ -333,7 +334,7 @@ typedef enum { ATTR_MIXED } bitAttr_t; -/// FilterChooser - FilterChooser chooses the best filter among a set of Filters +/// ARMFilterChooser - FilterChooser chooses the best filter among a set of Filters /// in order to perform the decoding of instructions at the current level. /// /// Decoding proceeds from the top down. Based on the well-known encoding bits @@ -348,11 +349,11 @@ typedef enum { /// It is useful to think of a Filter as governing the switch stmts of the /// decoding tree. And each case is delegated to an inferior FilterChooser to /// decide what further remaining bits to look at. -class FilterChooser { +class ARMFilterChooser { static TARGET_NAME_t TargetName; protected: - friend class Filter; + friend class ARMFilter; // Vector of codegen instructions to choose our filter. const std::vector &AllInstructions; @@ -361,14 +362,14 @@ protected: const std::vector Opcodes; // Vector of candidate filters. - std::vector Filters; + std::vector Filters; // Array of bit values passed down from our parent. // Set to all BIT_UNFILTERED's for Parent == NULL. bit_value_t FilterBitValues[BIT_WIDTH]; // Links to the FilterChooser above us in the decoding tree. - FilterChooser *Parent; + ARMFilterChooser *Parent; // Index of the best filter from Filters. int BestIndex; @@ -376,13 +377,13 @@ protected: public: static void setTargetName(TARGET_NAME_t tn) { TargetName = tn; } - FilterChooser(const FilterChooser &FC) : + ARMFilterChooser(const ARMFilterChooser &FC) : AllInstructions(FC.AllInstructions), Opcodes(FC.Opcodes), Filters(FC.Filters), Parent(FC.Parent), BestIndex(FC.BestIndex) { memcpy(FilterBitValues, FC.FilterBitValues, sizeof(FilterBitValues)); } - FilterChooser(const std::vector &Insts, + ARMFilterChooser(const std::vector &Insts, const std::vector &IDs) : AllInstructions(Insts), Opcodes(IDs), Filters(), Parent(NULL), BestIndex(-1) { @@ -392,10 +393,10 @@ public: doFilter(); } - FilterChooser(const std::vector &Insts, - const std::vector &IDs, - bit_value_t (&ParentFilterBitValues)[BIT_WIDTH], - FilterChooser &parent) : + ARMFilterChooser(const std::vector &Insts, + const std::vector &IDs, + bit_value_t (&ParentFilterBitValues)[BIT_WIDTH], + ARMFilterChooser &parent) : AllInstructions(Insts), Opcodes(IDs), Filters(), Parent(&parent), BestIndex(-1) { for (unsigned i = 0; i < BIT_WIDTH; ++i) @@ -426,8 +427,9 @@ protected: Insn[i] = bitFromBits(Bits, i); // Set Inst{21} to 1 (wback) when IndexModeBits == IndexModeUpd. - if (getByteField(*AllInstructions[Opcode]->TheDef, "IndexModeBits") - == IndexModeUpd) + Record *R = AllInstructions[Opcode]->TheDef; + if (R->getValue("IndexModeBits") && + getByteField(*R, "IndexModeBits") == IndexModeUpd) Insn[21] = BIT_TRUE; } @@ -452,7 +454,7 @@ protected: /// dumpFilterArray on each filter chooser up to the top level one. void dumpStack(raw_ostream &o, const char *prefix); - Filter &bestFilter() { + ARMFilter &bestFilter() { assert(BestIndex != -1 && "BestIndex not set"); return Filters[BestIndex]; } @@ -497,11 +499,12 @@ protected: bool emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,unsigned Opc); // Emits code to decode the singleton, and then to decode the rest. - void emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,Filter &Best); + void emitSingletonDecoder(raw_ostream &o, unsigned &Indentation, + ARMFilter &Best); // Assign a single filter and run with it. - void runSingleFilter(FilterChooser &owner, unsigned startBit, unsigned numBit, - bool mixed); + void runSingleFilter(ARMFilterChooser &owner, unsigned startBit, + unsigned numBit, bool mixed); // reportRegion is a helper function for filterProcessor to mark a region as // eligible for use as a filter region. @@ -530,7 +533,7 @@ protected: // // /////////////////////////// -Filter::Filter(const Filter &f) : +ARMFilter::ARMFilter(const ARMFilter &f) : Owner(f.Owner), StartBit(f.StartBit), NumBits(f.NumBits), Mixed(f.Mixed), FilteredInstructions(f.FilteredInstructions), VariableInstructions(f.VariableInstructions), @@ -538,7 +541,7 @@ Filter::Filter(const Filter &f) : LastOpcFiltered(f.LastOpcFiltered), NumVariable(f.NumVariable) { } -Filter::Filter(FilterChooser &owner, unsigned startBit, unsigned numBits, +ARMFilter::ARMFilter(ARMFilterChooser &owner, unsigned startBit, unsigned numBits, bool mixed) : Owner(&owner), StartBit(startBit), NumBits(numBits), Mixed(mixed) { assert(StartBit + NumBits - 1 < BIT_WIDTH); @@ -575,8 +578,8 @@ Filter::Filter(FilterChooser &owner, unsigned startBit, unsigned numBits, && "Filter returns no instruction categories"); } -Filter::~Filter() { - std::map::iterator filterIterator; +ARMFilter::~ARMFilter() { + std::map::iterator filterIterator; for (filterIterator = FilterChooserMap.begin(); filterIterator != FilterChooserMap.end(); filterIterator++) { @@ -590,7 +593,7 @@ Filter::~Filter() { // A special case arises when there's only one entry in the filtered // instructions. In order to unambiguously decode the singleton, we need to // match the remaining undecoded encoding bits against the singleton. -void Filter::recurse() { +void ARMFilter::recurse() { std::map >::const_iterator mapIterator; bit_value_t BitValueArray[BIT_WIDTH]; @@ -606,12 +609,12 @@ void Filter::recurse() { // Delegates to an inferior filter chooser for futher processing on this // group of instructions whose segment values are variable. - FilterChooserMap.insert(std::pair( + FilterChooserMap.insert(std::pair( (unsigned)-1, - new FilterChooser(Owner->AllInstructions, - VariableInstructions, - BitValueArray, - *Owner) + new ARMFilterChooser(Owner->AllInstructions, + VariableInstructions, + BitValueArray, + *Owner) )); } @@ -638,18 +641,18 @@ void Filter::recurse() { // Delegates to an inferior filter chooser for futher processing on this // category of instructions. - FilterChooserMap.insert(std::pair( + FilterChooserMap.insert(std::pair( mapIterator->first, - new FilterChooser(Owner->AllInstructions, - mapIterator->second, - BitValueArray, - *Owner) + new ARMFilterChooser(Owner->AllInstructions, + mapIterator->second, + BitValueArray, + *Owner) )); } } // Emit code to decode instructions given a segment or segments of bits. -void Filter::emit(raw_ostream &o, unsigned &Indentation) { +void ARMFilter::emit(raw_ostream &o, unsigned &Indentation) { o.indent(Indentation) << "// Check Inst{"; if (NumBits > 1) @@ -660,7 +663,7 @@ void Filter::emit(raw_ostream &o, unsigned &Indentation) { o.indent(Indentation) << "switch (fieldFromInstruction(insn, " << StartBit << ", " << NumBits << ")) {\n"; - std::map::iterator filterIterator; + std::map::iterator filterIterator; bool DefaultCase = false; for (filterIterator = FilterChooserMap.begin(); @@ -709,7 +712,7 @@ void Filter::emit(raw_ostream &o, unsigned &Indentation) { // Returns the number of fanout produced by the filter. More fanout implies // the filter distinguishes more categories of instructions. -unsigned Filter::usefulness() const { +unsigned ARMFilter::usefulness() const { if (VariableInstructions.size()) return FilteredInstructions.size(); else @@ -723,10 +726,10 @@ unsigned Filter::usefulness() const { ////////////////////////////////// // Define the symbol here. -TARGET_NAME_t FilterChooser::TargetName; +TARGET_NAME_t ARMFilterChooser::TargetName; // This provides an opportunity for target specific code emission. -void FilterChooser::emitTopHook(raw_ostream &o) { +void ARMFilterChooser::emitTopHook(raw_ostream &o) { if (TargetName == TARGET_ARM) { // Emit code that references the ARMFormat data type. o << "static const ARMFormat ARMFormats[] = {\n"; @@ -747,7 +750,7 @@ void FilterChooser::emitTopHook(raw_ostream &o) { } // Emit the top level typedef and decodeInstruction() function. -void FilterChooser::emitTop(raw_ostream &o, unsigned &Indentation) { +void ARMFilterChooser::emitTop(raw_ostream &o, unsigned &Indentation) { // Run the target specific emit hook. emitTopHook(o); @@ -801,7 +804,7 @@ void FilterChooser::emitTop(raw_ostream &o, unsigned &Indentation) { o << '\n'; - o.indent(Indentation) << "static uint16_t decodeInstruction(field_t insn) {\n"; + o.indent(Indentation) <<"static uint16_t decodeInstruction(field_t insn) {\n"; ++Indentation; ++Indentation; // Emits code to decode the instructions. @@ -818,7 +821,7 @@ void FilterChooser::emitTop(raw_ostream &o, unsigned &Indentation) { // This provides an opportunity for target specific code emission after // emitTop(). -void FilterChooser::emitBot(raw_ostream &o, unsigned &Indentation) { +void ARMFilterChooser::emitBot(raw_ostream &o, unsigned &Indentation) { if (TargetName != TARGET_THUMB) return; // Emit code that decodes the Thumb ISA. @@ -843,7 +846,7 @@ void FilterChooser::emitBot(raw_ostream &o, unsigned &Indentation) { // // Returns false if and on the first uninitialized bit value encountered. // Returns true, otherwise. -bool FilterChooser::fieldFromInsn(uint64_t &Field, insn_t &Insn, +bool ARMFilterChooser::fieldFromInsn(uint64_t &Field, insn_t &Insn, unsigned StartBit, unsigned NumBits) const { Field = 0; @@ -860,7 +863,7 @@ bool FilterChooser::fieldFromInsn(uint64_t &Field, insn_t &Insn, /// dumpFilterArray - dumpFilterArray prints out debugging info for the given /// filter array as a series of chars. -void FilterChooser::dumpFilterArray(raw_ostream &o, +void ARMFilterChooser::dumpFilterArray(raw_ostream &o, bit_value_t (&filter)[BIT_WIDTH]) { unsigned bitIndex; @@ -884,8 +887,8 @@ void FilterChooser::dumpFilterArray(raw_ostream &o, /// dumpStack - dumpStack traverses the filter chooser chain and calls /// dumpFilterArray on each filter chooser up to the top level one. -void FilterChooser::dumpStack(raw_ostream &o, const char *prefix) { - FilterChooser *current = this; +void ARMFilterChooser::dumpStack(raw_ostream &o, const char *prefix) { + ARMFilterChooser *current = this; while (current) { o << prefix; @@ -896,7 +899,7 @@ void FilterChooser::dumpStack(raw_ostream &o, const char *prefix) { } // Called from Filter::recurse() when singleton exists. For debug purpose. -void FilterChooser::SingletonExists(unsigned Opc) { +void ARMFilterChooser::SingletonExists(unsigned Opc) { insn_t Insn0; insnWithID(Insn0, Opc); @@ -923,7 +926,7 @@ void FilterChooser::SingletonExists(unsigned Opc) { // This returns a list of undecoded bits of an instructions, for example, // Inst{20} = 1 && Inst{3-0} == 0b1111 represents two islands of yet-to-be // decoded bits in order to verify that the instruction matches the Opcode. -unsigned FilterChooser::getIslands(std::vector &StartBits, +unsigned ARMFilterChooser::getIslands(std::vector &StartBits, std::vector &EndBits, std::vector &FieldVals, insn_t &Insn) { unsigned Num, BitNo; @@ -983,7 +986,7 @@ unsigned FilterChooser::getIslands(std::vector &StartBits, // Emits code to decode the singleton. Return true if we have matched all the // well-known bits. -bool FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation, +bool ARMFilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation, unsigned Opc) { std::vector StartBits; std::vector EndBits; @@ -1046,8 +1049,9 @@ bool FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation, } // Emits code to decode the singleton, and then to decode the rest. -void FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation, - Filter &Best) { +void ARMFilterChooser::emitSingletonDecoder(raw_ostream &o, + unsigned &Indentation, + ARMFilter &Best) { unsigned Opc = Best.getSingletonOpc(); @@ -1063,10 +1067,11 @@ void FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation, // Assign a single filter and run with it. Top level API client can initialize // with a single filter to start the filtering process. -void FilterChooser::runSingleFilter(FilterChooser &owner, unsigned startBit, - unsigned numBit, bool mixed) { +void ARMFilterChooser::runSingleFilter(ARMFilterChooser &owner, + unsigned startBit, + unsigned numBit, bool mixed) { Filters.clear(); - Filter F(*this, startBit, numBit, true); + ARMFilter F(*this, startBit, numBit, true); Filters.push_back(F); BestIndex = 0; // Sole Filter instance to choose from. bestFilter().recurse(); @@ -1074,18 +1079,18 @@ void FilterChooser::runSingleFilter(FilterChooser &owner, unsigned startBit, // reportRegion is a helper function for filterProcessor to mark a region as // eligible for use as a filter region. -void FilterChooser::reportRegion(bitAttr_t RA, unsigned StartBit, - unsigned BitIndex, bool AllowMixed) { +void ARMFilterChooser::reportRegion(bitAttr_t RA, unsigned StartBit, + unsigned BitIndex, bool AllowMixed) { if (RA == ATTR_MIXED && AllowMixed) - Filters.push_back(Filter(*this, StartBit, BitIndex - StartBit, true)); + Filters.push_back(ARMFilter(*this, StartBit, BitIndex - StartBit, true)); else if (RA == ATTR_ALL_SET && !AllowMixed) - Filters.push_back(Filter(*this, StartBit, BitIndex - StartBit, false)); + Filters.push_back(ARMFilter(*this, StartBit, BitIndex - StartBit, false)); } // FilterProcessor scans the well-known encoding bits of the instructions and // builds up a list of candidate filters. It chooses the best filter and // recursively descends down the decoding tree. -bool FilterChooser::filterProcessor(bool AllowMixed, bool Greedy) { +bool ARMFilterChooser::filterProcessor(bool AllowMixed, bool Greedy) { Filters.clear(); BestIndex = -1; unsigned numInstructions = Opcodes.size(); @@ -1317,7 +1322,7 @@ bool FilterChooser::filterProcessor(bool AllowMixed, bool Greedy) { // Decides on the best configuration of filter(s) to use in order to decode // the instructions. A conflict of instructions may occur, in which case we // dump the conflict set to the standard error. -void FilterChooser::doFilter() { +void ARMFilterChooser::doFilter() { unsigned Num = Opcodes.size(); assert(Num && "FilterChooser created with no instructions"); @@ -1350,7 +1355,7 @@ void FilterChooser::doFilter() { // Emits code to decode our share of instructions. Returns true if the // emitted code causes a return, which occurs if we know how to decode // the instruction at this level or the instruction is not decodeable. -bool FilterChooser::emit(raw_ostream &o, unsigned &Indentation) { +bool ARMFilterChooser::emit(raw_ostream &o, unsigned &Indentation) { if (Opcodes.size() == 1) // There is only one instruction in the set, which is great! // Call emitSingletonDecoder() to see whether there are any remaining @@ -1359,7 +1364,7 @@ bool FilterChooser::emit(raw_ostream &o, unsigned &Indentation) { // Choose the best filter to do the decodings! if (BestIndex != -1) { - Filter &Best = bestFilter(); + ARMFilter &Best = bestFilter(); if (Best.getNumFiltered() == 1) emitSingletonDecoder(o, Indentation, Best); else @@ -1488,11 +1493,11 @@ bool FilterChooser::emit(raw_ostream &o, unsigned &Indentation) { class ARMDecoderEmitter::ARMDEBackend { public: - ARMDEBackend(ARMDecoderEmitter &frontend) : + ARMDEBackend(ARMDecoderEmitter &frontend, RecordKeeper &Records) : NumberedInstructions(), Opcodes(), Frontend(frontend), - Target(), + Target(Records), FC(NULL) { if (Target.getName() == "ARM") @@ -1538,13 +1543,14 @@ protected: std::vector Opcodes2; ARMDecoderEmitter &Frontend; CodeGenTarget Target; - FilterChooser *FC; + ARMFilterChooser *FC; TARGET_NAME_t TargetName; }; -bool ARMDecoderEmitter::ARMDEBackend::populateInstruction( - const CodeGenInstruction &CGI, TARGET_NAME_t TN) { +bool ARMDecoderEmitter:: +ARMDEBackend::populateInstruction(const CodeGenInstruction &CGI, + TARGET_NAME_t TN) { const Record &Def = *CGI.TheDef; const StringRef Name = Def.getName(); uint8_t Form = getByteField(Def, "Form"); @@ -1559,6 +1565,10 @@ bool ARMDecoderEmitter::ARMDEBackend::populateInstruction( // which is a better design and less fragile than the name matchings. if (Bits.allInComplete()) return false; + // Ignore "asm parser only" instructions. + if (Def.getValueAsBit("isAsmParserOnly")) + return false; + if (TN == TARGET_ARM) { // FIXME: what about Int_MemBarrierV6 and Int_SyncBarrierV6? if ((Name != "Int_MemBarrierV7" && Name != "Int_SyncBarrierV7") && @@ -1566,13 +1576,6 @@ bool ARMDecoderEmitter::ARMDEBackend::populateInstruction( return false; if (thumbInstruction(Form)) return false; - if (Name.find("CMPz") != std::string::npos /* || - Name.find("CMNz") != std::string::npos */) - return false; - - // Ignore pseudo instructions. - if (Name == "BXr9" || Name == "BMOVPCRX" || Name == "BMOVPCRXr9") - return false; // Tail calls are other patterns that generate existing instructions. if (Name == "TCRETURNdi" || Name == "TCRETURNdiND" || @@ -1583,11 +1586,6 @@ bool ARMDecoderEmitter::ARMDEBackend::populateInstruction( Name == "MOVr_TC") return false; - // VLDMQ/VSTMQ can be handled with the more generic VLDMD/VSTMD. - if (Name == "VLDMQ" || Name == "VLDMQ_UPD" || - Name == "VSTMQ" || Name == "VSTMQ_UPD") - return false; - // // The following special cases are for conflict resolutions. // @@ -1610,13 +1608,13 @@ bool ARMDecoderEmitter::ARMDEBackend::populateInstruction( // better off using the generic RSCri and RSCrs instructions. if (Name == "RSCSri" || Name == "RSCSrs") return false; - // MOVCCr, MOVCCs, MOVCCi, FCYPScc, FCYPDcc, FNEGScc, and FNEGDcc are used - // in the compiler to implement conditional moves. We can ignore them in - // favor of their more generic versions of instructions. - // See also SDNode *ARMDAGToDAGISel::Select(SDValue Op). - if (Name == "MOVCCr" || Name == "MOVCCs" || Name == "MOVCCi" || - Name == "FCPYScc" || Name == "FCPYDcc" || - Name == "FNEGScc" || Name == "FNEGDcc") + // MOVCCr, MOVCCs, MOVCCi, MOVCCi16, FCYPScc, FCYPDcc, FNEGScc, and + // FNEGDcc are used in the compiler to implement conditional moves. + // We can ignore them in favor of their more generic versions of + // instructions. See also SDNode *ARMDAGToDAGISel::Select(SDValue Op). + if (Name == "MOVCCr" || Name == "MOVCCs" || Name == "MOVCCi" || + Name == "MOVCCi16" || Name == "FCPYScc" || Name == "FCPYDcc" || + Name == "FNEGScc" || Name == "FNEGDcc") return false; // Ditto for VMOVDcc, VMOVScc, VNEGDcc, and VNEGScc. @@ -1624,15 +1622,10 @@ bool ARMDecoderEmitter::ARMDEBackend::populateInstruction( Name == "VNEGScc") return false; - // Ignore the *_sfp instructions when decoding. They are used by the - // compiler to implement scalar floating point operations using vector - // operations in order to work around some performance issues. - if (Name.find("_sfp") != std::string::npos) return false; - - // LDM_RET is a special case of LDM (Load Multiple) where the registers + // LDMIA_RET is a special case of LDM (Load Multiple) where the registers // loaded include the PC, causing a branch to a loaded address. Ignore - // the LDM_RET instruction when decoding. - if (Name == "LDM_RET") return false; + // the LDMIA_RET instruction when decoding. + if (Name == "LDMIA_RET") return false; // Bcc is in a more generic form than B. Ignore B when decoding. if (Name == "B") return false; @@ -1671,18 +1664,17 @@ bool ARMDecoderEmitter::ARMDEBackend::populateInstruction( // VREV64qf is equivalent to VREV64q32. if (Name == "VREV64df" || Name == "VREV64qf") return false; - // VDUPLNfd is equivalent to VDUPLN32d; VDUPfdf is specialized VDUPLN32d. - // VDUPLNfq is equivalent to VDUPLN32q; VDUPfqf is specialized VDUPLN32q. + // VDUPLNfd is equivalent to VDUPLN32d. + // VDUPLNfq is equivalent to VDUPLN32q. // VLD1df is equivalent to VLD1d32. // VLD1qf is equivalent to VLD1q32. // VLD2d64 is equivalent to VLD1q64. // VST1df is equivalent to VST1d32. // VST1qf is equivalent to VST1q32. // VST2d64 is equivalent to VST1q64. - if (Name == "VDUPLNfd" || Name == "VDUPfdf" || - Name == "VDUPLNfq" || Name == "VDUPfqf" || - Name == "VLD1df" || Name == "VLD1qf" || Name == "VLD2d64" || - Name == "VST1df" || Name == "VST1qf" || Name == "VST2d64") + if (Name == "VDUPLNfd" || Name == "VDUPLNfq" || + Name == "VLD1df" || Name == "VLD1qf" || Name == "VLD2d64" || + Name == "VST1df" || Name == "VST1qf" || Name == "VST2d64") return false; } else if (TN == TARGET_THUMB) { if (!thumbInstruction(Form)) @@ -1696,12 +1688,8 @@ bool ARMDecoderEmitter::ARMDEBackend::populateInstruction( if (Name == "tTPsoft" || Name == "t2TPsoft") return false; - // Ignore tLEApcrel and tLEApcrelJT, prefer tADDrPCi. - if (Name == "tLEApcrel" || Name == "tLEApcrelJT") - return false; - - // Ignore t2LEApcrel, prefer the generic t2ADD* for disassembly printing. - if (Name == "t2LEApcrel") + // Ignore tADR, prefer tADDrPCi. + if (Name == "tADR") return false; // Ignore tADDrSP, tADDspr, and tPICADD, prefer the generic tADDhirr. @@ -1719,42 +1707,33 @@ bool ARMDecoderEmitter::ARMDEBackend::populateInstruction( if (Name == "t2LDRDpci") return false; - // Ignore t2TBB, t2TBH and prefer the generic t2TBBgen, t2TBHgen. - if (Name == "t2TBB" || Name == "t2TBH") - return false; - // Resolve conflicts: // // tBfar conflicts with tBLr9 - // tCMNz conflicts with tCMN (with assembly format strings being equal) - // tPOP_RET/t2LDM_RET conflict with tPOP/t2LDM (ditto) + // tPOP_RET/t2LDMIA_RET conflict with tPOP/t2LDM (ditto) // tMOVCCi conflicts with tMOVi8 // tMOVCCr conflicts with tMOVgpr2gpr - // tBR_JTr conflicts with tBRIND // tSpill conflicts with tSTRspi // tLDRcp conflicts with tLDRspi // tRestore conflicts with tLDRspi - // t2LEApcrelJT conflicts with t2LEApcrel + // t2MOVCCi16 conflicts with tMOVi16 if (Name == "tBfar" || - /* Name == "tCMNz" || */ Name == "tCMPzi8" || Name == "tCMPzr" || - Name == "tCMPzhir" || /* Name == "t2CMNzrr" || Name == "t2CMNzrs" || - Name == "t2CMNzri" || */ Name == "t2CMPzrr" || Name == "t2CMPzrs" || - Name == "t2CMPzri" || Name == "tPOP_RET" || Name == "t2LDM_RET" || - Name == "tMOVCCi" || Name == "tMOVCCr" || Name == "tBR_JTr" || + Name == "tPOP_RET" || Name == "t2LDMIA_RET" || + Name == "tMOVCCi" || Name == "tMOVCCr" || Name == "tSpill" || Name == "tLDRcp" || Name == "tRestore" || - Name == "t2LEApcrelJT") + Name == "t2MOVCCi16") return false; } - // Dumps the instruction encoding format. - switch (TargetName) { - case TARGET_ARM: - case TARGET_THUMB: - DEBUG(errs() << Name << " " << stringForARMFormat((ARMFormat)Form)); - break; - } - DEBUG({ + // Dumps the instruction encoding format. + switch (TargetName) { + case TARGET_ARM: + case TARGET_THUMB: + errs() << Name << " " << stringForARMFormat((ARMFormat)Form); + break; + } + errs() << " "; // Dumps the instruction encoding bits. @@ -1763,8 +1742,8 @@ bool ARMDecoderEmitter::ARMDEBackend::populateInstruction( errs() << '\n'; // Dumps the list of operand info. - for (unsigned i = 0, e = CGI.OperandList.size(); i != e; ++i) { - CodeGenInstruction::OperandInfo Info = CGI.OperandList[i]; + for (unsigned i = 0, e = CGI.Operands.size(); i != e; ++i) { + const CGIOperandList::OperandInfo &Info = CGI.Operands[i]; const std::string &OperandName = Info.Name; const Record &OperandDef = *Info.Rec; @@ -1778,32 +1757,20 @@ bool ARMDecoderEmitter::ARMDEBackend::populateInstruction( void ARMDecoderEmitter::ARMDEBackend::populateInstructions() { getInstructionsByEnumValue(NumberedInstructions); - uint16_t numUIDs = NumberedInstructions.size(); - uint16_t uid; - - const char *instClass = NULL; - - switch (TargetName) { - case TARGET_ARM: - instClass = "InstARM"; - break; - default: - assert(0 && "Unreachable code!"); - } - - for (uid = 0; uid < numUIDs; uid++) { - // filter out intrinsics - if (!NumberedInstructions[uid]->TheDef->isSubClassOf(instClass)) - continue; + unsigned numUIDs = NumberedInstructions.size(); + if (TargetName == TARGET_ARM) { + for (unsigned uid = 0; uid < numUIDs; uid++) { + // filter out intrinsics + if (!NumberedInstructions[uid]->TheDef->isSubClassOf("InstARM")) + continue; - if (populateInstruction(*NumberedInstructions[uid], TargetName)) - Opcodes.push_back(uid); - } + if (populateInstruction(*NumberedInstructions[uid], TargetName)) + Opcodes.push_back(uid); + } - // Special handling for the ARM chip, which supports two modes of execution. - // This branch handles the Thumb opcodes. - if (TargetName == TARGET_ARM) { - for (uid = 0; uid < numUIDs; uid++) { + // Special handling for the ARM chip, which supports two modes of execution. + // This branch handles the Thumb opcodes. + for (unsigned uid = 0; uid < numUIDs; uid++) { // filter out intrinsics if (!NumberedInstructions[uid]->TheDef->isSubClassOf("InstARM") && !NumberedInstructions[uid]->TheDef->isSubClassOf("InstThumb")) @@ -1812,6 +1779,18 @@ void ARMDecoderEmitter::ARMDEBackend::populateInstructions() { if (populateInstruction(*NumberedInstructions[uid], TARGET_THUMB)) Opcodes2.push_back(uid); } + + return; + } + + // For other targets. + for (unsigned uid = 0; uid < numUIDs; uid++) { + Record *R = NumberedInstructions[uid]->TheDef; + if (R->getValueAsString("Namespace") == "TargetOpcode") + continue; + + if (populateInstruction(*NumberedInstructions[uid], TargetName)) + Opcodes.push_back(uid); } } @@ -1826,25 +1805,25 @@ void ARMDecoderEmitter::ARMDEBackend::emit(raw_ostream &o) { assert(0 && "Unreachable code!"); } - o << "#include \"llvm/System/DataTypes.h\"\n"; + o << "#include \"llvm/Support/DataTypes.h\"\n"; o << "#include \n"; o << '\n'; o << "namespace llvm {\n\n"; - FilterChooser::setTargetName(TargetName); + ARMFilterChooser::setTargetName(TargetName); switch (TargetName) { case TARGET_ARM: { // Emit common utility and ARM ISA decoder. - FC = new FilterChooser(NumberedInstructions, Opcodes); + FC = new ARMFilterChooser(NumberedInstructions, Opcodes); // Reset indentation level. unsigned Indentation = 0; FC->emitTop(o, Indentation); delete FC; // Emit Thumb ISA decoder as well. - FilterChooser::setTargetName(TARGET_THUMB); - FC = new FilterChooser(NumberedInstructions, Opcodes2); + ARMFilterChooser::setTargetName(TARGET_THUMB); + FC = new ARMFilterChooser(NumberedInstructions, Opcodes2); // Reset indentation level. Indentation = 0; FC->emitBot(o, Indentation); @@ -1863,7 +1842,7 @@ void ARMDecoderEmitter::ARMDEBackend::emit(raw_ostream &o) { void ARMDecoderEmitter::initBackend() { - Backend = new ARMDEBackend(*this); + Backend = new ARMDEBackend(*this, Records); } void ARMDecoderEmitter::run(raw_ostream &o) diff --git a/utils/TableGen/ARMDecoderEmitter.h b/utils/TableGen/ARMDecoderEmitter.h index 571a94778acb..1faeb91fae8a 100644 --- a/utils/TableGen/ARMDecoderEmitter.h +++ b/utils/TableGen/ARMDecoderEmitter.h @@ -17,7 +17,7 @@ #include "TableGenBackend.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index 558398648d2c..e3def4185238 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -8,7 +8,11 @@ //===----------------------------------------------------------------------===// // // This tablegen backend emits a target specifier matcher for converting parsed -// assembly operands in the MCInst structures. +// assembly operands in the MCInst structures. It also emits a matcher for +// custom operand parsing. +// +// Converting assembly operands into MCInst structures +// --------------------------------------------------- // // The input to the target specific matcher is a list of literal tokens and // operands. The target specific parser should generally eliminate any syntax @@ -20,7 +24,7 @@ // Some example inputs, for X86: // 'addl' (immediate ...) (register ...) // 'add' (immediate ...) (memory ...) -// 'call' '*' %epc +// 'call' '*' %epc // // The assembly matcher is responsible for converting this input into a precise // machine instruction (i.e., an instruction with a well defined encoding). This @@ -63,26 +67,47 @@ // In addition, the subset relation amongst classes induces a partial order // on such tuples, which we use to resolve ambiguities. // -// FIXME: What do we do if a crazy case shows up where this is the wrong -// resolution? -// // 2. The input can now be treated as a tuple of classes (static tokens are // simple singleton sets). Each such tuple should generally map to a single // instruction (we currently ignore cases where this isn't true, whee!!!), // which we can emit a simple matcher for. // +// Custom Operand Parsing +// ---------------------- +// +// Some targets need a custom way to parse operands, some specific instructions +// can contain arguments that can represent processor flags and other kinds of +// identifiers that need to be mapped to specific valeus in the final encoded +// instructions. The target specific custom operand parsing works in the +// following way: +// +// 1. A operand match table is built, each entry contains a mnemonic, an +// operand class, a mask for all operand positions for that same +// class/mnemonic and target features to be checked while trying to match. +// +// 2. The operand matcher will try every possible entry with the same +// mnemonic and will check if the target feature for this mnemonic also +// matches. After that, if the operand to be matched has its index +// present in the mask, a successfull match occurs. Otherwise, fallback +// to the regular operand parsing. +// +// 3. For a match success, each operand class that has a 'ParserMethod' +// becomes part of a switch from where the custom method is called. +// //===----------------------------------------------------------------------===// #include "AsmMatcherEmitter.h" #include "CodeGenTarget.h" #include "Record.h" +#include "StringMatcher.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" -#include #include #include using namespace llvm; @@ -91,197 +116,8 @@ static cl::opt MatchPrefix("match-prefix", cl::init(""), cl::desc("Only match instructions with the given prefix")); -/// FlattenVariants - Flatten an .td file assembly string by selecting the -/// variant at index \arg N. -static std::string FlattenVariants(const std::string &AsmString, - unsigned N) { - StringRef Cur = AsmString; - std::string Res = ""; - - for (;;) { - // Find the start of the next variant string. - size_t VariantsStart = 0; - for (size_t e = Cur.size(); VariantsStart != e; ++VariantsStart) - if (Cur[VariantsStart] == '{' && - (VariantsStart == 0 || (Cur[VariantsStart-1] != '$' && - Cur[VariantsStart-1] != '\\'))) - break; - - // Add the prefix to the result. - Res += Cur.slice(0, VariantsStart); - if (VariantsStart == Cur.size()) - break; - - ++VariantsStart; // Skip the '{'. - - // Scan to the end of the variants string. - size_t VariantsEnd = VariantsStart; - unsigned NestedBraces = 1; - for (size_t e = Cur.size(); VariantsEnd != e; ++VariantsEnd) { - if (Cur[VariantsEnd] == '}' && Cur[VariantsEnd-1] != '\\') { - if (--NestedBraces == 0) - break; - } else if (Cur[VariantsEnd] == '{') - ++NestedBraces; - } - - // Select the Nth variant (or empty). - StringRef Selection = Cur.slice(VariantsStart, VariantsEnd); - for (unsigned i = 0; i != N; ++i) - Selection = Selection.split('|').second; - Res += Selection.split('|').first; - - assert(VariantsEnd != Cur.size() && - "Unterminated variants in assembly string!"); - Cur = Cur.substr(VariantsEnd + 1); - } - - return Res; -} - -/// TokenizeAsmString - Tokenize a simplified assembly string. -static void TokenizeAsmString(StringRef AsmString, - SmallVectorImpl &Tokens) { - unsigned Prev = 0; - bool InTok = true; - for (unsigned i = 0, e = AsmString.size(); i != e; ++i) { - switch (AsmString[i]) { - case '[': - case ']': - case '*': - case '!': - case ' ': - case '\t': - case ',': - if (InTok) { - Tokens.push_back(AsmString.slice(Prev, i)); - InTok = false; - } - if (!isspace(AsmString[i]) && AsmString[i] != ',') - Tokens.push_back(AsmString.substr(i, 1)); - Prev = i + 1; - break; - - case '\\': - if (InTok) { - Tokens.push_back(AsmString.slice(Prev, i)); - InTok = false; - } - ++i; - assert(i != AsmString.size() && "Invalid quoted character"); - Tokens.push_back(AsmString.substr(i, 1)); - Prev = i + 1; - break; - - case '$': { - // If this isn't "${", treat like a normal token. - if (i + 1 == AsmString.size() || AsmString[i + 1] != '{') { - if (InTok) { - Tokens.push_back(AsmString.slice(Prev, i)); - InTok = false; - } - Prev = i; - break; - } - - if (InTok) { - Tokens.push_back(AsmString.slice(Prev, i)); - InTok = false; - } - - StringRef::iterator End = - std::find(AsmString.begin() + i, AsmString.end(), '}'); - assert(End != AsmString.end() && "Missing brace in operand reference!"); - size_t EndPos = End - AsmString.begin(); - Tokens.push_back(AsmString.slice(i, EndPos+1)); - Prev = EndPos + 1; - i = EndPos; - break; - } - - case '.': - if (InTok) { - Tokens.push_back(AsmString.slice(Prev, i)); - } - Prev = i; - InTok = true; - break; - - default: - InTok = true; - } - } - if (InTok && Prev != AsmString.size()) - Tokens.push_back(AsmString.substr(Prev)); -} - -static bool IsAssemblerInstruction(StringRef Name, - const CodeGenInstruction &CGI, - const SmallVectorImpl &Tokens) { - // Ignore "codegen only" instructions. - if (CGI.TheDef->getValueAsBit("isCodeGenOnly")) - return false; - - // Ignore pseudo ops. - // - // FIXME: This is a hack; can we convert these instructions to set the - // "codegen only" bit instead? - if (const RecordVal *Form = CGI.TheDef->getValue("Form")) - if (Form->getValue()->getAsString() == "Pseudo") - return false; - - // Ignore "Int_*" and "*_Int" instructions, which are internal aliases. - // - // FIXME: This is a total hack. - if (StringRef(Name).startswith("Int_") || StringRef(Name).endswith("_Int")) - return false; - - // Ignore instructions with no .s string. - // - // FIXME: What are these? - if (CGI.AsmString.empty()) - return false; - - // FIXME: Hack; ignore any instructions with a newline in them. - if (std::find(CGI.AsmString.begin(), - CGI.AsmString.end(), '\n') != CGI.AsmString.end()) - return false; - - // Ignore instructions with attributes, these are always fake instructions for - // simplifying codegen. - // - // FIXME: Is this true? - // - // Also, check for instructions which reference the operand multiple times; - // this implies a constraint we would not honor. - std::set OperandNames; - for (unsigned i = 1, e = Tokens.size(); i < e; ++i) { - if (Tokens[i][0] == '$' && - std::find(Tokens[i].begin(), - Tokens[i].end(), ':') != Tokens[i].end()) { - DEBUG({ - errs() << "warning: '" << Name << "': " - << "ignoring instruction; operand with attribute '" - << Tokens[i] << "'\n"; - }); - return false; - } - - if (Tokens[i][0] == '$' && !OperandNames.insert(Tokens[i]).second) { - DEBUG({ - errs() << "warning: '" << Name << "': " - << "ignoring instruction with tied operand '" - << Tokens[i].str() << "'\n"; - }); - return false; - } - } - - return true; -} - namespace { - +class AsmMatcherInfo; struct SubtargetFeatureInfo; /// ClassInfo - Helper class for storing the information about a particular @@ -331,6 +167,10 @@ struct ClassInfo { /// MCInst; this is not valid for Token or register kinds. std::string RenderMethod; + /// ParserMethod - The name of the operand method to do a target specific + /// parsing on the operand. + std::string ParserMethod; + /// For register classes, the records for all the registers in this class. std::set Registers; @@ -360,7 +200,7 @@ public: std::set Tmp; std::insert_iterator< std::set > II(Tmp, Tmp.begin()); - std::set_intersection(Registers.begin(), Registers.end(), + std::set_intersection(Registers.begin(), Registers.end(), RHS.Registers.begin(), RHS.Registers.end(), II); @@ -380,11 +220,11 @@ public: const ClassInfo *RHSRoot = &RHS; while (!RHSRoot->SuperClasses.empty()) RHSRoot = RHSRoot->SuperClasses.front(); - + return Root == RHSRoot; } - /// isSubsetOf - Test whether this class is a subset of \arg RHS; + /// isSubsetOf - Test whether this class is a subset of \arg RHS; bool isSubsetOf(const ClassInfo &RHS) const { // This is a subset of RHS if it is the same class... if (this == &RHS) @@ -430,32 +270,131 @@ public: } }; -/// InstructionInfo - Helper class for storing the necessary information for an -/// instruction which is capable of being matched. -struct InstructionInfo { - struct Operand { +/// MatchableInfo - Helper class for storing the necessary information for an +/// instruction or alias which is capable of being matched. +struct MatchableInfo { + struct AsmOperand { + /// Token - This is the token that the operand came from. + StringRef Token; + /// The unique class instance this operand should match. ClassInfo *Class; - /// The original operand this corresponds to, if any. - const CodeGenInstruction::OperandInfo *OperandInfo; + /// The operand name this is, if anything. + StringRef SrcOpName; + + /// The suboperand index within SrcOpName, or -1 for the entire operand. + int SubOpIdx; + + explicit AsmOperand(StringRef T) : Token(T), Class(0), SubOpIdx(-1) {} + }; + + /// ResOperand - This represents a single operand in the result instruction + /// generated by the match. In cases (like addressing modes) where a single + /// assembler operand expands to multiple MCOperands, this represents the + /// single assembler operand, not the MCOperand. + struct ResOperand { + enum { + /// RenderAsmOperand - This represents an operand result that is + /// generated by calling the render method on the assembly operand. The + /// corresponding AsmOperand is specified by AsmOperandNum. + RenderAsmOperand, + + /// TiedOperand - This represents a result operand that is a duplicate of + /// a previous result operand. + TiedOperand, + + /// ImmOperand - This represents an immediate value that is dumped into + /// the operand. + ImmOperand, + + /// RegOperand - This represents a fixed register that is dumped in. + RegOperand + } Kind; + + union { + /// This is the operand # in the AsmOperands list that this should be + /// copied from. + unsigned AsmOperandNum; + + /// TiedOperandNum - This is the (earlier) result operand that should be + /// copied from. + unsigned TiedOperandNum; + + /// ImmVal - This is the immediate value added to the instruction. + int64_t ImmVal; + + /// Register - This is the register record. + Record *Register; + }; + + /// MINumOperands - The number of MCInst operands populated by this + /// operand. + unsigned MINumOperands; + + static ResOperand getRenderedOp(unsigned AsmOpNum, unsigned NumOperands) { + ResOperand X; + X.Kind = RenderAsmOperand; + X.AsmOperandNum = AsmOpNum; + X.MINumOperands = NumOperands; + return X; + } + + static ResOperand getTiedOp(unsigned TiedOperandNum) { + ResOperand X; + X.Kind = TiedOperand; + X.TiedOperandNum = TiedOperandNum; + X.MINumOperands = 1; + return X; + } + + static ResOperand getImmOp(int64_t Val) { + ResOperand X; + X.Kind = ImmOperand; + X.ImmVal = Val; + X.MINumOperands = 1; + return X; + } + + static ResOperand getRegOp(Record *Reg) { + ResOperand X; + X.Kind = RegOperand; + X.Register = Reg; + X.MINumOperands = 1; + return X; + } }; - /// InstrName - The target name for this instruction. - std::string InstrName; + /// TheDef - This is the definition of the instruction or InstAlias that this + /// matchable came from. + Record *const TheDef; + + /// DefRec - This is the definition that it came from. + PointerUnion DefRec; + + const CodeGenInstruction *getResultInst() const { + if (DefRec.is()) + return DefRec.get(); + return DefRec.get()->ResultInst; + } - /// Instr - The instruction this matches. - const CodeGenInstruction *Instr; + /// ResOperands - This is the operand list that should be built for the result + /// MCInst. + std::vector ResOperands; /// AsmString - The assembly string for this instruction (with variants - /// removed). + /// removed), e.g. "movsx $src, $dst". std::string AsmString; - /// Tokens - The tokenized assembly pattern that this instruction matches. - SmallVector Tokens; + /// Mnemonic - This is the first token of the matched instruction, its + /// mnemonic. + StringRef Mnemonic; - /// Operands - The operands that this instruction matches. - SmallVector Operands; + /// AsmOperands - The textual operands that this instruction matches, + /// annotated with a class and where in the OperandList they were defined. + /// This directly corresponds to the tokenized AsmString after the mnemonic is + /// removed. + SmallVector AsmOperands; /// Predicates - The required subtarget features to match this instruction. SmallVector RequiredFeatures; @@ -465,29 +404,79 @@ struct InstructionInfo { /// function. std::string ConversionFnKind; - /// operator< - Compare two instructions. - bool operator<(const InstructionInfo &RHS) const { - if (Operands.size() != RHS.Operands.size()) - return Operands.size() < RHS.Operands.size(); + MatchableInfo(const CodeGenInstruction &CGI) + : TheDef(CGI.TheDef), DefRec(&CGI), AsmString(CGI.AsmString) { + } + + MatchableInfo(const CodeGenInstAlias *Alias) + : TheDef(Alias->TheDef), DefRec(Alias), AsmString(Alias->AsmString) { + } + + void Initialize(const AsmMatcherInfo &Info, + SmallPtrSet &SingletonRegisters); + + /// Validate - Return true if this matchable is a valid thing to match against + /// and perform a bunch of validity checking. + bool Validate(StringRef CommentDelimiter, bool Hack) const; + + /// getSingletonRegisterForAsmOperand - If the specified token is a singleton + /// register, return the Record for it, otherwise return null. + Record *getSingletonRegisterForAsmOperand(unsigned i, + const AsmMatcherInfo &Info) const; + + /// FindAsmOperand - Find the AsmOperand with the specified name and + /// suboperand index. + int FindAsmOperand(StringRef N, int SubOpIdx) const { + for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) + if (N == AsmOperands[i].SrcOpName && + SubOpIdx == AsmOperands[i].SubOpIdx) + return i; + return -1; + } + + /// FindAsmOperandNamed - Find the first AsmOperand with the specified name. + /// This does not check the suboperand index. + int FindAsmOperandNamed(StringRef N) const { + for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) + if (N == AsmOperands[i].SrcOpName) + return i; + return -1; + } + + void BuildInstructionResultOperands(); + void BuildAliasResultOperands(); + + /// operator< - Compare two matchables. + bool operator<(const MatchableInfo &RHS) const { + // The primary comparator is the instruction mnemonic. + if (Mnemonic != RHS.Mnemonic) + return Mnemonic < RHS.Mnemonic; + + if (AsmOperands.size() != RHS.AsmOperands.size()) + return AsmOperands.size() < RHS.AsmOperands.size(); // Compare lexicographically by operand. The matcher validates that other - // orderings wouldn't be ambiguous using \see CouldMatchAmiguouslyWith(). - for (unsigned i = 0, e = Operands.size(); i != e; ++i) { - if (*Operands[i].Class < *RHS.Operands[i].Class) + // orderings wouldn't be ambiguous using \see CouldMatchAmbiguouslyWith(). + for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) { + if (*AsmOperands[i].Class < *RHS.AsmOperands[i].Class) return true; - if (*RHS.Operands[i].Class < *Operands[i].Class) + if (*RHS.AsmOperands[i].Class < *AsmOperands[i].Class) return false; } return false; } - /// CouldMatchAmiguouslyWith - Check whether this instruction could + /// CouldMatchAmbiguouslyWith - Check whether this matchable could /// ambiguously match the same set of operands as \arg RHS (without being a /// strictly superior match). - bool CouldMatchAmiguouslyWith(const InstructionInfo &RHS) { + bool CouldMatchAmbiguouslyWith(const MatchableInfo &RHS) { + // The primary comparator is the instruction mnemonic. + if (Mnemonic != RHS.Mnemonic) + return false; + // The number of operands is unambiguous. - if (Operands.size() != RHS.Operands.size()) + if (AsmOperands.size() != RHS.AsmOperands.size()) return false; // Otherwise, make sure the ordering of the two instructions is unambiguous @@ -496,29 +485,31 @@ struct InstructionInfo { // Tokens and operand kinds are unambiguous (assuming a correct target // specific parser). - for (unsigned i = 0, e = Operands.size(); i != e; ++i) - if (Operands[i].Class->Kind != RHS.Operands[i].Class->Kind || - Operands[i].Class->Kind == ClassInfo::Token) - if (*Operands[i].Class < *RHS.Operands[i].Class || - *RHS.Operands[i].Class < *Operands[i].Class) + for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) + if (AsmOperands[i].Class->Kind != RHS.AsmOperands[i].Class->Kind || + AsmOperands[i].Class->Kind == ClassInfo::Token) + if (*AsmOperands[i].Class < *RHS.AsmOperands[i].Class || + *RHS.AsmOperands[i].Class < *AsmOperands[i].Class) return false; - + // Otherwise, this operand could commute if all operands are equivalent, or // there is a pair of operands that compare less than and a pair that // compare greater than. bool HasLT = false, HasGT = false; - for (unsigned i = 0, e = Operands.size(); i != e; ++i) { - if (*Operands[i].Class < *RHS.Operands[i].Class) + for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) { + if (*AsmOperands[i].Class < *RHS.AsmOperands[i].Class) HasLT = true; - if (*RHS.Operands[i].Class < *Operands[i].Class) + if (*RHS.AsmOperands[i].Class < *AsmOperands[i].Class) HasGT = true; } return !(HasLT ^ HasGT); } -public: void dump(); + +private: + void TokenizeAsmString(const AsmMatcherInfo &Info); }; /// SubtargetFeatureInfo - Helper class for storing information on a subtarget @@ -530,26 +521,52 @@ struct SubtargetFeatureInfo { /// \brief An unique index assigned to represent this feature. unsigned Index; + SubtargetFeatureInfo(Record *D, unsigned Idx) : TheDef(D), Index(Idx) {} + /// \brief The name of the enumerated constant identifying this feature. - std::string EnumName; + std::string getEnumName() const { + return "Feature_" + TheDef->getName(); + } }; +struct OperandMatchEntry { + unsigned OperandMask; + MatchableInfo* MI; + ClassInfo *CI; + + static OperandMatchEntry Create(MatchableInfo* mi, ClassInfo *ci, + unsigned opMask) { + OperandMatchEntry X; + X.OperandMask = opMask; + X.CI = ci; + X.MI = mi; + return X; + } +}; + + class AsmMatcherInfo { public: + /// Tracked Records + RecordKeeper &Records; + /// The tablegen AsmParser record. Record *AsmParser; - /// The AsmParser "CommentDelimiter" value. - std::string CommentDelimiter; + /// Target - The target information. + CodeGenTarget &Target; /// The AsmParser "RegisterPrefix" value. std::string RegisterPrefix; /// The classes which are needed for matching. std::vector Classes; - - /// The information on the instruction to match. - std::vector Instructions; + + /// The information on the matchables to match. + std::vector Matchables; + + /// Info for custom matching operands by user defined methods. + std::vector OperandMatchInfo; /// Map of Register records to their class information. std::map RegisterClasses; @@ -572,108 +589,265 @@ private: ClassInfo *getTokenClass(StringRef Token); /// getOperandClass - Lookup or create the class for the given operand. - ClassInfo *getOperandClass(StringRef Token, - const CodeGenInstruction::OperandInfo &OI); - - /// getSubtargetFeature - Lookup or create the subtarget feature info for the - /// given operand. - SubtargetFeatureInfo *getSubtargetFeature(Record *Def) { - assert(Def->isSubClassOf("Predicate") && "Invalid predicate type!"); - - SubtargetFeatureInfo *&Entry = SubtargetFeatures[Def]; - if (!Entry) { - Entry = new SubtargetFeatureInfo; - Entry->TheDef = Def; - Entry->Index = SubtargetFeatures.size() - 1; - Entry->EnumName = "Feature_" + Def->getName(); - assert(Entry->Index < 32 && "Too many subtarget features!"); - } - - return Entry; - } + ClassInfo *getOperandClass(const CGIOperandList::OperandInfo &OI, + int SubOpIdx = -1); /// BuildRegisterClasses - Build the ClassInfo* instances for register /// classes. - void BuildRegisterClasses(CodeGenTarget &Target, - std::set &SingletonRegisterNames); + void BuildRegisterClasses(SmallPtrSet &SingletonRegisters); /// BuildOperandClasses - Build the ClassInfo* instances for user defined /// operand classes. - void BuildOperandClasses(CodeGenTarget &Target); + void BuildOperandClasses(); + + void BuildInstructionOperandReference(MatchableInfo *II, StringRef OpName, + unsigned AsmOpIdx); + void BuildAliasOperandReference(MatchableInfo *II, StringRef OpName, + MatchableInfo::AsmOperand &Op); public: - AsmMatcherInfo(Record *_AsmParser); + AsmMatcherInfo(Record *AsmParser, + CodeGenTarget &Target, + RecordKeeper &Records); /// BuildInfo - Construct the various tables used during matching. - void BuildInfo(CodeGenTarget &Target); + void BuildInfo(); + + /// BuildOperandMatchInfo - Build the necessary information to handle user + /// defined operand parsing methods. + void BuildOperandMatchInfo(); + + /// getSubtargetFeature - Lookup or create the subtarget feature info for the + /// given operand. + SubtargetFeatureInfo *getSubtargetFeature(Record *Def) const { + assert(Def->isSubClassOf("Predicate") && "Invalid predicate type!"); + std::map::const_iterator I = + SubtargetFeatures.find(Def); + return I == SubtargetFeatures.end() ? 0 : I->second; + } + + RecordKeeper &getRecords() const { + return Records; + } }; } -void InstructionInfo::dump() { - errs() << InstrName << " -- " << "flattened:\"" << AsmString << '\"' - << ", tokens:["; - for (unsigned i = 0, e = Tokens.size(); i != e; ++i) { - errs() << Tokens[i]; - if (i + 1 != e) - errs() << ", "; - } - errs() << "]\n"; +void MatchableInfo::dump() { + errs() << TheDef->getName() << " -- " << "flattened:\"" << AsmString <<"\"\n"; - for (unsigned i = 0, e = Operands.size(); i != e; ++i) { - Operand &Op = Operands[i]; + for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) { + AsmOperand &Op = AsmOperands[i]; errs() << " op[" << i << "] = " << Op.Class->ClassName << " - "; - if (Op.Class->Kind == ClassInfo::Token) { - errs() << '\"' << Tokens[i] << "\"\n"; - continue; + errs() << '\"' << Op.Token << "\"\n"; + } +} + +void MatchableInfo::Initialize(const AsmMatcherInfo &Info, + SmallPtrSet &SingletonRegisters) { + // TODO: Eventually support asmparser for Variant != 0. + AsmString = CodeGenInstruction::FlattenAsmStringVariants(AsmString, 0); + + TokenizeAsmString(Info); + + // Compute the require features. + std::vector Predicates =TheDef->getValueAsListOfDefs("Predicates"); + for (unsigned i = 0, e = Predicates.size(); i != e; ++i) + if (SubtargetFeatureInfo *Feature = + Info.getSubtargetFeature(Predicates[i])) + RequiredFeatures.push_back(Feature); + + // Collect singleton registers, if used. + for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) { + if (Record *Reg = getSingletonRegisterForAsmOperand(i, Info)) + SingletonRegisters.insert(Reg); + } +} + +/// TokenizeAsmString - Tokenize a simplified assembly string. +void MatchableInfo::TokenizeAsmString(const AsmMatcherInfo &Info) { + StringRef String = AsmString; + unsigned Prev = 0; + bool InTok = true; + for (unsigned i = 0, e = String.size(); i != e; ++i) { + switch (String[i]) { + case '[': + case ']': + case '*': + case '!': + case ' ': + case '\t': + case ',': + if (InTok) { + AsmOperands.push_back(AsmOperand(String.slice(Prev, i))); + InTok = false; + } + if (!isspace(String[i]) && String[i] != ',') + AsmOperands.push_back(AsmOperand(String.substr(i, 1))); + Prev = i + 1; + break; + + case '\\': + if (InTok) { + AsmOperands.push_back(AsmOperand(String.slice(Prev, i))); + InTok = false; + } + ++i; + assert(i != String.size() && "Invalid quoted character"); + AsmOperands.push_back(AsmOperand(String.substr(i, 1))); + Prev = i + 1; + break; + + case '$': { + if (InTok) { + AsmOperands.push_back(AsmOperand(String.slice(Prev, i))); + InTok = false; + } + + // If this isn't "${", treat like a normal token. + if (i + 1 == String.size() || String[i + 1] != '{') { + Prev = i; + break; + } + + StringRef::iterator End = std::find(String.begin() + i, String.end(),'}'); + assert(End != String.end() && "Missing brace in operand reference!"); + size_t EndPos = End - String.begin(); + AsmOperands.push_back(AsmOperand(String.slice(i, EndPos+1))); + Prev = EndPos + 1; + i = EndPos; + break; } - if (!Op.OperandInfo) { - errs() << "(singleton register)\n"; - continue; + case '.': + if (InTok) + AsmOperands.push_back(AsmOperand(String.slice(Prev, i))); + Prev = i; + InTok = true; + break; + + default: + InTok = true; } + } + if (InTok && Prev != String.size()) + AsmOperands.push_back(AsmOperand(String.substr(Prev))); + + // The first token of the instruction is the mnemonic, which must be a + // simple string, not a $foo variable or a singleton register. + assert(!AsmOperands.empty() && "Instruction has no tokens?"); + Mnemonic = AsmOperands[0].Token; + if (Mnemonic[0] == '$' || getSingletonRegisterForAsmOperand(0, Info)) + throw TGError(TheDef->getLoc(), + "Invalid instruction mnemonic '" + Mnemonic.str() + "'!"); + + // Remove the first operand, it is tracked in the mnemonic field. + AsmOperands.erase(AsmOperands.begin()); +} - const CodeGenInstruction::OperandInfo &OI = *Op.OperandInfo; - errs() << OI.Name << " " << OI.Rec->getName() - << " (" << OI.MIOperandNo << ", " << OI.MINumOperands << ")\n"; +bool MatchableInfo::Validate(StringRef CommentDelimiter, bool Hack) const { + // Reject matchables with no .s string. + if (AsmString.empty()) + throw TGError(TheDef->getLoc(), "instruction with empty asm string"); + + // Reject any matchables with a newline in them, they should be marked + // isCodeGenOnly if they are pseudo instructions. + if (AsmString.find('\n') != std::string::npos) + throw TGError(TheDef->getLoc(), + "multiline instruction is not valid for the asmparser, " + "mark it isCodeGenOnly"); + + // Remove comments from the asm string. We know that the asmstring only + // has one line. + if (!CommentDelimiter.empty() && + StringRef(AsmString).find(CommentDelimiter) != StringRef::npos) + throw TGError(TheDef->getLoc(), + "asmstring for instruction has comment character in it, " + "mark it isCodeGenOnly"); + + // Reject matchables with operand modifiers, these aren't something we can + // handle, the target should be refactored to use operands instead of + // modifiers. + // + // Also, check for instructions which reference the operand multiple times; + // this implies a constraint we would not honor. + std::set OperandNames; + for (unsigned i = 0, e = AsmOperands.size(); i != e; ++i) { + StringRef Tok = AsmOperands[i].Token; + if (Tok[0] == '$' && Tok.find(':') != StringRef::npos) + throw TGError(TheDef->getLoc(), + "matchable with operand modifier '" + Tok.str() + + "' not supported by asm matcher. Mark isCodeGenOnly!"); + + // Verify that any operand is only mentioned once. + // We reject aliases and ignore instructions for now. + if (Tok[0] == '$' && !OperandNames.insert(Tok).second) { + if (!Hack) + throw TGError(TheDef->getLoc(), + "ERROR: matchable with tied operand '" + Tok.str() + + "' can never be matched!"); + // FIXME: Should reject these. The ARM backend hits this with $lane in a + // bunch of instructions. It is unclear what the right answer is. + DEBUG({ + errs() << "warning: '" << TheDef->getName() << "': " + << "ignoring instruction with tied operand '" + << Tok.str() << "'\n"; + }); + return false; + } } + + return true; +} + +/// getSingletonRegisterForAsmOperand - If the specified token is a singleton +/// register, return the register name, otherwise return a null StringRef. +Record *MatchableInfo:: +getSingletonRegisterForAsmOperand(unsigned i, const AsmMatcherInfo &Info) const{ + StringRef Tok = AsmOperands[i].Token; + if (!Tok.startswith(Info.RegisterPrefix)) + return 0; + + StringRef RegName = Tok.substr(Info.RegisterPrefix.size()); + if (const CodeGenRegister *Reg = Info.Target.getRegisterByName(RegName)) + return Reg->TheDef; + + // If there is no register prefix (i.e. "%" in "%eax"), then this may + // be some random non-register token, just ignore it. + if (Info.RegisterPrefix.empty()) + return 0; + + // Otherwise, we have something invalid prefixed with the register prefix, + // such as %foo. + std::string Err = "unable to find register for '" + RegName.str() + + "' (which matches register prefix)"; + throw TGError(TheDef->getLoc(), Err); } static std::string getEnumNameForToken(StringRef Str) { std::string Res; - + for (StringRef::iterator it = Str.begin(), ie = Str.end(); it != ie; ++it) { switch (*it) { case '*': Res += "_STAR_"; break; case '%': Res += "_PCT_"; break; case ':': Res += "_COLON_"; break; - + case '!': Res += "_EXCLAIM_"; break; + case '.': Res += "_DOT_"; break; default: - if (isalnum(*it)) { + if (isalnum(*it)) Res += *it; - } else { + else Res += "_" + utostr((unsigned) *it) + "_"; - } } } return Res; } -/// getRegisterRecord - Get the register record for \arg name, or 0. -static Record *getRegisterRecord(CodeGenTarget &Target, StringRef Name) { - for (unsigned i = 0, e = Target.getRegisters().size(); i != e; ++i) { - const CodeGenRegister &Reg = Target.getRegisters()[i]; - if (Name == Reg.TheDef->getValueAsString("AsmName")) - return Reg.TheDef; - } - - return 0; -} - ClassInfo *AsmMatcherInfo::getTokenClass(StringRef Token) { ClassInfo *&Entry = TokenClasses[Token]; - + if (!Entry) { Entry = new ClassInfo(); Entry->Kind = ClassInfo::Token; @@ -682,6 +856,7 @@ ClassInfo *AsmMatcherInfo::getTokenClass(StringRef Token) { Entry->ValueName = Token; Entry->PredicateMethod = ""; Entry->RenderMethod = ""; + Entry->ParserMethod = ""; Classes.push_back(Entry); } @@ -689,65 +864,58 @@ ClassInfo *AsmMatcherInfo::getTokenClass(StringRef Token) { } ClassInfo * -AsmMatcherInfo::getOperandClass(StringRef Token, - const CodeGenInstruction::OperandInfo &OI) { - if (OI.Rec->isSubClassOf("RegisterClass")) { - ClassInfo *CI = RegisterClassClasses[OI.Rec]; - - if (!CI) { - PrintError(OI.Rec->getLoc(), "register class has no class info!"); - throw std::string("ERROR: Missing register class!"); - } - - return CI; +AsmMatcherInfo::getOperandClass(const CGIOperandList::OperandInfo &OI, + int SubOpIdx) { + Record *Rec = OI.Rec; + if (SubOpIdx != -1) + Rec = dynamic_cast(OI.MIOperandInfo->getArg(SubOpIdx))->getDef(); + + if (Rec->isSubClassOf("RegisterClass")) { + if (ClassInfo *CI = RegisterClassClasses[Rec]) + return CI; + throw TGError(Rec->getLoc(), "register class has no class info!"); } - assert(OI.Rec->isSubClassOf("Operand") && "Unexpected operand!"); - Record *MatchClass = OI.Rec->getValueAsDef("ParserMatchClass"); - ClassInfo *CI = AsmOperandClasses[MatchClass]; - - if (!CI) { - PrintError(OI.Rec->getLoc(), "operand has no match class!"); - throw std::string("ERROR: Missing match class!"); - } + assert(Rec->isSubClassOf("Operand") && "Unexpected operand!"); + Record *MatchClass = Rec->getValueAsDef("ParserMatchClass"); + if (ClassInfo *CI = AsmOperandClasses[MatchClass]) + return CI; - return CI; + throw TGError(Rec->getLoc(), "operand has no match class!"); } -void AsmMatcherInfo::BuildRegisterClasses(CodeGenTarget &Target, - std::set - &SingletonRegisterNames) { - std::vector RegisterClasses; - std::vector Registers; - - RegisterClasses = Target.getRegisterClasses(); - Registers = Target.getRegisters(); +void AsmMatcherInfo:: +BuildRegisterClasses(SmallPtrSet &SingletonRegisters) { + const std::vector &Registers = Target.getRegisters(); + const std::vector &RegClassList = + Target.getRegisterClasses(); // The register sets used for matching. std::set< std::set > RegisterSets; - // Gather the defined sets. - for (std::vector::iterator it = RegisterClasses.begin(), - ie = RegisterClasses.end(); it != ie; ++it) + // Gather the defined sets. + for (std::vector::const_iterator it = + RegClassList.begin(), ie = RegClassList.end(); it != ie; ++it) RegisterSets.insert(std::set(it->Elements.begin(), it->Elements.end())); // Add any required singleton sets. - for (std::set::iterator it = SingletonRegisterNames.begin(), - ie = SingletonRegisterNames.end(); it != ie; ++it) - if (Record *Rec = getRegisterRecord(Target, *it)) - RegisterSets.insert(std::set(&Rec, &Rec + 1)); - + for (SmallPtrSet::iterator it = SingletonRegisters.begin(), + ie = SingletonRegisters.end(); it != ie; ++it) { + Record *Rec = *it; + RegisterSets.insert(std::set(&Rec, &Rec + 1)); + } + // Introduce derived sets where necessary (when a register does not determine // a unique register set class), and build the mapping of registers to the set // they should classify to. std::map > RegisterMap; - for (std::vector::iterator it = Registers.begin(), + for (std::vector::const_iterator it = Registers.begin(), ie = Registers.end(); it != ie; ++it) { - CodeGenRegister &CGR = *it; + const CodeGenRegister &CGR = *it; // Compute the intersection of all sets containing this register. std::set ContainingSet; - + for (std::set< std::set >::iterator it = RegisterSets.begin(), ie = RegisterSets.end(); it != ie; ++it) { if (!it->count(CGR.TheDef)) @@ -755,14 +923,14 @@ void AsmMatcherInfo::BuildRegisterClasses(CodeGenTarget &Target, if (ContainingSet.empty()) { ContainingSet = *it; - } else { - std::set Tmp; - std::swap(Tmp, ContainingSet); - std::insert_iterator< std::set > II(ContainingSet, - ContainingSet.begin()); - std::set_intersection(Tmp.begin(), Tmp.end(), it->begin(), it->end(), - II); + continue; } + + std::set Tmp; + std::swap(Tmp, ContainingSet); + std::insert_iterator< std::set > II(ContainingSet, + ContainingSet.begin()); + std::set_intersection(Tmp.begin(), Tmp.end(), it->begin(), it->end(), II); } if (!ContainingSet.empty()) { @@ -795,14 +963,14 @@ void AsmMatcherInfo::BuildRegisterClasses(CodeGenTarget &Target, ClassInfo *CI = RegisterSetClasses[*it]; for (std::set< std::set >::iterator it2 = RegisterSets.begin(), ie2 = RegisterSets.end(); it2 != ie2; ++it2) - if (*it != *it2 && + if (*it != *it2 && std::includes(it2->begin(), it2->end(), it->begin(), it->end())) CI->SuperClasses.push_back(RegisterSetClasses[*it2]); } // Name the register classes which correspond to a user defined RegisterClass. - for (std::vector::iterator it = RegisterClasses.begin(), - ie = RegisterClasses.end(); it != ie; ++it) { + for (std::vector::const_iterator + it = RegClassList.begin(), ie = RegClassList.end(); it != ie; ++it) { ClassInfo *CI = RegisterSetClasses[std::set(it->Elements.begin(), it->Elements.end())]; if (CI->ValueName.empty()) { @@ -818,36 +986,35 @@ void AsmMatcherInfo::BuildRegisterClasses(CodeGenTarget &Target, // Populate the map for individual registers. for (std::map >::iterator it = RegisterMap.begin(), ie = RegisterMap.end(); it != ie; ++it) - this->RegisterClasses[it->first] = RegisterSetClasses[it->second]; + RegisterClasses[it->first] = RegisterSetClasses[it->second]; // Name the register classes which correspond to singleton registers. - for (std::set::iterator it = SingletonRegisterNames.begin(), - ie = SingletonRegisterNames.end(); it != ie; ++it) { - if (Record *Rec = getRegisterRecord(Target, *it)) { - ClassInfo *CI = this->RegisterClasses[Rec]; - assert(CI && "Missing singleton register class info!"); - - if (CI->ValueName.empty()) { - CI->ClassName = Rec->getName(); - CI->Name = "MCK_" + Rec->getName(); - CI->ValueName = Rec->getName(); - } else - CI->ValueName = CI->ValueName + "," + Rec->getName(); - } + for (SmallPtrSet::iterator it = SingletonRegisters.begin(), + ie = SingletonRegisters.end(); it != ie; ++it) { + Record *Rec = *it; + ClassInfo *CI = RegisterClasses[Rec]; + assert(CI && "Missing singleton register class info!"); + + if (CI->ValueName.empty()) { + CI->ClassName = Rec->getName(); + CI->Name = "MCK_" + Rec->getName(); + CI->ValueName = Rec->getName(); + } else + CI->ValueName = CI->ValueName + "," + Rec->getName(); } } -void AsmMatcherInfo::BuildOperandClasses(CodeGenTarget &Target) { - std::vector AsmOperands; - AsmOperands = Records.getAllDerivedDefinitions("AsmOperandClass"); +void AsmMatcherInfo::BuildOperandClasses() { + std::vector AsmOperands = + Records.getAllDerivedDefinitions("AsmOperandClass"); // Pre-populate AsmOperandClasses map. - for (std::vector::iterator it = AsmOperands.begin(), + for (std::vector::iterator it = AsmOperands.begin(), ie = AsmOperands.end(); it != ie; ++it) AsmOperandClasses[*it] = new ClassInfo(); unsigned Index = 0; - for (std::vector::iterator it = AsmOperands.begin(), + for (std::vector::iterator it = AsmOperands.begin(), ie = AsmOperands.end(); it != ie; ++it, ++Index) { ClassInfo *CI = AsmOperandClasses[*it]; CI->Kind = ClassInfo::UserClass0 + Index; @@ -875,7 +1042,7 @@ void AsmMatcherInfo::BuildOperandClasses(CodeGenTarget &Target) { if (StringInit *SI = dynamic_cast(PMName)) { CI->PredicateMethod = SI->getValue(); } else { - assert(dynamic_cast(PMName) && + assert(dynamic_cast(PMName) && "Unexpected PredicateMethod field!"); CI->PredicateMethod = "is" + CI->ClassName; } @@ -890,128 +1057,192 @@ void AsmMatcherInfo::BuildOperandClasses(CodeGenTarget &Target) { CI->RenderMethod = "add" + CI->ClassName + "Operands"; } + // Get the parse method name or leave it as empty. + Init *PRMName = (*it)->getValueInit("ParserMethod"); + if (StringInit *SI = dynamic_cast(PRMName)) + CI->ParserMethod = SI->getValue(); + AsmOperandClasses[*it] = CI; Classes.push_back(CI); } } -AsmMatcherInfo::AsmMatcherInfo(Record *_AsmParser) - : AsmParser(_AsmParser), - CommentDelimiter(AsmParser->getValueAsString("CommentDelimiter")), - RegisterPrefix(AsmParser->getValueAsString("RegisterPrefix")) -{ +AsmMatcherInfo::AsmMatcherInfo(Record *asmParser, + CodeGenTarget &target, + RecordKeeper &records) + : Records(records), AsmParser(asmParser), Target(target), + RegisterPrefix(AsmParser->getValueAsString("RegisterPrefix")) { } -void AsmMatcherInfo::BuildInfo(CodeGenTarget &Target) { +/// BuildOperandMatchInfo - Build the necessary information to handle user +/// defined operand parsing methods. +void AsmMatcherInfo::BuildOperandMatchInfo() { + + /// Map containing a mask with all operands indicies that can be found for + /// that class inside a instruction. + std::map OpClassMask; + + for (std::vector::const_iterator it = + Matchables.begin(), ie = Matchables.end(); + it != ie; ++it) { + MatchableInfo &II = **it; + OpClassMask.clear(); + + // Keep track of all operands of this instructions which belong to the + // same class. + for (unsigned i = 0, e = II.AsmOperands.size(); i != e; ++i) { + MatchableInfo::AsmOperand &Op = II.AsmOperands[i]; + if (Op.Class->ParserMethod.empty()) + continue; + unsigned &OperandMask = OpClassMask[Op.Class]; + OperandMask |= (1 << i); + } + + // Generate operand match info for each mnemonic/operand class pair. + for (std::map::iterator iit = OpClassMask.begin(), + iie = OpClassMask.end(); iit != iie; ++iit) { + unsigned OpMask = iit->second; + ClassInfo *CI = iit->first; + OperandMatchInfo.push_back(OperandMatchEntry::Create(&II, CI, OpMask)); + } + } +} + +void AsmMatcherInfo::BuildInfo() { + // Build information about all of the AssemblerPredicates. + std::vector AllPredicates = + Records.getAllDerivedDefinitions("Predicate"); + for (unsigned i = 0, e = AllPredicates.size(); i != e; ++i) { + Record *Pred = AllPredicates[i]; + // Ignore predicates that are not intended for the assembler. + if (!Pred->getValueAsBit("AssemblerMatcherPredicate")) + continue; + + if (Pred->getName().empty()) + throw TGError(Pred->getLoc(), "Predicate has no name!"); + + unsigned FeatureNo = SubtargetFeatures.size(); + SubtargetFeatures[Pred] = new SubtargetFeatureInfo(Pred, FeatureNo); + assert(FeatureNo < 32 && "Too many subtarget features!"); + } + + StringRef CommentDelimiter = AsmParser->getValueAsString("CommentDelimiter"); + // Parse the instructions; we need to do this first so that we can gather the // singleton register classes. - std::set SingletonRegisterNames; - - const std::vector &InstrList = - Target.getInstructionsByEnumValue(); - - for (unsigned i = 0, e = InstrList.size(); i != e; ++i) { - const CodeGenInstruction &CGI = *InstrList[i]; + SmallPtrSet SingletonRegisters; + for (CodeGenTarget::inst_iterator I = Target.inst_begin(), + E = Target.inst_end(); I != E; ++I) { + const CodeGenInstruction &CGI = **I; + // If the tblgen -match-prefix option is specified (for tblgen hackers), + // filter the set of instructions we consider. if (!StringRef(CGI.TheDef->getName()).startswith(MatchPrefix)) continue; - OwningPtr II(new InstructionInfo()); - - II->InstrName = CGI.TheDef->getName(); - II->Instr = &CGI; - II->AsmString = FlattenVariants(CGI.AsmString, 0); - - // Remove comments from the asm string. - if (!CommentDelimiter.empty()) { - size_t Idx = StringRef(II->AsmString).find(CommentDelimiter); - if (Idx != StringRef::npos) - II->AsmString = II->AsmString.substr(0, Idx); - } - - TokenizeAsmString(II->AsmString, II->Tokens); - - // Ignore instructions which shouldn't be matched. - if (!IsAssemblerInstruction(CGI.TheDef->getName(), CGI, II->Tokens)) + // Ignore "codegen only" instructions. + if (CGI.TheDef->getValueAsBit("isCodeGenOnly")) continue; - // Collect singleton registers, if used. - if (!RegisterPrefix.empty()) { - for (unsigned i = 0, e = II->Tokens.size(); i != e; ++i) { - if (II->Tokens[i].startswith(RegisterPrefix)) { - StringRef RegName = II->Tokens[i].substr(RegisterPrefix.size()); - Record *Rec = getRegisterRecord(Target, RegName); - - if (!Rec) { - std::string Err = "unable to find register for '" + RegName.str() + - "' (which matches register prefix)"; - throw TGError(CGI.TheDef->getLoc(), Err); - } - - SingletonRegisterNames.insert(RegName); + // Validate the operand list to ensure we can handle this instruction. + for (unsigned i = 0, e = CGI.Operands.size(); i != e; ++i) { + const CGIOperandList::OperandInfo &OI = CGI.Operands[i]; + + // Validate tied operands. + if (OI.getTiedRegister() != -1) { + // If we have a tied operand that consists of multiple MCOperands, + // reject it. We reject aliases and ignore instructions for now. + if (OI.MINumOperands != 1) { + // FIXME: Should reject these. The ARM backend hits this with $lane + // in a bunch of instructions. It is unclear what the right answer is. + DEBUG({ + errs() << "warning: '" << CGI.TheDef->getName() << "': " + << "ignoring instruction with multi-operand tied operand '" + << OI.Name << "'\n"; + }); + continue; } } } - // Compute the require features. - ListInit *Predicates = CGI.TheDef->getValueAsListInit("Predicates"); - for (unsigned i = 0, e = Predicates->getSize(); i != e; ++i) { - if (DefInit *Pred = dynamic_cast(Predicates->getElement(i))) { - // Ignore OptForSize and OptForSpeed, they aren't really requirements, - // rather they are hints to isel. - // - // FIXME: Find better way to model this. - if (Pred->getDef()->getName() == "OptForSize" || - Pred->getDef()->getName() == "OptForSpeed") - continue; + OwningPtr II(new MatchableInfo(CGI)); - // FIXME: Total hack; for now, we just limit ourselves to In32BitMode - // and In64BitMode, because we aren't going to have the right feature - // masks for SSE and friends. We need to decide what we are going to do - // about CPU subtypes to implement this the right way. - if (Pred->getDef()->getName() != "In32BitMode" && - Pred->getDef()->getName() != "In64BitMode") - continue; + II->Initialize(*this, SingletonRegisters); - II->RequiredFeatures.push_back(getSubtargetFeature(Pred->getDef())); - } - } + // Ignore instructions which shouldn't be matched and diagnose invalid + // instruction definitions with an error. + if (!II->Validate(CommentDelimiter, true)) + continue; - Instructions.push_back(II.take()); + // Ignore "Int_*" and "*_Int" instructions, which are internal aliases. + // + // FIXME: This is a total hack. + if (StringRef(II->TheDef->getName()).startswith("Int_") || + StringRef(II->TheDef->getName()).endswith("_Int")) + continue; + + Matchables.push_back(II.take()); + } + + // Parse all of the InstAlias definitions and stick them in the list of + // matchables. + std::vector AllInstAliases = + Records.getAllDerivedDefinitions("InstAlias"); + for (unsigned i = 0, e = AllInstAliases.size(); i != e; ++i) { + CodeGenInstAlias *Alias = new CodeGenInstAlias(AllInstAliases[i], Target); + + // If the tblgen -match-prefix option is specified (for tblgen hackers), + // filter the set of instruction aliases we consider, based on the target + // instruction. + if (!StringRef(Alias->ResultInst->TheDef->getName()).startswith( + MatchPrefix)) + continue; + + OwningPtr II(new MatchableInfo(Alias)); + + II->Initialize(*this, SingletonRegisters); + + // Validate the alias definitions. + II->Validate(CommentDelimiter, false); + + Matchables.push_back(II.take()); } // Build info for the register classes. - BuildRegisterClasses(Target, SingletonRegisterNames); + BuildRegisterClasses(SingletonRegisters); // Build info for the user defined assembly operand classes. - BuildOperandClasses(Target); + BuildOperandClasses(); - // Build the instruction information. - for (std::vector::iterator it = Instructions.begin(), - ie = Instructions.end(); it != ie; ++it) { - InstructionInfo *II = *it; + // Build the information about matchables, now that we have fully formed + // classes. + for (std::vector::iterator it = Matchables.begin(), + ie = Matchables.end(); it != ie; ++it) { + MatchableInfo *II = *it; - for (unsigned i = 0, e = II->Tokens.size(); i != e; ++i) { - StringRef Token = II->Tokens[i]; + // Parse the tokens after the mnemonic. + // Note: BuildInstructionOperandReference may insert new AsmOperands, so + // don't precompute the loop bound. + for (unsigned i = 0; i != II->AsmOperands.size(); ++i) { + MatchableInfo::AsmOperand &Op = II->AsmOperands[i]; + StringRef Token = Op.Token; // Check for singleton registers. - if (!RegisterPrefix.empty() && Token.startswith(RegisterPrefix)) { - StringRef RegName = II->Tokens[i].substr(RegisterPrefix.size()); - InstructionInfo::Operand Op; - Op.Class = RegisterClasses[getRegisterRecord(Target, RegName)]; - Op.OperandInfo = 0; + if (Record *RegRecord = II->getSingletonRegisterForAsmOperand(i, *this)) { + Op.Class = RegisterClasses[RegRecord]; assert(Op.Class && Op.Class->Registers.size() == 1 && "Unexpected class for singleton register"); - II->Operands.push_back(Op); continue; } // Check for simple tokens. if (Token[0] != '$') { - InstructionInfo::Operand Op; Op.Class = getTokenClass(Token); - Op.OperandInfo = 0; - II->Operands.push_back(Op); + continue; + } + + if (Token.size() > 1 && isdigit(Token[1])) { + Op.Class = getTokenClass(Token); continue; } @@ -1022,58 +1253,204 @@ void AsmMatcherInfo::BuildInfo(CodeGenTarget &Target) { else OperandName = Token.substr(1); - // Map this token to an operand. FIXME: Move elsewhere. - unsigned Idx; - try { - Idx = II->Instr->getOperandNamed(OperandName); - } catch(...) { - throw std::string("error: unable to find operand: '" + - OperandName.str() + "'"); - } + if (II->DefRec.is()) + BuildInstructionOperandReference(II, OperandName, i); + else + BuildAliasOperandReference(II, OperandName, Op); + } - // FIXME: This is annoying, the named operand may be tied (e.g., - // XCHG8rm). What we want is the untied operand, which we now have to - // grovel for. Only worry about this for single entry operands, we have to - // clean this up anyway. - const CodeGenInstruction::OperandInfo *OI = &II->Instr->OperandList[Idx]; - if (OI->Constraints[0].isTied()) { - unsigned TiedOp = OI->Constraints[0].getTiedOperand(); - - // The tied operand index is an MIOperand index, find the operand that - // contains it. - for (unsigned i = 0, e = II->Instr->OperandList.size(); i != e; ++i) { - if (II->Instr->OperandList[i].MIOperandNo == TiedOp) { - OI = &II->Instr->OperandList[i]; - break; - } - } + if (II->DefRec.is()) + II->BuildInstructionResultOperands(); + else + II->BuildAliasResultOperands(); + } - assert(OI && "Unable to find tied operand target!"); - } + // Reorder classes so that classes preceed super classes. + std::sort(Classes.begin(), Classes.end(), less_ptr()); +} - InstructionInfo::Operand Op; - Op.Class = getOperandClass(Token, *OI); - Op.OperandInfo = OI; - II->Operands.push_back(Op); +/// BuildInstructionOperandReference - The specified operand is a reference to a +/// named operand such as $src. Resolve the Class and OperandInfo pointers. +void AsmMatcherInfo:: +BuildInstructionOperandReference(MatchableInfo *II, + StringRef OperandName, + unsigned AsmOpIdx) { + const CodeGenInstruction &CGI = *II->DefRec.get(); + const CGIOperandList &Operands = CGI.Operands; + MatchableInfo::AsmOperand *Op = &II->AsmOperands[AsmOpIdx]; + + // Map this token to an operand. + unsigned Idx; + if (!Operands.hasOperandNamed(OperandName, Idx)) + throw TGError(II->TheDef->getLoc(), "error: unable to find operand: '" + + OperandName.str() + "'"); + + // If the instruction operand has multiple suboperands, but the parser + // match class for the asm operand is still the default "ImmAsmOperand", + // then handle each suboperand separately. + if (Op->SubOpIdx == -1 && Operands[Idx].MINumOperands > 1) { + Record *Rec = Operands[Idx].Rec; + assert(Rec->isSubClassOf("Operand") && "Unexpected operand!"); + Record *MatchClass = Rec->getValueAsDef("ParserMatchClass"); + if (MatchClass && MatchClass->getValueAsString("Name") == "Imm") { + // Insert remaining suboperands after AsmOpIdx in II->AsmOperands. + StringRef Token = Op->Token; // save this in case Op gets moved + for (unsigned SI = 1, SE = Operands[Idx].MINumOperands; SI != SE; ++SI) { + MatchableInfo::AsmOperand NewAsmOp(Token); + NewAsmOp.SubOpIdx = SI; + II->AsmOperands.insert(II->AsmOperands.begin()+AsmOpIdx+SI, NewAsmOp); + } + // Replace Op with first suboperand. + Op = &II->AsmOperands[AsmOpIdx]; // update the pointer in case it moved + Op->SubOpIdx = 0; } } - // Reorder classes so that classes preceed super classes. - std::sort(Classes.begin(), Classes.end(), less_ptr()); + // Set up the operand class. + Op->Class = getOperandClass(Operands[Idx], Op->SubOpIdx); + + // If the named operand is tied, canonicalize it to the untied operand. + // For example, something like: + // (outs GPR:$dst), (ins GPR:$src) + // with an asmstring of + // "inc $src" + // we want to canonicalize to: + // "inc $dst" + // so that we know how to provide the $dst operand when filling in the result. + int OITied = Operands[Idx].getTiedRegister(); + if (OITied != -1) { + // The tied operand index is an MIOperand index, find the operand that + // contains it. + std::pair Idx = Operands.getSubOperandNumber(OITied); + OperandName = Operands[Idx.first].Name; + Op->SubOpIdx = Idx.second; + } + + Op->SrcOpName = OperandName; } -static std::pair * -GetTiedOperandAtIndex(SmallVectorImpl > &List, - unsigned Index) { - for (unsigned i = 0, e = List.size(); i != e; ++i) - if (Index == List[i].first) - return &List[i]; +/// BuildAliasOperandReference - When parsing an operand reference out of the +/// matching string (e.g. "movsx $src, $dst"), determine what the class of the +/// operand reference is by looking it up in the result pattern definition. +void AsmMatcherInfo::BuildAliasOperandReference(MatchableInfo *II, + StringRef OperandName, + MatchableInfo::AsmOperand &Op) { + const CodeGenInstAlias &CGA = *II->DefRec.get(); + + // Set up the operand class. + for (unsigned i = 0, e = CGA.ResultOperands.size(); i != e; ++i) + if (CGA.ResultOperands[i].isRecord() && + CGA.ResultOperands[i].getName() == OperandName) { + // It's safe to go with the first one we find, because CodeGenInstAlias + // validates that all operands with the same name have the same record. + unsigned ResultIdx = CGA.ResultInstOperandIndex[i].first; + Op.SubOpIdx = CGA.ResultInstOperandIndex[i].second; + Op.Class = getOperandClass(CGA.ResultInst->Operands[ResultIdx], + Op.SubOpIdx); + Op.SrcOpName = OperandName; + return; + } - return 0; + throw TGError(II->TheDef->getLoc(), "error: unable to find operand: '" + + OperandName.str() + "'"); } -static void EmitConvertToMCInst(CodeGenTarget &Target, - std::vector &Infos, +void MatchableInfo::BuildInstructionResultOperands() { + const CodeGenInstruction *ResultInst = getResultInst(); + + // Loop over all operands of the result instruction, determining how to + // populate them. + for (unsigned i = 0, e = ResultInst->Operands.size(); i != e; ++i) { + const CGIOperandList::OperandInfo &OpInfo = ResultInst->Operands[i]; + + // If this is a tied operand, just copy from the previously handled operand. + int TiedOp = OpInfo.getTiedRegister(); + if (TiedOp != -1) { + ResOperands.push_back(ResOperand::getTiedOp(TiedOp)); + continue; + } + + // Find out what operand from the asmparser this MCInst operand comes from. + int SrcOperand = FindAsmOperandNamed(OpInfo.Name); + if (OpInfo.Name.empty() || SrcOperand == -1) + throw TGError(TheDef->getLoc(), "Instruction '" + + TheDef->getName() + "' has operand '" + OpInfo.Name + + "' that doesn't appear in asm string!"); + + // Check if the one AsmOperand populates the entire operand. + unsigned NumOperands = OpInfo.MINumOperands; + if (AsmOperands[SrcOperand].SubOpIdx == -1) { + ResOperands.push_back(ResOperand::getRenderedOp(SrcOperand, NumOperands)); + continue; + } + + // Add a separate ResOperand for each suboperand. + for (unsigned AI = 0; AI < NumOperands; ++AI) { + assert(AsmOperands[SrcOperand+AI].SubOpIdx == (int)AI && + AsmOperands[SrcOperand+AI].SrcOpName == OpInfo.Name && + "unexpected AsmOperands for suboperands"); + ResOperands.push_back(ResOperand::getRenderedOp(SrcOperand + AI, 1)); + } + } +} + +void MatchableInfo::BuildAliasResultOperands() { + const CodeGenInstAlias &CGA = *DefRec.get(); + const CodeGenInstruction *ResultInst = getResultInst(); + + // Loop over all operands of the result instruction, determining how to + // populate them. + unsigned AliasOpNo = 0; + unsigned LastOpNo = CGA.ResultInstOperandIndex.size(); + for (unsigned i = 0, e = ResultInst->Operands.size(); i != e; ++i) { + const CGIOperandList::OperandInfo *OpInfo = &ResultInst->Operands[i]; + + // If this is a tied operand, just copy from the previously handled operand. + int TiedOp = OpInfo->getTiedRegister(); + if (TiedOp != -1) { + ResOperands.push_back(ResOperand::getTiedOp(TiedOp)); + continue; + } + + // Handle all the suboperands for this operand. + const std::string &OpName = OpInfo->Name; + for ( ; AliasOpNo < LastOpNo && + CGA.ResultInstOperandIndex[AliasOpNo].first == i; ++AliasOpNo) { + int SubIdx = CGA.ResultInstOperandIndex[AliasOpNo].second; + + // Find out what operand from the asmparser that this MCInst operand + // comes from. + switch (CGA.ResultOperands[AliasOpNo].Kind) { + default: assert(0 && "unexpected InstAlias operand kind"); + case CodeGenInstAlias::ResultOperand::K_Record: { + StringRef Name = CGA.ResultOperands[AliasOpNo].getName(); + int SrcOperand = FindAsmOperand(Name, SubIdx); + if (SrcOperand == -1) + throw TGError(TheDef->getLoc(), "Instruction '" + + TheDef->getName() + "' has operand '" + OpName + + "' that doesn't appear in asm string!"); + unsigned NumOperands = (SubIdx == -1 ? OpInfo->MINumOperands : 1); + ResOperands.push_back(ResOperand::getRenderedOp(SrcOperand, + NumOperands)); + break; + } + case CodeGenInstAlias::ResultOperand::K_Imm: { + int64_t ImmVal = CGA.ResultOperands[AliasOpNo].getImm(); + ResOperands.push_back(ResOperand::getImmOp(ImmVal)); + break; + } + case CodeGenInstAlias::ResultOperand::K_Reg: { + Record *Reg = CGA.ResultOperands[AliasOpNo].getRegister(); + ResOperands.push_back(ResOperand::getRegOp(Reg)); + break; + } + } + } + } +} + +static void EmitConvertToMCInst(CodeGenTarget &Target, StringRef ClassName, + std::vector &Infos, raw_ostream &OS) { // Write the convert function to a separate stream, so we can drop it after // the enum. @@ -1084,8 +1461,8 @@ static void EmitConvertToMCInst(CodeGenTarget &Target, std::set GeneratedFns; // Start the unified conversion function. - - CvtOS << "static void ConvertToMCInst(ConversionKind Kind, MCInst &Inst, " + CvtOS << "bool " << Target.getName() << ClassName << "::\n"; + CvtOS << "ConvertToMCInst(unsigned Kind, MCInst &Inst, " << "unsigned Opcode,\n" << " const SmallVectorImpl &Operands) {\n"; @@ -1095,92 +1472,94 @@ static void EmitConvertToMCInst(CodeGenTarget &Target, // Start the enum, which we will generate inline. - OS << "// Unified function for converting operants to MCInst instances.\n\n"; + OS << "// Unified function for converting operands to MCInst instances.\n\n"; OS << "enum ConversionKind {\n"; - + // TargetOperandClass - This is the target's operand class, like X86Operand. std::string TargetOperandClass = Target.getName() + "Operand"; - - for (std::vector::const_iterator it = Infos.begin(), + + for (std::vector::const_iterator it = Infos.begin(), ie = Infos.end(); it != ie; ++it) { - InstructionInfo &II = **it; - - // Order the (class) operands by the order to convert them into an MCInst. - SmallVector, 4> MIOperandList; - for (unsigned i = 0, e = II.Operands.size(); i != e; ++i) { - InstructionInfo::Operand &Op = II.Operands[i]; - if (Op.OperandInfo) - MIOperandList.push_back(std::make_pair(Op.OperandInfo->MIOperandNo, i)); - } + MatchableInfo &II = **it; - // Find any tied operands. - SmallVector, 4> TiedOperands; - for (unsigned i = 0, e = II.Instr->OperandList.size(); i != e; ++i) { - const CodeGenInstruction::OperandInfo &OpInfo = II.Instr->OperandList[i]; - for (unsigned j = 0, e = OpInfo.Constraints.size(); j != e; ++j) { - const CodeGenInstruction::ConstraintInfo &CI = OpInfo.Constraints[j]; - if (CI.isTied()) - TiedOperands.push_back(std::make_pair(OpInfo.MIOperandNo + j, - CI.getTiedOperand())); - } - } + // Check if we have a custom match function. + StringRef AsmMatchConverter = II.getResultInst()->TheDef->getValueAsString( + "AsmMatchConverter"); + if (!AsmMatchConverter.empty()) { + std::string Signature = "ConvertCustom_" + AsmMatchConverter.str(); + II.ConversionFnKind = Signature; + + // Check if we have already generated this signature. + if (!GeneratedFns.insert(Signature).second) + continue; - std::sort(MIOperandList.begin(), MIOperandList.end()); + // If not, emit it now. Add to the enum list. + OS << " " << Signature << ",\n"; - // Compute the total number of operands. - unsigned NumMIOperands = 0; - for (unsigned i = 0, e = II.Instr->OperandList.size(); i != e; ++i) { - const CodeGenInstruction::OperandInfo &OI = II.Instr->OperandList[i]; - NumMIOperands = std::max(NumMIOperands, - OI.MIOperandNo + OI.MINumOperands); + CvtOS << " case " << Signature << ":\n"; + CvtOS << " return " << AsmMatchConverter + << "(Inst, Opcode, Operands);\n"; + continue; } // Build the conversion function signature. std::string Signature = "Convert"; - unsigned CurIndex = 0; - for (unsigned i = 0, e = MIOperandList.size(); i != e; ++i) { - InstructionInfo::Operand &Op = II.Operands[MIOperandList[i].second]; - assert(CurIndex <= Op.OperandInfo->MIOperandNo && - "Duplicate match for instruction operand!"); - - // Skip operands which weren't matched by anything, this occurs when the - // .td file encodes "implicit" operands as explicit ones. - // - // FIXME: This should be removed from the MCInst structure. - for (; CurIndex != Op.OperandInfo->MIOperandNo; ++CurIndex) { - std::pair *Tie = GetTiedOperandAtIndex(TiedOperands, - CurIndex); - if (!Tie) - Signature += "__Imp"; + std::string CaseBody; + raw_string_ostream CaseOS(CaseBody); + + // Compute the convert enum and the case body. + for (unsigned i = 0, e = II.ResOperands.size(); i != e; ++i) { + const MatchableInfo::ResOperand &OpInfo = II.ResOperands[i]; + + // Generate code to populate each result operand. + switch (OpInfo.Kind) { + case MatchableInfo::ResOperand::RenderAsmOperand: { + // This comes from something we parsed. + MatchableInfo::AsmOperand &Op = II.AsmOperands[OpInfo.AsmOperandNum]; + + // Registers are always converted the same, don't duplicate the + // conversion function based on them. + Signature += "__"; + if (Op.Class->isRegisterClass()) + Signature += "Reg"; else - Signature += "__Tie" + utostr(Tie->second); - } - - Signature += "__"; + Signature += Op.Class->ClassName; + Signature += utostr(OpInfo.MINumOperands); + Signature += "_" + itostr(OpInfo.AsmOperandNum); - // Registers are always converted the same, don't duplicate the conversion - // function based on them. - // - // FIXME: We could generalize this based on the render method, if it - // mattered. - if (Op.Class->isRegisterClass()) - Signature += "Reg"; - else - Signature += Op.Class->ClassName; - Signature += utostr(Op.OperandInfo->MINumOperands); - Signature += "_" + utostr(MIOperandList[i].second); - - CurIndex += Op.OperandInfo->MINumOperands; - } + CaseOS << " ((" << TargetOperandClass << "*)Operands[" + << (OpInfo.AsmOperandNum+1) << "])->" << Op.Class->RenderMethod + << "(Inst, " << OpInfo.MINumOperands << ");\n"; + break; + } - // Add any trailing implicit operands. - for (; CurIndex != NumMIOperands; ++CurIndex) { - std::pair *Tie = GetTiedOperandAtIndex(TiedOperands, - CurIndex); - if (!Tie) - Signature += "__Imp"; - else - Signature += "__Tie" + utostr(Tie->second); + case MatchableInfo::ResOperand::TiedOperand: { + // If this operand is tied to a previous one, just copy the MCInst + // operand from the earlier one.We can only tie single MCOperand values. + //assert(OpInfo.MINumOperands == 1 && "Not a singular MCOperand"); + unsigned TiedOp = OpInfo.TiedOperandNum; + assert(i > TiedOp && "Tied operand preceeds its target!"); + CaseOS << " Inst.addOperand(Inst.getOperand(" << TiedOp << "));\n"; + Signature += "__Tie" + utostr(TiedOp); + break; + } + case MatchableInfo::ResOperand::ImmOperand: { + int64_t Val = OpInfo.ImmVal; + CaseOS << " Inst.addOperand(MCOperand::CreateImm(" << Val << "));\n"; + Signature += "__imm" + itostr(Val); + break; + } + case MatchableInfo::ResOperand::RegOperand: { + if (OpInfo.Register == 0) { + CaseOS << " Inst.addOperand(MCOperand::CreateReg(0));\n"; + Signature += "__reg0"; + } else { + std::string N = getQualifiedName(OpInfo.Register); + CaseOS << " Inst.addOperand(MCOperand::CreateReg(" << N << "));\n"; + Signature += "__reg" + OpInfo.Register->getName(); + } + } + } } II.ConversionFnKind = Signature; @@ -1189,72 +1568,25 @@ static void EmitConvertToMCInst(CodeGenTarget &Target, if (!GeneratedFns.insert(Signature).second) continue; - // If not, emit it now. - - // Add to the enum list. + // If not, emit it now. Add to the enum list. OS << " " << Signature << ",\n"; - // And to the convert function. CvtOS << " case " << Signature << ":\n"; - CurIndex = 0; - for (unsigned i = 0, e = MIOperandList.size(); i != e; ++i) { - InstructionInfo::Operand &Op = II.Operands[MIOperandList[i].second]; - - // Add the implicit operands. - for (; CurIndex != Op.OperandInfo->MIOperandNo; ++CurIndex) { - // See if this is a tied operand. - std::pair *Tie = GetTiedOperandAtIndex(TiedOperands, - CurIndex); - - if (!Tie) { - // If not, this is some implicit operand. Just assume it is a register - // for now. - CvtOS << " Inst.addOperand(MCOperand::CreateReg(0));\n"; - } else { - // Copy the tied operand. - assert(Tie->first>Tie->second && "Tied operand preceeds its target!"); - CvtOS << " Inst.addOperand(Inst.getOperand(" - << Tie->second << "));\n"; - } - } - - CvtOS << " ((" << TargetOperandClass << "*)Operands[" - << MIOperandList[i].second - << "])->" << Op.Class->RenderMethod - << "(Inst, " << Op.OperandInfo->MINumOperands << ");\n"; - CurIndex += Op.OperandInfo->MINumOperands; - } - - // And add trailing implicit operands. - for (; CurIndex != NumMIOperands; ++CurIndex) { - std::pair *Tie = GetTiedOperandAtIndex(TiedOperands, - CurIndex); - - if (!Tie) { - // If not, this is some implicit operand. Just assume it is a register - // for now. - CvtOS << " Inst.addOperand(MCOperand::CreateReg(0));\n"; - } else { - // Copy the tied operand. - assert(Tie->first>Tie->second && "Tied operand preceeds its target!"); - CvtOS << " Inst.addOperand(Inst.getOperand(" - << Tie->second << "));\n"; - } - } - - CvtOS << " return;\n"; + CvtOS << CaseOS.str(); + CvtOS << " return true;\n"; } // Finish the convert function. CvtOS << " }\n"; + CvtOS << " return false;\n"; CvtOS << "}\n\n"; // Finish the enum, and drop the convert function after it. OS << " NumConversionVariants\n"; OS << "};\n\n"; - + OS << CvtOS.str(); } @@ -1268,7 +1600,7 @@ static void EmitMatchClassEnumeration(CodeGenTarget &Target, << "/// instruction matching.\n"; OS << "enum MatchClassKind {\n"; OS << " InvalidMatchClass = 0,\n"; - for (std::vector::iterator it = Infos.begin(), + for (std::vector::iterator it = Infos.begin(), ie = Infos.end(); it != ie; ++it) { ClassInfo &CI = **it; OS << " " << CI.Name << ", // "; @@ -1289,64 +1621,50 @@ static void EmitMatchClassEnumeration(CodeGenTarget &Target, OS << "}\n\n"; } -/// EmitClassifyOperand - Emit the function to classify an operand. -static void EmitClassifyOperand(CodeGenTarget &Target, - AsmMatcherInfo &Info, - raw_ostream &OS) { - OS << "static MatchClassKind ClassifyOperand(MCParsedAsmOperand *GOp) {\n" - << " " << Target.getName() << "Operand &Operand = *(" - << Target.getName() << "Operand*)GOp;\n"; +/// EmitValidateOperandClass - Emit the function to validate an operand class. +static void EmitValidateOperandClass(AsmMatcherInfo &Info, + raw_ostream &OS) { + OS << "static bool ValidateOperandClass(MCParsedAsmOperand *GOp, " + << "MatchClassKind Kind) {\n"; + OS << " " << Info.Target.getName() << "Operand &Operand = *(" + << Info.Target.getName() << "Operand*)GOp;\n"; - // Classify tokens. + // Check for Token operands first. OS << " if (Operand.isToken())\n"; - OS << " return MatchTokenString(Operand.getToken());\n\n"; + OS << " return MatchTokenString(Operand.getToken()) == Kind;\n\n"; - // Classify registers. - // - // FIXME: Don't hardcode isReg, getReg. + // Check for register operands, including sub-classes. OS << " if (Operand.isReg()) {\n"; + OS << " MatchClassKind OpKind;\n"; OS << " switch (Operand.getReg()) {\n"; - OS << " default: return InvalidMatchClass;\n"; - for (std::map::iterator + OS << " default: OpKind = InvalidMatchClass; break;\n"; + for (std::map::iterator it = Info.RegisterClasses.begin(), ie = Info.RegisterClasses.end(); it != ie; ++it) - OS << " case " << Target.getName() << "::" - << it->first->getName() << ": return " << it->second->Name << ";\n"; + OS << " case " << Info.Target.getName() << "::" + << it->first->getName() << ": OpKind = " << it->second->Name + << "; break;\n"; OS << " }\n"; + OS << " return IsSubclass(OpKind, Kind);\n"; OS << " }\n\n"; - // Classify user defined operands. - for (std::vector::iterator it = Info.Classes.begin(), + // Check the user classes. We don't care what order since we're only + // actually matching against one of them. + for (std::vector::iterator it = Info.Classes.begin(), ie = Info.Classes.end(); it != ie; ++it) { ClassInfo &CI = **it; if (!CI.isUserClass()) continue; - OS << " // '" << CI.ClassName << "' class"; - if (!CI.SuperClasses.empty()) { - OS << ", subclass of "; - for (unsigned i = 0, e = CI.SuperClasses.size(); i != e; ++i) { - if (i) OS << ", "; - OS << "'" << CI.SuperClasses[i]->ClassName << "'"; - assert(CI < *CI.SuperClasses[i] && "Invalid class relation!"); - } - } - OS << "\n"; - - OS << " if (Operand." << CI.PredicateMethod << "()) {\n"; - - // Validate subclass relationships. - if (!CI.SuperClasses.empty()) { - for (unsigned i = 0, e = CI.SuperClasses.size(); i != e; ++i) - OS << " assert(Operand." << CI.SuperClasses[i]->PredicateMethod - << "() && \"Invalid class relationship!\");\n"; - } - - OS << " return " << CI.Name << ";\n"; + OS << " // '" << CI.ClassName << "' class\n"; + OS << " if (Kind == " << CI.Name + << " && Operand." << CI.PredicateMethod << "()) {\n"; + OS << " return true;\n"; OS << " }\n\n"; } - OS << " return InvalidMatchClass;\n"; + + OS << " return false;\n"; OS << "}\n\n"; } @@ -1362,13 +1680,13 @@ static void EmitIsSubclass(CodeGenTarget &Target, OS << " switch (A) {\n"; OS << " default:\n"; OS << " return false;\n"; - for (std::vector::iterator it = Infos.begin(), + for (std::vector::iterator it = Infos.begin(), ie = Infos.end(); it != ie; ++it) { ClassInfo &A = **it; if (A.Kind != ClassInfo::Token) { std::vector SuperClasses; - for (std::vector::iterator it = Infos.begin(), + for (std::vector::iterator it = Infos.begin(), ie = Infos.end(); it != ie; ++it) { ClassInfo &B = **it; @@ -1397,153 +1715,25 @@ static void EmitIsSubclass(CodeGenTarget &Target, OS << "}\n\n"; } -typedef std::pair StringPair; - -/// FindFirstNonCommonLetter - Find the first character in the keys of the -/// string pairs that is not shared across the whole set of strings. All -/// strings are assumed to have the same length. -static unsigned -FindFirstNonCommonLetter(const std::vector &Matches) { - assert(!Matches.empty()); - for (unsigned i = 0, e = Matches[0]->first.size(); i != e; ++i) { - // Check to see if letter i is the same across the set. - char Letter = Matches[0]->first[i]; - - for (unsigned str = 0, e = Matches.size(); str != e; ++str) - if (Matches[str]->first[i] != Letter) - return i; - } - - return Matches[0]->first.size(); -} - -/// EmitStringMatcherForChar - Given a set of strings that are known to be the -/// same length and whose characters leading up to CharNo are the same, emit -/// code to verify that CharNo and later are the same. -/// -/// \return - True if control can leave the emitted code fragment. -static bool EmitStringMatcherForChar(const std::string &StrVariableName, - const std::vector &Matches, - unsigned CharNo, unsigned IndentCount, - raw_ostream &OS) { - assert(!Matches.empty() && "Must have at least one string to match!"); - std::string Indent(IndentCount*2+4, ' '); - - // If we have verified that the entire string matches, we're done: output the - // matching code. - if (CharNo == Matches[0]->first.size()) { - assert(Matches.size() == 1 && "Had duplicate keys to match on"); - - // FIXME: If Matches[0].first has embeded \n, this will be bad. - OS << Indent << Matches[0]->second << "\t // \"" << Matches[0]->first - << "\"\n"; - return false; - } - - // Bucket the matches by the character we are comparing. - std::map > MatchesByLetter; - - for (unsigned i = 0, e = Matches.size(); i != e; ++i) - MatchesByLetter[Matches[i]->first[CharNo]].push_back(Matches[i]); - - - // If we have exactly one bucket to match, see how many characters are common - // across the whole set and match all of them at once. - if (MatchesByLetter.size() == 1) { - unsigned FirstNonCommonLetter = FindFirstNonCommonLetter(Matches); - unsigned NumChars = FirstNonCommonLetter-CharNo; - - // Emit code to break out if the prefix doesn't match. - if (NumChars == 1) { - // Do the comparison with if (Str[1] != 'f') - // FIXME: Need to escape general characters. - OS << Indent << "if (" << StrVariableName << "[" << CharNo << "] != '" - << Matches[0]->first[CharNo] << "')\n"; - OS << Indent << " break;\n"; - } else { - // Do the comparison with if (Str.substr(1,3) != "foo"). - // FIXME: Need to escape general strings. - OS << Indent << "if (" << StrVariableName << ".substr(" << CharNo << "," - << NumChars << ") != \""; - OS << Matches[0]->first.substr(CharNo, NumChars) << "\")\n"; - OS << Indent << " break;\n"; - } - - return EmitStringMatcherForChar(StrVariableName, Matches, - FirstNonCommonLetter, IndentCount, OS); - } - - // Otherwise, we have multiple possible things, emit a switch on the - // character. - OS << Indent << "switch (" << StrVariableName << "[" << CharNo << "]) {\n"; - OS << Indent << "default: break;\n"; - - for (std::map >::iterator LI = - MatchesByLetter.begin(), E = MatchesByLetter.end(); LI != E; ++LI) { - // TODO: escape hard stuff (like \n) if we ever care about it. - OS << Indent << "case '" << LI->first << "':\t // " - << LI->second.size() << " strings to match.\n"; - if (EmitStringMatcherForChar(StrVariableName, LI->second, CharNo+1, - IndentCount+1, OS)) - OS << Indent << " break;\n"; - } - - OS << Indent << "}\n"; - return true; -} - - -/// EmitStringMatcher - Given a list of strings and code to execute when they -/// match, output a simple switch tree to classify the input string. -/// -/// If a match is found, the code in Vals[i].second is executed; control must -/// not exit this code fragment. If nothing matches, execution falls through. -/// -/// \param StrVariableName - The name of the variable to test. -static void EmitStringMatcher(const std::string &StrVariableName, - const std::vector &Matches, - raw_ostream &OS) { - // First level categorization: group strings by length. - std::map > MatchesByLength; - - for (unsigned i = 0, e = Matches.size(); i != e; ++i) - MatchesByLength[Matches[i].first.size()].push_back(&Matches[i]); - - // Output a switch statement on length and categorize the elements within each - // bin. - OS << " switch (" << StrVariableName << ".size()) {\n"; - OS << " default: break;\n"; - - for (std::map >::iterator LI = - MatchesByLength.begin(), E = MatchesByLength.end(); LI != E; ++LI) { - OS << " case " << LI->first << ":\t // " << LI->second.size() - << " strings to match.\n"; - if (EmitStringMatcherForChar(StrVariableName, LI->second, 0, 0, OS)) - OS << " break;\n"; - } - - OS << " }\n"; -} - - /// EmitMatchTokenString - Emit the function to match a token string to the /// appropriate match class value. static void EmitMatchTokenString(CodeGenTarget &Target, std::vector &Infos, raw_ostream &OS) { // Construct the match list. - std::vector Matches; - for (std::vector::iterator it = Infos.begin(), + std::vector Matches; + for (std::vector::iterator it = Infos.begin(), ie = Infos.end(); it != ie; ++it) { ClassInfo &CI = **it; if (CI.Kind == ClassInfo::Token) - Matches.push_back(StringPair(CI.ValueName, "return " + CI.Name + ";")); + Matches.push_back(StringMatcher::StringPair(CI.ValueName, + "return " + CI.Name + ";")); } OS << "static MatchClassKind MatchTokenString(StringRef Name) {\n"; - EmitStringMatcher("Name", Matches, OS); + StringMatcher("Name", Matches, OS).Emit(); OS << " return InvalidMatchClass;\n"; OS << "}\n\n"; @@ -1554,28 +1744,28 @@ static void EmitMatchTokenString(CodeGenTarget &Target, static void EmitMatchRegisterName(CodeGenTarget &Target, Record *AsmParser, raw_ostream &OS) { // Construct the match list. - std::vector Matches; + std::vector Matches; for (unsigned i = 0, e = Target.getRegisters().size(); i != e; ++i) { const CodeGenRegister &Reg = Target.getRegisters()[i]; if (Reg.TheDef->getValueAsString("AsmName").empty()) continue; - Matches.push_back(StringPair(Reg.TheDef->getValueAsString("AsmName"), - "return " + utostr(i + 1) + ";")); + Matches.push_back(StringMatcher::StringPair( + Reg.TheDef->getValueAsString("AsmName"), + "return " + utostr(i + 1) + ";")); } - + OS << "static unsigned MatchRegisterName(StringRef Name) {\n"; - EmitStringMatcher("Name", Matches, OS); - + StringMatcher("Name", Matches, OS).Emit(); + OS << " return 0;\n"; OS << "}\n\n"; } /// EmitSubtargetFeatureFlagEnumeration - Emit the subtarget feature flag /// definitions. -static void EmitSubtargetFeatureFlagEnumeration(CodeGenTarget &Target, - AsmMatcherInfo &Info, +static void EmitSubtargetFeatureFlagEnumeration(AsmMatcherInfo &Info, raw_ostream &OS) { OS << "// Flags for subtarget features that participate in " << "instruction matching.\n"; @@ -1584,7 +1774,7 @@ static void EmitSubtargetFeatureFlagEnumeration(CodeGenTarget &Target, it = Info.SubtargetFeatures.begin(), ie = Info.SubtargetFeatures.end(); it != ie; ++it) { SubtargetFeatureInfo &SFI = *it->second; - OS << " " << SFI.EnumName << " = (1 << " << SFI.Index << "),\n"; + OS << " " << SFI.getEnumName() << " = (1 << " << SFI.Index << "),\n"; } OS << " Feature_None = 0\n"; OS << "};\n\n"; @@ -1592,14 +1782,13 @@ static void EmitSubtargetFeatureFlagEnumeration(CodeGenTarget &Target, /// EmitComputeAvailableFeatures - Emit the function to compute the list of /// available features given a subtarget. -static void EmitComputeAvailableFeatures(CodeGenTarget &Target, - AsmMatcherInfo &Info, +static void EmitComputeAvailableFeatures(AsmMatcherInfo &Info, raw_ostream &OS) { std::string ClassName = Info.AsmParser->getValueAsString("AsmParserClassName"); - OS << "unsigned " << Target.getName() << ClassName << "::\n" - << "ComputeAvailableFeatures(const " << Target.getName() + OS << "unsigned " << Info.Target.getName() << ClassName << "::\n" + << "ComputeAvailableFeatures(const " << Info.Target.getName() << "Subtarget *Subtarget) const {\n"; OS << " unsigned Features = 0;\n"; for (std::map::const_iterator @@ -1608,73 +1797,375 @@ static void EmitComputeAvailableFeatures(CodeGenTarget &Target, SubtargetFeatureInfo &SFI = *it->second; OS << " if (" << SFI.TheDef->getValueAsString("CondString") << ")\n"; - OS << " Features |= " << SFI.EnumName << ";\n"; + OS << " Features |= " << SFI.getEnumName() << ";\n"; } OS << " return Features;\n"; OS << "}\n\n"; } +static std::string GetAliasRequiredFeatures(Record *R, + const AsmMatcherInfo &Info) { + std::vector ReqFeatures = R->getValueAsListOfDefs("Predicates"); + std::string Result; + unsigned NumFeatures = 0; + for (unsigned i = 0, e = ReqFeatures.size(); i != e; ++i) { + SubtargetFeatureInfo *F = Info.getSubtargetFeature(ReqFeatures[i]); + + if (F == 0) + throw TGError(R->getLoc(), "Predicate '" + ReqFeatures[i]->getName() + + "' is not marked as an AssemblerPredicate!"); + + if (NumFeatures) + Result += '|'; + + Result += F->getEnumName(); + ++NumFeatures; + } + + if (NumFeatures > 1) + Result = '(' + Result + ')'; + return Result; +} + +/// EmitMnemonicAliases - If the target has any MnemonicAlias<> definitions, +/// emit a function for them and return true, otherwise return false. +static bool EmitMnemonicAliases(raw_ostream &OS, const AsmMatcherInfo &Info) { + // Ignore aliases when match-prefix is set. + if (!MatchPrefix.empty()) + return false; + + std::vector Aliases = + Info.getRecords().getAllDerivedDefinitions("MnemonicAlias"); + if (Aliases.empty()) return false; + + OS << "static void ApplyMnemonicAliases(StringRef &Mnemonic, " + "unsigned Features) {\n"; + + // Keep track of all the aliases from a mnemonic. Use an std::map so that the + // iteration order of the map is stable. + std::map > AliasesFromMnemonic; + + for (unsigned i = 0, e = Aliases.size(); i != e; ++i) { + Record *R = Aliases[i]; + AliasesFromMnemonic[R->getValueAsString("FromMnemonic")].push_back(R); + } + + // Process each alias a "from" mnemonic at a time, building the code executed + // by the string remapper. + std::vector Cases; + for (std::map >::iterator + I = AliasesFromMnemonic.begin(), E = AliasesFromMnemonic.end(); + I != E; ++I) { + const std::vector &ToVec = I->second; + + // Loop through each alias and emit code that handles each case. If there + // are two instructions without predicates, emit an error. If there is one, + // emit it last. + std::string MatchCode; + int AliasWithNoPredicate = -1; + + for (unsigned i = 0, e = ToVec.size(); i != e; ++i) { + Record *R = ToVec[i]; + std::string FeatureMask = GetAliasRequiredFeatures(R, Info); + + // If this unconditionally matches, remember it for later and diagnose + // duplicates. + if (FeatureMask.empty()) { + if (AliasWithNoPredicate != -1) { + // We can't have two aliases from the same mnemonic with no predicate. + PrintError(ToVec[AliasWithNoPredicate]->getLoc(), + "two MnemonicAliases with the same 'from' mnemonic!"); + throw TGError(R->getLoc(), "this is the other MnemonicAlias."); + } + + AliasWithNoPredicate = i; + continue; + } + if (R->getValueAsString("ToMnemonic") == I->first) + throw TGError(R->getLoc(), "MnemonicAlias to the same string"); + + if (!MatchCode.empty()) + MatchCode += "else "; + MatchCode += "if ((Features & " + FeatureMask + ") == "+FeatureMask+")\n"; + MatchCode += " Mnemonic = \"" +R->getValueAsString("ToMnemonic")+"\";\n"; + } + + if (AliasWithNoPredicate != -1) { + Record *R = ToVec[AliasWithNoPredicate]; + if (!MatchCode.empty()) + MatchCode += "else\n "; + MatchCode += "Mnemonic = \"" + R->getValueAsString("ToMnemonic")+"\";\n"; + } + + MatchCode += "return;"; + + Cases.push_back(std::make_pair(I->first, MatchCode)); + } + + StringMatcher("Mnemonic", Cases, OS).Emit(); + OS << "}\n\n"; + + return true; +} + +static void EmitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target, + const AsmMatcherInfo &Info, StringRef ClassName) { + // Emit the static custom operand parsing table; + OS << "namespace {\n"; + OS << " struct OperandMatchEntry {\n"; + OS << " const char *Mnemonic;\n"; + OS << " unsigned OperandMask;\n"; + OS << " MatchClassKind Class;\n"; + OS << " unsigned RequiredFeatures;\n"; + OS << " };\n\n"; + + OS << " // Predicate for searching for an opcode.\n"; + OS << " struct LessOpcodeOperand {\n"; + OS << " bool operator()(const OperandMatchEntry &LHS, StringRef RHS) {\n"; + OS << " return StringRef(LHS.Mnemonic) < RHS;\n"; + OS << " }\n"; + OS << " bool operator()(StringRef LHS, const OperandMatchEntry &RHS) {\n"; + OS << " return LHS < StringRef(RHS.Mnemonic);\n"; + OS << " }\n"; + OS << " bool operator()(const OperandMatchEntry &LHS,"; + OS << " const OperandMatchEntry &RHS) {\n"; + OS << " return StringRef(LHS.Mnemonic) < StringRef(RHS.Mnemonic);\n"; + OS << " }\n"; + OS << " };\n"; + + OS << "} // end anonymous namespace.\n\n"; + + OS << "static const OperandMatchEntry OperandMatchTable[" + << Info.OperandMatchInfo.size() << "] = {\n"; + + OS << " /* Mnemonic, Operand List Mask, Operand Class, Features */\n"; + for (std::vector::const_iterator it = + Info.OperandMatchInfo.begin(), ie = Info.OperandMatchInfo.end(); + it != ie; ++it) { + const OperandMatchEntry &OMI = *it; + const MatchableInfo &II = *OMI.MI; + + OS << " { \"" << II.Mnemonic << "\"" + << ", " << OMI.OperandMask; + + OS << " /* "; + bool printComma = false; + for (int i = 0, e = 31; i !=e; ++i) + if (OMI.OperandMask & (1 << i)) { + if (printComma) + OS << ", "; + OS << i; + printComma = true; + } + OS << " */"; + + OS << ", " << OMI.CI->Name + << ", "; + + // Write the required features mask. + if (!II.RequiredFeatures.empty()) { + for (unsigned i = 0, e = II.RequiredFeatures.size(); i != e; ++i) { + if (i) OS << "|"; + OS << II.RequiredFeatures[i]->getEnumName(); + } + } else + OS << "0"; + OS << " },\n"; + } + OS << "};\n\n"; + + // Emit the operand class switch to call the correct custom parser for + // the found operand class. + OS << Target.getName() << ClassName << "::OperandMatchResultTy " + << Target.getName() << ClassName << "::\n" + << "TryCustomParseOperand(SmallVectorImpl" + << " &Operands,\n unsigned MCK) {\n\n" + << " switch(MCK) {\n"; + + for (std::vector::const_iterator it = Info.Classes.begin(), + ie = Info.Classes.end(); it != ie; ++it) { + ClassInfo *CI = *it; + if (CI->ParserMethod.empty()) + continue; + OS << " case " << CI->Name << ":\n" + << " return " << CI->ParserMethod << "(Operands);\n"; + } + + OS << " default:\n"; + OS << " return MatchOperand_NoMatch;\n"; + OS << " }\n"; + OS << " return MatchOperand_NoMatch;\n"; + OS << "}\n\n"; + + // Emit the static custom operand parser. This code is very similar with + // the other matcher. Also use MatchResultTy here just in case we go for + // a better error handling. + OS << Target.getName() << ClassName << "::OperandMatchResultTy " + << Target.getName() << ClassName << "::\n" + << "MatchOperandParserImpl(SmallVectorImpl" + << " &Operands,\n StringRef Mnemonic) {\n"; + + // Emit code to get the available features. + OS << " // Get the current feature set.\n"; + OS << " unsigned AvailableFeatures = getAvailableFeatures();\n\n"; + + OS << " // Get the next operand index.\n"; + OS << " unsigned NextOpNum = Operands.size()-1;\n"; + + // Emit code to search the table. + OS << " // Search the table.\n"; + OS << " std::pair"; + OS << " MnemonicRange =\n"; + OS << " std::equal_range(OperandMatchTable, OperandMatchTable+" + << Info.OperandMatchInfo.size() << ", Mnemonic,\n" + << " LessOpcodeOperand());\n\n"; + + OS << " if (MnemonicRange.first == MnemonicRange.second)\n"; + OS << " return MatchOperand_NoMatch;\n\n"; + + OS << " for (const OperandMatchEntry *it = MnemonicRange.first,\n" + << " *ie = MnemonicRange.second; it != ie; ++it) {\n"; + + OS << " // equal_range guarantees that instruction mnemonic matches.\n"; + OS << " assert(Mnemonic == it->Mnemonic);\n\n"; + + // Emit check that the required features are available. + OS << " // check if the available features match\n"; + OS << " if ((AvailableFeatures & it->RequiredFeatures) " + << "!= it->RequiredFeatures) {\n"; + OS << " continue;\n"; + OS << " }\n\n"; + + // Emit check to ensure the operand number matches. + OS << " // check if the operand in question has a custom parser.\n"; + OS << " if (!(it->OperandMask & (1 << NextOpNum)))\n"; + OS << " continue;\n\n"; + + // Emit call to the custom parser method + OS << " // call custom parse method to handle the operand\n"; + OS << " OperandMatchResultTy Result = "; + OS << "TryCustomParseOperand(Operands, it->Class);\n"; + OS << " if (Result != MatchOperand_NoMatch)\n"; + OS << " return Result;\n"; + OS << " }\n\n"; + + OS << " // Okay, we had no match.\n"; + OS << " return MatchOperand_NoMatch;\n"; + OS << "}\n\n"; +} + void AsmMatcherEmitter::run(raw_ostream &OS) { - CodeGenTarget Target; + CodeGenTarget Target(Records); Record *AsmParser = Target.getAsmParser(); std::string ClassName = AsmParser->getValueAsString("AsmParserClassName"); // Compute the information on the instructions to match. - AsmMatcherInfo Info(AsmParser); - Info.BuildInfo(Target); + AsmMatcherInfo Info(AsmParser, Target, Records); + Info.BuildInfo(); // Sort the instruction table using the partial order on classes. We use // stable_sort to ensure that ambiguous instructions are still // deterministically ordered. - std::stable_sort(Info.Instructions.begin(), Info.Instructions.end(), - less_ptr()); - + std::stable_sort(Info.Matchables.begin(), Info.Matchables.end(), + less_ptr()); + DEBUG_WITH_TYPE("instruction_info", { - for (std::vector::iterator - it = Info.Instructions.begin(), ie = Info.Instructions.end(); + for (std::vector::iterator + it = Info.Matchables.begin(), ie = Info.Matchables.end(); it != ie; ++it) (*it)->dump(); }); - // Check for ambiguous instructions. - unsigned NumAmbiguous = 0; - for (unsigned i = 0, e = Info.Instructions.size(); i != e; ++i) { - for (unsigned j = i + 1; j != e; ++j) { - InstructionInfo &A = *Info.Instructions[i]; - InstructionInfo &B = *Info.Instructions[j]; - - if (A.CouldMatchAmiguouslyWith(B)) { - DEBUG_WITH_TYPE("ambiguous_instrs", { - errs() << "warning: ambiguous instruction match:\n"; - A.dump(); - errs() << "\nis incomparable with:\n"; - B.dump(); - errs() << "\n\n"; - }); - ++NumAmbiguous; + // Check for ambiguous matchables. + DEBUG_WITH_TYPE("ambiguous_instrs", { + unsigned NumAmbiguous = 0; + for (unsigned i = 0, e = Info.Matchables.size(); i != e; ++i) { + for (unsigned j = i + 1; j != e; ++j) { + MatchableInfo &A = *Info.Matchables[i]; + MatchableInfo &B = *Info.Matchables[j]; + + if (A.CouldMatchAmbiguouslyWith(B)) { + errs() << "warning: ambiguous matchables:\n"; + A.dump(); + errs() << "\nis incomparable with:\n"; + B.dump(); + errs() << "\n\n"; + ++NumAmbiguous; + } } } - } - if (NumAmbiguous) - DEBUG_WITH_TYPE("ambiguous_instrs", { - errs() << "warning: " << NumAmbiguous - << " ambiguous instructions!\n"; - }); + if (NumAmbiguous) + errs() << "warning: " << NumAmbiguous + << " ambiguous matchables!\n"; + }); + + // Compute the information on the custom operand parsing. + Info.BuildOperandMatchInfo(); // Write the output. EmitSourceFileHeader("Assembly Matcher Source Fragment", OS); + // Information for the class declaration. + OS << "\n#ifdef GET_ASSEMBLER_HEADER\n"; + OS << "#undef GET_ASSEMBLER_HEADER\n"; + OS << " // This should be included into the middle of the declaration of\n"; + OS << " // your subclasses implementation of TargetAsmParser.\n"; + OS << " unsigned ComputeAvailableFeatures(const " << + Target.getName() << "Subtarget *Subtarget) const;\n"; + OS << " enum MatchResultTy {\n"; + OS << " Match_ConversionFail,\n"; + OS << " Match_InvalidOperand,\n"; + OS << " Match_MissingFeature,\n"; + OS << " Match_MnemonicFail,\n"; + OS << " Match_Success\n"; + OS << " };\n"; + OS << " bool ConvertToMCInst(unsigned Kind, MCInst &Inst, " + << "unsigned Opcode,\n" + << " const SmallVectorImpl " + << "&Operands);\n"; + OS << " bool MnemonicIsValid(StringRef Mnemonic);\n"; + OS << " MatchResultTy MatchInstructionImpl(\n"; + OS << " const SmallVectorImpl &Operands,\n"; + OS << " MCInst &Inst, unsigned &ErrorInfo);\n"; + + if (Info.OperandMatchInfo.size()) { + OS << "\n enum OperandMatchResultTy {\n"; + OS << " MatchOperand_Success, // operand matched successfully\n"; + OS << " MatchOperand_NoMatch, // operand did not match\n"; + OS << " MatchOperand_ParseFail // operand matched but had errors\n"; + OS << " };\n"; + OS << " OperandMatchResultTy MatchOperandParserImpl(\n"; + OS << " SmallVectorImpl &Operands,\n"; + OS << " StringRef Mnemonic);\n"; + + OS << " OperandMatchResultTy TryCustomParseOperand(\n"; + OS << " SmallVectorImpl &Operands,\n"; + OS << " unsigned MCK);\n\n"; + } + + OS << "#endif // GET_ASSEMBLER_HEADER_INFO\n\n"; + + OS << "\n#ifdef GET_REGISTER_MATCHER\n"; + OS << "#undef GET_REGISTER_MATCHER\n\n"; + // Emit the subtarget feature enumeration. - EmitSubtargetFeatureFlagEnumeration(Target, Info, OS); + EmitSubtargetFeatureFlagEnumeration(Info, OS); // Emit the function to match a register name to number. EmitMatchRegisterName(Target, AsmParser, OS); - - OS << "#ifndef REGISTERS_ONLY\n\n"; + + OS << "#endif // GET_REGISTER_MATCHER\n\n"; + + + OS << "\n#ifdef GET_MATCHER_IMPLEMENTATION\n"; + OS << "#undef GET_MATCHER_IMPLEMENTATION\n\n"; + + // Generate the function that remaps for mnemonic aliases. + bool HasMnemonicAliases = EmitMnemonicAliases(OS, Info); // Generate the unified function to convert operands into an MCInst. - EmitConvertToMCInst(Target, Info.Instructions, OS); + EmitConvertToMCInst(Target, ClassName, Info.Matchables, OS); // Emit the enumeration for classes which participate in matching. EmitMatchClassEnumeration(Target, Info.Classes, OS); @@ -1682,27 +2173,21 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { // Emit the routine to match token strings to their match class. EmitMatchTokenString(Target, Info.Classes, OS); - // Emit the routine to classify an operand. - EmitClassifyOperand(Target, Info, OS); - // Emit the subclass predicate routine. EmitIsSubclass(Target, Info.Classes, OS); + // Emit the routine to validate an operand against a match class. + EmitValidateOperandClass(Info, OS); + // Emit the available features compute function. - EmitComputeAvailableFeatures(Target, Info, OS); + EmitComputeAvailableFeatures(Info, OS); - // Finally, build the match function. size_t MaxNumOperands = 0; - for (std::vector::const_iterator it = - Info.Instructions.begin(), ie = Info.Instructions.end(); + for (std::vector::const_iterator it = + Info.Matchables.begin(), ie = Info.Matchables.end(); it != ie; ++it) - MaxNumOperands = std::max(MaxNumOperands, (*it)->Operands.size()); - - OS << "bool " << Target.getName() << ClassName << "::\n" - << "MatchInstructionImpl(const SmallVectorImpl" - << " &Operands,\n"; - OS << " MCInst &Inst) {\n"; + MaxNumOperands = std::max(MaxNumOperands, (*it)->AsmOperands.size()); // Emit the static match table; unused classes get initalized to 0 which is // guaranteed to be InvalidMatchClass. @@ -1714,23 +2199,44 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { // order the match kinds appropriately (putting mnemonics last), then we // should only end up using a few bits for each class, especially the ones // following the mnemonic. - OS << " static const struct MatchEntry {\n"; + OS << "namespace {\n"; + OS << " struct MatchEntry {\n"; OS << " unsigned Opcode;\n"; + OS << " const char *Mnemonic;\n"; OS << " ConversionKind ConvertFn;\n"; OS << " MatchClassKind Classes[" << MaxNumOperands << "];\n"; OS << " unsigned RequiredFeatures;\n"; - OS << " } MatchTable[" << Info.Instructions.size() << "] = {\n"; + OS << " };\n\n"; + + OS << " // Predicate for searching for an opcode.\n"; + OS << " struct LessOpcode {\n"; + OS << " bool operator()(const MatchEntry &LHS, StringRef RHS) {\n"; + OS << " return StringRef(LHS.Mnemonic) < RHS;\n"; + OS << " }\n"; + OS << " bool operator()(StringRef LHS, const MatchEntry &RHS) {\n"; + OS << " return LHS < StringRef(RHS.Mnemonic);\n"; + OS << " }\n"; + OS << " bool operator()(const MatchEntry &LHS, const MatchEntry &RHS) {\n"; + OS << " return StringRef(LHS.Mnemonic) < StringRef(RHS.Mnemonic);\n"; + OS << " }\n"; + OS << " };\n"; + + OS << "} // end anonymous namespace.\n\n"; + + OS << "static const MatchEntry MatchTable[" + << Info.Matchables.size() << "] = {\n"; - for (std::vector::const_iterator it = - Info.Instructions.begin(), ie = Info.Instructions.end(); + for (std::vector::const_iterator it = + Info.Matchables.begin(), ie = Info.Matchables.end(); it != ie; ++it) { - InstructionInfo &II = **it; + MatchableInfo &II = **it; - OS << " { " << Target.getName() << "::" << II.InstrName + OS << " { " << Target.getName() << "::" + << II.getResultInst()->TheDef->getName() << ", \"" << II.Mnemonic << "\"" << ", " << II.ConversionFnKind << ", { "; - for (unsigned i = 0, e = II.Operands.size(); i != e; ++i) { - InstructionInfo::Operand &Op = II.Operands[i]; - + for (unsigned i = 0, e = II.AsmOperands.size(); i != e; ++i) { + MatchableInfo::AsmOperand &Op = II.AsmOperands[i]; + if (i) OS << ", "; OS << Op.Class->Name; } @@ -1740,7 +2246,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { if (!II.RequiredFeatures.empty()) { for (unsigned i = 0, e = II.RequiredFeatures.size(); i != e; ++i) { if (i) OS << "|"; - OS << II.RequiredFeatures[i]->EnumName; + OS << II.RequiredFeatures[i]->getEnumName(); } } else OS << "0"; @@ -1748,52 +2254,101 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << "},\n"; } - OS << " };\n\n"; + OS << "};\n\n"; + // A method to determine if a mnemonic is in the list. + OS << "bool " << Target.getName() << ClassName << "::\n" + << "MnemonicIsValid(StringRef Mnemonic) {\n"; + OS << " // Search the table.\n"; + OS << " std::pair MnemonicRange =\n"; + OS << " std::equal_range(MatchTable, MatchTable+" + << Info.Matchables.size() << ", Mnemonic, LessOpcode());\n"; + OS << " return MnemonicRange.first != MnemonicRange.second;\n"; + OS << "}\n\n"; + + // Finally, build the match function. + OS << Target.getName() << ClassName << "::MatchResultTy " + << Target.getName() << ClassName << "::\n" + << "MatchInstructionImpl(const SmallVectorImpl" + << " &Operands,\n"; + OS << " MCInst &Inst, unsigned &ErrorInfo) {\n"; // Emit code to get the available features. OS << " // Get the current feature set.\n"; OS << " unsigned AvailableFeatures = getAvailableFeatures();\n\n"; - // Emit code to compute the class list for this operand vector. - OS << " // Eliminate obvious mismatches.\n"; - OS << " if (Operands.size() > " << MaxNumOperands << ")\n"; - OS << " return true;\n\n"; + OS << " // Get the instruction mnemonic, which is the first token.\n"; + OS << " StringRef Mnemonic = ((" << Target.getName() + << "Operand*)Operands[0])->getToken();\n\n"; - OS << " // Compute the class list for this operand vector.\n"; - OS << " MatchClassKind Classes[" << MaxNumOperands << "];\n"; - OS << " for (unsigned i = 0, e = Operands.size(); i != e; ++i) {\n"; - OS << " Classes[i] = ClassifyOperand(Operands[i]);\n\n"; + if (HasMnemonicAliases) { + OS << " // Process all MnemonicAliases to remap the mnemonic.\n"; + OS << " ApplyMnemonicAliases(Mnemonic, AvailableFeatures);\n\n"; + } - OS << " // Check for invalid operands before matching.\n"; - OS << " if (Classes[i] == InvalidMatchClass)\n"; - OS << " return true;\n"; + // Emit code to compute the class list for this operand vector. + OS << " // Eliminate obvious mismatches.\n"; + OS << " if (Operands.size() > " << (MaxNumOperands+1) << ") {\n"; + OS << " ErrorInfo = " << (MaxNumOperands+1) << ";\n"; + OS << " return Match_InvalidOperand;\n"; OS << " }\n\n"; - OS << " // Mark unused classes.\n"; - OS << " for (unsigned i = Operands.size(), e = " << MaxNumOperands << "; " - << "i != e; ++i)\n"; - OS << " Classes[i] = InvalidMatchClass;\n\n"; + OS << " // Some state to try to produce better error messages.\n"; + OS << " bool HadMatchOtherThanFeatures = false;\n\n"; + OS << " // Set ErrorInfo to the operand that mismatches if it is\n"; + OS << " // wrong for all instances of the instruction.\n"; + OS << " ErrorInfo = ~0U;\n"; // Emit code to search the table. OS << " // Search the table.\n"; - OS << " for (const MatchEntry *it = MatchTable, " - << "*ie = MatchTable + " << Info.Instructions.size() - << "; it != ie; ++it) {\n"; + OS << " std::pair MnemonicRange =\n"; + OS << " std::equal_range(MatchTable, MatchTable+" + << Info.Matchables.size() << ", Mnemonic, LessOpcode());\n\n"; - // Emit check that the required features are available. - OS << " if ((AvailableFeatures & it->RequiredFeatures) " - << "!= it->RequiredFeatures)\n"; - OS << " continue;\n"; + OS << " // Return a more specific error code if no mnemonics match.\n"; + OS << " if (MnemonicRange.first == MnemonicRange.second)\n"; + OS << " return Match_MnemonicFail;\n\n"; + + OS << " for (const MatchEntry *it = MnemonicRange.first, " + << "*ie = MnemonicRange.second;\n"; + OS << " it != ie; ++it) {\n"; + + OS << " // equal_range guarantees that instruction mnemonic matches.\n"; + OS << " assert(Mnemonic == it->Mnemonic);\n"; // Emit check that the subclasses match. - for (unsigned i = 0; i != MaxNumOperands; ++i) { - OS << " if (!IsSubclass(Classes[" - << i << "], it->Classes[" << i << "]))\n"; - OS << " continue;\n"; - } + OS << " bool OperandsValid = true;\n"; + OS << " for (unsigned i = 0; i != " << MaxNumOperands << "; ++i) {\n"; + OS << " if (i + 1 >= Operands.size()) {\n"; + OS << " OperandsValid = (it->Classes[i] == " <<"InvalidMatchClass);\n"; + OS << " break;"; + OS << " }\n"; + OS << " if (ValidateOperandClass(Operands[i+1], it->Classes[i]))\n"; + OS << " continue;\n"; + OS << " // If this operand is broken for all of the instances of this\n"; + OS << " // mnemonic, keep track of it so we can report loc info.\n"; + OS << " if (it == MnemonicRange.first || ErrorInfo <= i+1)\n"; + OS << " ErrorInfo = i+1;\n"; + OS << " // Otherwise, just reject this instance of the mnemonic.\n"; + OS << " OperandsValid = false;\n"; + OS << " break;\n"; + OS << " }\n\n"; + + OS << " if (!OperandsValid) continue;\n"; + + // Emit check that the required features are available. + OS << " if ((AvailableFeatures & it->RequiredFeatures) " + << "!= it->RequiredFeatures) {\n"; + OS << " HadMatchOtherThanFeatures = true;\n"; + OS << " continue;\n"; + OS << " }\n"; + OS << "\n"; + OS << " // We have selected a definite instruction, convert the parsed\n" + << " // operands into the appropriate MCInst.\n"; + OS << " if (!ConvertToMCInst(it->ConvertFn, Inst,\n" + << " it->Opcode, Operands))\n"; + OS << " return Match_ConversionFail;\n"; OS << "\n"; - OS << " ConvertToMCInst(it->ConvertFn, Inst, it->Opcode, Operands);\n"; // Call the post-processing function, if used. std::string InsnCleanupFn = @@ -1801,11 +2356,16 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { if (!InsnCleanupFn.empty()) OS << " " << InsnCleanupFn << "(Inst);\n"; - OS << " return false;\n"; + OS << " return Match_Success;\n"; OS << " }\n\n"; - OS << " return true;\n"; + OS << " // Okay, we had no match. Try to return a useful error code.\n"; + OS << " if (HadMatchOtherThanFeatures) return Match_MissingFeature;\n"; + OS << " return Match_InvalidOperand;\n"; OS << "}\n\n"; - - OS << "#endif // REGISTERS_ONLY\n"; + + if (Info.OperandMatchInfo.size()) + EmitCustomOperandParsing(OS, Target, Info, ClassName); + + OS << "#endif // GET_MATCHER_IMPLEMENTATION\n\n"; } diff --git a/utils/TableGen/AsmWriterEmitter.cpp b/utils/TableGen/AsmWriterEmitter.cpp index 23f13c2ae2d4..448ebad91f09 100644 --- a/utils/TableGen/AsmWriterEmitter.cpp +++ b/utils/TableGen/AsmWriterEmitter.cpp @@ -101,22 +101,22 @@ static void EmitInstructions(std::vector &Insts, } void AsmWriterEmitter:: -FindUniqueOperandCommands(std::vector &UniqueOperandCommands, +FindUniqueOperandCommands(std::vector &UniqueOperandCommands, std::vector &InstIdxs, std::vector &InstOpsUsed) const { InstIdxs.assign(NumberedInstructions.size(), ~0U); - + // This vector parallels UniqueOperandCommands, keeping track of which // instructions each case are used for. It is a comma separated string of // enums. std::vector InstrsForCase; InstrsForCase.resize(UniqueOperandCommands.size()); InstOpsUsed.assign(UniqueOperandCommands.size(), 0); - + for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { const AsmWriterInst *Inst = getAsmWriterInstByID(i); if (Inst == 0) continue; // PHI, INLINEASM, PROLOG_LABEL, etc. - + std::string Command; if (Inst->Operands.empty()) continue; // Instruction already done. @@ -143,13 +143,13 @@ FindUniqueOperandCommands(std::vector &UniqueOperandCommands, InstOpsUsed.push_back(1); } } - + // For each entry of UniqueOperandCommands, there is a set of instructions // that uses it. If the next command of all instructions in the set are // identical, fold it into the command. for (unsigned CommandIdx = 0, e = UniqueOperandCommands.size(); CommandIdx != e; ++CommandIdx) { - + for (unsigned Op = 1; ; ++Op) { // Scan for the first instruction in the set. std::vector::iterator NIT = @@ -158,7 +158,7 @@ FindUniqueOperandCommands(std::vector &UniqueOperandCommands, // If this instruction has no more operands, we isn't anything to merge // into this command. - const AsmWriterInst *FirstInst = + const AsmWriterInst *FirstInst = getAsmWriterInstByID(NIT-InstIdxs.begin()); if (!FirstInst || FirstInst->Operands.size() == Op) break; @@ -175,7 +175,7 @@ FindUniqueOperandCommands(std::vector &UniqueOperandCommands, NIT = std::find(NIT+1, InstIdxs.end(), CommandIdx)) { // Okay, found another instruction in this command set. If the operand // matches, we're ok, otherwise bail out. - const AsmWriterInst *OtherInst = + const AsmWriterInst *OtherInst = getAsmWriterInstByID(NIT-InstIdxs.begin()); if (OtherInst && @@ -189,16 +189,16 @@ FindUniqueOperandCommands(std::vector &UniqueOperandCommands, } } if (!AllSame) break; - + // Okay, everything in this command set has the same next operand. Add it // to UniqueOperandCommands and remember that it was consumed. std::string Command = " " + FirstInst->Operands[Op].getCode() + "\n"; - + UniqueOperandCommands[CommandIdx] += Command; InstOpsUsed[CommandIdx]++; } } - + // Prepend some of the instructions each case is used for onto the case val. for (unsigned i = 0, e = InstrsForCase.size(); i != e; ++i) { std::string Instrs = InstrsForCase[i]; @@ -206,9 +206,9 @@ FindUniqueOperandCommands(std::vector &UniqueOperandCommands, Instrs.erase(Instrs.begin()+70, Instrs.end()); Instrs += "..."; } - + if (!Instrs.empty()) - UniqueOperandCommands[i] = " // " + Instrs + "\n" + + UniqueOperandCommands[i] = " // " + Instrs + "\n" + UniqueOperandCommands[i]; } } @@ -240,15 +240,18 @@ static void UnescapeString(std::string &Str) { /// EmitPrintInstruction - Generate the code for the "printInstruction" method /// implementation. void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { - CodeGenTarget Target; + CodeGenTarget Target(Records); Record *AsmWriter = Target.getAsmWriter(); std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); - + bool isMC = AsmWriter->getValueAsBit("isMCAsmWriter"); + const char *MachineInstrClassName = isMC ? "MCInst" : "MachineInstr"; + O << "/// printInstruction - This method is automatically generated by tablegen\n" "/// from the instruction set description.\n" "void " << Target.getName() << ClassName - << "::printInstruction(const MachineInstr *MI, raw_ostream &O) {\n"; + << "::printInstruction(const " << MachineInstrClassName + << " *MI, raw_ostream &O) {\n"; std::vector Instructions; @@ -257,14 +260,14 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { if (!(*I)->AsmString.empty() && (*I)->TheDef->getName() != "PHI") Instructions.push_back( - AsmWriterInst(**I, + AsmWriterInst(**I, AsmWriter->getValueAsInt("Variant"), AsmWriter->getValueAsInt("FirstOperandColumn"), AsmWriter->getValueAsInt("OperandSpacing"))); // Get the instruction numbering. NumberedInstructions = Target.getInstructionsByEnumValue(); - + // Compute the CodeGenInstruction -> AsmWriterInst mapping. Note that not // all machine instructions are necessarily being printed, so there may be // target instructions not in this map. @@ -273,11 +276,11 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { // Build an aggregate string, and build a table of offsets into it. StringToOffsetTable StringTable; - + /// OpcodeInfo - This encodes the index of the string to use for the first /// chunk of the output as well as indices used for operand printing. std::vector OpcodeInfo; - + unsigned MaxStringIdx = 0; for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { AsmWriterInst *AWI = CGIAWIMap[NumberedInstructions[i]]; @@ -285,7 +288,7 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { if (AWI == 0) { // Something not handled by the asmwriter printer. Idx = ~0U; - } else if (AWI->Operands[0].OperandType != + } else if (AWI->Operands[0].OperandType != AsmWriterOperand::isLiteralTextOperand || AWI->Operands[0].Str.empty()) { // Something handled by the asmwriter printer, but with no leading string. @@ -295,51 +298,51 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { UnescapeString(Str); Idx = StringTable.GetOrAddStringOffset(Str); MaxStringIdx = std::max(MaxStringIdx, Idx); - + // Nuke the string from the operand list. It is now handled! AWI->Operands.erase(AWI->Operands.begin()); } - + // Bias offset by one since we want 0 as a sentinel. OpcodeInfo.push_back(Idx+1); } - + // Figure out how many bits we used for the string index. unsigned AsmStrBits = Log2_32_Ceil(MaxStringIdx+2); - + // To reduce code size, we compactify common instructions into a few bits // in the opcode-indexed table. unsigned BitsLeft = 32-AsmStrBits; std::vector > TableDrivenOperandPrinters; - + while (1) { std::vector UniqueOperandCommands; std::vector InstIdxs; std::vector NumInstOpsHandled; FindUniqueOperandCommands(UniqueOperandCommands, InstIdxs, NumInstOpsHandled); - + // If we ran out of operands to print, we're done. if (UniqueOperandCommands.empty()) break; - + // Compute the number of bits we need to represent these cases, this is // ceil(log2(numentries)). unsigned NumBits = Log2_32_Ceil(UniqueOperandCommands.size()); - + // If we don't have enough bits for this operand, don't include it. if (NumBits > BitsLeft) { DEBUG(errs() << "Not enough bits to densely encode " << NumBits << " more bits\n"); break; } - + // Otherwise, we can include this in the initial lookup table. Add it in. BitsLeft -= NumBits; for (unsigned i = 0, e = InstIdxs.size(); i != e; ++i) if (InstIdxs[i] != ~0U) OpcodeInfo[i] |= InstIdxs[i] << (BitsLeft+AsmStrBits); - + // Remove the info about this operand. for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { if (AsmWriterInst *Inst = getAsmWriterInstByID(i)) @@ -351,13 +354,13 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { Inst->Operands.begin()+NumOps); } } - + // Remember the handlers for this set of operands. TableDrivenOperandPrinters.push_back(UniqueOperandCommands); } - - - + + + O<<" static const unsigned OpInfo[] = {\n"; for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { O << " " << OpcodeInfo[i] << "U,\t// " @@ -366,7 +369,7 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { // Add a dummy entry so the array init doesn't end with a comma. O << " 0U\n"; O << " };\n\n"; - + // Emit the string itself. O << " const char *AsmStrs = \n"; StringTable.EmitString(O); @@ -388,13 +391,13 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { // ceil(log2(numentries)). unsigned NumBits = Log2_32_Ceil(Commands.size()); assert(NumBits <= BitsLeft && "consistency error"); - + // Emit code to extract this field from Bits. BitsLeft -= NumBits; - + O << "\n // Fragment " << i << " encoded into " << NumBits << " bits for " << Commands.size() << " unique commands.\n"; - + if (Commands.size() == 2) { // Emit two possibilitys with if/else. O << " if ((Bits >> " << (BitsLeft+AsmStrBits) << ") & " @@ -403,11 +406,14 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { << " } else {\n" << Commands[0] << " }\n\n"; + } else if (Commands.size() == 1) { + // Emit a single possibility. + O << Commands[0] << "\n\n"; } else { O << " switch ((Bits >> " << (BitsLeft+AsmStrBits) << ") & " << ((1 << NumBits)-1) << ") {\n" << " default: // unreachable.\n"; - + // Print out all the cases. for (unsigned i = 0, e = Commands.size(); i != e; ++i) { O << " case " << i << ":\n"; @@ -417,7 +423,7 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { O << " }\n\n"; } } - + // Okay, delete instructions with no operand info left. for (unsigned i = 0, e = Instructions.size(); i != e; ++i) { // Entire instruction has been emitted? @@ -428,12 +434,12 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { } } - + // Because this is a vector, we want to emit from the end. Reverse all of the // elements in the vector. std::reverse(Instructions.begin(), Instructions.end()); - - + + // Now that we've emitted all of the operand info that fit into 32 bits, emit // information for those instructions that are left. This is a less dense // encoding, but we expect the main 32-bit table to handle the majority of @@ -453,11 +459,11 @@ void AsmWriterEmitter::EmitPrintInstruction(raw_ostream &O) { void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) { - CodeGenTarget Target; + CodeGenTarget Target(Records); Record *AsmWriter = Target.getAsmWriter(); std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); const std::vector &Registers = Target.getRegisters(); - + StringToOffsetTable StringTable; O << "\n\n/// getRegisterName - This method is automatically generated by tblgen\n" @@ -475,33 +481,33 @@ void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) { std::string AsmName = Reg.TheDef->getValueAsString("AsmName"); if (AsmName.empty()) AsmName = Reg.getName(); - - + + if ((i % 14) == 0) O << "\n "; - + O << StringTable.GetOrAddStringOffset(AsmName) << ", "; } O << "0\n" << " };\n" << "\n"; - + O << " const char *AsmStrs =\n"; StringTable.EmitString(O); O << ";\n"; - + O << " return AsmStrs+RegAsmOffset[RegNo-1];\n" << "}\n"; } void AsmWriterEmitter::EmitGetInstructionName(raw_ostream &O) { - CodeGenTarget Target; + CodeGenTarget Target(Records); Record *AsmWriter = Target.getAsmWriter(); std::string ClassName = AsmWriter->getValueAsString("AsmWriterClassName"); const std::vector &NumberedInstructions = Target.getInstructionsByEnumValue(); - + StringToOffsetTable StringTable; O << "\n\n#ifdef GET_INSTRUCTION_NAME\n" @@ -517,21 +523,21 @@ void AsmWriterEmitter::EmitGetInstructionName(raw_ostream &O) { << " static const unsigned InstAsmOffset[] = {"; for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) { const CodeGenInstruction &Inst = *NumberedInstructions[i]; - + std::string AsmName = Inst.TheDef->getName(); if ((i % 14) == 0) O << "\n "; - + O << StringTable.GetOrAddStringOffset(AsmName) << ", "; } O << "0\n" << " };\n" << "\n"; - + O << " const char *Strs =\n"; StringTable.EmitString(O); O << ";\n"; - + O << " return Strs+InstAsmOffset[Opcode];\n" << "}\n\n#endif\n"; } @@ -540,7 +546,7 @@ void AsmWriterEmitter::EmitGetInstructionName(raw_ostream &O) { void AsmWriterEmitter::run(raw_ostream &O) { EmitSourceFileHeader("Assembly Writer Source Fragment", O); - + EmitPrintInstruction(O); EmitGetRegisterName(O); EmitGetInstructionName(O); diff --git a/utils/TableGen/AsmWriterInst.cpp b/utils/TableGen/AsmWriterInst.cpp index b2228b037ddd..fdf447f2aaf3 100644 --- a/utils/TableGen/AsmWriterInst.cpp +++ b/utils/TableGen/AsmWriterInst.cpp @@ -53,8 +53,6 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, int OperandSpacing) { this->CGI = &CGI; - unsigned CurVariant = ~0U; // ~0 if we are outside a {.|.|.} region, other #. - // This is the number of tabs we've seen if we're doing columnar layout. unsigned CurColumn = 0; @@ -62,54 +60,48 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, // NOTE: Any extensions to this code need to be mirrored in the // AsmPrinter::printInlineAsm code that executes as compile time (assuming // that inline asm strings should also get the new feature)! - const std::string &AsmString = CGI.AsmString; + std::string AsmString = CGI.FlattenAsmStringVariants(CGI.AsmString, Variant); std::string::size_type LastEmitted = 0; while (LastEmitted != AsmString.size()) { std::string::size_type DollarPos = - AsmString.find_first_of("${|}\\", LastEmitted); + AsmString.find_first_of("$\\", LastEmitted); if (DollarPos == std::string::npos) DollarPos = AsmString.size(); // Emit a constant string fragment. - if (DollarPos != LastEmitted) { - if (CurVariant == Variant || CurVariant == ~0U) { - for (; LastEmitted != DollarPos; ++LastEmitted) - switch (AsmString[LastEmitted]) { - case '\n': - AddLiteralString("\\n"); - break; - case '\t': - // If the asm writer is not using a columnar layout, \t is not - // magic. - if (FirstOperandColumn == -1 || OperandSpacing == -1) { - AddLiteralString("\\t"); - } else { - // We recognize a tab as an operand delimeter. - unsigned DestColumn = FirstOperandColumn + - CurColumn++ * OperandSpacing; - Operands.push_back( - AsmWriterOperand( - "O.PadToColumn(" + - utostr(DestColumn) + ");\n", - AsmWriterOperand::isLiteralStatementOperand)); - } - break; - case '"': - AddLiteralString("\\\""); - break; - case '\\': - AddLiteralString("\\\\"); - break; - default: - AddLiteralString(std::string(1, AsmString[LastEmitted])); - break; - } - } else { - LastEmitted = DollarPos; - } + for (; LastEmitted != DollarPos; ++LastEmitted) + switch (AsmString[LastEmitted]) { + case '\n': + AddLiteralString("\\n"); + break; + case '\t': + // If the asm writer is not using a columnar layout, \t is not + // magic. + if (FirstOperandColumn == -1 || OperandSpacing == -1) { + AddLiteralString("\\t"); + } else { + // We recognize a tab as an operand delimeter. + unsigned DestColumn = FirstOperandColumn + + CurColumn++ * OperandSpacing; + Operands.push_back( + AsmWriterOperand( + "O.PadToColumn(" + + utostr(DestColumn) + ");\n", + AsmWriterOperand::isLiteralStatementOperand)); + } + break; + case '"': + AddLiteralString("\\\""); + break; + case '\\': + AddLiteralString("\\\\"); + break; + default: + AddLiteralString(std::string(1, AsmString[LastEmitted])); + break; + } } else if (AsmString[DollarPos] == '\\') { - if (DollarPos+1 != AsmString.size() && - (CurVariant == Variant || CurVariant == ~0U)) { + if (DollarPos+1 != AsmString.size()) { if (AsmString[DollarPos+1] == 'n') { AddLiteralString("\\n"); } else if (AsmString[DollarPos+1] == 't') { @@ -137,29 +129,9 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, LastEmitted = DollarPos+2; continue; } - } else if (AsmString[DollarPos] == '{') { - if (CurVariant != ~0U) - throw "Nested variants found for instruction '" + - CGI.TheDef->getName() + "'!"; - LastEmitted = DollarPos+1; - CurVariant = 0; // We are now inside of the variant! - } else if (AsmString[DollarPos] == '|') { - if (CurVariant == ~0U) - throw "'|' character found outside of a variant in instruction '" - + CGI.TheDef->getName() + "'!"; - ++CurVariant; - ++LastEmitted; - } else if (AsmString[DollarPos] == '}') { - if (CurVariant == ~0U) - throw "'}' character found outside of a variant in instruction '" - + CGI.TheDef->getName() + "'!"; - ++LastEmitted; - CurVariant = ~0U; } else if (DollarPos+1 != AsmString.size() && AsmString[DollarPos+1] == '$') { - if (CurVariant == Variant || CurVariant == ~0U) { - AddLiteralString("$"); // "$$" -> $ - } + AddLiteralString("$"); // "$$" -> $ LastEmitted = DollarPos+2; } else { // Get the name of the variable. @@ -226,16 +198,12 @@ AsmWriterInst::AsmWriterInst(const CodeGenInstruction &CGI, Modifier)); } else { // Otherwise, normal operand. - unsigned OpNo = CGI.getOperandNamed(VarName); - CodeGenInstruction::OperandInfo OpInfo = CGI.OperandList[OpNo]; + unsigned OpNo = CGI.Operands.getOperandNamed(VarName); + CGIOperandList::OperandInfo OpInfo = CGI.Operands[OpNo]; - if (CurVariant == Variant || CurVariant == ~0U) { - unsigned MIOp = OpInfo.MIOperandNo; - Operands.push_back(AsmWriterOperand(OpInfo.PrinterMethodName, - OpNo, - MIOp, - Modifier)); - } + unsigned MIOp = OpInfo.MIOperandNo; + Operands.push_back(AsmWriterOperand(OpInfo.PrinterMethodName, + OpNo, MIOp, Modifier)); } LastEmitted = VarEnd; } diff --git a/utils/TableGen/AsmWriterInst.h b/utils/TableGen/AsmWriterInst.h index 20b8588862b7..ec7d8eb10395 100644 --- a/utils/TableGen/AsmWriterInst.h +++ b/utils/TableGen/AsmWriterInst.h @@ -23,51 +23,51 @@ namespace llvm { class CodeGenInstruction; class Record; - + struct AsmWriterOperand { enum OpType { // Output this text surrounded by quotes to the asm. - isLiteralTextOperand, + isLiteralTextOperand, // This is the name of a routine to call to print the operand. isMachineInstrOperand, // Output this text verbatim to the asm writer. It is code that // will output some text to the asm. isLiteralStatementOperand } OperandType; - + /// Str - For isLiteralTextOperand, this IS the literal text. For /// isMachineInstrOperand, this is the PrinterMethodName for the operand.. - /// For isLiteralStatementOperand, this is the code to insert verbatim + /// For isLiteralStatementOperand, this is the code to insert verbatim /// into the asm writer. std::string Str; - + /// CGIOpNo - For isMachineInstrOperand, this is the index of the operand in /// the CodeGenInstruction. unsigned CGIOpNo; - + /// MiOpNo - For isMachineInstrOperand, this is the operand number of the /// machine instruction. unsigned MIOpNo; - + /// MiModifier - For isMachineInstrOperand, this is the modifier string for /// an operand, specified with syntax like ${opname:modifier}. std::string MiModifier; - + // To make VS STL happy AsmWriterOperand(OpType op = isLiteralTextOperand):OperandType(op) {} - + AsmWriterOperand(const std::string &LitStr, OpType op = isLiteralTextOperand) : OperandType(op), Str(LitStr) {} - + AsmWriterOperand(const std::string &Printer, unsigned _CGIOpNo, unsigned _MIOpNo, const std::string &Modifier, - OpType op = isMachineInstrOperand) + OpType op = isMachineInstrOperand) : OperandType(op), Str(Printer), CGIOpNo(_CGIOpNo), MIOpNo(_MIOpNo), MiModifier(Modifier) {} - + bool operator!=(const AsmWriterOperand &Other) const { if (OperandType != Other.OperandType || Str != Other.Str) return true; if (OperandType == isMachineInstrOperand) @@ -77,26 +77,26 @@ namespace llvm { bool operator==(const AsmWriterOperand &Other) const { return !operator!=(Other); } - + /// getCode - Return the code that prints this operand. std::string getCode() const; }; - + class AsmWriterInst { public: std::vector Operands; const CodeGenInstruction *CGI; - - AsmWriterInst(const CodeGenInstruction &CGI, + + AsmWriterInst(const CodeGenInstruction &CGI, unsigned Variant, int FirstOperandColumn, int OperandSpacing); - + /// MatchesAllButOneOp - If this instruction is exactly identical to the /// specified instruction except for one differing operand, return the /// differing operand number. Otherwise return ~0. unsigned MatchesAllButOneOp(const AsmWriterInst &Other) const; - + private: void AddLiteralString(const std::string &Str) { // If the last operand was already a literal text string, append this to diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt index 972989ba6232..e24314c3e0ec 100644 --- a/utils/TableGen/CMakeLists.txt +++ b/utils/TableGen/CMakeLists.txt @@ -1,3 +1,8 @@ +set(LLVM_REQUIRES_EH 1) +set(LLVM_REQUIRES_RTTI 1) + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LLVM_TOOLS_BINARY_DIR}) + add_executable(tblgen ARMDecoderEmitter.cpp AsmMatcherEmitter.cpp @@ -7,6 +12,7 @@ add_executable(tblgen ClangASTNodesEmitter.cpp ClangAttrEmitter.cpp ClangDiagnosticsEmitter.cpp + ClangSACheckersEmitter.cpp CodeEmitterGen.cpp CodeGenDAGPatterns.cpp CodeGenInstruction.cpp @@ -19,6 +25,7 @@ add_executable(tblgen DisassemblerEmitter.cpp EDEmitter.cpp FastISelEmitter.cpp + FixedLenDecoderEmitter.cpp InstrEnumEmitter.cpp InstrInfoEmitter.cpp IntrinsicEmitter.cpp @@ -27,6 +34,7 @@ add_executable(tblgen OptParserEmitter.cpp Record.cpp RegisterInfoEmitter.cpp + StringMatcher.cpp SubtargetEmitter.cpp TGLexer.cpp TGParser.cpp @@ -37,10 +45,12 @@ add_executable(tblgen X86RecognizableInstr.cpp ) -target_link_libraries(tblgen LLVMSupport LLVMSystem) +target_link_libraries(tblgen LLVMSupport) if( MINGW ) target_link_libraries(tblgen imagehlp psapi) endif( MINGW ) if( LLVM_ENABLE_THREADS AND HAVE_LIBPTHREAD AND NOT BEOS ) target_link_libraries(tblgen pthread) endif() + +install(TARGETS tblgen RUNTIME DESTINATION bin) diff --git a/utils/TableGen/CallingConvEmitter.cpp b/utils/TableGen/CallingConvEmitter.cpp index 7643609b8724..c51afd82a37a 100644 --- a/utils/TableGen/CallingConvEmitter.cpp +++ b/utils/TableGen/CallingConvEmitter.cpp @@ -26,9 +26,9 @@ void CallingConvEmitter::run(raw_ostream &O) { // other. for (unsigned i = 0, e = CCs.size(); i != e; ++i) { O << "static bool " << CCs[i]->getName() - << "(unsigned ValNo, EVT ValVT,\n" + << "(unsigned ValNo, MVT ValVT,\n" << std::string(CCs[i]->getName().size()+13, ' ') - << "EVT LocVT, CCValAssign::LocInfo LocInfo,\n" + << "MVT LocVT, CCValAssign::LocInfo LocInfo,\n" << std::string(CCs[i]->getName().size()+13, ' ') << "ISD::ArgFlagsTy ArgFlags, CCState &State);\n"; } @@ -44,9 +44,9 @@ void CallingConvEmitter::EmitCallingConv(Record *CC, raw_ostream &O) { Counter = 0; O << "\n\nstatic bool " << CC->getName() - << "(unsigned ValNo, EVT ValVT,\n" + << "(unsigned ValNo, MVT ValVT,\n" << std::string(CC->getName().size()+13, ' ') - << "EVT LocVT, CCValAssign::LocInfo LocInfo,\n" + << "MVT LocVT, CCValAssign::LocInfo LocInfo,\n" << std::string(CC->getName().size()+13, ' ') << "ISD::ArgFlagsTy ArgFlags, CCState &State) {\n"; // Emit all of the actions, in order. @@ -163,12 +163,12 @@ void CallingConvEmitter::EmitAction(Record *Action, O << Size << ", "; else O << "\n" << IndentStr << " State.getTarget().getTargetData()" - "->getTypeAllocSize(LocVT.getTypeForEVT(State.getContext())), "; + "->getTypeAllocSize(EVT(LocVT).getTypeForEVT(State.getContext())), "; if (Align) O << Align; else O << "\n" << IndentStr << " State.getTarget().getTargetData()" - "->getABITypeAlignment(LocVT.getTypeForEVT(State.getContext()))"; + "->getABITypeAlignment(EVT(LocVT).getTypeForEVT(State.getContext()))"; if (Action->isSubClassOf("CCAssignToStackWithShadow")) O << ", " << getQualifiedName(Action->getValueAsDef("ShadowReg")); O << ");\n" << IndentStr diff --git a/utils/TableGen/ClangASTNodesEmitter.h b/utils/TableGen/ClangASTNodesEmitter.h index abf9c9a0f164..712333bd2d25 100644 --- a/utils/TableGen/ClangASTNodesEmitter.h +++ b/utils/TableGen/ClangASTNodesEmitter.h @@ -57,7 +57,7 @@ class ClangASTNodesEmitter : public TableGenBackend { public: explicit ClangASTNodesEmitter(RecordKeeper &R, const std::string &N, const std::string &S) - : Records(R), Root(N, SMLoc()), BaseSuffix(S) + : Records(R), Root(N, SMLoc(), R), BaseSuffix(S) {} // run - Output the .inc file contents diff --git a/utils/TableGen/ClangAttrEmitter.cpp b/utils/TableGen/ClangAttrEmitter.cpp index 8d3399a95970..27e1e027d0fa 100644 --- a/utils/TableGen/ClangAttrEmitter.cpp +++ b/utils/TableGen/ClangAttrEmitter.cpp @@ -19,8 +19,8 @@ using namespace llvm; -static const std::vector getValueAsListOfStrings(Record &R, - StringRef FieldName) { +static const std::vector +getValueAsListOfStrings(Record &R, StringRef FieldName) { ListInit *List = R.getValueAsListInit(FieldName); assert (List && "Got a null ListInit"); @@ -44,7 +44,8 @@ std::string ReadPCHRecord(StringRef type) { return StringSwitch(type) .EndsWith("Decl *", "cast_or_null<" + std::string(type, 0, type.size()-1) + ">(GetDecl(Record[Idx++]))") - .Case("QualType", "ReadTypeRecord(Idx++)") + .Case("QualType", "GetType(Record[Idx++])") + .Case("Expr *", "ReadSubExpr()") .Default("Record[Idx++]"); } @@ -54,6 +55,7 @@ std::string WritePCHRecord(StringRef type, StringRef name) { .EndsWith("Decl *", "AddDeclRef(" + std::string(name) + ", Record);\n") .Case("QualType", "AddTypeRef(" + std::string(name) + ", Record);\n") + .Case("Expr *", "AddStmt(" + std::string(name) + ");\n") .Default("Record.push_back(" + std::string(name) + ");\n"); } @@ -171,7 +173,8 @@ namespace { OS << "char *" << getLowerName() << ";"; } void writePCHReadDecls(raw_ostream &OS) const { - OS << " std::string " << getLowerName() << "= ReadString(Record, Idx);\n"; + OS << " std::string " << getLowerName() + << "= ReadString(Record, Idx);\n"; } void writePCHReadArgs(raw_ostream &OS) const { OS << getLowerName(); @@ -269,10 +272,10 @@ namespace { OS << " bool is" << getLowerName() << "Expr = Record[Idx++];\n"; OS << " void *" << getLowerName() << "Ptr;\n"; OS << " if (is" << getLowerName() << "Expr)\n"; - OS << " " << getLowerName() << "Ptr = ReadExpr(DeclsCursor);\n"; + OS << " " << getLowerName() << "Ptr = ReadExpr(F);\n"; OS << " else\n"; OS << " " << getLowerName() - << "Ptr = GetTypeSourceInfo(DeclsCursor, Record, Idx);\n"; + << "Ptr = GetTypeSourceInfo(F, Record, Idx);\n"; } void writePCHWrite(raw_ostream &OS) const { OS << " Record.push_back(SA->is" << getUpperName() << "Expr());\n"; @@ -461,8 +464,9 @@ void ClangAttrClassEmitter::run(raw_ostream &OS) { for (std::vector::iterator i = Attrs.begin(), e = Attrs.end(); i != e; ++i) { Record &R = **i; + const std::string &SuperName = R.getSuperClasses().back()->getName(); - OS << "class " << R.getName() << "Attr : public Attr {\n"; + OS << "class " << R.getName() << "Attr : public " << SuperName << " {\n"; std::vector ArgRecords = R.getValueAsListOfDefs("Args"); std::vector Args; @@ -493,7 +497,7 @@ void ClangAttrClassEmitter::run(raw_ostream &OS) { } OS << " )\n"; - OS << " : Attr(attr::" << R.getName() << ", L)\n"; + OS << " : " << SuperName << "(attr::" << R.getName() << ", L)\n"; for (ai = Args.begin(); ai != ae; ++ai) { OS << " , "; @@ -557,31 +561,58 @@ void ClangAttrImplEmitter::run(raw_ostream &OS) { } } +static void EmitAttrList(raw_ostream &OS, StringRef Class, + const std::vector &AttrList) { + std::vector::const_iterator i = AttrList.begin(), e = AttrList.end(); + + if (i != e) { + // Move the end iterator back to emit the last attribute. + for(--e; i != e; ++i) + OS << Class << "(" << (*i)->getName() << ")\n"; + + OS << "LAST_" << Class << "(" << (*i)->getName() << ")\n\n"; + } +} + void ClangAttrListEmitter::run(raw_ostream &OS) { OS << "// This file is generated by TableGen. Do not edit.\n\n"; OS << "#ifndef LAST_ATTR\n"; OS << "#define LAST_ATTR(NAME) ATTR(NAME)\n"; OS << "#endif\n\n"; - - std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); - std::vector::iterator i = Attrs.begin(), e = Attrs.end(); - if (i != e) { - // Move the end iterator back to emit the last attribute. - for(--e; i != e; ++i) - OS << "ATTR(" << (*i)->getName() << ")\n"; - - OS << "LAST_ATTR(" << (*i)->getName() << ")\n\n"; + OS << "#ifndef INHERITABLE_ATTR\n"; + OS << "#define INHERITABLE_ATTR(NAME) ATTR(NAME)\n"; + OS << "#endif\n\n"; + + OS << "#ifndef LAST_INHERITABLE_ATTR\n"; + OS << "#define LAST_INHERITABLE_ATTR(NAME) INHERITABLE_ATTR(NAME)\n"; + OS << "#endif\n\n"; + + Record *InhClass = Records.getClass("InheritableAttr"); + std::vector Attrs = Records.getAllDerivedDefinitions("Attr"), + NonInhAttrs, InhAttrs; + for (std::vector::iterator i = Attrs.begin(), e = Attrs.end(); + i != e; ++i) { + if ((*i)->isSubClassOf(InhClass)) + InhAttrs.push_back(*i); + else + NonInhAttrs.push_back(*i); } + EmitAttrList(OS, "INHERITABLE_ATTR", InhAttrs); + EmitAttrList(OS, "ATTR", NonInhAttrs); + OS << "#undef LAST_ATTR\n"; + OS << "#undef INHERITABLE_ATTR\n"; + OS << "#undef LAST_INHERITABLE_ATTR\n"; OS << "#undef ATTR\n"; } void ClangAttrPCHReadEmitter::run(raw_ostream &OS) { - OS << "// This file is generated by TableGen. Do not edi.\n\n"; + OS << "// This file is generated by TableGen. Do not edit.\n\n"; + Record *InhClass = Records.getClass("InheritableAttr"); std::vector Attrs = Records.getAllDerivedDefinitions("Attr"), ArgRecords; std::vector::iterator i = Attrs.begin(), e = Attrs.end(), ai, ae; @@ -595,6 +626,8 @@ void ClangAttrPCHReadEmitter::run(raw_ostream &OS) { for (; i != e; ++i) { Record &R = **i; OS << " case attr::" << R.getName() << ": {\n"; + if (R.isSubClassOf(InhClass)) + OS << " bool isInherited = Record[Idx++];\n"; ArgRecords = R.getValueAsListOfDefs("Args"); Args.clear(); for (ai = ArgRecords.begin(), ae = ArgRecords.end(); ai != ae; ++ai) { @@ -608,6 +641,8 @@ void ClangAttrPCHReadEmitter::run(raw_ostream &OS) { (*ri)->writePCHReadArgs(OS); } OS << ");\n"; + if (R.isSubClassOf(InhClass)) + OS << " cast(New)->setInherited(isInherited);\n"; OS << " break;\n"; OS << " }\n"; } @@ -615,6 +650,7 @@ void ClangAttrPCHReadEmitter::run(raw_ostream &OS) { } void ClangAttrPCHWriteEmitter::run(raw_ostream &OS) { + Record *InhClass = Records.getClass("InheritableAttr"); std::vector Attrs = Records.getAllDerivedDefinitions("Attr"), Args; std::vector::iterator i = Attrs.begin(), e = Attrs.end(), ai, ae; @@ -626,9 +662,11 @@ void ClangAttrPCHWriteEmitter::run(raw_ostream &OS) { Record &R = **i; OS << " case attr::" << R.getName() << ": {\n"; Args = R.getValueAsListOfDefs("Args"); - if (!Args.empty()) + if (R.isSubClassOf(InhClass) || !Args.empty()) OS << " const " << R.getName() << "Attr *SA = cast<" << R.getName() << "Attr>(A);\n"; + if (R.isSubClassOf(InhClass)) + OS << " Record.push_back(SA->isInherited());\n"; for (ai = Args.begin(), ae = Args.end(); ai != ae; ++ai) createArgument(**ai, R.getName())->writePCHWrite(OS); OS << " break;\n"; @@ -636,3 +674,21 @@ void ClangAttrPCHWriteEmitter::run(raw_ostream &OS) { } OS << " }\n"; } + +void ClangAttrSpellingListEmitter::run(raw_ostream &OS) { + OS << "// This file is generated by TableGen. Do not edit.\n\n"; + + std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); + + for (std::vector::iterator I = Attrs.begin(), E = Attrs.end(); I != E; ++I) { + Record &Attr = **I; + + std::vector Spellings = getValueAsListOfStrings(Attr, "Spellings"); + + for (std::vector::const_iterator I = Spellings.begin(), E = Spellings.end(); I != E; ++I) { + StringRef Spelling = *I; + OS << ".Case(\"" << Spelling << "\", true)\n"; + } + } + +} diff --git a/utils/TableGen/ClangAttrEmitter.h b/utils/TableGen/ClangAttrEmitter.h index 83149824b2e7..af870098a842 100644 --- a/utils/TableGen/ClangAttrEmitter.h +++ b/utils/TableGen/ClangAttrEmitter.h @@ -83,6 +83,19 @@ public: void run(raw_ostream &OS); }; +/// ClangAttrSpellingListEmitter - class emits the list of spellings for attributes for +/// clang. +class ClangAttrSpellingListEmitter : public TableGenBackend { + RecordKeeper &Records; + + public: + explicit ClangAttrSpellingListEmitter(RecordKeeper &R) + : Records(R) + {} + + void run(raw_ostream &OS); +}; + } #endif diff --git a/utils/TableGen/ClangDiagnosticsEmitter.cpp b/utils/TableGen/ClangDiagnosticsEmitter.cpp index 75b6252c4f9f..60e67c467466 100644 --- a/utils/TableGen/ClangDiagnosticsEmitter.cpp +++ b/utils/TableGen/ClangDiagnosticsEmitter.cpp @@ -29,9 +29,10 @@ using namespace llvm; namespace { class DiagGroupParentMap { + RecordKeeper &Records; std::map > Mapping; public: - DiagGroupParentMap() { + DiagGroupParentMap(RecordKeeper &records) : Records(records) { std::vector DiagGroups = Records.getAllDerivedDefinitions("DiagGroup"); for (unsigned i = 0, e = DiagGroups.size(); i != e; ++i) { @@ -84,11 +85,12 @@ static std::string getDiagnosticCategory(const Record *R, namespace { class DiagCategoryIDMap { + RecordKeeper &Records; StringMap CategoryIDs; std::vector CategoryStrings; public: - DiagCategoryIDMap() { - DiagGroupParentMap ParentInfo; + DiagCategoryIDMap(RecordKeeper &records) : Records(records) { + DiagGroupParentMap ParentInfo(Records); // The zero'th category is "". CategoryStrings.push_back(""); @@ -138,8 +140,8 @@ void ClangDiagsDefsEmitter::run(raw_ostream &OS) { const std::vector &Diags = Records.getAllDerivedDefinitions("Diagnostic"); - DiagCategoryIDMap CategoryIDs; - DiagGroupParentMap DGParentMap; + DiagCategoryIDMap CategoryIDs(Records); + DiagGroupParentMap DGParentMap(Records); for (unsigned i = 0, e = Diags.size(); i != e; ++i) { const Record &R = *Diags[i]; @@ -168,7 +170,13 @@ void ClangDiagsDefsEmitter::run(raw_ostream &OS) { OS << ", true"; else OS << ", false"; - + + // Access control bit + if (R.getValueAsBit("AccessControl")) + OS << ", true"; + else + OS << ", false"; + // Category number. OS << ", " << CategoryIDs.getID(getDiagnosticCategory(&R, DGParentMap)); OS << ")\n"; @@ -179,15 +187,17 @@ void ClangDiagsDefsEmitter::run(raw_ostream &OS) { // Warning Group Tables generation //===----------------------------------------------------------------------===// +namespace { struct GroupInfo { std::vector DiagsInGroup; std::vector SubGroups; unsigned IDNo; }; +} // end anonymous namespace. void ClangDiagGroupsEmitter::run(raw_ostream &OS) { // Compute a mapping from a DiagGroup to all of its parents. - DiagGroupParentMap DGParentMap; + DiagGroupParentMap DGParentMap(Records); // Invert the 1-[0/1] mapping of diags to group into a one to many mapping of // groups to diags in the group. @@ -277,7 +287,7 @@ void ClangDiagGroupsEmitter::run(raw_ostream &OS) { OS << "#endif // GET_DIAG_TABLE\n\n"; // Emit the category table next. - DiagCategoryIDMap CategoriesByID; + DiagCategoryIDMap CategoriesByID(Records); OS << "\n#ifdef GET_CATEGORY_TABLE\n"; for (DiagCategoryIDMap::iterator I = CategoriesByID.begin(), E = CategoriesByID.end(); I != E; ++I) diff --git a/utils/TableGen/ClangSACheckersEmitter.cpp b/utils/TableGen/ClangSACheckersEmitter.cpp new file mode 100644 index 000000000000..3e49ab138fcd --- /dev/null +++ b/utils/TableGen/ClangSACheckersEmitter.cpp @@ -0,0 +1,229 @@ +//=- ClangSACheckersEmitter.cpp - Generate Clang SA checkers tables -*- C++ -*- +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend emits Clang Static Analyzer checkers tables. +// +//===----------------------------------------------------------------------===// + +#include "ClangSACheckersEmitter.h" +#include "Record.h" +#include "llvm/ADT/DenseSet.h" +#include +#include +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Static Analyzer Checkers Tables generation +//===----------------------------------------------------------------------===// + +/// \brief True if it is specified hidden or a parent package is specified +/// as hidden, otherwise false. +static bool isHidden(const Record &R) { + if (R.getValueAsBit("Hidden")) + return true; + // Not declared as hidden, check the parent package if it is hidden. + if (DefInit *DI = dynamic_cast(R.getValueInit("ParentPackage"))) + return isHidden(*DI->getDef()); + + return false; +} + +static bool isCheckerNamed(const Record *R) { + return !R->getValueAsString("CheckerName").empty(); +} + +static std::string getPackageFullName(const Record *R); + +static std::string getParentPackageFullName(const Record *R) { + std::string name; + if (DefInit *DI = dynamic_cast(R->getValueInit("ParentPackage"))) + name = getPackageFullName(DI->getDef()); + return name; +} + +static std::string getPackageFullName(const Record *R) { + std::string name = getParentPackageFullName(R); + if (!name.empty()) name += "."; + return name + R->getValueAsString("PackageName"); +} + +static std::string getCheckerFullName(const Record *R) { + std::string name = getParentPackageFullName(R); + if (isCheckerNamed(R)) { + if (!name.empty()) name += "."; + name += R->getValueAsString("CheckerName"); + } + return name; +} + +static std::string getStringValue(const Record &R, StringRef field) { + if (StringInit * + SI = dynamic_cast(R.getValueInit(field))) + return SI->getValue(); + return std::string(); +} + +namespace { +struct GroupInfo { + std::vector Checkers; + llvm::DenseSet SubGroups; + bool Hidden; + unsigned Index; + + GroupInfo() : Hidden(false) { } +}; +} + +void ClangSACheckersEmitter::run(raw_ostream &OS) { + std::vector checkers = Records.getAllDerivedDefinitions("Checker"); + llvm::DenseMap checkerRecIndexMap; + for (unsigned i = 0, e = checkers.size(); i != e; ++i) + checkerRecIndexMap[checkers[i]] = i; + + OS << "\n#ifdef GET_CHECKERS\n"; + for (unsigned i = 0, e = checkers.size(); i != e; ++i) { + const Record &R = *checkers[i]; + + OS << "CHECKER(" << "\""; + std::string name; + if (isCheckerNamed(&R)) + name = getCheckerFullName(&R); + OS.write_escaped(name) << "\", "; + OS << R.getName() << ", "; + OS << getStringValue(R, "DescFile") << ", "; + OS << "\""; + OS.write_escaped(getStringValue(R, "HelpText")) << "\", "; + // Hidden bit + if (isHidden(R)) + OS << "true"; + else + OS << "false"; + OS << ")\n"; + } + OS << "#endif // GET_CHECKERS\n\n"; + + // Invert the mapping of checkers to package/group into a one to many + // mapping of packages/groups to checkers. + std::map groupInfoByName; + llvm::DenseMap recordGroupMap; + + std::vector packages = Records.getAllDerivedDefinitions("Package"); + for (unsigned i = 0, e = packages.size(); i != e; ++i) { + Record *R = packages[i]; + std::string fullName = getPackageFullName(R); + if (!fullName.empty()) { + GroupInfo &info = groupInfoByName[fullName]; + info.Hidden = isHidden(*R); + recordGroupMap[R] = &info; + } + } + + std::vector + checkerGroups = Records.getAllDerivedDefinitions("CheckerGroup"); + for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i) { + Record *R = checkerGroups[i]; + std::string name = R->getValueAsString("GroupName"); + if (!name.empty()) { + GroupInfo &info = groupInfoByName[name]; + recordGroupMap[R] = &info; + } + } + + for (unsigned i = 0, e = checkers.size(); i != e; ++i) { + Record *R = checkers[i]; + Record *package = 0; + if (DefInit * + DI = dynamic_cast(R->getValueInit("ParentPackage"))) + package = DI->getDef(); + if (!isCheckerNamed(R) && !package) + throw "Checker '" + R->getName() + "' is neither named, nor in a package!"; + + if (isCheckerNamed(R)) { + // Create a pseudo-group to hold this checker. + std::string fullName = getCheckerFullName(R); + GroupInfo &info = groupInfoByName[fullName]; + recordGroupMap[R] = &info; + info.Checkers.push_back(R); + } else { + recordGroupMap[package]->Checkers.push_back(R); + } + + Record *currR = isCheckerNamed(R) ? R : package; + // Insert the checker and its parent packages into the subgroups set of + // the corresponding parent package. + while (DefInit *DI + = dynamic_cast(currR->getValueInit("ParentPackage"))) { + Record *parentPackage = DI->getDef(); + recordGroupMap[parentPackage]->SubGroups.insert(currR); + currR = parentPackage; + } + // Insert the checker into the set of its group. + if (DefInit *DI = dynamic_cast(R->getValueInit("Group"))) + recordGroupMap[DI->getDef()]->Checkers.push_back(R); + } + + unsigned index = 0; + for (std::map::iterator + I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) + I->second.Index = index++; + + // Walk through the packages/groups/checkers emitting an array for each + // set of checkers and an array for each set of subpackages. + + OS << "\n#ifdef GET_MEMBER_ARRAYS\n"; + unsigned maxLen = 0; + for (std::map::iterator + I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) { + maxLen = std::max(maxLen, (unsigned)I->first.size()); + + std::vector &V = I->second.Checkers; + if (!V.empty()) { + OS << "static const short CheckerArray" << I->second.Index << "[] = { "; + for (unsigned i = 0, e = V.size(); i != e; ++i) + OS << checkerRecIndexMap[V[i]] << ", "; + OS << "-1 };\n"; + } + + llvm::DenseSet &subGroups = I->second.SubGroups; + if (!subGroups.empty()) { + OS << "static const short SubPackageArray" << I->second.Index << "[] = { "; + for (llvm::DenseSet::iterator + I = subGroups.begin(), E = subGroups.end(); I != E; ++I) { + OS << recordGroupMap[*I]->Index << ", "; + } + OS << "-1 };\n"; + } + } + OS << "#endif // GET_MEMBER_ARRAYS\n\n"; + + OS << "\n#ifdef GET_CHECKNAME_TABLE\n"; + for (std::map::iterator + I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) { + // Group option string. + OS << " { \""; + OS.write_escaped(I->first) << "\"," + << std::string(maxLen-I->first.size()+1, ' '); + + if (I->second.Checkers.empty()) + OS << "0, "; + else + OS << "CheckerArray" << I->second.Index << ", "; + + // Subgroups. + if (I->second.SubGroups.empty()) + OS << "0, "; + else + OS << "SubPackageArray" << I->second.Index << ", "; + + OS << (I->second.Hidden ? "true" : "false"); + + OS << " },\n"; + } + OS << "#endif // GET_CHECKNAME_TABLE\n\n"; +} diff --git a/utils/TableGen/ClangSACheckersEmitter.h b/utils/TableGen/ClangSACheckersEmitter.h new file mode 100644 index 000000000000..6bd163547329 --- /dev/null +++ b/utils/TableGen/ClangSACheckersEmitter.h @@ -0,0 +1,31 @@ +//===- ClangSACheckersEmitter.h - Generate Clang SA checkers tables -*- C++ -*- +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend emits Clang Static Analyzer checkers tables. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANGSACHECKERS_EMITTER_H +#define CLANGSACHECKERS_EMITTER_H + +#include "TableGenBackend.h" + +namespace llvm { + +class ClangSACheckersEmitter : public TableGenBackend { + RecordKeeper &Records; +public: + explicit ClangSACheckersEmitter(RecordKeeper &R) : Records(R) {} + + void run(raw_ostream &OS); +}; + +} // End llvm namespace + +#endif diff --git a/utils/TableGen/CodeEmitterGen.cpp b/utils/TableGen/CodeEmitterGen.cpp index ec702c2a5d9c..957dd19da1c2 100644 --- a/utils/TableGen/CodeEmitterGen.cpp +++ b/utils/TableGen/CodeEmitterGen.cpp @@ -17,9 +17,19 @@ #include "CodeGenTarget.h" #include "Record.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include using namespace llvm; +// FIXME: Somewhat hackish to use a command line option for this. There should +// be a CodeEmitter class in the Target.td that controls this sort of thing +// instead. +static cl::opt +MCEmitter("mc-emitter", + cl::desc("Generate CodeEmitter for use with the MC library."), + cl::init(false)); + void CodeEmitterGen::reverseBits(std::vector &Insts) { for (std::vector::iterator I = Insts.begin(), E = Insts.end(); I != E; ++I) { @@ -42,46 +52,171 @@ void CodeEmitterGen::reverseBits(std::vector &Insts) { unsigned middle = (numBits + 1) / 2; NewBI->setBit(middle, BI->getBit(middle)); } - + // Update the bits in reversed order so that emitInstrOpBits will get the // correct endianness. R->getValue("Inst")->setValue(NewBI); } } - // If the VarBitInit at position 'bit' matches the specified variable then // return the variable bit position. Otherwise return -1. int CodeEmitterGen::getVariableBit(const std::string &VarName, - BitsInit *BI, int bit) { - if (VarBitInit *VBI = dynamic_cast(BI->getBit(bit))) { - TypedInit *TI = VBI->getVariable(); + BitsInit *BI, int bit) { + if (VarBitInit *VBI = dynamic_cast(BI->getBit(bit))) + if (VarInit *VI = dynamic_cast(VBI->getVariable())) + if (VI->getName() == VarName) + return VBI->getBitNum(); + + return -1; +} + +void CodeEmitterGen:: +AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName, + unsigned &NumberedOp, + std::string &Case, CodeGenTarget &Target) { + CodeGenInstruction &CGI = Target.getInstruction(R); + + // Determine if VarName actually contributes to the Inst encoding. + int bit = BI->getNumBits()-1; + + // Scan for a bit that this contributed to. + for (; bit >= 0; ) { + if (getVariableBit(VarName, BI, bit) != -1) + break; - if (VarInit *VI = dynamic_cast(TI)) { - if (VI->getName() == VarName) return VBI->getBitNum(); + --bit; + } + + // If we found no bits, ignore this value, otherwise emit the call to get the + // operand encoding. + if (bit < 0) return; + + // If the operand matches by name, reference according to that + // operand number. Non-matching operands are assumed to be in + // order. + unsigned OpIdx; + if (CGI.Operands.hasOperandNamed(VarName, OpIdx)) { + // Get the machine operand number for the indicated operand. + OpIdx = CGI.Operands[OpIdx].MIOperandNo; + assert(!CGI.Operands.isFlatOperandNotEmitted(OpIdx) && + "Explicitly used operand also marked as not emitted!"); + } else { + /// If this operand is not supposed to be emitted by the + /// generated emitter, skip it. + while (CGI.Operands.isFlatOperandNotEmitted(NumberedOp)) + ++NumberedOp; + OpIdx = NumberedOp++; + } + + std::pair SO = CGI.Operands.getSubOperandNumber(OpIdx); + std::string &EncoderMethodName = CGI.Operands[SO.first].EncoderMethodName; + + // If the source operand has a custom encoder, use it. This will + // get the encoding for all of the suboperands. + if (!EncoderMethodName.empty()) { + // A custom encoder has all of the information for the + // sub-operands, if there are more than one, so only + // query the encoder once per source operand. + if (SO.second == 0) { + Case += " // op: " + VarName + "\n" + + " op = " + EncoderMethodName + "(MI, " + utostr(OpIdx); + if (MCEmitter) + Case += ", Fixups"; + Case += ");\n"; } + } else { + Case += " // op: " + VarName + "\n" + + " op = getMachineOpValue(MI, MI.getOperand(" + utostr(OpIdx) + ")"; + if (MCEmitter) + Case += ", Fixups"; + Case += ");\n"; } - return -1; -} + for (; bit >= 0; ) { + int varBit = getVariableBit(VarName, BI, bit); + + // If this bit isn't from a variable, skip it. + if (varBit == -1) { + --bit; + continue; + } + + // Figure out the consecutive range of bits covered by this operand, in + // order to generate better encoding code. + int beginInstBit = bit; + int beginVarBit = varBit; + int N = 1; + for (--bit; bit >= 0;) { + varBit = getVariableBit(VarName, BI, bit); + if (varBit == -1 || varBit != (beginVarBit - N)) break; + ++N; + --bit; + } + + unsigned opMask = ~0U >> (32-N); + int opShift = beginVarBit - N + 1; + opMask <<= opShift; + opShift = beginInstBit - beginVarBit; + + if (opShift > 0) { + Case += " Value |= (op & " + utostr(opMask) + "U) << " + + itostr(opShift) + ";\n"; + } else if (opShift < 0) { + Case += " Value |= (op & " + utostr(opMask) + "U) >> " + + itostr(-opShift) + ";\n"; + } else { + Case += " Value |= op & " + utostr(opMask) + "U;\n"; + } + } +} +std::string CodeEmitterGen::getInstructionCase(Record *R, + CodeGenTarget &Target) { + std::string Case; + + BitsInit *BI = R->getValueAsBitsInit("Inst"); + const std::vector &Vals = R->getValues(); + unsigned NumberedOp = 0; + + // Loop over all of the fields in the instruction, determining which are the + // operands to the instruction. + for (unsigned i = 0, e = Vals.size(); i != e; ++i) { + // Ignore fixed fields in the record, we're looking for values like: + // bits<5> RST = { ?, ?, ?, ?, ? }; + if (Vals[i].getPrefix() || Vals[i].getValue()->isComplete()) + continue; + + AddCodeToMergeInOperand(R, BI, Vals[i].getName(), NumberedOp, Case, Target); + } + + std::string PostEmitter = R->getValueAsString("PostEncoderMethod"); + if (!PostEmitter.empty()) + Case += " Value = " + PostEmitter + "(MI, Value);\n"; + + return Case; +} + void CodeEmitterGen::run(raw_ostream &o) { - CodeGenTarget Target; + CodeGenTarget Target(Records); std::vector Insts = Records.getAllDerivedDefinitions("Instruction"); - + // For little-endian instruction bit encodings, reverse the bit order if (Target.isLittleEndianEncoding()) reverseBits(Insts); EmitSourceFileHeader("Machine Code Emitter", o); - std::string Namespace = Insts[0]->getValueAsString("Namespace") + "::"; - + const std::vector &NumberedInstructions = Target.getInstructionsByEnumValue(); // Emit function declaration - o << "unsigned " << Target.getName() << "CodeEmitter::" - << "getBinaryCodeForInstr(const MachineInstr &MI) {\n"; + o << "unsigned " << Target.getName(); + if (MCEmitter) + o << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n" + << " SmallVectorImpl &Fixups) const {\n"; + else + o << "CodeEmitter::getBinaryCodeForInstr(const MachineInstr &MI) const {\n"; // Emit instruction base values o << " static const unsigned InstBits[] = {\n"; @@ -91,109 +226,45 @@ void CodeEmitterGen::run(raw_ostream &o) { IN != EN; ++IN) { const CodeGenInstruction *CGI = *IN; Record *R = CGI->TheDef; - + if (R->getValueAsString("Namespace") == "TargetOpcode") { o << " 0U,\n"; continue; } - + BitsInit *BI = R->getValueAsBitsInit("Inst"); - // Start by filling in fixed values... + // Start by filling in fixed values. unsigned Value = 0; for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i) { - if (BitInit *B = dynamic_cast(BI->getBit(e-i-1))) { + if (BitInit *B = dynamic_cast(BI->getBit(e-i-1))) Value |= B->getValue() << (e-i-1); - } } o << " " << Value << "U," << '\t' << "// " << R->getName() << "\n"; } o << " 0U\n };\n"; - + // Map to accumulate all the cases. std::map > CaseMap; - + // Construct all cases statement for each opcode for (std::vector::iterator IC = Insts.begin(), EC = Insts.end(); IC != EC; ++IC) { Record *R = *IC; if (R->getValueAsString("Namespace") == "TargetOpcode") continue; - const std::string &InstName = R->getName(); - std::string Case(""); - - BitsInit *BI = R->getValueAsBitsInit("Inst"); - const std::vector &Vals = R->getValues(); - CodeGenInstruction &CGI = Target.getInstruction(R); - - // Loop over all of the fields in the instruction, determining which are the - // operands to the instruction. - unsigned op = 0; - for (unsigned i = 0, e = Vals.size(); i != e; ++i) { - if (!Vals[i].getPrefix() && !Vals[i].getValue()->isComplete()) { - // Is the operand continuous? If so, we can just mask and OR it in - // instead of doing it bit-by-bit, saving a lot in runtime cost. - const std::string &VarName = Vals[i].getName(); - bool gotOp = false; - - for (int bit = BI->getNumBits()-1; bit >= 0; ) { - int varBit = getVariableBit(VarName, BI, bit); - - if (varBit == -1) { - --bit; - } else { - int beginInstBit = bit; - int beginVarBit = varBit; - int N = 1; - - for (--bit; bit >= 0;) { - varBit = getVariableBit(VarName, BI, bit); - if (varBit == -1 || varBit != (beginVarBit - N)) break; - ++N; - --bit; - } - - if (!gotOp) { - /// If this operand is not supposed to be emitted by the generated - /// emitter, skip it. - while (CGI.isFlatOperandNotEmitted(op)) - ++op; - - Case += " // op: " + VarName + "\n" - + " op = getMachineOpValue(MI, MI.getOperand(" - + utostr(op++) + "));\n"; - gotOp = true; - } - - unsigned opMask = ~0U >> (32-N); - int opShift = beginVarBit - N + 1; - opMask <<= opShift; - opShift = beginInstBit - beginVarBit; - - if (opShift > 0) { - Case += " Value |= (op & " + utostr(opMask) + "U) << " - + itostr(opShift) + ";\n"; - } else if (opShift < 0) { - Case += " Value |= (op & " + utostr(opMask) + "U) >> " - + itostr(-opShift) + ";\n"; - } else { - Case += " Value |= op & " + utostr(opMask) + "U;\n"; - } - } - } - } - } + const std::string &InstName = R->getValueAsString("Namespace") + "::" + + R->getName(); + std::string Case = getInstructionCase(R, Target); - std::vector &InstList = CaseMap[Case]; - InstList.push_back(InstName); + CaseMap[Case].push_back(InstName); } - // Emit initial function code o << " const unsigned opcode = MI.getOpcode();\n" << " unsigned Value = InstBits[opcode];\n" << " unsigned op = 0;\n" - << " op = op; // suppress warning\n" + << " (void)op; // suppress warning\n" << " switch (opcode) {\n"; // Emit each case statement @@ -204,7 +275,7 @@ void CodeEmitterGen::run(raw_ostream &o) { for (int i = 0, N = InstList.size(); i < N; i++) { if (i) o << "\n"; - o << " case " << Namespace << InstList[i] << ":"; + o << " case " << InstList[i] << ":"; } o << " {\n"; o << Case; diff --git a/utils/TableGen/CodeEmitterGen.h b/utils/TableGen/CodeEmitterGen.h index f0b3229c0411..a874d970feac 100644 --- a/utils/TableGen/CodeEmitterGen.h +++ b/utils/TableGen/CodeEmitterGen.h @@ -15,7 +15,6 @@ #define CODEMITTERGEN_H #include "TableGenBackend.h" -#include #include #include @@ -23,6 +22,7 @@ namespace llvm { class RecordVal; class BitsInit; +class CodeGenTarget; class CodeEmitterGen : public TableGenBackend { RecordKeeper &Records; @@ -36,6 +36,12 @@ private: void emitGetValueBit(raw_ostream &o, const std::string &Namespace); void reverseBits(std::vector &Insts); int getVariableBit(const std::string &VarName, BitsInit *BI, int bit); + std::string getInstructionCase(Record *R, CodeGenTarget &Target); + void + AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName, + unsigned &NumberedOp, + std::string &Case, CodeGenTarget &Target); + }; } // End llvm namespace diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp index 303aa6c450c2..aa60f871bff5 100644 --- a/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/utils/TableGen/CodeGenDAGPatterns.cpp @@ -56,11 +56,11 @@ EEVT::TypeSet::TypeSet(MVT::SimpleValueType VT, TreePattern &TP) { EEVT::TypeSet::TypeSet(const std::vector &VTList) { assert(!VTList.empty() && "empty list?"); TypeVec.append(VTList.begin(), VTList.end()); - + if (!VTList.empty()) assert(VTList[0] != MVT::iAny && VTList[0] != MVT::vAny && VTList[0] != MVT::fAny); - + // Verify no duplicates. array_pod_sort(TypeVec.begin(), TypeVec.end()); assert(std::unique(TypeVec.begin(), TypeVec.end()) == TypeVec.end()); @@ -72,9 +72,9 @@ bool EEVT::TypeSet::FillWithPossibleTypes(TreePattern &TP, bool (*Pred)(MVT::SimpleValueType), const char *PredicateName) { assert(isCompletelyUnknown()); - const std::vector &LegalTypes = + const std::vector &LegalTypes = TP.getDAGPatterns().getTargetInfo().getLegalValueTypes(); - + for (unsigned i = 0, e = LegalTypes.size(); i != e; ++i) if (Pred == 0 || Pred(LegalTypes[i])) TypeVec.push_back(LegalTypes[i]); @@ -82,14 +82,14 @@ bool EEVT::TypeSet::FillWithPossibleTypes(TreePattern &TP, // If we have nothing that matches the predicate, bail out. if (TypeVec.empty()) TP.error("Type inference contradiction found, no " + - std::string(PredicateName) + " types found"); + std::string(PredicateName) + " types found"); // No need to sort with one element. if (TypeVec.size() == 1) return true; // Remove duplicates. array_pod_sort(TypeVec.begin(), TypeVec.end()); TypeVec.erase(std::unique(TypeVec.begin(), TypeVec.end()), TypeVec.end()); - + return true; } @@ -100,7 +100,7 @@ bool EEVT::TypeSet::hasIntegerTypes() const { if (isInteger(TypeVec[i])) return true; return false; -} +} /// hasFloatingPointTypes - Return true if this TypeSet contains an fAny or /// a floating point value type. @@ -109,7 +109,7 @@ bool EEVT::TypeSet::hasFloatingPointTypes() const { if (isFloatingPoint(TypeVec[i])) return true; return false; -} +} /// hasVectorTypes - Return true if this TypeSet contains a vAny or a vector /// value type. @@ -123,9 +123,9 @@ bool EEVT::TypeSet::hasVectorTypes() const { std::string EEVT::TypeSet::getName() const { if (TypeVec.empty()) return ""; - + std::string Result; - + for (unsigned i = 0, e = TypeVec.size(); i != e; ++i) { std::string VTName = llvm::getEnumName(TypeVec[i]); // Strip off MVT:: prefix if present. @@ -134,7 +134,7 @@ std::string EEVT::TypeSet::getName() const { if (i) Result += ':'; Result += VTName; } - + if (TypeVec.size() == 1) return Result; return "{" + Result + "}"; @@ -146,14 +146,14 @@ std::string EEVT::TypeSet::getName() const { bool EEVT::TypeSet::MergeInTypeInfo(const EEVT::TypeSet &InVT, TreePattern &TP){ if (InVT.isCompletelyUnknown() || *this == InVT) return false; - + if (isCompletelyUnknown()) { *this = InVT; return true; } - + assert(TypeVec.size() >= 1 && InVT.TypeVec.size() >= 1 && "No unknowns"); - + // Handle the abstract cases, seeing if we can resolve them better. switch (TypeVec[0]) { default: break; @@ -163,26 +163,26 @@ bool EEVT::TypeSet::MergeInTypeInfo(const EEVT::TypeSet &InVT, TreePattern &TP){ EEVT::TypeSet InCopy(InVT); InCopy.EnforceInteger(TP); InCopy.EnforceScalar(TP); - + if (InCopy.isConcrete()) { // If the RHS has one integer type, upgrade iPTR to i32. TypeVec[0] = InVT.TypeVec[0]; return true; } - + // If the input has multiple scalar integers, this doesn't add any info. if (!InCopy.isCompletelyUnknown()) return false; } break; } - + // If the input constraint is iAny/iPTR and this is an integer type list, // remove non-integer types from the list. if ((InVT.TypeVec[0] == MVT::iPTR || InVT.TypeVec[0] == MVT::iPTRAny) && hasIntegerTypes()) { bool MadeChange = EnforceInteger(TP); - + // If we're merging in iPTR/iPTRAny and the node currently has a list of // multiple different integer types, replace them with a single iPTR. if ((InVT.TypeVec[0] == MVT::iPTR || InVT.TypeVec[0] == MVT::iPTRAny) && @@ -191,10 +191,10 @@ bool EEVT::TypeSet::MergeInTypeInfo(const EEVT::TypeSet &InVT, TreePattern &TP){ TypeVec[0] = InVT.TypeVec[0]; MadeChange = true; } - + return MadeChange; } - + // If this is a type list and the RHS is a typelist as well, eliminate entries // from this list that aren't in the other one. bool MadeChange = false; @@ -207,16 +207,16 @@ bool EEVT::TypeSet::MergeInTypeInfo(const EEVT::TypeSet &InVT, TreePattern &TP){ InInVT = true; break; } - + if (InInVT) continue; TypeVec.erase(TypeVec.begin()+i--); MadeChange = true; } - + // If we removed all of our types, we have a type contradiction. if (!TypeVec.empty()) return MadeChange; - + // FIXME: Really want an SMLoc here! TP.error("Type inference contradiction found, merging '" + InVT.getName() + "' into '" + InputSet.getName() + "'"); @@ -232,12 +232,12 @@ bool EEVT::TypeSet::EnforceInteger(TreePattern &TP) { return false; TypeSet InputSet(*this); - + // Filter out all the fp types. for (unsigned i = 0; i != TypeVec.size(); ++i) if (!isInteger(TypeVec[i])) TypeVec.erase(TypeVec.begin()+i--); - + if (TypeVec.empty()) TP.error("Type inference contradiction found, '" + InputSet.getName() + "' needs to be integer"); @@ -254,12 +254,12 @@ bool EEVT::TypeSet::EnforceFloatingPoint(TreePattern &TP) { return false; TypeSet InputSet(*this); - + // Filter out all the fp types. for (unsigned i = 0; i != TypeVec.size(); ++i) if (!isFloatingPoint(TypeVec[i])) TypeVec.erase(TypeVec.begin()+i--); - + if (TypeVec.empty()) TP.error("Type inference contradiction found, '" + InputSet.getName() + "' needs to be floating point"); @@ -276,12 +276,12 @@ bool EEVT::TypeSet::EnforceScalar(TreePattern &TP) { return false; TypeSet InputSet(*this); - + // Filter out all the vector types. for (unsigned i = 0; i != TypeVec.size(); ++i) if (!isScalar(TypeVec[i])) TypeVec.erase(TypeVec.begin()+i--); - + if (TypeVec.empty()) TP.error("Type inference contradiction found, '" + InputSet.getName() + "' needs to be scalar"); @@ -296,14 +296,14 @@ bool EEVT::TypeSet::EnforceVector(TreePattern &TP) { TypeSet InputSet(*this); bool MadeChange = false; - + // Filter out all the scalar types. for (unsigned i = 0; i != TypeVec.size(); ++i) if (!isVector(TypeVec[i])) { TypeVec.erase(TypeVec.begin()+i--); MadeChange = true; } - + if (TypeVec.empty()) TP.error("Type inference contradiction found, '" + InputSet.getName() + "' needs to be a vector"); @@ -317,13 +317,13 @@ bool EEVT::TypeSet::EnforceVector(TreePattern &TP) { bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) { // Both operands must be integer or FP, but we don't care which. bool MadeChange = false; - + if (isCompletelyUnknown()) MadeChange = FillWithPossibleTypes(TP); if (Other.isCompletelyUnknown()) MadeChange = Other.FillWithPossibleTypes(TP); - + // If one side is known to be integer or known to be FP but the other side has // no information, get at least the type integrality info in there. if (!hasFloatingPointTypes()) @@ -334,62 +334,165 @@ bool EEVT::TypeSet::EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP) { MadeChange |= EnforceInteger(TP); else if (!Other.hasIntegerTypes()) MadeChange |= EnforceFloatingPoint(TP); - + assert(!isCompletelyUnknown() && !Other.isCompletelyUnknown() && "Should have a type list now"); - + // If one contains vectors but the other doesn't pull vectors out. if (!hasVectorTypes()) MadeChange |= Other.EnforceScalar(TP); if (!hasVectorTypes()) MadeChange |= EnforceScalar(TP); + + if (TypeVec.size() == 1 && Other.TypeVec.size() == 1) { + // If we are down to concrete types, this code does not currently + // handle nodes which have multiple types, where some types are + // integer, and some are fp. Assert that this is not the case. + assert(!(hasIntegerTypes() && hasFloatingPointTypes()) && + !(Other.hasIntegerTypes() && Other.hasFloatingPointTypes()) && + "SDTCisOpSmallerThanOp does not handle mixed int/fp types!"); + + // Otherwise, if these are both vector types, either this vector + // must have a larger bitsize than the other, or this element type + // must be larger than the other. + EVT Type(TypeVec[0]); + EVT OtherType(Other.TypeVec[0]); + + if (hasVectorTypes() && Other.hasVectorTypes()) { + if (Type.getSizeInBits() >= OtherType.getSizeInBits()) + if (Type.getVectorElementType().getSizeInBits() + >= OtherType.getVectorElementType().getSizeInBits()) + TP.error("Type inference contradiction found, '" + + getName() + "' element type not smaller than '" + + Other.getName() +"'!"); + } + else + // For scalar types, the bitsize of this type must be larger + // than that of the other. + if (Type.getSizeInBits() >= OtherType.getSizeInBits()) + TP.error("Type inference contradiction found, '" + + getName() + "' is not smaller than '" + + Other.getName() +"'!"); + + } - // This code does not currently handle nodes which have multiple types, - // where some types are integer, and some are fp. Assert that this is not - // the case. - assert(!(hasIntegerTypes() && hasFloatingPointTypes()) && - !(Other.hasIntegerTypes() && Other.hasFloatingPointTypes()) && - "SDTCisOpSmallerThanOp does not handle mixed int/fp types!"); - + + // Handle int and fp as disjoint sets. This won't work for patterns + // that have mixed fp/int types but those are likely rare and would + // not have been accepted by this code previously. + // Okay, find the smallest type from the current set and remove it from the // largest set. - MVT::SimpleValueType Smallest = TypeVec[0]; + MVT::SimpleValueType SmallestInt = MVT::LAST_VALUETYPE; + for (unsigned i = 0, e = TypeVec.size(); i != e; ++i) + if (isInteger(TypeVec[i])) { + SmallestInt = TypeVec[i]; + break; + } for (unsigned i = 1, e = TypeVec.size(); i != e; ++i) - if (TypeVec[i] < Smallest) - Smallest = TypeVec[i]; - + if (isInteger(TypeVec[i]) && TypeVec[i] < SmallestInt) + SmallestInt = TypeVec[i]; + + MVT::SimpleValueType SmallestFP = MVT::LAST_VALUETYPE; + for (unsigned i = 0, e = TypeVec.size(); i != e; ++i) + if (isFloatingPoint(TypeVec[i])) { + SmallestFP = TypeVec[i]; + break; + } + for (unsigned i = 1, e = TypeVec.size(); i != e; ++i) + if (isFloatingPoint(TypeVec[i]) && TypeVec[i] < SmallestFP) + SmallestFP = TypeVec[i]; + + int OtherIntSize = 0; + int OtherFPSize = 0; + for (SmallVector::iterator TVI = + Other.TypeVec.begin(); + TVI != Other.TypeVec.end(); + /* NULL */) { + if (isInteger(*TVI)) { + ++OtherIntSize; + if (*TVI == SmallestInt) { + TVI = Other.TypeVec.erase(TVI); + --OtherIntSize; + MadeChange = true; + continue; + } + } + else if (isFloatingPoint(*TVI)) { + ++OtherFPSize; + if (*TVI == SmallestFP) { + TVI = Other.TypeVec.erase(TVI); + --OtherFPSize; + MadeChange = true; + continue; + } + } + ++TVI; + } + // If this is the only type in the large set, the constraint can never be // satisfied. - if (Other.TypeVec.size() == 1 && Other.TypeVec[0] == Smallest) + if ((Other.hasIntegerTypes() && OtherIntSize == 0) + || (Other.hasFloatingPointTypes() && OtherFPSize == 0)) TP.error("Type inference contradiction found, '" + Other.getName() + "' has nothing larger than '" + getName() +"'!"); - - SmallVector::iterator TVI = - std::find(Other.TypeVec.begin(), Other.TypeVec.end(), Smallest); - if (TVI != Other.TypeVec.end()) { - Other.TypeVec.erase(TVI); - MadeChange = true; - } - + // Okay, find the largest type in the Other set and remove it from the // current set. - MVT::SimpleValueType Largest = Other.TypeVec[0]; + MVT::SimpleValueType LargestInt = MVT::Other; + for (unsigned i = 0, e = Other.TypeVec.size(); i != e; ++i) + if (isInteger(Other.TypeVec[i])) { + LargestInt = Other.TypeVec[i]; + break; + } for (unsigned i = 1, e = Other.TypeVec.size(); i != e; ++i) - if (Other.TypeVec[i] > Largest) - Largest = Other.TypeVec[i]; - + if (isInteger(Other.TypeVec[i]) && Other.TypeVec[i] > LargestInt) + LargestInt = Other.TypeVec[i]; + + MVT::SimpleValueType LargestFP = MVT::Other; + for (unsigned i = 0, e = Other.TypeVec.size(); i != e; ++i) + if (isFloatingPoint(Other.TypeVec[i])) { + LargestFP = Other.TypeVec[i]; + break; + } + for (unsigned i = 1, e = Other.TypeVec.size(); i != e; ++i) + if (isFloatingPoint(Other.TypeVec[i]) && Other.TypeVec[i] > LargestFP) + LargestFP = Other.TypeVec[i]; + + int IntSize = 0; + int FPSize = 0; + for (SmallVector::iterator TVI = + TypeVec.begin(); + TVI != TypeVec.end(); + /* NULL */) { + if (isInteger(*TVI)) { + ++IntSize; + if (*TVI == LargestInt) { + TVI = TypeVec.erase(TVI); + --IntSize; + MadeChange = true; + continue; + } + } + else if (isFloatingPoint(*TVI)) { + ++FPSize; + if (*TVI == LargestFP) { + TVI = TypeVec.erase(TVI); + --FPSize; + MadeChange = true; + continue; + } + } + ++TVI; + } + // If this is the only type in the small set, the constraint can never be // satisfied. - if (TypeVec.size() == 1 && TypeVec[0] == Largest) + if ((hasIntegerTypes() && IntSize == 0) + || (hasFloatingPointTypes() && FPSize == 0)) TP.error("Type inference contradiction found, '" + getName() + "' has nothing smaller than '" + Other.getName()+"'!"); - - TVI = std::find(TypeVec.begin(), TypeVec.end(), Largest); - if (TVI != TypeVec.end()) { - TypeVec.erase(TVI); - MadeChange = true; - } - + return MadeChange; } @@ -406,7 +509,7 @@ bool EEVT::TypeSet::EnforceVectorEltTypeIs(EEVT::TypeSet &VTOperand, if (isConcrete()) { EVT IVT = getConcrete(); IVT = IVT.getVectorElementType(); - return MadeChange | + return MadeChange | VTOperand.MergeInTypeInfo(IVT.getSimpleVT().SimpleTy, TP); } @@ -414,11 +517,11 @@ bool EEVT::TypeSet::EnforceVectorEltTypeIs(EEVT::TypeSet &VTOperand, // disagree. if (!VTOperand.isConcrete()) return MadeChange; - + MVT::SimpleValueType VT = VTOperand.getConcrete(); - + TypeSet InputSet(*this); - + // Filter out all the types which don't have the right element type. for (unsigned i = 0; i != TypeVec.size(); ++i) { assert(isVector(TypeVec[i]) && "EnforceVector didn't work"); @@ -427,13 +530,43 @@ bool EEVT::TypeSet::EnforceVectorEltTypeIs(EEVT::TypeSet &VTOperand, MadeChange = true; } } - + if (TypeVec.empty()) // FIXME: Really want an SMLoc here! TP.error("Type inference contradiction found, forcing '" + InputSet.getName() + "' to have a vector element"); return MadeChange; } +/// EnforceVectorSubVectorTypeIs - 'this' is now constrainted to be a +/// vector type specified by VTOperand. +bool EEVT::TypeSet::EnforceVectorSubVectorTypeIs(EEVT::TypeSet &VTOperand, + TreePattern &TP) { + // "This" must be a vector and "VTOperand" must be a vector. + bool MadeChange = false; + MadeChange |= EnforceVector(TP); + MadeChange |= VTOperand.EnforceVector(TP); + + // "This" must be larger than "VTOperand." + MadeChange |= VTOperand.EnforceSmallerThan(*this, TP); + + // If we know the vector type, it forces the scalar types to agree. + if (isConcrete()) { + EVT IVT = getConcrete(); + IVT = IVT.getVectorElementType(); + + EEVT::TypeSet EltTypeSet(IVT.getSimpleVT().SimpleTy, TP); + MadeChange |= VTOperand.EnforceVectorEltTypeIs(EltTypeSet, TP); + } else if (VTOperand.isConcrete()) { + EVT IVT = VTOperand.getConcrete(); + IVT = IVT.getVectorElementType(); + + EEVT::TypeSet EltTypeSet(IVT.getSimpleVT().SimpleTy, TP); + MadeChange |= EnforceVectorEltTypeIs(EltTypeSet, TP); + } + + return MadeChange; +} + //===----------------------------------------------------------------------===// // Helpers for working with extended types. @@ -473,18 +606,21 @@ void FindDepVars(TreePatternNode *N, MultipleUseVarSet &DepVars) { } //! Dump the dependent variable set: +#ifndef NDEBUG void DumpDepVars(MultipleUseVarSet &DepVars) { if (DepVars.empty()) { DEBUG(errs() << ""); } else { DEBUG(errs() << "[ "); - for (MultipleUseVarSet::const_iterator i = DepVars.begin(), e = DepVars.end(); - i != e; ++i) { + for (MultipleUseVarSet::const_iterator i = DepVars.begin(), + e = DepVars.end(); i != e; ++i) { DEBUG(errs() << (*i) << " "); } DEBUG(errs() << "]"); } } +#endif + } //===----------------------------------------------------------------------===// @@ -502,7 +638,7 @@ static unsigned getPatternSize(const TreePatternNode *P, // e.g. (set R32:$dst, 0). if (P->isLeaf() && dynamic_cast(P->getLeafValue())) Size += 2; - + // FIXME: This is a hack to statically increase the priority of patterns // which maps a sub-dag to a complex pattern. e.g. favors LEA over ADD. // Later we can allow complexity / cost for each pattern to be (optionally) @@ -511,12 +647,12 @@ static unsigned getPatternSize(const TreePatternNode *P, const ComplexPattern *AM = P->getComplexPatternInfo(CGP); if (AM) Size += AM->getNumOperands() * 3; - + // If this node has some predicate function that must match, it adds to the // complexity of this node. if (!P->getPredicateFns().empty()) ++Size; - + // Count children in the count if they are also nodes. for (unsigned i = 0, e = P->getNumChildren(); i != e; ++i) { TreePatternNode *Child = P->getChild(i); @@ -524,7 +660,7 @@ static unsigned getPatternSize(const TreePatternNode *P, Child->getType(0) != MVT::Other) Size += getPatternSize(Child, CGP); else if (Child->isLeaf()) { - if (dynamic_cast(Child->getLeafValue())) + if (dynamic_cast(Child->getLeafValue())) Size += 5; // Matches a ConstantSDNode (+3) and a specific value (+2). else if (Child->getComplexPatternInfo(CGP)) Size += getPatternSize(Child, CGP); @@ -532,7 +668,7 @@ static unsigned getPatternSize(const TreePatternNode *P, ++Size; } } - + return Size; } @@ -573,13 +709,13 @@ std::string PatternToMatch::getPredicateCheck() const { SDTypeConstraint::SDTypeConstraint(Record *R) { OperandNo = R->getValueAsInt("OperandNum"); - + if (R->isSubClassOf("SDTCisVT")) { ConstraintType = SDTCisVT; x.SDTCisVT_Info.VT = getValueType(R->getValueAsDef("VT")); if (x.SDTCisVT_Info.VT == MVT::isVoid) throw TGError(R->getLoc(), "Cannot use 'Void' as type to SDTCisVT"); - + } else if (R->isSubClassOf("SDTCisPtrTy")) { ConstraintType = SDTCisPtrTy; } else if (R->isSubClassOf("SDTCisInt")) { @@ -593,15 +729,19 @@ SDTypeConstraint::SDTypeConstraint(Record *R) { x.SDTCisSameAs_Info.OtherOperandNum = R->getValueAsInt("OtherOperandNum"); } else if (R->isSubClassOf("SDTCisVTSmallerThanOp")) { ConstraintType = SDTCisVTSmallerThanOp; - x.SDTCisVTSmallerThanOp_Info.OtherOperandNum = + x.SDTCisVTSmallerThanOp_Info.OtherOperandNum = R->getValueAsInt("OtherOperandNum"); } else if (R->isSubClassOf("SDTCisOpSmallerThanOp")) { ConstraintType = SDTCisOpSmallerThanOp; - x.SDTCisOpSmallerThanOp_Info.BigOperandNum = + x.SDTCisOpSmallerThanOp_Info.BigOperandNum = R->getValueAsInt("BigOperandNum"); } else if (R->isSubClassOf("SDTCisEltOfVec")) { ConstraintType = SDTCisEltOfVec; x.SDTCisEltOfVec_Info.OtherOperandNum = R->getValueAsInt("OtherOpNum"); + } else if (R->isSubClassOf("SDTCisSubVecOfVec")) { + ConstraintType = SDTCisSubVecOfVec; + x.SDTCisSubVecOfVec_Info.OtherOperandNum = + R->getValueAsInt("OtherOpNum"); } else { errs() << "Unrecognized SDTypeConstraint '" << R->getName() << "'!\n"; exit(1); @@ -618,11 +758,11 @@ static TreePatternNode *getOperandNum(unsigned OpNo, TreePatternNode *N, ResNo = OpNo; return N; } - + OpNo -= NumResults; - + if (OpNo >= N->getNumChildren()) { - errs() << "Invalid operand number in type constraint " + errs() << "Invalid operand number in type constraint " << (OpNo+NumResults) << " "; N->dump(); errs() << '\n'; @@ -641,7 +781,7 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N, TreePattern &TP) const { unsigned ResNo = 0; // The result number being referenced. TreePatternNode *NodeToApply = getOperandNum(OperandNo, N, NodeInfo, ResNo); - + switch (ConstraintType) { default: assert(0 && "Unknown constraint type!"); case SDTCisVT: @@ -676,9 +816,9 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N, TP.error(N->getOperator()->getName() + " expects a VT operand!"); MVT::SimpleValueType VT = getValueType(static_cast(NodeToApply->getLeafValue())->getDef()); - + EEVT::TypeSet TypeListTmp(VT, TP); - + unsigned OResNo = 0; TreePatternNode *OtherNode = getOperandNum(x.SDTCisVTSmallerThanOp_Info.OtherOperandNum, N, NodeInfo, @@ -699,13 +839,24 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode *N, TreePatternNode *VecOperand = getOperandNum(x.SDTCisEltOfVec_Info.OtherOperandNum, N, NodeInfo, VResNo); - + // Filter vector types out of VecOperand that don't have the right element // type. return VecOperand->getExtType(VResNo). EnforceVectorEltTypeIs(NodeToApply->getExtType(ResNo), TP); } - } + case SDTCisSubVecOfVec: { + unsigned VResNo = 0; + TreePatternNode *BigVecOperand = + getOperandNum(x.SDTCisSubVecOfVec_Info.OtherOperandNum, N, NodeInfo, + VResNo); + + // Filter vector types out of BigVecOperand that don't have the + // right subvector type. + return BigVecOperand->getExtType(VResNo). + EnforceVectorSubVectorTypeIs(NodeToApply->getExtType(ResNo), TP); + } + } return false; } @@ -718,7 +869,7 @@ SDNodeInfo::SDNodeInfo(Record *R) : Def(R) { Record *TypeProfile = R->getValueAsDef("TypeProfile"); NumResults = TypeProfile->getValueAsInt("NumResults"); NumOperands = TypeProfile->getValueAsInt("NumOperands"); - + // Parse the properties. Properties = 0; std::vector PropList = R->getValueAsListOfDefs("Properties"); @@ -729,12 +880,12 @@ SDNodeInfo::SDNodeInfo(Record *R) : Def(R) { Properties |= 1 << SDNPAssociative; } else if (PropList[i]->getName() == "SDNPHasChain") { Properties |= 1 << SDNPHasChain; - } else if (PropList[i]->getName() == "SDNPOutFlag") { - Properties |= 1 << SDNPOutFlag; - } else if (PropList[i]->getName() == "SDNPInFlag") { - Properties |= 1 << SDNPInFlag; - } else if (PropList[i]->getName() == "SDNPOptInFlag") { - Properties |= 1 << SDNPOptInFlag; + } else if (PropList[i]->getName() == "SDNPOutGlue") { + Properties |= 1 << SDNPOutGlue; + } else if (PropList[i]->getName() == "SDNPInGlue") { + Properties |= 1 << SDNPInGlue; + } else if (PropList[i]->getName() == "SDNPOptInGlue") { + Properties |= 1 << SDNPOptInGlue; } else if (PropList[i]->getName() == "SDNPMayStore") { Properties |= 1 << SDNPMayStore; } else if (PropList[i]->getName() == "SDNPMayLoad") { @@ -751,8 +902,8 @@ SDNodeInfo::SDNodeInfo(Record *R) : Def(R) { exit(1); } } - - + + // Parse the type constraints. std::vector ConstraintList = TypeProfile->getValueAsListOfDefs("Constraints"); @@ -767,12 +918,12 @@ MVT::SimpleValueType SDNodeInfo::getKnownType(unsigned ResNo) const { assert(NumResults <= 1 && "We only work with nodes with zero or one result so far!"); assert(ResNo == 0 && "Only handles single result nodes so far"); - + for (unsigned i = 0, e = TypeConstraints.size(); i != e; ++i) { // Make sure that this applies to the correct node result. if (TypeConstraints[i].OperandNo >= NumResults) // FIXME: need value # continue; - + switch (TypeConstraints[i].ConstraintType) { default: break; case SDTypeConstraint::SDTCisVT: @@ -799,20 +950,20 @@ static unsigned GetNumNodeResults(Record *Operator, CodeGenDAGPatterns &CDP) { if (Operator->getName() == "set" || Operator->getName() == "implicit") return 0; // All return nothing. - + if (Operator->isSubClassOf("Intrinsic")) return CDP.getIntrinsic(Operator).IS.RetVTs.size(); - + if (Operator->isSubClassOf("SDNode")) return CDP.getSDNodeInfo(Operator).getNumResults(); - + if (Operator->isSubClassOf("PatFrag")) { // If we've already parsed this pattern fragment, get it. Otherwise, handle // the forward reference case where one pattern fragment references another // before it is processed. if (TreePattern *PFRec = CDP.getPatternFragmentIfRead(Operator)) return PFRec->getOnlyTree()->getNumTypes(); - + // Get the result tree. DagInit *Tree = Operator->getValueAsDag("Fragment"); Record *Op = 0; @@ -821,22 +972,22 @@ static unsigned GetNumNodeResults(Record *Operator, CodeGenDAGPatterns &CDP) { assert(Op && "Invalid Fragment"); return GetNumNodeResults(Op, CDP); } - + if (Operator->isSubClassOf("Instruction")) { CodeGenInstruction &InstInfo = CDP.getTargetInfo().getInstruction(Operator); // FIXME: Should allow access to all the results here. - unsigned NumDefsToAdd = InstInfo.NumDefs ? 1 : 0; - + unsigned NumDefsToAdd = InstInfo.Operands.NumDefs ? 1 : 0; + // Add on one implicit def if it has a resolvable type. if (InstInfo.HasOneImplicitDefWithKnownVT(CDP.getTargetInfo()) !=MVT::Other) ++NumDefsToAdd; return NumDefsToAdd; } - + if (Operator->isSubClassOf("SDNodeXForm")) return 1; // FIXME: Generalize SDNodeXForm - + Operator->dump(); errs() << "Unhandled node in GetNumNodeResults\n"; exit(1); @@ -862,7 +1013,7 @@ void TreePatternNode::print(raw_ostream &OS) const { } OS << ")"; } - + for (unsigned i = 0, e = PredicateFns.size(); i != e; ++i) OS << "<>"; if (TransformFn) @@ -900,7 +1051,7 @@ bool TreePatternNode::isIsomorphicTo(const TreePatternNode *N, } return getLeafValue() == N->getLeafValue(); } - + if (N->getOperator() != getOperator() || N->getNumChildren() != getNumChildren()) return false; for (unsigned i = 0, e = getNumChildren(); i != e; ++i) @@ -944,7 +1095,7 @@ void TreePatternNode::RemoveAllTypes() { void TreePatternNode:: SubstituteFormalArguments(std::map &ArgMap) { if (isLeaf()) return; - + for (unsigned i = 0, e = getNumChildren(); i != e; ++i) { TreePatternNode *Child = getChild(i); if (Child->isLeaf()) { @@ -972,7 +1123,7 @@ SubstituteFormalArguments(std::map &ArgMap) { TreePatternNode *TreePatternNode::InlinePatternFragments(TreePattern &TP) { if (isLeaf()) return this; // nothing to do. Record *Op = getOperator(); - + if (!Op->isSubClassOf("PatFrag")) { // Just recursively inline children nodes. for (unsigned i = 0, e = getNumChildren(); i != e; ++i) { @@ -991,7 +1142,7 @@ TreePatternNode *TreePatternNode::InlinePatternFragments(TreePattern &TP) { // Otherwise, we found a reference to a fragment. First, look up its // TreePattern record. TreePattern *Frag = TP.getDAGPatterns().getPatternFragment(Op); - + // Verify that we are passing the right number of operands. if (Frag->getNumArgs() != Children.size()) TP.error("'" + Op->getName() + "' fragment requires " + @@ -1009,10 +1160,10 @@ TreePatternNode *TreePatternNode::InlinePatternFragments(TreePattern &TP) { std::map ArgMap; for (unsigned i = 0, e = Frag->getNumArgs(); i != e; ++i) ArgMap[Frag->getArgName(i)] = getChild(i)->InlinePatternFragments(TP); - + FragTree->SubstituteFormalArguments(ArgMap); } - + FragTree->setName(getName()); for (unsigned i = 0, e = Types.size(); i != e; ++i) FragTree->UpdateNodeType(i, getExtType(i), TP); @@ -1023,7 +1174,7 @@ TreePatternNode *TreePatternNode::InlinePatternFragments(TreePattern &TP) { // Get a new copy of this fragment to stitch into here. //delete this; // FIXME: implement refcounting! - + // The fragment we inlined could have recursive inlining that is needed. See // if there are any pattern fragments in it and inline them as needed. return FragTree->InlinePatternFragments(TP); @@ -1038,21 +1189,21 @@ static EEVT::TypeSet getImplicitType(Record *R, unsigned ResNo, // Check to see if this is a register or a register class. if (R->isSubClassOf("RegisterClass")) { assert(ResNo == 0 && "Regclass ref only has one result!"); - if (NotRegisters) + if (NotRegisters) return EEVT::TypeSet(); // Unknown. const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo(); return EEVT::TypeSet(T.getRegisterClass(R).getValueTypes()); } - + if (R->isSubClassOf("PatFrag")) { assert(ResNo == 0 && "FIXME: PatFrag with multiple results?"); // Pattern fragment types will be resolved when they are inlined. return EEVT::TypeSet(); // Unknown. } - + if (R->isSubClassOf("Register")) { assert(ResNo == 0 && "Registers only produce one result!"); - if (NotRegisters) + if (NotRegisters) return EEVT::TypeSet(); // Unknown. const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo(); return EEVT::TypeSet(T.getRegisterVTs(R)); @@ -1062,16 +1213,16 @@ static EEVT::TypeSet getImplicitType(Record *R, unsigned ResNo, assert(ResNo == 0 && "SubRegisterIndices only produce one result!"); return EEVT::TypeSet(); } - + if (R->isSubClassOf("ValueType") || R->isSubClassOf("CondCode")) { assert(ResNo == 0 && "This node only has one result!"); // Using a VTSDNode or CondCodeSDNode. return EEVT::TypeSet(MVT::Other, TP); } - + if (R->isSubClassOf("ComplexPattern")) { assert(ResNo == 0 && "FIXME: ComplexPattern with multiple results?"); - if (NotRegisters) + if (NotRegisters) return EEVT::TypeSet(); // Unknown. return EEVT::TypeSet(TP.getDAGPatterns().getComplexPattern(R).getValueType(), TP); @@ -1080,13 +1231,13 @@ static EEVT::TypeSet getImplicitType(Record *R, unsigned ResNo, assert(ResNo == 0 && "Regclass can only have one result!"); return EEVT::TypeSet(MVT::iPTR, TP); } - + if (R->getName() == "node" || R->getName() == "srcvalue" || R->getName() == "zero_reg") { // Placeholder. return EEVT::TypeSet(); // Unknown. } - + TP.error("Unknown node flavor used in pattern: " + R->getName()); return EEVT::TypeSet(MVT::Other, TP); } @@ -1100,8 +1251,8 @@ getIntrinsicInfo(const CodeGenDAGPatterns &CDP) const { getOperator() != CDP.get_intrinsic_w_chain_sdnode() && getOperator() != CDP.get_intrinsic_wo_chain_sdnode()) return 0; - - unsigned IID = + + unsigned IID = dynamic_cast(getChild(0)->getLeafValue())->getValue(); return &CDP.getIntrinsicInfo(IID); } @@ -1111,7 +1262,7 @@ getIntrinsicInfo(const CodeGenDAGPatterns &CDP) const { const ComplexPattern * TreePatternNode::getComplexPatternInfo(const CodeGenDAGPatterns &CGP) const { if (!isLeaf()) return 0; - + DefInit *DI = dynamic_cast(getLeafValue()); if (DI && DI->getDef()->isSubClassOf("ComplexPattern")) return &CGP.getComplexPattern(DI->getDef()); @@ -1126,10 +1277,10 @@ bool TreePatternNode::NodeHasProperty(SDNP Property, return CP->hasProperty(Property); return false; } - + Record *Operator = getOperator(); if (!Operator->isSubClassOf("SDNode")) return false; - + return CGP.getSDNodeInfo(Operator).hasProperty(Property); } @@ -1146,7 +1297,7 @@ bool TreePatternNode::TreeHasProperty(SDNP Property, if (getChild(i)->TreeHasProperty(Property, CGP)) return true; return false; -} +} /// isCommutativeIntrinsic - Return true if the node corresponds to a /// commutative intrinsic. @@ -1173,27 +1324,27 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { NotRegisters, TP), TP); return MadeChange; } - + if (IntInit *II = dynamic_cast(getLeafValue())) { assert(Types.size() == 1 && "Invalid IntInit"); - + // Int inits are always integers. :) bool MadeChange = Types[0].EnforceInteger(TP); - + if (!Types[0].isConcrete()) return MadeChange; - + MVT::SimpleValueType VT = getType(0); if (VT == MVT::iPTR || VT == MVT::iPTRAny) return MadeChange; - + unsigned Size = EVT(VT).getSizeInBits(); // Make sure that the value is representable for this type. if (Size >= 32) return MadeChange; - + int Val = (II->getValue() << (32-Size)) >> (32-Size); if (Val == II->getValue()) return MadeChange; - + // If sign-extended doesn't fit, does it fit as unsigned? unsigned ValueMask; unsigned UnsignedVal; @@ -1202,34 +1353,34 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { if ((ValueMask & UnsignedVal) == UnsignedVal) return MadeChange; - + TP.error("Integer value '" + itostr(II->getValue())+ "' is out of range for type '" + getEnumName(getType(0)) + "'!"); return MadeChange; } return false; } - + // special handling for set, which isn't really an SDNode. if (getOperator()->getName() == "set") { assert(getNumTypes() == 0 && "Set doesn't produce a value"); assert(getNumChildren() >= 2 && "Missing RHS of a set?"); unsigned NC = getNumChildren(); - + TreePatternNode *SetVal = getChild(NC-1); bool MadeChange = SetVal->ApplyTypeConstraints(TP, NotRegisters); for (unsigned i = 0; i < NC-1; ++i) { TreePatternNode *Child = getChild(i); MadeChange |= Child->ApplyTypeConstraints(TP, NotRegisters); - + // Types of operands must match. MadeChange |= Child->UpdateNodeType(0, SetVal->getExtType(i), TP); MadeChange |= SetVal->UpdateNodeType(i, Child->getExtType(0), TP); } return MadeChange; } - + if (getOperator()->getName() == "implicit") { assert(getNumTypes() == 0 && "Node doesn't produce a value"); @@ -1238,15 +1389,15 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { MadeChange = getChild(i)->ApplyTypeConstraints(TP, NotRegisters); return MadeChange; } - + if (getOperator()->getName() == "COPY_TO_REGCLASS") { bool MadeChange = false; MadeChange |= getChild(0)->ApplyTypeConstraints(TP, NotRegisters); MadeChange |= getChild(1)->ApplyTypeConstraints(TP, NotRegisters); - + assert(getChild(0)->getNumTypes() == 1 && getChild(1)->getNumTypes() == 1 && "Unhandled case"); - + // child #1 of COPY_TO_REGCLASS should be a register class. We don't care // what type it gets, so if it didn't get a concrete type just give it the // first viable type from the reg class. @@ -1257,14 +1408,14 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { } return MadeChange; } - + if (const CodeGenIntrinsic *Int = getIntrinsicInfo(CDP)) { bool MadeChange = false; // Apply the result type to the node. unsigned NumRetVTs = Int->IS.RetVTs.size(); unsigned NumParamVTs = Int->IS.ParamVTs.size(); - + for (unsigned i = 0, e = NumRetVTs; i != e; ++i) MadeChange |= UpdateNodeType(i, Int->IS.RetVTs[i], TP); @@ -1275,46 +1426,46 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { // Apply type info to the intrinsic ID. MadeChange |= getChild(0)->UpdateNodeType(0, MVT::iPTR, TP); - + for (unsigned i = 0, e = getNumChildren()-1; i != e; ++i) { MadeChange |= getChild(i+1)->ApplyTypeConstraints(TP, NotRegisters); - + MVT::SimpleValueType OpVT = Int->IS.ParamVTs[i]; assert(getChild(i+1)->getNumTypes() == 1 && "Unhandled case"); MadeChange |= getChild(i+1)->UpdateNodeType(0, OpVT, TP); } return MadeChange; } - + if (getOperator()->isSubClassOf("SDNode")) { const SDNodeInfo &NI = CDP.getSDNodeInfo(getOperator()); - + // Check that the number of operands is sane. Negative operands -> varargs. if (NI.getNumOperands() >= 0 && getNumChildren() != (unsigned)NI.getNumOperands()) TP.error(getOperator()->getName() + " node requires exactly " + itostr(NI.getNumOperands()) + " operands!"); - + bool MadeChange = NI.ApplyTypeConstraints(this, TP); for (unsigned i = 0, e = getNumChildren(); i != e; ++i) MadeChange |= getChild(i)->ApplyTypeConstraints(TP, NotRegisters); return MadeChange; } - + if (getOperator()->isSubClassOf("Instruction")) { const DAGInstruction &Inst = CDP.getInstruction(getOperator()); CodeGenInstruction &InstInfo = CDP.getTargetInfo().getInstruction(getOperator()); - + bool MadeChange = false; // Apply the result types to the node, these come from the things in the // (outs) list of the instruction. // FIXME: Cap at one result so far. - unsigned NumResultsToAdd = InstInfo.NumDefs ? 1 : 0; + unsigned NumResultsToAdd = InstInfo.Operands.NumDefs ? 1 : 0; for (unsigned ResNo = 0; ResNo != NumResultsToAdd; ++ResNo) { Record *ResultNode = Inst.getResult(ResNo); - + if (ResultNode->isSubClassOf("PointerLikeRegClass")) { MadeChange |= UpdateNodeType(ResNo, MVT::iPTR, TP); } else if (ResultNode->getName() == "unknown") { @@ -1322,26 +1473,26 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { } else { assert(ResultNode->isSubClassOf("RegisterClass") && "Operands should be register classes!"); - const CodeGenRegisterClass &RC = + const CodeGenRegisterClass &RC = CDP.getTargetInfo().getRegisterClass(ResultNode); MadeChange |= UpdateNodeType(ResNo, RC.getValueTypes(), TP); } } - + // If the instruction has implicit defs, we apply the first one as a result. // FIXME: This sucks, it should apply all implicit defs. if (!InstInfo.ImplicitDefs.empty()) { unsigned ResNo = NumResultsToAdd; - + // FIXME: Generalize to multiple possible types and multiple possible // ImplicitDefs. MVT::SimpleValueType VT = InstInfo.HasOneImplicitDefWithKnownVT(CDP.getTargetInfo()); - + if (VT != MVT::Other) MadeChange |= UpdateNodeType(ResNo, VT, TP); } - + // If this is an INSERT_SUBREG, constrain the source and destination VTs to // be the same. if (getOperator()->getName() == "INSERT_SUBREG") { @@ -1353,7 +1504,7 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { unsigned ChildNo = 0; for (unsigned i = 0, e = Inst.getNumOperands(); i != e; ++i) { Record *OperandNode = Inst.getOperand(i); - + // If the instruction expects a predicate or optional def operand, we // codegen this by setting the operand to it's default value if it has a // non-empty DefaultOps field. @@ -1361,18 +1512,18 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { OperandNode->isSubClassOf("OptionalDefOperand")) && !CDP.getDefaultOperand(OperandNode).DefaultOps.empty()) continue; - + // Verify that we didn't run out of provided operands. if (ChildNo >= getNumChildren()) TP.error("Instruction '" + getOperator()->getName() + "' expects more operands than were provided."); - + MVT::SimpleValueType VT; TreePatternNode *Child = getChild(ChildNo++); unsigned ChildResNo = 0; // Instructions always use res #0 of their op. - + if (OperandNode->isSubClassOf("RegisterClass")) { - const CodeGenRegisterClass &RC = + const CodeGenRegisterClass &RC = CDP.getTargetInfo().getRegisterClass(OperandNode); MadeChange |= Child->UpdateNodeType(ChildResNo, RC.getValueTypes(), TP); } else if (OperandNode->isSubClassOf("Operand")) { @@ -1392,12 +1543,12 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { if (ChildNo != getNumChildren()) TP.error("Instruction '" + getOperator()->getName() + "' was provided too many operands!"); - + return MadeChange; } - + assert(getOperator()->isSubClassOf("SDNodeXForm") && "Unknown node type!"); - + // Node transforms always take one operand. if (getNumChildren() != 1) TP.error("Node transform '" + getOperator()->getName() + @@ -1405,7 +1556,7 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) { bool MadeChange = getChild(0)->ApplyTypeConstraints(TP, NotRegisters); - + // If either the output or input of the xform does not have exact // type info. We assume they must be the same. Otherwise, it is perfectly // legal to transform from one type to a completely different type. @@ -1435,7 +1586,7 @@ static bool OnlyOnRHSOfCommutative(TreePatternNode *N) { /// used as a sanity check for .td files (to prevent people from writing stuff /// that can never possibly work), and to prevent the pattern permuter from /// generating stuff that is useless. -bool TreePatternNode::canPatternMatch(std::string &Reason, +bool TreePatternNode::canPatternMatch(std::string &Reason, const CodeGenDAGPatterns &CDP) { if (isLeaf()) return true; @@ -1449,7 +1600,7 @@ bool TreePatternNode::canPatternMatch(std::string &Reason, // TODO: return true; } - + // If this node is a commutative operator, check that the LHS isn't an // immediate. const SDNodeInfo &NodeInfo = CDP.getSDNodeInfo(getOperator()); @@ -1466,7 +1617,7 @@ bool TreePatternNode::canPatternMatch(std::string &Reason, } } } - + return true; } @@ -1506,7 +1657,7 @@ void TreePattern::ComputeNamedNodes() { void TreePattern::ComputeNamedNodes(TreePatternNode *N) { if (!N->getName().empty()) NamedNodes[N->getName()].push_back(N); - + for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) ComputeNamedNodes(N->getChild(i)); } @@ -1515,7 +1666,7 @@ void TreePattern::ComputeNamedNodes(TreePatternNode *N) { TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){ if (DefInit *DI = dynamic_cast(TheInit)) { Record *R = DI->getDef(); - + // Direct reference to a leaf DagNode or PatFrag? Turn it into a // TreePatternNode if its own. For example: /// (foo GPR, imm) -> (foo GPR, (imm)) @@ -1523,7 +1674,7 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){ return ParseTreePattern(new DagInit(DI, "", std::vector >()), OpName); - + // Input argument? TreePatternNode *Res = new TreePatternNode(DI, 1); if (R->getName() == "node" && !OpName.empty()) { @@ -1535,13 +1686,13 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){ Res->setName(OpName); return Res; } - + if (IntInit *II = dynamic_cast(TheInit)) { if (!OpName.empty()) error("Constant int argument should not have a name!"); return new TreePatternNode(II, 1); } - + if (BitsInit *BI = dynamic_cast(TheInit)) { // Turn this into an IntInit. Init *II = BI->convertInitializerTo(new IntRecTy()); @@ -1558,34 +1709,34 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){ DefInit *OpDef = dynamic_cast(Dag->getOperator()); if (!OpDef) error("Pattern has unexpected operator type!"); Record *Operator = OpDef->getDef(); - + if (Operator->isSubClassOf("ValueType")) { // If the operator is a ValueType, then this must be "type cast" of a leaf // node. if (Dag->getNumArgs() != 1) error("Type cast only takes one operand!"); - + TreePatternNode *New = ParseTreePattern(Dag->getArg(0), Dag->getArgName(0)); - + // Apply the type cast. assert(New->getNumTypes() == 1 && "FIXME: Unhandled"); New->UpdateNodeType(0, getValueType(Operator), *this); - + if (!OpName.empty()) error("ValueType cast should not have a name!"); return New; } - + // Verify that this is something that makes sense for an operator. - if (!Operator->isSubClassOf("PatFrag") && + if (!Operator->isSubClassOf("PatFrag") && !Operator->isSubClassOf("SDNode") && - !Operator->isSubClassOf("Instruction") && + !Operator->isSubClassOf("Instruction") && !Operator->isSubClassOf("SDNodeXForm") && !Operator->isSubClassOf("Intrinsic") && Operator->getName() != "set" && Operator->getName() != "implicit") error("Unrecognized node '" + Operator->getName() + "'!"); - + // Check to see if this is something that is illegal in an input pattern. if (isInputPattern) { if (Operator->isSubClassOf("Instruction") || @@ -1594,7 +1745,7 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){ } else { if (Operator->isSubClassOf("Intrinsic")) error("Cannot use '" + Operator->getName() + "' in an output pattern!"); - + if (Operator->isSubClassOf("SDNode") && Operator->getName() != "imm" && Operator->getName() != "fpimm" && @@ -1609,15 +1760,15 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){ Operator->getName() != "vt") error("Cannot use '" + Operator->getName() + "' in an output pattern!"); } - + std::vector Children; // Parse all the operands. for (unsigned i = 0, e = Dag->getNumArgs(); i != e; ++i) Children.push_back(ParseTreePattern(Dag->getArg(i), Dag->getArgName(i))); - + // If the operator is an intrinsic, then this is just syntactic sugar for for - // (intrinsic_* , ..children..). Pick the right intrinsic node, and + // (intrinsic_* , ..children..). Pick the right intrinsic node, and // convert the intrinsic name to a number. if (Operator->isSubClassOf("Intrinsic")) { const CodeGenIntrinsic &Int = getDAGPatterns().getIntrinsic(Operator); @@ -1632,15 +1783,15 @@ TreePatternNode *TreePattern::ParseTreePattern(Init *TheInit, StringRef OpName){ Operator = getDAGPatterns().get_intrinsic_w_chain_sdnode(); else // Otherwise, no chain. Operator = getDAGPatterns().get_intrinsic_wo_chain_sdnode(); - + TreePatternNode *IIDNode = new TreePatternNode(new IntInit(IID), 1); Children.insert(Children.begin(), IIDNode); } - + unsigned NumResults = GetNumNodeResults(Operator, CDP); TreePatternNode *Result = new TreePatternNode(Operator, Children, NumResults); Result->setName(OpName); - + if (!Dag->getName().empty()) { assert(Result->getName().empty()); Result->setName(Dag->getName()); @@ -1698,10 +1849,10 @@ InferAllTypes(const StringMap > *InNamedTypes) { } // If there are constraints on our named nodes, apply them. - for (StringMap >::iterator + for (StringMap >::iterator I = NamedNodes.begin(), E = NamedNodes.end(); I != E; ++I) { SmallVectorImpl &Nodes = I->second; - + // If we have input named node types, propagate their types to the named // values here. if (InNamedTypes) { @@ -1724,7 +1875,7 @@ InferAllTypes(const StringMap > *InNamedTypes) { if (DI && DI->getDef()->isSubClassOf("RegisterClass")) continue; } - + assert(Nodes[i]->getNumTypes() == 1 && InNodes[0]->getNumTypes() == 1 && "FIXME: cannot name multiple result nodes yet"); @@ -1732,7 +1883,7 @@ InferAllTypes(const StringMap > *InNamedTypes) { *this); } } - + // If there are multiple nodes with the same name, they must all have the // same type. if (I->second.size() > 1) { @@ -1740,14 +1891,14 @@ InferAllTypes(const StringMap > *InNamedTypes) { TreePatternNode *N1 = Nodes[i], *N2 = Nodes[i+1]; assert(N1->getNumTypes() == 1 && N2->getNumTypes() == 1 && "FIXME: cannot name multiple result nodes yet"); - + MadeChange |= N1->UpdateNodeType(0, N2->getExtType(0), *this); MadeChange |= N2->UpdateNodeType(0, N1->getExtType(0), *this); } } } } - + bool HasUnresolvedTypes = false; for (unsigned i = 0, e = Trees.size(); i != e; ++i) HasUnresolvedTypes |= Trees[i]->ContainsUnresolvedType(); @@ -1763,7 +1914,7 @@ void TreePattern::print(raw_ostream &OS) const { OS << ")"; } OS << ": "; - + if (Trees.size() > 1) OS << "[\n"; for (unsigned i = 0, e = Trees.size(); i != e; ++i) { @@ -1782,7 +1933,9 @@ void TreePattern::dump() const { print(errs()); } // CodeGenDAGPatterns implementation // -CodeGenDAGPatterns::CodeGenDAGPatterns(RecordKeeper &R) : Records(R) { +CodeGenDAGPatterns::CodeGenDAGPatterns(RecordKeeper &R) : + Records(R), Target(R) { + Intrinsics = LoadIntrinsics(Records, false); TgtIntrinsics = LoadIntrinsics(Records, true); ParseNodeInfo(); @@ -1792,7 +1945,7 @@ CodeGenDAGPatterns::CodeGenDAGPatterns(RecordKeeper &R) : Records(R) { ParseDefaultOperands(); ParseInstructions(); ParsePatterns(); - + // Generate variants. For example, commutative patterns can match // multiple ways. Add them to PatternsToMatch as well. GenerateVariants(); @@ -1863,20 +2016,20 @@ void CodeGenDAGPatterns::ParseComplexPatterns() { /// void CodeGenDAGPatterns::ParsePatternFragments() { std::vector Fragments = Records.getAllDerivedDefinitions("PatFrag"); - + // First step, parse all of the fragments. for (unsigned i = 0, e = Fragments.size(); i != e; ++i) { DagInit *Tree = Fragments[i]->getValueAsDag("Fragment"); TreePattern *P = new TreePattern(Fragments[i], Tree, true, *this); PatternFragments[Fragments[i]] = P; - + // Validate the argument list, converting it to set, to discard duplicates. std::vector &Args = P->getArgList(); std::set OperandsSet(Args.begin(), Args.end()); - + if (OperandsSet.count("")) P->error("Cannot have unnamed 'node' values in pattern fragment!"); - + // Parse the operands list. DagInit *OpsList = Fragments[i]->getValueAsDag("Operands"); DefInit *OpsOp = dynamic_cast(OpsList->getOperator()); @@ -1887,8 +2040,8 @@ void CodeGenDAGPatterns::ParsePatternFragments() { OpsOp->getDef()->getName() != "outs" && OpsOp->getDef()->getName() != "ins")) P->error("Operands list should start with '(ops ... '!"); - - // Copy over the arguments. + + // Copy over the arguments. Args.clear(); for (unsigned j = 0, e = OpsList->getNumArgs(); j != e; ++j) { if (!dynamic_cast(OpsList->getArg(j)) || @@ -1903,7 +2056,7 @@ void CodeGenDAGPatterns::ParsePatternFragments() { OperandsSet.erase(OpsList->getArgName(j)); Args.push_back(OpsList->getArgName(j)); } - + if (!OperandsSet.empty()) P->error("Operands list does not contain an entry for operand '" + *OperandsSet.begin() + "'!"); @@ -1913,20 +2066,20 @@ void CodeGenDAGPatterns::ParsePatternFragments() { std::string Code = Fragments[i]->getValueAsCode("Predicate"); if (!Code.empty()) P->getOnlyTree()->addPredicateFn("Predicate_"+Fragments[i]->getName()); - + // If there is a node transformation corresponding to this, keep track of // it. Record *Transform = Fragments[i]->getValueAsDef("OperandTransform"); if (!getSDNodeTransform(Transform).second.empty()) // not noop xform? P->getOnlyTree()->setTransformFn(Transform); } - + // Now that we've parsed all of the tree fragments, do a closure on them so // that there are not references to PatFrags left inside of them. for (unsigned i = 0, e = Fragments.size(); i != e; ++i) { TreePattern *ThePat = PatternFragments[Fragments[i]]; ThePat->InlinePatternFragments(); - + // Infer as many types as possible. Don't worry about it if we don't infer // all of them, some may depend on the inputs of the pattern. try { @@ -1937,7 +2090,7 @@ void CodeGenDAGPatterns::ParsePatternFragments() { // actually used by instructions, the type consistency error will be // reported there. } - + // If debugging, print out the pattern fragment result. DEBUG(ThePat->dump()); } @@ -1951,11 +2104,11 @@ void CodeGenDAGPatterns::ParseDefaultOperands() { // Find some SDNode. assert(!SDNodes.empty() && "No SDNodes parsed?"); Init *SomeSDNode = new DefInit(SDNodes.begin()->first); - + for (unsigned iter = 0; iter != 2; ++iter) { for (unsigned i = 0, e = DefaultOps[iter].size(); i != e; ++i) { DagInit *DefaultInfo = DefaultOps[iter][i]->getValueAsDag("DefaultOps"); - + // Clone the DefaultInfo dag node, changing the operator from 'ops' to // SomeSDnode so that we can parse this. std::vector > Ops; @@ -1963,20 +2116,20 @@ void CodeGenDAGPatterns::ParseDefaultOperands() { Ops.push_back(std::make_pair(DefaultInfo->getArg(op), DefaultInfo->getArgName(op))); DagInit *DI = new DagInit(SomeSDNode, "", Ops); - + // Create a TreePattern to parse this. TreePattern P(DefaultOps[iter][i], DI, false, *this); assert(P.getNumTrees() == 1 && "This ctor can only produce one tree!"); // Copy the operands over into a DAGDefaultOperand. DAGDefaultOperand DefaultOpInfo; - + TreePatternNode *T = P.getTree(0); for (unsigned op = 0, e = T->getNumChildren(); op != e; ++op) { TreePatternNode *TPN = T->getChild(op); while (TPN->ApplyTypeConstraints(P, false)) /* Resolve all types */; - + if (TPN->ContainsUnresolvedType()) { if (iter == 0) throw "Value #" + utostr(i) + " of PredicateOperand '" + @@ -2033,7 +2186,7 @@ static bool HandleUse(TreePattern *I, TreePatternNode *Pat, assert(Slot->getNumChildren() == 0 && "can't be a use with children!"); SlotRec = Slot->getOperator(); } - + // Ensure that the inputs agree if we've already seen this input. if (Rec != SlotRec) I->error("All $" + Pat->getName() + " inputs must agree with each other"); @@ -2056,13 +2209,13 @@ FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat, I->error("Cannot specify a transform function for a non-input value!"); return; } - + if (Pat->getOperator()->getName() == "implicit") { for (unsigned i = 0, e = Pat->getNumChildren(); i != e; ++i) { TreePatternNode *Dest = Pat->getChild(i); if (!Dest->isLeaf()) I->error("implicitly defined value should be a register!"); - + DefInit *Val = dynamic_cast(Dest->getLeafValue()); if (!Val || !Val->getDef()->isSubClassOf("Register")) I->error("implicitly defined value should be a register!"); @@ -2070,7 +2223,7 @@ FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat, } return; } - + if (Pat->getOperator()->getName() != "set") { // If this is not a set, verify that the children nodes are not void typed, // and recurse. @@ -2080,30 +2233,30 @@ FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat, FindPatternInputsAndOutputs(I, Pat->getChild(i), InstInputs, InstResults, InstImpResults); } - + // If this is a non-leaf node with no children, treat it basically as if // it were a leaf. This handles nodes like (imm). bool isUse = HandleUse(I, Pat, InstInputs); - + if (!isUse && Pat->getTransformFn()) I->error("Cannot specify a transform function for a non-input value!"); return; } - + // Otherwise, this is a set, validate and collect instruction results. if (Pat->getNumChildren() == 0) I->error("set requires operands!"); - + if (Pat->getTransformFn()) I->error("Cannot specify a transform function on a set node!"); - + // Check the set destinations. unsigned NumDests = Pat->getNumChildren()-1; for (unsigned i = 0; i != NumDests; ++i) { TreePatternNode *Dest = Pat->getChild(i); if (!Dest->isLeaf()) I->error("set destination should be a register!"); - + DefInit *Val = dynamic_cast(Dest->getLeafValue()); if (!Val) I->error("set destination should be a register!"); @@ -2121,7 +2274,7 @@ FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat, I->error("set destination should be a register!"); } } - + // Verify and collect info from the computation. FindPatternInputsAndOutputs(I, Pat->getChild(NumDests), InstInputs, InstResults, InstImpResults); @@ -2254,8 +2407,8 @@ static void InferFromPattern(const CodeGenInstruction &Inst, "which already inferred this.\n", Inst.TheDef->getName().c_str()); HasSideEffects = true; } - - if (Inst.isVariadic) + + if (Inst.Operands.isVariadic) IsVariadic = true; // Can warn if we want. } @@ -2264,64 +2417,64 @@ static void InferFromPattern(const CodeGenInstruction &Inst, /// resolved instructions. void CodeGenDAGPatterns::ParseInstructions() { std::vector Instrs = Records.getAllDerivedDefinitions("Instruction"); - + for (unsigned i = 0, e = Instrs.size(); i != e; ++i) { ListInit *LI = 0; - + if (dynamic_cast(Instrs[i]->getValueInit("Pattern"))) LI = Instrs[i]->getValueAsListInit("Pattern"); - + // If there is no pattern, only collect minimal information about the // instruction for its operand list. We have to assume that there is one // result, as we have no detailed info. if (!LI || LI->getSize() == 0) { std::vector Results; std::vector Operands; - + CodeGenInstruction &InstInfo = Target.getInstruction(Instrs[i]); - if (InstInfo.OperandList.size() != 0) { - if (InstInfo.NumDefs == 0) { + if (InstInfo.Operands.size() != 0) { + if (InstInfo.Operands.NumDefs == 0) { // These produce no results - for (unsigned j = 0, e = InstInfo.OperandList.size(); j < e; ++j) - Operands.push_back(InstInfo.OperandList[j].Rec); + for (unsigned j = 0, e = InstInfo.Operands.size(); j < e; ++j) + Operands.push_back(InstInfo.Operands[j].Rec); } else { // Assume the first operand is the result. - Results.push_back(InstInfo.OperandList[0].Rec); - + Results.push_back(InstInfo.Operands[0].Rec); + // The rest are inputs. - for (unsigned j = 1, e = InstInfo.OperandList.size(); j < e; ++j) - Operands.push_back(InstInfo.OperandList[j].Rec); + for (unsigned j = 1, e = InstInfo.Operands.size(); j < e; ++j) + Operands.push_back(InstInfo.Operands[j].Rec); } } - + // Create and insert the instruction. std::vector ImpResults; - Instructions.insert(std::make_pair(Instrs[i], + Instructions.insert(std::make_pair(Instrs[i], DAGInstruction(0, Results, Operands, ImpResults))); continue; // no pattern. } - + // Parse the instruction. TreePattern *I = new TreePattern(Instrs[i], LI, true, *this); // Inline pattern fragments into it. I->InlinePatternFragments(); - + // Infer as many types as possible. If we cannot infer all of them, we can // never do anything with this instruction pattern: report it to the user. if (!I->InferAllTypes()) I->error("Could not infer all types in pattern!"); - - // InstInputs - Keep track of all of the inputs of the instruction, along + + // InstInputs - Keep track of all of the inputs of the instruction, along // with the record they are declared as. std::map InstInputs; - + // InstResults - Keep track of all the virtual registers that are 'set' // in the instruction, including what reg class they are. std::map InstResults; std::vector InstImpResults; - + // Verify that the top-level forms in the instruction are of void type, and // fill in the InstResults map. for (unsigned j = 0, e = I->getNumTrees(); j != e; ++j) { @@ -2348,29 +2501,29 @@ void CodeGenDAGPatterns::ParseInstructions() { std::vector Results; TreePatternNode *Res0Node = 0; for (unsigned i = 0; i != NumResults; ++i) { - if (i == CGI.OperandList.size()) + if (i == CGI.Operands.size()) I->error("'" + InstResults.begin()->first + "' set but does not appear in operand list!"); - const std::string &OpName = CGI.OperandList[i].Name; - + const std::string &OpName = CGI.Operands[i].Name; + // Check that it exists in InstResults. TreePatternNode *RNode = InstResults[OpName]; if (RNode == 0) I->error("Operand $" + OpName + " does not exist in operand list!"); - + if (i == 0) Res0Node = RNode; Record *R = dynamic_cast(RNode->getLeafValue())->getDef(); if (R == 0) I->error("Operand $" + OpName + " should be a set destination: all " "outputs must occur before inputs in operand list!"); - - if (CGI.OperandList[i].Rec != R) + + if (CGI.Operands[i].Rec != R) I->error("Operand $" + OpName + " class mismatch!"); - + // Remember the return type. - Results.push_back(CGI.OperandList[i].Rec); - + Results.push_back(CGI.Operands[i].Rec); + // Okay, this one checks out. InstResults.erase(OpName); } @@ -2381,8 +2534,8 @@ void CodeGenDAGPatterns::ParseInstructions() { std::vector ResultNodeOperands; std::vector Operands; - for (unsigned i = NumResults, e = CGI.OperandList.size(); i != e; ++i) { - CodeGenInstruction::OperandInfo &Op = CGI.OperandList[i]; + for (unsigned i = NumResults, e = CGI.Operands.size(); i != e; ++i) { + CGIOperandList::OperandInfo &Op = CGI.Operands[i]; const std::string &OpName = Op.Name; if (OpName.empty()) I->error("Operand #" + utostr(i) + " in operands list has no name!"); @@ -2403,7 +2556,7 @@ void CodeGenDAGPatterns::ParseInstructions() { } TreePatternNode *InVal = InstInputsCheck[OpName]; InstInputsCheck.erase(OpName); // It occurred, remove from map. - + if (InVal->isLeaf() && dynamic_cast(InVal->getLeafValue())) { Record *InRec = static_cast(InVal->getLeafValue())->getDef(); @@ -2412,13 +2565,13 @@ void CodeGenDAGPatterns::ParseInstructions() { " between the operand and pattern"); } Operands.push_back(Op.Rec); - + // Construct the result for the dest-pattern operand list. TreePatternNode *OpNode = InVal->clone(); - + // No predicate is useful on the result. OpNode->clearPredicateFns(); - + // Promote the xform function to be an explicit node if set. if (Record *Xform = OpNode->getTransformFn()) { OpNode->setTransformFn(0); @@ -2426,10 +2579,10 @@ void CodeGenDAGPatterns::ParseInstructions() { Children.push_back(OpNode); OpNode = new TreePatternNode(Xform, Children, OpNode->getNumTypes()); } - + ResultNodeOperands.push_back(OpNode); } - + if (!InstInputsCheck.empty()) I->error("Input operand $" + InstInputsCheck.begin()->first + " occurs in pattern but not in operands list!"); @@ -2454,10 +2607,10 @@ void CodeGenDAGPatterns::ParseInstructions() { DAGInstruction &TheInsertedInst = Instructions.find(I->getRecord())->second; TheInsertedInst.setResultPattern(Temp.getOnlyTree()); - + DEBUG(I->dump()); } - + // If we can, convert the instructions to be patterns that are matched! for (std::map::iterator II = Instructions.begin(), @@ -2476,10 +2629,11 @@ void CodeGenDAGPatterns::ParseInstructions() { // Not a set (store or something?) SrcPattern = Pattern; } - + Record *Instr = II->first; AddPatternToMatch(I, - PatternToMatch(Instr->getValueAsListInit("Predicates"), + PatternToMatch(Instr, + Instr->getValueAsListInit("Predicates"), SrcPattern, TheInst.getResultPattern(), TheInst.getImpResults(), @@ -2491,7 +2645,7 @@ void CodeGenDAGPatterns::ParseInstructions() { typedef std::pair NameRecord; -static void FindNames(const TreePatternNode *P, +static void FindNames(const TreePatternNode *P, std::map &Names, const TreePattern *PatternTop) { if (!P->getName().empty()) { @@ -2503,7 +2657,7 @@ static void FindNames(const TreePatternNode *P, PatternTop->error("repetition of value: $" + P->getName() + " where different uses have different types!"); } - + if (!P->isLeaf()) { for (unsigned i = 0, e = P->getNumChildren(); i != e; ++i) FindNames(P->getChild(i), Names, PatternTop); @@ -2516,7 +2670,7 @@ void CodeGenDAGPatterns::AddPatternToMatch(const TreePattern *Pattern, std::string Reason; if (!PTM.getSrcPattern()->canPatternMatch(Reason, *this)) Pattern->error("Pattern can never match: " + Reason); - + // If the source pattern's root is a complex pattern, that complex pattern // must specify the nodes it can potentially match. if (const ComplexPattern *CP = @@ -2524,8 +2678,8 @@ void CodeGenDAGPatterns::AddPatternToMatch(const TreePattern *Pattern, if (CP->getRootNodes().empty()) Pattern->error("ComplexPattern at root must specify list of opcodes it" " could match"); - - + + // Find all of the named values in the input and output, ensure they have the // same type. std::map SrcNames, DstNames; @@ -2540,14 +2694,14 @@ void CodeGenDAGPatterns::AddPatternToMatch(const TreePattern *Pattern, Pattern->error("Pattern has input without matching name in output: $" + I->first); } - + // Scan all of the named values in the source pattern, rejecting them if the // name isn't used in the dest, and isn't used to tie two values together. for (std::map::iterator I = SrcNames.begin(), E = SrcNames.end(); I != E; ++I) if (DstNames[I->first].first == 0 && SrcNames[I->first].second == 1) Pattern->error("Pattern has dead named input: $" + I->first); - + PatternsToMatch.push_back(PTM); } @@ -2566,7 +2720,7 @@ void CodeGenDAGPatterns::InferInstructionFlags() { InstInfo.mayStore = MayStore; InstInfo.mayLoad = MayLoad; InstInfo.hasSideEffects = HasSideEffects; - InstInfo.isVariadic = IsVariadic; + InstInfo.Operands.isVariadic = IsVariadic; } } @@ -2576,7 +2730,7 @@ void CodeGenDAGPatterns::InferInstructionFlags() { static bool ForceArbitraryInstResultType(TreePatternNode *N, TreePattern &TP) { if (N->isLeaf()) return false; - + // Analyze children. for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i) if (ForceArbitraryInstResultType(N->getChild(i), TP)) @@ -2590,12 +2744,12 @@ static bool ForceArbitraryInstResultType(TreePatternNode *N, TreePattern &TP) { for (unsigned i = 0, e = N->getNumTypes(); i != e; ++i) { if (N->getExtType(i).isCompletelyUnknown() || N->getExtType(i).isConcrete()) continue; - + // Otherwise, force its type to the first possibility (an arbitrary choice). if (N->getExtType(i).MergeInTypeInfo(N->getExtType(i).getTypeList()[0], TP)) return true; } - + return false; } @@ -2609,20 +2763,20 @@ void CodeGenDAGPatterns::ParsePatterns() { // Inline pattern fragments into it. Pattern->InlinePatternFragments(); - + ListInit *LI = CurPattern->getValueAsListInit("ResultInstrs"); if (LI->getSize() == 0) continue; // no pattern. - + // Parse the instruction. TreePattern *Result = new TreePattern(CurPattern, LI, false, *this); - + // Inline pattern fragments into it. Result->InlinePatternFragments(); if (Result->getNumTrees() != 1) Result->error("Cannot handle instructions producing instructions " "with temporaries yet!"); - + bool IterateInference; bool InferredAllPatternTypes, InferredAllResultTypes; do { @@ -2630,14 +2784,14 @@ void CodeGenDAGPatterns::ParsePatterns() { // can never do anything with this pattern: report it to the user. InferredAllPatternTypes = Pattern->InferAllTypes(&Pattern->getNamedNodesMap()); - + // Infer as many types as possible. If we cannot infer all of them, we // can never do anything with this pattern: report it to the user. InferredAllResultTypes = Result->InferAllTypes(&Pattern->getNamedNodesMap()); IterateInference = false; - + // Apply the type of the result to the source pattern. This helps us // resolve cases where the input type is known to be a pointer type (which // is considered resolved), but the result knows it needs to be 32- or @@ -2650,7 +2804,7 @@ void CodeGenDAGPatterns::ParsePatterns() { IterateInference |= Result->getTree(0)-> UpdateNodeType(i, Pattern->getTree(0)->getExtType(i), *Result); } - + // If our iteration has converged and the input pattern's types are fully // resolved but the result pattern is not fully resolved, we may have a // situation where we have two instructions in the result pattern and @@ -2665,7 +2819,7 @@ void CodeGenDAGPatterns::ParsePatterns() { IterateInference = ForceArbitraryInstResultType(Result->getTree(0), *Result); } while (IterateInference); - + // Verify that we inferred enough types that we can do something with the // pattern and result. If these fire the user has to add type casts. if (!InferredAllPatternTypes) @@ -2674,7 +2828,7 @@ void CodeGenDAGPatterns::ParsePatterns() { Pattern->dump(); Result->error("Could not infer all types in pattern result!"); } - + // Validate that the input pattern is correct. std::map InstInputs; std::map InstResults; @@ -2702,16 +2856,17 @@ void CodeGenDAGPatterns::ParsePatterns() { DstPattern = new TreePatternNode(DstPattern->getOperator(), ResultNodeOperands, DstPattern->getNumTypes()); - + for (unsigned i = 0, e = Result->getOnlyTree()->getNumTypes(); i != e; ++i) DstPattern->setType(i, Result->getOnlyTree()->getExtType(i)); - + TreePattern Temp(Result->getRecord(), DstPattern, false, *this); Temp.InferAllTypes(); - + AddPatternToMatch(Pattern, - PatternToMatch(CurPattern->getValueAsListInit("Predicates"), + PatternToMatch(CurPattern, + CurPattern->getValueAsListInit("Predicates"), Pattern->getTree(0), Temp.getOnlyTree(), InstImpResults, CurPattern->getValueAsInt("AddedComplexity"), @@ -2721,7 +2876,7 @@ void CodeGenDAGPatterns::ParsePatterns() { /// CombineChildVariants - Given a bunch of permutations of each child of the /// 'operator' node, put them together in all possible ways. -static void CombineChildVariants(TreePatternNode *Orig, +static void CombineChildVariants(TreePatternNode *Orig, const std::vector > &ChildVariants, std::vector &OutVariants, CodeGenDAGPatterns &CDP, @@ -2730,7 +2885,7 @@ static void CombineChildVariants(TreePatternNode *Orig, for (unsigned i = 0, e = ChildVariants.size(); i != e; ++i) if (ChildVariants[i].empty()) return; - + // The end result is an all-pairs construction of the resultant pattern. std::vector Idxs; Idxs.resize(ChildVariants.size()); @@ -2751,21 +2906,21 @@ static void CombineChildVariants(TreePatternNode *Orig, NewChildren.push_back(ChildVariants[i][Idxs[i]]); TreePatternNode *R = new TreePatternNode(Orig->getOperator(), NewChildren, Orig->getNumTypes()); - + // Copy over properties. R->setName(Orig->getName()); R->setPredicateFns(Orig->getPredicateFns()); R->setTransformFn(Orig->getTransformFn()); for (unsigned i = 0, e = Orig->getNumTypes(); i != e; ++i) R->setType(i, Orig->getExtType(i)); - + // If this pattern cannot match, do not include it as a variant. std::string ErrString; if (!R->canPatternMatch(ErrString, CDP)) { delete R; } else { bool AlreadyExists = false; - + // Scan to see if this pattern has already been emitted. We can get // duplication due to things like commuting: // (and GPRC:$a, GPRC:$b) -> (and GPRC:$b, GPRC:$a) @@ -2775,13 +2930,13 @@ static void CombineChildVariants(TreePatternNode *Orig, AlreadyExists = true; break; } - + if (AlreadyExists) delete R; else OutVariants.push_back(R); } - + // Increment indices to the next permutation by incrementing the // indicies from last index backward, e.g., generate the sequence // [0, 0], [0, 1], [1, 0], [1, 1]. @@ -2798,7 +2953,7 @@ static void CombineChildVariants(TreePatternNode *Orig, /// CombineChildVariants - A helper function for binary operators. /// -static void CombineChildVariants(TreePatternNode *Orig, +static void CombineChildVariants(TreePatternNode *Orig, const std::vector &LHS, const std::vector &RHS, std::vector &OutVariants, @@ -2808,14 +2963,14 @@ static void CombineChildVariants(TreePatternNode *Orig, ChildVariants.push_back(LHS); ChildVariants.push_back(RHS); CombineChildVariants(Orig, ChildVariants, OutVariants, CDP, DepVars); -} +} static void GatherChildrenOfAssociativeOpcode(TreePatternNode *N, std::vector &Children) { assert(N->getNumChildren()==2 &&"Associative but doesn't have 2 children!"); Record *Operator = N->getOperator(); - + // Only permit raw nodes. if (!N->getName().empty() || !N->getPredicateFns().empty() || N->getTransformFn()) { @@ -2852,7 +3007,7 @@ static void GenerateVariantsOf(TreePatternNode *N, // If this node is associative, re-associate. if (NodeInfo.hasProperty(SDNPAssociative)) { - // Re-associate by pulling together all of the linked operators + // Re-associate by pulling together all of the linked operators std::vector MaximalChildren; GatherChildrenOfAssociativeOpcode(N, MaximalChildren); @@ -2864,11 +3019,11 @@ static void GenerateVariantsOf(TreePatternNode *N, GenerateVariantsOf(MaximalChildren[0], AVariants, CDP, DepVars); GenerateVariantsOf(MaximalChildren[1], BVariants, CDP, DepVars); GenerateVariantsOf(MaximalChildren[2], CVariants, CDP, DepVars); - + // There are only two ways we can permute the tree: // (A op B) op C and A op (B op C) // Within these forms, we can also permute A/B/C. - + // Generate legal pair permutations of A/B/C. std::vector ABVariants; std::vector BAVariants; @@ -2901,7 +3056,7 @@ static void GenerateVariantsOf(TreePatternNode *N, return; } } - + // Compute permutations of all children. std::vector > ChildVariants; ChildVariants.resize(N->getNumChildren()); @@ -2953,7 +3108,7 @@ static void GenerateVariantsOf(TreePatternNode *N, // match multiple ways. Add them to PatternsToMatch as well. void CodeGenDAGPatterns::GenerateVariants() { DEBUG(errs() << "Generating instruction variants.\n"); - + // Loop over all of the patterns we've collected, checking to see if we can // generate variants of the instruction, through the exploitation of // identities. This permits the target to provide aggressive matching without @@ -2970,7 +3125,8 @@ void CodeGenDAGPatterns::GenerateVariants() { DEBUG(errs() << "Dependent/multiply used variables: "); DEBUG(DumpDepVars(DepVars)); DEBUG(errs() << "\n"); - GenerateVariantsOf(PatternsToMatch[i].getSrcPattern(), Variants, *this, DepVars); + GenerateVariantsOf(PatternsToMatch[i].getSrcPattern(), Variants, *this, + DepVars); assert(!Variants.empty() && "Must create at least original variant!"); Variants.erase(Variants.begin()); // Remove the original pattern. @@ -2988,7 +3144,7 @@ void CodeGenDAGPatterns::GenerateVariants() { DEBUG(errs() << " VAR#" << v << ": "; Variant->dump(); errs() << "\n"); - + // Scan to see if an instruction or explicit pattern already matches this. bool AlreadyExists = false; for (unsigned p = 0, e = PatternsToMatch.size(); p != e; ++p) { @@ -2997,7 +3153,8 @@ void CodeGenDAGPatterns::GenerateVariants() { PatternsToMatch[p].getPredicates()) continue; // Check to see if this variant already exists. - if (Variant->isIsomorphicTo(PatternsToMatch[p].getSrcPattern(), DepVars)) { + if (Variant->isIsomorphicTo(PatternsToMatch[p].getSrcPattern(), + DepVars)) { DEBUG(errs() << " *** ALREADY EXISTS, ignoring variant.\n"); AlreadyExists = true; break; @@ -3008,7 +3165,8 @@ void CodeGenDAGPatterns::GenerateVariants() { // Otherwise, add it to the list of patterns we have. PatternsToMatch. - push_back(PatternToMatch(PatternsToMatch[i].getPredicates(), + push_back(PatternToMatch(PatternsToMatch[i].getSrcRecord(), + PatternsToMatch[i].getPredicates(), Variant, PatternsToMatch[i].getDstPattern(), PatternsToMatch[i].getDstRegs(), PatternsToMatch[i].getAddedComplexity(), diff --git a/utils/TableGen/CodeGenDAGPatterns.h b/utils/TableGen/CodeGenDAGPatterns.h index 0a1362ab2494..946dceed66c0 100644 --- a/utils/TableGen/CodeGenDAGPatterns.h +++ b/utils/TableGen/CodeGenDAGPatterns.h @@ -58,50 +58,50 @@ namespace EEVT { public: TypeSet() {} TypeSet(MVT::SimpleValueType VT, TreePattern &TP); - TypeSet(const std::vector &VTList); - + TypeSet(const std::vector &VTList); + bool isCompletelyUnknown() const { return TypeVec.empty(); } - + bool isConcrete() const { if (TypeVec.size() != 1) return false; unsigned char T = TypeVec[0]; (void)T; assert(T < MVT::LAST_VALUETYPE || T == MVT::iPTR || T == MVT::iPTRAny); return true; } - + MVT::SimpleValueType getConcrete() const { assert(isConcrete() && "Type isn't concrete yet"); return (MVT::SimpleValueType)TypeVec[0]; } - + bool isDynamicallyResolved() const { return getConcrete() == MVT::iPTR || getConcrete() == MVT::iPTRAny; } - + const SmallVectorImpl &getTypeList() const { assert(!TypeVec.empty() && "Not a type list!"); return TypeVec; } - + bool isVoid() const { return TypeVec.size() == 1 && TypeVec[0] == MVT::isVoid; } - + /// hasIntegerTypes - Return true if this TypeSet contains any integer value /// types. bool hasIntegerTypes() const; - + /// hasFloatingPointTypes - Return true if this TypeSet contains an fAny or /// a floating point value type. bool hasFloatingPointTypes() const; - + /// hasVectorTypes - Return true if this TypeSet contains a vector value /// type. bool hasVectorTypes() const; - + /// getName() - Return this TypeSet as a string. std::string getName() const; - + /// MergeInTypeInfo - This merges in type information from the specified /// argument. If 'this' changes, it returns true. If the two types are /// contradictory (e.g. merge f32 into i32) then this throws an exception. @@ -126,14 +126,18 @@ namespace EEVT { /// EnforceSmallerThan - 'this' must be a smaller VT than Other. Update /// this an other based on this information. bool EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP); - + /// EnforceVectorEltTypeIs - 'this' is now constrainted to be a vector type /// whose element is VT. bool EnforceVectorEltTypeIs(EEVT::TypeSet &VT, TreePattern &TP); - + + /// EnforceVectorSubVectorTypeIs - 'this' is now constrainted to + /// be a vector type VT. + bool EnforceVectorSubVectorTypeIs(EEVT::TypeSet &VT, TreePattern &TP); + bool operator!=(const TypeSet &RHS) const { return TypeVec != RHS.TypeVec; } bool operator==(const TypeSet &RHS) const { return TypeVec == RHS.TypeVec; } - + private: /// FillWithPossibleTypes - Set to all legal types and return true, only /// valid on completely unknown type sets. If Pred is non-null, only MVTs @@ -151,13 +155,14 @@ typedef std::set MultipleUseVarSet; /// corresponding to the SDTypeConstraint tablegen class in Target.td. struct SDTypeConstraint { SDTypeConstraint(Record *R); - + unsigned OperandNo; // The operand # this constraint applies to. - enum { - SDTCisVT, SDTCisPtrTy, SDTCisInt, SDTCisFP, SDTCisVec, SDTCisSameAs, - SDTCisVTSmallerThanOp, SDTCisOpSmallerThanOp, SDTCisEltOfVec + enum { + SDTCisVT, SDTCisPtrTy, SDTCisInt, SDTCisFP, SDTCisVec, SDTCisSameAs, + SDTCisVTSmallerThanOp, SDTCisOpSmallerThanOp, SDTCisEltOfVec, + SDTCisSubVecOfVec } ConstraintType; - + union { // The discriminated union. struct { MVT::SimpleValueType VT; @@ -174,6 +179,9 @@ struct SDTypeConstraint { struct { unsigned OtherOperandNum; } SDTCisEltOfVec_Info; + struct { + unsigned OtherOperandNum; + } SDTCisSubVecOfVec_Info; } x; /// ApplyTypeConstraint - Given a node in a pattern, apply this type @@ -197,25 +205,25 @@ class SDNodeInfo { std::vector TypeConstraints; public: SDNodeInfo(Record *R); // Parse the specified record. - + unsigned getNumResults() const { return NumResults; } - + /// getNumOperands - This is the number of operands required or -1 if /// variadic. int getNumOperands() const { return NumOperands; } Record *getRecord() const { return Def; } const std::string &getEnumName() const { return EnumName; } const std::string &getSDClassName() const { return SDClassName; } - + const std::vector &getTypeConstraints() const { return TypeConstraints; } - + /// getKnownType - If the type constraints on this node imply a fixed type /// (e.g. all stores return void, etc), then return it as an /// MVT::SimpleValueType. Otherwise, return MVT::Other. MVT::SimpleValueType getKnownType(unsigned ResNo) const; - + /// hasProperty - Return true if this node has the specified property. /// bool hasProperty(enum SDNP Prop) const { return Properties & (1 << Prop); } @@ -240,31 +248,31 @@ class TreePatternNode { /// result may be a set of possible types. After (successful) type inference, /// each is a single concrete type. SmallVector Types; - + /// Operator - The Record for the operator if this is an interior node (not /// a leaf). Record *Operator; - + /// Val - The init value (e.g. the "GPRC" record, or "7") for a leaf. /// Init *Val; - + /// Name - The name given to this node with the :$foo notation. /// std::string Name; - + /// PredicateFns - The predicate functions to execute on this node to check /// for a match. If this list is empty, no predicate is involved. std::vector PredicateFns; - + /// TransformFn - The transformation function to execute on this node before /// it can be substituted into the resulting instruction on a pattern match. Record *TransformFn; - + std::vector Children; public: TreePatternNode(Record *Op, const std::vector &Ch, - unsigned NumResults) + unsigned NumResults) : Operator(Op), Val(0), TransformFn(0), Children(Ch) { Types.resize(NumResults); } @@ -273,12 +281,12 @@ public: Types.resize(NumResults); } ~TreePatternNode(); - + const std::string &getName() const { return Name; } void setName(StringRef N) { Name.assign(N.begin(), N.end()); } - + bool isLeaf() const { return Val != 0; } - + // Type accessors. unsigned getNumTypes() const { return Types.size(); } MVT::SimpleValueType getType(unsigned ResNo) const { @@ -288,7 +296,7 @@ public: const EEVT::TypeSet &getExtType(unsigned ResNo) const { return Types[ResNo]; } EEVT::TypeSet &getExtType(unsigned ResNo) { return Types[ResNo]; } void setType(unsigned ResNo, const EEVT::TypeSet &T) { Types[ResNo] = T; } - + bool hasTypeSet(unsigned ResNo) const { return Types[ResNo].isConcrete(); } @@ -298,16 +306,16 @@ public: bool isTypeDynamicallyResolved(unsigned ResNo) const { return Types[ResNo].isDynamicallyResolved(); } - + Init *getLeafValue() const { assert(isLeaf()); return Val; } Record *getOperator() const { assert(!isLeaf()); return Operator; } - + unsigned getNumChildren() const { return Children.size(); } TreePatternNode *getChild(unsigned N) const { return Children[N]; } void setChild(unsigned i, TreePatternNode *N) { Children[i] = N; } - + /// hasChild - Return true if N is any of our children. bool hasChild(const TreePatternNode *N) const { for (unsigned i = 0, e = Children.size(); i != e; ++i) @@ -321,7 +329,7 @@ public: assert(PredicateFns.empty() && "Overwriting non-empty predicate list!"); PredicateFns = Fns; } - void addPredicateFn(const std::string &Fn) { + void addPredicateFn(const std::string &Fn) { assert(!Fn.empty() && "Empty predicate string!"); if (std::find(PredicateFns.begin(), PredicateFns.end(), Fn) == PredicateFns.end()) @@ -330,7 +338,7 @@ public: Record *getTransformFn() const { return TransformFn; } void setTransformFn(Record *Fn) { TransformFn = Fn; } - + /// getIntrinsicInfo - If this node corresponds to an intrinsic, return the /// CodeGenIntrinsic information for it, otherwise return a null pointer. const CodeGenIntrinsic *getIntrinsicInfo(const CodeGenDAGPatterns &CDP) const; @@ -342,18 +350,18 @@ public: /// NodeHasProperty - Return true if this node has the specified property. bool NodeHasProperty(SDNP Property, const CodeGenDAGPatterns &CGP) const; - + /// TreeHasProperty - Return true if any node in this tree has the specified /// property. bool TreeHasProperty(SDNP Property, const CodeGenDAGPatterns &CGP) const; - + /// isCommutativeIntrinsic - Return true if the node is an intrinsic which is /// marked isCommutative. bool isCommutativeIntrinsic(const CodeGenDAGPatterns &CDP) const; - + void print(raw_ostream &OS) const; void dump() const; - + public: // Higher level manipulation routines. /// clone - Return a new copy of this tree. @@ -362,14 +370,14 @@ public: // Higher level manipulation routines. /// RemoveAllTypes - Recursively strip all the types of this tree. void RemoveAllTypes(); - + /// isIsomorphicTo - Return true if this node is recursively isomorphic to /// the specified node. For this comparison, all of the state of the node /// is considered, except for the assigned name. Nodes with differing names /// that are otherwise identical are considered isomorphic. bool isIsomorphicTo(const TreePatternNode *N, const MultipleUseVarSet &DepVars) const; - + /// SubstituteFormalArguments - Replace the formal arguments in this tree /// with actual values specified by ArgMap. void SubstituteFormalArguments(std::mapContainsUnresolvedType()) return true; return false; } - + /// canPatternMatch - If it is impossible for this pattern to match on this /// target, fill in Reason and return false. Otherwise, return true. bool canPatternMatch(std::string &Reason, const CodeGenDAGPatterns &CDP); @@ -420,7 +428,7 @@ inline raw_ostream &operator<<(raw_ostream &OS, const TreePatternNode &TPN) { TPN.print(OS); return OS; } - + /// TreePattern - Represent a pattern, used for instructions, pattern /// fragments, etc. @@ -430,19 +438,19 @@ class TreePattern { /// Note that PatFrag's only have a single tree. /// std::vector Trees; - + /// NamedNodes - This is all of the nodes that have names in the trees in this /// pattern. StringMap > NamedNodes; - + /// TheRecord - The actual TableGen record corresponding to this pattern. /// Record *TheRecord; - + /// Args - This is a list of all of the arguments to this pattern (for /// PatFrag patterns), which are the 'node' markers in this pattern. std::vector Args; - + /// CDP - the top-level object coordinating this madness. /// CodeGenDAGPatterns &CDP; @@ -451,7 +459,7 @@ class TreePattern { /// False if this is an output pattern, something to emit. bool isInputPattern; public: - + /// TreePattern constructor - Parse the specified DagInits into the /// current record. TreePattern(Record *TheRec, ListInit *RawPat, bool isInput, @@ -460,7 +468,7 @@ public: CodeGenDAGPatterns &ise); TreePattern(Record *TheRec, TreePatternNode *Pat, bool isInput, CodeGenDAGPatterns &ise); - + /// getTrees - Return the tree patterns which corresponds to this pattern. /// const std::vector &getTrees() const { return Trees; } @@ -470,25 +478,25 @@ public: assert(Trees.size() == 1 && "Doesn't have exactly one pattern!"); return Trees[0]; } - + const StringMap > &getNamedNodesMap() { if (NamedNodes.empty()) ComputeNamedNodes(); return NamedNodes; } - + /// getRecord - Return the actual TableGen record corresponding to this /// pattern. /// Record *getRecord() const { return TheRecord; } - + unsigned getNumArgs() const { return Args.size(); } const std::string &getArgName(unsigned i) const { assert(i < Args.size() && "Argument reference out of range!"); return Args[i]; } std::vector &getArgList() { return Args; } - + CodeGenDAGPatterns &getDAGPatterns() const { return CDP; } /// InlinePatternFragments - If this pattern refers to any pattern @@ -498,20 +506,20 @@ public: for (unsigned i = 0, e = Trees.size(); i != e; ++i) Trees[i] = Trees[i]->InlinePatternFragments(*this); } - + /// InferAllTypes - Infer/propagate as many types throughout the expression /// patterns as possible. Return true if all types are inferred, false /// otherwise. Throw an exception if a type contradiction is found. bool InferAllTypes(const StringMap > *NamedTypes=0); - + /// error - Throw an exception, prefixing it with information about this /// pattern. void error(const std::string &Msg) const; - + void print(raw_ostream &OS) const; void dump() const; - + private: TreePatternNode *ParseTreePattern(Init *DI, StringRef OpName); void ComputeNamedNodes(); @@ -535,7 +543,7 @@ public: const std::vector &results, const std::vector &operands, const std::vector &impresults) - : Pattern(TP), Results(results), Operands(operands), + : Pattern(TP), Results(results), Operands(operands), ImpResults(impresults), ResultPattern(0) {} const TreePattern *getPattern() const { return Pattern; } @@ -543,14 +551,14 @@ public: unsigned getNumOperands() const { return Operands.size(); } unsigned getNumImpResults() const { return ImpResults.size(); } const std::vector& getImpResults() const { return ImpResults; } - + void setResultPattern(TreePatternNode *R) { ResultPattern = R; } - + Record *getResult(unsigned RN) const { assert(RN < Results.size()); return Results[RN]; } - + Record *getOperand(unsigned ON) const { assert(ON < Operands.size()); return Operands[ON]; @@ -560,21 +568,22 @@ public: assert(RN < ImpResults.size()); return ImpResults[RN]; } - + TreePatternNode *getResultPattern() const { return ResultPattern; } }; - + /// PatternToMatch - Used by CodeGenDAGPatterns to keep tab of patterns /// processed to produce isel. class PatternToMatch { public: - PatternToMatch(ListInit *preds, + PatternToMatch(Record *srcrecord, ListInit *preds, TreePatternNode *src, TreePatternNode *dst, const std::vector &dstregs, unsigned complexity, unsigned uid) - : Predicates(preds), SrcPattern(src), DstPattern(dst), + : SrcRecord(srcrecord), Predicates(preds), SrcPattern(src), DstPattern(dst), Dstregs(dstregs), AddedComplexity(complexity), ID(uid) {} + Record *SrcRecord; // Originating Record for the pattern. ListInit *Predicates; // Top level predicate conditions to match. TreePatternNode *SrcPattern; // Source pattern to match. TreePatternNode *DstPattern; // Resulting pattern. @@ -582,6 +591,7 @@ public: unsigned AddedComplexity; // Add to matching pattern complexity. unsigned ID; // Unique ID for the record. + Record *getSrcRecord() const { return SrcRecord; } ListInit *getPredicates() const { return Predicates; } TreePatternNode *getSrcPattern() const { return SrcPattern; } TreePatternNode *getDstPattern() const { return DstPattern; } @@ -589,7 +599,7 @@ public: unsigned getAddedComplexity() const { return AddedComplexity; } std::string getPredicateCheck() const; - + /// Compute the complexity metric for the input pattern. This roughly /// corresponds to the number of nodes that are covered. unsigned getPatternComplexity(const CodeGenDAGPatterns &CGP) const; @@ -599,60 +609,60 @@ public: struct RecordPtrCmp { bool operator()(const Record *LHS, const Record *RHS) const; }; - + class CodeGenDAGPatterns { RecordKeeper &Records; CodeGenTarget Target; std::vector Intrinsics; std::vector TgtIntrinsics; - + std::map SDNodes; std::map, RecordPtrCmp> SDNodeXForms; std::map ComplexPatterns; std::map PatternFragments; std::map DefaultOperands; std::map Instructions; - + // Specific SDNode definitions: Record *intrinsic_void_sdnode; Record *intrinsic_w_chain_sdnode, *intrinsic_wo_chain_sdnode; - + /// PatternsToMatch - All of the things we are matching on the DAG. The first /// value is the pattern to match, the second pattern is the result to /// emit. std::vector PatternsToMatch; public: - CodeGenDAGPatterns(RecordKeeper &R); + CodeGenDAGPatterns(RecordKeeper &R); ~CodeGenDAGPatterns(); - + CodeGenTarget &getTargetInfo() { return Target; } const CodeGenTarget &getTargetInfo() const { return Target; } - + Record *getSDNodeNamed(const std::string &Name) const; - + const SDNodeInfo &getSDNodeInfo(Record *R) const { assert(SDNodes.count(R) && "Unknown node!"); return SDNodes.find(R)->second; } - + // Node transformation lookups. typedef std::pair NodeXForm; const NodeXForm &getSDNodeTransform(Record *R) const { assert(SDNodeXForms.count(R) && "Invalid transform!"); return SDNodeXForms.find(R)->second; } - + typedef std::map::const_iterator nx_iterator; nx_iterator nx_begin() const { return SDNodeXForms.begin(); } nx_iterator nx_end() const { return SDNodeXForms.end(); } - + const ComplexPattern &getComplexPattern(Record *R) const { assert(ComplexPatterns.count(R) && "Unknown addressing mode!"); return ComplexPatterns.find(R)->second; } - + const CodeGenIntrinsic &getIntrinsic(Record *R) const { for (unsigned i = 0, e = Intrinsics.size(); i != e; ++i) if (Intrinsics[i].TheDef == R) return Intrinsics[i]; @@ -661,7 +671,7 @@ public: assert(0 && "Unknown intrinsic!"); abort(); } - + const CodeGenIntrinsic &getIntrinsicInfo(unsigned IID) const { if (IID-1 < Intrinsics.size()) return Intrinsics[IID-1]; @@ -670,7 +680,7 @@ public: assert(0 && "Bad intrinsic ID!"); abort(); } - + unsigned getIntrinsicID(Record *R) const { for (unsigned i = 0, e = Intrinsics.size(); i != e; ++i) if (Intrinsics[i].TheDef == R) return i; @@ -679,12 +689,12 @@ public: assert(0 && "Unknown intrinsic!"); abort(); } - + const DAGDefaultOperand &getDefaultOperand(Record *R) const { assert(DefaultOperands.count(R) &&"Isn't an analyzed default operand!"); return DefaultOperands.find(R)->second; } - + // Pattern Fragment information. TreePattern *getPatternFragment(Record *R) const { assert(PatternFragments.count(R) && "Invalid pattern fragment request!"); @@ -694,7 +704,7 @@ public: if (!PatternFragments.count(R)) return 0; return PatternFragments.find(R)->second; } - + typedef std::map::const_iterator pf_iterator; pf_iterator pf_begin() const { return PatternFragments.begin(); } @@ -704,14 +714,14 @@ public: typedef std::vector::const_iterator ptm_iterator; ptm_iterator ptm_begin() const { return PatternsToMatch.begin(); } ptm_iterator ptm_end() const { return PatternsToMatch.end(); } - - - + + + const DAGInstruction &getInstruction(Record *R) const { assert(Instructions.count(R) && "Unknown instruction!"); return Instructions.find(R)->second; } - + Record *get_intrinsic_void_sdnode() const { return intrinsic_void_sdnode; } @@ -721,7 +731,7 @@ public: Record *get_intrinsic_wo_chain_sdnode() const { return intrinsic_wo_chain_sdnode; } - + bool hasTargetIntrinsics() { return !TgtIntrinsics.empty(); } private: @@ -734,7 +744,7 @@ private: void ParsePatterns(); void InferInstructionFlags(); void GenerateVariants(); - + void AddPatternToMatch(const TreePattern *Pattern, const PatternToMatch &PTM); void FindPatternInputsAndOutputs(TreePattern *I, TreePatternNode *Pat, std::map using namespace llvm; -static void ParseConstraint(const std::string &CStr, CodeGenInstruction *I) { - // EARLY_CLOBBER: @early $reg - std::string::size_type wpos = CStr.find_first_of(" \t"); - std::string::size_type start = CStr.find_first_not_of(" \t"); - std::string Tok = CStr.substr(start, wpos - start); - if (Tok == "@earlyclobber") { - std::string Name = CStr.substr(wpos+1); - wpos = Name.find_first_not_of(" \t"); - if (wpos == std::string::npos) - throw "Illegal format for @earlyclobber constraint: '" + CStr + "'"; - Name = Name.substr(wpos); - std::pair Op = - I->ParseOperandName(Name, false); - - // Build the string for the operand - if (!I->OperandList[Op.first].Constraints[Op.second].isNone()) - throw "Operand '" + Name + "' cannot have multiple constraints!"; - I->OperandList[Op.first].Constraints[Op.second] = - CodeGenInstruction::ConstraintInfo::getEarlyClobber(); - return; - } - - // Only other constraint is "TIED_TO" for now. - std::string::size_type pos = CStr.find_first_of('='); - assert(pos != std::string::npos && "Unrecognized constraint"); - start = CStr.find_first_not_of(" \t"); - std::string Name = CStr.substr(start, pos - start); - - // TIED_TO: $src1 = $dst - wpos = Name.find_first_of(" \t"); - if (wpos == std::string::npos) - throw "Illegal format for tied-to constraint: '" + CStr + "'"; - std::string DestOpName = Name.substr(0, wpos); - std::pair DestOp = I->ParseOperandName(DestOpName, false); - - Name = CStr.substr(pos+1); - wpos = Name.find_first_not_of(" \t"); - if (wpos == std::string::npos) - throw "Illegal format for tied-to constraint: '" + CStr + "'"; - - std::pair SrcOp = - I->ParseOperandName(Name.substr(wpos), false); - if (SrcOp > DestOp) - throw "Illegal tied-to operand constraint '" + CStr + "'"; - - - unsigned FlatOpNo = I->getFlattenedOperandNumber(SrcOp); - - if (!I->OperandList[DestOp.first].Constraints[DestOp.second].isNone()) - throw "Operand '" + DestOpName + "' cannot have multiple constraints!"; - I->OperandList[DestOp.first].Constraints[DestOp.second] = - CodeGenInstruction::ConstraintInfo::getTied(FlatOpNo); -} - -static void ParseConstraints(const std::string &CStr, CodeGenInstruction *I) { - // Make sure the constraints list for each operand is large enough to hold - // constraint info, even if none is present. - for (unsigned i = 0, e = I->OperandList.size(); i != e; ++i) - I->OperandList[i].Constraints.resize(I->OperandList[i].MINumOperands); - - if (CStr.empty()) return; - - const std::string delims(","); - std::string::size_type bidx, eidx; - - bidx = CStr.find_first_not_of(delims); - while (bidx != std::string::npos) { - eidx = CStr.find_first_of(delims, bidx); - if (eidx == std::string::npos) - eidx = CStr.length(); - - ParseConstraint(CStr.substr(bidx, eidx - bidx), I); - bidx = CStr.find_first_not_of(delims, eidx); - } -} - -CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr) - : TheDef(R), AsmString(AsmStr) { - Namespace = R->getValueAsString("Namespace"); +//===----------------------------------------------------------------------===// +// CGIOperandList Implementation +//===----------------------------------------------------------------------===// - isReturn = R->getValueAsBit("isReturn"); - isBranch = R->getValueAsBit("isBranch"); - isIndirectBranch = R->getValueAsBit("isIndirectBranch"); - isCompare = R->getValueAsBit("isCompare"); - isBarrier = R->getValueAsBit("isBarrier"); - isCall = R->getValueAsBit("isCall"); - canFoldAsLoad = R->getValueAsBit("canFoldAsLoad"); - mayLoad = R->getValueAsBit("mayLoad"); - mayStore = R->getValueAsBit("mayStore"); - isPredicable = R->getValueAsBit("isPredicable"); - isConvertibleToThreeAddress = R->getValueAsBit("isConvertibleToThreeAddress"); - isCommutable = R->getValueAsBit("isCommutable"); - isTerminator = R->getValueAsBit("isTerminator"); - isReMaterializable = R->getValueAsBit("isReMaterializable"); - hasDelaySlot = R->getValueAsBit("hasDelaySlot"); - usesCustomInserter = R->getValueAsBit("usesCustomInserter"); - hasCtrlDep = R->getValueAsBit("hasCtrlDep"); - isNotDuplicable = R->getValueAsBit("isNotDuplicable"); - hasSideEffects = R->getValueAsBit("hasSideEffects"); - neverHasSideEffects = R->getValueAsBit("neverHasSideEffects"); - isAsCheapAsAMove = R->getValueAsBit("isAsCheapAsAMove"); - hasExtraSrcRegAllocReq = R->getValueAsBit("hasExtraSrcRegAllocReq"); - hasExtraDefRegAllocReq = R->getValueAsBit("hasExtraDefRegAllocReq"); +CGIOperandList::CGIOperandList(Record *R) : TheDef(R) { + isPredicable = false; hasOptionalDef = false; isVariadic = false; - ImplicitDefs = R->getValueAsListOfDefs("Defs"); - ImplicitUses = R->getValueAsListOfDefs("Uses"); - - if (neverHasSideEffects + hasSideEffects > 1) - throw R->getName() + ": multiple conflicting side-effect flags set!"; DagInit *OutDI = R->getValueAsDag("OutOperandList"); @@ -137,16 +36,16 @@ CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr) throw R->getName() + ": invalid def name for output list: use 'outs'"; } else throw R->getName() + ": invalid output list: use 'outs'"; - + NumDefs = OutDI->getNumArgs(); - + DagInit *InDI = R->getValueAsDag("InOperandList"); if (DefInit *Init = dynamic_cast(InDI->getOperator())) { if (Init->getDef()->getName() != "ins") throw R->getName() + ": invalid def name for input list: use 'ins'"; } else throw R->getName() + ": invalid input list: use 'ins'"; - + unsigned MIOperandNo = 0; std::set OperandNames; for (unsigned i = 0, e = InDI->getNumArgs()+OutDI->getNumArgs(); i != e; ++i){ @@ -159,25 +58,28 @@ CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr) ArgInit = InDI->getArg(i-NumDefs); ArgName = InDI->getArgName(i-NumDefs); } - + DefInit *Arg = dynamic_cast(ArgInit); if (!Arg) throw "Illegal operand for the '" + R->getName() + "' instruction!"; Record *Rec = Arg->getDef(); std::string PrintMethod = "printOperand"; + std::string EncoderMethod; unsigned NumOps = 1; DagInit *MIOpInfo = 0; if (Rec->isSubClassOf("Operand")) { PrintMethod = Rec->getValueAsString("PrintMethod"); + // If there is an explicit encoder method, use it. + EncoderMethod = Rec->getValueAsString("EncoderMethod"); MIOpInfo = Rec->getValueAsDag("MIOperandInfo"); // Verify that MIOpInfo has an 'ops' root value. if (!dynamic_cast(MIOpInfo->getOperator()) || dynamic_cast(MIOpInfo->getOperator()) - ->getDef()->getName() != "ops") + ->getDef()->getName() != "ops") throw "Bad value for MIOperandInfo in operand '" + Rec->getName() + - "'\n"; + "'\n"; // If we have MIOpInfo, then we have #operands equal to number of entries // in MIOperandInfo. @@ -192,58 +94,58 @@ CodeGenInstruction::CodeGenInstruction(Record *R, const std::string &AsmStr) isVariadic = true; continue; } else if (!Rec->isSubClassOf("RegisterClass") && - Rec->getName() != "ptr_rc" && Rec->getName() != "unknown") + !Rec->isSubClassOf("PointerLikeRegClass") && + Rec->getName() != "unknown") throw "Unknown operand class '" + Rec->getName() + - "' in '" + R->getName() + "' instruction!"; + "' in '" + R->getName() + "' instruction!"; // Check that the operand has a name and that it's unique. if (ArgName.empty()) throw "In instruction '" + R->getName() + "', operand #" + utostr(i) + - " has no name!"; + " has no name!"; if (!OperandNames.insert(ArgName).second) throw "In instruction '" + R->getName() + "', operand #" + utostr(i) + - " has the same name as a previous operand!"; + " has the same name as a previous operand!"; - OperandList.push_back(OperandInfo(Rec, ArgName, PrintMethod, + OperandList.push_back(OperandInfo(Rec, ArgName, PrintMethod, EncoderMethod, MIOperandNo, NumOps, MIOpInfo)); MIOperandNo += NumOps; } - // Parse Constraints. - ParseConstraints(R->getValueAsString("Constraints"), this); - - // Parse the DisableEncoding field. - std::string DisableEncoding = R->getValueAsString("DisableEncoding"); - while (1) { - std::string OpName; - tie(OpName, DisableEncoding) = getToken(DisableEncoding, " ,\t"); - if (OpName.empty()) break; - - // Figure out which operand this is. - std::pair Op = ParseOperandName(OpName, false); - // Mark the operand as not-to-be encoded. - if (Op.second >= OperandList[Op.first].DoNotEncode.size()) - OperandList[Op.first].DoNotEncode.resize(Op.second+1); - OperandList[Op.first].DoNotEncode[Op.second] = true; - } + // Make sure the constraints list for each operand is large enough to hold + // constraint info, even if none is present. + for (unsigned i = 0, e = OperandList.size(); i != e; ++i) + OperandList[i].Constraints.resize(OperandList[i].MINumOperands); } + /// getOperandNamed - Return the index of the operand with the specified /// non-empty name. If the instruction does not have an operand with the /// specified name, throw an exception. /// -unsigned CodeGenInstruction::getOperandNamed(const std::string &Name) const { +unsigned CGIOperandList::getOperandNamed(StringRef Name) const { + unsigned OpIdx; + if (hasOperandNamed(Name, OpIdx)) return OpIdx; + throw "'" + TheDef->getName() + "' does not have an operand named '$" + + Name.str() + "'!"; +} + +/// hasOperandNamed - Query whether the instruction has an operand of the +/// given name. If so, return true and set OpIdx to the index of the +/// operand. Otherwise, return false. +bool CGIOperandList::hasOperandNamed(StringRef Name, unsigned &OpIdx) const { assert(!Name.empty() && "Cannot search for operand with no name!"); for (unsigned i = 0, e = OperandList.size(); i != e; ++i) - if (OperandList[i].Name == Name) return i; - throw "Instruction '" + TheDef->getName() + - "' does not have an operand named '$" + Name + "'!"; + if (OperandList[i].Name == Name) { + OpIdx = i; + return true; + } + return false; } std::pair -CodeGenInstruction::ParseOperandName(const std::string &Op, - bool AllowWholeOp) { +CGIOperandList::ParseOperandName(const std::string &Op, bool AllowWholeOp) { if (Op.empty() || Op[0] != '$') throw TheDef->getName() + ": Illegal operand name: '" + Op + "'"; @@ -266,7 +168,7 @@ CodeGenInstruction::ParseOperandName(const std::string &Op, if (OperandList[OpIdx].MINumOperands > 1 && !AllowWholeOp && SubOpName.empty()) throw TheDef->getName() + ": Illegal to refer to" - " whole operand part of complex operand '" + Op + "'"; + " whole operand part of complex operand '" + Op + "'"; // Otherwise, return the operand. return std::make_pair(OpIdx, 0U); @@ -286,6 +188,137 @@ CodeGenInstruction::ParseOperandName(const std::string &Op, throw TheDef->getName() + ": unknown suboperand name in '" + Op + "'"; } +static void ParseConstraint(const std::string &CStr, CGIOperandList &Ops) { + // EARLY_CLOBBER: @early $reg + std::string::size_type wpos = CStr.find_first_of(" \t"); + std::string::size_type start = CStr.find_first_not_of(" \t"); + std::string Tok = CStr.substr(start, wpos - start); + if (Tok == "@earlyclobber") { + std::string Name = CStr.substr(wpos+1); + wpos = Name.find_first_not_of(" \t"); + if (wpos == std::string::npos) + throw "Illegal format for @earlyclobber constraint: '" + CStr + "'"; + Name = Name.substr(wpos); + std::pair Op = Ops.ParseOperandName(Name, false); + + // Build the string for the operand + if (!Ops[Op.first].Constraints[Op.second].isNone()) + throw "Operand '" + Name + "' cannot have multiple constraints!"; + Ops[Op.first].Constraints[Op.second] = + CGIOperandList::ConstraintInfo::getEarlyClobber(); + return; + } + + // Only other constraint is "TIED_TO" for now. + std::string::size_type pos = CStr.find_first_of('='); + assert(pos != std::string::npos && "Unrecognized constraint"); + start = CStr.find_first_not_of(" \t"); + std::string Name = CStr.substr(start, pos - start); + + // TIED_TO: $src1 = $dst + wpos = Name.find_first_of(" \t"); + if (wpos == std::string::npos) + throw "Illegal format for tied-to constraint: '" + CStr + "'"; + std::string DestOpName = Name.substr(0, wpos); + std::pair DestOp = Ops.ParseOperandName(DestOpName, false); + + Name = CStr.substr(pos+1); + wpos = Name.find_first_not_of(" \t"); + if (wpos == std::string::npos) + throw "Illegal format for tied-to constraint: '" + CStr + "'"; + + std::pair SrcOp = + Ops.ParseOperandName(Name.substr(wpos), false); + if (SrcOp > DestOp) + throw "Illegal tied-to operand constraint '" + CStr + "'"; + + + unsigned FlatOpNo = Ops.getFlattenedOperandNumber(SrcOp); + + if (!Ops[DestOp.first].Constraints[DestOp.second].isNone()) + throw "Operand '" + DestOpName + "' cannot have multiple constraints!"; + Ops[DestOp.first].Constraints[DestOp.second] = + CGIOperandList::ConstraintInfo::getTied(FlatOpNo); +} + +static void ParseConstraints(const std::string &CStr, CGIOperandList &Ops) { + if (CStr.empty()) return; + + const std::string delims(","); + std::string::size_type bidx, eidx; + + bidx = CStr.find_first_not_of(delims); + while (bidx != std::string::npos) { + eidx = CStr.find_first_of(delims, bidx); + if (eidx == std::string::npos) + eidx = CStr.length(); + + ParseConstraint(CStr.substr(bidx, eidx - bidx), Ops); + bidx = CStr.find_first_not_of(delims, eidx); + } +} + +void CGIOperandList::ProcessDisableEncoding(std::string DisableEncoding) { + while (1) { + std::string OpName; + tie(OpName, DisableEncoding) = getToken(DisableEncoding, " ,\t"); + if (OpName.empty()) break; + + // Figure out which operand this is. + std::pair Op = ParseOperandName(OpName, false); + + // Mark the operand as not-to-be encoded. + if (Op.second >= OperandList[Op.first].DoNotEncode.size()) + OperandList[Op.first].DoNotEncode.resize(Op.second+1); + OperandList[Op.first].DoNotEncode[Op.second] = true; + } + +} + +//===----------------------------------------------------------------------===// +// CodeGenInstruction Implementation +//===----------------------------------------------------------------------===// + +CodeGenInstruction::CodeGenInstruction(Record *R) : TheDef(R), Operands(R) { + Namespace = R->getValueAsString("Namespace"); + AsmString = R->getValueAsString("AsmString"); + + isReturn = R->getValueAsBit("isReturn"); + isBranch = R->getValueAsBit("isBranch"); + isIndirectBranch = R->getValueAsBit("isIndirectBranch"); + isCompare = R->getValueAsBit("isCompare"); + isMoveImm = R->getValueAsBit("isMoveImm"); + isBarrier = R->getValueAsBit("isBarrier"); + isCall = R->getValueAsBit("isCall"); + canFoldAsLoad = R->getValueAsBit("canFoldAsLoad"); + mayLoad = R->getValueAsBit("mayLoad"); + mayStore = R->getValueAsBit("mayStore"); + isPredicable = Operands.isPredicable || R->getValueAsBit("isPredicable"); + isConvertibleToThreeAddress = R->getValueAsBit("isConvertibleToThreeAddress"); + isCommutable = R->getValueAsBit("isCommutable"); + isTerminator = R->getValueAsBit("isTerminator"); + isReMaterializable = R->getValueAsBit("isReMaterializable"); + hasDelaySlot = R->getValueAsBit("hasDelaySlot"); + usesCustomInserter = R->getValueAsBit("usesCustomInserter"); + hasCtrlDep = R->getValueAsBit("hasCtrlDep"); + isNotDuplicable = R->getValueAsBit("isNotDuplicable"); + hasSideEffects = R->getValueAsBit("hasSideEffects"); + neverHasSideEffects = R->getValueAsBit("neverHasSideEffects"); + isAsCheapAsAMove = R->getValueAsBit("isAsCheapAsAMove"); + hasExtraSrcRegAllocReq = R->getValueAsBit("hasExtraSrcRegAllocReq"); + hasExtraDefRegAllocReq = R->getValueAsBit("hasExtraDefRegAllocReq"); + ImplicitDefs = R->getValueAsListOfDefs("Defs"); + ImplicitUses = R->getValueAsListOfDefs("Uses"); + + if (neverHasSideEffects + hasSideEffects > 1) + throw R->getName() + ": multiple conflicting side-effect flags set!"; + + // Parse Constraints. + ParseConstraints(R->getValueAsString("Constraints"), Operands); + + // Parse the DisableEncoding field. + Operands.ProcessDisableEncoding(R->getValueAsString("DisableEncoding")); +} /// HasOneImplicitDefWithKnownVT - If the instruction has at least one /// implicit def and it has a known VT, return the VT, otherwise return @@ -293,14 +326,212 @@ CodeGenInstruction::ParseOperandName(const std::string &Op, MVT::SimpleValueType CodeGenInstruction:: HasOneImplicitDefWithKnownVT(const CodeGenTarget &TargetInfo) const { if (ImplicitDefs.empty()) return MVT::Other; - + // Check to see if the first implicit def has a resolvable type. Record *FirstImplicitDef = ImplicitDefs[0]; assert(FirstImplicitDef->isSubClassOf("Register")); - const std::vector &RegVTs = + const std::vector &RegVTs = TargetInfo.getRegisterVTs(FirstImplicitDef); if (RegVTs.size() == 1) return RegVTs[0]; return MVT::Other; } + +/// FlattenAsmStringVariants - Flatten the specified AsmString to only +/// include text from the specified variant, returning the new string. +std::string CodeGenInstruction:: +FlattenAsmStringVariants(StringRef Cur, unsigned Variant) { + std::string Res = ""; + + for (;;) { + // Find the start of the next variant string. + size_t VariantsStart = 0; + for (size_t e = Cur.size(); VariantsStart != e; ++VariantsStart) + if (Cur[VariantsStart] == '{' && + (VariantsStart == 0 || (Cur[VariantsStart-1] != '$' && + Cur[VariantsStart-1] != '\\'))) + break; + + // Add the prefix to the result. + Res += Cur.slice(0, VariantsStart); + if (VariantsStart == Cur.size()) + break; + + ++VariantsStart; // Skip the '{'. + + // Scan to the end of the variants string. + size_t VariantsEnd = VariantsStart; + unsigned NestedBraces = 1; + for (size_t e = Cur.size(); VariantsEnd != e; ++VariantsEnd) { + if (Cur[VariantsEnd] == '}' && Cur[VariantsEnd-1] != '\\') { + if (--NestedBraces == 0) + break; + } else if (Cur[VariantsEnd] == '{') + ++NestedBraces; + } + + // Select the Nth variant (or empty). + StringRef Selection = Cur.slice(VariantsStart, VariantsEnd); + for (unsigned i = 0; i != Variant; ++i) + Selection = Selection.split('|').second; + Res += Selection.split('|').first; + + assert(VariantsEnd != Cur.size() && + "Unterminated variants in assembly string!"); + Cur = Cur.substr(VariantsEnd + 1); + } + + return Res; +} + + +//===----------------------------------------------------------------------===// +/// CodeGenInstAlias Implementation +//===----------------------------------------------------------------------===// + +/// tryAliasOpMatch - This is a helper function for the CodeGenInstAlias +/// constructor. It checks if an argument in an InstAlias pattern matches +/// the corresponding operand of the instruction. It returns true on a +/// successful match, with ResOp set to the result operand to be used. +bool CodeGenInstAlias::tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo, + Record *InstOpRec, bool hasSubOps, + SMLoc Loc, CodeGenTarget &T, + ResultOperand &ResOp) { + Init *Arg = Result->getArg(AliasOpNo); + DefInit *ADI = dynamic_cast(Arg); + + if (ADI && ADI->getDef() == InstOpRec) { + // If the operand is a record, it must have a name, and the record type + // must match up with the instruction's argument type. + if (Result->getArgName(AliasOpNo).empty()) + throw TGError(Loc, "result argument #" + utostr(AliasOpNo) + + " must have a name!"); + ResOp = ResultOperand(Result->getArgName(AliasOpNo), ADI->getDef()); + return true; + } + + // Handle explicit registers. + if (ADI && ADI->getDef()->isSubClassOf("Register")) { + if (!InstOpRec->isSubClassOf("RegisterClass")) + return false; + + if (!T.getRegisterClass(InstOpRec).containsRegister(ADI->getDef())) + throw TGError(Loc, "fixed register " +ADI->getDef()->getName() + + " is not a member of the " + InstOpRec->getName() + + " register class!"); + + if (!Result->getArgName(AliasOpNo).empty()) + throw TGError(Loc, "result fixed register argument must " + "not have a name!"); + + ResOp = ResultOperand(ADI->getDef()); + return true; + } + + // Handle "zero_reg" for optional def operands. + if (ADI && ADI->getDef()->getName() == "zero_reg") { + + // Check if this is an optional def. + if (!InstOpRec->isSubClassOf("OptionalDefOperand")) + throw TGError(Loc, "reg0 used for result that is not an " + "OptionalDefOperand!"); + + ResOp = ResultOperand(static_cast(0)); + return true; + } + + if (IntInit *II = dynamic_cast(Arg)) { + if (hasSubOps || !InstOpRec->isSubClassOf("Operand")) + return false; + // Integer arguments can't have names. + if (!Result->getArgName(AliasOpNo).empty()) + throw TGError(Loc, "result argument #" + utostr(AliasOpNo) + + " must not have a name!"); + ResOp = ResultOperand(II->getValue()); + return true; + } + + return false; +} + +CodeGenInstAlias::CodeGenInstAlias(Record *R, CodeGenTarget &T) : TheDef(R) { + AsmString = R->getValueAsString("AsmString"); + Result = R->getValueAsDag("ResultInst"); + + // Verify that the root of the result is an instruction. + DefInit *DI = dynamic_cast(Result->getOperator()); + if (DI == 0 || !DI->getDef()->isSubClassOf("Instruction")) + throw TGError(R->getLoc(), "result of inst alias should be an instruction"); + + ResultInst = &T.getInstruction(DI->getDef()); + + // NameClass - If argument names are repeated, we need to verify they have + // the same class. + StringMap NameClass; + for (unsigned i = 0, e = Result->getNumArgs(); i != e; ++i) { + DefInit *ADI = dynamic_cast(Result->getArg(i)); + if (!ADI || Result->getArgName(i).empty()) + continue; + // Verify we don't have something like: (someinst GR16:$foo, GR32:$foo) + // $foo can exist multiple times in the result list, but it must have the + // same type. + Record *&Entry = NameClass[Result->getArgName(i)]; + if (Entry && Entry != ADI->getDef()) + throw TGError(R->getLoc(), "result value $" + Result->getArgName(i) + + " is both " + Entry->getName() + " and " + + ADI->getDef()->getName() + "!"); + Entry = ADI->getDef(); + } + + // Decode and validate the arguments of the result. + unsigned AliasOpNo = 0; + for (unsigned i = 0, e = ResultInst->Operands.size(); i != e; ++i) { + + // Tied registers don't have an entry in the result dag. + if (ResultInst->Operands[i].getTiedRegister() != -1) + continue; + + if (AliasOpNo >= Result->getNumArgs()) + throw TGError(R->getLoc(), "not enough arguments for instruction!"); + + Record *InstOpRec = ResultInst->Operands[i].Rec; + unsigned NumSubOps = ResultInst->Operands[i].MINumOperands; + ResultOperand ResOp(static_cast(0)); + if (tryAliasOpMatch(Result, AliasOpNo, InstOpRec, (NumSubOps > 1), + R->getLoc(), T, ResOp)) { + ResultOperands.push_back(ResOp); + ResultInstOperandIndex.push_back(std::make_pair(i, -1)); + ++AliasOpNo; + continue; + } + + // If the argument did not match the instruction operand, and the operand + // is composed of multiple suboperands, try matching the suboperands. + if (NumSubOps > 1) { + DagInit *MIOI = ResultInst->Operands[i].MIOperandInfo; + for (unsigned SubOp = 0; SubOp != NumSubOps; ++SubOp) { + if (AliasOpNo >= Result->getNumArgs()) + throw TGError(R->getLoc(), "not enough arguments for instruction!"); + Record *SubRec = dynamic_cast(MIOI->getArg(SubOp))->getDef(); + if (tryAliasOpMatch(Result, AliasOpNo, SubRec, false, + R->getLoc(), T, ResOp)) { + ResultOperands.push_back(ResOp); + ResultInstOperandIndex.push_back(std::make_pair(i, SubOp)); + ++AliasOpNo; + } else { + throw TGError(R->getLoc(), "result argument #" + utostr(AliasOpNo) + + " does not match instruction operand class " + + (SubOp == 0 ? InstOpRec->getName() :SubRec->getName())); + } + } + continue; + } + throw TGError(R->getLoc(), "result argument #" + utostr(AliasOpNo) + + " does not match instruction operand class " + + InstOpRec->getName()); + } + + if (AliasOpNo != Result->getNumArgs()) + throw TGError(R->getLoc(), "too many operands for instruction!"); +} diff --git a/utils/TableGen/CodeGenInstruction.h b/utils/TableGen/CodeGenInstruction.h index b02d0d38f975..58913b9da26b 100644 --- a/utils/TableGen/CodeGenInstruction.h +++ b/utils/TableGen/CodeGenInstruction.h @@ -15,6 +15,8 @@ #define CODEGEN_INSTRUCTION_H #include "llvm/CodeGen/ValueTypes.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/SourceMgr.h" #include #include #include @@ -23,22 +25,16 @@ namespace llvm { class Record; class DagInit; class CodeGenTarget; - - class CodeGenInstruction { + class StringRef; + + class CGIOperandList { public: - Record *TheDef; // The actual record defining this instruction. - std::string Namespace; // The namespace the instruction is in. - - /// AsmString - The format string used to emit a .s file for the - /// instruction. - std::string AsmString; - class ConstraintInfo { enum { None, EarlyClobber, Tied } Kind; unsigned OtherTiedOperand; public: ConstraintInfo() : Kind(None) {} - + static ConstraintInfo getEarlyClobber() { ConstraintInfo I; I.Kind = EarlyClobber; @@ -62,22 +58,26 @@ namespace llvm { return OtherTiedOperand; } }; - + /// OperandInfo - The information we keep track of for each operand in the /// operand list for a tablegen instruction. struct OperandInfo { /// Rec - The definition this operand is declared as. /// Record *Rec; - + /// Name - If this operand was assigned a symbolic name, this is it, /// otherwise, it's empty. std::string Name; - + /// PrinterMethodName - The method used to print operands of this type in /// the asmprinter. std::string PrinterMethodName; - + + /// EncoderMethodName - The method used to get the machine operand value + /// for binary encoding. "getMachineOpValue" by default. + std::string EncoderMethodName; + /// MIOperandNo - Currently (this is meant to be phased out), some logical /// operands correspond to multiple MachineInstr operands. In the X86 /// target for example, one address operand is represented as 4 @@ -86,7 +86,7 @@ namespace llvm { /// does, this contains the MI operand index of this operand. unsigned MIOperandNo; unsigned MINumOperands; // The number of operands. - + /// DoNotEncode - Bools are set to true in this vector for each operand in /// the DisableEncoding list. These should not be emitted by the code /// emitter. @@ -99,52 +99,61 @@ namespace llvm { /// Constraint info for this operand. This operand can have pieces, so we /// track constraint info for each. std::vector Constraints; - - OperandInfo(Record *R, const std::string &N, const std::string &PMN, - unsigned MION, unsigned MINO, DagInit *MIOI) - : Rec(R), Name(N), PrinterMethodName(PMN), MIOperandNo(MION), - MINumOperands(MINO), MIOperandInfo(MIOI) {} + + OperandInfo(Record *R, const std::string &N, const std::string &PMN, + const std::string &EMN, unsigned MION, unsigned MINO, + DagInit *MIOI) + : Rec(R), Name(N), PrinterMethodName(PMN), EncoderMethodName(EMN), + MIOperandNo(MION), MINumOperands(MINO), MIOperandInfo(MIOI) {} + + + /// getTiedOperand - If this operand is tied to another one, return the + /// other operand number. Otherwise, return -1. + int getTiedRegister() const { + for (unsigned j = 0, e = Constraints.size(); j != e; ++j) { + const CGIOperandList::ConstraintInfo &CI = Constraints[j]; + if (CI.isTied()) return CI.getTiedOperand(); + } + return -1; + } }; + + CGIOperandList(Record *D); + + Record *TheDef; // The actual record containing this OperandList. /// NumDefs - Number of def operands declared, this is the number of /// elements in the instruction's (outs) list. /// unsigned NumDefs; - + /// OperandList - The list of declared operands, along with their declared /// type (which is a record). std::vector OperandList; - - /// ImplicitDefs/ImplicitUses - These are lists of registers that are - /// implicitly defined and used by the instruction. - std::vector ImplicitDefs, ImplicitUses; - - // Various boolean values we track for the instruction. - bool isReturn; - bool isBranch; - bool isIndirectBranch; - bool isCompare; - bool isBarrier; - bool isCall; - bool canFoldAsLoad; - bool mayLoad, mayStore; + + // Information gleaned from the operand list. bool isPredicable; - bool isConvertibleToThreeAddress; - bool isCommutable; - bool isTerminator; - bool isReMaterializable; - bool hasDelaySlot; - bool usesCustomInserter; - bool isVariadic; - bool hasCtrlDep; - bool isNotDuplicable; bool hasOptionalDef; - bool hasSideEffects; - bool neverHasSideEffects; - bool isAsCheapAsAMove; - bool hasExtraSrcRegAllocReq; - bool hasExtraDefRegAllocReq; + bool isVariadic; + + // Provide transparent accessors to the operand list. + unsigned size() const { return OperandList.size(); } + const OperandInfo &operator[](unsigned i) const { return OperandList[i]; } + OperandInfo &operator[](unsigned i) { return OperandList[i]; } + OperandInfo &back() { return OperandList.back(); } + const OperandInfo &back() const { return OperandList.back(); } + + + /// getOperandNamed - Return the index of the operand with the specified + /// non-empty name. If the instruction does not have an operand with the + /// specified name, throw an exception. + unsigned getOperandNamed(StringRef Name) const; + /// hasOperandNamed - Query whether the instruction has an operand of the + /// given name. If so, return true and set OpIdx to the index of the + /// operand. Otherwise, return false. + bool hasOperandNamed(StringRef Name, unsigned &OpIdx) const; + /// ParseOperandName - Parse an operand name like "$foo" or "$foo.bar", /// where $foo is a whole operand and $foo.bar refers to a suboperand. /// This throws an exception if the name is invalid. If AllowWholeOp is @@ -178,20 +187,130 @@ namespace llvm { return OperandList[Op.first].DoNotEncode[Op.second]; return false; } + + void ProcessDisableEncoding(std::string Value); + }; + - CodeGenInstruction(Record *R, const std::string &AsmStr); + class CodeGenInstruction { + public: + Record *TheDef; // The actual record defining this instruction. + std::string Namespace; // The namespace the instruction is in. + + /// AsmString - The format string used to emit a .s file for the + /// instruction. + std::string AsmString; + + /// Operands - This is information about the (ins) and (outs) list specified + /// to the instruction. + CGIOperandList Operands; + + /// ImplicitDefs/ImplicitUses - These are lists of registers that are + /// implicitly defined and used by the instruction. + std::vector ImplicitDefs, ImplicitUses; + + // Various boolean values we track for the instruction. + bool isReturn; + bool isBranch; + bool isIndirectBranch; + bool isCompare; + bool isMoveImm; + bool isBarrier; + bool isCall; + bool canFoldAsLoad; + bool mayLoad, mayStore; + bool isPredicable; + bool isConvertibleToThreeAddress; + bool isCommutable; + bool isTerminator; + bool isReMaterializable; + bool hasDelaySlot; + bool usesCustomInserter; + bool hasCtrlDep; + bool isNotDuplicable; + bool hasSideEffects; + bool neverHasSideEffects; + bool isAsCheapAsAMove; + bool hasExtraSrcRegAllocReq; + bool hasExtraDefRegAllocReq; + + + CodeGenInstruction(Record *R); - /// getOperandNamed - Return the index of the operand with the specified - /// non-empty name. If the instruction does not have an operand with the - /// specified name, throw an exception. - unsigned getOperandNamed(const std::string &Name) const; - /// HasOneImplicitDefWithKnownVT - If the instruction has at least one /// implicit def and it has a known VT, return the VT, otherwise return /// MVT::Other. - MVT::SimpleValueType + MVT::SimpleValueType HasOneImplicitDefWithKnownVT(const CodeGenTarget &TargetInfo) const; + + + /// FlattenAsmStringVariants - Flatten the specified AsmString to only + /// include text from the specified variant, returning the new string. + static std::string FlattenAsmStringVariants(StringRef AsmString, + unsigned Variant); }; + + + /// CodeGenInstAlias - This represents an InstAlias definition. + class CodeGenInstAlias { + public: + Record *TheDef; // The actual record defining this InstAlias. + + /// AsmString - The format string used to emit a .s file for the + /// instruction. + std::string AsmString; + + /// Result - The result instruction. + DagInit *Result; + + /// ResultInst - The instruction generated by the alias (decoded from + /// Result). + CodeGenInstruction *ResultInst; + + + struct ResultOperand { + private: + StringRef Name; + Record *R; + + int64_t Imm; + public: + enum { + K_Record, + K_Imm, + K_Reg + } Kind; + + ResultOperand(StringRef N, Record *r) : Name(N), R(r), Kind(K_Record) {} + ResultOperand(int64_t I) : Imm(I), Kind(K_Imm) {} + ResultOperand(Record *r) : R(r), Kind(K_Reg) {} + + bool isRecord() const { return Kind == K_Record; } + bool isImm() const { return Kind == K_Imm; } + bool isReg() const { return Kind == K_Reg; } + + StringRef getName() const { assert(isRecord()); return Name; } + Record *getRecord() const { assert(isRecord()); return R; } + int64_t getImm() const { assert(isImm()); return Imm; } + Record *getRegister() const { assert(isReg()); return R; } + }; + + /// ResultOperands - The decoded operands for the result instruction. + std::vector ResultOperands; + + /// ResultInstOperandIndex - For each operand, this vector holds a pair of + /// indices to identify the corresponding operand in the result + /// instruction. The first index specifies the operand and the second + /// index specifies the suboperand. If there are no suboperands or if all + /// of them are matched by the operand, the second value should be -1. + std::vector > ResultInstOperandIndex; + + CodeGenInstAlias(Record *R, CodeGenTarget &T); + + bool tryAliasOpMatch(DagInit *Result, unsigned AliasOpNo, + Record *InstOpRec, bool hasSubOps, SMLoc Loc, + CodeGenTarget &T, ResultOperand &ResOp); + }; } #endif diff --git a/utils/TableGen/CodeGenRegisters.h b/utils/TableGen/CodeGenRegisters.h index ccd3d222bbad..bbd0cefa5804 100644 --- a/utils/TableGen/CodeGenRegisters.h +++ b/utils/TableGen/CodeGenRegisters.h @@ -57,6 +57,12 @@ namespace llvm { abort(); } + bool containsRegister(Record *R) const { + for (unsigned i = 0, e = Elements.size(); i != e; ++i) + if (Elements[i] == R) return true; + return false; + } + // Returns true if RC is a strict subclass. // RC is a sub-class of this class if it is a valid replacement for any // instruction operand where a register of this classis required. It must diff --git a/utils/TableGen/CodeGenTarget.cpp b/utils/TableGen/CodeGenTarget.cpp index cbfe2addbf2b..d0f7d8b44079 100644 --- a/utils/TableGen/CodeGenTarget.cpp +++ b/utils/TableGen/CodeGenTarget.cpp @@ -48,46 +48,47 @@ std::string llvm::getName(MVT::SimpleValueType T) { std::string llvm::getEnumName(MVT::SimpleValueType T) { switch (T) { - case MVT::Other: return "MVT::Other"; - case MVT::i1: return "MVT::i1"; - case MVT::i8: return "MVT::i8"; - case MVT::i16: return "MVT::i16"; - case MVT::i32: return "MVT::i32"; - case MVT::i64: return "MVT::i64"; - case MVT::i128: return "MVT::i128"; - case MVT::iAny: return "MVT::iAny"; - case MVT::fAny: return "MVT::fAny"; - case MVT::vAny: return "MVT::vAny"; - case MVT::f32: return "MVT::f32"; - case MVT::f64: return "MVT::f64"; - case MVT::f80: return "MVT::f80"; - case MVT::f128: return "MVT::f128"; + case MVT::Other: return "MVT::Other"; + case MVT::i1: return "MVT::i1"; + case MVT::i8: return "MVT::i8"; + case MVT::i16: return "MVT::i16"; + case MVT::i32: return "MVT::i32"; + case MVT::i64: return "MVT::i64"; + case MVT::i128: return "MVT::i128"; + case MVT::iAny: return "MVT::iAny"; + case MVT::fAny: return "MVT::fAny"; + case MVT::vAny: return "MVT::vAny"; + case MVT::f32: return "MVT::f32"; + case MVT::f64: return "MVT::f64"; + case MVT::f80: return "MVT::f80"; + case MVT::f128: return "MVT::f128"; case MVT::ppcf128: return "MVT::ppcf128"; - case MVT::Flag: return "MVT::Flag"; - case MVT::isVoid:return "MVT::isVoid"; - case MVT::v2i8: return "MVT::v2i8"; - case MVT::v4i8: return "MVT::v4i8"; - case MVT::v8i8: return "MVT::v8i8"; - case MVT::v16i8: return "MVT::v16i8"; - case MVT::v32i8: return "MVT::v32i8"; - case MVT::v2i16: return "MVT::v2i16"; - case MVT::v4i16: return "MVT::v4i16"; - case MVT::v8i16: return "MVT::v8i16"; - case MVT::v16i16: return "MVT::v16i16"; - case MVT::v2i32: return "MVT::v2i32"; - case MVT::v4i32: return "MVT::v4i32"; - case MVT::v8i32: return "MVT::v8i32"; - case MVT::v1i64: return "MVT::v1i64"; - case MVT::v2i64: return "MVT::v2i64"; - case MVT::v4i64: return "MVT::v4i64"; - case MVT::v8i64: return "MVT::v8i64"; - case MVT::v2f32: return "MVT::v2f32"; - case MVT::v4f32: return "MVT::v4f32"; - case MVT::v8f32: return "MVT::v8f32"; - case MVT::v2f64: return "MVT::v2f64"; - case MVT::v4f64: return "MVT::v4f64"; + case MVT::x86mmx: return "MVT::x86mmx"; + case MVT::Glue: return "MVT::Glue"; + case MVT::isVoid: return "MVT::isVoid"; + case MVT::v2i8: return "MVT::v2i8"; + case MVT::v4i8: return "MVT::v4i8"; + case MVT::v8i8: return "MVT::v8i8"; + case MVT::v16i8: return "MVT::v16i8"; + case MVT::v32i8: return "MVT::v32i8"; + case MVT::v2i16: return "MVT::v2i16"; + case MVT::v4i16: return "MVT::v4i16"; + case MVT::v8i16: return "MVT::v8i16"; + case MVT::v16i16: return "MVT::v16i16"; + case MVT::v2i32: return "MVT::v2i32"; + case MVT::v4i32: return "MVT::v4i32"; + case MVT::v8i32: return "MVT::v8i32"; + case MVT::v1i64: return "MVT::v1i64"; + case MVT::v2i64: return "MVT::v2i64"; + case MVT::v4i64: return "MVT::v4i64"; + case MVT::v8i64: return "MVT::v8i64"; + case MVT::v2f32: return "MVT::v2f32"; + case MVT::v4f32: return "MVT::v4f32"; + case MVT::v8f32: return "MVT::v8f32"; + case MVT::v2f64: return "MVT::v2f64"; + case MVT::v4f64: return "MVT::v4f64"; case MVT::Metadata: return "MVT::Metadata"; - case MVT::iPTR: return "MVT::iPTR"; + case MVT::iPTR: return "MVT::iPTR"; case MVT::iPTRAny: return "MVT::iPTRAny"; default: assert(0 && "ILLEGAL VALUE TYPE!"); return ""; } @@ -107,7 +108,7 @@ std::string llvm::getQualifiedName(const Record *R) { /// getTarget - Return the current instance of the Target class. /// -CodeGenTarget::CodeGenTarget() { +CodeGenTarget::CodeGenTarget(RecordKeeper &records) : Records(records) { std::vector Targets = Records.getAllDerivedDefinitions("Target"); if (Targets.size() == 0) throw std::string("ERROR: No 'Target' subclasses defined!"); @@ -189,6 +190,19 @@ void CodeGenTarget::ReadRegisterClasses() const { RegisterClasses.assign(RegClasses.begin(), RegClasses.end()); } +/// getRegisterByName - If there is a register with the specific AsmName, +/// return it. +const CodeGenRegister *CodeGenTarget::getRegisterByName(StringRef Name) const { + const std::vector &Regs = getRegisters(); + for (unsigned i = 0, e = Regs.size(); i != e; ++i) { + const CodeGenRegister &Reg = Regs[i]; + if (Reg.TheDef->getValueAsString("AsmName") == Name) + return &Reg; + } + + return 0; +} + std::vector CodeGenTarget:: getRegisterVTs(Record *R) const { std::vector Result; @@ -294,18 +308,14 @@ void CodeGenTarget::ReadInstructions() const { throw std::string("No 'Instruction' subclasses defined!"); // Parse the instructions defined in the .td file. - std::string InstFormatName = - getAsmWriter()->getValueAsString("InstFormatName"); - - for (unsigned i = 0, e = Insts.size(); i != e; ++i) { - std::string AsmStr = Insts[i]->getValueAsString(InstFormatName); - Instructions[Insts[i]] = new CodeGenInstruction(Insts[i], AsmStr); - } + for (unsigned i = 0, e = Insts.size(); i != e; ++i) + Instructions[Insts[i]] = new CodeGenInstruction(Insts[i]); } static const CodeGenInstruction * GetInstByName(const char *Name, - const DenseMap &Insts) { + const DenseMap &Insts, + RecordKeeper &Records) { const Record *Rec = Records.getDef(Name); DenseMap::const_iterator @@ -349,7 +359,7 @@ void CodeGenTarget::ComputeInstrsByEnum() const { }; const DenseMap &Insts = getInstructions(); for (const char *const *p = FixedInstrs; *p; ++p) { - const CodeGenInstruction *Instr = GetInstByName(*p, Insts); + const CodeGenInstruction *Instr = GetInstByName(*p, Insts, Records); assert(Instr && "Missing target independent instruction"); assert(Instr->Namespace == "TargetOpcode" && "Bad namespace"); InstrsByEnum.push_back(Instr); @@ -394,8 +404,8 @@ ComplexPattern::ComplexPattern(Record *R) { for (unsigned i = 0, e = PropList.size(); i != e; ++i) if (PropList[i]->getName() == "SDNPHasChain") { Properties |= 1 << SDNPHasChain; - } else if (PropList[i]->getName() == "SDNPOptInFlag") { - Properties |= 1 << SDNPOptInFlag; + } else if (PropList[i]->getName() == "SDNPOptInGlue") { + Properties |= 1 << SDNPOptInGlue; } else if (PropList[i]->getName() == "SDNPMayStore") { Properties |= 1 << SDNPMayStore; } else if (PropList[i]->getName() == "SDNPMayLoad") { @@ -406,6 +416,10 @@ ComplexPattern::ComplexPattern(Record *R) { Properties |= 1 << SDNPMemOperand; } else if (PropList[i]->getName() == "SDNPVariadic") { Properties |= 1 << SDNPVariadic; + } else if (PropList[i]->getName() == "SDNPWantRoot") { + Properties |= 1 << SDNPWantRoot; + } else if (PropList[i]->getName() == "SDNPWantParent") { + Properties |= 1 << SDNPWantParent; } else { errs() << "Unsupported SD Node property '" << PropList[i]->getName() << "' on ComplexPattern '" << R->getName() << "'!\n"; diff --git a/utils/TableGen/CodeGenTarget.h b/utils/TableGen/CodeGenTarget.h index 6b06b66c29bc..f1058eb63181 100644 --- a/utils/TableGen/CodeGenTarget.h +++ b/utils/TableGen/CodeGenTarget.h @@ -35,14 +35,16 @@ enum SDNP { SDNPCommutative, SDNPAssociative, SDNPHasChain, - SDNPOutFlag, - SDNPInFlag, - SDNPOptInFlag, + SDNPOutGlue, + SDNPInGlue, + SDNPOptInGlue, SDNPMayLoad, SDNPMayStore, SDNPSideEffect, SDNPMemOperand, - SDNPVariadic + SDNPVariadic, + SDNPWantRoot, + SDNPWantParent }; /// getValueType - Return the MVT::SimpleValueType that the specified TableGen @@ -59,6 +61,7 @@ std::string getQualifiedName(const Record *R); /// CodeGenTarget - This class corresponds to the Target class in the .td files. /// class CodeGenTarget { + RecordKeeper &Records; Record *TargetRec; mutable DenseMap Instructions; @@ -74,7 +77,7 @@ class CodeGenTarget { mutable std::vector InstrsByEnum; public: - CodeGenTarget(); + CodeGenTarget(RecordKeeper &Records); Record *getTargetRecord() const { return TargetRec; } const std::string &getName() const; @@ -99,6 +102,10 @@ public: if (Registers.empty()) ReadRegisters(); return Registers; } + + /// getRegisterByName - If there is a register with the specific AsmName, + /// return it. + const CodeGenRegister *getRegisterByName(StringRef Name) const; const std::vector &getSubRegIndices() const { if (SubRegIndices.empty()) ReadSubRegIndices(); diff --git a/utils/TableGen/DAGISelMatcher.cpp b/utils/TableGen/DAGISelMatcher.cpp index 9f12a686e4cf..2afa2b907bc4 100644 --- a/utils/TableGen/DAGISelMatcher.cpp +++ b/utils/TableGen/DAGISelMatcher.cpp @@ -35,7 +35,7 @@ void Matcher::printOne(raw_ostream &OS) const { Matcher *Matcher::unlinkNode(Matcher *Other) { if (this == Other) return takeNext(); - + // Scan until we find the predecessor of Other. Matcher *Cur = this; for (; Cur && Cur->getNext() != Other; Cur = Cur->getNext()) @@ -67,11 +67,11 @@ bool Matcher::canMoveBeforeNode(const Matcher *Other) const { // We can move simple predicates before record nodes. if (isSimplePredicateNode()) return Other->isSimplePredicateOrRecordNode(); - + // We can move record nodes across simple predicates. if (isSimplePredicateOrRecordNode()) return isSimplePredicateNode(); - + // We can't move record nodes across each other etc. return false; } @@ -107,8 +107,8 @@ void RecordMemRefMatcher::printImpl(raw_ostream &OS, unsigned indent) const { OS.indent(indent) << "RecordMemRef\n"; } -void CaptureFlagInputMatcher::printImpl(raw_ostream &OS, unsigned indent) const{ - OS.indent(indent) << "CaptureFlagInput\n"; +void CaptureGlueInputMatcher::printImpl(raw_ostream &OS, unsigned indent) const{ + OS.indent(indent) << "CaptureGlueInput\n"; } void MoveChildMatcher::printImpl(raw_ostream &OS, unsigned indent) const { @@ -246,8 +246,8 @@ void EmitNodeMatcherCommon::printImpl(raw_ostream &OS, unsigned indent) const { OS << ")\n"; } -void MarkFlagResultsMatcher::printImpl(raw_ostream &OS, unsigned indent) const { - OS.indent(indent) << "MarkFlagResults \n"; +void MarkGlueResultsMatcher::printImpl(raw_ostream &OS, unsigned indent) const { + OS.indent(indent) << "MarkGlueResults \n"; } void CompleteMatchMatcher::printImpl(raw_ostream &OS, unsigned indent) const { @@ -296,7 +296,7 @@ unsigned EmitMergeInputChainsMatcher::getHashImpl() const { bool CheckOpcodeMatcher::isEqualImpl(const Matcher *M) const { // Note: pointer equality isn't enough here, we have to check the enum names - // to ensure that the nodes are for the same opcode. + // to ensure that the nodes are for the same opcode. return cast(M)->Opcode.getEnumName() == Opcode.getEnumName(); } @@ -306,7 +306,7 @@ bool EmitNodeMatcherCommon::isEqualImpl(const Matcher *m) const { const EmitNodeMatcherCommon *M = cast(m); return M->OpcodeName == OpcodeName && M->VTs == VTs && M->Operands == Operands && M->HasChain == HasChain && - M->HasInFlag == HasInFlag && M->HasOutFlag == HasOutFlag && + M->HasInGlue == HasInGlue && M->HasOutGlue == HasOutGlue && M->HasMemRefs == HasMemRefs && M->NumFixedArityOperands == NumFixedArityOperands; } @@ -316,12 +316,12 @@ unsigned EmitNodeMatcherCommon::getHashImpl() const { } -unsigned MarkFlagResultsMatcher::getHashImpl() const { - return HashUnsigneds(FlagResultNodes.begin(), FlagResultNodes.end()); +unsigned MarkGlueResultsMatcher::getHashImpl() const { + return HashUnsigneds(GlueResultNodes.begin(), GlueResultNodes.end()); } unsigned CompleteMatchMatcher::getHashImpl() const { - return HashUnsigneds(Results.begin(), Results.end()) ^ + return HashUnsigneds(Results.begin(), Results.end()) ^ ((unsigned)(intptr_t)&Pattern << 8); } @@ -332,15 +332,15 @@ static bool TypesAreContradictory(MVT::SimpleValueType T1, // If the two types are the same, then they are the same, so they don't // contradict. if (T1 == T2) return false; - + // If either type is about iPtr, then they don't conflict unless the other // one is not a scalar integer type. if (T1 == MVT::iPTR) return !MVT(T2).isInteger() || MVT(T2).isVector(); - + if (T2 == MVT::iPTR) return !MVT(T1).isInteger() || MVT(T1).isVector(); - + // Otherwise, they are two different non-iPTR types, they conflict. return true; } @@ -349,10 +349,10 @@ bool CheckOpcodeMatcher::isContradictoryImpl(const Matcher *M) const { if (const CheckOpcodeMatcher *COM = dyn_cast(M)) { // One node can't have two different opcodes! // Note: pointer equality isn't enough here, we have to check the enum names - // to ensure that the nodes are for the same opcode. + // to ensure that the nodes are for the same opcode. return COM->getOpcode().getEnumName() != getOpcode().getEnumName(); } - + // If the node has a known type, and if the type we're checking for is // different, then we know they contradict. For example, a check for // ISD::STORE will never be true at the same time a check for Type i32 is. @@ -360,12 +360,12 @@ bool CheckOpcodeMatcher::isContradictoryImpl(const Matcher *M) const { // If checking for a result the opcode doesn't have, it can't match. if (CT->getResNo() >= getOpcode().getNumResults()) return true; - + MVT::SimpleValueType NodeType = getOpcode().getKnownType(CT->getResNo()); if (NodeType != MVT::Other) return TypesAreContradictory(NodeType, CT->getType()); } - + return false; } @@ -381,12 +381,12 @@ bool CheckChildTypeMatcher::isContradictoryImpl(const Matcher *M) const { // conflict! if (CC->getChildNo() != getChildNo()) return false; - + return TypesAreContradictory(getType(), CC->getType()); } return false; } - + bool CheckIntegerMatcher::isContradictoryImpl(const Matcher *M) const { if (const CheckIntegerMatcher *CIM = dyn_cast(M)) return CIM->getValue() != getValue(); diff --git a/utils/TableGen/DAGISelMatcher.h b/utils/TableGen/DAGISelMatcher.h index d9b25d556430..8e6e44647ea1 100644 --- a/utils/TableGen/DAGISelMatcher.h +++ b/utils/TableGen/DAGISelMatcher.h @@ -31,7 +31,7 @@ Matcher *OptimizeMatcher(Matcher *Matcher, const CodeGenDAGPatterns &CGP); void EmitMatcherTable(const Matcher *Matcher, const CodeGenDAGPatterns &CGP, raw_ostream &OS); - + /// Matcher - Base class for all the the DAG ISel Matcher representation /// nodes. class Matcher { @@ -45,10 +45,10 @@ public: RecordNode, // Record the current node. RecordChild, // Record a child of the current node. RecordMemRef, // Record the memref in the current node. - CaptureFlagInput, // If the current node has an input flag, save it. + CaptureGlueInput, // If the current node has an input glue, save it. MoveChild, // Move current node to specified child. MoveParent, // Move current node to parent. - + // Predicate checking. CheckSame, // Fail if not same as prev match. CheckPatternPredicate, @@ -65,7 +65,7 @@ public: CheckAndImm, CheckOrImm, CheckFoldableChainNode, - + // Node creation/emisssion. EmitInteger, // Create a TargetConstant EmitStringInteger, // Create a TargetConstant from a string. @@ -75,7 +75,7 @@ public: EmitCopyToReg, // Emit a copytoreg into a physreg. EmitNode, // Create a DAG node EmitNodeXForm, // Run a SDNodeXForm - MarkFlagResults, // Indicate which interior nodes have flag results. + MarkGlueResults, // Indicate which interior nodes have glue results. CompleteMatch, // Finish a match and update the results. MorphNodeTo // Build a node, finish a match and update results. }; @@ -85,7 +85,7 @@ protected: Matcher(KindTy K) : Kind(K) {} public: virtual ~Matcher() {} - + KindTy getKind() const { return Kind; } Matcher *getNext() { return Next.get(); } @@ -94,25 +94,25 @@ public: Matcher *takeNext() { return Next.take(); } OwningPtr &getNextPtr() { return Next; } - + static inline bool classof(const Matcher *) { return true; } - + bool isEqual(const Matcher *M) const { if (getKind() != M->getKind()) return false; return isEqualImpl(M); } - + unsigned getHash() const { // Clear the high bit so we don't conflict with tombstones etc. return ((getHashImpl() << 4) ^ getKind()) & (~0U>>1); } - + /// isSafeToReorderWithPatternPredicate - Return true if it is safe to sink a /// PatternPredicate node past this one. virtual bool isSafeToReorderWithPatternPredicate() const { return false; } - + /// isSimplePredicateNode - Return true if this is a simple predicate that /// operates on the node or its children without potential side effects or a /// change of the current node. @@ -134,28 +134,28 @@ public: return true; } } - + /// isSimplePredicateOrRecordNode - Return true if this is a record node or /// a simple predicate. bool isSimplePredicateOrRecordNode() const { return isSimplePredicateNode() || getKind() == RecordNode || getKind() == RecordChild; } - + /// unlinkNode - Unlink the specified node from this chain. If Other == this, /// we unlink the next pointer and return it. Otherwise we unlink Other from /// the list and return this. Matcher *unlinkNode(Matcher *Other); - + /// canMoveBefore - Return true if this matcher is the same as Other, or if /// we can move this matcher past all of the nodes in-between Other and this /// node. Other must be equal to or before this. bool canMoveBefore(const Matcher *Other) const; - + /// canMoveBefore - Return true if it is safe to move the current matcher /// across the specified one. bool canMoveBeforeNode(const Matcher *Other) const; - + /// isContradictory - Return true of these two matchers could never match on /// the same node. bool isContradictory(const Matcher *Other) const { @@ -167,7 +167,7 @@ public: return isContradictoryImpl(Other); return Other->isContradictoryImpl(this); } - + void print(raw_ostream &OS, unsigned indent = 0) const; void printOne(raw_ostream &OS) const; void dump() const; @@ -177,7 +177,7 @@ protected: virtual unsigned getHashImpl() const = 0; virtual bool isContradictoryImpl(const Matcher *M) const { return false; } }; - + /// ScopeMatcher - This attempts to match each of its children to find the first /// one that successfully matches. If one child fails, it tries the next child. /// If none of the children match then this check fails. It never has a 'next'. @@ -188,12 +188,12 @@ public: : Matcher(Scope), Children(children, children+numchildren) { } virtual ~ScopeMatcher(); - + unsigned getNumChildren() const { return Children.size(); } - + Matcher *getChild(unsigned i) { return Children[i]; } const Matcher *getChild(unsigned i) const { return Children[i]; } - + void resetChild(unsigned i, Matcher *N) { delete Children[i]; Children[i] = N; @@ -204,7 +204,7 @@ public: Children[i] = 0; return Res; } - + void setNumChildren(unsigned NC) { if (NC < Children.size()) { // delete any children we're about to lose pointers to. @@ -217,7 +217,7 @@ public: static inline bool classof(const Matcher *N) { return N->getKind() == Scope; } - + private: virtual void printImpl(raw_ostream &OS, unsigned indent) const; virtual bool isEqualImpl(const Matcher *M) const { return false; } @@ -229,38 +229,38 @@ class RecordMatcher : public Matcher { /// WhatFor - This is a string indicating why we're recording this. This /// should only be used for comment generation not anything semantic. std::string WhatFor; - + /// ResultNo - The slot number in the RecordedNodes vector that this will be, /// just printed as a comment. unsigned ResultNo; public: RecordMatcher(const std::string &whatfor, unsigned resultNo) : Matcher(RecordNode), WhatFor(whatfor), ResultNo(resultNo) {} - + const std::string &getWhatFor() const { return WhatFor; } unsigned getResultNo() const { return ResultNo; } - + static inline bool classof(const Matcher *N) { return N->getKind() == RecordNode; } - + virtual bool isSafeToReorderWithPatternPredicate() const { return true; } private: virtual void printImpl(raw_ostream &OS, unsigned indent) const; virtual bool isEqualImpl(const Matcher *M) const { return true; } virtual unsigned getHashImpl() const { return 0; } }; - + /// RecordChildMatcher - Save a numbered child of the current node, or fail /// the match if it doesn't exist. This is logically equivalent to: /// MoveChild N + RecordNode + MoveParent. class RecordChildMatcher : public Matcher { unsigned ChildNo; - + /// WhatFor - This is a string indicating why we're recording this. This /// should only be used for comment generation not anything semantic. std::string WhatFor; - + /// ResultNo - The slot number in the RecordedNodes vector that this will be, /// just printed as a comment. unsigned ResultNo; @@ -269,7 +269,7 @@ public: unsigned resultNo) : Matcher(RecordChild), ChildNo(childno), WhatFor(whatfor), ResultNo(resultNo) {} - + unsigned getChildNo() const { return ChildNo; } const std::string &getWhatFor() const { return WhatFor; } unsigned getResultNo() const { return ResultNo; } @@ -277,7 +277,7 @@ public: static inline bool classof(const Matcher *N) { return N->getKind() == RecordChild; } - + virtual bool isSafeToReorderWithPatternPredicate() const { return true; } private: @@ -287,16 +287,16 @@ private: } virtual unsigned getHashImpl() const { return getChildNo(); } }; - + /// RecordMemRefMatcher - Save the current node's memref. class RecordMemRefMatcher : public Matcher { public: RecordMemRefMatcher() : Matcher(RecordMemRef) {} - + static inline bool classof(const Matcher *N) { return N->getKind() == RecordMemRef; } - + virtual bool isSafeToReorderWithPatternPredicate() const { return true; } private: @@ -305,17 +305,17 @@ private: virtual unsigned getHashImpl() const { return 0; } }; - -/// CaptureFlagInputMatcher - If the current record has a flag input, record + +/// CaptureGlueInputMatcher - If the current record has a glue input, record /// it so that it is used as an input to the generated code. -class CaptureFlagInputMatcher : public Matcher { +class CaptureGlueInputMatcher : public Matcher { public: - CaptureFlagInputMatcher() : Matcher(CaptureFlagInput) {} - + CaptureGlueInputMatcher() : Matcher(CaptureGlueInput) {} + static inline bool classof(const Matcher *N) { - return N->getKind() == CaptureFlagInput; + return N->getKind() == CaptureGlueInput; } - + virtual bool isSafeToReorderWithPatternPredicate() const { return true; } private: @@ -323,20 +323,20 @@ private: virtual bool isEqualImpl(const Matcher *M) const { return true; } virtual unsigned getHashImpl() const { return 0; } }; - + /// MoveChildMatcher - This tells the interpreter to move into the /// specified child node. class MoveChildMatcher : public Matcher { unsigned ChildNo; public: MoveChildMatcher(unsigned childNo) : Matcher(MoveChild), ChildNo(childNo) {} - + unsigned getChildNo() const { return ChildNo; } - + static inline bool classof(const Matcher *N) { return N->getKind() == MoveChild; } - + virtual bool isSafeToReorderWithPatternPredicate() const { return true; } private: @@ -346,17 +346,17 @@ private: } virtual unsigned getHashImpl() const { return getChildNo(); } }; - + /// MoveParentMatcher - This tells the interpreter to move to the parent /// of the current node. class MoveParentMatcher : public Matcher { public: MoveParentMatcher() : Matcher(MoveParent) {} - + static inline bool classof(const Matcher *N) { return N->getKind() == MoveParent; } - + virtual bool isSafeToReorderWithPatternPredicate() const { return true; } private: @@ -373,13 +373,13 @@ class CheckSameMatcher : public Matcher { public: CheckSameMatcher(unsigned matchnumber) : Matcher(CheckSame), MatchNumber(matchnumber) {} - + unsigned getMatchNumber() const { return MatchNumber; } - + static inline bool classof(const Matcher *N) { return N->getKind() == CheckSame; } - + virtual bool isSafeToReorderWithPatternPredicate() const { return true; } private: @@ -389,7 +389,7 @@ private: } virtual unsigned getHashImpl() const { return getMatchNumber(); } }; - + /// CheckPatternPredicateMatcher - This checks the target-specific predicate /// to see if the entire pattern is capable of matching. This predicate does /// not take a node as input. This is used for subtarget feature checks etc. @@ -398,13 +398,13 @@ class CheckPatternPredicateMatcher : public Matcher { public: CheckPatternPredicateMatcher(StringRef predicate) : Matcher(CheckPatternPredicate), Predicate(predicate) {} - + StringRef getPredicate() const { return Predicate; } - + static inline bool classof(const Matcher *N) { return N->getKind() == CheckPatternPredicate; } - + virtual bool isSafeToReorderWithPatternPredicate() const { return true; } private: @@ -414,7 +414,7 @@ private: } virtual unsigned getHashImpl() const; }; - + /// CheckPredicateMatcher - This checks the target-specific predicate to /// see if the node is acceptable. class CheckPredicateMatcher : public Matcher { @@ -422,13 +422,13 @@ class CheckPredicateMatcher : public Matcher { public: CheckPredicateMatcher(StringRef predname) : Matcher(CheckPredicate), PredName(predname) {} - + StringRef getPredicateName() const { return PredName; } static inline bool classof(const Matcher *N) { return N->getKind() == CheckPredicate; } - + // TODO: Ok? //virtual bool isSafeToReorderWithPatternPredicate() const { return true; } @@ -439,8 +439,8 @@ private: } virtual unsigned getHashImpl() const; }; - - + + /// CheckOpcodeMatcher - This checks to see if the current node has the /// specified opcode, if not it fails to match. class CheckOpcodeMatcher : public Matcher { @@ -448,13 +448,13 @@ class CheckOpcodeMatcher : public Matcher { public: CheckOpcodeMatcher(const SDNodeInfo &opcode) : Matcher(CheckOpcode), Opcode(opcode) {} - + const SDNodeInfo &getOpcode() const { return Opcode; } - + static inline bool classof(const Matcher *N) { return N->getKind() == CheckOpcode; } - + virtual bool isSafeToReorderWithPatternPredicate() const { return true; } private: @@ -478,19 +478,19 @@ public: static inline bool classof(const Matcher *N) { return N->getKind() == SwitchOpcode; } - + unsigned getNumCases() const { return Cases.size(); } - + const SDNodeInfo &getCaseOpcode(unsigned i) const { return *Cases[i].first; } Matcher *getCaseMatcher(unsigned i) { return Cases[i].second; } const Matcher *getCaseMatcher(unsigned i) const { return Cases[i].second; } - + private: virtual void printImpl(raw_ostream &OS, unsigned indent) const; virtual bool isEqualImpl(const Matcher *M) const { return false; } virtual unsigned getHashImpl() const { return 4123; } }; - + /// CheckTypeMatcher - This checks to see if the current node has the /// specified type at the specified result, if not it fails to match. class CheckTypeMatcher : public Matcher { @@ -499,14 +499,14 @@ class CheckTypeMatcher : public Matcher { public: CheckTypeMatcher(MVT::SimpleValueType type, unsigned resno) : Matcher(CheckType), Type(type), ResNo(resno) {} - + MVT::SimpleValueType getType() const { return Type; } unsigned getResNo() const { return ResNo; } - + static inline bool classof(const Matcher *N) { return N->getKind() == CheckType; } - + virtual bool isSafeToReorderWithPatternPredicate() const { return true; } private: @@ -517,7 +517,7 @@ private: virtual unsigned getHashImpl() const { return Type; } virtual bool isContradictoryImpl(const Matcher *M) const; }; - + /// SwitchTypeMatcher - Switch based on the current node's type, dispatching /// to one matcher per case. If the type doesn't match any of the cases, /// then the match fails. This is semantically equivalent to a Scope node where @@ -528,24 +528,24 @@ public: SwitchTypeMatcher(const std::pair *cases, unsigned numcases) : Matcher(SwitchType), Cases(cases, cases+numcases) {} - + static inline bool classof(const Matcher *N) { return N->getKind() == SwitchType; } - + unsigned getNumCases() const { return Cases.size(); } - + MVT::SimpleValueType getCaseType(unsigned i) const { return Cases[i].first; } Matcher *getCaseMatcher(unsigned i) { return Cases[i].second; } const Matcher *getCaseMatcher(unsigned i) const { return Cases[i].second; } - + private: virtual void printImpl(raw_ostream &OS, unsigned indent) const; virtual bool isEqualImpl(const Matcher *M) const { return false; } virtual unsigned getHashImpl() const { return 4123; } }; - - + + /// CheckChildTypeMatcher - This checks to see if a child node has the /// specified type, if not it fails to match. class CheckChildTypeMatcher : public Matcher { @@ -554,14 +554,14 @@ class CheckChildTypeMatcher : public Matcher { public: CheckChildTypeMatcher(unsigned childno, MVT::SimpleValueType type) : Matcher(CheckChildType), ChildNo(childno), Type(type) {} - + unsigned getChildNo() const { return ChildNo; } MVT::SimpleValueType getType() const { return Type; } - + static inline bool classof(const Matcher *N) { return N->getKind() == CheckChildType; } - + virtual bool isSafeToReorderWithPatternPredicate() const { return true; } private: @@ -573,7 +573,7 @@ private: virtual unsigned getHashImpl() const { return (Type << 3) | ChildNo; } virtual bool isContradictoryImpl(const Matcher *M) const; }; - + /// CheckIntegerMatcher - This checks to see if the current node is a /// ConstantSDNode with the specified integer value, if not it fails to match. @@ -582,13 +582,13 @@ class CheckIntegerMatcher : public Matcher { public: CheckIntegerMatcher(int64_t value) : Matcher(CheckInteger), Value(value) {} - + int64_t getValue() const { return Value; } - + static inline bool classof(const Matcher *N) { return N->getKind() == CheckInteger; } - + virtual bool isSafeToReorderWithPatternPredicate() const { return true; } private: @@ -599,7 +599,7 @@ private: virtual unsigned getHashImpl() const { return Value; } virtual bool isContradictoryImpl(const Matcher *M) const; }; - + /// CheckCondCodeMatcher - This checks to see if the current node is a /// CondCodeSDNode with the specified condition, if not it fails to match. class CheckCondCodeMatcher : public Matcher { @@ -607,13 +607,13 @@ class CheckCondCodeMatcher : public Matcher { public: CheckCondCodeMatcher(StringRef condcodename) : Matcher(CheckCondCode), CondCodeName(condcodename) {} - + StringRef getCondCodeName() const { return CondCodeName; } - + static inline bool classof(const Matcher *N) { return N->getKind() == CheckCondCode; } - + virtual bool isSafeToReorderWithPatternPredicate() const { return true; } private: @@ -623,7 +623,7 @@ private: } virtual unsigned getHashImpl() const; }; - + /// CheckValueTypeMatcher - This checks to see if the current node is a /// VTSDNode with the specified type, if not it fails to match. class CheckValueTypeMatcher : public Matcher { @@ -631,13 +631,13 @@ class CheckValueTypeMatcher : public Matcher { public: CheckValueTypeMatcher(StringRef type_name) : Matcher(CheckValueType), TypeName(type_name) {} - + StringRef getTypeName() const { return TypeName; } static inline bool classof(const Matcher *N) { return N->getKind() == CheckValueType; } - + virtual bool isSafeToReorderWithPatternPredicate() const { return true; } private: @@ -648,21 +648,21 @@ private: virtual unsigned getHashImpl() const; bool isContradictoryImpl(const Matcher *M) const; }; - - - + + + /// CheckComplexPatMatcher - This node runs the specified ComplexPattern on /// the current node. class CheckComplexPatMatcher : public Matcher { const ComplexPattern &Pattern; - - /// MatchNumber - This is the recorded nodes slot that contains the node we want to - /// match against. + + /// MatchNumber - This is the recorded nodes slot that contains the node we + /// want to match against. unsigned MatchNumber; - + /// Name - The name of the node we're matching, for comment emission. std::string Name; - + /// FirstResult - This is the first slot in the RecordedNodes list that the /// result of the match populates. unsigned FirstResult; @@ -671,17 +671,17 @@ public: const std::string &name, unsigned firstresult) : Matcher(CheckComplexPat), Pattern(pattern), MatchNumber(matchnumber), Name(name), FirstResult(firstresult) {} - + const ComplexPattern &getPattern() const { return Pattern; } unsigned getMatchNumber() const { return MatchNumber; } - + const std::string getName() const { return Name; } unsigned getFirstResult() const { return FirstResult; } - + static inline bool classof(const Matcher *N) { return N->getKind() == CheckComplexPat; } - + // Not safe to move a pattern predicate past a complex pattern. virtual bool isSafeToReorderWithPatternPredicate() const { return false; } @@ -695,7 +695,7 @@ private: return (unsigned)(intptr_t)&Pattern ^ MatchNumber; } }; - + /// CheckAndImmMatcher - This checks to see if the current node is an 'and' /// with something equivalent to the specified immediate. class CheckAndImmMatcher : public Matcher { @@ -703,13 +703,13 @@ class CheckAndImmMatcher : public Matcher { public: CheckAndImmMatcher(int64_t value) : Matcher(CheckAndImm), Value(value) {} - + int64_t getValue() const { return Value; } - + static inline bool classof(const Matcher *N) { return N->getKind() == CheckAndImm; } - + virtual bool isSafeToReorderWithPatternPredicate() const { return true; } private: @@ -727,13 +727,13 @@ class CheckOrImmMatcher : public Matcher { public: CheckOrImmMatcher(int64_t value) : Matcher(CheckOrImm), Value(value) {} - + int64_t getValue() const { return Value; } static inline bool classof(const Matcher *N) { return N->getKind() == CheckOrImm; } - + virtual bool isSafeToReorderWithPatternPredicate() const { return true; } private: @@ -750,11 +750,11 @@ class CheckFoldableChainNodeMatcher : public Matcher { public: CheckFoldableChainNodeMatcher() : Matcher(CheckFoldableChainNode) {} - + static inline bool classof(const Matcher *N) { return N->getKind() == CheckFoldableChainNode; } - + virtual bool isSafeToReorderWithPatternPredicate() const { return true; } private: @@ -770,14 +770,14 @@ class EmitIntegerMatcher : public Matcher { public: EmitIntegerMatcher(int64_t val, MVT::SimpleValueType vt) : Matcher(EmitInteger), Val(val), VT(vt) {} - + int64_t getValue() const { return Val; } MVT::SimpleValueType getVT() const { return VT; } - + static inline bool classof(const Matcher *N) { return N->getKind() == EmitInteger; } - + private: virtual void printImpl(raw_ostream &OS, unsigned indent) const; virtual bool isEqualImpl(const Matcher *M) const { @@ -795,14 +795,14 @@ class EmitStringIntegerMatcher : public Matcher { public: EmitStringIntegerMatcher(const std::string &val, MVT::SimpleValueType vt) : Matcher(EmitStringInteger), Val(val), VT(vt) {} - + const std::string &getValue() const { return Val; } MVT::SimpleValueType getVT() const { return VT; } - + static inline bool classof(const Matcher *N) { return N->getKind() == EmitStringInteger; } - + private: virtual void printImpl(raw_ostream &OS, unsigned indent) const; virtual bool isEqualImpl(const Matcher *M) const { @@ -811,7 +811,7 @@ private: } virtual unsigned getHashImpl() const; }; - + /// EmitRegisterMatcher - This creates a new TargetConstant. class EmitRegisterMatcher : public Matcher { /// Reg - The def for the register that we're emitting. If this is null, then @@ -821,14 +821,14 @@ class EmitRegisterMatcher : public Matcher { public: EmitRegisterMatcher(Record *reg, MVT::SimpleValueType vt) : Matcher(EmitRegister), Reg(reg), VT(vt) {} - + Record *getReg() const { return Reg; } MVT::SimpleValueType getVT() const { return VT; } - + static inline bool classof(const Matcher *N) { return N->getKind() == EmitRegister; } - + private: virtual void printImpl(raw_ostream &OS, unsigned indent) const; virtual bool isEqualImpl(const Matcher *M) const { @@ -848,13 +848,13 @@ class EmitConvertToTargetMatcher : public Matcher { public: EmitConvertToTargetMatcher(unsigned slot) : Matcher(EmitConvertToTarget), Slot(slot) {} - + unsigned getSlot() const { return Slot; } - + static inline bool classof(const Matcher *N) { return N->getKind() == EmitConvertToTarget; } - + private: virtual void printImpl(raw_ostream &OS, unsigned indent) const; virtual bool isEqualImpl(const Matcher *M) const { @@ -862,7 +862,7 @@ private: } virtual unsigned getHashImpl() const { return Slot; } }; - + /// EmitMergeInputChainsMatcher - Emit a node that merges a list of input /// chains together with a token factor. The list of nodes are the nodes in the /// matched pattern that have chain input/outputs. This node adds all input @@ -872,18 +872,18 @@ class EmitMergeInputChainsMatcher : public Matcher { public: EmitMergeInputChainsMatcher(const unsigned *nodes, unsigned NumNodes) : Matcher(EmitMergeInputChains), ChainNodes(nodes, nodes+NumNodes) {} - + unsigned getNumNodes() const { return ChainNodes.size(); } - + unsigned getNode(unsigned i) const { assert(i < ChainNodes.size()); return ChainNodes[i]; - } - + } + static inline bool classof(const Matcher *N) { return N->getKind() == EmitMergeInputChains; } - + private: virtual void printImpl(raw_ostream &OS, unsigned indent) const; virtual bool isEqualImpl(const Matcher *M) const { @@ -891,9 +891,9 @@ private: } virtual unsigned getHashImpl() const; }; - + /// EmitCopyToRegMatcher - Emit a CopyToReg node from a value to a physreg, -/// pushing the chain and flag results. +/// pushing the chain and glue results. /// class EmitCopyToRegMatcher : public Matcher { unsigned SrcSlot; // Value to copy into the physreg. @@ -901,27 +901,27 @@ class EmitCopyToRegMatcher : public Matcher { public: EmitCopyToRegMatcher(unsigned srcSlot, Record *destPhysReg) : Matcher(EmitCopyToReg), SrcSlot(srcSlot), DestPhysReg(destPhysReg) {} - + unsigned getSrcSlot() const { return SrcSlot; } Record *getDestPhysReg() const { return DestPhysReg; } - + static inline bool classof(const Matcher *N) { return N->getKind() == EmitCopyToReg; } - + private: virtual void printImpl(raw_ostream &OS, unsigned indent) const; virtual bool isEqualImpl(const Matcher *M) const { return cast(M)->SrcSlot == SrcSlot && - cast(M)->DestPhysReg == DestPhysReg; + cast(M)->DestPhysReg == DestPhysReg; } virtual unsigned getHashImpl() const { return SrcSlot ^ ((unsigned)(intptr_t)DestPhysReg << 4); } }; - - - + + + /// EmitNodeXFormMatcher - Emit an operation that runs an SDNodeXForm on a /// recorded node and records the result. class EmitNodeXFormMatcher : public Matcher { @@ -930,33 +930,33 @@ class EmitNodeXFormMatcher : public Matcher { public: EmitNodeXFormMatcher(unsigned slot, Record *nodeXForm) : Matcher(EmitNodeXForm), Slot(slot), NodeXForm(nodeXForm) {} - + unsigned getSlot() const { return Slot; } Record *getNodeXForm() const { return NodeXForm; } - + static inline bool classof(const Matcher *N) { return N->getKind() == EmitNodeXForm; } - + private: virtual void printImpl(raw_ostream &OS, unsigned indent) const; virtual bool isEqualImpl(const Matcher *M) const { return cast(M)->Slot == Slot && - cast(M)->NodeXForm == NodeXForm; + cast(M)->NodeXForm == NodeXForm; } virtual unsigned getHashImpl() const { return Slot ^ ((unsigned)(intptr_t)NodeXForm << 4); } }; - + /// EmitNodeMatcherCommon - Common class shared between EmitNode and /// MorphNodeTo. class EmitNodeMatcherCommon : public Matcher { std::string OpcodeName; const SmallVector VTs; const SmallVector Operands; - bool HasChain, HasInFlag, HasOutFlag, HasMemRefs; - + bool HasChain, HasInGlue, HasOutGlue, HasMemRefs; + /// NumFixedArityOperands - If this is a fixed arity node, this is set to -1. /// If this is a varidic node, this is set to the number of fixed arity /// operands in the root of the pattern. The rest are appended to this node. @@ -965,16 +965,16 @@ public: EmitNodeMatcherCommon(const std::string &opcodeName, const MVT::SimpleValueType *vts, unsigned numvts, const unsigned *operands, unsigned numops, - bool hasChain, bool hasInFlag, bool hasOutFlag, + bool hasChain, bool hasInGlue, bool hasOutGlue, bool hasmemrefs, int numfixedarityoperands, bool isMorphNodeTo) : Matcher(isMorphNodeTo ? MorphNodeTo : EmitNode), OpcodeName(opcodeName), VTs(vts, vts+numvts), Operands(operands, operands+numops), - HasChain(hasChain), HasInFlag(hasInFlag), HasOutFlag(hasOutFlag), + HasChain(hasChain), HasInGlue(hasInGlue), HasOutGlue(hasOutGlue), HasMemRefs(hasmemrefs), NumFixedArityOperands(numfixedarityoperands) {} - + const std::string &getOpcodeName() const { return OpcodeName; } - + unsigned getNumVTs() const { return VTs.size(); } MVT::SimpleValueType getVT(unsigned i) const { assert(i < VTs.size()); @@ -986,27 +986,27 @@ public: assert(i < Operands.size()); return Operands[i]; } - + const SmallVectorImpl &getVTList() const { return VTs; } const SmallVectorImpl &getOperandList() const { return Operands; } - + bool hasChain() const { return HasChain; } - bool hasInFlag() const { return HasInFlag; } - bool hasOutFlag() const { return HasOutFlag; } + bool hasInFlag() const { return HasInGlue; } + bool hasOutFlag() const { return HasOutGlue; } bool hasMemRefs() const { return HasMemRefs; } int getNumFixedArityOperands() const { return NumFixedArityOperands; } - + static inline bool classof(const Matcher *N) { return N->getKind() == EmitNode || N->getKind() == MorphNodeTo; } - + private: virtual void printImpl(raw_ostream &OS, unsigned indent) const; virtual bool isEqualImpl(const Matcher *M) const; virtual unsigned getHashImpl() const; }; - + /// EmitNodeMatcher - This signals a successful match and generates a node. class EmitNodeMatcher : public EmitNodeMatcherCommon { unsigned FirstResultSlot; @@ -1021,15 +1021,15 @@ public: hasInFlag, hasOutFlag, hasmemrefs, numfixedarityoperands, false), FirstResultSlot(firstresultslot) {} - + unsigned getFirstResultSlot() const { return FirstResultSlot; } - + static inline bool classof(const Matcher *N) { return N->getKind() == EmitNode; } - + }; - + class MorphNodeToMatcher : public EmitNodeMatcherCommon { const PatternToMatch &Pattern; public: @@ -1044,38 +1044,38 @@ public: numfixedarityoperands, true), Pattern(pattern) { } - + const PatternToMatch &getPattern() const { return Pattern; } static inline bool classof(const Matcher *N) { return N->getKind() == MorphNodeTo; } }; - -/// MarkFlagResultsMatcher - This node indicates which non-root nodes in the -/// pattern produce flags. This allows CompleteMatchMatcher to update them -/// with the output flag of the resultant code. -class MarkFlagResultsMatcher : public Matcher { - SmallVector FlagResultNodes; + +/// MarkGlueResultsMatcher - This node indicates which non-root nodes in the +/// pattern produce glue. This allows CompleteMatchMatcher to update them +/// with the output glue of the resultant code. +class MarkGlueResultsMatcher : public Matcher { + SmallVector GlueResultNodes; public: - MarkFlagResultsMatcher(const unsigned *nodes, unsigned NumNodes) - : Matcher(MarkFlagResults), FlagResultNodes(nodes, nodes+NumNodes) {} - - unsigned getNumNodes() const { return FlagResultNodes.size(); } - + MarkGlueResultsMatcher(const unsigned *nodes, unsigned NumNodes) + : Matcher(MarkGlueResults), GlueResultNodes(nodes, nodes+NumNodes) {} + + unsigned getNumNodes() const { return GlueResultNodes.size(); } + unsigned getNode(unsigned i) const { - assert(i < FlagResultNodes.size()); - return FlagResultNodes[i]; - } - + assert(i < GlueResultNodes.size()); + return GlueResultNodes[i]; + } + static inline bool classof(const Matcher *N) { - return N->getKind() == MarkFlagResults; + return N->getKind() == MarkGlueResults; } - + private: virtual void printImpl(raw_ostream &OS, unsigned indent) const; virtual bool isEqualImpl(const Matcher *M) const { - return cast(M)->FlagResultNodes == FlagResultNodes; + return cast(M)->GlueResultNodes == GlueResultNodes; } virtual unsigned getHashImpl() const; }; @@ -1095,11 +1095,11 @@ public: unsigned getNumResults() const { return Results.size(); } unsigned getResult(unsigned R) const { return Results[R]; } const PatternToMatch &getPattern() const { return Pattern; } - + static inline bool classof(const Matcher *N) { return N->getKind() == CompleteMatch; } - + private: virtual void printImpl(raw_ostream &OS, unsigned indent) const; virtual bool isEqualImpl(const Matcher *M) const { @@ -1108,7 +1108,7 @@ private: } virtual unsigned getHashImpl() const; }; - + } // end namespace llvm #endif diff --git a/utils/TableGen/DAGISelMatcherEmitter.cpp b/utils/TableGen/DAGISelMatcherEmitter.cpp index dfbfe80c0a1d..0b7fbf7c8518 100644 --- a/utils/TableGen/DAGISelMatcherEmitter.cpp +++ b/utils/TableGen/DAGISelMatcherEmitter.cpp @@ -220,8 +220,8 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, OS << "OPC_RecordMemRef,\n"; return 1; - case Matcher::CaptureFlagInput: - OS << "OPC_CaptureFlagInput,\n"; + case Matcher::CaptureGlueInput: + OS << "OPC_CaptureGlueInput,\n"; return 1; case Matcher::MoveChild: @@ -485,8 +485,8 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, OS << ", TARGET_OPCODE(" << EN->getOpcodeName() << "), 0"; if (EN->hasChain()) OS << "|OPFL_Chain"; - if (EN->hasInFlag()) OS << "|OPFL_FlagInput"; - if (EN->hasOutFlag()) OS << "|OPFL_FlagOutput"; + if (EN->hasInFlag()) OS << "|OPFL_GlueInput"; + if (EN->hasOutFlag()) OS << "|OPFL_GlueOutput"; if (EN->hasMemRefs()) OS << "|OPFL_MemRefs"; if (EN->getNumFixedArityOperands() != -1) OS << "|OPFL_Variadic" << EN->getNumFixedArityOperands(); @@ -531,9 +531,9 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx, return 6+EN->getNumVTs()+NumOperandBytes; } - case Matcher::MarkFlagResults: { - const MarkFlagResultsMatcher *CFR = cast(N); - OS << "OPC_MarkFlagResults, " << CFR->getNumNodes() << ", "; + case Matcher::MarkGlueResults: { + const MarkGlueResultsMatcher *CFR = cast(N); + OS << "OPC_MarkGlueResults, " << CFR->getNumNodes() << ", "; unsigned NumOperandBytes = 0; for (unsigned i = 0, e = CFR->getNumNodes(); i != e; ++i) NumOperandBytes += EmitVBRValue(CFR->getNode(i), OS); @@ -633,8 +633,9 @@ void MatcherTableEmitter::EmitPredicateFunctions(formatted_raw_ostream &OS) { // Emit CompletePattern matchers. // FIXME: This should be const. if (!ComplexPatterns.empty()) { - OS << "bool CheckComplexPattern(SDNode *Root, SDValue N,\n"; - OS << " unsigned PatternNo, SmallVectorImpl &Result) {\n"; + OS << "bool CheckComplexPattern(SDNode *Root, SDNode *Parent, SDValue N,\n"; + OS << " unsigned PatternNo,\n"; + OS << " SmallVectorImpl > &Result) {\n"; OS << " unsigned NextRes = Result.size();\n"; OS << " switch (PatternNo) {\n"; OS << " default: assert(0 && \"Invalid pattern # in table?\");\n"; @@ -649,9 +650,20 @@ void MatcherTableEmitter::EmitPredicateFunctions(formatted_raw_ostream &OS) { OS << " Result.resize(NextRes+" << NumOps << ");\n"; OS << " return " << P.getSelectFunc(); - OS << "(Root, N"; + OS << "("; + // If the complex pattern wants the root of the match, pass it in as the + // first argument. + if (P.hasProperty(SDNPWantRoot)) + OS << "Root, "; + + // If the complex pattern wants the parent of the operand being matched, + // pass it in as the next argument. + if (P.hasProperty(SDNPWantParent)) + OS << "Parent, "; + + OS << "N"; for (unsigned i = 0; i != NumOps; ++i) - OS << ", Result[NextRes+" << i << ']'; + OS << ", Result[NextRes+" << i << "].first"; OS << ");\n"; } OS << " }\n"; @@ -730,7 +742,7 @@ void MatcherTableEmitter::EmitHistogram(const Matcher *M, case Matcher::RecordNode: OS << "OPC_RecordNode"; break; case Matcher::RecordChild: OS << "OPC_RecordChild"; break; case Matcher::RecordMemRef: OS << "OPC_RecordMemRef"; break; - case Matcher::CaptureFlagInput: OS << "OPC_CaptureFlagInput"; break; + case Matcher::CaptureGlueInput: OS << "OPC_CaptureGlueInput"; break; case Matcher::MoveChild: OS << "OPC_MoveChild"; break; case Matcher::MoveParent: OS << "OPC_MoveParent"; break; case Matcher::CheckSame: OS << "OPC_CheckSame"; break; @@ -759,7 +771,7 @@ void MatcherTableEmitter::EmitHistogram(const Matcher *M, case Matcher::EmitNode: OS << "OPC_EmitNode"; break; case Matcher::MorphNodeTo: OS << "OPC_MorphNodeTo"; break; case Matcher::EmitNodeXForm: OS << "OPC_EmitNodeXForm"; break; - case Matcher::MarkFlagResults: OS << "OPC_MarkFlagResults"; break; + case Matcher::MarkGlueResults: OS << "OPC_MarkGlueResults"; break; case Matcher::CompleteMatch: OS << "OPC_CompleteMatch"; break; } diff --git a/utils/TableGen/DAGISelMatcherGen.cpp b/utils/TableGen/DAGISelMatcherGen.cpp index aba6636a1370..7c0badec1d6d 100644 --- a/utils/TableGen/DAGISelMatcherGen.cpp +++ b/utils/TableGen/DAGISelMatcherGen.cpp @@ -25,12 +25,12 @@ static MVT::SimpleValueType getRegisterValueType(Record *R, MVT::SimpleValueType VT = MVT::Other; const std::vector &RCs = T.getRegisterClasses(); std::vector::const_iterator Element; - + for (unsigned rc = 0, e = RCs.size(); rc != e; ++rc) { const CodeGenRegisterClass &RC = RCs[rc]; if (!std::count(RC.Elements.begin(), RC.Elements.end(), R)) continue; - + if (!FoundRC) { FoundRC = true; VT = RC.getValueTypeNum(0); @@ -48,30 +48,30 @@ namespace { class MatcherGen { const PatternToMatch &Pattern; const CodeGenDAGPatterns &CGP; - + /// PatWithNoTypes - This is a clone of Pattern.getSrcPattern() that starts /// out with all of the types removed. This allows us to insert type checks /// as we scan the tree. TreePatternNode *PatWithNoTypes; - + /// VariableMap - A map from variable names ('$dst') to the recorded operand /// number that they were captured as. These are biased by 1 to make /// insertion easier. StringMap VariableMap; - + /// NextRecordedOperandNo - As we emit opcodes to record matched values in /// the RecordedNodes array, this keeps track of which slot will be next to /// record into. unsigned NextRecordedOperandNo; - + /// MatchedChainNodes - This maintains the position in the recorded nodes /// array of all of the recorded input nodes that have chains. SmallVector MatchedChainNodes; - /// MatchedFlagResultNodes - This maintains the position in the recorded - /// nodes array of all of the recorded input nodes that have flag results. - SmallVector MatchedFlagResultNodes; - + /// MatchedGlueResultNodes - This maintains the position in the recorded + /// nodes array of all of the recorded input nodes that have glue results. + SmallVector MatchedGlueResultNodes; + /// MatchedComplexPatterns - This maintains a list of all of the /// ComplexPatterns that we need to check. The patterns are known to have /// names which were recorded. The second element of each pair is the first @@ -79,40 +79,39 @@ namespace { /// results into. SmallVector, 2> MatchedComplexPatterns; - + /// PhysRegInputs - List list has an entry for each explicitly specified /// physreg input to the pattern. The first elt is the Register node, the /// second is the recorded slot number the input pattern match saved it in. SmallVector, 2> PhysRegInputs; - + /// Matcher - This is the top level of the generated matcher, the result. Matcher *TheMatcher; - + /// CurPredicate - As we emit matcher nodes, this points to the latest check /// which should have future checks stuck into its Next position. Matcher *CurPredicate; public: MatcherGen(const PatternToMatch &pattern, const CodeGenDAGPatterns &cgp); - + ~MatcherGen() { delete PatWithNoTypes; } - + bool EmitMatcherCode(unsigned Variant); void EmitResultCode(); - + Matcher *GetMatcher() const { return TheMatcher; } - Matcher *GetCurPredicate() const { return CurPredicate; } private: void AddMatcher(Matcher *NewNode); void InferPossibleTypes(); - + // Matcher Generation. void EmitMatchCode(const TreePatternNode *N, TreePatternNode *NodeNoTypes); void EmitLeafMatchCode(const TreePatternNode *N); void EmitOperatorMatchCode(const TreePatternNode *N, TreePatternNode *NodeNoTypes); - + // Result Code Generation. unsigned getNamedArgumentSlot(StringRef Name) { unsigned VarMapEntry = VariableMap[Name]; @@ -124,7 +123,7 @@ namespace { /// GetInstPatternNode - Get the pattern for an instruction. const TreePatternNode *GetInstPatternNode(const DAGInstruction &Ins, const TreePatternNode *N); - + void EmitResultOperand(const TreePatternNode *N, SmallVectorImpl &ResultOps); void EmitResultOfNamedOperand(const TreePatternNode *N, @@ -136,7 +135,7 @@ namespace { void EmitResultSDNodeXFormAsOperand(const TreePatternNode *N, SmallVectorImpl &ResultOps); }; - + } // end anon namespace. MatcherGen::MatcherGen(const PatternToMatch &pattern, @@ -157,7 +156,7 @@ MatcherGen::MatcherGen(const PatternToMatch &pattern, // PatWithNoTypes = Pattern.getSrcPattern()->clone(); PatWithNoTypes->RemoveAllTypes(); - + // If there are types that are manifestly known, infer them. InferPossibleTypes(); } @@ -170,7 +169,7 @@ void MatcherGen::InferPossibleTypes() { // TP - Get *SOME* tree pattern, we don't care which. It is only used for // diagnostics, which we know are impossible at this point. TreePattern &TP = *CGP.pf_begin()->second; - + try { bool MadeChange = true; while (MadeChange) @@ -183,7 +182,7 @@ void MatcherGen::InferPossibleTypes() { } -/// AddMatcher - Add a matcher node to the current graph we're building. +/// AddMatcher - Add a matcher node to the current graph we're building. void MatcherGen::AddMatcher(Matcher *NewNode) { if (CurPredicate != 0) CurPredicate->setNext(NewNode); @@ -200,7 +199,7 @@ void MatcherGen::AddMatcher(Matcher *NewNode) { /// EmitLeafMatchCode - Generate matching code for leaf nodes. void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) { assert(N->isLeaf() && "Not a leaf?"); - + // Direct match against an integer constant. if (IntInit *II = dynamic_cast(N->getLeafValue())) { // If this is the root of the dag we're matching, we emit a redundant opcode @@ -213,16 +212,16 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) { return AddMatcher(new CheckIntegerMatcher(II->getValue())); } - + DefInit *DI = dynamic_cast(N->getLeafValue()); if (DI == 0) { errs() << "Unknown leaf kind: " << *DI << "\n"; abort(); } - + Record *LeafRec = DI->getDef(); if (// Handle register references. Nothing to do here, they always match. - LeafRec->isSubClassOf("RegisterClass") || + LeafRec->isSubClassOf("RegisterClass") || LeafRec->isSubClassOf("PointerLikeRegClass") || LeafRec->isSubClassOf("SubRegIndex") || // Place holder for SRCVALUE nodes. Nothing to do here. @@ -230,20 +229,20 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) { return; // If we have a physreg reference like (mul gpr:$src, EAX) then we need to - // record the register + // record the register if (LeafRec->isSubClassOf("Register")) { AddMatcher(new RecordMatcher("physreg input "+LeafRec->getName(), NextRecordedOperandNo)); PhysRegInputs.push_back(std::make_pair(LeafRec, NextRecordedOperandNo++)); return; } - + if (LeafRec->isSubClassOf("ValueType")) return AddMatcher(new CheckValueTypeMatcher(LeafRec->getName())); - + if (LeafRec->isSubClassOf("CondCode")) return AddMatcher(new CheckCondCodeMatcher(LeafRec->getName())); - + if (LeafRec->isSubClassOf("ComplexPattern")) { // We can't model ComplexPattern uses that don't have their name taken yet. // The OPC_CheckComplexPattern operation implicitly records the results. @@ -257,7 +256,7 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode *N) { MatchedComplexPatterns.push_back(std::make_pair(N, 0)); return; } - + errs() << "Unknown leaf kind: " << *N << "\n"; abort(); } @@ -266,7 +265,7 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N, TreePatternNode *NodeNoTypes) { assert(!N->isLeaf() && "Not an operator?"); const SDNodeInfo &CInfo = CGP.getSDNodeInfo(N->getOperator()); - + // If this is an 'and R, 1234' where the operation is AND/OR and the RHS is // a constant without a predicate fn that has more that one bit set, handle // this as a special case. This is usually for targets that have special @@ -277,7 +276,7 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N, // them from the mask in the dag. For example, it might turn 'AND X, 255' // into 'AND X, 254' if it knows the low bit is set. Emit code that checks // to handle this. - if ((N->getOperator()->getName() == "and" || + if ((N->getOperator()->getName() == "and" || N->getOperator()->getName() == "or") && N->getChild(1)->isLeaf() && N->getChild(1)->getPredicateFns().empty() && N->getPredicateFns().empty()) { @@ -303,15 +302,15 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N, } } } - + // Check that the current opcode lines up. AddMatcher(new CheckOpcodeMatcher(CInfo)); - + // If this node has memory references (i.e. is a load or store), tell the // interpreter to capture them in the memref array. if (N->NodeHasProperty(SDNPMemOperand, CGP)) AddMatcher(new RecordMemRefMatcher()); - + // If this node has a chain, then the chain is operand #0 is the SDNode, and // the child numbers of the node are all offset by one. unsigned OpNo = 0; @@ -322,7 +321,7 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N, NextRecordedOperandNo)); // Remember all of the input chains our pattern will match. MatchedChainNodes.push_back(NextRecordedOperandNo++); - + // Don't look at the input chain when matching the tree pattern to the // SDNode. OpNo = 1; @@ -353,11 +352,11 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N, // If there is a node between the root and this node, then we definitely // need to emit the check. bool NeedCheck = !Root->hasChild(N); - + // If it *is* an immediate child of the root, we can still need a check if // the root SDNode has multiple inputs. For us, this means that it is an // intrinsic, has multiple operands, or has other inputs like chain or - // flag). + // glue). if (!NeedCheck) { const SDNodeInfo &PInfo = CGP.getSDNodeInfo(Root->getOperator()); NeedCheck = @@ -366,34 +365,34 @@ void MatcherGen::EmitOperatorMatchCode(const TreePatternNode *N, Root->getOperator() == CGP.get_intrinsic_wo_chain_sdnode() || PInfo.getNumOperands() > 1 || PInfo.hasProperty(SDNPHasChain) || - PInfo.hasProperty(SDNPInFlag) || - PInfo.hasProperty(SDNPOptInFlag); + PInfo.hasProperty(SDNPInGlue) || + PInfo.hasProperty(SDNPOptInGlue); } - + if (NeedCheck) AddMatcher(new CheckFoldableChainNodeMatcher()); } } - // If this node has an output flag and isn't the root, remember it. - if (N->NodeHasProperty(SDNPOutFlag, CGP) && + // If this node has an output glue and isn't the root, remember it. + if (N->NodeHasProperty(SDNPOutGlue, CGP) && N != Pattern.getSrcPattern()) { - // TODO: This redundantly records nodes with both flags and chains. - + // TODO: This redundantly records nodes with both glues and chains. + // Record the node and remember it in our chained nodes list. AddMatcher(new RecordMatcher("'" + N->getOperator()->getName() + - "' flag output node", + "' glue output node", NextRecordedOperandNo)); - // Remember all of the nodes with output flags our pattern will match. - MatchedFlagResultNodes.push_back(NextRecordedOperandNo++); + // Remember all of the nodes with output glue our pattern will match. + MatchedGlueResultNodes.push_back(NextRecordedOperandNo++); } - - // If this node is known to have an input flag or if it *might* have an input - // flag, capture it as the flag input of the pattern. - if (N->NodeHasProperty(SDNPOptInFlag, CGP) || - N->NodeHasProperty(SDNPInFlag, CGP)) - AddMatcher(new CaptureFlagInputMatcher()); - + + // If this node is known to have an input glue or if it *might* have an input + // glue, capture it as the glue input of the pattern. + if (N->NodeHasProperty(SDNPOptInGlue, CGP) || + N->NodeHasProperty(SDNPInGlue, CGP)) + AddMatcher(new CaptureGlueInputMatcher()); + for (unsigned i = 0, e = N->getNumChildren(); i != e; ++i, ++OpNo) { // Get the code suitable for matching this child. Move to the child, check // it then move back to the parent. @@ -410,14 +409,14 @@ void MatcherGen::EmitMatchCode(const TreePatternNode *N, // need to do a type check. Emit the check, apply the tyep to NodeNoTypes and // reinfer any correlated types. SmallVector ResultsToTypeCheck; - + for (unsigned i = 0, e = NodeNoTypes->getNumTypes(); i != e; ++i) { if (NodeNoTypes->getExtType(i) == N->getExtType(i)) continue; NodeNoTypes->setType(i, N->getExtType(i)); InferPossibleTypes(); ResultsToTypeCheck.push_back(i); } - + // If this node has a name associated with it, capture it in VariableMap. If // we already saw this in the pattern, emit code to verify dagness. if (!N->getName().empty()) { @@ -435,16 +434,16 @@ void MatcherGen::EmitMatchCode(const TreePatternNode *N, return; } } - + if (N->isLeaf()) EmitLeafMatchCode(N); else EmitOperatorMatchCode(N, NodeNoTypes); - + // If there are node predicates for this node, generate their checks. for (unsigned i = 0, e = N->getPredicateFns().size(); i != e; ++i) AddMatcher(new CheckPredicateMatcher(N->getPredicateFns()[i])); - + for (unsigned i = 0, e = ResultsToTypeCheck.size(); i != e; ++i) AddMatcher(new CheckTypeMatcher(N->getType(ResultsToTypeCheck[i]), ResultsToTypeCheck[i])); @@ -463,27 +462,27 @@ bool MatcherGen::EmitMatcherCode(unsigned Variant) { const std::vector &OpNodes = CP->getRootNodes(); assert(!OpNodes.empty() &&"Complex Pattern must specify what it can match"); if (Variant >= OpNodes.size()) return true; - + AddMatcher(new CheckOpcodeMatcher(CGP.getSDNodeInfo(OpNodes[Variant]))); } else { if (Variant != 0) return true; } - + // Emit the matcher for the pattern structure and types. EmitMatchCode(Pattern.getSrcPattern(), PatWithNoTypes); - + // If the pattern has a predicate on it (e.g. only enabled when a subtarget // feature is around, do the check). if (!Pattern.getPredicateCheck().empty()) AddMatcher(new CheckPatternPredicateMatcher(Pattern.getPredicateCheck())); - + // Now that we've completed the structural type match, emit any ComplexPattern // checks (e.g. addrmode matches). We emit this after the structural match // because they are generally more expensive to evaluate and more difficult to // factor. for (unsigned i = 0, e = MatchedComplexPatterns.size(); i != e; ++i) { const TreePatternNode *N = MatchedComplexPatterns[i].first; - + // Remember where the results of this match get stuck. MatchedComplexPatterns[i].second = NextRecordedOperandNo; @@ -492,15 +491,15 @@ bool MatcherGen::EmitMatcherCode(unsigned Variant) { assert(!N->getName().empty() && RecNodeEntry && "Complex pattern should have a name and slot"); --RecNodeEntry; // Entries in VariableMap are biased. - + const ComplexPattern &CP = CGP.getComplexPattern(((DefInit*)N->getLeafValue())->getDef()); - + // Emit a CheckComplexPat operation, which does the match (aborting if it // fails) and pushes the matched operands onto the recorded nodes list. AddMatcher(new CheckComplexPatMatcher(CP, RecNodeEntry, N->getName(), NextRecordedOperandNo)); - + // Record the right number of operands. NextRecordedOperandNo += CP.getNumOperands(); if (CP.hasProperty(SDNPHasChain)) { @@ -508,17 +507,17 @@ bool MatcherGen::EmitMatcherCode(unsigned Variant) { // fact that we just recorded a chain input. The chain input will be // matched as the last operand of the predicate if it was successful. ++NextRecordedOperandNo; // Chained node operand. - + // It is the last operand recorded. assert(NextRecordedOperandNo > 1 && "Should have recorded input/result chains at least!"); MatchedChainNodes.push_back(NextRecordedOperandNo-1); } - - // TODO: Complex patterns can't have output flags, if they did, we'd want + + // TODO: Complex patterns can't have output glues, if they did, we'd want // to record them. } - + return false; } @@ -530,7 +529,7 @@ bool MatcherGen::EmitMatcherCode(unsigned Variant) { void MatcherGen::EmitResultOfNamedOperand(const TreePatternNode *N, SmallVectorImpl &ResultOps){ assert(!N->getName().empty() && "Operand not named!"); - + // A reference to a complex pattern gets all of the results of the complex // pattern's match. if (const ComplexPattern *CP = N->getComplexPatternInfo(CGP)) { @@ -541,7 +540,7 @@ void MatcherGen::EmitResultOfNamedOperand(const TreePatternNode *N, break; } assert(SlotNo != 0 && "Didn't get a slot number assigned?"); - + // The first slot entry is the node itself, the subsequent entries are the // matched values. for (unsigned i = 0, e = CP->getNumOperands(); i != e; ++i) @@ -562,20 +561,20 @@ void MatcherGen::EmitResultOfNamedOperand(const TreePatternNode *N, return; } } - + ResultOps.push_back(SlotNo); } void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N, SmallVectorImpl &ResultOps) { assert(N->isLeaf() && "Must be a leaf"); - + if (IntInit *II = dynamic_cast(N->getLeafValue())) { AddMatcher(new EmitIntegerMatcher(II->getValue(), N->getType(0))); ResultOps.push_back(NextRecordedOperandNo++); return; } - + // If this is an explicit register reference, handle it. if (DefInit *DI = dynamic_cast(N->getLeafValue())) { if (DI->getDef()->isSubClassOf("Register")) { @@ -583,13 +582,13 @@ void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N, ResultOps.push_back(NextRecordedOperandNo++); return; } - + if (DI->getDef()->getName() == "zero_reg") { AddMatcher(new EmitRegisterMatcher(0, N->getType(0))); ResultOps.push_back(NextRecordedOperandNo++); return; } - + // Handle a reference to a register class. This is used // in COPY_TO_SUBREG instructions. if (DI->getDef()->isSubClassOf("RegisterClass")) { @@ -607,17 +606,17 @@ void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N, return; } } - + errs() << "unhandled leaf node: \n"; N->dump(); } /// GetInstPatternNode - Get the pattern for an instruction. -/// +/// const TreePatternNode *MatcherGen:: GetInstPatternNode(const DAGInstruction &Inst, const TreePatternNode *N) { const TreePattern *InstPat = Inst.getPattern(); - + // FIXME2?: Assume actual pattern comes before "implicit". TreePatternNode *InstPatNode; if (InstPat) @@ -626,11 +625,11 @@ GetInstPatternNode(const DAGInstruction &Inst, const TreePatternNode *N) { InstPatNode = Pattern.getSrcPattern(); else return 0; - + if (InstPatNode && !InstPatNode->isLeaf() && InstPatNode->getOperator()->getName() == "set") InstPatNode = InstPatNode->getChild(InstPatNode->getNumChildren()-1); - + return InstPatNode; } @@ -641,7 +640,7 @@ EmitResultInstructionAsOperand(const TreePatternNode *N, const CodeGenTarget &CGT = CGP.getTargetInfo(); CodeGenInstruction &II = CGT.getInstruction(Op); const DAGInstruction &Inst = CGP.getInstruction(Op); - + // If we can, get the pattern for the instruction we're generating. We derive // a variety of information from this pattern, such as whether it has a chain. // @@ -650,27 +649,27 @@ EmitResultInstructionAsOperand(const TreePatternNode *N, // nodes can't duplicate. const TreePatternNode *InstPatNode = GetInstPatternNode(Inst, N); - // NodeHasChain - Whether the instruction node we're creating takes chains. + // NodeHasChain - Whether the instruction node we're creating takes chains. bool NodeHasChain = InstPatNode && InstPatNode->TreeHasProperty(SDNPHasChain, CGP); - + bool isRoot = N == Pattern.getDstPattern(); - // TreeHasOutFlag - True if this tree has a flag. - bool TreeHasInFlag = false, TreeHasOutFlag = false; + // TreeHasOutGlue - True if this tree has glue. + bool TreeHasInGlue = false, TreeHasOutGlue = false; if (isRoot) { const TreePatternNode *SrcPat = Pattern.getSrcPattern(); - TreeHasInFlag = SrcPat->TreeHasProperty(SDNPOptInFlag, CGP) || - SrcPat->TreeHasProperty(SDNPInFlag, CGP); - + TreeHasInGlue = SrcPat->TreeHasProperty(SDNPOptInGlue, CGP) || + SrcPat->TreeHasProperty(SDNPInGlue, CGP); + // FIXME2: this is checking the entire pattern, not just the node in // question, doing this just for the root seems like a total hack. - TreeHasOutFlag = SrcPat->TreeHasProperty(SDNPOutFlag, CGP); + TreeHasOutGlue = SrcPat->TreeHasProperty(SDNPOutGlue, CGP); } // NumResults - This is the number of results produced by the instruction in // the "outs" list. - unsigned NumResults = Inst.getNumResults(); + unsigned NumResults = Inst.getNumResults(); // Loop over all of the operands of the instruction pattern, emitting code // to fill them all in. The node 'N' usually has number children equal to @@ -679,41 +678,41 @@ EmitResultInstructionAsOperand(const TreePatternNode *N, // in the 'execute always' values. Match up the node operands to the // instruction operands to do this. SmallVector InstOps; - for (unsigned ChildNo = 0, InstOpNo = NumResults, e = II.OperandList.size(); + for (unsigned ChildNo = 0, InstOpNo = NumResults, e = II.Operands.size(); InstOpNo != e; ++InstOpNo) { - + // Determine what to emit for this operand. - Record *OperandNode = II.OperandList[InstOpNo].Rec; + Record *OperandNode = II.Operands[InstOpNo].Rec; if ((OperandNode->isSubClassOf("PredicateOperand") || OperandNode->isSubClassOf("OptionalDefOperand")) && !CGP.getDefaultOperand(OperandNode).DefaultOps.empty()) { // This is a predicate or optional def operand; emit the // 'default ops' operands. const DAGDefaultOperand &DefaultOp - = CGP.getDefaultOperand(OperandNode); + = CGP.getDefaultOperand(OperandNode); for (unsigned i = 0, e = DefaultOp.DefaultOps.size(); i != e; ++i) EmitResultOperand(DefaultOp.DefaultOps[i], InstOps); continue; } - + const TreePatternNode *Child = N->getChild(ChildNo); - + // Otherwise this is a normal operand or a predicate operand without // 'execute always'; emit it. unsigned BeforeAddingNumOps = InstOps.size(); EmitResultOperand(Child, InstOps); assert(InstOps.size() > BeforeAddingNumOps && "Didn't add any operands"); - + // If the operand is an instruction and it produced multiple results, just // take the first one. if (!Child->isLeaf() && Child->getOperator()->isSubClassOf("Instruction")) InstOps.resize(BeforeAddingNumOps+1); - + ++ChildNo; } - - // If this node has an input flag or explicitly specified input physregs, we - // need to add chained and flagged copyfromreg nodes and materialize the flag + + // If this node has input glue or explicitly specified input physregs, we + // need to add chained and glued copyfromreg nodes and materialize the glue // input. if (isRoot && !PhysRegInputs.empty()) { // Emit all of the CopyToReg nodes for the input physical registers. These @@ -721,18 +720,18 @@ EmitResultInstructionAsOperand(const TreePatternNode *N, for (unsigned i = 0, e = PhysRegInputs.size(); i != e; ++i) AddMatcher(new EmitCopyToRegMatcher(PhysRegInputs[i].second, PhysRegInputs[i].first)); - // Even if the node has no other flag inputs, the resultant node must be - // flagged to the CopyFromReg nodes we just generated. - TreeHasInFlag = true; + // Even if the node has no other glue inputs, the resultant node must be + // glued to the CopyFromReg nodes we just generated. + TreeHasInGlue = true; } - - // Result order: node results, chain, flags - + + // Result order: node results, chain, glue + // Determine the result types. SmallVector ResultVTs; for (unsigned i = 0, e = N->getNumTypes(); i != e; ++i) ResultVTs.push_back(N->getType(i)); - + // If this is the root instruction of a pattern that has physical registers in // its result pattern, add output VTs for them. For example, X86 has: // (set AL, (mul ...)) @@ -744,7 +743,7 @@ EmitResultInstructionAsOperand(const TreePatternNode *N, Record *HandledReg = 0; if (II.HasOneImplicitDefWithKnownVT(CGT) != MVT::Other) HandledReg = II.ImplicitDefs[0]; - + for (unsigned i = 0; i != Pattern.getDstRegs().size(); ++i) { Record *Reg = Pattern.getDstRegs()[i]; if (!Reg->isSubClassOf("Register") || Reg == HandledReg) continue; @@ -759,7 +758,7 @@ EmitResultInstructionAsOperand(const TreePatternNode *N, if (isRoot && (Pattern.getSrcPattern()->NodeHasProperty(SDNPVariadic, CGP))) NumFixedArityOperands = Pattern.getSrcPattern()->getNumChildren(); - + // If this is the root node and any of the nodes matched nodes in the input // pattern have MemRefs in them, have the interpreter collect them and plop // them onto this node. @@ -776,19 +775,19 @@ EmitResultInstructionAsOperand(const TreePatternNode *N, bool NodeHasMemRefs = isRoot && Pattern.getSrcPattern()->TreeHasProperty(SDNPMemOperand, CGP); - assert((!ResultVTs.empty() || TreeHasOutFlag || NodeHasChain) && + assert((!ResultVTs.empty() || TreeHasOutGlue || NodeHasChain) && "Node has no result"); - + AddMatcher(new EmitNodeMatcher(II.Namespace+"::"+II.TheDef->getName(), ResultVTs.data(), ResultVTs.size(), InstOps.data(), InstOps.size(), - NodeHasChain, TreeHasInFlag, TreeHasOutFlag, + NodeHasChain, TreeHasInGlue, TreeHasOutGlue, NodeHasMemRefs, NumFixedArityOperands, NextRecordedOperandNo)); - - // The non-chain and non-flag results of the newly emitted node get recorded. + + // The non-chain and non-glue results of the newly emitted node get recorded. for (unsigned i = 0, e = ResultVTs.size(); i != e; ++i) { - if (ResultVTs[i] == MVT::Other || ResultVTs[i] == MVT::Flag) break; + if (ResultVTs[i] == MVT::Other || ResultVTs[i] == MVT::Glue) break; OutputOps.push_back(NextRecordedOperandNo++); } } @@ -800,7 +799,7 @@ EmitResultSDNodeXFormAsOperand(const TreePatternNode *N, // Emit the operand. SmallVector InputOps; - + // FIXME2: Could easily generalize this to support multiple inputs and outputs // to the SDNodeXForm. For now we just support one input and one output like // the old instruction selector. @@ -839,7 +838,7 @@ void MatcherGen::EmitResultCode() { if (!MatchedChainNodes.empty()) AddMatcher(new EmitMergeInputChainsMatcher (MatchedChainNodes.data(), MatchedChainNodes.size())); - + // Codegen the root of the result pattern, capturing the resulting values. SmallVector Ops; EmitResultOperand(Pattern.getDstPattern(), Ops); @@ -847,11 +846,11 @@ void MatcherGen::EmitResultCode() { // At this point, we have however many values the result pattern produces. // However, the input pattern might not need all of these. If there are // excess values at the end (such as implicit defs of condition codes etc) - // just lop them off. This doesn't need to worry about flags or chains, just + // just lop them off. This doesn't need to worry about glue or chains, just // explicit results. // unsigned NumSrcResults = Pattern.getSrcPattern()->getNumTypes(); - + // If the pattern also has (implicit) results, count them as well. if (!Pattern.getDstRegs().empty()) { // If the root came from an implicit def in the instruction handling stuff, @@ -865,23 +864,23 @@ void MatcherGen::EmitResultCode() { if (II.HasOneImplicitDefWithKnownVT(CGT) != MVT::Other) HandledReg = II.ImplicitDefs[0]; } - + for (unsigned i = 0; i != Pattern.getDstRegs().size(); ++i) { Record *Reg = Pattern.getDstRegs()[i]; if (!Reg->isSubClassOf("Register") || Reg == HandledReg) continue; ++NumSrcResults; } - } - + } + assert(Ops.size() >= NumSrcResults && "Didn't provide enough results"); Ops.resize(NumSrcResults); - // If the matched pattern covers nodes which define a flag result, emit a node + // If the matched pattern covers nodes which define a glue result, emit a node // that tells the matcher about them so that it can update their results. - if (!MatchedFlagResultNodes.empty()) - AddMatcher(new MarkFlagResultsMatcher(MatchedFlagResultNodes.data(), - MatchedFlagResultNodes.size())); - + if (!MatchedGlueResultNodes.empty()) + AddMatcher(new MarkGlueResultsMatcher(MatchedGlueResultNodes.data(), + MatchedGlueResultNodes.size())); + AddMatcher(new CompleteMatchMatcher(Ops.data(), Ops.size(), Pattern)); } @@ -896,12 +895,12 @@ Matcher *llvm::ConvertPatternToMatcher(const PatternToMatch &Pattern, // Generate the code for the matcher. if (Gen.EmitMatcherCode(Variant)) return 0; - + // FIXME2: Kill extra MoveParent commands at the end of the matcher sequence. // FIXME2: Split result code out to another table, and make the matcher end // with an "Emit " command. This allows result generation stuff to be // shared and factored? - + // If the match succeeds, then we generate Pattern. Gen.EmitResultCode(); diff --git a/utils/TableGen/DAGISelMatcherOpt.cpp b/utils/TableGen/DAGISelMatcherOpt.cpp index c73bdb9efb68..3169ea1e16af 100644 --- a/utils/TableGen/DAGISelMatcherOpt.cpp +++ b/utils/TableGen/DAGISelMatcherOpt.cpp @@ -75,7 +75,7 @@ static void ContractNodes(OwningPtr &MatcherPtr, // MarkFlagResults->EmitNode->CompleteMatch when we can to encourage // MorphNodeTo formation. This is safe because MarkFlagResults never refers // to the root of the pattern. - if (isa(N) && isa(N->getNext()) && + if (isa(N) && isa(N->getNext()) && isa(N->getNext()->getNext())) { // Unlink the two nodes from the list. Matcher *EmitNode = MatcherPtr.take(); @@ -100,7 +100,7 @@ static void ContractNodes(OwningPtr &MatcherPtr, if (CM->getResult(i) != RootResultFirst+i) ResultsMatch = false; - // If the selected node defines a subset of the flag/chain results, we + // If the selected node defines a subset of the glue/chain results, we // can't use MorphNodeTo. For example, we can't use MorphNodeTo if the // matched pattern has a chain but the root node doesn't. const PatternToMatch &Pattern = CM->getPattern(); @@ -109,23 +109,23 @@ static void ContractNodes(OwningPtr &MatcherPtr, Pattern.getSrcPattern()->NodeHasProperty(SDNPHasChain, CGP)) ResultsMatch = false; - // If the matched node has a flag and the output root doesn't, we can't + // If the matched node has glue and the output root doesn't, we can't // use MorphNodeTo. // - // NOTE: Strictly speaking, we don't have to check for the flag here + // NOTE: Strictly speaking, we don't have to check for glue here // because the code in the pattern generator doesn't handle it right. We // do it anyway for thoroughness. if (!EN->hasOutFlag() && - Pattern.getSrcPattern()->NodeHasProperty(SDNPOutFlag, CGP)) + Pattern.getSrcPattern()->NodeHasProperty(SDNPOutGlue, CGP)) ResultsMatch = false; // If the root result node defines more results than the source root node - // *and* has a chain or flag input, then we can't match it because it - // would end up replacing the extra result with the chain/flag. + // *and* has a chain or glue input, then we can't match it because it + // would end up replacing the extra result with the chain/glue. #if 0 - if ((EN->hasFlag() || EN->hasChain()) && - EN->getNumNonChainFlagVTs() > ... need to get no results reliably ...) + if ((EN->hasGlue() || EN->hasChain()) && + EN->getNumNonChainGlueVTs() > ... need to get no results reliably ...) ResultMatch = false; #endif diff --git a/utils/TableGen/DisassemblerEmitter.cpp b/utils/TableGen/DisassemblerEmitter.cpp index 3284366c6dd8..90a2af21f3a4 100644 --- a/utils/TableGen/DisassemblerEmitter.cpp +++ b/utils/TableGen/DisassemblerEmitter.cpp @@ -13,6 +13,7 @@ #include "X86DisassemblerTables.h" #include "X86RecognizableInstr.h" #include "ARMDecoderEmitter.h" +#include "FixedLenDecoderEmitter.h" using namespace llvm; using namespace llvm::X86Disassembler; @@ -94,7 +95,7 @@ using namespace llvm::X86Disassembler; /// instruction. void DisassemblerEmitter::run(raw_ostream &OS) { - CodeGenTarget Target; + CodeGenTarget Target(Records); OS << "/*===- TableGen'erated file " << "---------------------------------------*- C -*-===*\n" @@ -127,11 +128,11 @@ void DisassemblerEmitter::run(raw_ostream &OS) { } // Fixed-instruction-length targets use a common disassembler. + // ARM use its own implementation for now. if (Target.getName() == "ARM") { ARMDecoderEmitter(Records).run(OS); return; } - throw TGError(Target.getTargetRecord()->getLoc(), - "Unable to generate disassembler for this target"); + FixedLenDecoderEmitter(Records).run(OS); } diff --git a/utils/TableGen/EDEmitter.cpp b/utils/TableGen/EDEmitter.cpp index 525fffb0ee2c..020a4a312d7b 100644 --- a/utils/TableGen/EDEmitter.cpp +++ b/utils/TableGen/EDEmitter.cpp @@ -35,22 +35,22 @@ using namespace llvm; /////////////////////////////////////////////////////////// namespace { - + class EnumEmitter { private: std::string Name; std::vector Entries; public: - EnumEmitter(const char *N) : Name(N) { + EnumEmitter(const char *N) : Name(N) { } - int addEntry(const char *e) { + int addEntry(const char *e) { Entries.push_back(std::string(e)); - return Entries.size() - 1; + return Entries.size() - 1; } void emit(raw_ostream &o, unsigned int &i) { o.indent(i) << "enum " << Name.c_str() << " {" << "\n"; i += 2; - + unsigned int index = 0; unsigned int numEntries = Entries.size(); for (index = 0; index < numEntries; ++index) { @@ -59,15 +59,15 @@ namespace { o << ","; o << "\n"; } - + i -= 2; o.indent(i) << "};" << "\n"; } - + void emitAsFlags(raw_ostream &o, unsigned int &i) { o.indent(i) << "enum " << Name.c_str() << " {" << "\n"; i += 2; - + unsigned int index = 0; unsigned int numEntries = Entries.size(); unsigned int flag = 1; @@ -78,7 +78,7 @@ namespace { o << "\n"; flag <<= 1; } - + i -= 2; o.indent(i) << "};" << "\n"; } @@ -89,7 +89,7 @@ namespace { virtual ~ConstantEmitter() { } virtual void emit(raw_ostream &o, unsigned int &i) = 0; }; - + class LiteralConstantEmitter : public ConstantEmitter { private: bool IsNumber; @@ -98,7 +98,7 @@ namespace { const char* String; }; public: - LiteralConstantEmitter(int number = 0) : + LiteralConstantEmitter(int number = 0) : IsNumber(true), Number(number) { } @@ -117,7 +117,7 @@ namespace { o << String; } }; - + class CompoundConstantEmitter : public ConstantEmitter { private: unsigned int Padding; @@ -127,7 +127,7 @@ namespace { } CompoundConstantEmitter &addEntry(ConstantEmitter *e) { Entries.push_back(e); - + return *this; } ~CompoundConstantEmitter() { @@ -140,12 +140,12 @@ namespace { void emit(raw_ostream &o, unsigned int &i) { o << "{" << "\n"; i += 2; - + unsigned int index; unsigned int numEntries = Entries.size(); - + unsigned int numToPrint; - + if (Padding) { if (numEntries > Padding) { fprintf(stderr, "%u entries but %u padding\n", numEntries, Padding); @@ -155,24 +155,24 @@ namespace { } else { numToPrint = numEntries; } - + for (index = 0; index < numToPrint; ++index) { o.indent(i); if (index < numEntries) Entries[index]->emit(o, i); else o << "-1"; - + if (index < (numToPrint - 1)) o << ","; o << "\n"; } - + i -= 2; o.indent(i) << "}"; } }; - + class FlagsConstantEmitter : public ConstantEmitter { private: std::vector Flags; @@ -188,7 +188,7 @@ namespace { unsigned int numFlags = Flags.size(); if (numFlags == 0) o << "0"; - + for (index = 0; index < numFlags; ++index) { o << Flags[index].c_str(); if (index < (numFlags - 1)) @@ -218,15 +218,15 @@ void populateOperandOrder(CompoundConstantEmitter *operandOrder, const CodeGenInstruction &inst, unsigned syntax) { unsigned int numArgs = 0; - + AsmWriterInst awInst(inst, syntax, -1, -1); - + std::vector::iterator operandIterator; - + for (operandIterator = awInst.Operands.begin(); operandIterator != awInst.Operands.end(); ++operandIterator) { - if (operandIterator->OperandType == + if (operandIterator->OperandType == AsmWriterOperand::isMachineInstrOperand) { operandOrder->addEntry( new LiteralConstantEmitter(operandIterator->CGIOpNo)); @@ -274,7 +274,7 @@ static int X86TypeFromOpName(LiteralConstantEmitter *type, REG("SEGMENT_REG"); REG("DEBUG_REG"); REG("CONTROL_REG"); - + IMM("i8imm"); IMM("i16imm"); IMM("i16i8imm"); @@ -284,7 +284,7 @@ static int X86TypeFromOpName(LiteralConstantEmitter *type, IMM("i64i8imm"); IMM("i64i32imm"); IMM("SSECC"); - + // all R, I, R, I, R MEM("i8mem"); MEM("i8mem_NOREX"); @@ -306,12 +306,12 @@ static int X86TypeFromOpName(LiteralConstantEmitter *type, MEM("f128mem"); MEM("f256mem"); MEM("opaque512mem"); - + // all R, I, R, I LEA("lea32mem"); LEA("lea64_32mem"); LEA("lea64mem"); - + // all I PCR("i16imm_pcrel"); PCR("i32imm_pcrel"); @@ -322,7 +322,12 @@ static int X86TypeFromOpName(LiteralConstantEmitter *type, PCR("offset32"); PCR("offset64"); PCR("brtarget"); - + PCR("uncondbrtarget"); + PCR("bltarget"); + + // all I, ARM mode only, conditional/unconditional + PCR("br_target"); + PCR("bl_target"); return 1; } @@ -344,19 +349,19 @@ static void X86PopulateOperands( const CodeGenInstruction &inst) { if (!inst.TheDef->isSubClassOf("X86Inst")) return; - + unsigned int index; - unsigned int numOperands = inst.OperandList.size(); - + unsigned int numOperands = inst.Operands.size(); + for (index = 0; index < numOperands; ++index) { - const CodeGenInstruction::OperandInfo &operandInfo = - inst.OperandList[index]; + const CGIOperandList::OperandInfo &operandInfo = inst.Operands[index]; Record &rec = *operandInfo.Rec; - - if (X86TypeFromOpName(operandTypes[index], rec.getName())) { + + if (X86TypeFromOpName(operandTypes[index], rec.getName()) && + !rec.isSubClassOf("PointerLikeRegClass")) { errs() << "Operand type: " << rec.getName().c_str() << "\n"; errs() << "Operand name: " << operandInfo.Name.c_str() << "\n"; - errs() << "Instruction mame: " << inst.TheDef->getName().c_str() << "\n"; + errs() << "Instruction name: " << inst.TheDef->getName().c_str() << "\n"; llvm_unreachable("Unhandled type"); } } @@ -375,9 +380,9 @@ static inline void decorate1( const char *opName, const char *opFlag) { unsigned opIndex; - - opIndex = inst.getOperandNamed(std::string(opName)); - + + opIndex = inst.Operands.getOperandNamed(std::string(opName)); + operandFlags[opIndex]->addEntry(opFlag); } @@ -414,7 +419,7 @@ static inline void decorate1( } /// X86ExtractSemantics - Performs various checks on the name of an X86 -/// instruction to determine what sort of an instruction it is and then adds +/// instruction to determine what sort of an instruction it is and then adds /// the appropriate flags to the instruction and its operands /// /// @arg instType - A reference to the type for the instruction as a whole @@ -425,7 +430,7 @@ static void X86ExtractSemantics( FlagsConstantEmitter *(&operandFlags)[EDIS_MAX_OPERANDS], const CodeGenInstruction &inst) { const std::string &name = inst.TheDef->getName(); - + if (name.find("MOV") != name.npos) { if (name.find("MOV_V") != name.npos) { // ignore (this is a pseudoinstruction) @@ -450,7 +455,7 @@ static void X86ExtractSemantics( MOV("src", "dst"); } } - + if (name.find("JMP") != name.npos || name.find("J") == 0) { if (name.find("FAR") != name.npos && name.find("i") != name.npos) { @@ -459,10 +464,14 @@ static void X86ExtractSemantics( BRANCH("dst"); } } - + if (name.find("PUSH") != name.npos) { - if (name.find("FS") != name.npos || - name.find("GS") != name.npos) { + if (name.find("CS") != name.npos || + name.find("DS") != name.npos || + name.find("ES") != name.npos || + name.find("FS") != name.npos || + name.find("GS") != name.npos || + name.find("SS") != name.npos) { instType.set("kInstructionTypePush"); // TODO add support for fixed operands } else if (name.find("F") != name.npos) { @@ -477,12 +486,16 @@ static void X86ExtractSemantics( PUSH("reg"); } } - + if (name.find("POP") != name.npos) { if (name.find("POPCNT") != name.npos) { // ignore (not a real pop) - } else if (name.find("FS") != name.npos || - name.find("GS") != name.npos) { + } else if (name.find("CS") != name.npos || + name.find("DS") != name.npos || + name.find("ES") != name.npos || + name.find("FS") != name.npos || + name.find("GS") != name.npos || + name.find("SS") != name.npos) { instType.set("kInstructionTypePop"); // TODO add support for fixed operands } else if (name.find("F") != name.npos) { @@ -495,7 +508,7 @@ static void X86ExtractSemantics( POP("reg"); } } - + if (name.find("CALL") != name.npos) { if (name.find("ADJ") != name.npos) { // ignore (not a call) @@ -509,7 +522,7 @@ static void X86ExtractSemantics( CALL("dst"); } } - + if (name.find("RET") != name.npos) { RETURN(); } @@ -553,12 +566,20 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type, REG("QPR"); REG("QQPR"); REG("QQQQPR"); - + IMM("i32imm"); + IMM("i32imm_hilo16"); IMM("bf_inv_mask_imm"); + IMM("lsb_pos_imm"); + IMM("width_imm"); IMM("jtblock_operand"); IMM("nohash_imm"); + IMM("p_imm"); + IMM("c_imm"); + IMM("imod_op"); + IMM("iflags_op"); IMM("cpinst_operand"); + IMM("setend_op"); IMM("cps_opt"); IMM("vfp_f64imm"); IMM("vfp_f32imm"); @@ -566,46 +587,73 @@ static int ARMFlagFromOpName(LiteralConstantEmitter *type, IMM("msr_mask"); IMM("neg_zero"); IMM("imm0_31"); + IMM("imm0_31_m1"); IMM("nModImm"); IMM("imm0_4095"); IMM("jt2block_operand"); IMM("t_imm_s4"); IMM("pclabel"); + IMM("adrlabel"); + IMM("t_adrlabel"); + IMM("t2adrlabel"); IMM("shift_imm"); - + IMM("neon_vcvt_imm32"); + MISC("brtarget", "kOperandTypeARMBranchTarget"); // ? + MISC("uncondbrtarget", "kOperandTypeARMBranchTarget"); // ? + MISC("t_brtarget", "kOperandTypeARMBranchTarget"); // ? + MISC("t_bcctarget", "kOperandTypeARMBranchTarget"); // ? + MISC("t_cbtarget", "kOperandTypeARMBranchTarget"); // ? + MISC("bltarget", "kOperandTypeARMBranchTarget"); // ? + + MISC("br_target", "kOperandTypeARMBranchTarget"); // ? + MISC("bl_target", "kOperandTypeARMBranchTarget"); // ? + + MISC("t_bltarget", "kOperandTypeARMBranchTarget"); // ? + MISC("t_blxtarget", "kOperandTypeARMBranchTarget"); // ? MISC("so_reg", "kOperandTypeARMSoReg"); // R, R, I + MISC("shift_so_reg", "kOperandTypeARMSoReg"); // R, R, I MISC("t2_so_reg", "kOperandTypeThumb2SoReg"); // R, I MISC("so_imm", "kOperandTypeARMSoImm"); // I + MISC("rot_imm", "kOperandTypeARMRotImm"); // I MISC("t2_so_imm", "kOperandTypeThumb2SoImm"); // I MISC("so_imm2part", "kOperandTypeARMSoImm2Part"); // I MISC("pred", "kOperandTypeARMPredicate"); // I, R MISC("it_pred", "kOperandTypeARMPredicate"); // I + MISC("addrmode_imm12", "kOperandTypeAddrModeImm12"); // R, I + MISC("ldst_so_reg", "kOperandTypeLdStSOReg"); // R, R, I MISC("addrmode2", "kOperandTypeARMAddrMode2"); // R, R, I MISC("am2offset", "kOperandTypeARMAddrMode2Offset"); // R, I MISC("addrmode3", "kOperandTypeARMAddrMode3"); // R, R, I MISC("am3offset", "kOperandTypeARMAddrMode3Offset"); // R, I - MISC("addrmode4", "kOperandTypeARMAddrMode4"); // R, I + MISC("ldstm_mode", "kOperandTypeARMLdStmMode"); // I MISC("addrmode5", "kOperandTypeARMAddrMode5"); // R, I MISC("addrmode6", "kOperandTypeARMAddrMode6"); // R, R, I, I MISC("am6offset", "kOperandTypeARMAddrMode6Offset"); // R, I, I + MISC("addrmode6dup", "kOperandTypeARMAddrMode6"); // R, R, I, I MISC("addrmodepc", "kOperandTypeARMAddrModePC"); // R, I MISC("reglist", "kOperandTypeARMRegisterList"); // I, R, ... + MISC("dpr_reglist", "kOperandTypeARMDPRRegisterList"); // I, R, ... + MISC("spr_reglist", "kOperandTypeARMSPRRegisterList"); // I, R, ... MISC("it_mask", "kOperandTypeThumbITMask"); // I MISC("t2addrmode_imm8", "kOperandTypeThumb2AddrModeImm8"); // R, I MISC("t2am_imm8_offset", "kOperandTypeThumb2AddrModeImm8Offset");//I MISC("t2addrmode_imm12", "kOperandTypeThumb2AddrModeImm12"); // R, I MISC("t2addrmode_so_reg", "kOperandTypeThumb2AddrModeSoReg"); // R, R, I MISC("t2addrmode_imm8s4", "kOperandTypeThumb2AddrModeImm8s4"); // R, I - MISC("t2am_imm8s4_offset", "kOperandTypeThumb2AddrModeImm8s4Offset"); + MISC("t2am_imm8s4_offset", "kOperandTypeThumb2AddrModeImm8s4Offset"); // R, I MISC("tb_addrmode", "kOperandTypeARMTBAddrMode"); // I - MISC("t_addrmode_s1", "kOperandTypeThumbAddrModeS1"); // R, I, R - MISC("t_addrmode_s2", "kOperandTypeThumbAddrModeS2"); // R, I, R - MISC("t_addrmode_s4", "kOperandTypeThumbAddrModeS4"); // R, I, R + MISC("t_addrmode_rrs1", "kOperandTypeThumbAddrModeRegS"); // R, R + MISC("t_addrmode_rrs2", "kOperandTypeThumbAddrModeRegS"); // R, R + MISC("t_addrmode_rrs4", "kOperandTypeThumbAddrModeRegS"); // R, R + MISC("t_addrmode_is1", "kOperandTypeThumbAddrModeImmS"); // R, I + MISC("t_addrmode_is2", "kOperandTypeThumbAddrModeImmS"); // R, I + MISC("t_addrmode_is4", "kOperandTypeThumbAddrModeImmS"); // R, I MISC("t_addrmode_rr", "kOperandTypeThumbAddrModeRR"); // R, R MISC("t_addrmode_sp", "kOperandTypeThumbAddrModeSP"); // R, I - + MISC("t_addrmode_pc", "kOperandTypeThumbAddrModePC"); // R, I + return 1; } @@ -631,25 +679,24 @@ static void ARMPopulateOperands( if (!inst.TheDef->isSubClassOf("InstARM") && !inst.TheDef->isSubClassOf("InstThumb")) return; - + unsigned int index; - unsigned int numOperands = inst.OperandList.size(); - + unsigned int numOperands = inst.Operands.size(); + if (numOperands > EDIS_MAX_OPERANDS) { - errs() << "numOperands == " << numOperands << " > " << + errs() << "numOperands == " << numOperands << " > " << EDIS_MAX_OPERANDS << '\n'; llvm_unreachable("Too many operands"); } - + for (index = 0; index < numOperands; ++index) { - const CodeGenInstruction::OperandInfo &operandInfo = - inst.OperandList[index]; + const CGIOperandList::OperandInfo &operandInfo = inst.Operands[index]; Record &rec = *operandInfo.Rec; - + if (ARMFlagFromOpName(operandTypes[index], rec.getName())) { errs() << "Operand type: " << rec.getName() << '\n'; errs() << "Operand name: " << operandInfo.Name << '\n'; - errs() << "Instruction mame: " << inst.TheDef->getName() << '\n'; + errs() << "Instruction name: " << inst.TheDef->getName() << '\n'; llvm_unreachable("Unhandled type"); } } @@ -661,7 +708,7 @@ static void ARMPopulateOperands( } /// ARMExtractSemantics - Performs various checks on the name of an ARM -/// instruction to determine what sort of an instruction it is and then adds +/// instruction to determine what sort of an instruction it is and then adds /// the appropriate flags to the instruction and its operands /// /// @arg instType - A reference to the type for the instruction as a whole @@ -674,7 +721,7 @@ static void ARMExtractSemantics( FlagsConstantEmitter *(&operandFlags)[EDIS_MAX_OPERANDS], const CodeGenInstruction &inst) { const std::string &name = inst.TheDef->getName(); - + if (name == "tBcc" || name == "tB" || name == "t2Bcc" || @@ -683,7 +730,7 @@ static void ARMExtractSemantics( name == "tCBNZ") { BRANCH("target"); } - + if (name == "tBLr9" || name == "BLr9_pred" || name == "tBLXi_r9" || @@ -692,9 +739,9 @@ static void ARMExtractSemantics( name == "t2BXJ" || name == "BXJ") { BRANCH("func"); - + unsigned opIndex; - opIndex = inst.getOperandNamed("func"); + opIndex = inst.Operands.getOperandNamed("func"); if (operandTypes[opIndex]->is("kOperandTypeImmediate")) operandTypes[opIndex]->set("kOperandTypeARMBranchTarget"); } @@ -702,7 +749,7 @@ static void ARMExtractSemantics( #undef BRANCH -/// populateInstInfo - Fills an array of InstInfos with information about each +/// populateInstInfo - Fills an array of InstInfos with information about each /// instruction in a target /// /// @arg infoArray - The array of InstInfo objects to populate @@ -711,45 +758,45 @@ static void populateInstInfo(CompoundConstantEmitter &infoArray, CodeGenTarget &target) { const std::vector &numberedInstructions = target.getInstructionsByEnumValue(); - + unsigned int index; unsigned int numInstructions = numberedInstructions.size(); - + for (index = 0; index < numInstructions; ++index) { const CodeGenInstruction& inst = *numberedInstructions[index]; - + CompoundConstantEmitter *infoStruct = new CompoundConstantEmitter; infoArray.addEntry(infoStruct); - + LiteralConstantEmitter *instType = new LiteralConstantEmitter; infoStruct->addEntry(instType); - - LiteralConstantEmitter *numOperandsEmitter = - new LiteralConstantEmitter(inst.OperandList.size()); + + LiteralConstantEmitter *numOperandsEmitter = + new LiteralConstantEmitter(inst.Operands.size()); infoStruct->addEntry(numOperandsEmitter); - + CompoundConstantEmitter *operandTypeArray = new CompoundConstantEmitter; infoStruct->addEntry(operandTypeArray); - + LiteralConstantEmitter *operandTypes[EDIS_MAX_OPERANDS]; - + CompoundConstantEmitter *operandFlagArray = new CompoundConstantEmitter; infoStruct->addEntry(operandFlagArray); - + FlagsConstantEmitter *operandFlags[EDIS_MAX_OPERANDS]; - - for (unsigned operandIndex = 0; - operandIndex < EDIS_MAX_OPERANDS; + + for (unsigned operandIndex = 0; + operandIndex < EDIS_MAX_OPERANDS; ++operandIndex) { operandTypes[operandIndex] = new LiteralConstantEmitter; operandTypeArray->addEntry(operandTypes[operandIndex]); - + operandFlags[operandIndex] = new FlagsConstantEmitter; operandFlagArray->addEntry(operandFlags[operandIndex]); } - + unsigned numSyntaxes = 0; - + if (target.getName() == "X86") { X86PopulateOperands(operandTypes, inst); X86ExtractSemantics(*instType, operandFlags, inst); @@ -760,24 +807,24 @@ static void populateInstInfo(CompoundConstantEmitter &infoArray, ARMExtractSemantics(*instType, operandTypes, operandFlags, inst); numSyntaxes = 1; } - - CompoundConstantEmitter *operandOrderArray = new CompoundConstantEmitter; - + + CompoundConstantEmitter *operandOrderArray = new CompoundConstantEmitter; + infoStruct->addEntry(operandOrderArray); - - for (unsigned syntaxIndex = 0; - syntaxIndex < EDIS_MAX_SYNTAXES; + + for (unsigned syntaxIndex = 0; + syntaxIndex < EDIS_MAX_SYNTAXES; ++syntaxIndex) { - CompoundConstantEmitter *operandOrder = + CompoundConstantEmitter *operandOrder = new CompoundConstantEmitter(EDIS_MAX_OPERANDS); - + operandOrderArray->addEntry(operandOrder); - + if (syntaxIndex < numSyntaxes) { populateOperandOrder(operandOrder, inst, syntaxIndex); } } - + infoStruct = NULL; } } @@ -793,25 +840,30 @@ static void emitCommonEnums(raw_ostream &o, unsigned int &i) { operandTypes.addEntry("kOperandTypeARMBranchTarget"); operandTypes.addEntry("kOperandTypeARMSoReg"); operandTypes.addEntry("kOperandTypeARMSoImm"); + operandTypes.addEntry("kOperandTypeARMRotImm"); operandTypes.addEntry("kOperandTypeARMSoImm2Part"); operandTypes.addEntry("kOperandTypeARMPredicate"); + operandTypes.addEntry("kOperandTypeAddrModeImm12"); + operandTypes.addEntry("kOperandTypeLdStSOReg"); operandTypes.addEntry("kOperandTypeARMAddrMode2"); operandTypes.addEntry("kOperandTypeARMAddrMode2Offset"); operandTypes.addEntry("kOperandTypeARMAddrMode3"); operandTypes.addEntry("kOperandTypeARMAddrMode3Offset"); - operandTypes.addEntry("kOperandTypeARMAddrMode4"); + operandTypes.addEntry("kOperandTypeARMLdStmMode"); operandTypes.addEntry("kOperandTypeARMAddrMode5"); operandTypes.addEntry("kOperandTypeARMAddrMode6"); operandTypes.addEntry("kOperandTypeARMAddrMode6Offset"); operandTypes.addEntry("kOperandTypeARMAddrModePC"); operandTypes.addEntry("kOperandTypeARMRegisterList"); + operandTypes.addEntry("kOperandTypeARMDPRRegisterList"); + operandTypes.addEntry("kOperandTypeARMSPRRegisterList"); operandTypes.addEntry("kOperandTypeARMTBAddrMode"); operandTypes.addEntry("kOperandTypeThumbITMask"); - operandTypes.addEntry("kOperandTypeThumbAddrModeS1"); - operandTypes.addEntry("kOperandTypeThumbAddrModeS2"); - operandTypes.addEntry("kOperandTypeThumbAddrModeS4"); + operandTypes.addEntry("kOperandTypeThumbAddrModeRegS"); + operandTypes.addEntry("kOperandTypeThumbAddrModeImmS"); operandTypes.addEntry("kOperandTypeThumbAddrModeRR"); operandTypes.addEntry("kOperandTypeThumbAddrModeSP"); + operandTypes.addEntry("kOperandTypeThumbAddrModePC"); operandTypes.addEntry("kOperandTypeThumb2SoReg"); operandTypes.addEntry("kOperandTypeThumb2SoImm"); operandTypes.addEntry("kOperandTypeThumb2AddrModeImm8"); @@ -821,16 +873,16 @@ static void emitCommonEnums(raw_ostream &o, unsigned int &i) { operandTypes.addEntry("kOperandTypeThumb2AddrModeImm8s4"); operandTypes.addEntry("kOperandTypeThumb2AddrModeImm8s4Offset"); operandTypes.emit(o, i); - + o << "\n"; - + EnumEmitter operandFlags("OperandFlags"); operandFlags.addEntry("kOperandFlagSource"); operandFlags.addEntry("kOperandFlagTarget"); operandFlags.emitAsFlags(o, i); - + o << "\n"; - + EnumEmitter instructionTypes("InstructionTypes"); instructionTypes.addEntry("kInstructionTypeNone"); instructionTypes.addEntry("kInstructionTypeMove"); @@ -840,25 +892,25 @@ static void emitCommonEnums(raw_ostream &o, unsigned int &i) { instructionTypes.addEntry("kInstructionTypeCall"); instructionTypes.addEntry("kInstructionTypeReturn"); instructionTypes.emit(o, i); - + o << "\n"; } void EDEmitter::run(raw_ostream &o) { unsigned int i = 0; - + CompoundConstantEmitter infoArray; - CodeGenTarget target; - + CodeGenTarget target(Records); + populateInstInfo(infoArray, target); - + emitCommonEnums(o, i); - + o << "namespace {\n"; - + o << "llvm::EDInstInfo instInfo" << target.getName().c_str() << "[] = "; infoArray.emit(o, i); o << ";" << "\n"; - + o << "}\n"; } diff --git a/utils/TableGen/FastISelEmitter.cpp b/utils/TableGen/FastISelEmitter.cpp index 6c16fcfaa8a2..f01de1dcfce6 100644 --- a/utils/TableGen/FastISelEmitter.cpp +++ b/utils/TableGen/FastISelEmitter.cpp @@ -20,6 +20,7 @@ #include "FastISelEmitter.h" #include "Record.h" #include "llvm/Support/Debug.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/VectorExtras.h" using namespace llvm; @@ -65,23 +66,23 @@ struct OperandsSignature { return true; } } - + const CodeGenRegisterClass *DstRC = 0; - + for (unsigned i = 0, e = InstPatNode->getNumChildren(); i != e; ++i) { TreePatternNode *Op = InstPatNode->getChild(i); - + // For now, filter out any operand with a predicate. // For now, filter out any operand with multiple values. if (!Op->getPredicateFns().empty() || Op->getNumTypes() != 1) return false; - + assert(Op->hasTypeSet(0) && "Type infererence not done?"); // For now, all the operands must have the same type. if (Op->getType(0) != VT) return false; - + if (!Op->isLeaf()) { if (Op->getOperator()->getName() == "imm") { Operands.push_back("i"); @@ -107,7 +108,7 @@ struct OperandsSignature { RC = Target.getRegisterClassForRegister(OpLeafRec); else return false; - + // For now, this needs to be a register class of some sort. if (!RC) return false; @@ -212,7 +213,7 @@ class FastISelMap { typedef std::map RetPredMap; typedef std::map TypeRetPredMap; typedef std::map OpcodeTypeRetPredMap; - typedef std::map + typedef std::map OperandsOpcodeTypeRetPredMap; OperandsOpcodeTypeRetPredMap SimplePatterns; @@ -263,9 +264,9 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) { if (!Op->isSubClassOf("Instruction")) continue; CodeGenInstruction &II = CGP.getTargetInfo().getInstruction(Op); - if (II.OperandList.empty()) + if (II.Operands.size() == 0) continue; - + // For now, ignore multi-instruction patterns. bool MultiInsts = false; for (unsigned i = 0, e = Dst->getNumChildren(); i != e; ++i) { @@ -285,7 +286,7 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) { const CodeGenRegisterClass *DstRC = 0; std::string SubRegNo; if (Op->getName() != "EXTRACT_SUBREG") { - Record *Op0Rec = II.OperandList[0].Rec; + Record *Op0Rec = II.Operands[0].Rec; if (!Op0Rec->isSubClassOf("RegisterClass")) continue; DstRC = &Target.getRegisterClass(Op0Rec); @@ -295,7 +296,7 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) { // If this isn't a leaf, then continue since the register classes are // a bit too complicated for now. if (!Dst->getChild(1)->isLeaf()) continue; - + DefInit *SR = dynamic_cast(Dst->getChild(1)->getLeafValue()); if (SR) SubRegNo = getQualifiedName(SR->getDef()); @@ -310,7 +311,7 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) { // Ignore multiple result nodes for now. if (InstPatNode->getNumTypes() > 1) continue; - + Record *InstPatOp = InstPatNode->getOperator(); std::string OpcodeName = getOpcodeName(InstPatOp, CGP); MVT::SimpleValueType RetVT = MVT::isVoid; @@ -334,7 +335,7 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) { OperandsSignature Operands; if (!Operands.initialize(InstPatNode, Target, VT)) continue; - + std::vector* PhysRegInputs = new std::vector(); if (!InstPatNode->isLeaf() && (InstPatNode->getOperator()->getName() == "imm" || @@ -347,7 +348,7 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) { PhysRegInputs->push_back(""); continue; } - + DefInit *OpDI = dynamic_cast(Op->getLeafValue()); Record *OpLeafRec = OpDI->getDef(); std::string PhysReg; @@ -355,7 +356,7 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) { PhysReg += static_cast(OpLeafRec->getValue( \ "Namespace")->getValue())->getValue(); PhysReg += "::"; - + std::vector Regs = Target.getRegisters(); for (unsigned i = 0; i < Regs.size(); ++i) { if (Regs[i].TheDef == OpLeafRec) { @@ -364,7 +365,7 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) { } } } - + PhysRegInputs->push_back(PhysReg); } } else @@ -380,9 +381,10 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) { SubRegNo, PhysRegInputs }; - assert(!SimplePatterns[Operands][OpcodeName][VT][RetVT] - .count(PredicateCheck) && - "Duplicate pattern!"); + if (SimplePatterns[Operands][OpcodeName][VT][RetVT] + .count(PredicateCheck)) + throw TGError(Pattern.getSrcRecord()->getLoc(), "Duplicate record!"); + SimplePatterns[Operands][OpcodeName][VT][RetVT][PredicateCheck] = Memo; } } @@ -429,7 +431,7 @@ void FastISelMap::PrintFunctionDefinitions(raw_ostream &OS) { PI != PE; ++PI) { std::string PredicateCheck = PI->first; const InstructionMemo &Memo = PI->second; - + if (PredicateCheck.empty()) { assert(!HasPred && "Multiple instructions match, at least one has " @@ -439,14 +441,14 @@ void FastISelMap::PrintFunctionDefinitions(raw_ostream &OS) { OS << " "; HasPred = true; } - + for (unsigned i = 0; i < Memo.PhysRegs->size(); ++i) { if ((*Memo.PhysRegs)[i] != "") OS << " BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, " << "TII.get(TargetOpcode::COPY), " << (*Memo.PhysRegs)[i] << ").addReg(Op" << i << ");\n"; } - + OS << " return FastEmitInst_"; if (Memo.SubRegNo.empty()) { Operands.PrintManglingSuffix(OS, *Memo.PhysRegs); @@ -462,10 +464,10 @@ void FastISelMap::PrintFunctionDefinitions(raw_ostream &OS) { OS << Memo.SubRegNo; OS << ");\n"; } - + if (HasPred) OS << " }\n"; - + } // Return 0 if none of the predicates were satisfied. if (HasPred) @@ -473,7 +475,7 @@ void FastISelMap::PrintFunctionDefinitions(raw_ostream &OS) { OS << "}\n"; OS << "\n"; } - + // Emit one function for the type that demultiplexes on return type. OS << "unsigned FastEmit_" << getLegalCName(Opcode) << "_" @@ -496,7 +498,7 @@ void FastISelMap::PrintFunctionDefinitions(raw_ostream &OS) { OS << ");\n"; } OS << " default: return 0;\n}\n}\n\n"; - + } else { // Non-variadic return type. OS << "unsigned FastEmit_" @@ -508,13 +510,13 @@ void FastISelMap::PrintFunctionDefinitions(raw_ostream &OS) { OS << ", "; Operands.PrintParameters(OS); OS << ") {\n"; - + OS << " if (RetVT.SimpleTy != " << getName(RM.begin()->first) << ")\n return 0;\n"; - + const PredMap &PM = RM.begin()->second; bool HasPred = false; - + // Emit code for each possible instruction. There may be // multiple if there are subtarget concerns. for (PredMap::const_iterator PI = PM.begin(), PE = PM.end(); PI != PE; @@ -531,16 +533,16 @@ void FastISelMap::PrintFunctionDefinitions(raw_ostream &OS) { OS << " "; HasPred = true; } - + for (unsigned i = 0; i < Memo.PhysRegs->size(); ++i) { if ((*Memo.PhysRegs)[i] != "") OS << " BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DL, " << "TII.get(TargetOpcode::COPY), " << (*Memo.PhysRegs)[i] << ").addReg(Op" << i << ");\n"; } - + OS << " return FastEmitInst_"; - + if (Memo.SubRegNo.empty()) { Operands.PrintManglingSuffix(OS, *Memo.PhysRegs); OS << "(" << InstNS << Memo.Name << ", "; @@ -554,11 +556,11 @@ void FastISelMap::PrintFunctionDefinitions(raw_ostream &OS) { OS << Memo.SubRegNo; OS << ");\n"; } - + if (HasPred) OS << " }\n"; } - + // Return 0 if none of the predicates were satisfied. if (HasPred) OS << " return 0;\n"; diff --git a/utils/TableGen/FixedLenDecoderEmitter.cpp b/utils/TableGen/FixedLenDecoderEmitter.cpp new file mode 100644 index 000000000000..2c222b39b137 --- /dev/null +++ b/utils/TableGen/FixedLenDecoderEmitter.cpp @@ -0,0 +1,1372 @@ +//===------------ FixedLenDecoderEmitter.cpp - Decoder Generator ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// It contains the tablegen backend that emits the decoder functions for +// targets with fixed length instruction set. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "decoder-emitter" + +#include "FixedLenDecoderEmitter.h" +#include "CodeGenTarget.h" +#include "Record.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include + +using namespace llvm; + +// The set (BIT_TRUE, BIT_FALSE, BIT_UNSET) represents a ternary logic system +// for a bit value. +// +// BIT_UNFILTERED is used as the init value for a filter position. It is used +// only for filter processings. +typedef enum { + BIT_TRUE, // '1' + BIT_FALSE, // '0' + BIT_UNSET, // '?' + BIT_UNFILTERED // unfiltered +} bit_value_t; + +static bool ValueSet(bit_value_t V) { + return (V == BIT_TRUE || V == BIT_FALSE); +} +static bool ValueNotSet(bit_value_t V) { + return (V == BIT_UNSET); +} +static int Value(bit_value_t V) { + return ValueNotSet(V) ? -1 : (V == BIT_FALSE ? 0 : 1); +} +static bit_value_t bitFromBits(BitsInit &bits, unsigned index) { + if (BitInit *bit = dynamic_cast(bits.getBit(index))) + return bit->getValue() ? BIT_TRUE : BIT_FALSE; + + // The bit is uninitialized. + return BIT_UNSET; +} +// Prints the bit value for each position. +static void dumpBits(raw_ostream &o, BitsInit &bits) { + unsigned index; + + for (index = bits.getNumBits(); index > 0; index--) { + switch (bitFromBits(bits, index - 1)) { + case BIT_TRUE: + o << "1"; + break; + case BIT_FALSE: + o << "0"; + break; + case BIT_UNSET: + o << "_"; + break; + default: + assert(0 && "unexpected return value from bitFromBits"); + } + } +} + +static BitsInit &getBitsField(const Record &def, const char *str) { + BitsInit *bits = def.getValueAsBitsInit(str); + return *bits; +} + +// Forward declaration. +class FilterChooser; + +// FIXME: Possibly auto-detected? +#define BIT_WIDTH 32 + +// Representation of the instruction to work on. +typedef bit_value_t insn_t[BIT_WIDTH]; + +/// Filter - Filter works with FilterChooser to produce the decoding tree for +/// the ISA. +/// +/// It is useful to think of a Filter as governing the switch stmts of the +/// decoding tree in a certain level. Each case stmt delegates to an inferior +/// FilterChooser to decide what further decoding logic to employ, or in another +/// words, what other remaining bits to look at. The FilterChooser eventually +/// chooses a best Filter to do its job. +/// +/// This recursive scheme ends when the number of Opcodes assigned to the +/// FilterChooser becomes 1 or if there is a conflict. A conflict happens when +/// the Filter/FilterChooser combo does not know how to distinguish among the +/// Opcodes assigned. +/// +/// An example of a conflict is +/// +/// Conflict: +/// 111101000.00........00010000.... +/// 111101000.00........0001........ +/// 1111010...00........0001........ +/// 1111010...00.................... +/// 1111010......................... +/// 1111............................ +/// ................................ +/// VST4q8a 111101000_00________00010000____ +/// VST4q8b 111101000_00________00010000____ +/// +/// The Debug output shows the path that the decoding tree follows to reach the +/// the conclusion that there is a conflict. VST4q8a is a vst4 to double-spaced +/// even registers, while VST4q8b is a vst4 to double-spaced odd regsisters. +/// +/// The encoding info in the .td files does not specify this meta information, +/// which could have been used by the decoder to resolve the conflict. The +/// decoder could try to decode the even/odd register numbering and assign to +/// VST4q8a or VST4q8b, but for the time being, the decoder chooses the "a" +/// version and return the Opcode since the two have the same Asm format string. +class Filter { +protected: + FilterChooser *Owner; // points to the FilterChooser who owns this filter + unsigned StartBit; // the starting bit position + unsigned NumBits; // number of bits to filter + bool Mixed; // a mixed region contains both set and unset bits + + // Map of well-known segment value to the set of uid's with that value. + std::map > FilteredInstructions; + + // Set of uid's with non-constant segment values. + std::vector VariableInstructions; + + // Map of well-known segment value to its delegate. + std::map FilterChooserMap; + + // Number of instructions which fall under FilteredInstructions category. + unsigned NumFiltered; + + // Keeps track of the last opcode in the filtered bucket. + unsigned LastOpcFiltered; + + // Number of instructions which fall under VariableInstructions category. + unsigned NumVariable; + +public: + unsigned getNumFiltered() { return NumFiltered; } + unsigned getNumVariable() { return NumVariable; } + unsigned getSingletonOpc() { + assert(NumFiltered == 1); + return LastOpcFiltered; + } + // Return the filter chooser for the group of instructions without constant + // segment values. + FilterChooser &getVariableFC() { + assert(NumFiltered == 1); + assert(FilterChooserMap.size() == 1); + return *(FilterChooserMap.find((unsigned)-1)->second); + } + + Filter(const Filter &f); + Filter(FilterChooser &owner, unsigned startBit, unsigned numBits, bool mixed); + + ~Filter(); + + // Divides the decoding task into sub tasks and delegates them to the + // inferior FilterChooser's. + // + // A special case arises when there's only one entry in the filtered + // instructions. In order to unambiguously decode the singleton, we need to + // match the remaining undecoded encoding bits against the singleton. + void recurse(); + + // Emit code to decode instructions given a segment or segments of bits. + void emit(raw_ostream &o, unsigned &Indentation); + + // Returns the number of fanout produced by the filter. More fanout implies + // the filter distinguishes more categories of instructions. + unsigned usefulness() const; +}; // End of class Filter + +// These are states of our finite state machines used in FilterChooser's +// filterProcessor() which produces the filter candidates to use. +typedef enum { + ATTR_NONE, + ATTR_FILTERED, + ATTR_ALL_SET, + ATTR_ALL_UNSET, + ATTR_MIXED +} bitAttr_t; + +/// FilterChooser - FilterChooser chooses the best filter among a set of Filters +/// in order to perform the decoding of instructions at the current level. +/// +/// Decoding proceeds from the top down. Based on the well-known encoding bits +/// of instructions available, FilterChooser builds up the possible Filters that +/// can further the task of decoding by distinguishing among the remaining +/// candidate instructions. +/// +/// Once a filter has been chosen, it is called upon to divide the decoding task +/// into sub-tasks and delegates them to its inferior FilterChoosers for further +/// processings. +/// +/// It is useful to think of a Filter as governing the switch stmts of the +/// decoding tree. And each case is delegated to an inferior FilterChooser to +/// decide what further remaining bits to look at. +class FilterChooser { +protected: + friend class Filter; + + // Vector of codegen instructions to choose our filter. + const std::vector &AllInstructions; + + // Vector of uid's for this filter chooser to work on. + const std::vector Opcodes; + + // Lookup table for the operand decoding of instructions. + std::map > &Operands; + + // Vector of candidate filters. + std::vector Filters; + + // Array of bit values passed down from our parent. + // Set to all BIT_UNFILTERED's for Parent == NULL. + bit_value_t FilterBitValues[BIT_WIDTH]; + + // Links to the FilterChooser above us in the decoding tree. + FilterChooser *Parent; + + // Index of the best filter from Filters. + int BestIndex; + +public: + FilterChooser(const FilterChooser &FC) : + AllInstructions(FC.AllInstructions), Opcodes(FC.Opcodes), + Operands(FC.Operands), Filters(FC.Filters), Parent(FC.Parent), + BestIndex(FC.BestIndex) { + memcpy(FilterBitValues, FC.FilterBitValues, sizeof(FilterBitValues)); + } + + FilterChooser(const std::vector &Insts, + const std::vector &IDs, + std::map > &Ops) : + AllInstructions(Insts), Opcodes(IDs), Operands(Ops), Filters(), + Parent(NULL), BestIndex(-1) { + for (unsigned i = 0; i < BIT_WIDTH; ++i) + FilterBitValues[i] = BIT_UNFILTERED; + + doFilter(); + } + + FilterChooser(const std::vector &Insts, + const std::vector &IDs, + std::map > &Ops, + bit_value_t (&ParentFilterBitValues)[BIT_WIDTH], + FilterChooser &parent) : + AllInstructions(Insts), Opcodes(IDs), Operands(Ops), + Filters(), Parent(&parent), BestIndex(-1) { + for (unsigned i = 0; i < BIT_WIDTH; ++i) + FilterBitValues[i] = ParentFilterBitValues[i]; + + doFilter(); + } + + // The top level filter chooser has NULL as its parent. + bool isTopLevel() { return Parent == NULL; } + + // Emit the top level typedef and decodeInstruction() function. + void emitTop(raw_ostream &o, unsigned Indentation); + +protected: + // Populates the insn given the uid. + void insnWithID(insn_t &Insn, unsigned Opcode) const { + BitsInit &Bits = getBitsField(*AllInstructions[Opcode]->TheDef, "Inst"); + + for (unsigned i = 0; i < BIT_WIDTH; ++i) + Insn[i] = bitFromBits(Bits, i); + } + + // Returns the record name. + const std::string &nameWithID(unsigned Opcode) const { + return AllInstructions[Opcode]->TheDef->getName(); + } + + // Populates the field of the insn given the start position and the number of + // consecutive bits to scan for. + // + // Returns false if there exists any uninitialized bit value in the range. + // Returns true, otherwise. + bool fieldFromInsn(uint64_t &Field, insn_t &Insn, unsigned StartBit, + unsigned NumBits) const; + + /// dumpFilterArray - dumpFilterArray prints out debugging info for the given + /// filter array as a series of chars. + void dumpFilterArray(raw_ostream &o, bit_value_t (&filter)[BIT_WIDTH]); + + /// dumpStack - dumpStack traverses the filter chooser chain and calls + /// dumpFilterArray on each filter chooser up to the top level one. + void dumpStack(raw_ostream &o, const char *prefix); + + Filter &bestFilter() { + assert(BestIndex != -1 && "BestIndex not set"); + return Filters[BestIndex]; + } + + // Called from Filter::recurse() when singleton exists. For debug purpose. + void SingletonExists(unsigned Opc); + + bool PositionFiltered(unsigned i) { + return ValueSet(FilterBitValues[i]); + } + + // Calculates the island(s) needed to decode the instruction. + // This returns a lit of undecoded bits of an instructions, for example, + // Inst{20} = 1 && Inst{3-0} == 0b1111 represents two islands of yet-to-be + // decoded bits in order to verify that the instruction matches the Opcode. + unsigned getIslands(std::vector &StartBits, + std::vector &EndBits, std::vector &FieldVals, + insn_t &Insn); + + // Emits code to decode the singleton. Return true if we have matched all the + // well-known bits. + bool emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,unsigned Opc); + + // Emits code to decode the singleton, and then to decode the rest. + void emitSingletonDecoder(raw_ostream &o, unsigned &Indentation,Filter &Best); + + // Assign a single filter and run with it. + void runSingleFilter(FilterChooser &owner, unsigned startBit, unsigned numBit, + bool mixed); + + // reportRegion is a helper function for filterProcessor to mark a region as + // eligible for use as a filter region. + void reportRegion(bitAttr_t RA, unsigned StartBit, unsigned BitIndex, + bool AllowMixed); + + // FilterProcessor scans the well-known encoding bits of the instructions and + // builds up a list of candidate filters. It chooses the best filter and + // recursively descends down the decoding tree. + bool filterProcessor(bool AllowMixed, bool Greedy = true); + + // Decides on the best configuration of filter(s) to use in order to decode + // the instructions. A conflict of instructions may occur, in which case we + // dump the conflict set to the standard error. + void doFilter(); + + // Emits code to decode our share of instructions. Returns true if the + // emitted code causes a return, which occurs if we know how to decode + // the instruction at this level or the instruction is not decodeable. + bool emit(raw_ostream &o, unsigned &Indentation); +}; + +/////////////////////////// +// // +// Filter Implmenetation // +// // +/////////////////////////// + +Filter::Filter(const Filter &f) : + Owner(f.Owner), StartBit(f.StartBit), NumBits(f.NumBits), Mixed(f.Mixed), + FilteredInstructions(f.FilteredInstructions), + VariableInstructions(f.VariableInstructions), + FilterChooserMap(f.FilterChooserMap), NumFiltered(f.NumFiltered), + LastOpcFiltered(f.LastOpcFiltered), NumVariable(f.NumVariable) { +} + +Filter::Filter(FilterChooser &owner, unsigned startBit, unsigned numBits, + bool mixed) : Owner(&owner), StartBit(startBit), NumBits(numBits), + Mixed(mixed) { + assert(StartBit + NumBits - 1 < BIT_WIDTH); + + NumFiltered = 0; + LastOpcFiltered = 0; + NumVariable = 0; + + for (unsigned i = 0, e = Owner->Opcodes.size(); i != e; ++i) { + insn_t Insn; + + // Populates the insn given the uid. + Owner->insnWithID(Insn, Owner->Opcodes[i]); + + uint64_t Field; + // Scans the segment for possibly well-specified encoding bits. + bool ok = Owner->fieldFromInsn(Field, Insn, StartBit, NumBits); + + if (ok) { + // The encoding bits are well-known. Lets add the uid of the + // instruction into the bucket keyed off the constant field value. + LastOpcFiltered = Owner->Opcodes[i]; + FilteredInstructions[Field].push_back(LastOpcFiltered); + ++NumFiltered; + } else { + // Some of the encoding bit(s) are unspecfied. This contributes to + // one additional member of "Variable" instructions. + VariableInstructions.push_back(Owner->Opcodes[i]); + ++NumVariable; + } + } + + assert((FilteredInstructions.size() + VariableInstructions.size() > 0) + && "Filter returns no instruction categories"); +} + +Filter::~Filter() { + std::map::iterator filterIterator; + for (filterIterator = FilterChooserMap.begin(); + filterIterator != FilterChooserMap.end(); + filterIterator++) { + delete filterIterator->second; + } +} + +// Divides the decoding task into sub tasks and delegates them to the +// inferior FilterChooser's. +// +// A special case arises when there's only one entry in the filtered +// instructions. In order to unambiguously decode the singleton, we need to +// match the remaining undecoded encoding bits against the singleton. +void Filter::recurse() { + std::map >::const_iterator mapIterator; + + bit_value_t BitValueArray[BIT_WIDTH]; + // Starts by inheriting our parent filter chooser's filter bit values. + memcpy(BitValueArray, Owner->FilterBitValues, sizeof(BitValueArray)); + + unsigned bitIndex; + + if (VariableInstructions.size()) { + // Conservatively marks each segment position as BIT_UNSET. + for (bitIndex = 0; bitIndex < NumBits; bitIndex++) + BitValueArray[StartBit + bitIndex] = BIT_UNSET; + + // Delegates to an inferior filter chooser for futher processing on this + // group of instructions whose segment values are variable. + FilterChooserMap.insert(std::pair( + (unsigned)-1, + new FilterChooser(Owner->AllInstructions, + VariableInstructions, + Owner->Operands, + BitValueArray, + *Owner) + )); + } + + // No need to recurse for a singleton filtered instruction. + // See also Filter::emit(). + if (getNumFiltered() == 1) { + //Owner->SingletonExists(LastOpcFiltered); + assert(FilterChooserMap.size() == 1); + return; + } + + // Otherwise, create sub choosers. + for (mapIterator = FilteredInstructions.begin(); + mapIterator != FilteredInstructions.end(); + mapIterator++) { + + // Marks all the segment positions with either BIT_TRUE or BIT_FALSE. + for (bitIndex = 0; bitIndex < NumBits; bitIndex++) { + if (mapIterator->first & (1ULL << bitIndex)) + BitValueArray[StartBit + bitIndex] = BIT_TRUE; + else + BitValueArray[StartBit + bitIndex] = BIT_FALSE; + } + + // Delegates to an inferior filter chooser for futher processing on this + // category of instructions. + FilterChooserMap.insert(std::pair( + mapIterator->first, + new FilterChooser(Owner->AllInstructions, + mapIterator->second, + Owner->Operands, + BitValueArray, + *Owner) + )); + } +} + +// Emit code to decode instructions given a segment or segments of bits. +void Filter::emit(raw_ostream &o, unsigned &Indentation) { + o.indent(Indentation) << "// Check Inst{"; + + if (NumBits > 1) + o << (StartBit + NumBits - 1) << '-'; + + o << StartBit << "} ...\n"; + + o.indent(Indentation) << "switch (fieldFromInstruction(insn, " + << StartBit << ", " << NumBits << ")) {\n"; + + std::map::iterator filterIterator; + + bool DefaultCase = false; + for (filterIterator = FilterChooserMap.begin(); + filterIterator != FilterChooserMap.end(); + filterIterator++) { + + // Field value -1 implies a non-empty set of variable instructions. + // See also recurse(). + if (filterIterator->first == (unsigned)-1) { + DefaultCase = true; + + o.indent(Indentation) << "default:\n"; + o.indent(Indentation) << " break; // fallthrough\n"; + + // Closing curly brace for the switch statement. + // This is unconventional because we want the default processing to be + // performed for the fallthrough cases as well, i.e., when the "cases" + // did not prove a decoded instruction. + o.indent(Indentation) << "}\n"; + + } else + o.indent(Indentation) << "case " << filterIterator->first << ":\n"; + + // We arrive at a category of instructions with the same segment value. + // Now delegate to the sub filter chooser for further decodings. + // The case may fallthrough, which happens if the remaining well-known + // encoding bits do not match exactly. + if (!DefaultCase) { ++Indentation; ++Indentation; } + + bool finished = filterIterator->second->emit(o, Indentation); + // For top level default case, there's no need for a break statement. + if (Owner->isTopLevel() && DefaultCase) + break; + if (!finished) + o.indent(Indentation) << "break;\n"; + + if (!DefaultCase) { --Indentation; --Indentation; } + } + + // If there is no default case, we still need to supply a closing brace. + if (!DefaultCase) { + // Closing curly brace for the switch statement. + o.indent(Indentation) << "}\n"; + } +} + +// Returns the number of fanout produced by the filter. More fanout implies +// the filter distinguishes more categories of instructions. +unsigned Filter::usefulness() const { + if (VariableInstructions.size()) + return FilteredInstructions.size(); + else + return FilteredInstructions.size() + 1; +} + +////////////////////////////////// +// // +// Filterchooser Implementation // +// // +////////////////////////////////// + +// Emit the top level typedef and decodeInstruction() function. +void FilterChooser::emitTop(raw_ostream &o, unsigned Indentation) { + switch (BIT_WIDTH) { + case 8: + o.indent(Indentation) << "typedef uint8_t field_t;\n"; + break; + case 16: + o.indent(Indentation) << "typedef uint16_t field_t;\n"; + break; + case 32: + o.indent(Indentation) << "typedef uint32_t field_t;\n"; + break; + case 64: + o.indent(Indentation) << "typedef uint64_t field_t;\n"; + break; + default: + assert(0 && "Unexpected instruction size!"); + } + + o << '\n'; + + o.indent(Indentation) << "static field_t " << + "fieldFromInstruction(field_t insn, unsigned startBit, unsigned numBits)\n"; + + o.indent(Indentation) << "{\n"; + + ++Indentation; ++Indentation; + o.indent(Indentation) << "assert(startBit + numBits <= " << BIT_WIDTH + << " && \"Instruction field out of bounds!\");\n"; + o << '\n'; + o.indent(Indentation) << "field_t fieldMask;\n"; + o << '\n'; + o.indent(Indentation) << "if (numBits == " << BIT_WIDTH << ")\n"; + + ++Indentation; ++Indentation; + o.indent(Indentation) << "fieldMask = (field_t)-1;\n"; + --Indentation; --Indentation; + + o.indent(Indentation) << "else\n"; + + ++Indentation; ++Indentation; + o.indent(Indentation) << "fieldMask = ((1 << numBits) - 1) << startBit;\n"; + --Indentation; --Indentation; + + o << '\n'; + o.indent(Indentation) << "return (insn & fieldMask) >> startBit;\n"; + --Indentation; --Indentation; + + o.indent(Indentation) << "}\n"; + + o << '\n'; + + o.indent(Indentation) << + "static bool decodeInstruction(MCInst &MI, field_t insn) {\n"; + o.indent(Indentation) << " unsigned tmp = 0;\n"; + + ++Indentation; ++Indentation; + // Emits code to decode the instructions. + emit(o, Indentation); + + o << '\n'; + o.indent(Indentation) << "return false;\n"; + --Indentation; --Indentation; + + o.indent(Indentation) << "}\n"; + + o << '\n'; +} + +// Populates the field of the insn given the start position and the number of +// consecutive bits to scan for. +// +// Returns false if and on the first uninitialized bit value encountered. +// Returns true, otherwise. +bool FilterChooser::fieldFromInsn(uint64_t &Field, insn_t &Insn, + unsigned StartBit, unsigned NumBits) const { + Field = 0; + + for (unsigned i = 0; i < NumBits; ++i) { + if (Insn[StartBit + i] == BIT_UNSET) + return false; + + if (Insn[StartBit + i] == BIT_TRUE) + Field = Field | (1ULL << i); + } + + return true; +} + +/// dumpFilterArray - dumpFilterArray prints out debugging info for the given +/// filter array as a series of chars. +void FilterChooser::dumpFilterArray(raw_ostream &o, + bit_value_t (&filter)[BIT_WIDTH]) { + unsigned bitIndex; + + for (bitIndex = BIT_WIDTH; bitIndex > 0; bitIndex--) { + switch (filter[bitIndex - 1]) { + case BIT_UNFILTERED: + o << "."; + break; + case BIT_UNSET: + o << "_"; + break; + case BIT_TRUE: + o << "1"; + break; + case BIT_FALSE: + o << "0"; + break; + } + } +} + +/// dumpStack - dumpStack traverses the filter chooser chain and calls +/// dumpFilterArray on each filter chooser up to the top level one. +void FilterChooser::dumpStack(raw_ostream &o, const char *prefix) { + FilterChooser *current = this; + + while (current) { + o << prefix; + dumpFilterArray(o, current->FilterBitValues); + o << '\n'; + current = current->Parent; + } +} + +// Called from Filter::recurse() when singleton exists. For debug purpose. +void FilterChooser::SingletonExists(unsigned Opc) { + insn_t Insn0; + insnWithID(Insn0, Opc); + + errs() << "Singleton exists: " << nameWithID(Opc) + << " with its decoding dominating "; + for (unsigned i = 0; i < Opcodes.size(); ++i) { + if (Opcodes[i] == Opc) continue; + errs() << nameWithID(Opcodes[i]) << ' '; + } + errs() << '\n'; + + dumpStack(errs(), "\t\t"); + for (unsigned i = 0; i < Opcodes.size(); i++) { + const std::string &Name = nameWithID(Opcodes[i]); + + errs() << '\t' << Name << " "; + dumpBits(errs(), + getBitsField(*AllInstructions[Opcodes[i]]->TheDef, "Inst")); + errs() << '\n'; + } +} + +// Calculates the island(s) needed to decode the instruction. +// This returns a list of undecoded bits of an instructions, for example, +// Inst{20} = 1 && Inst{3-0} == 0b1111 represents two islands of yet-to-be +// decoded bits in order to verify that the instruction matches the Opcode. +unsigned FilterChooser::getIslands(std::vector &StartBits, + std::vector &EndBits, std::vector &FieldVals, + insn_t &Insn) { + unsigned Num, BitNo; + Num = BitNo = 0; + + uint64_t FieldVal = 0; + + // 0: Init + // 1: Water (the bit value does not affect decoding) + // 2: Island (well-known bit value needed for decoding) + int State = 0; + int Val = -1; + + for (unsigned i = 0; i < BIT_WIDTH; ++i) { + Val = Value(Insn[i]); + bool Filtered = PositionFiltered(i); + switch (State) { + default: + assert(0 && "Unreachable code!"); + break; + case 0: + case 1: + if (Filtered || Val == -1) + State = 1; // Still in Water + else { + State = 2; // Into the Island + BitNo = 0; + StartBits.push_back(i); + FieldVal = Val; + } + break; + case 2: + if (Filtered || Val == -1) { + State = 1; // Into the Water + EndBits.push_back(i - 1); + FieldVals.push_back(FieldVal); + ++Num; + } else { + State = 2; // Still in Island + ++BitNo; + FieldVal = FieldVal | Val << BitNo; + } + break; + } + } + // If we are still in Island after the loop, do some housekeeping. + if (State == 2) { + EndBits.push_back(BIT_WIDTH - 1); + FieldVals.push_back(FieldVal); + ++Num; + } + + assert(StartBits.size() == Num && EndBits.size() == Num && + FieldVals.size() == Num); + return Num; +} + +// Emits code to decode the singleton. Return true if we have matched all the +// well-known bits. +bool FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation, + unsigned Opc) { + std::vector StartBits; + std::vector EndBits; + std::vector FieldVals; + insn_t Insn; + insnWithID(Insn, Opc); + + // Look for islands of undecoded bits of the singleton. + getIslands(StartBits, EndBits, FieldVals, Insn); + + unsigned Size = StartBits.size(); + unsigned I, NumBits; + + // If we have matched all the well-known bits, just issue a return. + if (Size == 0) { + o.indent(Indentation) << "{\n"; + o.indent(Indentation) << " MI.setOpcode(" << Opc << ");\n"; + std::vector& InsnOperands = Operands[Opc]; + for (std::vector::iterator + I = InsnOperands.begin(), E = InsnOperands.end(); I != E; ++I) { + // If a custom instruction decoder was specified, use that. + if (I->FieldBase == ~0U && I->FieldLength == ~0U) { + o.indent(Indentation) << " " << I->Decoder << "(MI, insn);\n"; + break; + } + + o.indent(Indentation) + << " tmp = fieldFromInstruction(insn, " << I->FieldBase + << ", " << I->FieldLength << ");\n"; + if (I->Decoder != "") { + o.indent(Indentation) << " " << I->Decoder << "(MI, tmp);\n"; + } else { + o.indent(Indentation) + << " MI.addOperand(MCOperand::CreateImm(tmp));\n"; + } + } + + o.indent(Indentation) << " return true; // " << nameWithID(Opc) + << '\n'; + o.indent(Indentation) << "}\n"; + return true; + } + + // Otherwise, there are more decodings to be done! + + // Emit code to match the island(s) for the singleton. + o.indent(Indentation) << "// Check "; + + for (I = Size; I != 0; --I) { + o << "Inst{" << EndBits[I-1] << '-' << StartBits[I-1] << "} "; + if (I > 1) + o << "&& "; + else + o << "for singleton decoding...\n"; + } + + o.indent(Indentation) << "if ("; + + for (I = Size; I != 0; --I) { + NumBits = EndBits[I-1] - StartBits[I-1] + 1; + o << "fieldFromInstruction(insn, " << StartBits[I-1] << ", " << NumBits + << ") == " << FieldVals[I-1]; + if (I > 1) + o << " && "; + else + o << ") {\n"; + } + o.indent(Indentation) << " MI.setOpcode(" << Opc << ");\n"; + std::vector& InsnOperands = Operands[Opc]; + for (std::vector::iterator + I = InsnOperands.begin(), E = InsnOperands.end(); I != E; ++I) { + // If a custom instruction decoder was specified, use that. + if (I->FieldBase == ~0U && I->FieldLength == ~0U) { + o.indent(Indentation) << " " << I->Decoder << "(MI, insn);\n"; + break; + } + + o.indent(Indentation) + << " tmp = fieldFromInstruction(insn, " << I->FieldBase + << ", " << I->FieldLength << ");\n"; + if (I->Decoder != "") { + o.indent(Indentation) << " " << I->Decoder << "(MI, tmp);\n"; + } else { + o.indent(Indentation) + << " MI.addOperand(MCOperand::CreateImm(tmp));\n"; + } + } + o.indent(Indentation) << " return true; // " << nameWithID(Opc) + << '\n'; + o.indent(Indentation) << "}\n"; + + return false; +} + +// Emits code to decode the singleton, and then to decode the rest. +void FilterChooser::emitSingletonDecoder(raw_ostream &o, unsigned &Indentation, + Filter &Best) { + + unsigned Opc = Best.getSingletonOpc(); + + emitSingletonDecoder(o, Indentation, Opc); + + // Emit code for the rest. + o.indent(Indentation) << "else\n"; + + Indentation += 2; + Best.getVariableFC().emit(o, Indentation); + Indentation -= 2; +} + +// Assign a single filter and run with it. Top level API client can initialize +// with a single filter to start the filtering process. +void FilterChooser::runSingleFilter(FilterChooser &owner, unsigned startBit, + unsigned numBit, bool mixed) { + Filters.clear(); + Filter F(*this, startBit, numBit, true); + Filters.push_back(F); + BestIndex = 0; // Sole Filter instance to choose from. + bestFilter().recurse(); +} + +// reportRegion is a helper function for filterProcessor to mark a region as +// eligible for use as a filter region. +void FilterChooser::reportRegion(bitAttr_t RA, unsigned StartBit, + unsigned BitIndex, bool AllowMixed) { + if (RA == ATTR_MIXED && AllowMixed) + Filters.push_back(Filter(*this, StartBit, BitIndex - StartBit, true)); + else if (RA == ATTR_ALL_SET && !AllowMixed) + Filters.push_back(Filter(*this, StartBit, BitIndex - StartBit, false)); +} + +// FilterProcessor scans the well-known encoding bits of the instructions and +// builds up a list of candidate filters. It chooses the best filter and +// recursively descends down the decoding tree. +bool FilterChooser::filterProcessor(bool AllowMixed, bool Greedy) { + Filters.clear(); + BestIndex = -1; + unsigned numInstructions = Opcodes.size(); + + assert(numInstructions && "Filter created with no instructions"); + + // No further filtering is necessary. + if (numInstructions == 1) + return true; + + // Heuristics. See also doFilter()'s "Heuristics" comment when num of + // instructions is 3. + if (AllowMixed && !Greedy) { + assert(numInstructions == 3); + + for (unsigned i = 0; i < Opcodes.size(); ++i) { + std::vector StartBits; + std::vector EndBits; + std::vector FieldVals; + insn_t Insn; + + insnWithID(Insn, Opcodes[i]); + + // Look for islands of undecoded bits of any instruction. + if (getIslands(StartBits, EndBits, FieldVals, Insn) > 0) { + // Found an instruction with island(s). Now just assign a filter. + runSingleFilter(*this, StartBits[0], EndBits[0] - StartBits[0] + 1, + true); + return true; + } + } + } + + unsigned BitIndex, InsnIndex; + + // We maintain BIT_WIDTH copies of the bitAttrs automaton. + // The automaton consumes the corresponding bit from each + // instruction. + // + // Input symbols: 0, 1, and _ (unset). + // States: NONE, FILTERED, ALL_SET, ALL_UNSET, and MIXED. + // Initial state: NONE. + // + // (NONE) ------- [01] -> (ALL_SET) + // (NONE) ------- _ ----> (ALL_UNSET) + // (ALL_SET) ---- [01] -> (ALL_SET) + // (ALL_SET) ---- _ ----> (MIXED) + // (ALL_UNSET) -- [01] -> (MIXED) + // (ALL_UNSET) -- _ ----> (ALL_UNSET) + // (MIXED) ------ . ----> (MIXED) + // (FILTERED)---- . ----> (FILTERED) + + bitAttr_t bitAttrs[BIT_WIDTH]; + + // FILTERED bit positions provide no entropy and are not worthy of pursuing. + // Filter::recurse() set either BIT_TRUE or BIT_FALSE for each position. + for (BitIndex = 0; BitIndex < BIT_WIDTH; ++BitIndex) + if (FilterBitValues[BitIndex] == BIT_TRUE || + FilterBitValues[BitIndex] == BIT_FALSE) + bitAttrs[BitIndex] = ATTR_FILTERED; + else + bitAttrs[BitIndex] = ATTR_NONE; + + for (InsnIndex = 0; InsnIndex < numInstructions; ++InsnIndex) { + insn_t insn; + + insnWithID(insn, Opcodes[InsnIndex]); + + for (BitIndex = 0; BitIndex < BIT_WIDTH; ++BitIndex) { + switch (bitAttrs[BitIndex]) { + case ATTR_NONE: + if (insn[BitIndex] == BIT_UNSET) + bitAttrs[BitIndex] = ATTR_ALL_UNSET; + else + bitAttrs[BitIndex] = ATTR_ALL_SET; + break; + case ATTR_ALL_SET: + if (insn[BitIndex] == BIT_UNSET) + bitAttrs[BitIndex] = ATTR_MIXED; + break; + case ATTR_ALL_UNSET: + if (insn[BitIndex] != BIT_UNSET) + bitAttrs[BitIndex] = ATTR_MIXED; + break; + case ATTR_MIXED: + case ATTR_FILTERED: + break; + } + } + } + + // The regionAttr automaton consumes the bitAttrs automatons' state, + // lowest-to-highest. + // + // Input symbols: F(iltered), (all_)S(et), (all_)U(nset), M(ixed) + // States: NONE, ALL_SET, MIXED + // Initial state: NONE + // + // (NONE) ----- F --> (NONE) + // (NONE) ----- S --> (ALL_SET) ; and set region start + // (NONE) ----- U --> (NONE) + // (NONE) ----- M --> (MIXED) ; and set region start + // (ALL_SET) -- F --> (NONE) ; and report an ALL_SET region + // (ALL_SET) -- S --> (ALL_SET) + // (ALL_SET) -- U --> (NONE) ; and report an ALL_SET region + // (ALL_SET) -- M --> (MIXED) ; and report an ALL_SET region + // (MIXED) ---- F --> (NONE) ; and report a MIXED region + // (MIXED) ---- S --> (ALL_SET) ; and report a MIXED region + // (MIXED) ---- U --> (NONE) ; and report a MIXED region + // (MIXED) ---- M --> (MIXED) + + bitAttr_t RA = ATTR_NONE; + unsigned StartBit = 0; + + for (BitIndex = 0; BitIndex < BIT_WIDTH; BitIndex++) { + bitAttr_t bitAttr = bitAttrs[BitIndex]; + + assert(bitAttr != ATTR_NONE && "Bit without attributes"); + + switch (RA) { + case ATTR_NONE: + switch (bitAttr) { + case ATTR_FILTERED: + break; + case ATTR_ALL_SET: + StartBit = BitIndex; + RA = ATTR_ALL_SET; + break; + case ATTR_ALL_UNSET: + break; + case ATTR_MIXED: + StartBit = BitIndex; + RA = ATTR_MIXED; + break; + default: + assert(0 && "Unexpected bitAttr!"); + } + break; + case ATTR_ALL_SET: + switch (bitAttr) { + case ATTR_FILTERED: + reportRegion(RA, StartBit, BitIndex, AllowMixed); + RA = ATTR_NONE; + break; + case ATTR_ALL_SET: + break; + case ATTR_ALL_UNSET: + reportRegion(RA, StartBit, BitIndex, AllowMixed); + RA = ATTR_NONE; + break; + case ATTR_MIXED: + reportRegion(RA, StartBit, BitIndex, AllowMixed); + StartBit = BitIndex; + RA = ATTR_MIXED; + break; + default: + assert(0 && "Unexpected bitAttr!"); + } + break; + case ATTR_MIXED: + switch (bitAttr) { + case ATTR_FILTERED: + reportRegion(RA, StartBit, BitIndex, AllowMixed); + StartBit = BitIndex; + RA = ATTR_NONE; + break; + case ATTR_ALL_SET: + reportRegion(RA, StartBit, BitIndex, AllowMixed); + StartBit = BitIndex; + RA = ATTR_ALL_SET; + break; + case ATTR_ALL_UNSET: + reportRegion(RA, StartBit, BitIndex, AllowMixed); + RA = ATTR_NONE; + break; + case ATTR_MIXED: + break; + default: + assert(0 && "Unexpected bitAttr!"); + } + break; + case ATTR_ALL_UNSET: + assert(0 && "regionAttr state machine has no ATTR_UNSET state"); + case ATTR_FILTERED: + assert(0 && "regionAttr state machine has no ATTR_FILTERED state"); + } + } + + // At the end, if we're still in ALL_SET or MIXED states, report a region + switch (RA) { + case ATTR_NONE: + break; + case ATTR_FILTERED: + break; + case ATTR_ALL_SET: + reportRegion(RA, StartBit, BitIndex, AllowMixed); + break; + case ATTR_ALL_UNSET: + break; + case ATTR_MIXED: + reportRegion(RA, StartBit, BitIndex, AllowMixed); + break; + } + + // We have finished with the filter processings. Now it's time to choose + // the best performing filter. + BestIndex = 0; + bool AllUseless = true; + unsigned BestScore = 0; + + for (unsigned i = 0, e = Filters.size(); i != e; ++i) { + unsigned Usefulness = Filters[i].usefulness(); + + if (Usefulness) + AllUseless = false; + + if (Usefulness > BestScore) { + BestIndex = i; + BestScore = Usefulness; + } + } + + if (!AllUseless) + bestFilter().recurse(); + + return !AllUseless; +} // end of FilterChooser::filterProcessor(bool) + +// Decides on the best configuration of filter(s) to use in order to decode +// the instructions. A conflict of instructions may occur, in which case we +// dump the conflict set to the standard error. +void FilterChooser::doFilter() { + unsigned Num = Opcodes.size(); + assert(Num && "FilterChooser created with no instructions"); + + // Try regions of consecutive known bit values first. + if (filterProcessor(false)) + return; + + // Then regions of mixed bits (both known and unitialized bit values allowed). + if (filterProcessor(true)) + return; + + // Heuristics to cope with conflict set {t2CMPrs, t2SUBSrr, t2SUBSrs} where + // no single instruction for the maximum ATTR_MIXED region Inst{14-4} has a + // well-known encoding pattern. In such case, we backtrack and scan for the + // the very first consecutive ATTR_ALL_SET region and assign a filter to it. + if (Num == 3 && filterProcessor(true, false)) + return; + + // If we come to here, the instruction decoding has failed. + // Set the BestIndex to -1 to indicate so. + BestIndex = -1; +} + +// Emits code to decode our share of instructions. Returns true if the +// emitted code causes a return, which occurs if we know how to decode +// the instruction at this level or the instruction is not decodeable. +bool FilterChooser::emit(raw_ostream &o, unsigned &Indentation) { + if (Opcodes.size() == 1) + // There is only one instruction in the set, which is great! + // Call emitSingletonDecoder() to see whether there are any remaining + // encodings bits. + return emitSingletonDecoder(o, Indentation, Opcodes[0]); + + // Choose the best filter to do the decodings! + if (BestIndex != -1) { + Filter &Best = bestFilter(); + if (Best.getNumFiltered() == 1) + emitSingletonDecoder(o, Indentation, Best); + else + bestFilter().emit(o, Indentation); + return false; + } + + // We don't know how to decode these instructions! Return 0 and dump the + // conflict set! + o.indent(Indentation) << "return 0;" << " // Conflict set: "; + for (int i = 0, N = Opcodes.size(); i < N; ++i) { + o << nameWithID(Opcodes[i]); + if (i < (N - 1)) + o << ", "; + else + o << '\n'; + } + + // Print out useful conflict information for postmortem analysis. + errs() << "Decoding Conflict:\n"; + + dumpStack(errs(), "\t\t"); + + for (unsigned i = 0; i < Opcodes.size(); i++) { + const std::string &Name = nameWithID(Opcodes[i]); + + errs() << '\t' << Name << " "; + dumpBits(errs(), + getBitsField(*AllInstructions[Opcodes[i]]->TheDef, "Inst")); + errs() << '\n'; + } + + return true; +} + +bool FixedLenDecoderEmitter::populateInstruction(const CodeGenInstruction &CGI, + unsigned Opc){ + const Record &Def = *CGI.TheDef; + // If all the bit positions are not specified; do not decode this instruction. + // We are bound to fail! For proper disassembly, the well-known encoding bits + // of the instruction must be fully specified. + // + // This also removes pseudo instructions from considerations of disassembly, + // which is a better design and less fragile than the name matchings. + BitsInit &Bits = getBitsField(Def, "Inst"); + if (Bits.allInComplete()) return false; + + // Ignore "asm parser only" instructions. + if (Def.getValueAsBit("isAsmParserOnly")) + return false; + + std::vector InsnOperands; + + // If the instruction has specified a custom decoding hook, use that instead + // of trying to auto-generate the decoder. + std::string InstDecoder = Def.getValueAsString("DecoderMethod"); + if (InstDecoder != "") { + InsnOperands.push_back(OperandInfo(~0U, ~0U, InstDecoder)); + Operands[Opc] = InsnOperands; + return true; + } + + // Generate a description of the operand of the instruction that we know + // how to decode automatically. + // FIXME: We'll need to have a way to manually override this as needed. + + // Gather the outputs/inputs of the instruction, so we can find their + // positions in the encoding. This assumes for now that they appear in the + // MCInst in the order that they're listed. + std::vector > InOutOperands; + DagInit *Out = Def.getValueAsDag("OutOperandList"); + DagInit *In = Def.getValueAsDag("InOperandList"); + for (unsigned i = 0; i < Out->getNumArgs(); ++i) + InOutOperands.push_back(std::make_pair(Out->getArg(i), Out->getArgName(i))); + for (unsigned i = 0; i < In->getNumArgs(); ++i) + InOutOperands.push_back(std::make_pair(In->getArg(i), In->getArgName(i))); + + // For each operand, see if we can figure out where it is encoded. + for (std::vector >::iterator + NI = InOutOperands.begin(), NE = InOutOperands.end(); NI != NE; ++NI) { + unsigned PrevBit = ~0; + unsigned Base = ~0; + unsigned PrevPos = ~0; + std::string Decoder = ""; + + for (unsigned bi = 0; bi < Bits.getNumBits(); ++bi) { + VarBitInit *BI = dynamic_cast(Bits.getBit(bi)); + if (!BI) continue; + + VarInit *Var = dynamic_cast(BI->getVariable()); + assert(Var); + unsigned CurrBit = BI->getBitNum(); + if (Var->getName() != NI->second) continue; + + // Figure out the lowest bit of the value, and the width of the field. + // Deliberately don't try to handle cases where the field is scattered, + // or where not all bits of the the field are explicit. + if (Base == ~0U && PrevBit == ~0U && PrevPos == ~0U) { + if (CurrBit == 0) + Base = bi; + else + continue; + } + + if ((PrevPos != ~0U && bi-1 != PrevPos) || + (CurrBit != ~0U && CurrBit-1 != PrevBit)) { + PrevBit = ~0; + Base = ~0; + PrevPos = ~0; + } + + PrevPos = bi; + PrevBit = CurrBit; + + // At this point, we can locate the field, but we need to know how to + // interpret it. As a first step, require the target to provide callbacks + // for decoding register classes. + // FIXME: This need to be extended to handle instructions with custom + // decoder methods, and operands with (simple) MIOperandInfo's. + TypedInit *TI = dynamic_cast(NI->first); + RecordRecTy *Type = dynamic_cast(TI->getType()); + Record *TypeRecord = Type->getRecord(); + bool isReg = false; + if (TypeRecord->isSubClassOf("RegisterClass")) { + Decoder = "Decode" + Type->getRecord()->getName() + "RegisterClass"; + isReg = true; + } + + RecordVal *DecoderString = TypeRecord->getValue("DecoderMethod"); + StringInit *String = DecoderString ? + dynamic_cast(DecoderString->getValue()) : + 0; + if (!isReg && String && String->getValue() != "") + Decoder = String->getValue(); + } + + if (Base != ~0U) { + InsnOperands.push_back(OperandInfo(Base, PrevBit+1, Decoder)); + DEBUG(errs() << "ENCODED OPERAND: $" << NI->second << " @ (" + << utostr(Base+PrevBit) << ", " << utostr(Base) << ")\n"); + } + } + + Operands[Opc] = InsnOperands; + + +#if 0 + DEBUG({ + // Dumps the instruction encoding bits. + dumpBits(errs(), Bits); + + errs() << '\n'; + + // Dumps the list of operand info. + for (unsigned i = 0, e = CGI.Operands.size(); i != e; ++i) { + const CGIOperandList::OperandInfo &Info = CGI.Operands[i]; + const std::string &OperandName = Info.Name; + const Record &OperandDef = *Info.Rec; + + errs() << "\t" << OperandName << " (" << OperandDef.getName() << ")\n"; + } + }); +#endif + + return true; +} + +void FixedLenDecoderEmitter::populateInstructions() { + for (unsigned i = 0, e = NumberedInstructions.size(); i < e; ++i) { + Record *R = NumberedInstructions[i]->TheDef; + if (R->getValueAsString("Namespace") == "TargetOpcode") + continue; + + if (populateInstruction(*NumberedInstructions[i], i)) + Opcodes.push_back(i); + } +} + +// Emits disassembler code for instruction decoding. +void FixedLenDecoderEmitter::run(raw_ostream &o) +{ + o << "#include \"llvm/MC/MCInst.h\"\n"; + o << "#include \"llvm/Support/DataTypes.h\"\n"; + o << "#include \n"; + o << '\n'; + o << "namespace llvm {\n\n"; + + NumberedInstructions = Target.getInstructionsByEnumValue(); + populateInstructions(); + FilterChooser FC(NumberedInstructions, Opcodes, Operands); + FC.emitTop(o, 0); + + o << "\n} // End llvm namespace \n"; +} diff --git a/utils/TableGen/FixedLenDecoderEmitter.h b/utils/TableGen/FixedLenDecoderEmitter.h new file mode 100644 index 000000000000..d46a495540ea --- /dev/null +++ b/utils/TableGen/FixedLenDecoderEmitter.h @@ -0,0 +1,56 @@ +//===------------ FixedLenDecoderEmitter.h - Decoder Generator --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// It contains the tablegen backend that emits the decoder functions for +// targets with fixed length instruction set. +// +//===----------------------------------------------------------------------===// + +#ifndef FixedLenDECODEREMITTER_H +#define FixedLenDECODEREMITTER_H + +#include "CodeGenTarget.h" +#include "TableGenBackend.h" + +#include "llvm/Support/DataTypes.h" + +namespace llvm { + +struct OperandInfo { + unsigned FieldBase; + unsigned FieldLength; + std::string Decoder; + + OperandInfo(unsigned FB, unsigned FL, std::string D) + : FieldBase(FB), FieldLength(FL), Decoder(D) { } +}; + +class FixedLenDecoderEmitter : public TableGenBackend { +public: + FixedLenDecoderEmitter(RecordKeeper &R) : + Records(R), Target(R), + NumberedInstructions(Target.getInstructionsByEnumValue()) {} + + // run - Output the code emitter + void run(raw_ostream &o); + +private: + RecordKeeper &Records; + CodeGenTarget Target; + std::vector NumberedInstructions; + std::vector Opcodes; + std::map > Operands; + + bool populateInstruction(const CodeGenInstruction &CGI, unsigned Opc); + void populateInstructions(); +}; + +} // end llvm namespace + +#endif diff --git a/utils/TableGen/InstrEnumEmitter.cpp b/utils/TableGen/InstrEnumEmitter.cpp index 47a8474c35ec..aa596892f52f 100644 --- a/utils/TableGen/InstrEnumEmitter.cpp +++ b/utils/TableGen/InstrEnumEmitter.cpp @@ -23,7 +23,7 @@ void InstrEnumEmitter::run(raw_ostream &OS) { EmitSourceFileHeader("Target Instruction Enum Values", OS); OS << "namespace llvm {\n\n"; - CodeGenTarget Target; + CodeGenTarget Target(Records); // We must emit the PHI opcode first... std::string Namespace = Target.getInstNamespace(); diff --git a/utils/TableGen/InstrInfoEmitter.cpp b/utils/TableGen/InstrInfoEmitter.cpp index 4d3aa5e621c9..2b684bede3ea 100644 --- a/utils/TableGen/InstrInfoEmitter.cpp +++ b/utils/TableGen/InstrInfoEmitter.cpp @@ -60,23 +60,23 @@ std::vector InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) { std::vector Result; - for (unsigned i = 0, e = Inst.OperandList.size(); i != e; ++i) { + for (unsigned i = 0, e = Inst.Operands.size(); i != e; ++i) { // Handle aggregate operands and normal operands the same way by expanding // either case into a list of operands for this op. - std::vector OperandList; + std::vector OperandList; // This might be a multiple operand thing. Targets like X86 have // registers in their multi-operand operands. It may also be an anonymous // operand, which has a single operand, but no declared class for the // operand. - DagInit *MIOI = Inst.OperandList[i].MIOperandInfo; + DagInit *MIOI = Inst.Operands[i].MIOperandInfo; if (!MIOI || MIOI->getNumArgs() == 0) { // Single, anonymous, operand. - OperandList.push_back(Inst.OperandList[i]); + OperandList.push_back(Inst.Operands[i]); } else { - for (unsigned j = 0, e = Inst.OperandList[i].MINumOperands; j != e; ++j) { - OperandList.push_back(Inst.OperandList[i]); + for (unsigned j = 0, e = Inst.Operands[i].MINumOperands; j != e; ++j) { + OperandList.push_back(Inst.Operands[i]); Record *OpR = dynamic_cast(MIOI->getArg(j))->getDef(); OperandList.back().Rec = OpR; @@ -104,19 +104,19 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) { // Predicate operands. Check to see if the original unexpanded operand // was of type PredicateOperand. - if (Inst.OperandList[i].Rec->isSubClassOf("PredicateOperand")) + if (Inst.Operands[i].Rec->isSubClassOf("PredicateOperand")) Res += "|(1<isSubClassOf("OptionalDefOperand")) + if (Inst.Operands[i].Rec->isSubClassOf("OptionalDefOperand")) Res += "|(1<getName() << "\", 0"; // Emit all of the target indepedent flags... @@ -271,6 +271,7 @@ void InstrInfoEmitter::emitRecord(const CodeGenInstruction &Inst, unsigned Num, if (Inst.isBranch) OS << "|(1< using namespace llvm; @@ -67,16 +68,19 @@ void IntrinsicEmitter::run(raw_ostream &OS) { void IntrinsicEmitter::EmitPrefix(raw_ostream &OS) { OS << "// VisualStudio defines setjmp as _setjmp\n" - "#if defined(_MSC_VER) && defined(setjmp)\n" - "#define setjmp_undefined_for_visual_studio\n" - "#undef setjmp\n" + "#if defined(_MSC_VER) && defined(setjmp) && \\\n" + " !defined(setjmp_undefined_for_msvc)\n" + "# pragma push_macro(\"setjmp\")\n" + "# undef setjmp\n" + "# define setjmp_undefined_for_msvc\n" "#endif\n\n"; } void IntrinsicEmitter::EmitSuffix(raw_ostream &OS) { - OS << "#if defined(_MSC_VER) && defined(setjmp_undefined_for_visual_studio)\n" + OS << "#if defined(_MSC_VER) && defined(setjmp_undefined_for_msvc)\n" "// let's return it to _setjmp state\n" - "#define setjmp _setjmp\n" + "# pragma pop_macro(\"setjmp\")\n" + "# undef setjmp_undefined_for_msvc\n" "#endif\n\n"; } @@ -96,37 +100,48 @@ void IntrinsicEmitter::EmitEnumInfo(const std::vector &Ints, void IntrinsicEmitter:: EmitFnNameRecognizer(const std::vector &Ints, raw_ostream &OS) { - // Build a function name -> intrinsic name mapping. - std::map IntMapping; + // Build a 'first character of function name' -> intrinsic # mapping. + std::map > IntMapping; for (unsigned i = 0, e = Ints.size(); i != e; ++i) - IntMapping[Ints[i].Name] = i; - + IntMapping[Ints[i].Name[5]].push_back(i); + OS << "// Function name -> enum value recognizer code.\n"; OS << "#ifdef GET_FUNCTION_RECOGNIZER\n"; - OS << " switch (Name[5]) {\n"; - OS << " default:\n"; - // Emit the intrinsics in sorted order. - char LastChar = 0; - for (std::map::iterator I = IntMapping.begin(), + OS << " StringRef NameR(Name+6, Len-6); // Skip over 'llvm.'\n"; + OS << " switch (Name[5]) { // Dispatch on first letter.\n"; + OS << " default: break;\n"; + // Emit the intrinsic matching stuff by first letter. + for (std::map >::iterator I = IntMapping.begin(), E = IntMapping.end(); I != E; ++I) { - if (I->first[5] != LastChar) { - LastChar = I->first[5]; - OS << " break;\n"; - OS << " case '" << LastChar << "':\n"; + OS << " case '" << I->first << "':\n"; + std::vector &IntList = I->second; + + // Emit all the overloaded intrinsics first, build a table of the + // non-overloaded ones. + std::vector MatchTable; + + for (unsigned i = 0, e = IntList.size(); i != e; ++i) { + unsigned IntNo = IntList[i]; + std::string Result = "return " + TargetPrefix + "Intrinsic::" + + Ints[IntNo].EnumName + ";"; + + if (!Ints[IntNo].isOverloaded) { + MatchTable.push_back(std::make_pair(Ints[IntNo].Name.substr(6),Result)); + continue; + } + + // For overloaded intrinsics, only the prefix needs to match + std::string TheStr = Ints[IntNo].Name.substr(6); + TheStr += '.'; // Require "bswap." instead of bswap. + OS << " if (NameR.startswith(\"" << TheStr << "\")) " + << Result << '\n'; } - // For overloaded intrinsics, only the prefix needs to match - if (Ints[I->second].isOverloaded) - OS << " if (Len > " << I->first.size() - << " && !memcmp(Name, \"" << I->first << ".\", " - << (I->first.size() + 1) << ")) return " << TargetPrefix << "Intrinsic::" - << Ints[I->second].EnumName << ";\n"; - else - OS << " if (Len == " << I->first.size() - << " && !memcmp(Name, \"" << I->first << "\", " - << I->first.size() << ")) return " << TargetPrefix << "Intrinsic::" - << Ints[I->second].EnumName << ";\n"; + // Emit the matcher logic for the fixed length strings. + StringMatcher("NameR", MatchTable, OS).Emit(1); + OS << " break; // end of '" << I->first << "' case.\n"; } + OS << " }\n"; OS << "#endif\n\n"; } @@ -180,6 +195,8 @@ static void EmitTypeForValueType(raw_ostream &OS, MVT::SimpleValueType VT) { OS << "Type::getVoidTy(Context)"; } else if (VT == MVT::Metadata) { OS << "Type::getMetadataTy(Context)"; + } else if (VT == MVT::x86mmx) { + OS << "Type::getX86_MMXTy(Context)"; } else { assert(false && "Unsupported ValueType!"); } @@ -556,11 +573,13 @@ EmitModRefBehavior(const std::vector &Ints, raw_ostream &OS){ OS << " return DoesNotAccessMemory;\n"; break; case CodeGenIntrinsic::ReadArgMem: + OS << " return OnlyReadsArgumentPointees;\n"; + break; case CodeGenIntrinsic::ReadMem: OS << " return OnlyReadsMemory;\n"; break; case CodeGenIntrinsic::ReadWriteArgMem: - OS << " return AccessesArguments;\n"; + OS << " return OnlyAccessesArgumentPointees;\n"; break; } } @@ -584,112 +603,22 @@ EmitGCCBuiltinList(const std::vector &Ints, raw_ostream &OS){ OS << "#endif\n\n"; } -/// EmitBuiltinComparisons - Emit comparisons to determine whether the specified -/// sorted range of builtin names is equal to the current builtin. This breaks -/// it down into a simple tree. -/// -/// At this point, we know that all the builtins in the range have the same name -/// for the first 'CharStart' characters. Only the end of the name needs to be -/// discriminated. -typedef std::map::const_iterator StrMapIterator; -static void EmitBuiltinComparisons(StrMapIterator Start, StrMapIterator End, - unsigned CharStart, unsigned Indent, - std::string TargetPrefix, raw_ostream &OS) { - if (Start == End) return; // empty range. - - // Determine what, if anything, is the same about all these strings. - std::string CommonString = Start->first; - unsigned NumInRange = 0; - for (StrMapIterator I = Start; I != End; ++I, ++NumInRange) { - // Find the first character that doesn't match. - const std::string &ThisStr = I->first; - unsigned NonMatchChar = CharStart; - while (NonMatchChar < CommonString.size() && - NonMatchChar < ThisStr.size() && - CommonString[NonMatchChar] == ThisStr[NonMatchChar]) - ++NonMatchChar; - // Truncate off pieces that don't match. - CommonString.resize(NonMatchChar); - } - - // Just compare the rest of the string. - if (NumInRange == 1) { - if (CharStart != CommonString.size()) { - OS << std::string(Indent*2, ' ') << "if (!memcmp(BuiltinName"; - if (CharStart) OS << "+" << CharStart; - OS << ", \"" << (CommonString.c_str()+CharStart) << "\", "; - OS << CommonString.size() - CharStart << "))\n"; - ++Indent; - } - OS << std::string(Indent*2, ' ') << "IntrinsicID = " << TargetPrefix - << "Intrinsic::"; - OS << Start->second << ";\n"; - return; - } - - // At this point, we potentially have a common prefix for these builtins, emit - // a check for this common prefix. - if (CommonString.size() != CharStart) { - OS << std::string(Indent*2, ' ') << "if (!memcmp(BuiltinName"; - if (CharStart) OS << "+" << CharStart; - OS << ", \"" << (CommonString.c_str()+CharStart) << "\", "; - OS << CommonString.size()-CharStart << ")) {\n"; - - EmitBuiltinComparisons(Start, End, CommonString.size(), Indent+1, - TargetPrefix, OS); - OS << std::string(Indent*2, ' ') << "}\n"; - return; - } - - // Output a switch on the character that differs across the set. - OS << std::string(Indent*2, ' ') << "switch (BuiltinName[" << CharStart - << "]) {"; - if (CharStart) - OS << " // \"" << std::string(Start->first.begin(), - Start->first.begin()+CharStart) << "\""; - OS << "\n"; - - for (StrMapIterator I = Start; I != End; ) { - char ThisChar = I->first[CharStart]; - OS << std::string(Indent*2, ' ') << "case '" << ThisChar << "':\n"; - // Figure out the range that has this common character. - StrMapIterator NextChar = I; - for (++NextChar; NextChar != End && NextChar->first[CharStart] == ThisChar; - ++NextChar) - /*empty*/; - EmitBuiltinComparisons(I, NextChar, CharStart+1, Indent+1, TargetPrefix,OS); - OS << std::string(Indent*2, ' ') << " break;\n"; - I = NextChar; - } - OS << std::string(Indent*2, ' ') << "}\n"; -} - /// EmitTargetBuiltins - All of the builtins in the specified map are for the /// same target, and we already checked it. static void EmitTargetBuiltins(const std::map &BIM, const std::string &TargetPrefix, raw_ostream &OS) { - // Rearrange the builtins by length. - std::vector > BuiltinsByLen; - BuiltinsByLen.reserve(100); - for (StrMapIterator I = BIM.begin(), E = BIM.end(); I != E; ++I) { - if (I->first.size() >= BuiltinsByLen.size()) - BuiltinsByLen.resize(I->first.size()+1); - BuiltinsByLen[I->first.size()].insert(*I); - } + std::vector Results; - // Now that we have all the builtins by their length, emit a switch stmt. - OS << " switch (strlen(BuiltinName)) {\n"; - OS << " default: break;\n"; - for (unsigned i = 0, e = BuiltinsByLen.size(); i != e; ++i) { - if (BuiltinsByLen[i].empty()) continue; - OS << " case " << i << ":\n"; - EmitBuiltinComparisons(BuiltinsByLen[i].begin(), BuiltinsByLen[i].end(), - 0, 3, TargetPrefix, OS); - OS << " break;\n"; + for (std::map::const_iterator I = BIM.begin(), + E = BIM.end(); I != E; ++I) { + std::string ResultCode = + "return " + TargetPrefix + "Intrinsic::" + I->second + ";"; + Results.push_back(StringMatcher::StringPair(I->first, ResultCode)); } - OS << " }\n"; + + StringMatcher("BuiltinName", Results, OS).Emit(); } @@ -719,24 +648,20 @@ EmitIntrinsicToGCCBuiltinMap(const std::vector &Ints, if (TargetOnly) { OS << "static " << TargetPrefix << "Intrinsic::ID " << "getIntrinsicForGCCBuiltin(const char " - << "*TargetPrefix, const char *BuiltinName) {\n"; - OS << " " << TargetPrefix << "Intrinsic::ID IntrinsicID = "; + << "*TargetPrefixStr, const char *BuiltinNameStr) {\n"; } else { OS << "Intrinsic::ID Intrinsic::getIntrinsicForGCCBuiltin(const char " - << "*TargetPrefix, const char *BuiltinName) {\n"; - OS << " Intrinsic::ID IntrinsicID = "; + << "*TargetPrefixStr, const char *BuiltinNameStr) {\n"; } - if (TargetOnly) - OS << "(" << TargetPrefix<< "Intrinsic::ID)"; - - OS << "Intrinsic::not_intrinsic;\n"; + OS << " StringRef BuiltinName(BuiltinNameStr);\n"; + OS << " StringRef TargetPrefix(TargetPrefixStr);\n\n"; // Note: this could emit significantly better code if we cared. for (BIMTy::iterator I = BuiltinMap.begin(), E = BuiltinMap.end();I != E;++I){ OS << " "; if (!I->first.empty()) - OS << "if (!strcmp(TargetPrefix, \"" << I->first << "\")) "; + OS << "if (TargetPrefix == \"" << I->first << "\") "; else OS << "/* Target Independent Builtins */ "; OS << "{\n"; @@ -745,7 +670,10 @@ EmitIntrinsicToGCCBuiltinMap(const std::vector &Ints, EmitTargetBuiltins(I->second, TargetPrefix, OS); OS << " }\n"; } - OS << " return IntrinsicID;\n"; + OS << " return "; + if (!TargetPrefix.empty()) + OS << "(" << TargetPrefix << "Intrinsic::ID)"; + OS << "Intrinsic::not_intrinsic;\n"; OS << "}\n"; OS << "#endif\n\n"; } diff --git a/utils/TableGen/LLVMCConfigurationEmitter.cpp b/utils/TableGen/LLVMCConfigurationEmitter.cpp index 8b81e14cc26a..c40a39dff729 100644 --- a/utils/TableGen/LLVMCConfigurationEmitter.cpp +++ b/utils/TableGen/LLVMCConfigurationEmitter.cpp @@ -25,6 +25,7 @@ #include #include + using namespace llvm; namespace { @@ -164,18 +165,6 @@ void CheckedIncrement(I& P, I E, S ErrorString) { throw ErrorString; } -// apply is needed because C++'s syntax doesn't let us construct a function -// object and call it in the same statement. -template -void apply(F Fun, T0& Arg0) { - return Fun(Arg0); -} - -template -void apply(F Fun, T0& Arg0, T1& Arg1) { - return Fun(Arg0, Arg1); -} - //===----------------------------------------------------------------------===// /// Back-end specific code @@ -779,14 +768,21 @@ public: CheckNumberOfArguments(d, 2); + // Alias option store the aliased option name in the 'Help' field and do not + // have any properties. if (OD.isAlias()) { - // Aliases store the aliased option name in the 'Help' field. OD.Help = InitPtrToString(d.getArg(1)); } else { processOptionProperties(d, OD); } + // Switch options are ZeroOrMore by default. + if (OD.isSwitch()) { + if (!(OD.isOptional() || OD.isOneOrMore() || OD.isRequired())) + OD.setZeroOrMore(); + } + OptDescs_.InsertDescription(OD); } @@ -809,13 +805,12 @@ void CollectOptionDescriptions (const RecordVector& V, OptionDescriptions& OptDescs) { // For every OptionList: - for (RecordVector::const_iterator B = V.begin(), - E = V.end(); B!=E; ++B) { + for (RecordVector::const_iterator B = V.begin(), E = V.end(); B!=E; ++B) + { // Throws an exception if the value does not exist. ListInit* PropList = (*B)->getValueAsListInit("options"); - // For every option description in this list: - // collect the information and + // For every option description in this list: invoke AddOption. std::for_each(PropList->begin(), PropList->end(), AddOption(OptDescs)); } } @@ -833,7 +828,7 @@ struct ToolDescription : public RefCountedBase { StrVector InLanguage; std::string InFileOption; std::string OutFileOption; - std::string OutLanguage; + StrVector OutLanguage; std::string OutputSuffix; unsigned Flags; const Init* OnEmpty; @@ -919,31 +914,24 @@ private: toolDesc_.CmdLine = d.getArg(0); } - void onInLanguage (const DagInit& d) { + /// onInOutLanguage - Common implementation of on{In,Out}Language(). + void onInOutLanguage (const DagInit& d, StrVector& OutVec) { CheckNumberOfArguments(d, 1); - Init* arg = d.getArg(0); - // Find out the argument's type. - if (typeid(*arg) == typeid(StringInit)) { - // It's a string. - toolDesc_.InLanguage.push_back(InitPtrToString(arg)); + // Copy strings to the output vector. + for (unsigned i = 0, NumArgs = d.getNumArgs(); i < NumArgs; ++i) { + OutVec.push_back(InitPtrToString(d.getArg(i))); } - else { - // It's a list. - const ListInit& lst = InitPtrToList(arg); - StrVector& out = toolDesc_.InLanguage; - // Copy strings to the output vector. - for (ListInit::const_iterator B = lst.begin(), E = lst.end(); - B != E; ++B) { - out.push_back(InitPtrToString(*B)); - } + // Remove duplicates. + std::sort(OutVec.begin(), OutVec.end()); + StrVector::iterator newE = std::unique(OutVec.begin(), OutVec.end()); + OutVec.erase(newE, OutVec.end()); + } - // Remove duplicates. - std::sort(out.begin(), out.end()); - StrVector::iterator newE = std::unique(out.begin(), out.end()); - out.erase(newE, out.end()); - } + + void onInLanguage (const DagInit& d) { + this->onInOutLanguage(d, toolDesc_.InLanguage); } void onJoin (const DagInit& d) { @@ -952,8 +940,7 @@ private: } void onOutLanguage (const DagInit& d) { - CheckNumberOfArguments(d, 1); - toolDesc_.OutLanguage = InitPtrToString(d.getArg(0)); + this->onInOutLanguage(d, toolDesc_.OutLanguage); } void onOutFileOption (const DagInit& d) { @@ -1062,47 +1049,62 @@ void FilterNotInGraph (const DagVector& EdgeVector, } /// FillInToolToLang - Fills in two tables that map tool names to -/// (input, output) languages. Helper function used by TypecheckGraph(). +/// input & output language names. Helper function used by TypecheckGraph(). void FillInToolToLang (const ToolDescriptions& ToolDescs, StringMap >& ToolToInLang, - StringMap& ToolToOutLang) { + StringMap >& ToolToOutLang) { for (ToolDescriptions::const_iterator B = ToolDescs.begin(), E = ToolDescs.end(); B != E; ++B) { const ToolDescription& D = *(*B); for (StrVector::const_iterator B = D.InLanguage.begin(), E = D.InLanguage.end(); B != E; ++B) ToolToInLang[D.Name].insert(*B); - ToolToOutLang[D.Name] = D.OutLanguage; + for (StrVector::const_iterator B = D.OutLanguage.begin(), + E = D.OutLanguage.end(); B != E; ++B) + ToolToOutLang[D.Name].insert(*B); } } +/// Intersect - Is set intersection non-empty? +bool Intersect (const StringSet<>& S1, const StringSet<>& S2) { + for (StringSet<>::const_iterator B = S1.begin(), E = S1.end(); B != E; ++B) { + if (S2.count(B->first()) != 0) + return true; + } + return false; +} + /// TypecheckGraph - Check that names for output and input languages /// on all edges do match. void TypecheckGraph (const DagVector& EdgeVector, const ToolDescriptions& ToolDescs) { StringMap > ToolToInLang; - StringMap ToolToOutLang; + StringMap > ToolToOutLang; FillInToolToLang(ToolDescs, ToolToInLang, ToolToOutLang); - StringMap::iterator IAE = ToolToOutLang.end(); - StringMap >::iterator IBE = ToolToInLang.end(); for (DagVector::const_iterator B = EdgeVector.begin(), E = EdgeVector.end(); B != E; ++B) { const DagInit* Edge = *B; const std::string& NodeA = InitPtrToString(Edge->getArg(0)); const std::string& NodeB = InitPtrToString(Edge->getArg(1)); - StringMap::iterator IA = ToolToOutLang.find(NodeA); + StringMap >::iterator IA = ToolToOutLang.find(NodeA); StringMap >::iterator IB = ToolToInLang.find(NodeB); + if (NodeB == "root") + throw "Edges back to the root are not allowed!"; + if (NodeA != "root") { - if (IA != IAE && IB != IBE && IB->second.count(IA->second) == 0) + if (IA == ToolToOutLang.end()) + throw NodeA + ": no output language defined!"; + if (IB == ToolToInLang.end()) + throw NodeB + ": no input language defined!"; + + if (!Intersect(IA->second, IB->second)) { throw "Edge " + NodeA + "->" + NodeB + ": output->input language mismatch"; + } } - - if (NodeB == "root") - throw "Edges back to the root are not allowed!"; } } @@ -1178,25 +1180,20 @@ class ExtractOptionNames { if (ActionName == "forward" || ActionName == "forward_as" || ActionName == "forward_value" || ActionName == "forward_transformed_value" || - ActionName == "switch_on" || ActionName == "any_switch_on" || - ActionName == "parameter_equals" || - ActionName == "element_in_list" || ActionName == "not_empty" || - ActionName == "empty") { + ActionName == "parameter_equals" || ActionName == "element_in_list") { CheckNumberOfArguments(Stmt, 1); Init* Arg = Stmt.getArg(0); - if (typeid(*Arg) == typeid(StringInit)) { - const std::string& Name = InitPtrToString(Arg); - OptionNames_.insert(Name); - } - else { - // It's a list. - const ListInit& List = InitPtrToList(Arg); - for (ListInit::const_iterator B = List.begin(), E = List.end(); - B != E; ++B) { - const std::string& Name = InitPtrToString(*B); - OptionNames_.insert(Name); - } + if (typeid(*Arg) == typeid(StringInit)) + OptionNames_.insert(InitPtrToString(Arg)); + } + else if (ActionName == "any_switch_on" || ActionName == "switch_on" || + ActionName == "any_not_empty" || ActionName == "any_empty" || + ActionName == "not_empty" || ActionName == "empty") { + for (unsigned i = 0, NumArgs = Stmt.getNumArgs(); i < NumArgs; ++i) { + Init* Arg = Stmt.getArg(i); + if (typeid(*Arg) == typeid(StringInit)) + OptionNames_.insert(InitPtrToString(Arg)); } } else if (ActionName == "and" || ActionName == "or" || ActionName == "not") { @@ -1211,6 +1208,7 @@ public: {} void operator()(const Init* Statement) { + // Statement is either a dag, or a list of dags. if (typeid(*Statement) == typeid(ListInit)) { const ListInit& DagList = *static_cast(Statement); for (ListInit::const_iterator B = DagList.begin(), E = DagList.end(); @@ -1291,24 +1289,20 @@ bool EmitCaseTest0Args(const std::string& TestName, raw_ostream& O) { return false; } -/// EmitListTest - Helper function used by EmitCaseTest1ArgList(). +/// EmitMultipleArgumentTest - Helper function used by +/// EmitCaseTestMultipleArgs() template -void EmitListTest(const ListInit& L, const char* LogicOp, - F Callback, raw_ostream& O) +void EmitMultipleArgumentTest(const DagInit& D, const char* LogicOp, + F Callback, raw_ostream& O) { - // This is a lot like EmitLogicalOperationTest, but works on ListInits instead - // of Dags... - bool isFirst = true; - for (ListInit::const_iterator B = L.begin(), E = L.end(); B != E; ++B) { - if (isFirst) - isFirst = false; - else - O << ' ' << LogicOp << ' '; - Callback(InitPtrToString(*B), O); + for (unsigned i = 0, NumArgs = D.getNumArgs(); i < NumArgs; ++i) { + if (i != 0) + O << ' ' << LogicOp << ' '; + Callback(InitPtrToString(D.getArg(i)), O); } } -// Callbacks for use with EmitListTest. +// Callbacks for use with EmitMultipleArgumentTest class EmitSwitchOn { const OptionDescriptions& OptDescs_; @@ -1346,54 +1340,48 @@ public: }; -/// EmitCaseTest1ArgList - Helper function used by EmitCaseTest1Arg(); -bool EmitCaseTest1ArgList(const std::string& TestName, - const DagInit& d, - const OptionDescriptions& OptDescs, - raw_ostream& O) { - const ListInit& L = InitPtrToList(d.getArg(0)); - +/// EmitCaseTestMultipleArgs - Helper function used by EmitCaseTest1Arg() +bool EmitCaseTestMultipleArgs (const std::string& TestName, + const DagInit& d, + const OptionDescriptions& OptDescs, + raw_ostream& O) { if (TestName == "any_switch_on") { - EmitListTest(L, "||", EmitSwitchOn(OptDescs), O); + EmitMultipleArgumentTest(d, "||", EmitSwitchOn(OptDescs), O); return true; } else if (TestName == "switch_on") { - EmitListTest(L, "&&", EmitSwitchOn(OptDescs), O); + EmitMultipleArgumentTest(d, "&&", EmitSwitchOn(OptDescs), O); return true; } else if (TestName == "any_not_empty") { - EmitListTest(L, "||", EmitEmptyTest(true, OptDescs), O); + EmitMultipleArgumentTest(d, "||", EmitEmptyTest(true, OptDescs), O); return true; } else if (TestName == "any_empty") { - EmitListTest(L, "||", EmitEmptyTest(false, OptDescs), O); + EmitMultipleArgumentTest(d, "||", EmitEmptyTest(false, OptDescs), O); return true; } else if (TestName == "not_empty") { - EmitListTest(L, "&&", EmitEmptyTest(true, OptDescs), O); + EmitMultipleArgumentTest(d, "&&", EmitEmptyTest(true, OptDescs), O); return true; } else if (TestName == "empty") { - EmitListTest(L, "&&", EmitEmptyTest(false, OptDescs), O); + EmitMultipleArgumentTest(d, "&&", EmitEmptyTest(false, OptDescs), O); return true; } return false; } -/// EmitCaseTest1ArgStr - Helper function used by EmitCaseTest1Arg(); -bool EmitCaseTest1ArgStr(const std::string& TestName, - const DagInit& d, - const OptionDescriptions& OptDescs, - raw_ostream& O) { - const std::string& OptName = InitPtrToString(d.getArg(0)); +/// EmitCaseTest1Arg - Helper function used by EmitCaseTest1OrMoreArgs() +bool EmitCaseTest1Arg (const std::string& TestName, + const DagInit& d, + const OptionDescriptions& OptDescs, + raw_ostream& O) { + const std::string& Arg = InitPtrToString(d.getArg(0)); - if (TestName == "switch_on") { - apply(EmitSwitchOn(OptDescs), OptName, O); - return true; - } - else if (TestName == "input_languages_contain") { - O << "InLangs.count(\"" << OptName << "\") != 0"; + if (TestName == "input_languages_contain") { + O << "InLangs.count(\"" << Arg << "\") != 0"; return true; } else if (TestName == "in_language") { @@ -1401,28 +1389,22 @@ bool EmitCaseTest1ArgStr(const std::string& TestName, // tools can process several files in different languages simultaneously. // TODO: make this work with Edge::Weight (if possible). - O << "LangMap.GetLanguage(inFile) == \"" << OptName << '\"'; - return true; - } - else if (TestName == "not_empty" || TestName == "empty") { - bool EmitNegate = (TestName == "not_empty"); - apply(EmitEmptyTest(EmitNegate, OptDescs), OptName, O); + O << "LangMap.GetLanguage(inFile) == \"" << Arg << '\"'; return true; } return false; } -/// EmitCaseTest1Arg - Helper function used by EmitCaseConstructHandler(); -bool EmitCaseTest1Arg(const std::string& TestName, - const DagInit& d, - const OptionDescriptions& OptDescs, - raw_ostream& O) { +/// EmitCaseTest1OrMoreArgs - Helper function used by +/// EmitCaseConstructHandler() +bool EmitCaseTest1OrMoreArgs(const std::string& TestName, + const DagInit& d, + const OptionDescriptions& OptDescs, + raw_ostream& O) { CheckNumberOfArguments(d, 1); - if (typeid(*d.getArg(0)) == typeid(ListInit)) - return EmitCaseTest1ArgList(TestName, d, OptDescs, O); - else - return EmitCaseTest1ArgStr(TestName, d, OptDescs, O); + return EmitCaseTest1Arg(TestName, d, OptDescs, O) || + EmitCaseTestMultipleArgs(TestName, d, OptDescs, O); } /// EmitCaseTest2Args - Helper function used by EmitCaseConstructHandler(). @@ -1466,10 +1448,10 @@ void EmitLogicalOperationTest(const DagInit& d, const char* LogicOp, const OptionDescriptions& OptDescs, raw_ostream& O) { O << '('; - for (unsigned j = 0, NumArgs = d.getNumArgs(); j < NumArgs; ++j) { - const DagInit& InnerTest = InitPtrToDag(d.getArg(j)); + for (unsigned i = 0, NumArgs = d.getNumArgs(); i < NumArgs; ++i) { + const DagInit& InnerTest = InitPtrToDag(d.getArg(i)); EmitCaseTest(InnerTest, IndentLevel, OptDescs, O); - if (j != NumArgs - 1) { + if (i != NumArgs - 1) { O << ")\n"; O.indent(IndentLevel + Indent1) << ' ' << LogicOp << " ("; } @@ -1503,7 +1485,7 @@ void EmitCaseTest(const DagInit& d, unsigned IndentLevel, EmitLogicalNot(d, IndentLevel, OptDescs, O); else if (EmitCaseTest0Args(TestName, O)) return; - else if (EmitCaseTest1Arg(TestName, d, OptDescs, O)) + else if (EmitCaseTest1OrMoreArgs(TestName, d, OptDescs, O)) return; else if (EmitCaseTest2Args(TestName, d, IndentLevel, OptDescs, O)) return; @@ -1550,10 +1532,12 @@ public: {} void operator() (const Init* Statement, unsigned IndentLevel) { + // Is this a nested 'case'? + bool IsCase = dynamic_cast(Statement) && + GetOperatorName(static_cast(*Statement)) == "case"; - // Ignore nested 'case' DAG. - if (!(dynamic_cast(Statement) && - GetOperatorName(static_cast(*Statement)) == "case")) { + // If so, ignore it, it is handled by our caller, WalkCase. + if (!IsCase) { if (typeid(*Statement) == typeid(ListInit)) { const ListInit& DagList = *static_cast(Statement); for (ListInit::const_iterator B = DagList.begin(), E = DagList.end(); @@ -2250,11 +2234,8 @@ void EmitInOutLanguageMethods (const ToolDescription& D, raw_ostream& O) { O.indent(Indent2) << "return InputLanguages_;\n"; O.indent(Indent1) << "}\n\n"; - if (D.OutLanguage.empty()) - throw "Tool " + D.Name + " has no 'out_language' property!"; - - O.indent(Indent1) << "const char* OutputLanguage() const {\n"; - O.indent(Indent2) << "return \"" << D.OutLanguage << "\";\n"; + O.indent(Indent1) << "const char** OutputLanguages() const {\n"; + O.indent(Indent2) << "return OutputLanguages_;\n"; O.indent(Indent1) << "}\n\n"; } @@ -2299,17 +2280,28 @@ void EmitWorksOnEmptyMethod (const ToolDescription& D, O.indent(Indent1) << "}\n\n"; } +/// EmitStrArray - Emit definition of a 'const char**' static member +/// variable. Helper used by EmitStaticMemberDefinitions(); +void EmitStrArray(const std::string& Name, const std::string& VarName, + const StrVector& StrVec, raw_ostream& O) { + O << "const char* " << Name << "::" << VarName << "[] = {"; + for (StrVector::const_iterator B = StrVec.begin(), E = StrVec.end(); + B != E; ++B) + O << '\"' << *B << "\", "; + O << "0};\n"; +} + /// EmitStaticMemberDefinitions - Emit static member definitions for a /// given Tool class. void EmitStaticMemberDefinitions(const ToolDescription& D, raw_ostream& O) { if (D.InLanguage.empty()) throw "Tool " + D.Name + " has no 'in_language' property!"; + if (D.OutLanguage.empty()) + throw "Tool " + D.Name + " has no 'out_language' property!"; - O << "const char* " << D.Name << "::InputLanguages_[] = {"; - for (StrVector::const_iterator B = D.InLanguage.begin(), - E = D.InLanguage.end(); B != E; ++B) - O << '\"' << *B << "\", "; - O << "0};\n\n"; + EmitStrArray(D.Name, "InputLanguages_", D.InLanguage, O); + EmitStrArray(D.Name, "OutputLanguages_", D.OutLanguage, O); + O << '\n'; } /// EmitToolClassDefinition - Emit a Tool class definition. @@ -2327,7 +2319,8 @@ void EmitToolClassDefinition (const ToolDescription& D, O << "Tool"; O << " {\nprivate:\n"; - O.indent(Indent1) << "static const char* InputLanguages_[];\n\n"; + O.indent(Indent1) << "static const char* InputLanguages_[];\n"; + O.indent(Indent1) << "static const char* OutputLanguages_[];\n\n"; O << "public:\n"; EmitNameMethod(D, O); @@ -2448,21 +2441,13 @@ class EmitPreprocessOptionsCallback : const OptionDescriptions& OptDescs_; - void onListOrDag(const DagInit& d, HandlerImpl h, - unsigned IndentLevel, raw_ostream& O) const + void onEachArgument(const DagInit& d, HandlerImpl h, + unsigned IndentLevel, raw_ostream& O) const { CheckNumberOfArguments(d, 1); - const Init* I = d.getArg(0); - // If I is a list, apply h to each element. - if (typeid(*I) == typeid(ListInit)) { - const ListInit& L = *static_cast(I); - for (ListInit::const_iterator B = L.begin(), E = L.end(); B != E; ++B) - ((this)->*(h))(*B, IndentLevel, O); - } - // Otherwise, apply h to I. - else { - ((this)->*(h))(I, IndentLevel, O); + for (unsigned i = 0, NumArgs = d.getNumArgs(); i < NumArgs; ++i) { + ((this)->*(h))(d.getArg(i), IndentLevel, O); } } @@ -2489,16 +2474,17 @@ class EmitPreprocessOptionsCallback : void onUnsetOption(const DagInit& d, unsigned IndentLevel, raw_ostream& O) const { - this->onListOrDag(d, &EmitPreprocessOptionsCallback::onUnsetOptionImpl, - IndentLevel, O); + this->onEachArgument(d, &EmitPreprocessOptionsCallback::onUnsetOptionImpl, + IndentLevel, O); } - void onSetOptionImpl(const DagInit& d, + void onSetOptionImpl(const DagInit& D, unsigned IndentLevel, raw_ostream& O) const { - CheckNumberOfArguments(d, 2); - const std::string& OptName = InitPtrToString(d.getArg(0)); - const Init* Value = d.getArg(1); + CheckNumberOfArguments(D, 2); + + const std::string& OptName = InitPtrToString(D.getArg(0)); const OptionDescription& OptDesc = OptDescs_.FindOption(OptName); + const Init* Value = D.getArg(1); if (OptDesc.isList()) { const ListInit& List = InitPtrToList(Value); @@ -2528,7 +2514,7 @@ class EmitPreprocessOptionsCallback : << " = \"" << Str << "\";\n"; } else { - throw "Can't apply 'set_option' to alias option -" + OptName + " !"; + throw "Can't apply 'set_option' to alias option '" + OptName + "'!"; } } @@ -2548,15 +2534,22 @@ class EmitPreprocessOptionsCallback : { CheckNumberOfArguments(d, 1); - // Two arguments: (set_option "parameter", VALUE), where VALUE can be a - // boolean, a string or a string list. - if (d.getNumArgs() > 1) - this->onSetOptionImpl(d, IndentLevel, O); - // One argument: (set_option "switch") - // or (set_option ["switch1", "switch2", ...]) - else - this->onListOrDag(d, &EmitPreprocessOptionsCallback::onSetSwitch, - IndentLevel, O); + // 2-argument form: (set_option "A", true), (set_option "B", "C"), + // (set_option "D", ["E", "F"]) + if (d.getNumArgs() == 2) { + const OptionDescription& OptDesc = + OptDescs_.FindOption(InitPtrToString(d.getArg(0))); + const Init* Opt2 = d.getArg(1); + + if (!OptDesc.isSwitch() || typeid(*Opt2) != typeid(StringInit)) { + this->onSetOptionImpl(d, IndentLevel, O); + return; + } + } + + // Multiple argument form: (set_option "A"), (set_option "B", "C", "D") + this->onEachArgument(d, &EmitPreprocessOptionsCallback::onSetSwitch, + IndentLevel, O); } public: @@ -2661,10 +2654,11 @@ void EmitPopulateLanguageMap (const RecordKeeper& Records, raw_ostream& O) { O << "int PopulateLanguageMap (LanguageMap& langMap) {\n"; - // For each LangMap: + // For each LanguageMap: const RecordVector& LangMaps = Records.getAllDerivedDefinitions("LanguageMap"); + // Call DoEmitPopulateLanguageMap. for (RecordVector::const_iterator B = LangMaps.begin(), E = LangMaps.end(); B!=E; ++B) { ListInit* LangMap = (*B)->getValueAsListInit("map"); @@ -2899,7 +2893,7 @@ public: return; } - // We're invoked on a command line. + // We're invoked on a command line string. this->onCmdLine(InitPtrToString(Arg)); } @@ -3041,7 +3035,8 @@ void CheckDriverData(DriverData& Data) { CheckForSuperfluousOptions(Data.Edges, Data.ToolDescs, Data.OptDescs); } -void EmitDriverCode(const DriverData& Data, raw_ostream& O) { +void EmitDriverCode(const DriverData& Data, + raw_ostream& O, RecordKeeper &Records) { // Emit file header. EmitIncludes(O); @@ -3102,7 +3097,7 @@ void LLVMCConfigurationEmitter::run (raw_ostream &O) { CheckDriverData(Data); this->EmitSourceFileHeader("llvmc-based driver: auto-generated code", O); - EmitDriverCode(Data, O); + EmitDriverCode(Data, O, Records); } catch (std::exception& Error) { throw Error.what() + std::string(" - usually this means a syntax error."); diff --git a/utils/TableGen/LLVMCConfigurationEmitter.h b/utils/TableGen/LLVMCConfigurationEmitter.h index b37b83fb9255..0f2ff3719678 100644 --- a/utils/TableGen/LLVMCConfigurationEmitter.h +++ b/utils/TableGen/LLVMCConfigurationEmitter.h @@ -21,8 +21,10 @@ namespace llvm { /// LLVMCConfigurationEmitter - TableGen backend that generates /// configuration code for LLVMC. class LLVMCConfigurationEmitter : public TableGenBackend { + RecordKeeper &Records; public: - explicit LLVMCConfigurationEmitter(RecordKeeper&) {} + explicit LLVMCConfigurationEmitter(RecordKeeper &records) : + Records(records) {} // run - Output the asmwriter, returning true on failure. void run(raw_ostream &o); diff --git a/utils/TableGen/Makefile b/utils/TableGen/Makefile index f27cd995783e..c01b6602faa3 100644 --- a/utils/TableGen/Makefile +++ b/utils/TableGen/Makefile @@ -9,7 +9,7 @@ LEVEL = ../.. TOOLNAME = tblgen -USEDLIBS = LLVMSupport.a LLVMSystem.a +USEDLIBS = LLVMSupport.a REQUIRES_EH := 1 REQUIRES_RTTI := 1 diff --git a/utils/TableGen/NeonEmitter.cpp b/utils/TableGen/NeonEmitter.cpp index 0a12f3766699..64224d9e51d0 100644 --- a/utils/TableGen/NeonEmitter.cpp +++ b/utils/TableGen/NeonEmitter.cpp @@ -8,17 +8,18 @@ //===----------------------------------------------------------------------===// // // This tablegen backend is responsible for emitting arm_neon.h, which includes -// a declaration and definition of each function specified by the ARM NEON +// a declaration and definition of each function specified by the ARM NEON // compiler interface. See ARM document DUI0348B. // // Each NEON instruction is implemented in terms of 1 or more functions which -// are suffixed with the element type of the input vectors. Functions may be +// are suffixed with the element type of the input vectors. Functions may be // implemented in terms of generic vector operations such as +, *, -, etc. or // by calling a __builtin_-prefixed function which will be handled by clang's // CodeGen library. // // Additional validation code can be generated by this file when runHeader() is -// called, rather than the normal run() entry point. +// called, rather than the normal run() entry point. A complete set of tests +// for Neon intrinsics can be generated by calling the runTests() entry point. // //===----------------------------------------------------------------------===// @@ -38,11 +39,11 @@ static void ParseTypes(Record *r, std::string &s, SmallVectorImpl &TV) { const char *data = s.data(); int len = 0; - + for (unsigned i = 0, e = s.size(); i != e; ++i, ++len) { if (data[len] == 'P' || data[len] == 'Q' || data[len] == 'U') continue; - + switch (data[len]) { case 'c': case 's': @@ -72,6 +73,8 @@ static char Widen(const char t) { return 'i'; case 'i': return 'l'; + case 'h': + return 'f'; default: throw "unhandled type in widen!"; } return '\0'; @@ -89,7 +92,7 @@ static char Narrow(const char t) { return 'i'; case 'f': return 'h'; - default: throw "unhandled type in widen!"; + default: throw "unhandled type in narrow!"; } return '\0'; } @@ -98,25 +101,25 @@ static char Narrow(const char t) { /// the quad-vector, polynomial, or unsigned modifiers set. static char ClassifyType(StringRef ty, bool &quad, bool &poly, bool &usgn) { unsigned off = 0; - + // remember quad. if (ty[off] == 'Q') { quad = true; ++off; } - + // remember poly. if (ty[off] == 'P') { poly = true; ++off; } - + // remember unsigned. if (ty[off] == 'U') { usgn = true; ++off; } - + // base type to get the type string for. return ty[off]; } @@ -134,7 +137,12 @@ static char ModType(const char mod, char type, bool &quad, bool &poly, break; case 'u': usgn = true; + poly = false; + if (type == 'f') + type = 'i'; + break; case 'x': + usgn = false; poly = false; if (type == 'f') type = 'i'; @@ -155,6 +163,10 @@ static char ModType(const char mod, char type, bool &quad, bool &poly, case 'n': type = Widen(type); break; + case 'i': + type = 'i'; + scal = true; + break; case 'l': type = 'l'; scal = true; @@ -189,36 +201,31 @@ static char ModType(const char mod, char type, bool &quad, bool &poly, } /// TypeString - for a modifier and type, generate the name of the typedef for -/// that type. If generic is true, emit the generic vector type rather than -/// the public NEON type. QUc -> uint8x8_t / __neon_uint8x8_t. -static std::string TypeString(const char mod, StringRef typestr, - bool generic = false) { +/// that type. QUc -> uint8x8_t. +static std::string TypeString(const char mod, StringRef typestr) { bool quad = false; bool poly = false; bool usgn = false; bool scal = false; bool cnst = false; bool pntr = false; - + if (mod == 'v') return "void"; if (mod == 'i') return "int"; - + // base type to get the type string for. char type = ClassifyType(typestr, quad, poly, usgn); - + // Based on the modifying character, change the type and width if necessary. type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr); - + SmallString<128> s; - - if (generic) - s += "__neon_"; - + if (usgn) s.push_back('u'); - + switch (type) { case 'c': s += poly ? "poly8" : "int8"; @@ -267,16 +274,16 @@ static std::string TypeString(const char mod, StringRef typestr, s += "x3"; if (mod == '4') s += "x4"; - + // Append _t, finishing the type string typedef type. s += "_t"; - + if (cnst) s += " const"; - + if (pntr) s += " *"; - + return s.str(); } @@ -291,23 +298,25 @@ static std::string BuiltinTypeString(const char mod, StringRef typestr, bool scal = false; bool cnst = false; bool pntr = false; - + if (mod == 'v') - return "v"; + return "v"; // void if (mod == 'i') - return "i"; - + return "i"; // int + // base type to get the type string for. char type = ClassifyType(typestr, quad, poly, usgn); - + // Based on the modifying character, change the type and width if necessary. type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr); + // All pointers are void* pointers. Change type to 'v' now. if (pntr) { usgn = false; poly = false; type = 'v'; } + // Treat half-float ('h') types as unsigned short ('s') types. if (type == 'h') { type = 's'; usgn = true; @@ -319,12 +328,14 @@ static std::string BuiltinTypeString(const char mod, StringRef typestr, if (usgn) s.push_back('U'); - - if (type == 'l') + else if (type == 'c') + s.push_back('S'); // make chars explicitly signed + + if (type == 'l') // 64-bit long s += "LLi"; else s.push_back(type); - + if (cnst) s.push_back('C'); if (pntr) @@ -337,8 +348,8 @@ static std::string BuiltinTypeString(const char mod, StringRef typestr, // returning structs of 2, 3, or 4 vectors which are returned in a sret-like // fashion, storing them to a pointer arg. if (ret) { - if (mod == '2' || mod == '3' || mod == '4') - return "vv*"; + if (mod >= '2' && mod <= '4') + return "vv*"; // void result with void* first argument if (mod == 'f' || (ck != ClassB && type == 'f')) return quad ? "V4f" : "V2f"; if (ck != ClassB && type == 's') @@ -347,17 +358,17 @@ static std::string BuiltinTypeString(const char mod, StringRef typestr, return quad ? "V4i" : "V2i"; if (ck != ClassB && type == 'l') return quad ? "V2LLi" : "V1LLi"; - - return quad ? "V16c" : "V8c"; - } + + return quad ? "V16Sc" : "V8Sc"; + } // Non-return array types are passed as individual vectors. if (mod == '2') - return quad ? "V16cV16c" : "V8cV8c"; + return quad ? "V16ScV16Sc" : "V8ScV8Sc"; if (mod == '3') - return quad ? "V16cV16cV16c" : "V8cV8cV8c"; + return quad ? "V16ScV16ScV16Sc" : "V8ScV8ScV8Sc"; if (mod == '4') - return quad ? "V16cV16cV16cV16c" : "V8cV8cV8cV8c"; + return quad ? "V16ScV16ScV16ScV16Sc" : "V8ScV8ScV8ScV8Sc"; if (mod == 'f' || (ck != ClassB && type == 'f')) return quad ? "V4f" : "V2f"; @@ -367,71 +378,25 @@ static std::string BuiltinTypeString(const char mod, StringRef typestr, return quad ? "V4i" : "V2i"; if (ck != ClassB && type == 'l') return quad ? "V2LLi" : "V1LLi"; - - return quad ? "V16c" : "V8c"; -} -/// StructTag - generate the name of the struct tag for a type. -/// These names are mandated by ARM's ABI. -static std::string StructTag(StringRef typestr) { - bool quad = false; - bool poly = false; - bool usgn = false; - - // base type to get the type string for. - char type = ClassifyType(typestr, quad, poly, usgn); - - SmallString<128> s; - s += "__simd"; - s += quad ? "128_" : "64_"; - if (usgn) - s.push_back('u'); - - switch (type) { - case 'c': - s += poly ? "poly8" : "int8"; - break; - case 's': - s += poly ? "poly16" : "int16"; - break; - case 'i': - s += "int32"; - break; - case 'l': - s += "int64"; - break; - case 'h': - s += "float16"; - break; - case 'f': - s += "float32"; - break; - default: - throw "unhandled type!"; - break; - } - - // Append _t, finishing the struct tag name. - s += "_t"; - - return s.str(); + return quad ? "V16Sc" : "V8Sc"; } -/// MangleName - Append a type or width suffix to a base neon function name, +/// MangleName - Append a type or width suffix to a base neon function name, /// and insert a 'q' in the appropriate location if the operation works on /// 128b rather than 64b. E.g. turn "vst2_lane" into "vst2q_lane_f32", etc. static std::string MangleName(const std::string &name, StringRef typestr, ClassKind ck) { if (name == "vcvt_f32_f16") return name; - + bool quad = false; bool poly = false; bool usgn = false; char type = ClassifyType(typestr, quad, poly, usgn); std::string s = name; - + switch (type) { case 'c': switch (ck) { @@ -487,8 +452,8 @@ static std::string MangleName(const std::string &name, StringRef typestr, } if (ck == ClassB) s += "_v"; - - // Insert a 'q' before the first '_' character so that it ends up before + + // Insert a 'q' before the first '_' character so that it ends up before // _lane or _n on vector-scalar operations. if (quad) { size_t pos = s.find('_'); @@ -501,177 +466,344 @@ static std::string MangleName(const std::string &name, StringRef typestr, static std::string GenArgs(const std::string &proto, StringRef typestr) { bool define = proto.find('i') != std::string::npos; char arg = 'a'; - + std::string s; s += "("; - + for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { - if (!define) { - s += TypeString(proto[i], typestr); - s.push_back(' '); + if (define) { + // Immediate macro arguments are used directly instead of being assigned + // to local temporaries; prepend an underscore prefix to make their + // names consistent with the local temporaries. + if (proto[i] == 'i') + s += "__"; + } else { + s += TypeString(proto[i], typestr) + " __"; } s.push_back(arg); if ((i + 1) < e) s += ", "; } - + s += ")"; return s; } -static std::string Duplicate(unsigned nElts, StringRef typestr, +// Macro arguments are not type-checked like inline function arguments, so +// assign them to local temporaries to get the right type checking. +static std::string GenMacroLocals(const std::string &proto, StringRef typestr) { + char arg = 'a'; + std::string s; + + for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { + // Do not create a temporary for an immediate argument. + // That would defeat the whole point of using a macro! + if (proto[i] == 'i') continue; + + s += TypeString(proto[i], typestr) + " __"; + s.push_back(arg); + s += " = ("; + s.push_back(arg); + s += "); "; + } + + s += "\\\n "; + return s; +} + +// Use the vmovl builtin to sign-extend or zero-extend a vector. +static std::string Extend(StringRef typestr, const std::string &a) { + std::string s; + s = MangleName("vmovl", typestr, ClassS); + s += "(" + a + ")"; + return s; +} + +static std::string Duplicate(unsigned nElts, StringRef typestr, const std::string &a) { std::string s; - - s = "(__neon_" + TypeString('d', typestr) + "){ "; + + s = "(" + TypeString('d', typestr) + "){ "; for (unsigned i = 0; i != nElts; ++i) { s += a; if ((i + 1) < nElts) s += ", "; } s += " }"; - + return s; } -// Generate the definition for this intrinsic, e.g. "a + b" for OpAdd. -// If structTypes is true, the NEON types are structs of vector types rather -// than vector types, and the call becomes "a.val + b.val" -static std::string GenOpString(OpKind op, const std::string &proto, - StringRef typestr, bool structTypes = true) { - bool dummy, quad = false; +static std::string SplatLane(unsigned nElts, const std::string &vec, + const std::string &lane) { + std::string s = "__builtin_shufflevector(" + vec + ", " + vec; + for (unsigned i = 0; i < nElts; ++i) + s += ", " + lane; + s += ")"; + return s; +} + +static unsigned GetNumElements(StringRef typestr, bool &quad) { + quad = false; + bool dummy = false; char type = ClassifyType(typestr, quad, dummy, dummy); unsigned nElts = 0; switch (type) { - case 'c': nElts = 8; break; - case 's': nElts = 4; break; - case 'i': nElts = 2; break; - case 'l': nElts = 1; break; - case 'h': nElts = 4; break; - case 'f': nElts = 2; break; + case 'c': nElts = 8; break; + case 's': nElts = 4; break; + case 'i': nElts = 2; break; + case 'l': nElts = 1; break; + case 'h': nElts = 4; break; + case 'f': nElts = 2; break; + default: + throw "unhandled type!"; + break; } - + if (quad) nElts <<= 1; + return nElts; +} + +// Generate the definition for this intrinsic, e.g. "a + b" for OpAdd. +static std::string GenOpString(OpKind op, const std::string &proto, + StringRef typestr) { + bool quad; + unsigned nElts = GetNumElements(typestr, quad); + + // If this builtin takes an immediate argument, we need to #define it rather + // than use a standard declaration, so that SemaChecking can range check + // the immediate passed by the user. + bool define = proto.find('i') != std::string::npos; + std::string ts = TypeString(proto[0], typestr); - std::string s = ts + " r; r"; - - if (structTypes) - s += ".val"; - - s += " = "; - - std::string a, b, c; - if (proto.size() > 1) - a = (structTypes && proto[1] != 'l' && proto[1] != 's') ? "a.val" : "a"; - b = structTypes ? "b.val" : "b"; - c = structTypes ? "c.val" : "c"; - + std::string s; + if (!define) { + s = "return "; + } + switch(op) { case OpAdd: - s += a + " + " + b; + s += "__a + __b;"; + break; + case OpAddl: + s += Extend(typestr, "__a") + " + " + Extend(typestr, "__b") + ";"; + break; + case OpAddw: + s += "__a + " + Extend(typestr, "__b") + ";"; break; case OpSub: - s += a + " - " + b; + s += "__a - __b;"; + break; + case OpSubl: + s += Extend(typestr, "__a") + " - " + Extend(typestr, "__b") + ";"; + break; + case OpSubw: + s += "__a - " + Extend(typestr, "__b") + ";"; break; case OpMulN: - b = Duplicate(nElts << (int)quad, typestr, "b"); + s += "__a * " + Duplicate(nElts, typestr, "__b") + ";"; + break; + case OpMulLane: + s += "__a * " + SplatLane(nElts, "__b", "__c") + ";"; + break; case OpMul: - s += a + " * " + b; + s += "__a * __b;"; + break; + case OpMullN: + s += Extend(typestr, "__a") + " * " + + Extend(typestr, Duplicate(nElts << (int)quad, typestr, "__b")) + ";"; + break; + case OpMullLane: + s += Extend(typestr, "__a") + " * " + + Extend(typestr, SplatLane(nElts, "__b", "__c")) + ";"; + break; + case OpMull: + s += Extend(typestr, "__a") + " * " + Extend(typestr, "__b") + ";"; break; case OpMlaN: - c = Duplicate(nElts << (int)quad, typestr, "c"); + s += "__a + (__b * " + Duplicate(nElts, typestr, "__c") + ");"; + break; + case OpMlaLane: + s += "__a + (__b * " + SplatLane(nElts, "__c", "__d") + ");"; + break; case OpMla: - s += a + " + ( " + b + " * " + c + " )"; + s += "__a + (__b * __c);"; + break; + case OpMlalN: + s += "__a + (" + Extend(typestr, "__b") + " * " + + Extend(typestr, Duplicate(nElts, typestr, "__c")) + ");"; + break; + case OpMlalLane: + s += "__a + (" + Extend(typestr, "__b") + " * " + + Extend(typestr, SplatLane(nElts, "__c", "__d")) + ");"; + break; + case OpMlal: + s += "__a + (" + Extend(typestr, "__b") + " * " + + Extend(typestr, "__c") + ");"; break; case OpMlsN: - c = Duplicate(nElts << (int)quad, typestr, "c"); + s += "__a - (__b * " + Duplicate(nElts, typestr, "__c") + ");"; + break; + case OpMlsLane: + s += "__a - (__b * " + SplatLane(nElts, "__c", "__d") + ");"; + break; case OpMls: - s += a + " - ( " + b + " * " + c + " )"; + s += "__a - (__b * __c);"; + break; + case OpMlslN: + s += "__a - (" + Extend(typestr, "__b") + " * " + + Extend(typestr, Duplicate(nElts, typestr, "__c")) + ");"; + break; + case OpMlslLane: + s += "__a - (" + Extend(typestr, "__b") + " * " + + Extend(typestr, SplatLane(nElts, "__c", "__d")) + ");"; + break; + case OpMlsl: + s += "__a - (" + Extend(typestr, "__b") + " * " + + Extend(typestr, "__c") + ");"; + break; + case OpQDMullLane: + s += MangleName("vqdmull", typestr, ClassS) + "(__a, " + + SplatLane(nElts, "__b", "__c") + ");"; + break; + case OpQDMlalLane: + s += MangleName("vqdmlal", typestr, ClassS) + "(__a, __b, " + + SplatLane(nElts, "__c", "__d") + ");"; + break; + case OpQDMlslLane: + s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, __b, " + + SplatLane(nElts, "__c", "__d") + ");"; + break; + case OpQDMulhLane: + s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " + + SplatLane(nElts, "__b", "__c") + ");"; + break; + case OpQRDMulhLane: + s += MangleName("vqrdmulh", typestr, ClassS) + "(__a, " + + SplatLane(nElts, "__b", "__c") + ");"; break; case OpEq: - s += "(__neon_" + ts + ")(" + a + " == " + b + ")"; + s += "(" + ts + ")(__a == __b);"; break; case OpGe: - s += "(__neon_" + ts + ")(" + a + " >= " + b + ")"; + s += "(" + ts + ")(__a >= __b);"; break; case OpLe: - s += "(__neon_" + ts + ")(" + a + " <= " + b + ")"; + s += "(" + ts + ")(__a <= __b);"; break; case OpGt: - s += "(__neon_" + ts + ")(" + a + " > " + b + ")"; + s += "(" + ts + ")(__a > __b);"; break; case OpLt: - s += "(__neon_" + ts + ")(" + a + " < " + b + ")"; + s += "(" + ts + ")(__a < __b);"; break; case OpNeg: - s += " -" + a; + s += " -__a;"; break; case OpNot: - s += " ~" + a; + s += " ~__a;"; break; case OpAnd: - s += a + " & " + b; + s += "__a & __b;"; break; case OpOr: - s += a + " | " + b; + s += "__a | __b;"; break; case OpXor: - s += a + " ^ " + b; + s += "__a ^ __b;"; break; case OpAndNot: - s += a + " & ~" + b; + s += "__a & ~__b;"; break; case OpOrNot: - s += a + " | ~" + b; + s += "__a | ~__b;"; break; case OpCast: - s += "(__neon_" + ts + ")" + a; + s += "(" + ts + ")__a;"; break; case OpConcat: - s += "__builtin_shufflevector((__neon_int64x1_t)" + a; - s += ", (__neon_int64x1_t)" + b + ", 0, 1)"; + s += "(" + ts + ")__builtin_shufflevector((int64x1_t)__a"; + s += ", (int64x1_t)__b, 0, 1);"; break; case OpHi: - s += "(__neon_int64x1_t)(((__neon_int64x2_t)" + a + ")[1])"; + s += "(" + ts + + ")__builtin_shufflevector((int64x2_t)__a, (int64x2_t)__a, 1);"; break; case OpLo: - s += "(__neon_int64x1_t)(((__neon_int64x2_t)" + a + ")[0])"; + s += "(" + ts + + ")__builtin_shufflevector((int64x2_t)__a, (int64x2_t)__a, 0);"; break; case OpDup: - s += Duplicate(nElts << (int)quad, typestr, a); + s += Duplicate(nElts, typestr, "__a") + ";"; + break; + case OpDupLane: + s += SplatLane(nElts, "__a", "__b") + ";"; break; case OpSelect: // ((0 & 1) | (~0 & 2)) + s += "(" + ts + ")"; ts = TypeString(proto[1], typestr); - s += "( " + a + " & (__neon_" + ts + ")" + b + ") | "; - s += "(~" + a + " & (__neon_" + ts + ")" + c + ")"; + s += "((__a & (" + ts + ")__b) | "; + s += "(~__a & (" + ts + ")__c));"; break; case OpRev16: - s += "__builtin_shufflevector(" + a + ", " + a; - for (unsigned i = 2; i <= nElts << (int)quad; i += 2) + s += "__builtin_shufflevector(__a, __a"; + for (unsigned i = 2; i <= nElts; i += 2) for (unsigned j = 0; j != 2; ++j) s += ", " + utostr(i - j - 1); - s += ")"; + s += ");"; break; - case OpRev32: - nElts >>= 1; - s += "__builtin_shufflevector(" + a + ", " + a; - for (unsigned i = nElts; i <= nElts << (1 + (int)quad); i += nElts) - for (unsigned j = 0; j != nElts; ++j) + case OpRev32: { + unsigned WordElts = nElts >> (1 + (int)quad); + s += "__builtin_shufflevector(__a, __a"; + for (unsigned i = WordElts; i <= nElts; i += WordElts) + for (unsigned j = 0; j != WordElts; ++j) s += ", " + utostr(i - j - 1); - s += ")"; + s += ");"; break; - case OpRev64: - s += "__builtin_shufflevector(" + a + ", " + a; - for (unsigned i = nElts; i <= nElts << (int)quad; i += nElts) - for (unsigned j = 0; j != nElts; ++j) + } + case OpRev64: { + unsigned DblWordElts = nElts >> (int)quad; + s += "__builtin_shufflevector(__a, __a"; + for (unsigned i = DblWordElts; i <= nElts; i += DblWordElts) + for (unsigned j = 0; j != DblWordElts; ++j) s += ", " + utostr(i - j - 1); - s += ")"; + s += ");"; + break; + } + case OpAbdl: { + std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; + if (typestr[0] != 'U') { + // vabd results are always unsigned and must be zero-extended. + std::string utype = "U" + typestr.str(); + s += "(" + TypeString(proto[0], typestr) + ")"; + abd = "(" + TypeString('d', utype) + ")" + abd; + s += Extend(utype, abd) + ";"; + } else { + s += Extend(typestr, abd) + ";"; + } + break; + } + case OpAba: + s += "__a + " + MangleName("vabd", typestr, ClassS) + "(__b, __c);"; break; + case OpAbal: { + s += "__a + "; + std::string abd = MangleName("vabd", typestr, ClassS) + "(__b, __c)"; + if (typestr[0] != 'U') { + // vabd results are always unsigned and must be zero-extended. + std::string utype = "U" + typestr.str(); + s += "(" + TypeString(proto[0], typestr) + ")"; + abd = "(" + TypeString('d', utype) + ")" + abd; + s += Extend(utype, abd) + ";"; + } else { + s += Extend(typestr, abd) + ";"; + } + break; + } default: throw "unknown OpKind!"; break; } - s += "; return r;"; return s; } @@ -688,10 +820,10 @@ static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) { bool scal = false; bool cnst = false; bool pntr = false; - + // Base type to get the type string for. char type = ClassifyType(typestr, quad, poly, usgn); - + // Based on the modifying character, change the type and width if necessary. type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr); @@ -699,9 +831,9 @@ static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) { ret |= 0x08; if (quad && proto[1] != 'g') ret |= 0x10; - + switch (type) { - case 'c': + case 'c': ret |= poly ? 5 : 0; break; case 's': @@ -727,65 +859,45 @@ static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) { } // Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a) -// If structTypes is true, the NEON types are structs of vector types rather -// than vector types, and the call becomes __builtin_neon_cls(a.val) static std::string GenBuiltin(const std::string &name, const std::string &proto, - StringRef typestr, ClassKind ck, - bool structTypes = true) { - bool dummy, quad = false; - char type = ClassifyType(typestr, quad, dummy, dummy); - unsigned nElts = 0; - switch (type) { - case 'c': nElts = 8; break; - case 's': nElts = 4; break; - case 'i': nElts = 2; break; - case 'l': nElts = 1; break; - case 'h': nElts = 4; break; - case 'f': nElts = 2; break; - } - if (quad) nElts <<= 1; - - char arg = 'a'; + StringRef typestr, ClassKind ck) { std::string s; // If this builtin returns a struct 2, 3, or 4 vectors, pass it as an implicit // sret-like argument. - bool sret = (proto[0] == '2' || proto[0] == '3' || proto[0] == '4'); + bool sret = (proto[0] >= '2' && proto[0] <= '4'); // If this builtin takes an immediate argument, we need to #define it rather // than use a standard declaration, so that SemaChecking can range check // the immediate passed by the user. bool define = proto.find('i') != std::string::npos; - // If all types are the same size, bitcasting the args will take care - // of arg checking. The actual signedness etc. will be taken care of with - // special enums. + // Check if the prototype has a scalar operand with the type of the vector + // elements. If not, bitcasting the args will take care of arg checking. + // The actual signedness etc. will be taken care of with special enums. if (proto.find('s') == std::string::npos) ck = ClassB; if (proto[0] != 'v') { std::string ts = TypeString(proto[0], typestr); - + if (define) { if (sret) - s += "({ " + ts + " r; "; - else if (proto[0] != 's') - s += "(" + ts + "){(__neon_" + ts + ")"; + s += ts + " r; "; + else + s += "(" + ts + ")"; } else if (sret) { s += ts + " r; "; } else { - s += ts + " r; r"; - if (structTypes && proto[0] != 's' && proto[0] != 'i' && proto[0] != 'l') - s += ".val"; - - s += " = "; + s += "return (" + ts + ")"; } } - + bool splat = proto.find('a') != std::string::npos; - + s += "__builtin_neon_"; if (splat) { + // Call the non-splat builtin: chop off the "_n" suffix from the name. std::string vname(name, 0, name.size()-2); s += MangleName(vname, typestr, ck); } else { @@ -797,17 +909,32 @@ static std::string GenBuiltin(const std::string &name, const std::string &proto, // builtins. if (sret) s += "&r, "; - + + char arg = 'a'; for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { std::string args = std::string(&arg, 1); - if (define) - args = "(" + args + ")"; - + + // Use the local temporaries instead of the macro arguments. + args = "__" + args; + + bool argQuad = false; + bool argPoly = false; + bool argUsgn = false; + bool argScalar = false; + bool dummy = false; + char argType = ClassifyType(typestr, argQuad, argPoly, argUsgn); + argType = ModType(proto[i], argType, argQuad, argPoly, argUsgn, argScalar, + dummy, dummy); + // Handle multiple-vector values specially, emitting each subvector as an // argument to the __builtin. - if (structTypes && (proto[i] == '2' || proto[i] == '3' || proto[i] == '4')){ + if (proto[i] >= '2' && proto[i] <= '4') { + // Check if an explicit cast is needed. + if (argType != 'c' || argPoly || argUsgn) + args = (argQuad ? "(int8x16_t)" : "(int8x8_t)") + args; + for (unsigned vi = 0, ve = proto[i] - '0'; vi != ve; ++vi) { - s += args + ".val[" + utostr(vi) + "].val"; + s += args + ".val[" + utostr(vi) + "]"; if ((vi + 1) < ve) s += ", "; } @@ -816,77 +943,158 @@ static std::string GenBuiltin(const std::string &name, const std::string &proto, continue; } - - if (splat && (i + 1) == e) - s += Duplicate(nElts, typestr, args); - else - s += args; - - if (structTypes && proto[i] != 's' && proto[i] != 'i' && proto[i] != 'l' && - proto[i] != 'p' && proto[i] != 'c' && proto[i] != 'a') { - s += ".val"; + + if (splat && (i + 1) == e) + args = Duplicate(GetNumElements(typestr, argQuad), typestr, args); + + // Check if an explicit cast is needed. + if ((splat || !argScalar) && + ((ck == ClassB && argType != 'c') || argPoly || argUsgn)) { + std::string argTypeStr = "c"; + if (ck != ClassB) + argTypeStr = argType; + if (argQuad) + argTypeStr = "Q" + argTypeStr; + args = "(" + TypeString('d', argTypeStr) + ")" + args; } + + s += args; if ((i + 1) < e) s += ", "; } - + // Extra constant integer to hold type class enum for this function, e.g. s8 if (ck == ClassB) s += ", " + utostr(GetNeonEnum(proto, typestr)); - - if (define) - s += ")"; - else - s += ");"; - if (proto[0] != 'v') { - if (define) { - if (sret) - s += "; r; })"; - else if (proto[0] != 's') - s += "}"; - } else { + s += ");"; + + if (proto[0] != 'v' && sret) { + if (define) + s += " r;"; + else s += " return r;"; - } } return s; } -static std::string GenBuiltinDef(const std::string &name, +static std::string GenBuiltinDef(const std::string &name, const std::string &proto, StringRef typestr, ClassKind ck) { std::string s("BUILTIN(__builtin_neon_"); - // If all types are the same size, bitcasting the args will take care + // If all types are the same size, bitcasting the args will take care // of arg checking. The actual signedness etc. will be taken care of with // special enums. if (proto.find('s') == std::string::npos) ck = ClassB; - + s += MangleName(name, typestr, ck); s += ", \""; - + for (unsigned i = 0, e = proto.size(); i != e; ++i) s += BuiltinTypeString(proto[i], typestr, ck, i == 0); // Extra constant integer to hold type class enum for this function, e.g. s8 if (ck == ClassB) s += "i"; - + s += "\", \"n\")"; return s; } +static std::string GenIntrinsic(const std::string &name, + const std::string &proto, + StringRef outTypeStr, StringRef inTypeStr, + OpKind kind, ClassKind classKind) { + assert(!proto.empty() && ""); + bool define = proto.find('i') != std::string::npos; + std::string s; + + // static always inline + return type + if (define) + s += "#define "; + else + s += "__ai " + TypeString(proto[0], outTypeStr) + " "; + + // Function name with type suffix + std::string mangledName = MangleName(name, outTypeStr, ClassS); + if (outTypeStr != inTypeStr) { + // If the input type is different (e.g., for vreinterpret), append a suffix + // for the input type. String off a "Q" (quad) prefix so that MangleName + // does not insert another "q" in the name. + unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0); + StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff); + mangledName = MangleName(mangledName, inTypeNoQuad, ClassS); + } + s += mangledName; + + // Function arguments + s += GenArgs(proto, inTypeStr); + + // Definition. + if (define) { + s += " __extension__ ({ \\\n "; + s += GenMacroLocals(proto, inTypeStr); + } else { + s += " { \\\n "; + } + + if (kind != OpNone) + s += GenOpString(kind, proto, outTypeStr); + else + s += GenBuiltin(name, proto, outTypeStr, classKind); + if (define) + s += " })"; + else + s += " }"; + s += "\n"; + return s; +} + /// run - Read the records in arm_neon.td and output arm_neon.h. arm_neon.h /// is comprised of type definitions and function declarations. void NeonEmitter::run(raw_ostream &OS) { - EmitSourceFileHeader("ARM NEON Header", OS); - - // FIXME: emit license into file? - + OS << + "/*===---- arm_neon.h - ARM Neon intrinsics ------------------------------" + "---===\n" + " *\n" + " * Permission is hereby granted, free of charge, to any person obtaining " + "a copy\n" + " * of this software and associated documentation files (the \"Software\")," + " to deal\n" + " * in the Software without restriction, including without limitation the " + "rights\n" + " * to use, copy, modify, merge, publish, distribute, sublicense, " + "and/or sell\n" + " * copies of the Software, and to permit persons to whom the Software is\n" + " * furnished to do so, subject to the following conditions:\n" + " *\n" + " * The above copyright notice and this permission notice shall be " + "included in\n" + " * all copies or substantial portions of the Software.\n" + " *\n" + " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, " + "EXPRESS OR\n" + " * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " + "MERCHANTABILITY,\n" + " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT " + "SHALL THE\n" + " * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR " + "OTHER\n" + " * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, " + "ARISING FROM,\n" + " * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER " + "DEALINGS IN\n" + " * THE SOFTWARE.\n" + " *\n" + " *===--------------------------------------------------------------------" + "---===\n" + " */\n\n"; + OS << "#ifndef __ARM_NEON_H\n"; OS << "#define __ARM_NEON_H\n\n"; - + OS << "#ifndef __ARM_NEON__\n"; OS << "#error \"NEON support not enabled\"\n"; OS << "#endif\n\n"; @@ -895,8 +1103,8 @@ void NeonEmitter::run(raw_ostream &OS) { // Emit NEON-specific scalar typedefs. OS << "typedef float float32_t;\n"; - OS << "typedef uint8_t poly8_t;\n"; - OS << "typedef uint16_t poly16_t;\n"; + OS << "typedef int8_t poly8_t;\n"; + OS << "typedef int16_t poly16_t;\n"; OS << "typedef uint16_t float16_t;\n"; // Emit Neon vector typedefs. @@ -905,105 +1113,105 @@ void NeonEmitter::run(raw_ostream &OS) { ParseTypes(0, TypedefTypes, TDTypeVec); // Emit vector typedefs. - for (unsigned v = 1; v != 5; ++v) { - for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) { - bool dummy, quad = false; - (void) ClassifyType(TDTypeVec[i], quad, dummy, dummy); - OS << "typedef __attribute__(( __vector_size__("; - - OS << utostr(8*v*(quad ? 2 : 1)) << ") )) "; - if (!quad) - OS << " "; - - OS << TypeString('s', TDTypeVec[i]); - OS << " __neon_"; - - char t = (v == 1) ? 'd' : '0' + v; - OS << TypeString(t, TDTypeVec[i]) << ";\n"; - } + for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) { + bool dummy, quad = false, poly = false; + (void) ClassifyType(TDTypeVec[i], quad, poly, dummy); + if (poly) + OS << "typedef __attribute__((neon_polyvector_type("; + else + OS << "typedef __attribute__((neon_vector_type("; + + unsigned nElts = GetNumElements(TDTypeVec[i], quad); + OS << utostr(nElts) << "))) "; + if (nElts < 10) + OS << " "; + + OS << TypeString('s', TDTypeVec[i]); + OS << " " << TypeString('d', TDTypeVec[i]) << ";\n"; } OS << "\n"; // Emit struct typedefs. - for (unsigned vi = 1; vi != 5; ++vi) { + for (unsigned vi = 2; vi != 5; ++vi) { for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) { - std::string ts = TypeString('d', TDTypeVec[i], vi == 1); - std::string vs = TypeString((vi > 1) ? '0' + vi : 'd', TDTypeVec[i]); - std::string tag = (vi > 1) ? vs : StructTag(TDTypeVec[i]); - OS << "typedef struct " << tag << " {\n"; + std::string ts = TypeString('d', TDTypeVec[i]); + std::string vs = TypeString('0' + vi, TDTypeVec[i]); + OS << "typedef struct " << vs << " {\n"; OS << " " << ts << " val"; - if (vi > 1) - OS << "[" << utostr(vi) << "]"; - OS << ";\n} " << vs << ";\n\n"; + OS << "[" << utostr(vi) << "]"; + OS << ";\n} "; + OS << vs << ";\n\n"; } } - + OS << "#define __ai static __attribute__((__always_inline__))\n\n"; std::vector RV = Records.getAllDerivedDefinitions("Inst"); - - // Unique the return+pattern types, and assign them. + + // Emit vmovl and vabd intrinsics first so they can be used by other + // intrinsics. (Some of the saturating multiply instructions are also + // used to implement the corresponding "_lane" variants, but tablegen + // sorts the records into alphabetical order so that the "_lane" variants + // come after the intrinsics they use.) + emitIntrinsic(OS, Records.getDef("VMOVL")); + emitIntrinsic(OS, Records.getDef("VABD")); + for (unsigned i = 0, e = RV.size(); i != e; ++i) { Record *R = RV[i]; - std::string name = LowercaseString(R->getName()); - std::string Proto = R->getValueAsString("Prototype"); - std::string Types = R->getValueAsString("Types"); - - SmallVector TypeVec; - ParseTypes(R, Types, TypeVec); - - OpKind k = OpMap[R->getValueAsDef("Operand")->getName()]; - - bool define = Proto.find('i') != std::string::npos; - - for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { - assert(!Proto.empty() && ""); - - // static always inline + return type - if (define) - OS << "#define"; - else - OS << "__ai " << TypeString(Proto[0], TypeVec[ti]); - - // Function name with type suffix - OS << " " << MangleName(name, TypeVec[ti], ClassS); - - // Function arguments - OS << GenArgs(Proto, TypeVec[ti]); - - // Definition. - if (define) - OS << " "; - else - OS << " { "; - - if (k != OpNone) { - OS << GenOpString(k, Proto, TypeVec[ti]); - } else { - if (R->getSuperClasses().size() < 2) - throw TGError(R->getLoc(), "Builtin has no class kind"); - - ClassKind ck = ClassMap[R->getSuperClasses()[1]]; - - if (ck == ClassNone) - throw TGError(R->getLoc(), "Builtin has no class kind"); - OS << GenBuiltin(name, Proto, TypeVec[ti], ck); - } - if (!define) - OS << " }"; - OS << "\n"; - } - OS << "\n"; + if (R->getName() != "VMOVL" && R->getName() != "VABD") + emitIntrinsic(OS, R); } + OS << "#undef __ai\n\n"; OS << "#endif /* __ARM_NEON_H */\n"; } -static unsigned RangeFromType(StringRef typestr) { +/// emitIntrinsic - Write out the arm_neon.h header file definitions for the +/// intrinsics specified by record R. +void NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R) { + std::string name = R->getValueAsString("Name"); + std::string Proto = R->getValueAsString("Prototype"); + std::string Types = R->getValueAsString("Types"); + + SmallVector TypeVec; + ParseTypes(R, Types, TypeVec); + + OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()]; + + ClassKind classKind = ClassNone; + if (R->getSuperClasses().size() >= 2) + classKind = ClassMap[R->getSuperClasses()[1]]; + if (classKind == ClassNone && kind == OpNone) + throw TGError(R->getLoc(), "Builtin has no class kind"); + + for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { + if (kind == OpReinterpret) { + bool outQuad = false; + bool dummy = false; + (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy); + for (unsigned srcti = 0, srcte = TypeVec.size(); + srcti != srcte; ++srcti) { + bool inQuad = false; + (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy); + if (srcti == ti || inQuad != outQuad) + continue; + OS << GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[srcti], + OpCast, ClassS); + } + } else { + OS << GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[ti], + kind, classKind); + } + } + OS << "\n"; +} + +static unsigned RangeFromType(const char mod, StringRef typestr) { // base type to get the type string for. bool quad = false, dummy = false; char type = ClassifyType(typestr, quad, dummy, dummy); - + type = ModType(mod, type, quad, dummy, dummy, dummy, dummy, dummy); + switch (type) { case 'c': return (8 << (int)quad) - 1; @@ -1031,7 +1239,7 @@ void NeonEmitter::runHeader(raw_ostream &OS) { std::vector RV = Records.getAllDerivedDefinitions("Inst"); StringMap EmittedMap; - + // Generate BuiltinsARM.def for NEON OS << "#ifdef GET_NEON_BUILTINS\n"; for (unsigned i = 0, e = RV.size(); i != e; ++i) { @@ -1041,22 +1249,22 @@ void NeonEmitter::runHeader(raw_ostream &OS) { continue; std::string Proto = R->getValueAsString("Prototype"); - + // Functions with 'a' (the splat code) in the type prototype should not get // their own builtin as they use the non-splat variant. if (Proto.find('a') != std::string::npos) continue; - + std::string Types = R->getValueAsString("Types"); SmallVector TypeVec; ParseTypes(R, Types, TypeVec); - + if (R->getSuperClasses().size() < 2) throw TGError(R->getLoc(), "Builtin has no class kind"); - - std::string name = LowercaseString(R->getName()); + + std::string name = R->getValueAsString("Name"); ClassKind ck = ClassMap[R->getSuperClasses()[1]]; - + for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { // Generate the BuiltinsARM.def declaration for this builtin, ensuring // that each unique BUILTIN() macro appears only once in the output @@ -1064,13 +1272,13 @@ void NeonEmitter::runHeader(raw_ostream &OS) { std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck); if (EmittedMap.count(bd)) continue; - + EmittedMap[bd] = OpNone; OS << bd << "\n"; } } OS << "#endif\n\n"; - + // Generate the overloaded type checking code for SemaChecking.cpp OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n"; for (unsigned i = 0, e = RV.size(); i != e; ++i) { @@ -1078,34 +1286,34 @@ void NeonEmitter::runHeader(raw_ostream &OS) { OpKind k = OpMap[R->getValueAsDef("Operand")->getName()]; if (k != OpNone) continue; - + std::string Proto = R->getValueAsString("Prototype"); std::string Types = R->getValueAsString("Types"); - std::string name = LowercaseString(R->getName()); - + std::string name = R->getValueAsString("Name"); + // Functions with 'a' (the splat code) in the type prototype should not get // their own builtin as they use the non-splat variant. if (Proto.find('a') != std::string::npos) continue; - + // Functions which have a scalar argument cannot be overloaded, no need to // check them if we are emitting the type checking code. if (Proto.find('s') != std::string::npos) continue; - + SmallVector TypeVec; ParseTypes(R, Types, TypeVec); - + if (R->getSuperClasses().size() < 2) throw TGError(R->getLoc(), "Builtin has no class kind"); - + int si = -1, qi = -1; unsigned mask = 0, qmask = 0; for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { // Generate the switch case(s) for this builtin for the type validation. bool quad = false, poly = false, usgn = false; (void) ClassifyType(TypeVec[ti], quad, poly, usgn); - + if (quad) { qi = ti; qmask |= 1 << GetNeonEnum(Proto, TypeVec[ti]); @@ -1115,64 +1323,67 @@ void NeonEmitter::runHeader(raw_ostream &OS) { } } if (mask) - OS << "case ARM::BI__builtin_neon_" - << MangleName(name, TypeVec[si], ClassB) - << ": mask = " << "0x" << utohexstr(mask) << "; break;\n"; + OS << "case ARM::BI__builtin_neon_" + << MangleName(name, TypeVec[si], ClassB) + << ": mask = " << "0x" << utohexstr(mask) << "; break;\n"; if (qmask) - OS << "case ARM::BI__builtin_neon_" - << MangleName(name, TypeVec[qi], ClassB) - << ": mask = " << "0x" << utohexstr(qmask) << "; break;\n"; + OS << "case ARM::BI__builtin_neon_" + << MangleName(name, TypeVec[qi], ClassB) + << ": mask = " << "0x" << utohexstr(qmask) << "; break;\n"; } OS << "#endif\n\n"; - + // Generate the intrinsic range checking code for shift/lane immediates. OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n"; for (unsigned i = 0, e = RV.size(); i != e; ++i) { Record *R = RV[i]; - + OpKind k = OpMap[R->getValueAsDef("Operand")->getName()]; if (k != OpNone) continue; - - std::string name = LowercaseString(R->getName()); + + std::string name = R->getValueAsString("Name"); std::string Proto = R->getValueAsString("Prototype"); std::string Types = R->getValueAsString("Types"); - + // Functions with 'a' (the splat code) in the type prototype should not get // their own builtin as they use the non-splat variant. if (Proto.find('a') != std::string::npos) continue; - + // Functions which do not have an immediate do not need to have range // checking code emitted. - if (Proto.find('i') == std::string::npos) + size_t immPos = Proto.find('i'); + if (immPos == std::string::npos) continue; - + SmallVector TypeVec; ParseTypes(R, Types, TypeVec); - + if (R->getSuperClasses().size() < 2) throw TGError(R->getLoc(), "Builtin has no class kind"); - + ClassKind ck = ClassMap[R->getSuperClasses()[1]]; - + for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { std::string namestr, shiftstr, rangestr; - + // Builtins which are overloaded by type will need to have their upper // bound computed at Sema time based on the type constant. if (Proto.find('s') == std::string::npos) { ck = ClassB; if (R->getValueAsBit("isShift")) { shiftstr = ", true"; - + // Right shifts have an 'r' in the name, left shifts do not. if (name.find('r') != std::string::npos) rangestr = "l = 1; "; } rangestr += "u = RFT(TV" + shiftstr + ")"; } else { - rangestr = "u = " + utostr(RangeFromType(TypeVec[ti])); + // The immediate generally refers to a lane in the preceding argument. + assert(immPos > 0 && "unexpected immediate operand"); + rangestr = "u = " + utostr(RangeFromType(Proto[immPos-1], TypeVec[ti])); } // Make sure cases appear only once by uniquing them in a string map. namestr = MangleName(name, TypeVec[ti], ck); @@ -1182,13 +1393,13 @@ void NeonEmitter::runHeader(raw_ostream &OS) { // Calculate the index of the immediate that should be range checked. unsigned immidx = 0; - + // Builtins that return a struct of multiple vectors have an extra // leading arg for the struct return. - if (Proto[0] == '2' || Proto[0] == '3' || Proto[0] == '4') + if (Proto[0] >= '2' && Proto[0] <= '4') ++immidx; - - // Add one to the index for each argument until we reach the immediate + + // Add one to the index for each argument until we reach the immediate // to be checked. Structs of vectors are passed as multiple arguments. for (unsigned ii = 1, ie = Proto.size(); ii != ie; ++ii) { switch (Proto[ii]) { @@ -1199,9 +1410,113 @@ void NeonEmitter::runHeader(raw_ostream &OS) { case 'i': ie = ii + 1; break; } } - OS << "case ARM::BI__builtin_neon_" << MangleName(name, TypeVec[ti], ck) + OS << "case ARM::BI__builtin_neon_" << MangleName(name, TypeVec[ti], ck) << ": i = " << immidx << "; " << rangestr << "; break;\n"; } } OS << "#endif\n\n"; } + +/// GenTest - Write out a test for the intrinsic specified by the name and +/// type strings, including the embedded patterns for FileCheck to match. +static std::string GenTest(const std::string &name, + const std::string &proto, + StringRef outTypeStr, StringRef inTypeStr, + bool isShift) { + assert(!proto.empty() && ""); + std::string s; + + // Function name with type suffix + std::string mangledName = MangleName(name, outTypeStr, ClassS); + if (outTypeStr != inTypeStr) { + // If the input type is different (e.g., for vreinterpret), append a suffix + // for the input type. String off a "Q" (quad) prefix so that MangleName + // does not insert another "q" in the name. + unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0); + StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff); + mangledName = MangleName(mangledName, inTypeNoQuad, ClassS); + } + + // Emit the FileCheck patterns. + s += "// CHECK: test_" + mangledName + "\n"; + // s += "// CHECK: \n"; // FIXME: + expected instruction opcode. + + // Emit the start of the test function. + s += TypeString(proto[0], outTypeStr) + " test_" + mangledName + "("; + char arg = 'a'; + std::string comma; + for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { + // Do not create arguments for values that must be immediate constants. + if (proto[i] == 'i') + continue; + s += comma + TypeString(proto[i], inTypeStr) + " "; + s.push_back(arg); + comma = ", "; + } + s += ") { \\\n "; + + if (proto[0] != 'v') + s += "return "; + s += mangledName + "("; + arg = 'a'; + for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { + if (proto[i] == 'i') { + // For immediate operands, test the maximum value. + if (isShift) + s += "1"; // FIXME + else + // The immediate generally refers to a lane in the preceding argument. + s += utostr(RangeFromType(proto[i-1], inTypeStr)); + } else { + s.push_back(arg); + } + if ((i + 1) < e) + s += ", "; + } + s += ");\n}\n\n"; + return s; +} + +/// runTests - Write out a complete set of tests for all of the Neon +/// intrinsics. +void NeonEmitter::runTests(raw_ostream &OS) { + OS << + "// RUN: %clang_cc1 -triple thumbv7-apple-darwin \\\n" + "// RUN: -target-cpu cortex-a9 -ffreestanding -S -o - %s | FileCheck %s\n" + "\n" + "#include \n" + "\n"; + + std::vector RV = Records.getAllDerivedDefinitions("Inst"); + for (unsigned i = 0, e = RV.size(); i != e; ++i) { + Record *R = RV[i]; + std::string name = R->getValueAsString("Name"); + std::string Proto = R->getValueAsString("Prototype"); + std::string Types = R->getValueAsString("Types"); + bool isShift = R->getValueAsBit("isShift"); + + SmallVector TypeVec; + ParseTypes(R, Types, TypeVec); + + OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()]; + for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { + if (kind == OpReinterpret) { + bool outQuad = false; + bool dummy = false; + (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy); + for (unsigned srcti = 0, srcte = TypeVec.size(); + srcti != srcte; ++srcti) { + bool inQuad = false; + (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy); + if (srcti == ti || inQuad != outQuad) + continue; + OS << GenTest(name, Proto, TypeVec[ti], TypeVec[srcti], isShift); + } + } else { + OS << GenTest(name, Proto, TypeVec[ti], TypeVec[ti], isShift); + } + } + OS << "\n"; + } +} + diff --git a/utils/TableGen/NeonEmitter.h b/utils/TableGen/NeonEmitter.h index 6c6760d732fa..1e6fcbf555df 100644 --- a/utils/TableGen/NeonEmitter.h +++ b/utils/TableGen/NeonEmitter.h @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // // This tablegen backend is responsible for emitting arm_neon.h, which includes -// a declaration and definition of each function specified by the ARM NEON +// a declaration and definition of each function specified by the ARM NEON // compiler interface. See ARM document DUI0348B. // //===----------------------------------------------------------------------===// @@ -24,13 +24,34 @@ enum OpKind { OpNone, OpAdd, + OpAddl, + OpAddw, OpSub, + OpSubl, + OpSubw, OpMul, + OpMull, OpMla, + OpMlal, OpMls, + OpMlsl, OpMulN, + OpMullN, OpMlaN, OpMlsN, + OpMlalN, + OpMlslN, + OpMulLane, + OpMullLane, + OpMlaLane, + OpMlsLane, + OpMlalLane, + OpMlslLane, + OpQDMullLane, + OpQDMlalLane, + OpQDMlslLane, + OpQDMulhLane, + OpQRDMulhLane, OpEq, OpGe, OpLe, @@ -46,40 +67,66 @@ enum OpKind { OpCast, OpConcat, OpDup, + OpDupLane, OpHi, OpLo, OpSelect, OpRev16, OpRev32, - OpRev64 + OpRev64, + OpReinterpret, + OpAbdl, + OpAba, + OpAbal }; enum ClassKind { ClassNone, - ClassI, - ClassS, - ClassW, - ClassB + ClassI, // generic integer instruction, e.g., "i8" suffix + ClassS, // signed/unsigned/poly, e.g., "s8", "u8" or "p8" suffix + ClassW, // width-specific instruction, e.g., "8" suffix + ClassB // bitcast arguments with enum argument to specify type }; namespace llvm { - + class NeonEmitter : public TableGenBackend { RecordKeeper &Records; StringMap OpMap; DenseMap ClassMap; - + public: NeonEmitter(RecordKeeper &R) : Records(R) { OpMap["OP_NONE"] = OpNone; OpMap["OP_ADD"] = OpAdd; + OpMap["OP_ADDL"] = OpAddl; + OpMap["OP_ADDW"] = OpAddw; OpMap["OP_SUB"] = OpSub; + OpMap["OP_SUBL"] = OpSubl; + OpMap["OP_SUBW"] = OpSubw; OpMap["OP_MUL"] = OpMul; + OpMap["OP_MULL"] = OpMull; OpMap["OP_MLA"] = OpMla; + OpMap["OP_MLAL"] = OpMlal; OpMap["OP_MLS"] = OpMls; + OpMap["OP_MLSL"] = OpMlsl; OpMap["OP_MUL_N"] = OpMulN; + OpMap["OP_MULL_N"]= OpMullN; OpMap["OP_MLA_N"] = OpMlaN; OpMap["OP_MLS_N"] = OpMlsN; + OpMap["OP_MLAL_N"] = OpMlalN; + OpMap["OP_MLSL_N"] = OpMlslN; + OpMap["OP_MUL_LN"]= OpMulLane; + OpMap["OP_MULL_LN"] = OpMullLane; + OpMap["OP_MLA_LN"]= OpMlaLane; + OpMap["OP_MLS_LN"]= OpMlsLane; + OpMap["OP_MLAL_LN"] = OpMlalLane; + OpMap["OP_MLSL_LN"] = OpMlslLane; + OpMap["OP_QDMULL_LN"] = OpQDMullLane; + OpMap["OP_QDMLAL_LN"] = OpQDMlalLane; + OpMap["OP_QDMLSL_LN"] = OpQDMlslLane; + OpMap["OP_QDMULH_LN"] = OpQDMulhLane; + OpMap["OP_QRDMULH_LN"] = OpQRDMulhLane; OpMap["OP_EQ"] = OpEq; OpMap["OP_GE"] = OpGe; OpMap["OP_LE"] = OpLe; @@ -97,10 +144,15 @@ namespace llvm { OpMap["OP_HI"] = OpHi; OpMap["OP_LO"] = OpLo; OpMap["OP_DUP"] = OpDup; + OpMap["OP_DUP_LN"] = OpDupLane; OpMap["OP_SEL"] = OpSelect; OpMap["OP_REV16"] = OpRev16; OpMap["OP_REV32"] = OpRev32; OpMap["OP_REV64"] = OpRev64; + OpMap["OP_REINT"] = OpReinterpret; + OpMap["OP_ABDL"] = OpAbdl; + OpMap["OP_ABA"] = OpAba; + OpMap["OP_ABAL"] = OpAbal; Record *SI = R.getClass("SInst"); Record *II = R.getClass("IInst"); @@ -109,14 +161,20 @@ namespace llvm { ClassMap[II] = ClassI; ClassMap[WI] = ClassW; } - + // run - Emit arm_neon.h.inc void run(raw_ostream &o); // runHeader - Emit all the __builtin prototypes used in arm_neon.h void runHeader(raw_ostream &o); + + // runTests - Emit tests for all the Neon intrinsics. + void runTests(raw_ostream &o); + + private: + void emitIntrinsic(raw_ostream &OS, Record *R); }; - + } // End llvm namespace #endif diff --git a/utils/TableGen/Record.cpp b/utils/TableGen/Record.cpp index dc793586fbee..abbbafed09d8 100644 --- a/utils/TableGen/Record.cpp +++ b/utils/TableGen/Record.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "Record.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/Support/Format.h" #include "llvm/ADT/StringExtras.h" @@ -59,26 +59,34 @@ Init *BitsRecTy::convertValue(UnsetInit *UI) { } Init *BitsRecTy::convertValue(BitInit *UI) { - if (Size != 1) return 0; // Can only convert single bit... + if (Size != 1) return 0; // Can only convert single bit. BitsInit *Ret = new BitsInit(1); Ret->setBit(0, UI); return Ret; } -// convertValue from Int initializer to bits type: Split the integer up into the -// appropriate bits... -// -Init *BitsRecTy::convertValue(IntInit *II) { - int64_t Value = II->getValue(); - // Make sure this bitfield is large enough to hold the integer value... +/// canFitInBitfield - Return true if the number of bits is large enough to hold +/// the integer value. +static bool canFitInBitfield(int64_t Value, unsigned NumBits) { if (Value >= 0) { - if (Value & ~((1LL << Size)-1)) - return 0; - } else { - if ((Value >> Size) != -1 || ((Value & (1LL << (Size-1))) == 0)) - return 0; + if (Value & ~((1LL << NumBits) - 1)) + return false; + } else if ((Value >> NumBits) != -1 || (Value & (1LL << (NumBits-1))) == 0) { + return false; } + return true; +} + +/// convertValue from Int initializer to bits type: Split the integer up into the +/// appropriate bits. +/// +Init *BitsRecTy::convertValue(IntInit *II) { + int64_t Value = II->getValue(); + // Make sure this bitfield is large enough to hold the integer value. + if (!canFitInBitfield(Value, Size)) + return 0; + BitsInit *Ret = new BitsInit(Size); for (unsigned i = 0; i != Size; ++i) Ret->setBit(i, new BitInit(Value & (1LL << i))); @@ -88,7 +96,7 @@ Init *BitsRecTy::convertValue(IntInit *II) { Init *BitsRecTy::convertValue(BitsInit *BI) { // If the number of bits is right, return it. Otherwise we need to expand or - // truncate... + // truncate. if (BI->getNumBits() == Size) return BI; return 0; } @@ -101,12 +109,56 @@ Init *BitsRecTy::convertValue(TypedInit *VI) { Ret->setBit(i, new VarBitInit(VI, i)); return Ret; } + if (Size == 1 && dynamic_cast(VI->getType())) { BitsInit *Ret = new BitsInit(1); Ret->setBit(0, VI); return Ret; } + if (TernOpInit *Tern = dynamic_cast(VI)) { + if (Tern->getOpcode() == TernOpInit::IF) { + Init *LHS = Tern->getLHS(); + Init *MHS = Tern->getMHS(); + Init *RHS = Tern->getRHS(); + + IntInit *MHSi = dynamic_cast(MHS); + IntInit *RHSi = dynamic_cast(RHS); + + if (MHSi && RHSi) { + int64_t MHSVal = MHSi->getValue(); + int64_t RHSVal = RHSi->getValue(); + + if (canFitInBitfield(MHSVal, Size) && canFitInBitfield(RHSVal, Size)) { + BitsInit *Ret = new BitsInit(Size); + + for (unsigned i = 0; i != Size; ++i) + Ret->setBit(i, new TernOpInit(TernOpInit::IF, LHS, + new IntInit((MHSVal & (1LL << i)) ? 1 : 0), + new IntInit((RHSVal & (1LL << i)) ? 1 : 0), + VI->getType())); + + return Ret; + } + } else { + BitsInit *MHSbs = dynamic_cast(MHS); + BitsInit *RHSbs = dynamic_cast(RHS); + + if (MHSbs && RHSbs) { + BitsInit *Ret = new BitsInit(Size); + + for (unsigned i = 0; i != Size; ++i) + Ret->setBit(i, new TernOpInit(TernOpInit::IF, LHS, + MHSbs->getBit(i), + RHSbs->getBit(i), + VI->getType())); + + return Ret; + } + } + } + } + return 0; } @@ -152,16 +204,6 @@ Init *StringRecTy::convertValue(BinOpInit *BO) { return new BinOpInit(BinOpInit::STRCONCAT, L, R, new StringRecTy); return BO; } - if (BO->getOpcode() == BinOpInit::NAMECONCAT) { - if (BO->getType()->getAsString() == getAsString()) { - Init *L = BO->getLHS()->convertInitializerTo(this); - Init *R = BO->getRHS()->convertInitializerTo(this); - if (L == 0 || R == 0) return 0; - if (L != BO->getLHS() || R != BO->getRHS()) - return new BinOpInit(BinOpInit::NAMECONCAT, L, R, new StringRecTy); - return BO; - } - } return convertValue((TypedInit*)BO); } @@ -236,16 +278,6 @@ Init *DagRecTy::convertValue(BinOpInit *BO) { return new BinOpInit(BinOpInit::CONCAT, L, R, new DagRecTy); return BO; } - if (BO->getOpcode() == BinOpInit::NAMECONCAT) { - if (BO->getType()->getAsString() == getAsString()) { - Init *L = BO->getLHS()->convertInitializerTo(this); - Init *R = BO->getRHS()->convertInitializerTo(this); - if (L == 0 || R == 0) return 0; - if (L != BO->getLHS() || R != BO->getRHS()) - return new BinOpInit(BinOpInit::CONCAT, L, R, new DagRecTy); - return BO; - } - } return 0; } @@ -518,9 +550,8 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) { // From TGParser::ParseIDValue if (CurRec) { if (const RecordVal *RV = CurRec->getValue(Name)) { - if (RV->getType() != getType()) { - throw "type mismatch in nameconcat"; - } + if (RV->getType() != getType()) + throw "type mismatch in cast"; return new VarInit(Name, RV->getType()); } @@ -529,9 +560,8 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) { const RecordVal *RV = CurRec->getValue(TemplateArgName); assert(RV && "Template arg doesn't exist??"); - if (RV->getType() != getType()) { - throw "type mismatch in nameconcat"; - } + if (RV->getType() != getType()) + throw "type mismatch in cast"; return new VarInit(TemplateArgName, RV->getType()); } @@ -543,15 +573,14 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) { const RecordVal *RV = CurMultiClass->Rec.getValue(MCName); assert(RV && "Template arg doesn't exist??"); - if (RV->getType() != getType()) { - throw "type mismatch in nameconcat"; - } + if (RV->getType() != getType()) + throw "type mismatch in cast"; return new VarInit(MCName, RV->getType()); } } - if (Record *D = Records.getDef(Name)) + if (Record *D = (CurRec->getRecords()).getDef(Name)) return new DefInit(D); errs() << "Variable not defined: '" + Name + "'\n"; @@ -561,7 +590,7 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) { } break; } - case CAR: { + case HEAD: { ListInit *LHSl = dynamic_cast(LHS); if (LHSl) { if (LHSl->getSize() == 0) { @@ -572,7 +601,7 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) { } break; } - case CDR: { + case TAIL: { ListInit *LHSl = dynamic_cast(LHS); if (LHSl) { if (LHSl->getSize() == 0) { @@ -585,7 +614,7 @@ Init *UnOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) { } break; } - case LNULL: { + case EMPTY: { ListInit *LHSl = dynamic_cast(LHS); if (LHSl) { if (LHSl->getSize() == 0) { @@ -621,9 +650,9 @@ std::string UnOpInit::getAsString() const { std::string Result; switch (Opc) { case CAST: Result = "!cast<" + getType()->getAsString() + ">"; break; - case CAR: Result = "!car"; break; - case CDR: Result = "!cdr"; break; - case LNULL: Result = "!null"; break; + case HEAD: Result = "!head"; break; + case TAIL: Result = "!tail"; break; + case EMPTY: Result = "!empty"; break; } return Result + "(" + LHS->getAsString() + ")"; } @@ -660,57 +689,6 @@ Init *BinOpInit::Fold(Record *CurRec, MultiClass *CurMultiClass) { return new StringInit(LHSs->getValue() + RHSs->getValue()); break; } - case NAMECONCAT: { - StringInit *LHSs = dynamic_cast(LHS); - StringInit *RHSs = dynamic_cast(RHS); - if (LHSs && RHSs) { - std::string Name(LHSs->getValue() + RHSs->getValue()); - - // From TGParser::ParseIDValue - if (CurRec) { - if (const RecordVal *RV = CurRec->getValue(Name)) { - if (RV->getType() != getType()) { - throw "type mismatch in nameconcat"; - } - return new VarInit(Name, RV->getType()); - } - - std::string TemplateArgName = CurRec->getName()+":"+Name; - if (CurRec->isTemplateArg(TemplateArgName)) { - const RecordVal *RV = CurRec->getValue(TemplateArgName); - assert(RV && "Template arg doesn't exist??"); - - if (RV->getType() != getType()) { - throw "type mismatch in nameconcat"; - } - - return new VarInit(TemplateArgName, RV->getType()); - } - } - - if (CurMultiClass) { - std::string MCName = CurMultiClass->Rec.getName()+"::"+Name; - if (CurMultiClass->Rec.isTemplateArg(MCName)) { - const RecordVal *RV = CurMultiClass->Rec.getValue(MCName); - assert(RV && "Template arg doesn't exist??"); - - if (RV->getType() != getType()) { - throw "type mismatch in nameconcat"; - } - - return new VarInit(MCName, RV->getType()); - } - } - - if (Record *D = Records.getDef(Name)) - return new DefInit(D); - - errs() << "Variable not defined in !nameconcat: '" + Name + "'\n"; - assert(0 && "Variable not found in !nameconcat"); - return 0; - } - break; - } case EQ: { // try to fold eq comparison for 'bit' and 'int', otherwise fallback // to string objects. @@ -771,8 +749,6 @@ std::string BinOpInit::getAsString() const { case SRL: Result = "!srl"; break; case EQ: Result = "!eq"; break; case STRCONCAT: Result = "!strconcat"; break; - case NAMECONCAT: - Result = "!nameconcat<" + getType()->getAsString() + ">"; break; } return Result + "(" + LHS->getAsString() + ", " + RHS->getAsString() + ")"; } @@ -1042,7 +1018,7 @@ RecTy *TypedInit::getFieldType(const std::string &FieldName) const { Init *TypedInit::convertInitializerBitRange(const std::vector &Bits) { BitsRecTy *T = dynamic_cast(getType()); - if (T == 0) return 0; // Cannot subscript a non-bits variable... + if (T == 0) return 0; // Cannot subscript a non-bits variable. unsigned NumBits = T->getNumBits(); BitsInit *BI = new BitsInit(Bits.size()); @@ -1058,7 +1034,7 @@ Init *TypedInit::convertInitializerBitRange(const std::vector &Bits) { Init *TypedInit::convertInitListSlice(const std::vector &Elements) { ListRecTy *T = dynamic_cast(getType()); - if (T == 0) return 0; // Cannot subscript a non-list variable... + if (T == 0) return 0; // Cannot subscript a non-list variable. if (Elements.size() == 1) return new VarListElementInit(this, Elements[0]); @@ -1211,7 +1187,7 @@ Init *FieldInit::resolveBitReference(Record &R, const RecordVal *RV, assert(Bit < BI->getNumBits() && "Bit reference out of range!"); Init *B = BI->getBit(Bit); - if (dynamic_cast(B)) // If the bit is set... + if (dynamic_cast(B)) // If the bit is set. return B; // Replace the VarBitInit with it. } return 0; @@ -1303,14 +1279,14 @@ void RecordVal::print(raw_ostream &OS, bool PrintSem) const { unsigned Record::LastID = 0; void Record::setName(const std::string &Name) { - if (Records.getDef(getName()) == this) { - Records.removeDef(getName()); + if (TrackedRecords.getDef(getName()) == this) { + TrackedRecords.removeDef(getName()); this->Name = Name; - Records.addDef(this); + TrackedRecords.addDef(this); } else { - Records.removeClass(getName()); + TrackedRecords.removeClass(getName()); this->Name = Name; - Records.addClass(this); + TrackedRecords.addClass(this); } } @@ -1573,7 +1549,7 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, const RecordKeeper &RK) { /// name does not exist, an error is printed and true is returned. std::vector RecordKeeper::getAllDerivedDefinitions(const std::string &ClassName) const { - Record *Class = Records.getClass(ClassName); + Record *Class = getClass(ClassName); if (!Class) throw "ERROR: Couldn't find the `" + ClassName + "' class!\n"; diff --git a/utils/TableGen/Record.h b/utils/TableGen/Record.h index d6f37eec749e..f3a5df23ec5c 100644 --- a/utils/TableGen/Record.h +++ b/utils/TableGen/Record.h @@ -16,7 +16,7 @@ #define RECORD_H #include "llvm/Support/SourceMgr.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/Support/raw_ostream.h" #include @@ -57,6 +57,7 @@ class VarListElementInit; class Record; class RecordVal; struct MultiClass; +class RecordKeeper; //===----------------------------------------------------------------------===// // Type Classes @@ -810,7 +811,7 @@ public: /// class UnOpInit : public OpInit { public: - enum UnaryOp { CAST, CAR, CDR, LNULL }; + enum UnaryOp { CAST, HEAD, TAIL, EMPTY }; private: UnaryOp Opc; Init *LHS; @@ -848,7 +849,7 @@ public: /// class BinOpInit : public OpInit { public: - enum BinaryOp { SHL, SRA, SRL, STRCONCAT, CONCAT, NAMECONCAT, EQ }; + enum BinaryOp { SHL, SRA, SRL, STRCONCAT, CONCAT, EQ }; private: BinaryOp Opc; Init *LHS, *RHS; @@ -930,6 +931,8 @@ public: // possible to fold. Init *Fold(Record *CurRec, MultiClass *CurMultiClass); + virtual bool isComplete() const { return false; } + virtual Init *resolveReferences(Record &R, const RecordVal *RV); virtual std::string getAsString() const; @@ -1227,16 +1230,21 @@ class Record { std::vector TemplateArgs; std::vector Values; std::vector SuperClasses; + + // Tracks Record instances. Not owned by Record. + RecordKeeper &TrackedRecords; + public: - explicit Record(const std::string &N, SMLoc loc) : - ID(LastID++), Name(N), Loc(loc) {} + // Constructs a record. + explicit Record(const std::string &N, SMLoc loc, RecordKeeper &records) : + ID(LastID++), Name(N), Loc(loc), TrackedRecords(records) {} ~Record() {} - + static unsigned getNewUID() { return LastID++; } - - + + unsigned getID() const { return ID; } const std::string &getName() const { return Name; } @@ -1315,6 +1323,10 @@ public: /// possible references. void resolveReferencesTo(const RecordVal *RV); + RecordKeeper &getRecords() const { + return TrackedRecords; + } + void dump() const; //===--------------------------------------------------------------------===// @@ -1350,9 +1362,9 @@ public: /// std::vector getValueAsListOfDefs(StringRef FieldName) const; - /// getValueAsListOfInts - This method looks up the specified field and returns - /// its value as a vector of integers, throwing an exception if the field does - /// not exist or if the value is not the right type. + /// getValueAsListOfInts - This method looks up the specified field and + /// returns its value as a vector of integers, throwing an exception if the + /// field does not exist or if the value is not the right type. /// std::vector getValueAsListOfInts(StringRef FieldName) const; @@ -1396,7 +1408,8 @@ struct MultiClass { void dump() const; - MultiClass(const std::string &Name, SMLoc Loc) : Rec(Name, Loc) {} + MultiClass(const std::string &Name, SMLoc Loc, RecordKeeper &Records) : + Rec(Name, Loc, Records) {} }; class RecordKeeper { @@ -1453,7 +1466,6 @@ public: std::vector getAllDerivedDefinitions(const std::string &ClassName) const; - void dump() const; }; @@ -1488,9 +1500,7 @@ public: raw_ostream &operator<<(raw_ostream &OS, const RecordKeeper &RK); -extern RecordKeeper Records; - -void PrintError(SMLoc ErrorLoc, const std::string &Msg); +void PrintError(SMLoc ErrorLoc, const Twine &Msg); } // End llvm namespace diff --git a/utils/TableGen/RegisterInfoEmitter.cpp b/utils/TableGen/RegisterInfoEmitter.cpp index 6f06705243e9..96399a4d0525 100644 --- a/utils/TableGen/RegisterInfoEmitter.cpp +++ b/utils/TableGen/RegisterInfoEmitter.cpp @@ -25,7 +25,7 @@ using namespace llvm; // runEnums - Print out enum values for all of the registers. void RegisterInfoEmitter::runEnums(raw_ostream &OS) { - CodeGenTarget Target; + CodeGenTarget Target(Records); const std::vector &Registers = Target.getRegisters(); std::string Namespace = Registers[0].TheDef->getValueAsString("Namespace"); @@ -63,7 +63,7 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS) { void RegisterInfoEmitter::runHeader(raw_ostream &OS) { EmitSourceFileHeader("Register Information Header Fragment", OS); - CodeGenTarget Target; + CodeGenTarget Target(Records); const std::string &TargetName = Target.getName(); std::string ClassName = TargetName + "GenRegisterInfo"; @@ -333,7 +333,7 @@ public: // RegisterInfoEmitter::run - Main register file description emitter. // void RegisterInfoEmitter::run(raw_ostream &OS) { - CodeGenTarget Target; + CodeGenTarget Target(Records); EmitSourceFileHeader("Register Information Source Fragment", OS); OS << "namespace llvm {\n\n"; @@ -777,17 +777,13 @@ void RegisterInfoEmitter::run(raw_ostream &OS) { delete [] AliasesHashTable; if (!RegisterAliases.empty()) - OS << "\n\n // Register Alias Sets...\n"; + OS << "\n\n // Register Overlap Lists...\n"; - // Emit the empty alias list - OS << " const unsigned Empty_AliasSet[] = { 0 };\n"; - // Loop over all of the registers which have aliases, emitting the alias list - // to memory. + // Emit an overlap list for all registers. for (std::map, LessRecord >::iterator I = RegisterAliases.begin(), E = RegisterAliases.end(); I != E; ++I) { - if (I->second.empty()) - continue; - OS << " const unsigned " << I->first->getName() << "_AliasSet[] = { "; + OS << " const unsigned " << I->first->getName() << "_Overlaps[] = { " + << getQualifiedName(I->first) << ", "; for (std::set::iterator ASI = I->second.begin(), E = I->second.end(); ASI != E; ++ASI) OS << getQualifiedName(*ASI) << ", "; @@ -849,11 +845,7 @@ void RegisterInfoEmitter::run(raw_ostream &OS) { for (unsigned i = 0, e = Regs.size(); i != e; ++i) { const CodeGenRegister &Reg = Regs[i]; OS << " { \""; - OS << Reg.getName() << "\",\t"; - if (!RegisterAliases[Reg.TheDef].empty()) - OS << Reg.getName() << "_AliasSet,\t"; - else - OS << "Empty_AliasSet,\t"; + OS << Reg.getName() << "\",\t" << Reg.getName() << "_Overlaps,\t"; if (!RegisterSubRegs[Reg.TheDef].empty()) OS << Reg.getName() << "_SubRegsSet,\t"; else diff --git a/utils/TableGen/StringMatcher.cpp b/utils/TableGen/StringMatcher.cpp new file mode 100644 index 000000000000..6aedcbf458a8 --- /dev/null +++ b/utils/TableGen/StringMatcher.cpp @@ -0,0 +1,149 @@ +//===- StringMatcher.cpp - Generate a matcher for input strings -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the StringMatcher class. +// +//===----------------------------------------------------------------------===// + +#include "StringMatcher.h" +#include "llvm/Support/raw_ostream.h" +#include +using namespace llvm; + +/// FindFirstNonCommonLetter - Find the first character in the keys of the +/// string pairs that is not shared across the whole set of strings. All +/// strings are assumed to have the same length. +static unsigned +FindFirstNonCommonLetter(const std::vector &Matches) { + assert(!Matches.empty()); + for (unsigned i = 0, e = Matches[0]->first.size(); i != e; ++i) { + // Check to see if letter i is the same across the set. + char Letter = Matches[0]->first[i]; + + for (unsigned str = 0, e = Matches.size(); str != e; ++str) + if (Matches[str]->first[i] != Letter) + return i; + } + + return Matches[0]->first.size(); +} + +/// EmitStringMatcherForChar - Given a set of strings that are known to be the +/// same length and whose characters leading up to CharNo are the same, emit +/// code to verify that CharNo and later are the same. +/// +/// \return - True if control can leave the emitted code fragment. +bool StringMatcher:: +EmitStringMatcherForChar(const std::vector &Matches, + unsigned CharNo, unsigned IndentCount) const { + assert(!Matches.empty() && "Must have at least one string to match!"); + std::string Indent(IndentCount*2+4, ' '); + + // If we have verified that the entire string matches, we're done: output the + // matching code. + if (CharNo == Matches[0]->first.size()) { + assert(Matches.size() == 1 && "Had duplicate keys to match on"); + + // If the to-execute code has \n's in it, indent each subsequent line. + StringRef Code = Matches[0]->second; + + std::pair Split = Code.split('\n'); + OS << Indent << Split.first << "\t // \"" << Matches[0]->first << "\"\n"; + + Code = Split.second; + while (!Code.empty()) { + Split = Code.split('\n'); + OS << Indent << Split.first << "\n"; + Code = Split.second; + } + return false; + } + + // Bucket the matches by the character we are comparing. + std::map > MatchesByLetter; + + for (unsigned i = 0, e = Matches.size(); i != e; ++i) + MatchesByLetter[Matches[i]->first[CharNo]].push_back(Matches[i]); + + + // If we have exactly one bucket to match, see how many characters are common + // across the whole set and match all of them at once. + if (MatchesByLetter.size() == 1) { + unsigned FirstNonCommonLetter = FindFirstNonCommonLetter(Matches); + unsigned NumChars = FirstNonCommonLetter-CharNo; + + // Emit code to break out if the prefix doesn't match. + if (NumChars == 1) { + // Do the comparison with if (Str[1] != 'f') + // FIXME: Need to escape general characters. + OS << Indent << "if (" << StrVariableName << "[" << CharNo << "] != '" + << Matches[0]->first[CharNo] << "')\n"; + OS << Indent << " break;\n"; + } else { + // Do the comparison with if (Str.substr(1, 3) != "foo"). + // FIXME: Need to escape general strings. + OS << Indent << "if (" << StrVariableName << ".substr(" << CharNo << ", " + << NumChars << ") != \""; + OS << Matches[0]->first.substr(CharNo, NumChars) << "\")\n"; + OS << Indent << " break;\n"; + } + + return EmitStringMatcherForChar(Matches, FirstNonCommonLetter, IndentCount); + } + + // Otherwise, we have multiple possible things, emit a switch on the + // character. + OS << Indent << "switch (" << StrVariableName << "[" << CharNo << "]) {\n"; + OS << Indent << "default: break;\n"; + + for (std::map >::iterator LI = + MatchesByLetter.begin(), E = MatchesByLetter.end(); LI != E; ++LI) { + // TODO: escape hard stuff (like \n) if we ever care about it. + OS << Indent << "case '" << LI->first << "':\t // " + << LI->second.size() << " string"; + if (LI->second.size() != 1) OS << 's'; + OS << " to match.\n"; + if (EmitStringMatcherForChar(LI->second, CharNo+1, IndentCount+1)) + OS << Indent << " break;\n"; + } + + OS << Indent << "}\n"; + return true; +} + + +/// Emit - Top level entry point. +/// +void StringMatcher::Emit(unsigned Indent) const { + // If nothing to match, just fall through. + if (Matches.empty()) return; + + // First level categorization: group strings by length. + std::map > MatchesByLength; + + for (unsigned i = 0, e = Matches.size(); i != e; ++i) + MatchesByLength[Matches[i].first.size()].push_back(&Matches[i]); + + // Output a switch statement on length and categorize the elements within each + // bin. + OS.indent(Indent*2+2) << "switch (" << StrVariableName << ".size()) {\n"; + OS.indent(Indent*2+2) << "default: break;\n"; + + for (std::map >::iterator LI = + MatchesByLength.begin(), E = MatchesByLength.end(); LI != E; ++LI) { + OS.indent(Indent*2+2) << "case " << LI->first << ":\t // " + << LI->second.size() + << " string" << (LI->second.size() == 1 ? "" : "s") << " to match.\n"; + if (EmitStringMatcherForChar(LI->second, 0, Indent)) + OS.indent(Indent*2+4) << "break;\n"; + } + + OS.indent(Indent*2+2) << "}\n"; +} diff --git a/utils/TableGen/StringMatcher.h b/utils/TableGen/StringMatcher.h new file mode 100644 index 000000000000..1dadc76200b0 --- /dev/null +++ b/utils/TableGen/StringMatcher.h @@ -0,0 +1,54 @@ +//===- StringMatcher.h - Generate a matcher for input strings ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the StringMatcher class. +// +//===----------------------------------------------------------------------===// + +#ifndef STRINGMATCHER_H +#define STRINGMATCHER_H + +#include +#include +#include +#include "llvm/ADT/StringRef.h" + +namespace llvm { + class raw_ostream; + +/// StringMatcher - Given a list of strings and code to execute when they match, +/// output a simple switch tree to classify the input string. +/// +/// If a match is found, the code in Vals[i].second is executed; control must +/// not exit this code fragment. If nothing matches, execution falls through. +/// +class StringMatcher { +public: + typedef std::pair StringPair; +private: + StringRef StrVariableName; + const std::vector &Matches; + raw_ostream &OS; + +public: + StringMatcher(StringRef strVariableName, + const std::vector &matches, raw_ostream &os) + : StrVariableName(strVariableName), Matches(matches), OS(os) {} + + void Emit(unsigned Indent = 0) const; + + +private: + bool EmitStringMatcherForChar(const std::vector &Matches, + unsigned CharNo, unsigned IndentCount) const; +}; + +} // end llvm namespace. + +#endif diff --git a/utils/TableGen/SubtargetEmitter.cpp b/utils/TableGen/SubtargetEmitter.cpp index b04eaf88f73a..e35bdca97887 100644 --- a/utils/TableGen/SubtargetEmitter.cpp +++ b/utils/TableGen/SubtargetEmitter.cpp @@ -172,13 +172,10 @@ void SubtargetEmitter::CPUKeyValues(raw_ostream &OS) { // CollectAllItinClasses - Gathers and enumerates all the itinerary classes. // Returns itinerary class count. // -unsigned SubtargetEmitter::CollectAllItinClasses(raw_ostream &OS, - std::map &ItinClassesMap) { - // Gather and sort all itinerary classes - std::vector ItinClassList = - Records.getAllDerivedDefinitions("InstrItinClass"); - std::sort(ItinClassList.begin(), ItinClassList.end(), LessRecord()); - +unsigned SubtargetEmitter:: +CollectAllItinClasses(raw_ostream &OS, + std::map &ItinClassesMap, + std::vector &ItinClassList) { // For each itinerary class unsigned N = ItinClassList.size(); for (unsigned i = 0; i < N; i++) { @@ -265,13 +262,32 @@ void SubtargetEmitter::FormItineraryOperandCycleString(Record *ItinData, } } +void SubtargetEmitter::FormItineraryBypassString(const std::string &Name, + Record *ItinData, + std::string &ItinString, + unsigned NOperandCycles) { + const std::vector &BypassList = + ItinData->getValueAsListOfDefs("Bypasses"); + unsigned N = BypassList.size(); + unsigned i = 0; + for (; i < N;) { + ItinString += Name + "Bypass::" + BypassList[i]->getName(); + if (++i < NOperandCycles) ItinString += ", "; + } + for (; i < NOperandCycles;) { + ItinString += " 0"; + if (++i < NOperandCycles) ItinString += ", "; + } +} + // // EmitStageAndOperandCycleData - Generate unique itinerary stages and // operand cycle tables. Record itineraries for processors. // void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS, unsigned NItinClasses, - std::map &ItinClassesMap, + std::map &ItinClassesMap, + std::vector &ItinClassList, std::vector > &ProcList) { // Gather processor iteraries std::vector ProcItinList = @@ -298,6 +314,19 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS, << " = 1 << " << j << ";\n"; OS << "}\n"; + + std::vector BPs = Proc->getValueAsListOfDefs("BP"); + if (BPs.size()) { + OS << "\n// Pipeline forwarding pathes for itineraries \"" << Name + << "\"\n" << "namespace " << Name << "Bypass {\n"; + + OS << " const unsigned NoBypass = 0;\n"; + for (unsigned j = 0, BPN = BPs.size(); j < BPN; ++j) + OS << " const unsigned " << BPs[j]->getName() + << " = 1 << " << j << ";\n"; + + OS << "}\n"; + } } // Begin stages table @@ -307,10 +336,14 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS, // Begin operand cycle table std::string OperandCycleTable = "static const unsigned OperandCycles[] = {\n"; OperandCycleTable += " 0, // No itinerary\n"; + + // Begin pipeline bypass table + std::string BypassTable = "static const unsigned ForwardingPathes[] = {\n"; + BypassTable += " 0, // No itinerary\n"; unsigned StageCount = 1, OperandCycleCount = 1; unsigned ItinStageEnum = 1, ItinOperandCycleEnum = 1; - std::map ItinStageMap, ItinOperandCycleMap; + std::map ItinStageMap, ItinOperandMap; for (unsigned i = 0, N = ProcItinList.size(); i < N; i++) { // Next record Record *Proc = ProcItinList[i]; @@ -344,6 +377,10 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS, FormItineraryOperandCycleString(ItinData, ItinOperandCycleString, NOperandCycles); + std::string ItinBypassString; + FormItineraryBypassString(Name, ItinData, ItinBypassString, + NOperandCycles); + // Check to see if stage already exists and create if it doesn't unsigned FindStage = 0; if (NStages > 0) { @@ -361,27 +398,35 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS, // Check to see if operand cycle already exists and create if it doesn't unsigned FindOperandCycle = 0; if (NOperandCycles > 0) { - FindOperandCycle = ItinOperandCycleMap[ItinOperandCycleString]; + std::string ItinOperandString = ItinOperandCycleString+ItinBypassString; + FindOperandCycle = ItinOperandMap[ItinOperandString]; if (FindOperandCycle == 0) { // Emit as cycle, // index OperandCycleTable += ItinOperandCycleString + ", // " + itostr(ItinOperandCycleEnum) + "\n"; // Record Itin class number. - ItinOperandCycleMap[ItinOperandCycleString] = + ItinOperandMap[ItinOperandCycleString] = FindOperandCycle = OperandCycleCount; + + // Emit as bypass, // index + BypassTable += ItinBypassString + ", // " + + itostr(ItinOperandCycleEnum) + "\n"; + OperandCycleCount += NOperandCycles; ItinOperandCycleEnum++; } } - // Set up itinerary as location and location + stage count - InstrItinerary Intinerary = { FindStage, FindStage + NStages, - FindOperandCycle, FindOperandCycle + NOperandCycles}; - // Locate where to inject into processor itinerary table const std::string &Name = ItinData->getValueAsDef("TheClass")->getName(); unsigned Find = ItinClassesMap[Name]; + // Set up itinerary as location and location + stage count + unsigned NumUOps = ItinClassList[Find]->getValueAsInt("NumMicroOps"); + InstrItinerary Intinerary = { NumUOps, FindStage, FindStage + NStages, + FindOperandCycle, + FindOperandCycle + NOperandCycles}; + // Inject - empty slots will be 0, 0 ItinList[Find] = Intinerary; } @@ -389,7 +434,7 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS, // Add process itinerary to list ProcList.push_back(ItinList); } - + // Closing stage StageTable += " { 0, 0, 0, llvm::InstrStage::Required } // End itinerary\n"; StageTable += "};\n"; @@ -398,9 +443,13 @@ void SubtargetEmitter::EmitStageAndOperandCycleData(raw_ostream &OS, OperandCycleTable += " 0 // End itinerary\n"; OperandCycleTable += "};\n"; + BypassTable += " 0 // End itinerary\n"; + BypassTable += "};\n"; + // Emit tables. OS << StageTable; OS << OperandCycleTable; + OS << BypassTable; // Emit size of tables OS<<"\nenum {\n"; @@ -443,9 +492,11 @@ void SubtargetEmitter::EmitProcessorData(raw_ostream &OS, // Emit in the form of // { firstStage, lastStage, firstCycle, lastCycle } // index if (Intinerary.FirstStage == 0) { - OS << " { 0, 0, 0, 0 }"; + OS << " { 1, 0, 0, 0, 0 }"; } else { - OS << " { " << Intinerary.FirstStage << ", " << + OS << " { " << + Intinerary.NumMicroOps << ", " << + Intinerary.FirstStage << ", " << Intinerary.LastStage << ", " << Intinerary.FirstOperandCycle << ", " << Intinerary.LastOperandCycle << " }"; @@ -455,7 +506,7 @@ void SubtargetEmitter::EmitProcessorData(raw_ostream &OS, } // End processor itinerary table - OS << " { ~0U, ~0U, ~0U, ~0U } // end marker\n"; + OS << " { 1, ~0U, ~0U, ~0U, ~0U } // end marker\n"; OS << "};\n"; } } @@ -511,16 +562,22 @@ void SubtargetEmitter::EmitProcessorLookup(raw_ostream &OS) { // void SubtargetEmitter::EmitData(raw_ostream &OS) { std::map ItinClassesMap; - std::vector > ProcList; + // Gather and sort all itinerary classes + std::vector ItinClassList = + Records.getAllDerivedDefinitions("InstrItinClass"); + std::sort(ItinClassList.begin(), ItinClassList.end(), LessRecord()); // Enumerate all the itinerary classes - unsigned NItinClasses = CollectAllItinClasses(OS, ItinClassesMap); + unsigned NItinClasses = CollectAllItinClasses(OS, ItinClassesMap, + ItinClassList); // Make sure the rest is worth the effort HasItineraries = NItinClasses != 1; // Ignore NoItinerary. if (HasItineraries) { + std::vector > ProcList; // Emit the stage data - EmitStageAndOperandCycleData(OS, NItinClasses, ItinClassesMap, ProcList); + EmitStageAndOperandCycleData(OS, NItinClasses, ItinClassesMap, + ItinClassList, ProcList); // Emit the processor itinerary data EmitProcessorData(OS, ProcList); // Emit the processor lookup data @@ -569,7 +626,8 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS) { OS << "\n" << " InstrItinerary *Itinerary = (InstrItinerary *)" << "Features.getInfo(ProcItinKV, ProcItinKVSize);\n" - << " InstrItins = InstrItineraryData(Stages, OperandCycles, Itinerary);\n"; + << " InstrItins = InstrItineraryData(Stages, OperandCycles, " + << "ForwardingPathes, Itinerary);\n"; } OS << " return Features.getCPU();\n" @@ -580,7 +638,7 @@ void SubtargetEmitter::ParseFeaturesFunction(raw_ostream &OS) { // SubtargetEmitter::run - Main subtarget enumeration emitter. // void SubtargetEmitter::run(raw_ostream &OS) { - Target = CodeGenTarget().getName(); + Target = CodeGenTarget(Records).getName(); EmitSourceFileHeader("Subtarget Enumeration Source Fragment", OS); diff --git a/utils/TableGen/SubtargetEmitter.h b/utils/TableGen/SubtargetEmitter.h index f43a4431d61e..3abec3b24091 100644 --- a/utils/TableGen/SubtargetEmitter.h +++ b/utils/TableGen/SubtargetEmitter.h @@ -33,14 +33,19 @@ class SubtargetEmitter : public TableGenBackend { void FeatureKeyValues(raw_ostream &OS); void CPUKeyValues(raw_ostream &OS); unsigned CollectAllItinClasses(raw_ostream &OS, - std::map &ItinClassesMap); + std::map &ItinClassesMap, + std::vector &ItinClassList); void FormItineraryStageString(const std::string &Names, Record *ItinData, std::string &ItinString, unsigned &NStages); void FormItineraryOperandCycleString(Record *ItinData, std::string &ItinString, unsigned &NOperandCycles); + void FormItineraryBypassString(const std::string &Names, + Record *ItinData, + std::string &ItinString, unsigned NOperandCycles); void EmitStageAndOperandCycleData(raw_ostream &OS, unsigned NItinClasses, std::map &ItinClassesMap, + std::vector &ItinClassList, std::vector > &ProcList); void EmitProcessorData(raw_ostream &OS, std::vector > &ProcList); diff --git a/utils/TableGen/TGLexer.cpp b/utils/TableGen/TGLexer.cpp index 2c7becc71824..82d2b6491aac 100644 --- a/utils/TableGen/TGLexer.cpp +++ b/utils/TableGen/TGLexer.cpp @@ -15,6 +15,8 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Config/config.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Twine.h" #include #include #include @@ -36,17 +38,17 @@ SMLoc TGLexer::getLoc() const { /// ReturnError - Set the error to the specified string at the specified /// location. This is defined to always return tgtok::Error. -tgtok::TokKind TGLexer::ReturnError(const char *Loc, const std::string &Msg) { +tgtok::TokKind TGLexer::ReturnError(const char *Loc, const Twine &Msg) { PrintError(Loc, Msg); return tgtok::Error; } -void TGLexer::PrintError(const char *Loc, const std::string &Msg) const { +void TGLexer::PrintError(const char *Loc, const Twine &Msg) const { SrcMgr.PrintMessage(SMLoc::getFromPointer(Loc), Msg, "error"); } -void TGLexer::PrintError(SMLoc Loc, const std::string &Msg) const { +void TGLexer::PrintError(SMLoc Loc, const Twine &Msg) const { SrcMgr.PrintMessage(Loc, Msg, "error"); } @@ -95,7 +97,7 @@ tgtok::TokKind TGLexer::LexToken() { switch (CurChar) { default: - // Handle letters: [a-zA-Z_] + // Handle letters: [a-zA-Z_#] if (isalpha(CurChar) || CurChar == '_' || CurChar == '#') return LexIdentifier(); @@ -214,23 +216,13 @@ tgtok::TokKind TGLexer::LexVarName() { tgtok::TokKind TGLexer::LexIdentifier() { - // The first letter is [a-zA-Z_]. + // The first letter is [a-zA-Z_#]. const char *IdentStart = TokStart; - // Match the rest of the identifier regex: [0-9a-zA-Z_]* - while (isalpha(*CurPtr) || isdigit(*CurPtr) || *CurPtr == '_' - || *CurPtr == '#') { - // If this contains a '#', make sure it's value - if (*CurPtr == '#') { - if (strncmp(CurPtr, "#NAME#", 6) != 0) { - return tgtok::Error; - } - CurPtr += 6; - } - else { - ++CurPtr; - } - } + // Match the rest of the identifier regex: [0-9a-zA-Z_#]* + while (isalpha(*CurPtr) || isdigit(*CurPtr) || *CurPtr == '_' || + *CurPtr == '#') + ++CurPtr; // Check to see if this identifier is a keyword. @@ -421,30 +413,30 @@ tgtok::TokKind TGLexer::LexBracket() { /// LexExclaim - Lex '!' and '![a-zA-Z]+'. tgtok::TokKind TGLexer::LexExclaim() { if (!isalpha(*CurPtr)) - return ReturnError(CurPtr-1, "Invalid \"!operator\""); + return ReturnError(CurPtr - 1, "Invalid \"!operator\""); const char *Start = CurPtr++; while (isalpha(*CurPtr)) ++CurPtr; // Check to see which operator this is. - unsigned Len = CurPtr-Start; - - if (Len == 3 && !memcmp(Start, "con", 3)) return tgtok::XConcat; - if (Len == 3 && !memcmp(Start, "sra", 3)) return tgtok::XSRA; - if (Len == 3 && !memcmp(Start, "srl", 3)) return tgtok::XSRL; - if (Len == 3 && !memcmp(Start, "shl", 3)) return tgtok::XSHL; - if (Len == 2 && !memcmp(Start, "eq", 2)) return tgtok::XEq; - if (Len == 9 && !memcmp(Start, "strconcat", 9)) return tgtok::XStrConcat; - if (Len == 10 && !memcmp(Start, "nameconcat", 10)) return tgtok::XNameConcat; - if (Len == 5 && !memcmp(Start, "subst", 5)) return tgtok::XSubst; - if (Len == 7 && !memcmp(Start, "foreach", 7)) return tgtok::XForEach; - if (Len == 4 && !memcmp(Start, "cast", 4)) return tgtok::XCast; - if (Len == 3 && !memcmp(Start, "car", 3)) return tgtok::XCar; - if (Len == 3 && !memcmp(Start, "cdr", 3)) return tgtok::XCdr; - if (Len == 4 && !memcmp(Start, "null", 4)) return tgtok::XNull; - if (Len == 2 && !memcmp(Start, "if", 2)) return tgtok::XIf; - - return ReturnError(Start-1, "Unknown operator"); + tgtok::TokKind Kind = + StringSwitch(StringRef(Start, CurPtr - Start)) + .Case("eq", tgtok::XEq) + .Case("if", tgtok::XIf) + .Case("head", tgtok::XHead) + .Case("tail", tgtok::XTail) + .Case("con", tgtok::XConcat) + .Case("shl", tgtok::XSHL) + .Case("sra", tgtok::XSRA) + .Case("srl", tgtok::XSRL) + .Case("cast", tgtok::XCast) + .Case("empty", tgtok::XEmpty) + .Case("subst", tgtok::XSubst) + .Case("foreach", tgtok::XForEach) + .Case("strconcat", tgtok::XStrConcat) + .Default(tgtok::Error); + + return Kind != tgtok::Error ? Kind : ReturnError(Start-1, "Unknown operator"); } diff --git a/utils/TableGen/TGLexer.h b/utils/TableGen/TGLexer.h index 835f351d3d0d..55a6c5d9b52e 100644 --- a/utils/TableGen/TGLexer.h +++ b/utils/TableGen/TGLexer.h @@ -14,7 +14,7 @@ #ifndef TGLEXER_H #define TGLEXER_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include #include #include @@ -23,7 +23,8 @@ namespace llvm { class MemoryBuffer; class SourceMgr; class SMLoc; - +class Twine; + namespace tgtok { enum TokKind { // Markers @@ -44,8 +45,8 @@ namespace tgtok { MultiClass, String, // !keywords. - XConcat, XSRA, XSRL, XSHL, XStrConcat, XNameConcat, XCast, XSubst, - XForEach, XCar, XCdr, XNull, XIf, XEq, + XConcat, XSRA, XSRL, XSHL, XStrConcat, XCast, XSubst, + XForEach, XHead, XTail, XEmpty, XIf, XEq, // Integer value. IntVal, @@ -95,14 +96,14 @@ public: SMLoc getLoc() const; - void PrintError(const char *Loc, const std::string &Msg) const; - void PrintError(SMLoc Loc, const std::string &Msg) const; + void PrintError(const char *Loc, const Twine &Msg) const; + void PrintError(SMLoc Loc, const Twine &Msg) const; private: /// LexToken - Read the next token and return its code. tgtok::TokKind LexToken(); - tgtok::TokKind ReturnError(const char *Loc, const std::string &Msg); + tgtok::TokKind ReturnError(const char *Loc, const Twine &Msg); int getNextChar(); void SkipBCPLComment(); diff --git a/utils/TableGen/TGParser.cpp b/utils/TableGen/TGParser.cpp index f81aabe79b03..f6041be95e16 100644 --- a/utils/TableGen/TGParser.cpp +++ b/utils/TableGen/TGParser.cpp @@ -16,6 +16,8 @@ #include "llvm/ADT/StringExtras.h" #include #include +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/CommandLine.h" using namespace llvm; //===----------------------------------------------------------------------===// @@ -294,20 +296,23 @@ static bool isObjectStart(tgtok::TokKind K) { K == tgtok::Defm || K == tgtok::Let || K == tgtok::MultiClass; } +static std::string GetNewAnonymousName() { + static unsigned AnonCounter = 0; + return "anonymous."+utostr(AnonCounter++); +} + /// ParseObjectName - If an object name is specified, return it. Otherwise, /// return an anonymous name. /// ObjectName ::= ID /// ObjectName ::= /*empty*/ /// std::string TGParser::ParseObjectName() { - if (Lex.getCode() == tgtok::Id) { - std::string Ret = Lex.getCurStrVal(); - Lex.Lex(); - return Ret; - } + if (Lex.getCode() != tgtok::Id) + return GetNewAnonymousName(); - static unsigned AnonCounter = 0; - return "anonymous."+utostr(AnonCounter++); + std::string Ret = Lex.getCurStrVal(); + Lex.Lex(); + return Ret; } @@ -678,9 +683,9 @@ Init *TGParser::ParseOperation(Record *CurRec) { TokError("unknown operation"); return 0; break; - case tgtok::XCar: - case tgtok::XCdr: - case tgtok::XNull: + case tgtok::XHead: + case tgtok::XTail: + case tgtok::XEmpty: case tgtok::XCast: { // Value ::= !unop '(' Value ')' UnOpInit::UnaryOp Code; RecTy *Type = 0; @@ -699,17 +704,17 @@ Init *TGParser::ParseOperation(Record *CurRec) { } break; - case tgtok::XCar: + case tgtok::XHead: Lex.Lex(); // eat the operation - Code = UnOpInit::CAR; + Code = UnOpInit::HEAD; break; - case tgtok::XCdr: + case tgtok::XTail: Lex.Lex(); // eat the operation - Code = UnOpInit::CDR; + Code = UnOpInit::TAIL; break; - case tgtok::XNull: + case tgtok::XEmpty: Lex.Lex(); // eat the operation - Code = UnOpInit::LNULL; + Code = UnOpInit::EMPTY; Type = new IntRecTy; break; } @@ -722,9 +727,9 @@ Init *TGParser::ParseOperation(Record *CurRec) { Init *LHS = ParseValue(CurRec); if (LHS == 0) return 0; - if (Code == UnOpInit::CAR - || Code == UnOpInit::CDR - || Code == UnOpInit::LNULL) { + if (Code == UnOpInit::HEAD + || Code == UnOpInit::TAIL + || Code == UnOpInit::EMPTY) { ListInit *LHSl = dynamic_cast(LHS); StringInit *LHSs = dynamic_cast(LHS); TypedInit *LHSt = dynamic_cast(LHS); @@ -741,8 +746,8 @@ Init *TGParser::ParseOperation(Record *CurRec) { } } - if (Code == UnOpInit::CAR - || Code == UnOpInit::CDR) { + if (Code == UnOpInit::HEAD + || Code == UnOpInit::TAIL) { if (LHSl == 0 && LHSt == 0) { TokError("expected list type argumnet in unary operator"); return 0; @@ -759,7 +764,7 @@ Init *TGParser::ParseOperation(Record *CurRec) { TokError("untyped list element in unary operator"); return 0; } - if (Code == UnOpInit::CAR) { + if (Code == UnOpInit::HEAD) { Type = Itemt->getType(); } else { Type = new ListRecTy(Itemt->getType()); @@ -771,7 +776,7 @@ Init *TGParser::ParseOperation(Record *CurRec) { TokError("expected list type argumnet in unary operator"); return 0; } - if (Code == UnOpInit::CAR) { + if (Code == UnOpInit::HEAD) { Type = LType->getElementType(); } else { Type = LType; @@ -793,81 +798,68 @@ Init *TGParser::ParseOperation(Record *CurRec) { case tgtok::XSRL: case tgtok::XSHL: case tgtok::XEq: - case tgtok::XStrConcat: - case tgtok::XNameConcat: { // Value ::= !binop '(' Value ',' Value ')' + case tgtok::XStrConcat: { // Value ::= !binop '(' Value ',' Value ')' + tgtok::TokKind OpTok = Lex.getCode(); + SMLoc OpLoc = Lex.getLoc(); + Lex.Lex(); // eat the operation + BinOpInit::BinaryOp Code; RecTy *Type = 0; - - switch (Lex.getCode()) { + switch (OpTok) { default: assert(0 && "Unhandled code!"); - case tgtok::XConcat: - Lex.Lex(); // eat the operation - Code = BinOpInit::CONCAT; - Type = new DagRecTy(); - break; - case tgtok::XSRA: - Lex.Lex(); // eat the operation - Code = BinOpInit::SRA; - Type = new IntRecTy(); - break; - case tgtok::XSRL: - Lex.Lex(); // eat the operation - Code = BinOpInit::SRL; - Type = new IntRecTy(); - break; - case tgtok::XSHL: - Lex.Lex(); // eat the operation - Code = BinOpInit::SHL; - Type = new IntRecTy(); - break; - case tgtok::XEq: - Lex.Lex(); // eat the operation - Code = BinOpInit::EQ; - Type = new IntRecTy(); - break; + case tgtok::XConcat: Code = BinOpInit::CONCAT; Type = new DagRecTy(); break; + case tgtok::XSRA: Code = BinOpInit::SRA; Type = new IntRecTy(); break; + case tgtok::XSRL: Code = BinOpInit::SRL; Type = new IntRecTy(); break; + case tgtok::XSHL: Code = BinOpInit::SHL; Type = new IntRecTy(); break; + case tgtok::XEq: Code = BinOpInit::EQ; Type = new BitRecTy(); break; case tgtok::XStrConcat: - Lex.Lex(); // eat the operation Code = BinOpInit::STRCONCAT; Type = new StringRecTy(); - break; - case tgtok::XNameConcat: - Lex.Lex(); // eat the operation - Code = BinOpInit::NAMECONCAT; - - Type = ParseOperatorType(); - - if (Type == 0) { - TokError("did not get type for binary operator"); - return 0; - } - break; } + if (Lex.getCode() != tgtok::l_paren) { TokError("expected '(' after binary operator"); return 0; } Lex.Lex(); // eat the '(' - Init *LHS = ParseValue(CurRec); - if (LHS == 0) return 0; + SmallVector InitList; - if (Lex.getCode() != tgtok::comma) { - TokError("expected ',' in binary operator"); - return 0; - } - Lex.Lex(); // eat the ',' + InitList.push_back(ParseValue(CurRec)); + if (InitList.back() == 0) return 0; - Init *RHS = ParseValue(CurRec); - if (RHS == 0) return 0; + while (Lex.getCode() == tgtok::comma) { + Lex.Lex(); // eat the ',' + + InitList.push_back(ParseValue(CurRec)); + if (InitList.back() == 0) return 0; + } if (Lex.getCode() != tgtok::r_paren) { - TokError("expected ')' in binary operator"); + TokError("expected ')' in operator"); return 0; } Lex.Lex(); // eat the ')' - return (new BinOpInit(Code, LHS, RHS, Type))->Fold(CurRec, CurMultiClass); + + // We allow multiple operands to associative operators like !strconcat as + // shorthand for nesting them. + if (Code == BinOpInit::STRCONCAT) { + while (InitList.size() > 2) { + Init *RHS = InitList.pop_back_val(); + RHS = (new BinOpInit(Code, InitList.back(), RHS, Type)) + ->Fold(CurRec, CurMultiClass); + InitList.back() = RHS; + } + } + + if (InitList.size() == 2) + return (new BinOpInit(Code, InitList[0], InitList[1], Type)) + ->Fold(CurRec, CurMultiClass); + + Error(OpLoc, "expected two operands to operator"); + return 0; } case tgtok::XIf: @@ -876,7 +868,6 @@ Init *TGParser::ParseOperation(Record *CurRec) { TernOpInit::TernaryOp Code; RecTy *Type = 0; - tgtok::TokKind LexCode = Lex.getCode(); Lex.Lex(); // eat the operation switch (LexCode) { @@ -927,16 +918,45 @@ Init *TGParser::ParseOperation(Record *CurRec) { switch (LexCode) { default: assert(0 && "Unhandled code!"); case tgtok::XIf: { - TypedInit *MHSt = dynamic_cast(MHS); - TypedInit *RHSt = dynamic_cast(RHS); - if (MHSt == 0 || RHSt == 0) { + // FIXME: The `!if' operator doesn't handle non-TypedInit well at + // all. This can be made much more robust. + TypedInit *MHSt = dynamic_cast(MHS); + TypedInit *RHSt = dynamic_cast(RHS); + + RecTy *MHSTy = 0; + RecTy *RHSTy = 0; + + if (MHSt == 0 && RHSt == 0) { + BitsInit *MHSbits = dynamic_cast(MHS); + BitsInit *RHSbits = dynamic_cast(RHS); + + if (MHSbits && RHSbits && + MHSbits->getNumBits() == RHSbits->getNumBits()) { + Type = new BitRecTy(); + break; + } else { + BitInit *MHSbit = dynamic_cast(MHS); + BitInit *RHSbit = dynamic_cast(RHS); + + if (MHSbit && RHSbit) { + Type = new BitRecTy(); + break; + } + } + } else if (MHSt != 0 && RHSt != 0) { + MHSTy = MHSt->getType(); + RHSTy = RHSt->getType(); + } + + if (!MHSTy || !RHSTy) { TokError("could not get type for !if"); return 0; } - if (MHSt->getType()->typeIsConvertibleTo(RHSt->getType())) { - Type = RHSt->getType(); - } else if (RHSt->getType()->typeIsConvertibleTo(MHSt->getType())) { - Type = MHSt->getType(); + + if (MHSTy->typeIsConvertibleTo(RHSTy)) { + Type = RHSTy; + } else if (RHSTy->typeIsConvertibleTo(MHSTy)) { + Type = MHSTy; } else { TokError("inconsistent types for !if"); return 0; @@ -1037,8 +1057,13 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType) { break; } case tgtok::CodeFragment: - R = new CodeInit(Lex.getCurStrVal()); Lex.Lex(); break; - case tgtok::question: R = new UnsetInit(); Lex.Lex(); break; + R = new CodeInit(Lex.getCurStrVal()); + Lex.Lex(); + break; + case tgtok::question: + R = new UnsetInit(); + Lex.Lex(); + break; case tgtok::Id: { SMLoc NameLoc = Lex.getLoc(); std::string Name = Lex.getCurStrVal(); @@ -1071,7 +1096,9 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType) { // Create the new record, set it as CurRec temporarily. static unsigned AnonCounter = 0; - Record *NewRec = new Record("anonymous.val."+utostr(AnonCounter++),NameLoc); + Record *NewRec = new Record("anonymous.val."+utostr(AnonCounter++), + NameLoc, + Records); SubClassReference SCRef; SCRef.RefLoc = NameLoc; SCRef.Rec = Class; @@ -1212,21 +1239,13 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType) { } case tgtok::l_paren: { // Value ::= '(' IDValue DagArgList ')' Lex.Lex(); // eat the '(' - if (Lex.getCode() != tgtok::Id - && Lex.getCode() != tgtok::XCast - && Lex.getCode() != tgtok::XNameConcat) { + if (Lex.getCode() != tgtok::Id && Lex.getCode() != tgtok::XCast) { TokError("expected identifier in dag init"); return 0; } - Init *Operator = 0; - if (Lex.getCode() == tgtok::Id) { - Operator = ParseIDValue(CurRec); - if (Operator == 0) return 0; - } else { - Operator = ParseOperation(CurRec); - if (Operator == 0) return 0; - } + Init *Operator = ParseValue(CurRec); + if (Operator == 0) return 0; // If the operator name is present, parse it. std::string OperatorName; @@ -1252,25 +1271,22 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType) { Lex.Lex(); // eat the ')' return new DagInit(Operator, OperatorName, DagArgs); - break; } - case tgtok::XCar: - case tgtok::XCdr: - case tgtok::XNull: + case tgtok::XHead: + case tgtok::XTail: + case tgtok::XEmpty: case tgtok::XCast: // Value ::= !unop '(' Value ')' case tgtok::XConcat: case tgtok::XSRA: case tgtok::XSRL: case tgtok::XSHL: case tgtok::XEq: - case tgtok::XStrConcat: - case tgtok::XNameConcat: // Value ::= !binop '(' Value ',' Value ')' + case tgtok::XStrConcat: // Value ::= !binop '(' Value ',' Value ')' case tgtok::XIf: case tgtok::XForEach: case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')' return ParseOperation(CurRec); - break; } } @@ -1646,7 +1662,7 @@ bool TGParser::ParseDef(MultiClass *CurMultiClass) { Lex.Lex(); // Eat the 'def' token. // Parse ObjectName and make a record for it. - Record *CurRec = new Record(ParseObjectName(), DefLoc); + Record *CurRec = new Record(ParseObjectName(), DefLoc, Records); if (!CurMultiClass) { // Top-level def definition. @@ -1713,7 +1729,7 @@ bool TGParser::ParseClass() { return TokError("Class '" + CurRec->getName() + "' already defined"); } else { // If this is the first reference to this class, create and add it. - CurRec = new Record(Lex.getCurStrVal(), Lex.getLoc()); + CurRec = new Record(Lex.getCurStrVal(), Lex.getLoc(), Records); Records.addClass(CurRec); } Lex.Lex(); // eat the name. @@ -1830,7 +1846,8 @@ bool TGParser::ParseMultiClass() { if (MultiClasses.count(Name)) return TokError("multiclass '" + Name + "' already defined"); - CurMultiClass = MultiClasses[Name] = new MultiClass(Name, Lex.getLoc()); + CurMultiClass = MultiClasses[Name] = new MultiClass(Name, + Lex.getLoc(), Records); Lex.Lex(); // Eat the identifier. // If there are template args, parse them. @@ -1899,12 +1916,15 @@ bool TGParser::ParseMultiClass() { /// bool TGParser::ParseDefm(MultiClass *CurMultiClass) { assert(Lex.getCode() == tgtok::Defm && "Unexpected token!"); - if (Lex.Lex() != tgtok::Id) // eat the defm. - return TokError("expected identifier after defm"); + + std::string DefmPrefix; + if (Lex.Lex() == tgtok::Id) { // eat the defm. + DefmPrefix = Lex.getCurStrVal(); + Lex.Lex(); // Eat the defm prefix. + } SMLoc DefmPrefixLoc = Lex.getLoc(); - std::string DefmPrefix = Lex.getCurStrVal(); - if (Lex.Lex() != tgtok::colon) + if (Lex.getCode() != tgtok::colon) return TokError("expected ':' after defm identifier"); // Keep track of the new generated record definitions. @@ -1939,17 +1959,24 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) { for (unsigned i = 0, e = MC->DefPrototypes.size(); i != e; ++i) { Record *DefProto = MC->DefPrototypes[i]; - // Add in the defm name + // Add in the defm name. If the defm prefix is empty, give each + // instantiated def a unique name. Otherwise, if "#NAME#" exists in the + // name, substitute the prefix for #NAME#. Otherwise, use the defm name + // as a prefix. std::string DefName = DefProto->getName(); - std::string::size_type idx = DefName.find("#NAME#"); - if (idx != std::string::npos) { - DefName.replace(idx, 6, DefmPrefix); + if (DefmPrefix.empty()) { + DefName = GetNewAnonymousName(); } else { - // Add the suffix to the defm name to get the new name. - DefName = DefmPrefix + DefName; + std::string::size_type idx = DefName.find("#NAME#"); + if (idx != std::string::npos) { + DefName.replace(idx, 6, DefmPrefix); + } else { + // Add the suffix to the defm name to get the new name. + DefName = DefmPrefix + DefName; + } } - Record *CurRec = new Record(DefName, DefmPrefixLoc); + Record *CurRec = new Record(DefName, DefmPrefixLoc, Records); SubClassReference Ref; Ref.RefLoc = DefmPrefixLoc; @@ -2091,7 +2118,8 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) { /// Object ::= LETCommand Object bool TGParser::ParseObject(MultiClass *MC) { switch (Lex.getCode()) { - default: assert(0 && "This is not an object"); + default: + return TokError("Expected class, def, defm, multiclass or let definition"); case tgtok::Let: return ParseTopLevelLet(MC); case tgtok::Def: return ParseDef(MC); case tgtok::Defm: return ParseDefm(MC); diff --git a/utils/TableGen/TGParser.h b/utils/TableGen/TGParser.h index 0aee931423a6..9cdf68ff9749 100644 --- a/utils/TableGen/TGParser.h +++ b/utils/TableGen/TGParser.h @@ -15,12 +15,14 @@ #define TGPARSER_H #include "TGLexer.h" +#include "llvm/ADT/Twine.h" #include "llvm/Support/SourceMgr.h" #include namespace llvm { class Record; class RecordVal; + class RecordKeeper; struct RecTy; struct Init; struct MultiClass; @@ -46,18 +48,22 @@ class TGParser { /// CurMultiClass - If we are parsing a 'multiclass' definition, this is the /// current value. MultiClass *CurMultiClass; + + // Record tracker + RecordKeeper &Records; public: - TGParser(SourceMgr &SrcMgr) : Lex(SrcMgr), CurMultiClass(0) {} + TGParser(SourceMgr &SrcMgr, RecordKeeper &records) : + Lex(SrcMgr), CurMultiClass(0), Records(records) {} /// ParseFile - Main entrypoint for parsing a tblgen file. These parser /// routines return true on error, or false on success. bool ParseFile(); - bool Error(SMLoc L, const std::string &Msg) const { + bool Error(SMLoc L, const Twine &Msg) const { Lex.PrintError(L, Msg); return true; } - bool TokError(const std::string &Msg) const { + bool TokError(const Twine &Msg) const { return Error(Lex.getLoc(), Msg); } private: // Semantic analysis methods. diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp index 5e3e2829b87f..3b7dc0193b28 100644 --- a/utils/TableGen/TableGen.cpp +++ b/utils/TableGen/TableGen.cpp @@ -21,6 +21,7 @@ #include "ClangASTNodesEmitter.h" #include "ClangAttrEmitter.h" #include "ClangDiagnosticsEmitter.h" +#include "ClangSACheckersEmitter.h" #include "CodeEmitterGen.h" #include "DAGISelEmitter.h" #include "DisassemblerEmitter.h" @@ -37,11 +38,13 @@ #include "ARMDecoderEmitter.h" #include "SubtargetEmitter.h" #include "TGParser.h" +#include "llvm/ADT/OwningPtr.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/System/Signals.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/system_error.h" #include #include using namespace llvm; @@ -59,10 +62,12 @@ enum ActionType { GenClangAttrList, GenClangAttrPCHRead, GenClangAttrPCHWrite, + GenClangAttrSpellingList, GenClangDiagsDefs, GenClangDiagGroups, GenClangDeclNodes, GenClangStmtNodes, + GenClangSACheckers, GenDAGISel, GenFastISel, GenOptParserDefs, GenOptParserImpl, @@ -73,6 +78,7 @@ enum ActionType { GenEDInfo, GenArmNeon, GenArmNeonSema, + GenArmNeonTest, PrintEnums }; @@ -127,14 +133,18 @@ namespace { "Generate clang PCH attribute reader"), clEnumValN(GenClangAttrPCHWrite, "gen-clang-attr-pch-write", "Generate clang PCH attribute writer"), + clEnumValN(GenClangAttrSpellingList, "gen-clang-attr-spelling-list", + "Generate a clang attribute spelling list"), clEnumValN(GenClangDiagsDefs, "gen-clang-diags-defs", "Generate Clang diagnostics definitions"), clEnumValN(GenClangDiagGroups, "gen-clang-diag-groups", "Generate Clang diagnostic groups"), clEnumValN(GenClangDeclNodes, "gen-clang-decl-nodes", - "Generate Clang AST statement nodes"), + "Generate Clang AST declaration nodes"), clEnumValN(GenClangStmtNodes, "gen-clang-stmt-nodes", "Generate Clang AST statement nodes"), + clEnumValN(GenClangSACheckers, "gen-clang-sa-checkers", + "Generate Clang Static Analyzer checkers"), clEnumValN(GenLLVMCConf, "gen-llvmc", "Generate LLVMC configuration library"), clEnumValN(GenEDInfo, "gen-enhanced-disassembly-info", @@ -143,6 +153,8 @@ namespace { "Generate arm_neon.h for clang"), clEnumValN(GenArmNeonSema, "gen-arm-neon-sema", "Generate ARM NEON sema support for clang"), + clEnumValN(GenArmNeonTest, "gen-arm-neon-test", + "Generate ARM NEON tests for clang"), clEnumValN(PrintEnums, "print-enums", "Print enum values for a class"), clEnumValEnd)); @@ -169,12 +181,9 @@ namespace { } -// FIXME: Eliminate globals from tblgen. -RecordKeeper llvm::Records; - static SourceMgr SrcMgr; -void llvm::PrintError(SMLoc ErrorLoc, const std::string &Msg) { +void llvm::PrintError(SMLoc ErrorLoc, const Twine &Msg) { SrcMgr.PrintMessage(ErrorLoc, Msg, "error"); } @@ -184,14 +193,15 @@ void llvm::PrintError(SMLoc ErrorLoc, const std::string &Msg) { /// file. static bool ParseFile(const std::string &Filename, const std::vector &IncludeDirs, - SourceMgr &SrcMgr) { - std::string ErrorStr; - MemoryBuffer *F = MemoryBuffer::getFileOrSTDIN(Filename.c_str(), &ErrorStr); - if (F == 0) { + SourceMgr &SrcMgr, + RecordKeeper &Records) { + OwningPtr File; + if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename.c_str(), File)) { errs() << "Could not open input file '" << Filename << "': " - << ErrorStr <<"\n"; + << ec.message() <<"\n"; return true; } + MemoryBuffer *F = File.take(); // Tell SrcMgr about this buffer, which is what TGParser will pick up. SrcMgr.AddNewSourceBuffer(F, SMLoc()); @@ -200,19 +210,21 @@ static bool ParseFile(const std::string &Filename, // it later. SrcMgr.setIncludeDirs(IncludeDirs); - TGParser Parser(SrcMgr); + TGParser Parser(SrcMgr, Records); return Parser.ParseFile(); } int main(int argc, char **argv) { + RecordKeeper Records; + sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); cl::ParseCommandLineOptions(argc, argv); // Parse the input file. - if (ParseFile(InputFilename, IncludeDirs, SrcMgr)) + if (ParseFile(InputFilename, IncludeDirs, SrcMgr, Records)) return 1; std::string Error; @@ -274,6 +286,9 @@ int main(int argc, char **argv) { case GenClangAttrPCHWrite: ClangAttrPCHWriteEmitter(Records).run(Out.os()); break; + case GenClangAttrSpellingList: + ClangAttrSpellingListEmitter(Records).run(Out.os()); + break; case GenClangDiagsDefs: ClangDiagsDefsEmitter(Records, ClangComponent).run(Out.os()); break; @@ -287,6 +302,9 @@ int main(int argc, char **argv) { case GenClangStmtNodes: ClangASTNodesEmitter(Records, "Stmt", "").run(Out.os()); break; + case GenClangSACheckers: + ClangSACheckersEmitter(Records).run(Out.os()); + break; case GenDisassembler: DisassemblerEmitter(Records).run(Out.os()); break; @@ -323,6 +341,9 @@ int main(int argc, char **argv) { case GenArmNeonSema: NeonEmitter(Records).runHeader(Out.os()); break; + case GenArmNeonTest: + NeonEmitter(Records).runTests(Out.os()); + break; case PrintEnums: { std::vector Recs = Records.getAllDerivedDefinitions(Class); diff --git a/utils/TableGen/X86DisassemblerTables.cpp b/utils/TableGen/X86DisassemblerTables.cpp index 2176224523a3..94797f55f713 100644 --- a/utils/TableGen/X86DisassemblerTables.cpp +++ b/utils/TableGen/X86DisassemblerTables.cpp @@ -161,7 +161,7 @@ void DisassemblerTables::emitOneID(raw_ostream &o, /// @param i - The indentation level for that output stream. static void emitEmptyTable(raw_ostream &o, uint32_t &i) { - o.indent(i * 2) << "static InstrUID modRMEmptyTable[1] = { 0 };" << "\n"; + o.indent(i * 2) << "static const InstrUID modRMEmptyTable[1] = { 0 };\n"; o << "\n"; } @@ -275,7 +275,7 @@ void DisassemblerTables::emitModRMDecision(raw_ostream &o1, return; } - o1.indent(i1) << "static InstrUID modRMTable" << thisTableNumber; + o1.indent(i1) << "static const InstrUID modRMTable" << thisTableNumber; switch (dt) { default: @@ -365,7 +365,7 @@ void DisassemblerTables::emitContextDecision( uint32_t &i2, ContextDecision &decision, const char* name) const { - o2.indent(i2) << "struct ContextDecision " << name << " = {" << "\n"; + o2.indent(i2) << "static const struct ContextDecision " << name << " = {\n"; i2++; o2.indent(i2) << "{ /* opcodeDecisions */" << "\n"; i2++; @@ -392,10 +392,8 @@ void DisassemblerTables::emitContextDecision( void DisassemblerTables::emitInstructionInfo(raw_ostream &o, uint32_t &i) const { - o.indent(i * 2) << "struct InstructionSpecifier "; - o << INSTRUCTIONS_STR << "["; - o << InstructionSpecifiers.size(); - o << "] = {" << "\n"; + o.indent(i * 2) << "static const struct InstructionSpecifier "; + o << INSTRUCTIONS_STR "[" << InstructionSpecifiers.size() << "] = {\n"; i++; @@ -456,8 +454,8 @@ void DisassemblerTables::emitInstructionInfo(raw_ostream &o, uint32_t &i) void DisassemblerTables::emitContextTable(raw_ostream &o, uint32_t &i) const { uint16_t index; - o.indent(i * 2) << "InstructionContext "; - o << CONTEXTS_STR << "[256] = {" << "\n"; + o.indent(i * 2) << "static const InstructionContext " CONTEXTS_STR + "[256] = {\n"; i++; for (index = 0; index < 256; ++index) { diff --git a/utils/TableGen/X86ModRMFilters.h b/utils/TableGen/X86ModRMFilters.h index 45cb07a3d393..199040bad840 100644 --- a/utils/TableGen/X86ModRMFilters.h +++ b/utils/TableGen/X86ModRMFilters.h @@ -18,7 +18,7 @@ #ifndef X86MODRMFILTERS_H #define X86MODRMFILTERS_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { diff --git a/utils/TableGen/X86RecognizableInstr.cpp b/utils/TableGen/X86RecognizableInstr.cpp index 4dba85b16681..ccd3efd980a2 100644 --- a/utils/TableGen/X86RecognizableInstr.cpp +++ b/utils/TableGen/X86RecognizableInstr.cpp @@ -51,10 +51,11 @@ namespace X86Local { MRM0m = 24, MRM1m = 25, MRM2m = 26, MRM3m = 27, MRM4m = 28, MRM5m = 29, MRM6m = 30, MRM7m = 31, MRMInitReg = 32, - #define MAP(from, to) MRM_##from = to, MRM_MAPPING #undef MAP + RawFrmImm8 = 43, + RawFrmImm16 = 44, lastMRM }; @@ -113,7 +114,6 @@ namespace X86Local { EXTENSION_TABLE(72) \ EXTENSION_TABLE(73) \ EXTENSION_TABLE(ae) \ - EXTENSION_TABLE(b9) \ EXTENSION_TABLE(ba) \ EXTENSION_TABLE(c7) @@ -219,7 +219,7 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables, Name = Rec->getName(); AsmString = Rec->getValueAsString("AsmString"); - Operands = &insn.OperandList; + Operands = &insn.Operands.OperandList; IsSSE = HasOpSizePrefix && (Name.find("16") == Name.npos); HasFROperands = false; @@ -311,7 +311,7 @@ RecognizableInstr::filter_ret RecognizableInstr::filter() const { return FILTER_STRONG; // Special cases. - + if (Name.find("PCMPISTRI") != Name.npos && Name != "PCMPISTRI") return FILTER_WEAK; if (Name.find("PCMPESTRI") != Name.npos && Name != "PCMPESTRI") @@ -424,7 +424,7 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) { Spec->insnContext = insnContext(); - const std::vector &OperandList = *Operands; + const std::vector &OperandList = *Operands; unsigned operandIndex; unsigned numOperands = OperandList.size(); @@ -440,7 +440,7 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) { for (operandIndex = 0; operandIndex < numOperands; ++operandIndex) { if (OperandList[operandIndex].Constraints.size()) { - const CodeGenInstruction::ConstraintInfo &Constraint = + const CGIOperandList::ConstraintInfo &Constraint = OperandList[operandIndex].Constraints[0]; if (Constraint.isTied()) { operandMapping[operandIndex] = Constraint.getTiedOperand(); @@ -587,6 +587,20 @@ void RecognizableInstr::emitInstructionSpecifier(DisassemblerTables &tables) { HANDLE_OPERAND(memory) HANDLE_OPTIONAL(relocation) break; + case X86Local::RawFrmImm8: + // operand 1 is a 16-bit immediate + // operand 2 is an 8-bit immediate + assert(numPhysicalOperands == 2 && + "Unexpected number of operands for X86Local::RawFrmImm8"); + HANDLE_OPERAND(immediate) + HANDLE_OPERAND(immediate) + break; + case X86Local::RawFrmImm16: + // operand 1 is a 16-bit immediate + // operand 2 is a 16-bit immediate + HANDLE_OPERAND(immediate) + HANDLE_OPERAND(immediate) + break; case X86Local::MRMInitReg: // Ignored. break; @@ -829,10 +843,13 @@ OperandType RecognizableInstr::typeFromString(const std::string &s, TYPE("GR8", TYPE_R8) TYPE("VR128", TYPE_XMM128) TYPE("f128mem", TYPE_M128) + TYPE("f256mem", TYPE_M256) TYPE("FR64", TYPE_XMM64) TYPE("f64mem", TYPE_M64FP) + TYPE("sdmem", TYPE_M64FP) TYPE("FR32", TYPE_XMM32) TYPE("f32mem", TYPE_M32FP) + TYPE("ssmem", TYPE_M32FP) TYPE("RST", TYPE_ST) TYPE("i128mem", TYPE_M128) TYPE("i64i32imm_pcrel", TYPE_REL64) @@ -840,6 +857,7 @@ OperandType RecognizableInstr::typeFromString(const std::string &s, TYPE("i32imm_pcrel", TYPE_REL32) TYPE("SSECC", TYPE_IMM3) TYPE("brtarget", TYPE_RELv) + TYPE("uncondbrtarget", TYPE_RELv) TYPE("brtarget8", TYPE_REL8) TYPE("f80mem", TYPE_M80FP) TYPE("lea32mem", TYPE_LEA) @@ -924,7 +942,10 @@ OperandEncoding RecognizableInstr::memoryEncodingFromString ENCODING("i32mem", ENCODING_RM) ENCODING("i64mem", ENCODING_RM) ENCODING("i8mem", ENCODING_RM) + ENCODING("ssmem", ENCODING_RM) + ENCODING("sdmem", ENCODING_RM) ENCODING("f128mem", ENCODING_RM) + ENCODING("f256mem", ENCODING_RM) ENCODING("f64mem", ENCODING_RM) ENCODING("f32mem", ENCODING_RM) ENCODING("i128mem", ENCODING_RM) diff --git a/utils/TableGen/X86RecognizableInstr.h b/utils/TableGen/X86RecognizableInstr.h index db4d96dda032..c043b909b42f 100644 --- a/utils/TableGen/X86RecognizableInstr.h +++ b/utils/TableGen/X86RecognizableInstr.h @@ -22,7 +22,7 @@ #include "CodeGenTarget.h" #include "Record.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/ADT/SmallVector.h" namespace llvm { @@ -76,7 +76,8 @@ private: /// The operands of the instruction, as listed in the CodeGenInstruction. /// They are not one-to-one with operands listed in the MCInst; for example, /// memory operands expand to 5 operands in the MCInst - const std::vector* Operands; + const std::vector* Operands; + /// The description of the instruction that is emitted into the instruction /// info table InstructionSpecifier* Spec; diff --git a/utils/Target/ARM/analyze-match-table.py b/utils/Target/ARM/analyze-match-table.py new file mode 100644 index 000000000000..aa952d40085a --- /dev/null +++ b/utils/Target/ARM/analyze-match-table.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python + +def analyze_match_table(path): + # Extract the instruction table. + data = open(path).read() + start = data.index("static const MatchEntry MatchTable") + end = data.index("\n};\n", start) + lines = data[start:end].split("\n")[1:] + + # Parse the instructions. + insns = [] + for ln in lines: + ln = ln.split("{", 1)[1] + ln = ln.rsplit("}", 1)[0] + a,bc = ln.split("{", 1) + b,c = bc.split("}", 1) + code, string, converter, _ = [s.strip() + for s in a.split(",")] + items = [s.strip() for s in b.split(",")] + _,features = [s.strip() for s in c.split(",")] + assert string[0] == string[-1] == '"' + string = string[1:-1] + insns.append((code,string,converter,items,features)) + + # For every mnemonic, compute whether or not it can have a carry setting + # operand and whether or not it can have a predication code. + mnemonic_flags = {} + for insn in insns: + mnemonic = insn[1] + items = insn[3] + flags = mnemonic_flags[mnemonic] = mnemonic_flags.get(mnemonic, set()) + flags.update(items) + + mnemonics = set(mnemonic_flags) + ccout_mnemonics = set(m for m in mnemonics + if 'MCK_CCOut' in mnemonic_flags[m]) + condcode_mnemonics = set(m for m in mnemonics + if 'MCK_CondCode' in mnemonic_flags[m]) + noncondcode_mnemonics = mnemonics - condcode_mnemonics + print ' || '.join('Mnemonic == "%s"' % m + for m in ccout_mnemonics) + print ' || '.join('Mnemonic == "%s"' % m + for m in noncondcode_mnemonics) + +def main(): + import sys + if len(sys.argv) == 1: + import os + from lit.Util import capture + llvm_obj_root = capture(["llvm-config", "--obj-root"]) + file = os.path.join(llvm_obj_root, + "lib/Target/ARM/ARMGenAsmMatcher.inc") + elif len(sys.argv) == 2: + file = sys.argv[1] + else: + raise NotImplementedError + + analyze_match_table(file) + +if __name__ == '__main__': + main() diff --git a/utils/buildit/build_llvm b/utils/buildit/build_llvm index 39ec1ccda9c0..5e8369cdd326 100755 --- a/utils/buildit/build_llvm +++ b/utils/buildit/build_llvm @@ -105,7 +105,7 @@ if [ "$ARM_HOSTED_BUILD" = yes ]; then T=`xcrun -sdk $SDKROOT -find ${prog}` fi echo '#!/bin/sh' > $P || exit 1 - echo 'exec '$T' -arch armv6 -isysroot '${SDKROOT}' "$@"' >> $P || exit 1 + echo 'exec '$T' -arch armv7 -isysroot '${SDKROOT}' "$@"' >> $P || exit 1 chmod a+x $P || exit 1 done @@ -174,11 +174,6 @@ if [ "x$MAJ_VER" != "x4" -o "x$MIN_VER" != "x0" ]; then # Figure out how many make processes to run. SYSCTL=`sysctl -n hw.activecpu` - # hw.activecpu only available in 10.2.6 and later - if [ -z "$SYSCTL" ]; then - SYSCTL=`sysctl -n hw.ncpu` - fi - # sysctl -n hw.* does not work when invoked via B&I chroot /BuildRoot. # Builders can default to 2, since even if they are single processor, # nothing else is running on the machine. @@ -269,8 +264,11 @@ else -exec lipo -extract ppc7400 -extract i386 -extract x86_64 {} -output {} \; fi -# The Hello dylib is an example of how to build a pass. No need to install it. -rm $DEST_DIR$DEST_ROOT/lib/LLVMHello.dylib +# The Hello dylib is an example of how to build a pass. +# The BugpointPasses module is only used to test bugpoint. +# These unversioned dylibs cause verification failures, so do not install them. +rm $DEST_DIR$DEST_ROOT/lib/libLLVMHello.dylib +rm $DEST_DIR$DEST_ROOT/lib/libBugpointPasses.dylib # Compress manpages MDIR=$DEST_DIR$DEST_ROOT/share/man/man1 diff --git a/utils/emacs/llvm-mode.el b/utils/emacs/llvm-mode.el index b1af853883ad..3780624b5a43 100644 --- a/utils/emacs/llvm-mode.el +++ b/utils/emacs/llvm-mode.el @@ -19,7 +19,7 @@ ;; Unnamed variable slots '("%[-]?[0-9]+" . font-lock-variable-name-face) ;; Types - '("\\bvoid\\b\\|\\bi[0-9]+\\b\\|\\float\\b\\|\\bdouble\\b\\|\\btype\\b\\|\\blabel\\b\\|\\bopaque\\b" . font-lock-type-face) + `(,(regexp-opt '("void" "i[0-9]+" "float" "double" "type" "label" "opaque") 'words) . font-lock-type-face) ;; Integer literals '("\\b[-]?[0-9]+\\b" . font-lock-preprocessor-face) ;; Floating point constants @@ -27,15 +27,20 @@ ;; Hex constants '("\\b0x[0-9A-Fa-f]+\\b" . font-lock-preprocessor-face) ;; Keywords - '("\\bbegin\\b\\|\\bend\\b\\|\\btrue\\b\\|\\bfalse\\b\\|\\bzeroinitializer\\b\\|\\bdeclare\\b\\|\\bdefine\\b\\|\\bglobal\\b\\|\\bconstant\\b\\|\\bconst\\b\\|\\binternal\\b\\|\\blinkonce\\b\\|\\blinkonce_odr\\b\\|\\bweak\\b\\|\\bweak_odr\\b\\|\\bappending\\b\\|\\buninitialized\\b\\|\\bimplementation\\b\\|\\b\\.\\.\\.\\b\\|\\bnull\\b\\|\\bundef\\b\\|\\bto\\b\\|\\bexcept\\b\\|\\bnot\\b\\|\\btarget\\b\\|\\bendian\\b\\|\\blittle\\b\\|\\bbig\\b\\|\\bpointersize\\b\\|\\bdeplibs\\b\\|\\bvolatile\\b\\|\\bfastcc\\b\\|\\bcoldcc\\b\\|\\bcc\\b" . font-lock-keyword-face) + `(,(regexp-opt '("begin" "end" "true" "false" "zeroinitializer" "declare" + "define" "global" "constant" "const" "internal" "linkonce" "linkonce_odr" + "weak" "weak_odr" "appending" "uninitialized" "implementation" "..." + "null" "undef" "to" "except" "not" "target" "endian" "little" "big" + "pointersize" "deplibs" "volatile" "fastcc" "coldcc" "cc") 'words) . font-lock-keyword-face) ;; Arithmetic and Logical Operators - '("\\badd\\b\\|\\bsub\\b\\|\\bmul\\b\\|\\bdiv\\b\\|\\brem\\b\\|\\band\\b\\|\\bor\\b\\|\\bxor\\b\\|\\bset\\(ne\\b\\|\\beq\\b\\|\\blt\\b\\|\\bgt\\b\\|\\ble\\b\\|\\bge\\b\\)" . font-lock-keyword-face) + `(,(regexp-opt '("add" "sub" "mul" "div" "rem" "and" "or" "xor" + "setne" "seteq" "setlt" "setgt" "setle" "setge") 'words) . font-lock-keyword-face) ;; Special instructions - '("\\bphi\\b\\|\\btail\\b\\|\\bcall\\b\\|\\bcast\\b\\|\\bselect\\b\\|\\bto\\b\\|\\bshl\\b\\|\\bshr\\b\\|\\bvaarg\\b\\|\\bvanext\\b" . font-lock-keyword-face) + `(,(regexp-opt '("phi" "tail" "call" "cast" "select" "to" "shl" "shr" "vaarg" "vanext") 'words) . font-lock-keyword-face) ;; Control instructions - '("\\bret\\b\\|\\bbr\\b\\|\\bswitch\\b\\|\\binvoke\\b\\|\\bunwind\\b\\|\\bunreachable\\b" . font-lock-keyword-face) + `(,(regexp-opt '("ret" "br" "switch" "invoke" "unwind" "unreachable") 'words) . font-lock-keyword-face) ;; Memory operators - '("\\bmalloc\\b\\|\\balloca\\b\\|\\bfree\\b\\|\\bload\\b\\|\\bstore\\b\\|\\bgetelementptr\\b" . font-lock-keyword-face) + `(,(regexp-opt '("malloc" "alloca" "free" "load" "store" "getelementptr") 'words) . font-lock-keyword-face) ) "Syntax highlighting for LLVM" ) diff --git a/utils/emacs/tablegen-mode.el b/utils/emacs/tablegen-mode.el index 833c16c599d4..3853ce66a285 100644 --- a/utils/emacs/tablegen-mode.el +++ b/utils/emacs/tablegen-mode.el @@ -12,13 +12,11 @@ (make-face 'td-decorators-face) (defvar tablegen-font-lock-keywords - (let ((kw (mapconcat 'identity - '("class" "defm" "def" "field" "include" "in" + (let ((kw (regexp-opt '("class" "defm" "def" "field" "include" "in" "let" "multiclass") - "\\|")) - (type-kw (mapconcat 'identity - '("bit" "bits" "code" "dag" "int" "list" "string") - "\\|")) + 'words)) + (type-kw (regexp-opt '("bit" "bits" "code" "dag" "int" "list" "string") + 'words)) ) (list ;; Comments @@ -36,10 +34,10 @@ '("^[ \t]*\\(@.+\\)" 1 'td-decorators-face) ;; Keywords - (cons (concat "\\<\\(" kw "\\)\\>[ \n\t(]") 1) + (cons (concat kw "[ \n\t(]") 1) ;; Type keywords - (cons (concat "\\<\\(" type-kw "\\)[ \n\t(]") 1) + (cons (concat type-kw "[ \n\t(]") 1) )) "Additional expressions to highlight in TableGen mode.") (put 'tablegen-mode 'font-lock-defaults '(tablegen-font-lock-keywords)) diff --git a/utils/findmisopt b/utils/findmisopt index b7ffbd9947d5..f2a872c6dc3e 100755 --- a/utils/findmisopt +++ b/utils/findmisopt @@ -7,7 +7,7 @@ # it from finding a problem unless the set of failing optimizations are # known and given to it on the command line. # -# Given a bytecode file that produces correct output (or return code), +# Given a bitcode file that produces correct output (or return code), # this script will run through all the optimizations passes that gccas # uses (in the same order) and will narrow down which optimizations # cause the program either generate different output or return a @@ -21,7 +21,7 @@ # # Where: # bcfile -# is the bytecode file input (the unoptimized working case) +# is the bitcode file input (the unoptimized working case) # outdir # is a directory into which intermediate results are placed # progargs diff --git a/utils/findoptdiff b/utils/findoptdiff index 4f8d08dbffe1..7a2eab05d71a 100755 --- a/utils/findoptdiff +++ b/utils/findoptdiff @@ -14,7 +14,7 @@ # second build contains some experimental optimization features that # are suspected of producing a misoptimization. # -# The script takes two bytecode files, one from each build. They are +# The script takes two bitcode files, one from each build. They are # presumed to be a compilation of the same program or program fragment # with the only difference being the builds. # @@ -39,9 +39,9 @@ # llvm2 # is the path to the second llvm build dir # bc1 -# is the bytecode file for the first llvm environment +# is the bitcode file for the first llvm environment # bc2 -# is the bytecode file for the second llvm environment +# is the bitcode file for the second llvm environment # filter1 # is an optional filter for filtering the llvm1 generated assembly # filter2 diff --git a/utils/fpcmp/Makefile b/utils/fpcmp/Makefile index fd2f7477bb4e..81db3b9c3f6e 100644 --- a/utils/fpcmp/Makefile +++ b/utils/fpcmp/Makefile @@ -1,15 +1,15 @@ ##===- utils/fpcmp/Makefile --------------------------------*- Makefile -*-===## -# +# # The LLVM Compiler Infrastructure # # This file is distributed under the University of Illinois Open Source # License. See LICENSE.TXT for details. -# +# ##===----------------------------------------------------------------------===## LEVEL = ../.. TOOLNAME = fpcmp -USEDLIBS = LLVMSupport.a LLVMSystem.a +USEDLIBS = LLVMSupport.a NO_INSTALL = 1 include $(LEVEL)/Makefile.common diff --git a/utils/kate/README b/utils/kate/README new file mode 100644 index 000000000000..efe53b7e237e --- /dev/null +++ b/utils/kate/README @@ -0,0 +1,12 @@ +-*- llvm/utils/kate/README -*- + +These are syntax highlighting files for the Kate editor. Included are: + +* llvm.xml + + Syntax Highlighting Mode for the KDE Kate editor. To install just copy + this file to ~/.kde/share/apps/katepart/syntax (or better yet, symlink it). + +Note: If you notice missing or incorrect syntax highlighting, please contact +; if you wish to provide a patch to improve the +functionality, it will be most appreciated. Thank you. diff --git a/utils/kate/llvm.xml b/utils/kate/llvm.xml new file mode 100644 index 000000000000..074fa16cb884 --- /dev/null +++ b/utils/kate/llvm.xml @@ -0,0 +1,255 @@ + + + + + + begin + end + true + false + declare + define + global + constant + gc + module + asm + target + datalayout + null + undef + blockaddress + sideeffect + alignstack + to + unwind + nuw + nsw + inbounds + tail + triple + type + align + alias + + + private + linker_private + linker_private_weak + linker_private_weak_def_auto + internal + available_externally + linkonce + weak + common + appending + extern_weak + linkonce_odr + weak_odr + dllimport + dllexport + + + ccc + fastcc + coldcc + cc + + + default + hidden + protected + + + zeroext + signext + inreg + byval + sret + noalias + nocapture + nest + + + alignstack + alwaysinline + inlinehint + naked + noimplicitfloat + noinline + noredzone + noreturn + nounwind + optsize + readnone + readonly + ssp + sspreq + + + float + double + fp128 + x86_fp80 + ppc_fp128 + x86mmx + void + label + metadata + opaque + + + llvm.used + llvm.compiler.used + llvm.global_ctors + llvm.global_dtors + + + ret + br + switch + indirectbr + invoke + unwind + unreachable + add + fadd + sub + fsub + mul + fmul + udiv + sdiv + fdiv + urem + srem + frem + shl + lshr + ashr + and + or + xor + extractelement + insertelement + shufflevector + extractvalue + insertvalue + alloca + load + store + getelementptr + trunc + zext + sext + fptrunc + fpext + fptoui + fptosi + uitofp + sitofp + ptrtoint + inttoptr + bitcast + icmp + fcmp + phi + select + call + va_arg + + + eq + ne + ugt + uge + ult + ule + sgt + sge + slt + sle + oeq + ogt + oge + olt + ole + one + ord + ueq + une + uno + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/utils/lit/TODO b/utils/lit/TODO index 4d00d2c1cfcd..6d7f7ea529ae 100644 --- a/utils/lit/TODO +++ b/utils/lit/TODO @@ -2,18 +2,8 @@ - Add --show-unsupported, don't show by default? - - Finish documentation. - - Optionally use multiprocessing. - - Support llvmc and ocaml tests. - - Support valgrind in all configs, and LLVM style valgrind. - - Provide test suite config for running unit tests. - - Support a timeout / ulimit. - - - Support "disabling" tests? The advantage of making this distinct from XFAIL - is it makes it more obvious that it is a temporary measure (and lit can put - in a separate category). diff --git a/utils/lit/lit/LitConfig.py b/utils/lit/lit/LitConfig.py index ac4859137e54..7ca1b9c4c634 100644 --- a/utils/lit/lit/LitConfig.py +++ b/utils/lit/lit/LitConfig.py @@ -8,6 +8,9 @@ class LitConfig: easily. """ + # Provide access to Test module. + import Test + # Provide access to built-in formats. import LitFormats as formats @@ -82,6 +85,22 @@ class LitConfig: return self.bashPath + def getToolsPath(self, dir, paths, tools): + import os, Util + if dir is not None and os.path.isabs(dir) and os.path.isdir(dir): + if not Util.checkToolsPath(dir, tools): + return None + else: + dir = Util.whichTools(tools, paths) + + # bash + self.bashPath = Util.which('bash', dir) + if self.bashPath is None: + self.warning("Unable to find 'bash.exe'.") + self.bashPath = '' + + return dir + def _write_message(self, kind, message): import inspect, os, sys diff --git a/utils/lit/lit/LitFormats.py b/utils/lit/lit/LitFormats.py index e86f103fe6b2..931d107109b3 100644 --- a/utils/lit/lit/LitFormats.py +++ b/utils/lit/lit/LitFormats.py @@ -1,2 +1,3 @@ +from TestFormats import FileBasedTest from TestFormats import GoogleTest, ShTest, TclTest from TestFormats import SyntaxCheckTest, OneCommandPerFileTest diff --git a/utils/lit/lit/TestFormats.py b/utils/lit/lit/TestFormats.py index 7ffbd2bf7663..6dda2fdb608d 100644 --- a/utils/lit/lit/TestFormats.py +++ b/utils/lit/lit/TestFormats.py @@ -1,15 +1,15 @@ import os -import platform +import sys import Test import TestRunner import Util -kIsWindows = platform.system() == 'Windows' +kIsWindows = sys.platform in ['win32', 'cygwin'] class GoogleTest(object): def __init__(self, test_sub_dir, test_suffix): - self.test_sub_dir = str(test_sub_dir) + self.test_sub_dir = os.path.normcase(str(test_sub_dir)).split(';') self.test_suffix = str(test_suffix) # On Windows, assume tests will also end in '.exe'. @@ -28,7 +28,10 @@ class GoogleTest(object): try: lines = Util.capture([path, '--gtest_list_tests'], - env=localConfig.environment).split('\n') + env=localConfig.environment) + if kIsWindows: + lines = lines.replace('\r', '') + lines = lines.split('\n') except: litConfig.error("unable to discover google-tests in %r" % path) raise StopIteration @@ -44,7 +47,7 @@ class GoogleTest(object): index += 1 while len(nested_tests) > index: nested_tests.pop() - + ln = ln[index*2:] if ln.endswith('.'): nested_tests.append(ln) @@ -56,10 +59,14 @@ class GoogleTest(object): source_path = testSuite.getSourcePath(path_in_suite) for filename in os.listdir(source_path): # Check for the one subdirectory (build directory) tests will be in. - if filename != self.test_sub_dir: - continue + if not '.' in self.test_sub_dir: + if not os.path.normcase(filename) in self.test_sub_dir: + continue filepath = os.path.join(source_path, filename) + if not os.path.isdir(filepath): + continue + for subfilename in os.listdir(filepath): if subfilename.endswith(self.test_suffix): execpath = os.path.join(filepath, subfilename) @@ -84,7 +91,7 @@ class GoogleTest(object): out, err, exitCode = TestRunner.executeCommand( cmd, env=test.config.environment) - + if not exitCode: return Test.PASS,'' diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py index 0eb51a829408..dba78143bee2 100644 --- a/utils/lit/lit/TestRunner.py +++ b/utils/lit/lit/TestRunner.py @@ -8,6 +8,8 @@ import Util import platform import tempfile +import re + class InternalShellError(Exception): def __init__(self, command, message): self.command = command @@ -178,6 +180,13 @@ def executeShCmd(cmd, cfg, cwd, results): else: input = subprocess.PIPE + # Explicitly close any redirected files. We need to do this now because we + # need to release any handles we may have on the temporary files (important + # on Win32, for example). Since we have already spawned the subprocess, our + # handles have already been transferred so we do not need them anymore. + for f in opened_files: + f.close() + # FIXME: There is probably still deadlock potential here. Yawn. procData = [None] * len(procs) procData[-1] = procs[-1].communicate() @@ -215,10 +224,6 @@ def executeShCmd(cmd, cfg, cwd, results): else: exitCode = res - # Explicitly close any redirected files. - for f in opened_files: - f.close() - # Remove any named temporary files we created. for f in named_temp_files: try: @@ -441,11 +446,15 @@ def parseIntegratedTestScript(test, normalize_slashes=False): if ln[ln.index('END.'):].strip() == 'END.': break - # Apply substitutions to the script. + # Apply substitutions to the script. Allow full regular + # expression syntax. Replace each matching occurrence of regular + # expression pattern a with substitution b in line ln. def processLine(ln): # Apply substitutions for a,b in substitutions: - ln = ln.replace(a,b) + if kIsWindows: + b = b.replace("\\","\\\\") + ln = re.sub(a, b, ln) # Strip the trailing newline and any extra whitespace. return ln.strip() diff --git a/utils/lit/lit/TestingConfig.py b/utils/lit/lit/TestingConfig.py index 5c1b27394857..0d9bc00a8357 100644 --- a/utils/lit/lit/TestingConfig.py +++ b/utils/lit/lit/TestingConfig.py @@ -10,12 +10,14 @@ class TestingConfig: if config is None: # Set the environment based on the command line arguments. environment = { + 'LIBRARY_PATH' : os.environ.get('LIBRARY_PATH',''), 'LD_LIBRARY_PATH' : os.environ.get('LD_LIBRARY_PATH',''), 'PATH' : os.pathsep.join(litConfig.path + [os.environ.get('PATH','')]), 'PATHEXT' : os.environ.get('PATHEXT',''), 'SYSTEMROOT' : os.environ.get('SYSTEMROOT',''), 'LLVM_DISABLE_CRT_DEBUG' : '1', + 'PRINTF_EXPONENT_DIGITS' : '2', } config = TestingConfig(parent, diff --git a/utils/lit/lit/Util.py b/utils/lit/lit/Util.py index 414b714c82c3..5635f50baef3 100644 --- a/utils/lit/lit/Util.py +++ b/utils/lit/lit/Util.py @@ -64,7 +64,11 @@ def which(command, paths = None): paths = os.defpath # Get suffixes to search. - pathext = os.environ.get('PATHEXT', '').split(os.pathsep) + # On Cygwin, 'PATHEXT' may exist but it should not be used. + if os.pathsep == ';': + pathext = os.environ.get('PATHEXT', '').split(';') + else: + pathext = [''] # Search the paths... for path in paths.split(os.pathsep): @@ -75,6 +79,18 @@ def which(command, paths = None): return None +def checkToolsPath(dir, tools): + for tool in tools: + if not os.path.exists(os.path.join(dir, tool)): + return False; + return True; + +def whichTools(tools, paths): + for path in paths.split(os.pathsep): + if checkToolsPath(path, tools): + return path + return None + def printHistogram(items, title = 'Items'): import itertools, math diff --git a/utils/lit/lit/__init__.py b/utils/lit/lit/__init__.py index 01026023d29b..f3fbb1cd8276 100644 --- a/utils/lit/lit/__init__.py +++ b/utils/lit/lit/__init__.py @@ -1,10 +1,10 @@ """'lit' Testing Tool""" -from lit import main +from main import main __author__ = 'Daniel Dunbar' __email__ = 'daniel@zuster.org' -__versioninfo__ = (0, 1, 0) -__version__ = '.'.join(map(str, __versioninfo__)) +__versioninfo__ = (0, 2, 0) +__version__ = '.'.join(map(str, __versioninfo__)) + 'dev' __all__ = [] diff --git a/utils/lit/lit/lit.py b/utils/lit/lit/lit.py deleted file mode 100755 index 13d263009ddd..000000000000 --- a/utils/lit/lit/lit.py +++ /dev/null @@ -1,648 +0,0 @@ -#!/usr/bin/env python - -""" -lit - LLVM Integrated Tester. - -See lit.pod for more information. -""" - -import math, os, platform, random, re, sys, time, threading, traceback - -import ProgressBar -import TestRunner -import Util - -from TestingConfig import TestingConfig -import LitConfig -import Test - -# Configuration files to look for when discovering test suites. These can be -# overridden with --config-prefix. -# -# FIXME: Rename to 'config.lit', 'site.lit', and 'local.lit' ? -gConfigName = 'lit.cfg' -gSiteConfigName = 'lit.site.cfg' - -kLocalConfigName = 'lit.local.cfg' - -class TestingProgressDisplay: - def __init__(self, opts, numTests, progressBar=None): - self.opts = opts - self.numTests = numTests - self.current = None - self.lock = threading.Lock() - self.progressBar = progressBar - self.completed = 0 - - def update(self, test): - # Avoid locking overhead in quiet mode - if self.opts.quiet and not test.result.isFailure: - self.completed += 1 - return - - # Output lock. - self.lock.acquire() - try: - self.handleUpdate(test) - finally: - self.lock.release() - - def finish(self): - if self.progressBar: - self.progressBar.clear() - elif self.opts.quiet: - pass - elif self.opts.succinct: - sys.stdout.write('\n') - - def handleUpdate(self, test): - self.completed += 1 - if self.progressBar: - self.progressBar.update(float(self.completed)/self.numTests, - test.getFullName()) - - if self.opts.succinct and not test.result.isFailure: - return - - if self.progressBar: - self.progressBar.clear() - - print '%s: %s (%d of %d)' % (test.result.name, test.getFullName(), - self.completed, self.numTests) - - if test.result.isFailure and self.opts.showOutput: - print "%s TEST '%s' FAILED %s" % ('*'*20, test.getFullName(), - '*'*20) - print test.output - print "*" * 20 - - sys.stdout.flush() - -class TestProvider: - def __init__(self, tests, maxTime): - self.maxTime = maxTime - self.iter = iter(tests) - self.lock = threading.Lock() - self.startTime = time.time() - - def get(self): - # Check if we have run out of time. - if self.maxTime is not None: - if time.time() - self.startTime > self.maxTime: - return None - - # Otherwise take the next test. - self.lock.acquire() - try: - item = self.iter.next() - except StopIteration: - item = None - self.lock.release() - return item - -class Tester(threading.Thread): - def __init__(self, litConfig, provider, display): - threading.Thread.__init__(self) - self.litConfig = litConfig - self.provider = provider - self.display = display - - def run(self): - while 1: - item = self.provider.get() - if item is None: - break - self.runTest(item) - - def runTest(self, test): - result = None - startTime = time.time() - try: - result, output = test.config.test_format.execute(test, - self.litConfig) - except KeyboardInterrupt: - # This is a sad hack. Unfortunately subprocess goes - # bonkers with ctrl-c and we start forking merrily. - print '\nCtrl-C detected, goodbye.' - os.kill(0,9) - except: - if self.litConfig.debug: - raise - result = Test.UNRESOLVED - output = 'Exception during script execution:\n' - output += traceback.format_exc() - output += '\n' - elapsed = time.time() - startTime - - test.setResult(result, output, elapsed) - self.display.update(test) - -def dirContainsTestSuite(path): - cfgpath = os.path.join(path, gSiteConfigName) - if os.path.exists(cfgpath): - return cfgpath - cfgpath = os.path.join(path, gConfigName) - if os.path.exists(cfgpath): - return cfgpath - -def getTestSuite(item, litConfig, cache): - """getTestSuite(item, litConfig, cache) -> (suite, relative_path) - - Find the test suite containing @arg item. - - @retval (None, ...) - Indicates no test suite contains @arg item. - @retval (suite, relative_path) - The suite that @arg item is in, and its - relative path inside that suite. - """ - def search1(path): - # Check for a site config or a lit config. - cfgpath = dirContainsTestSuite(path) - - # If we didn't find a config file, keep looking. - if not cfgpath: - parent,base = os.path.split(path) - if parent == path: - return (None, ()) - - ts, relative = search(parent) - return (ts, relative + (base,)) - - # We found a config file, load it. - if litConfig.debug: - litConfig.note('loading suite config %r' % cfgpath) - - cfg = TestingConfig.frompath(cfgpath, None, litConfig, mustExist = True) - source_root = os.path.realpath(cfg.test_source_root or path) - exec_root = os.path.realpath(cfg.test_exec_root or path) - return Test.TestSuite(cfg.name, source_root, exec_root, cfg), () - - def search(path): - # Check for an already instantiated test suite. - res = cache.get(path) - if res is None: - cache[path] = res = search1(path) - return res - - # Canonicalize the path. - item = os.path.realpath(item) - - # Skip files and virtual components. - components = [] - while not os.path.isdir(item): - parent,base = os.path.split(item) - if parent == item: - return (None, ()) - components.append(base) - item = parent - components.reverse() - - ts, relative = search(item) - return ts, tuple(relative + tuple(components)) - -def getLocalConfig(ts, path_in_suite, litConfig, cache): - def search1(path_in_suite): - # Get the parent config. - if not path_in_suite: - parent = ts.config - else: - parent = search(path_in_suite[:-1]) - - # Load the local configuration. - source_path = ts.getSourcePath(path_in_suite) - cfgpath = os.path.join(source_path, kLocalConfigName) - if litConfig.debug: - litConfig.note('loading local config %r' % cfgpath) - return TestingConfig.frompath(cfgpath, parent, litConfig, - mustExist = False, - config = parent.clone(cfgpath)) - - def search(path_in_suite): - key = (ts, path_in_suite) - res = cache.get(key) - if res is None: - cache[key] = res = search1(path_in_suite) - return res - - return search(path_in_suite) - -def getTests(path, litConfig, testSuiteCache, localConfigCache): - # Find the test suite for this input and its relative path. - ts,path_in_suite = getTestSuite(path, litConfig, testSuiteCache) - if ts is None: - litConfig.warning('unable to find test suite for %r' % path) - return (),() - - if litConfig.debug: - litConfig.note('resolved input %r to %r::%r' % (path, ts.name, - path_in_suite)) - - return ts, getTestsInSuite(ts, path_in_suite, litConfig, - testSuiteCache, localConfigCache) - -def getTestsInSuite(ts, path_in_suite, litConfig, - testSuiteCache, localConfigCache): - # Check that the source path exists (errors here are reported by the - # caller). - source_path = ts.getSourcePath(path_in_suite) - if not os.path.exists(source_path): - return - - # Check if the user named a test directly. - if not os.path.isdir(source_path): - lc = getLocalConfig(ts, path_in_suite[:-1], litConfig, localConfigCache) - yield Test.Test(ts, path_in_suite, lc) - return - - # Otherwise we have a directory to search for tests, start by getting the - # local configuration. - lc = getLocalConfig(ts, path_in_suite, litConfig, localConfigCache) - - # Search for tests. - if lc.test_format is not None: - for res in lc.test_format.getTestsInDirectory(ts, path_in_suite, - litConfig, lc): - yield res - - # Search subdirectories. - for filename in os.listdir(source_path): - # FIXME: This doesn't belong here? - if filename in ('Output', '.svn') or filename in lc.excludes: - continue - - # Ignore non-directories. - file_sourcepath = os.path.join(source_path, filename) - if not os.path.isdir(file_sourcepath): - continue - - # Check for nested test suites, first in the execpath in case there is a - # site configuration and then in the source path. - file_execpath = ts.getExecPath(path_in_suite + (filename,)) - if dirContainsTestSuite(file_execpath): - sub_ts, subiter = getTests(file_execpath, litConfig, - testSuiteCache, localConfigCache) - elif dirContainsTestSuite(file_sourcepath): - sub_ts, subiter = getTests(file_sourcepath, litConfig, - testSuiteCache, localConfigCache) - else: - # Otherwise, continue loading from inside this test suite. - subiter = getTestsInSuite(ts, path_in_suite + (filename,), - litConfig, testSuiteCache, - localConfigCache) - sub_ts = None - - N = 0 - for res in subiter: - N += 1 - yield res - if sub_ts and not N: - litConfig.warning('test suite %r contained no tests' % sub_ts.name) - -def runTests(numThreads, litConfig, provider, display): - # If only using one testing thread, don't use threads at all; this lets us - # profile, among other things. - if numThreads == 1: - t = Tester(litConfig, provider, display) - t.run() - return - - # Otherwise spin up the testing threads and wait for them to finish. - testers = [Tester(litConfig, provider, display) - for i in range(numThreads)] - for t in testers: - t.start() - try: - for t in testers: - t.join() - except KeyboardInterrupt: - sys.exit(2) - -def load_test_suite(inputs): - import unittest - - # Create the global config object. - litConfig = LitConfig.LitConfig(progname = 'lit', - path = [], - quiet = False, - useValgrind = False, - valgrindLeakCheck = False, - valgrindArgs = [], - useTclAsSh = False, - noExecute = False, - debug = False, - isWindows = (platform.system()=='Windows'), - params = {}) - - # Load the tests from the inputs. - tests = [] - testSuiteCache = {} - localConfigCache = {} - for input in inputs: - prev = len(tests) - tests.extend(getTests(input, litConfig, - testSuiteCache, localConfigCache)[1]) - if prev == len(tests): - litConfig.warning('input %r contained no tests' % input) - - # If there were any errors during test discovery, exit now. - if litConfig.numErrors: - print >>sys.stderr, '%d errors, exiting.' % litConfig.numErrors - sys.exit(2) - - # Return a unittest test suite which just runs the tests in order. - def get_test_fn(test): - return unittest.FunctionTestCase( - lambda: test.config.test_format.execute( - test, litConfig), - description = test.getFullName()) - - from LitTestCase import LitTestCase - return unittest.TestSuite([LitTestCase(test, litConfig) for test in tests]) - -def main(builtinParameters = {}): # Bump the GIL check interval, its more important to get any one thread to a - # blocking operation (hopefully exec) than to try and unblock other threads. - # - # FIXME: This is a hack. - import sys - sys.setcheckinterval(1000) - - global options - from optparse import OptionParser, OptionGroup - parser = OptionParser("usage: %prog [options] {file-or-path}") - - parser.add_option("-j", "--threads", dest="numThreads", metavar="N", - help="Number of testing threads", - type=int, action="store", default=None) - parser.add_option("", "--config-prefix", dest="configPrefix", - metavar="NAME", help="Prefix for 'lit' config files", - action="store", default=None) - parser.add_option("", "--param", dest="userParameters", - metavar="NAME=VAL", - help="Add 'NAME' = 'VAL' to the user defined parameters", - type=str, action="append", default=[]) - - group = OptionGroup(parser, "Output Format") - # FIXME: I find these names very confusing, although I like the - # functionality. - group.add_option("-q", "--quiet", dest="quiet", - help="Suppress no error output", - action="store_true", default=False) - group.add_option("-s", "--succinct", dest="succinct", - help="Reduce amount of output", - action="store_true", default=False) - group.add_option("-v", "--verbose", dest="showOutput", - help="Show all test output", - action="store_true", default=False) - group.add_option("", "--no-progress-bar", dest="useProgressBar", - help="Do not use curses based progress bar", - action="store_false", default=True) - parser.add_option_group(group) - - group = OptionGroup(parser, "Test Execution") - group.add_option("", "--path", dest="path", - help="Additional paths to add to testing environment", - action="append", type=str, default=[]) - group.add_option("", "--vg", dest="useValgrind", - help="Run tests under valgrind", - action="store_true", default=False) - group.add_option("", "--vg-leak", dest="valgrindLeakCheck", - help="Check for memory leaks under valgrind", - action="store_true", default=False) - group.add_option("", "--vg-arg", dest="valgrindArgs", metavar="ARG", - help="Specify an extra argument for valgrind", - type=str, action="append", default=[]) - group.add_option("", "--time-tests", dest="timeTests", - help="Track elapsed wall time for each test", - action="store_true", default=False) - group.add_option("", "--no-execute", dest="noExecute", - help="Don't execute any tests (assume PASS)", - action="store_true", default=False) - parser.add_option_group(group) - - group = OptionGroup(parser, "Test Selection") - group.add_option("", "--max-tests", dest="maxTests", metavar="N", - help="Maximum number of tests to run", - action="store", type=int, default=None) - group.add_option("", "--max-time", dest="maxTime", metavar="N", - help="Maximum time to spend testing (in seconds)", - action="store", type=float, default=None) - group.add_option("", "--shuffle", dest="shuffle", - help="Run tests in random order", - action="store_true", default=False) - parser.add_option_group(group) - - group = OptionGroup(parser, "Debug and Experimental Options") - group.add_option("", "--debug", dest="debug", - help="Enable debugging (for 'lit' development)", - action="store_true", default=False) - group.add_option("", "--show-suites", dest="showSuites", - help="Show discovered test suites", - action="store_true", default=False) - group.add_option("", "--no-tcl-as-sh", dest="useTclAsSh", - help="Don't run Tcl scripts using 'sh'", - action="store_false", default=True) - group.add_option("", "--repeat", dest="repeatTests", metavar="N", - help="Repeat tests N times (for timing)", - action="store", default=None, type=int) - parser.add_option_group(group) - - (opts, args) = parser.parse_args() - - if not args: - parser.error('No inputs specified') - - if opts.configPrefix is not None: - global gConfigName, gSiteConfigName - gConfigName = '%s.cfg' % opts.configPrefix - gSiteConfigName = '%s.site.cfg' % opts.configPrefix - - if opts.numThreads is None: -# Python <2.5 has a race condition causing lit to always fail with numThreads>1 -# http://bugs.python.org/issue1731717 -# I haven't seen this bug occur with 2.5.2 and later, so only enable multiple -# threads by default there. - if sys.hexversion >= 0x2050200: - opts.numThreads = Util.detectCPUs() - else: - opts.numThreads = 1 - - inputs = args - - # Create the user defined parameters. - userParams = dict(builtinParameters) - for entry in opts.userParameters: - if '=' not in entry: - name,val = entry,'' - else: - name,val = entry.split('=', 1) - userParams[name] = val - - # Create the global config object. - litConfig = LitConfig.LitConfig(progname = os.path.basename(sys.argv[0]), - path = opts.path, - quiet = opts.quiet, - useValgrind = opts.useValgrind, - valgrindLeakCheck = opts.valgrindLeakCheck, - valgrindArgs = opts.valgrindArgs, - useTclAsSh = opts.useTclAsSh, - noExecute = opts.noExecute, - debug = opts.debug, - isWindows = (platform.system()=='Windows'), - params = userParams) - - # Expand '@...' form in inputs. - actual_inputs = [] - for input in inputs: - if os.path.exists(input) or not input.startswith('@'): - actual_inputs.append(input) - else: - f = open(input[1:]) - try: - for ln in f: - ln = ln.strip() - if ln: - actual_inputs.append(ln) - finally: - f.close() - - - # Load the tests from the inputs. - tests = [] - testSuiteCache = {} - localConfigCache = {} - for input in actual_inputs: - prev = len(tests) - tests.extend(getTests(input, litConfig, - testSuiteCache, localConfigCache)[1]) - if prev == len(tests): - litConfig.warning('input %r contained no tests' % input) - - # If there were any errors during test discovery, exit now. - if litConfig.numErrors: - print >>sys.stderr, '%d errors, exiting.' % litConfig.numErrors - sys.exit(2) - - if opts.showSuites: - suitesAndTests = dict([(ts,[]) - for ts,_ in testSuiteCache.values() - if ts]) - for t in tests: - suitesAndTests[t.suite].append(t) - - print '-- Test Suites --' - suitesAndTests = suitesAndTests.items() - suitesAndTests.sort(key = lambda (ts,_): ts.name) - for ts,ts_tests in suitesAndTests: - print ' %s - %d tests' %(ts.name, len(ts_tests)) - print ' Source Root: %s' % ts.source_root - print ' Exec Root : %s' % ts.exec_root - - # Select and order the tests. - numTotalTests = len(tests) - if opts.shuffle: - random.shuffle(tests) - else: - tests.sort(key = lambda t: t.getFullName()) - if opts.maxTests is not None: - tests = tests[:opts.maxTests] - - extra = '' - if len(tests) != numTotalTests: - extra = ' of %d' % numTotalTests - header = '-- Testing: %d%s tests, %d threads --'%(len(tests),extra, - opts.numThreads) - - if opts.repeatTests: - tests = [t.copyWithIndex(i) - for t in tests - for i in range(opts.repeatTests)] - - progressBar = None - if not opts.quiet: - if opts.succinct and opts.useProgressBar: - try: - tc = ProgressBar.TerminalController() - progressBar = ProgressBar.ProgressBar(tc, header) - except ValueError: - print header - progressBar = ProgressBar.SimpleProgressBar('Testing: ') - else: - print header - - # Don't create more threads than tests. - opts.numThreads = min(len(tests), opts.numThreads) - - startTime = time.time() - display = TestingProgressDisplay(opts, len(tests), progressBar) - provider = TestProvider(tests, opts.maxTime) - runTests(opts.numThreads, litConfig, provider, display) - display.finish() - - if not opts.quiet: - print 'Testing Time: %.2fs'%(time.time() - startTime) - - # Update results for any tests which weren't run. - for t in tests: - if t.result is None: - t.setResult(Test.UNRESOLVED, '', 0.0) - - # List test results organized by kind. - hasFailures = False - byCode = {} - for t in tests: - if t.result not in byCode: - byCode[t.result] = [] - byCode[t.result].append(t) - if t.result.isFailure: - hasFailures = True - - # FIXME: Show unresolved and (optionally) unsupported tests. - for title,code in (('Unexpected Passing Tests', Test.XPASS), - ('Failing Tests', Test.FAIL)): - elts = byCode.get(code) - if not elts: - continue - print '*'*20 - print '%s (%d):' % (title, len(elts)) - for t in elts: - print ' %s' % t.getFullName() - print - - if opts.timeTests: - # Collate, in case we repeated tests. - times = {} - for t in tests: - key = t.getFullName() - times[key] = times.get(key, 0.) + t.elapsed - - byTime = list(times.items()) - byTime.sort(key = lambda (name,elapsed): elapsed) - if byTime: - Util.printHistogram(byTime, title='Tests') - - for name,code in (('Expected Passes ', Test.PASS), - ('Expected Failures ', Test.XFAIL), - ('Unsupported Tests ', Test.UNSUPPORTED), - ('Unresolved Tests ', Test.UNRESOLVED), - ('Unexpected Passes ', Test.XPASS), - ('Unexpected Failures', Test.FAIL),): - if opts.quiet and not code.isFailure: - continue - N = len(byCode.get(code,[])) - if N: - print ' %s: %d' % (name,N) - - # If we encountered any additional errors, exit abnormally. - if litConfig.numErrors: - print >>sys.stderr, '\n%d error(s), exiting.' % litConfig.numErrors - sys.exit(2) - - # Warn about warnings. - if litConfig.numWarnings: - print >>sys.stderr, '\n%d warning(s) in tests.' % litConfig.numWarnings - - if hasFailures: - sys.exit(1) - sys.exit(0) - -if __name__=='__main__': - main() diff --git a/utils/lit/lit/main.py b/utils/lit/lit/main.py new file mode 100755 index 000000000000..13d263009ddd --- /dev/null +++ b/utils/lit/lit/main.py @@ -0,0 +1,648 @@ +#!/usr/bin/env python + +""" +lit - LLVM Integrated Tester. + +See lit.pod for more information. +""" + +import math, os, platform, random, re, sys, time, threading, traceback + +import ProgressBar +import TestRunner +import Util + +from TestingConfig import TestingConfig +import LitConfig +import Test + +# Configuration files to look for when discovering test suites. These can be +# overridden with --config-prefix. +# +# FIXME: Rename to 'config.lit', 'site.lit', and 'local.lit' ? +gConfigName = 'lit.cfg' +gSiteConfigName = 'lit.site.cfg' + +kLocalConfigName = 'lit.local.cfg' + +class TestingProgressDisplay: + def __init__(self, opts, numTests, progressBar=None): + self.opts = opts + self.numTests = numTests + self.current = None + self.lock = threading.Lock() + self.progressBar = progressBar + self.completed = 0 + + def update(self, test): + # Avoid locking overhead in quiet mode + if self.opts.quiet and not test.result.isFailure: + self.completed += 1 + return + + # Output lock. + self.lock.acquire() + try: + self.handleUpdate(test) + finally: + self.lock.release() + + def finish(self): + if self.progressBar: + self.progressBar.clear() + elif self.opts.quiet: + pass + elif self.opts.succinct: + sys.stdout.write('\n') + + def handleUpdate(self, test): + self.completed += 1 + if self.progressBar: + self.progressBar.update(float(self.completed)/self.numTests, + test.getFullName()) + + if self.opts.succinct and not test.result.isFailure: + return + + if self.progressBar: + self.progressBar.clear() + + print '%s: %s (%d of %d)' % (test.result.name, test.getFullName(), + self.completed, self.numTests) + + if test.result.isFailure and self.opts.showOutput: + print "%s TEST '%s' FAILED %s" % ('*'*20, test.getFullName(), + '*'*20) + print test.output + print "*" * 20 + + sys.stdout.flush() + +class TestProvider: + def __init__(self, tests, maxTime): + self.maxTime = maxTime + self.iter = iter(tests) + self.lock = threading.Lock() + self.startTime = time.time() + + def get(self): + # Check if we have run out of time. + if self.maxTime is not None: + if time.time() - self.startTime > self.maxTime: + return None + + # Otherwise take the next test. + self.lock.acquire() + try: + item = self.iter.next() + except StopIteration: + item = None + self.lock.release() + return item + +class Tester(threading.Thread): + def __init__(self, litConfig, provider, display): + threading.Thread.__init__(self) + self.litConfig = litConfig + self.provider = provider + self.display = display + + def run(self): + while 1: + item = self.provider.get() + if item is None: + break + self.runTest(item) + + def runTest(self, test): + result = None + startTime = time.time() + try: + result, output = test.config.test_format.execute(test, + self.litConfig) + except KeyboardInterrupt: + # This is a sad hack. Unfortunately subprocess goes + # bonkers with ctrl-c and we start forking merrily. + print '\nCtrl-C detected, goodbye.' + os.kill(0,9) + except: + if self.litConfig.debug: + raise + result = Test.UNRESOLVED + output = 'Exception during script execution:\n' + output += traceback.format_exc() + output += '\n' + elapsed = time.time() - startTime + + test.setResult(result, output, elapsed) + self.display.update(test) + +def dirContainsTestSuite(path): + cfgpath = os.path.join(path, gSiteConfigName) + if os.path.exists(cfgpath): + return cfgpath + cfgpath = os.path.join(path, gConfigName) + if os.path.exists(cfgpath): + return cfgpath + +def getTestSuite(item, litConfig, cache): + """getTestSuite(item, litConfig, cache) -> (suite, relative_path) + + Find the test suite containing @arg item. + + @retval (None, ...) - Indicates no test suite contains @arg item. + @retval (suite, relative_path) - The suite that @arg item is in, and its + relative path inside that suite. + """ + def search1(path): + # Check for a site config or a lit config. + cfgpath = dirContainsTestSuite(path) + + # If we didn't find a config file, keep looking. + if not cfgpath: + parent,base = os.path.split(path) + if parent == path: + return (None, ()) + + ts, relative = search(parent) + return (ts, relative + (base,)) + + # We found a config file, load it. + if litConfig.debug: + litConfig.note('loading suite config %r' % cfgpath) + + cfg = TestingConfig.frompath(cfgpath, None, litConfig, mustExist = True) + source_root = os.path.realpath(cfg.test_source_root or path) + exec_root = os.path.realpath(cfg.test_exec_root or path) + return Test.TestSuite(cfg.name, source_root, exec_root, cfg), () + + def search(path): + # Check for an already instantiated test suite. + res = cache.get(path) + if res is None: + cache[path] = res = search1(path) + return res + + # Canonicalize the path. + item = os.path.realpath(item) + + # Skip files and virtual components. + components = [] + while not os.path.isdir(item): + parent,base = os.path.split(item) + if parent == item: + return (None, ()) + components.append(base) + item = parent + components.reverse() + + ts, relative = search(item) + return ts, tuple(relative + tuple(components)) + +def getLocalConfig(ts, path_in_suite, litConfig, cache): + def search1(path_in_suite): + # Get the parent config. + if not path_in_suite: + parent = ts.config + else: + parent = search(path_in_suite[:-1]) + + # Load the local configuration. + source_path = ts.getSourcePath(path_in_suite) + cfgpath = os.path.join(source_path, kLocalConfigName) + if litConfig.debug: + litConfig.note('loading local config %r' % cfgpath) + return TestingConfig.frompath(cfgpath, parent, litConfig, + mustExist = False, + config = parent.clone(cfgpath)) + + def search(path_in_suite): + key = (ts, path_in_suite) + res = cache.get(key) + if res is None: + cache[key] = res = search1(path_in_suite) + return res + + return search(path_in_suite) + +def getTests(path, litConfig, testSuiteCache, localConfigCache): + # Find the test suite for this input and its relative path. + ts,path_in_suite = getTestSuite(path, litConfig, testSuiteCache) + if ts is None: + litConfig.warning('unable to find test suite for %r' % path) + return (),() + + if litConfig.debug: + litConfig.note('resolved input %r to %r::%r' % (path, ts.name, + path_in_suite)) + + return ts, getTestsInSuite(ts, path_in_suite, litConfig, + testSuiteCache, localConfigCache) + +def getTestsInSuite(ts, path_in_suite, litConfig, + testSuiteCache, localConfigCache): + # Check that the source path exists (errors here are reported by the + # caller). + source_path = ts.getSourcePath(path_in_suite) + if not os.path.exists(source_path): + return + + # Check if the user named a test directly. + if not os.path.isdir(source_path): + lc = getLocalConfig(ts, path_in_suite[:-1], litConfig, localConfigCache) + yield Test.Test(ts, path_in_suite, lc) + return + + # Otherwise we have a directory to search for tests, start by getting the + # local configuration. + lc = getLocalConfig(ts, path_in_suite, litConfig, localConfigCache) + + # Search for tests. + if lc.test_format is not None: + for res in lc.test_format.getTestsInDirectory(ts, path_in_suite, + litConfig, lc): + yield res + + # Search subdirectories. + for filename in os.listdir(source_path): + # FIXME: This doesn't belong here? + if filename in ('Output', '.svn') or filename in lc.excludes: + continue + + # Ignore non-directories. + file_sourcepath = os.path.join(source_path, filename) + if not os.path.isdir(file_sourcepath): + continue + + # Check for nested test suites, first in the execpath in case there is a + # site configuration and then in the source path. + file_execpath = ts.getExecPath(path_in_suite + (filename,)) + if dirContainsTestSuite(file_execpath): + sub_ts, subiter = getTests(file_execpath, litConfig, + testSuiteCache, localConfigCache) + elif dirContainsTestSuite(file_sourcepath): + sub_ts, subiter = getTests(file_sourcepath, litConfig, + testSuiteCache, localConfigCache) + else: + # Otherwise, continue loading from inside this test suite. + subiter = getTestsInSuite(ts, path_in_suite + (filename,), + litConfig, testSuiteCache, + localConfigCache) + sub_ts = None + + N = 0 + for res in subiter: + N += 1 + yield res + if sub_ts and not N: + litConfig.warning('test suite %r contained no tests' % sub_ts.name) + +def runTests(numThreads, litConfig, provider, display): + # If only using one testing thread, don't use threads at all; this lets us + # profile, among other things. + if numThreads == 1: + t = Tester(litConfig, provider, display) + t.run() + return + + # Otherwise spin up the testing threads and wait for them to finish. + testers = [Tester(litConfig, provider, display) + for i in range(numThreads)] + for t in testers: + t.start() + try: + for t in testers: + t.join() + except KeyboardInterrupt: + sys.exit(2) + +def load_test_suite(inputs): + import unittest + + # Create the global config object. + litConfig = LitConfig.LitConfig(progname = 'lit', + path = [], + quiet = False, + useValgrind = False, + valgrindLeakCheck = False, + valgrindArgs = [], + useTclAsSh = False, + noExecute = False, + debug = False, + isWindows = (platform.system()=='Windows'), + params = {}) + + # Load the tests from the inputs. + tests = [] + testSuiteCache = {} + localConfigCache = {} + for input in inputs: + prev = len(tests) + tests.extend(getTests(input, litConfig, + testSuiteCache, localConfigCache)[1]) + if prev == len(tests): + litConfig.warning('input %r contained no tests' % input) + + # If there were any errors during test discovery, exit now. + if litConfig.numErrors: + print >>sys.stderr, '%d errors, exiting.' % litConfig.numErrors + sys.exit(2) + + # Return a unittest test suite which just runs the tests in order. + def get_test_fn(test): + return unittest.FunctionTestCase( + lambda: test.config.test_format.execute( + test, litConfig), + description = test.getFullName()) + + from LitTestCase import LitTestCase + return unittest.TestSuite([LitTestCase(test, litConfig) for test in tests]) + +def main(builtinParameters = {}): # Bump the GIL check interval, its more important to get any one thread to a + # blocking operation (hopefully exec) than to try and unblock other threads. + # + # FIXME: This is a hack. + import sys + sys.setcheckinterval(1000) + + global options + from optparse import OptionParser, OptionGroup + parser = OptionParser("usage: %prog [options] {file-or-path}") + + parser.add_option("-j", "--threads", dest="numThreads", metavar="N", + help="Number of testing threads", + type=int, action="store", default=None) + parser.add_option("", "--config-prefix", dest="configPrefix", + metavar="NAME", help="Prefix for 'lit' config files", + action="store", default=None) + parser.add_option("", "--param", dest="userParameters", + metavar="NAME=VAL", + help="Add 'NAME' = 'VAL' to the user defined parameters", + type=str, action="append", default=[]) + + group = OptionGroup(parser, "Output Format") + # FIXME: I find these names very confusing, although I like the + # functionality. + group.add_option("-q", "--quiet", dest="quiet", + help="Suppress no error output", + action="store_true", default=False) + group.add_option("-s", "--succinct", dest="succinct", + help="Reduce amount of output", + action="store_true", default=False) + group.add_option("-v", "--verbose", dest="showOutput", + help="Show all test output", + action="store_true", default=False) + group.add_option("", "--no-progress-bar", dest="useProgressBar", + help="Do not use curses based progress bar", + action="store_false", default=True) + parser.add_option_group(group) + + group = OptionGroup(parser, "Test Execution") + group.add_option("", "--path", dest="path", + help="Additional paths to add to testing environment", + action="append", type=str, default=[]) + group.add_option("", "--vg", dest="useValgrind", + help="Run tests under valgrind", + action="store_true", default=False) + group.add_option("", "--vg-leak", dest="valgrindLeakCheck", + help="Check for memory leaks under valgrind", + action="store_true", default=False) + group.add_option("", "--vg-arg", dest="valgrindArgs", metavar="ARG", + help="Specify an extra argument for valgrind", + type=str, action="append", default=[]) + group.add_option("", "--time-tests", dest="timeTests", + help="Track elapsed wall time for each test", + action="store_true", default=False) + group.add_option("", "--no-execute", dest="noExecute", + help="Don't execute any tests (assume PASS)", + action="store_true", default=False) + parser.add_option_group(group) + + group = OptionGroup(parser, "Test Selection") + group.add_option("", "--max-tests", dest="maxTests", metavar="N", + help="Maximum number of tests to run", + action="store", type=int, default=None) + group.add_option("", "--max-time", dest="maxTime", metavar="N", + help="Maximum time to spend testing (in seconds)", + action="store", type=float, default=None) + group.add_option("", "--shuffle", dest="shuffle", + help="Run tests in random order", + action="store_true", default=False) + parser.add_option_group(group) + + group = OptionGroup(parser, "Debug and Experimental Options") + group.add_option("", "--debug", dest="debug", + help="Enable debugging (for 'lit' development)", + action="store_true", default=False) + group.add_option("", "--show-suites", dest="showSuites", + help="Show discovered test suites", + action="store_true", default=False) + group.add_option("", "--no-tcl-as-sh", dest="useTclAsSh", + help="Don't run Tcl scripts using 'sh'", + action="store_false", default=True) + group.add_option("", "--repeat", dest="repeatTests", metavar="N", + help="Repeat tests N times (for timing)", + action="store", default=None, type=int) + parser.add_option_group(group) + + (opts, args) = parser.parse_args() + + if not args: + parser.error('No inputs specified') + + if opts.configPrefix is not None: + global gConfigName, gSiteConfigName + gConfigName = '%s.cfg' % opts.configPrefix + gSiteConfigName = '%s.site.cfg' % opts.configPrefix + + if opts.numThreads is None: +# Python <2.5 has a race condition causing lit to always fail with numThreads>1 +# http://bugs.python.org/issue1731717 +# I haven't seen this bug occur with 2.5.2 and later, so only enable multiple +# threads by default there. + if sys.hexversion >= 0x2050200: + opts.numThreads = Util.detectCPUs() + else: + opts.numThreads = 1 + + inputs = args + + # Create the user defined parameters. + userParams = dict(builtinParameters) + for entry in opts.userParameters: + if '=' not in entry: + name,val = entry,'' + else: + name,val = entry.split('=', 1) + userParams[name] = val + + # Create the global config object. + litConfig = LitConfig.LitConfig(progname = os.path.basename(sys.argv[0]), + path = opts.path, + quiet = opts.quiet, + useValgrind = opts.useValgrind, + valgrindLeakCheck = opts.valgrindLeakCheck, + valgrindArgs = opts.valgrindArgs, + useTclAsSh = opts.useTclAsSh, + noExecute = opts.noExecute, + debug = opts.debug, + isWindows = (platform.system()=='Windows'), + params = userParams) + + # Expand '@...' form in inputs. + actual_inputs = [] + for input in inputs: + if os.path.exists(input) or not input.startswith('@'): + actual_inputs.append(input) + else: + f = open(input[1:]) + try: + for ln in f: + ln = ln.strip() + if ln: + actual_inputs.append(ln) + finally: + f.close() + + + # Load the tests from the inputs. + tests = [] + testSuiteCache = {} + localConfigCache = {} + for input in actual_inputs: + prev = len(tests) + tests.extend(getTests(input, litConfig, + testSuiteCache, localConfigCache)[1]) + if prev == len(tests): + litConfig.warning('input %r contained no tests' % input) + + # If there were any errors during test discovery, exit now. + if litConfig.numErrors: + print >>sys.stderr, '%d errors, exiting.' % litConfig.numErrors + sys.exit(2) + + if opts.showSuites: + suitesAndTests = dict([(ts,[]) + for ts,_ in testSuiteCache.values() + if ts]) + for t in tests: + suitesAndTests[t.suite].append(t) + + print '-- Test Suites --' + suitesAndTests = suitesAndTests.items() + suitesAndTests.sort(key = lambda (ts,_): ts.name) + for ts,ts_tests in suitesAndTests: + print ' %s - %d tests' %(ts.name, len(ts_tests)) + print ' Source Root: %s' % ts.source_root + print ' Exec Root : %s' % ts.exec_root + + # Select and order the tests. + numTotalTests = len(tests) + if opts.shuffle: + random.shuffle(tests) + else: + tests.sort(key = lambda t: t.getFullName()) + if opts.maxTests is not None: + tests = tests[:opts.maxTests] + + extra = '' + if len(tests) != numTotalTests: + extra = ' of %d' % numTotalTests + header = '-- Testing: %d%s tests, %d threads --'%(len(tests),extra, + opts.numThreads) + + if opts.repeatTests: + tests = [t.copyWithIndex(i) + for t in tests + for i in range(opts.repeatTests)] + + progressBar = None + if not opts.quiet: + if opts.succinct and opts.useProgressBar: + try: + tc = ProgressBar.TerminalController() + progressBar = ProgressBar.ProgressBar(tc, header) + except ValueError: + print header + progressBar = ProgressBar.SimpleProgressBar('Testing: ') + else: + print header + + # Don't create more threads than tests. + opts.numThreads = min(len(tests), opts.numThreads) + + startTime = time.time() + display = TestingProgressDisplay(opts, len(tests), progressBar) + provider = TestProvider(tests, opts.maxTime) + runTests(opts.numThreads, litConfig, provider, display) + display.finish() + + if not opts.quiet: + print 'Testing Time: %.2fs'%(time.time() - startTime) + + # Update results for any tests which weren't run. + for t in tests: + if t.result is None: + t.setResult(Test.UNRESOLVED, '', 0.0) + + # List test results organized by kind. + hasFailures = False + byCode = {} + for t in tests: + if t.result not in byCode: + byCode[t.result] = [] + byCode[t.result].append(t) + if t.result.isFailure: + hasFailures = True + + # FIXME: Show unresolved and (optionally) unsupported tests. + for title,code in (('Unexpected Passing Tests', Test.XPASS), + ('Failing Tests', Test.FAIL)): + elts = byCode.get(code) + if not elts: + continue + print '*'*20 + print '%s (%d):' % (title, len(elts)) + for t in elts: + print ' %s' % t.getFullName() + print + + if opts.timeTests: + # Collate, in case we repeated tests. + times = {} + for t in tests: + key = t.getFullName() + times[key] = times.get(key, 0.) + t.elapsed + + byTime = list(times.items()) + byTime.sort(key = lambda (name,elapsed): elapsed) + if byTime: + Util.printHistogram(byTime, title='Tests') + + for name,code in (('Expected Passes ', Test.PASS), + ('Expected Failures ', Test.XFAIL), + ('Unsupported Tests ', Test.UNSUPPORTED), + ('Unresolved Tests ', Test.UNRESOLVED), + ('Unexpected Passes ', Test.XPASS), + ('Unexpected Failures', Test.FAIL),): + if opts.quiet and not code.isFailure: + continue + N = len(byCode.get(code,[])) + if N: + print ' %s: %d' % (name,N) + + # If we encountered any additional errors, exit abnormally. + if litConfig.numErrors: + print >>sys.stderr, '\n%d error(s), exiting.' % litConfig.numErrors + sys.exit(2) + + # Warn about warnings. + if litConfig.numWarnings: + print >>sys.stderr, '\n%d warning(s) in tests.' % litConfig.numWarnings + + if hasFailures: + sys.exit(1) + sys.exit(0) + +if __name__=='__main__': + main() diff --git a/utils/lit/setup.py b/utils/lit/setup.py index e6ae3d880488..738ee23776d8 100644 --- a/utils/lit/setup.py +++ b/utils/lit/setup.py @@ -3,7 +3,7 @@ import lit # FIXME: Support distutils? from setuptools import setup, find_packages setup( - name = "Lit", + name = "lit", version = lit.__version__, author = lit.__author__, @@ -14,15 +14,16 @@ setup( description = "A Software Testing Tool", keywords = 'test C++ automatic discovery', long_description = """\ -Lit -+++ +*lit* ++++++ About ===== -Lit is a portable tool for executing LLVM and Clang style test suites, -summarizing their results, and providing indication of failures. Lit is designed -to be a lightweight testing tool with as simple a user interface as possible. +*lit* is a portable tool for executing LLVM and Clang style test suites, +summarizing their results, and providing indication of failures. *lit* is +designed to be a lightweight testing tool with as simple a user interface as +possible. Features @@ -37,15 +38,15 @@ Features Documentation ============= -The offical Lit documentation is in the man page, available online in the `LLVM -Command Guide http://llvm.org/cmds/lit.html`_. +The offical *lit* documentation is in the man page, available online at the LLVM +Command Guide: http://llvm.org/cmds/lit.html. Source ====== -The Lit source is available as part of LLVM, in the `LLVM SVN repository - +# Syntax: profile.pl [OPTIONS] bitcodefile # # OPTIONS may include one or more of the following: # -block - Enable basicblock profiling @@ -56,7 +56,7 @@ while (scalar(@ARGV) and ($_ = $ARGV[0], /^[-+]/)) { $LLVMProfOpts .= " " . $_; } -die "Must specify LLVM bytecode file as first argument!" if (@ARGV == 0); +die "Must specify LLVM bitcode file as first argument!" if (@ARGV == 0); my $BytecodeFile = $ARGV[0]; diff --git a/utils/release/test-release.sh b/utils/release/test-release.sh new file mode 100755 index 000000000000..e24638e714a3 --- /dev/null +++ b/utils/release/test-release.sh @@ -0,0 +1,398 @@ +#!/bin/bash +#===-- test-release.sh - Test the LLVM release candidates ------------------===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. +# +#===------------------------------------------------------------------------===# +# +# Download, build, and test the release candidate for an LLVM release. +# +#===------------------------------------------------------------------------===# + +set -e + +Release="" +Release_no_dot="" +RC="" +do_checkout="yes" +do_ada="no" +do_objc="yes" +do_fortran="yes" +do_64bit="yes" +BuildDir="`pwd`" + +function usage() { + echo "usage: `basename $0` -release X.Y -rc NUM [OPTIONS]" + echo "" + echo " -release X.Y The release number to test." + echo " -rc NUM The pre-release candidate number." + echo " -j NUM Number of compile jobs to run. [default: 3]" + echo " -build-dir DIR Directory to perform testing in. [default: pwd]" + echo " -no-checkout Don't checkout the sources from SVN." + echo " -no-64bit Don't test the 64-bit version. [default: yes]" + echo " -ada Build Ada. [default: no]" + echo " -disable-objc Disable ObjC build. [default: build]" + echo " -disable-fortran Disable Fortran build. [default: build]" +} + +while [ $# -gt 0 ]; do + case $1 in + -release | --release ) + shift + Release="$1" + Release_no_dot="`echo $1 | sed -e 's,\.,,'`" + ;; + -rc | --rc | -RC | --RC ) + shift + RC=$1 + ;; + -j* ) + NumJobs="`echo $1 | sed -e 's,-j\([0-9]*\),\1,g'`" + if [ -z "$NumJobs" ]; then + shift + NumJobs="$1" + fi + ;; + -build-dir | --build-dir | -builddir | --builddir ) + shift + BuildDir="$1" + ;; + -no-checkout | --no-checkout ) + do_checkout="no" + ;; + -no-64bit | --no-64bit ) + do_64bit="no" + ;; + -ada | --ada ) + do_ada="yes" + ;; + -disable-objc | --disable-objc ) + do_objc="no" + ;; + -disable-fortran | --disable-fortran ) + echo "WARNING: Do you *really* need to disable Fortran?" + sleep 5 + do_fortran="no" + ;; + -help | --help | -h | --h | -\? ) + usage + exit 0 + ;; + * ) + echo "unknown option: $1" + usage + exit 1 + ;; + esac + shift +done + +# Check required arguments. +if [ -z "$Release" ]; then + echo "No release number specified!" + exit 1 +fi +if [ -z "$RC" ]; then + echo "No release candidate number specified!" + exit 1 +fi + +# Figure out how many make processes to run. +if [ -z "$NumJobs" ]; then + NumJobs=`sysctl -n hw.activecpu 2> /dev/null || true` +fi +if [ -z "$NumJobs" ]; then + NumJobs=`sysctl -n hw.ncpu 2> /dev/null || true` +fi +if [ -z "$NumJobs" ]; then + NumJobs=`grep -c processor /proc/cpuinfo 2> /dev/null || true` +fi +if [ -z "$NumJobs" ]; then + NumJobs=3 +fi + +# Location of sources. +llvmCore_srcdir=$BuildDir/llvmCore-$Release-rc$RC.src +llvmgcc42_srcdir=$BuildDir/llvmgcc42-$Release-rc$RC.src + +# Location of log files. +LogDirName="$Release-rc$RC.logs" +LogDir=$BuildDir/$LogDirName +mkdir -p $LogDir + +# SVN URLs for the sources. +Base_url="http://llvm.org/svn/llvm-project" +llvmCore_RC_url="$Base_url/llvm/tags/RELEASE_$Release_no_dot/rc$RC" +llvmgcc42_RC_url="$Base_url/llvm-gcc-4.2/tags/RELEASE_$Release_no_dot/rc$RC" +clang_RC_url="$Base_url/cfe/tags/RELEASE_$Release_no_dot/rc$RC" +test_suite_RC_url="$Base_url/test-suite/tags/RELEASE_$Release_no_dot/rc$RC" + +# Make sure that the URLs are valid. +function check_valid_urls() { + echo "# Validating SVN URLs" + if ! svn ls $llvmCore_RC_url > /dev/null 2>&1 ; then + echo "llvm $Release release candidate $RC doesn't exist!" + exit 1 + fi + if ! svn ls $llvmgcc42_RC_url > /dev/null 2>&1 ; then + echo "llvm-gcc-4.2 $Release release candidate $RC doesn't exist!" + exit 1 + fi + if ! svn ls $clang_RC_url > /dev/null 2>&1 ; then + echo "clang $Release release candidate $RC doesn't exist!" + exit 1 + fi + if ! svn ls $test_suite_RC_url > /dev/null 2>&1 ; then + echo "test-suite $Release release candidate $RC doesn't exist!" + exit 1 + fi +} + +# Export sources to the the build directory. +function export_sources() { + check_valid_urls + + echo "# Exporting llvm $Release-RC$RC sources" + svn export -q $llvmCore_RC_url $llvmCore_srcdir + echo "# Exporting llvm-gcc-4.2 $Release-rc$RC sources" + svn export -q $llvmgcc42_RC_url $llvmgcc42_srcdir + echo "# Exporting clang $Release-rc$RC sources" + svn export -q $clang_RC_url $llvmCore_srcdir/tools/clang + echo "# Exporting llvm test suite $Release-rc$RC sources" + svn export -q $test_suite_RC_url $llvmCore_srcdir/projects/llvm-test +} + +function configure_llvmCore() { + Phase="$1" + Flavor="$2" + ObjDir="$3" + InstallDir="$4" + llvmgccDir="$5" + + case $Flavor in + Release | Release-64 ) + Optimized="yes" + Assertions="no" + ;; + Release+Asserts ) + Optimized="yes" + Assertions="yes" + ;; + Debug ) + Optimized="no" + Assertions="yes" + ;; + * ) + echo "# Invalid flavor $Flavor!" + echo "" + return + ;; + esac + + cd $ObjDir + echo "# Configuring llvm $Release-rc$RC $Flavor" + echo "# $llvmCore_srcdir/configure --prefix=$InstallDir \ + --enable-optimized=$Optimized \ + --enable-assertions=$Assertions \ + --with-llvmgccdir=$llvmgccDir" + $llvmCore_srcdir/configure --prefix=$InstallDir \ + --enable-optimized=$Optimized \ + --enable-assertions=$Assertions \ + --with-llvmgccdir=$llvmgccDir \ + > $LogDir/llvm.configure.$Release-rc$RC-Phase$Phase-$Flavor.log 2>&1 + cd - +} + +function build_llvmCore() { + Phase="$1" + Flavor="$2" + ObjDir="$3" + ExtraOpts="" + + CompilerFlags="" + if [ "$Phase" = "2" ]; then + CompilerFlags="CC=$llvmgccDir/bin/llvm-gcc CXX=$llvmgccDir/bin/llvm-g++" + fi + if [ "$Flavor" = "Release-64" ]; then + ExtraOpts="EXTRA_OPTIONS=-m64" + fi + + cd $ObjDir + echo "# Compiling llvm $Release-rc$RC $Flavor" + echo "# make -j $NumJobs VERBOSE=1 $ExtraOpts" + make -j $NumJobs VERBOSE=1 $ExtraOpts $CompilerFlags \ + > $LogDir/llvm.make.$Release-rc$RC-Phase$Phase-$Flavor.log 2>&1 + + echo "# Installing llvm $Release-rc$RC $Flavor" + echo "# make install" + make install \ + > $LogDir/llvm.install.$Release-rc$RC-Phase$Phase-$Flavor.log 2>&1 + cd - +} + +function test_llvmCore() { + Phase="$1" + Flavor="$2" + ObjDir="$3" + + cd $ObjDir + make check \ + > $LogDir/llvm.check.$Release-rc$RC-Phase$Phase-$Flavor.log 2>&1 + make -C tools/clang test \ + > $LogDir/clang.check.$Release-rc$RC-Phase$Phase-$Flavor.log 2>&1 + make unittests \ + > $LogDir/llvm.unittests.$Release-rc$RC-Phase$Phase-$Flavor.log 2>&1 + cd - +} + +function configure_llvm_gcc() { + Phase="$1" + Flavor="$2" + ObjDir="$3" + InstallDir="$4" + llvmObjDir="$5" + + languages="c,c++" + if [ "$do_objc" = "yes" ]; then + languages="$languages,objc,obj-c++" + fi + if [ "$do_fortran" = "yes" ]; then + languages="$languages,fortran" + fi + if [ "$do_ada" = "yes" ]; then + languages="$languages,ada" + fi + + cd $ObjDir + echo "# Configuring llvm-gcc $Release-rc$RC $Flavor" + echo "# $llvmgcc42_srcdir/configure --prefix=$InstallDir \ + --program-prefix=llvm- --enable-llvm=$llvmObjDir \ + --enable-languages=$languages" + $llvmgcc42_srcdir/configure --prefix=$InstallDir \ + --program-prefix=llvm- --enable-llvm=$llvmObjDir \ + --enable-languages=$languages \ + > $LogDir/llvm-gcc.configure.$Release-rc$RC-Phase$Phase-$Flavor.log 2>&1 + cd - +} + +function build_llvm_gcc() { + Phase="$1" + Flavor="$2" + ObjDir="$3" + llvmgccDir="$4" + + CompilerFlags="" + if [ "$Phase" = "2" ]; then + CompilerFlags="CC=$llvmgccDir/bin/llvm-gcc CXX=$llvmgccDir/bin/llvm-g++" + fi + + cd $ObjDir + echo "# Compiling llvm-gcc $Release-rc$RC $Flavor" + echo "# make -j $NumJobs bootstrap LLVM_VERSION_INFO=$Release" + make -j $NumJobs bootstrap LLVM_VERSION_INFO=$Release $CompilerFlags \ + > $LogDir/llvm-gcc.make.$Release-rc$RC-Phase$Phase-$Flavor.log 2>&1 + + echo "# Installing llvm-gcc $Release-rc$RC $Flavor" + echo "# make install" + make install \ + > $LogDir/llvm-gcc.install.$Release-rc$RC-Phase$Phase-$Flavor.log 2>&1 + cd - +} + +if [ "$do_checkout" = "yes" ]; then + export_sources +fi + +( +Flavors="Debug Release Release+Asserts" +if [ "$do_64bit" = "yes" ]; then + Flavors="$Flavors Release-64" +fi + +for Flavor in $Flavors ; do + echo "" + echo "" + echo "********************************************************************************" + echo " Release: $Release-rc$RC" + echo " Build: $Flavor" + echo " System Info: " + echo " `uname -a`" + echo "********************************************************************************" + echo "" + + llvmCore_phase1_objdir=$BuildDir/Phase1/$Flavor/llvmCore-$Release-rc$RC.obj + llvmCore_phase1_installdir=$BuildDir/Phase1/$Flavor/llvmCore-$Release-rc$RC.install + + llvmCore_phase2_objdir=$BuildDir/Phase2/$Flavor/llvmCore-$Release-rc$RC.obj + llvmCore_phase2_installdir=$BuildDir/Phase2/$Flavor/llvmCore-$Release-rc$RC.install + + rm -rf $llvmCore_phase1_objdir + rm -rf $llvmCore_phase1_installdir + rm -rf $llvmCore_phase2_objdir + rm -rf $llvmCore_phase2_installdir + + mkdir -p $llvmCore_phase1_objdir + mkdir -p $llvmCore_phase1_installdir + mkdir -p $llvmCore_phase2_objdir + mkdir -p $llvmCore_phase2_installdir + + llvmgcc42_phase1_objdir=$BuildDir/Phase1/$Flavor/llvmgcc42-$Release-rc$RC.obj + llvmgcc42_phase1_installdir=$BuildDir/Phase1/$Flavor/llvmgcc42-$Release-rc$RC.install + + llvmgcc42_phase2_objdir=$BuildDir/Phase2/$Flavor/llvmgcc42-$Release-rc$RC.obj + llvmgcc42_phase2_installdir=$BuildDir/Phase2/$Flavor/llvmgcc42-$Release-rc$RC.install + + rm -rf $llvmgcc42_phase1_objdir + rm -rf $llvmgcc42_phase1_installdir + rm -rf $llvmgcc42_phase2_objdir + rm -rf $llvmgcc42_phase2_installdir + + mkdir -p $llvmgcc42_phase1_objdir + mkdir -p $llvmgcc42_phase1_installdir + mkdir -p $llvmgcc42_phase2_objdir + mkdir -p $llvmgcc42_phase2_installdir + + ############################################################################ + # Phase 1: Build llvmCore and llvmgcc42 + echo "# Phase 1: Building llvmCore" + configure_llvmCore 1 $Flavor \ + $llvmCore_phase1_objdir $llvmCore_phase1_installdir \ + $llvmgcc42_phase1_installdir + build_llvmCore 1 $Flavor \ + $llvmCore_phase1_objdir + + echo "# Phase 1: Building llvmgcc42" + configure_llvm_gcc 1 $Flavor \ + $llvmgcc42_phase1_objdir $llvmgcc42_phase1_installdir \ + $llvmCore_phase1_objdir + build_llvm_gcc 1 $Flavor \ + $llvmgcc42_phase1_objdir $llvmgcc42_phase1_installdir + + ############################################################################ + # Phase 2: Build llvmCore with newly built llvmgcc42 from phase 1. + echo "# Phase 2: Building llvmCore" + configure_llvmCore 2 $Flavor \ + $llvmCore_phase2_objdir $llvmCore_phase2_installdir \ + $llvmgcc42_phase1_installdir + build_llvmCore 2 $Flavor \ + $llvmCore_phase2_objdir + + echo "# Phase 2: Building llvmgcc42" + configure_llvm_gcc 2 $Flavor \ + $llvmgcc42_phase2_objdir $llvmgcc42_phase2_installdir \ + $llvmCore_phase2_objdir + build_llvm_gcc 2 $Flavor \ + $llvmgcc42_phase2_objdir $llvmgcc42_phase1_installdir + + echo "# Testing - built with llvmgcc42" + test_llvmCore 2 $Flavor $llvmCore_phase2_objdir +done +) 2>&1 | tee $LogDir/testing.$Release-rc$RC.log + +# Woo hoo! +echo "### Testing Finished ###" +echo "### Logs: $LogDir" +exit 0 diff --git a/utils/test_debuginfo.pl b/utils/test_debuginfo.pl new file mode 100755 index 000000000000..fb61fb02616d --- /dev/null +++ b/utils/test_debuginfo.pl @@ -0,0 +1,61 @@ +#!/usr/bin/perl +# +# This script tests debugging information generated by a compiler. +# Input arguments +# - Input source program. Usually this source file is decorated using +# special comments to communicate debugger commands. +# - Executable file. This file is generated by the compiler. +# +# This perl script extracts debugger commands from input source program +# comments in a script. A debugger is used to load the executable file +# and run the script generated from source program comments. Finally, +# the debugger output is checked, using FileCheck, to validate +# debugging information. + +use File::Basename; + +my $testcase_file = $ARGV[0]; +my $executable_file = $ARGV[1]; + +my $input_filename = basename $testcase_file; +my $output_dir = dirname $executable_file; + +my $debugger_script_file = "$output_dir/$input_filename.debugger.script"; +my $output_file = "$output_dir/$input_filename.gdb.output"; + +# Extract debugger commands from testcase. They are marked with DEBUGGER: +# at the beginnign of a comment line. +open(INPUT, $testcase_file); +open(OUTPUT, ">$debugger_script_file"); +while() { + my($line) = $_; + $i = index($line, "DEBUGGER:"); + if ( $i >= 0) { + $l = length("DEBUGGER:"); + $s = substr($line, $i + $l); + print OUTPUT "$s"; + } +} +print OUTPUT "\n"; +print OUTPUT "quit\n"; +close(INPUT); +close(OUTPUT); + +# setup debugger and debugger options to run a script. +my $my_debugger = $ENV{'DEBUGGER'}; +if (!$my_debugger) { + $my_debugger = "gdb"; +} +my $debugger_options = "-q -batch -n -x"; + +# run debugger and capture output. +system("$my_debugger $debugger_options $debugger_script_file $executable_file >& $output_file"); + +# validate output. +system("FileCheck", "-input-file", "$output_file", "$testcase_file"); +if ($?>>8 == 1) { + exit 1; +} +else { + exit 0; +} diff --git a/utils/unittest/CMakeLists.txt b/utils/unittest/CMakeLists.txt new file mode 100644 index 000000000000..29218bb37c71 --- /dev/null +++ b/utils/unittest/CMakeLists.txt @@ -0,0 +1,41 @@ +######################################################################## +# Experimental CMake build script for Google Test. +# +# Consider this a prototype. It will change drastically. For now, +# this is only for people on the cutting edge. +# +# To run the tests for Google Test itself on Linux, use 'make test' or +# ctest. You can select which tests to run using 'ctest -R regex'. +# For more options, run 'ctest --help'. +######################################################################## +# +# Project-wide settings + +# Where gtest's .h files can be found. +include_directories( + googletest/include + ) + +if(WIN32) + add_definitions(-DGTEST_OS_WINDOWS=1) +endif() + +if(SUPPORTS_NO_VARIADIC_MACROS_FLAG) + add_definitions("-Wno-variadic-macros") +endif() + +set(LLVM_REQUIRES_RTTI 1) +add_definitions( -DGTEST_HAS_RTTI=0 ) + +add_llvm_library(gtest + googletest/gtest.cc + googletest/gtest-death-test.cc + googletest/gtest-filepath.cc + googletest/gtest-port.cc + googletest/gtest-test-part.cc + googletest/gtest-typed-test.cc + ) + +add_llvm_library(gtest_main + UnitTestMain/TestMain.cpp + ) diff --git a/utils/unittest/UnitTestMain/TestMain.cpp b/utils/unittest/UnitTestMain/TestMain.cpp index d97dca872ad7..b35bae5abfb1 100644 --- a/utils/unittest/UnitTestMain/TestMain.cpp +++ b/utils/unittest/UnitTestMain/TestMain.cpp @@ -7,9 +7,36 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Config/config.h" +#include "llvm/Support/Signals.h" #include "gtest/gtest.h" + +#if defined(LLVM_ON_WIN32) +# include +# if defined(_MSC_VER) +# include +# endif +#endif + int main(int argc, char **argv) { + llvm::sys::PrintStackTraceOnErrorSignal(); testing::InitGoogleTest(&argc, argv); + +# if defined(LLVM_ON_WIN32) + // Disable all of the possible ways Windows conspires to make automated + // testing impossible. + ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); +# if defined(_MSC_VER) + ::_set_error_mode(_OUT_TO_STDERR); + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); + _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); +# endif +# endif + return RUN_ALL_TESTS(); } diff --git a/utils/unittest/googletest/gtest.cc b/utils/unittest/googletest/gtest.cc index aa2d5bb92509..51732afd4999 100644 --- a/utils/unittest/googletest/gtest.cc +++ b/utils/unittest/googletest/gtest.cc @@ -1964,8 +1964,8 @@ void ReportFailureInUnknownLocation(TestPartResult::Type result_type, } // namespace internal -#if GTEST_OS_WINDOWS -// We are on Windows. +#if GTEST_HAS_SEH +// We are on Windows with SEH. // Adds an "exception thrown" fatal failure to the current test. static void AddExceptionThrownFailure(DWORD exception_code, @@ -1978,7 +1978,7 @@ static void AddExceptionThrownFailure(DWORD exception_code, message.GetString()); } -#endif // GTEST_OS_WINDOWS +#endif // GTEST_HAS_SEH // Google Test requires all tests in the same test case to use the same test // fixture class. This function checks if the current test has the @@ -2224,35 +2224,6 @@ int TestInfo::increment_death_test_count() { return impl_->result()->increment_death_test_count(); } -namespace { - -// A predicate that checks the test name of a TestInfo against a known -// value. -// -// This is used for implementation of the TestCase class only. We put -// it in the anonymous namespace to prevent polluting the outer -// namespace. -// -// TestNameIs is copyable. -class TestNameIs { - public: - // Constructor. - // - // TestNameIs has NO default constructor. - explicit TestNameIs(const char* name) - : name_(name) {} - - // Returns true iff the test name of test_info matches name_. - bool operator()(const TestInfo * test_info) const { - return test_info && internal::String(test_info->name()).Compare(name_) == 0; - } - - private: - internal::String name_; -}; - -} // namespace - namespace internal { // This method expands all parameterized tests registered with macros TEST_P diff --git a/utils/unittest/googletest/include/gtest/internal/gtest-port.h b/utils/unittest/googletest/include/gtest/internal/gtest-port.h index 9683271e48f0..3d076eb44c78 100644 --- a/utils/unittest/googletest/include/gtest/internal/gtest-port.h +++ b/utils/unittest/googletest/include/gtest/internal/gtest-port.h @@ -403,7 +403,8 @@ // defining __GNUC__ and friends, but cannot compile GCC's tuple // implementation. MSVC 2008 (9.0) provides TR1 tuple in a 323 MB // Feature Pack download, which we cannot assume the user has. -#if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000)) \ +#if (defined(__GNUC__) && !(defined(__CUDACC__) || defined(__clang__)) \ + && (GTEST_GCC_VER_ >= 40000)) \ || _MSC_VER >= 1600 #define GTEST_USE_OWN_TR1_TUPLE 0 #else diff --git a/utils/valgrind/x86_64-pc-linux-gnu.supp b/utils/valgrind/x86_64-pc-linux-gnu.supp index f5aae990f697..7b2dd4517daf 100644 --- a/utils/valgrind/x86_64-pc-linux-gnu.supp +++ b/utils/valgrind/x86_64-pc-linux-gnu.supp @@ -11,19 +11,19 @@ { ADDRESS_IN_RANGE/Invalid read of size 4 Memcheck:Addr4 - obj:/usr/bin/python2.5 + obj:/usr/bin/python* } { ADDRESS_IN_RANGE/Invalid read of size 4 Memcheck:Value8 - obj:/usr/bin/python2.5 + obj:/usr/bin/python* } { ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value Memcheck:Cond - obj:/usr/bin/python2.5 + obj:/usr/bin/python* } { @@ -42,5 +42,5 @@ We don't care if python leaks Memcheck:Leak fun:malloc - obj:/usr/bin/python2.5 + obj:/usr/bin/python* } diff --git a/utils/vim/llvm.vim b/utils/vim/llvm.vim index acebc20bc344..83e4c232dbe5 100644 --- a/utils/vim/llvm.vim +++ b/utils/vim/llvm.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: llvm " Maintainer: The LLVM team, http://llvm.org/ -" Version: $Revision: 112382 $ +" Version: $Revision: 114788 $ if version < 600 syntax clear @@ -49,6 +49,7 @@ syn keyword llvmKeyword hidden protected default syn keyword llvmKeyword except deplibs syn keyword llvmKeyword volatile fastcc coldcc cc ccc syn keyword llvmKeyword x86_stdcallcc x86_fastcallcc +syn keyword llvmKeyword ptx_kernel ptx_device syn keyword llvmKeyword signext zeroext inreg sret nounwind noreturn syn keyword llvmKeyword nocapture byval nest readnone readonly noalias syn keyword llvmKeyword inlinehint noinline alwaysinline optsize ssp sspreq diff --git a/utils/vim/vimrc b/utils/vim/vimrc index 1f314c2e3f37..3f863d64bc49 100644 --- a/utils/vim/vimrc +++ b/utils/vim/vimrc @@ -1,5 +1,5 @@ " LLVM coding guidelines conformance for VIM -" $Revision: 112982 $ +" $Revision: 117415 $ " " Maintainer: The LLVM Team, http://llvm.org " WARNING: Read before you source in all these commands and macros! Some @@ -92,7 +92,7 @@ augroup END "set incsearch "set ruler -" Clang code-completion support. This is highly experimental! +" Clang code-completion support. This is somewhat experimental! " A path to a clang executable. let g:clang_path = "clang++" @@ -216,5 +216,6 @@ function! ClangComplete(findstart, base) return [] endfunction ClangComplete -" Uncomment this to enable the highly-broken autocompletion support. -"set omnifunc=ClangComplete +" This to enables the somewhat-experimental clang-based +" autocompletion support. +set omnifunc=ClangComplete -- cgit v1.3