[llvm] r210280 - Add a new attribute called 'jumptable' that creates jump-instruction tables for functions marked with this attribute.
Alp Toker
alp at nuanti.com
Sat Jun 7 13:47:57 PDT 2014
On 07/06/2014 23:00, Alp Toker wrote:
> Hi,
>
> I think this commit broke the shared build (CMake):
>
> Undefined symbols for architecture x86_64:
> "llvm::initializeJumpInstrTablesPass(llvm::PassRegistry&)",
> referenced from:
> llvm::LTOCodeGenerator::initializeLTOPasses() in
> LTOCodeGenerator.cpp.o
> ld: symbol(s) not found for architecture x86_64
> clang: error: linker command failed with exit code 1 (use -v to see
> invocation)
>
> Locally we've worked around the problem with the following patch:
>
> --- a/lib/LTO/LLVMBuild.txt
> +++ b/lib/LTO/LLVMBuild.txt
> @@ -19,4 +19,4 @@
> type = Library
> name = LTO
> parent = Libraries
> -required_libraries = BitReader BitWriter Core IPA IPO InstCombine
> Linker MC MCParser ObjCARC Scalar Support Target TransformUtils
> +required_libraries = BitReader BitWriter CodeGen Core IPA IPO
> InstCombine Linker MC MCParser ObjCARC Scalar Support Target
> TransformUtils
>
> However it doesn't seem right to incur a dependency on CodeGen from LTO.
>
> Another option would be to remove initializeJumpInstrTablesPass from
> lib/LTO/LTOCodeGenerator.cpp.
I've checked in build fix r210400 and all tests are passing now. Please
review when you get a chance.
Alp.
>
> I don't know the details of your pass so I can't advise further.
> Please investigate
>
> Regards,
> Alp.
>
>
> On 05/06/2014 22:29, Tom Roeder wrote:
>> Author: tmroeder
>> Date: Thu Jun 5 14:29:43 2014
>> New Revision: 210280
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=210280&view=rev
>> Log:
>> Add a new attribute called 'jumptable' that creates jump-instruction
>> tables for functions marked with this attribute.
>> It includes a pass that rewrites all indirect calls to jumptable
>> functions to pass through these tables.
>>
>> This also adds backend support for generating the jump-instruction
>> tables on ARM and X86.
>> Note that since the jumptable attribute creates a second function
>> pointer for a
>> function, any function marked with jumptable must also be marked with
>> unnamed_addr.
>>
>> Added:
>> llvm/trunk/include/llvm/Analysis/JumpInstrTableInfo.h
>> llvm/trunk/include/llvm/CodeGen/JumpInstrTables.h
>> llvm/trunk/lib/Analysis/JumpInstrTableInfo.cpp
>> llvm/trunk/lib/CodeGen/JumpInstrTables.cpp
>> llvm/trunk/test/CodeGen/ARM/jump_tables.ll
>> llvm/trunk/test/CodeGen/X86/jump_table_alias.ll
>> llvm/trunk/test/CodeGen/X86/jump_table_bitcast.ll
>> llvm/trunk/test/CodeGen/X86/jump_tables.ll
>> llvm/trunk/test/Verifier/jumptable.ll
>> Modified:
>> llvm/trunk/docs/LangRef.rst
>> llvm/trunk/include/llvm-c/Core.h
>> llvm/trunk/include/llvm/Analysis/Passes.h
>> llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h
>> llvm/trunk/include/llvm/CodeGen/CommandFlags.h
>> llvm/trunk/include/llvm/CodeGen/Passes.h
>> llvm/trunk/include/llvm/IR/Attributes.h
>> llvm/trunk/include/llvm/InitializePasses.h
>> llvm/trunk/include/llvm/LinkAllPasses.h
>> llvm/trunk/include/llvm/Target/TargetInstrInfo.h
>> llvm/trunk/include/llvm/Target/TargetOptions.h
>> llvm/trunk/lib/Analysis/Analysis.cpp
>> llvm/trunk/lib/Analysis/CMakeLists.txt
>> llvm/trunk/lib/AsmParser/LLLexer.cpp
>> llvm/trunk/lib/AsmParser/LLParser.cpp
>> llvm/trunk/lib/AsmParser/LLToken.h
>> llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
>> llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
>> llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
>> llvm/trunk/lib/CodeGen/CMakeLists.txt
>> llvm/trunk/lib/CodeGen/LLVMTargetMachine.cpp
>> llvm/trunk/lib/IR/Attributes.cpp
>> llvm/trunk/lib/IR/Verifier.cpp
>> llvm/trunk/lib/LTO/LTOCodeGenerator.cpp
>> llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp
>> llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.h
>> llvm/trunk/lib/Target/X86/X86InstrInfo.cpp
>> llvm/trunk/lib/Target/X86/X86InstrInfo.h
>> llvm/trunk/lib/Transforms/IPO/IPO.cpp
>> llvm/trunk/test/Bitcode/attributes.ll
>> llvm/trunk/test/CodeGen/Generic/stop-after.ll
>>
>> Modified: llvm/trunk/docs/LangRef.rst
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/LangRef.rst?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/docs/LangRef.rst (original)
>> +++ llvm/trunk/docs/LangRef.rst Thu Jun 5 14:29:43 2014
>> @@ -1020,6 +1020,14 @@ example:
>> inlining this function is desirable (such as the "inline"
>> keyword in
>> C/C++). It is just a hint; it imposes no requirements on the
>> inliner.
>> +``jumptable``
>> + This attribute indicates that the function should be added to a
>> + jump-instruction table at code-generation time, and that all
>> address-taken
>> + references to this function should be replaced with a reference
>> to the
>> + appropriate jump-instruction-table function pointer. Note that
>> this creates
>> + a new pointer for the original function, which means that code
>> that depends
>> + on function-pointer identity can break. So, any function
>> annotated with
>> + ``jumptable`` must also be ``unnamed_addr``.
>> ``minsize``
>> This attribute suggests that optimization passes and code
>> generator
>> passes make choices that keep the code size of this function as
>> small
>>
>> Modified: llvm/trunk/include/llvm-c/Core.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm-c/Core.h?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/include/llvm-c/Core.h (original)
>> +++ llvm/trunk/include/llvm-c/Core.h Thu Jun 5 14:29:43 2014
>> @@ -166,7 +166,8 @@ typedef enum {
>> LLVMCold = 1ULL << 34,
>> LLVMOptimizeNone = 1ULL << 35,
>> LLVMInAllocaAttribute = 1ULL << 36,
>> - LLVMNonNullAttribute = 1ULL << 37
>> + LLVMNonNullAttribute = 1ULL << 37,
>> + LLVMJumpTableAttribute = 1ULL << 38,
>> */
>> } LLVMAttribute;
>>
>> Added: llvm/trunk/include/llvm/Analysis/JumpInstrTableInfo.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/JumpInstrTableInfo.h?rev=210280&view=auto
>> ==============================================================================
>>
>> --- llvm/trunk/include/llvm/Analysis/JumpInstrTableInfo.h (added)
>> +++ llvm/trunk/include/llvm/Analysis/JumpInstrTableInfo.h Thu Jun 5
>> 14:29:43 2014
>> @@ -0,0 +1,60 @@
>> +//===-- JumpInstrTableInfo.h: Info for Jump-Instruction Tables --*-
>> C++ -*-===//
>> +//
>> +// This file is distributed under the University of Illinois Open
>> Source
>> +// License. See LICENSE.TXT for details.
>> +//
>> +//===----------------------------------------------------------------------===//
>>
>> +///
>> +/// \file
>> +/// \brief Information about jump-instruction tables that have been
>> created by
>> +/// JumpInstrTables pass.
>> +///
>> +//===----------------------------------------------------------------------===//
>>
>> +
>> +#ifndef LLVM_ANALYSIS_JUMPINSTRTABLEINFO_H
>> +#define LLVM_ANALYSIS_JUMPINSTRTABLEINFO_H
>> +
>> +#include "llvm/ADT/DenseMap.h"
>> +#include "llvm/Pass.h"
>> +
>> +#include <vector>
>> +
>> +namespace llvm {
>> +class Function;
>> +class FunctionType;
>> +
>> +/// This class stores information about jump-instruction tables
>> created by the
>> +/// JumpInstrTables pass (in lib/CodeGen/JumpInstrTables.cpp). Each
>> table is a
>> +/// map from a function type to a vector of pairs. The first element
>> of each
>> +/// pair is the function that has the jumptable annotation. The
>> second element
>> +/// is a function that was declared by JumpInstrTables and used to
>> replace all
>> +/// address-taking sites for the original function.
>> +///
>> +/// The information in this pass is used in AsmPrinter
>> +/// (lib/CodeGen/AsmPrinter/AsmPrinter.cpp) to generate the required
>> assembly
>> +/// for the jump-instruction tables.
>> +class JumpInstrTableInfo : public ImmutablePass {
>> +public:
>> + static char ID;
>> +
>> + JumpInstrTableInfo();
>> + virtual ~JumpInstrTableInfo();
>> + const char *getPassName() const override {
>> + return "Jump-Instruction Table Info";
>> + }
>> +
>> + typedef std::pair<Function *, Function *> JumpPair;
>> + typedef DenseMap<FunctionType *, std::vector<JumpPair> > JumpTables;
>> +
>> + /// Inserts an entry in a table, adding the table if it doesn't
>> exist.
>> + void insertEntry(FunctionType *TableFunTy, Function *Target,
>> Function *Jump);
>> +
>> + /// Gets the tables.
>> + const JumpTables &getTables() const { return Tables; }
>> +
>> +private:
>> + JumpTables Tables;
>> +};
>> +}
>> +
>> +#endif /* LLVM_ANALYSIS_JUMPINSTRTABLEINFO_H */
>>
>> Modified: llvm/trunk/include/llvm/Analysis/Passes.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/Passes.h?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/include/llvm/Analysis/Passes.h (original)
>> +++ llvm/trunk/include/llvm/Analysis/Passes.h Thu Jun 5 14:29:43 2014
>> @@ -142,6 +142,10 @@ namespace llvm {
>> // information and prints it with -analyze.
>> //
>> FunctionPass *createMemDepPrinter();
>> +
>> + // createJumpInstrTableInfoPass - This creates a pass that stores
>> information
>> + // about the jump tables created by JumpInstrTables
>> + ImmutablePass *createJumpInstrTableInfoPass();
>> }
>> #endif
>>
>> Modified: llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h (original)
>> +++ llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h Thu Jun 5
>> 14:29:43 2014
>> @@ -372,7 +372,8 @@ namespace bitc {
>> ATTR_KIND_COLD = 36,
>> ATTR_KIND_OPTIMIZE_NONE = 37,
>> ATTR_KIND_IN_ALLOCA = 38,
>> - ATTR_KIND_NON_NULL = 39
>> + ATTR_KIND_NON_NULL = 39,
>> + ATTR_KIND_JUMP_TABLE = 40
>> };
>> } // End bitc namespace
>>
>> Modified: llvm/trunk/include/llvm/CodeGen/CommandFlags.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/CommandFlags.h?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/include/llvm/CodeGen/CommandFlags.h (original)
>> +++ llvm/trunk/include/llvm/CodeGen/CommandFlags.h Thu Jun 5
>> 14:29:43 2014
>> @@ -202,6 +202,21 @@ FunctionSections("function-sections",
>> cl::desc("Emit functions into separate sections"),
>> cl::init(false));
>> +cl::opt<llvm::JumpTable::JumpTableType>
>> +JTableType("jump-table-type",
>> + cl::desc("Choose the type of Jump-Instruction Table for
>> jumptable."),
>> + cl::init(JumpTable::Single),
>> + cl::values(
>> + clEnumValN(JumpTable::Single, "single",
>> + "Create a single table for all jumptable
>> functions"),
>> + clEnumValN(JumpTable::Arity, "arity",
>> + "Create one table per number of parameters."),
>> + clEnumValN(JumpTable::Simplified, "simplified",
>> + "Create one table per simplified function
>> type."),
>> + clEnumValN(JumpTable::Full, "full",
>> + "Create one table per unique function type."),
>> + clEnumValEnd));
>> +
>> // Common utility function tightly tied to the options listed here.
>> Initializes
>> // a TargetOptions object with CodeGen flags and returns it.
>> static inline TargetOptions InitTargetOptionsFromCodeGenFlags() {
>> @@ -228,6 +243,7 @@ static inline TargetOptions InitTargetOp
>> Options.FunctionSections = FunctionSections;
>> Options.MCOptions = InitMCTargetOptionsFromFlags();
>> + Options.JTType = JTableType;
>> return Options;
>> }
>>
>> Added: llvm/trunk/include/llvm/CodeGen/JumpInstrTables.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/JumpInstrTables.h?rev=210280&view=auto
>> ==============================================================================
>>
>> --- llvm/trunk/include/llvm/CodeGen/JumpInstrTables.h (added)
>> +++ llvm/trunk/include/llvm/CodeGen/JumpInstrTables.h Thu Jun 5
>> 14:29:43 2014
>> @@ -0,0 +1,102 @@
>> +//===-- JumpInstrTables.h: Jump-Instruction Tables --------------*-
>> C++ -*-===//
>> +//
>> +// This file is distributed under the University of Illinois Open
>> Source
>> +// License. See LICENSE.TXT for details.
>> +//
>> +//===----------------------------------------------------------------------===//
>>
>> +///
>> +/// \file
>> +/// \brief An implementation of tables consisting of jump instructions
>> +///
>> +//===----------------------------------------------------------------------===//
>>
>> +
>> +#ifndef LLVM_CODEGEN_JUMPINSTRTABLES_H
>> +#define LLVM_CODEGEN_JUMPINSTRTABLES_H
>> +
>> +#include "llvm/ADT/DenseMap.h"
>> +#include "llvm/Pass.h"
>> +#include "llvm/Target/TargetOptions.h"
>> +
>> +namespace llvm {
>> +class Constant;
>> +class Function;
>> +class FunctionType;
>> +class JumpInstrTableInfo;
>> +class Module;
>> +
>> +/// A class to manage a set of jump tables indexed on function type.
>> It looks at
>> +/// each function in the module to find all the functions that have the
>> +/// jumptable attribute set. For each such function, it creates a new
>> +/// jump-instruction-table function and stores the mapping in the
>> ImmutablePass
>> +/// JumpInstrTableInfo.
>> +///
>> +/// These special functions get lowered in AsmPrinter to assembly of
>> the form:
>> +/// .globl f
>> +/// .type f, at function
>> +/// .align 8,0x90
>> +/// f:
>> +/// jmp f_orig at PLT
>> +///
>> +/// Support for an architecture depends on two functions in
>> TargetInstrInfo:
>> +/// getUnconditionalBranch, and getTrap. AsmPrinter uses these to
>> generate the
>> +/// appropriate instructions for the jump statement (an
>> unconditional branch)
>> +/// and for padding to make the table have a size that is a power of
>> two. This
>> +/// padding uses a trap instruction to ensure that calls to this
>> area halt the
>> +/// program. The default implementations of these functions call
>> +/// llvm_unreachable.
>> +class JumpInstrTables : public ModulePass {
>> +public:
>> + static char ID;
>> +
>> + JumpInstrTables();
>> + JumpInstrTables(JumpTable::JumpTableType JTT);
>> + virtual ~JumpInstrTables();
>> + bool runOnModule(Module &M) override;
>> + const char *getPassName() const override { return
>> "Jump-Instruction Tables"; }
>> + void getAnalysisUsage(AnalysisUsage &AU) const override;
>> +
>> + /// Creates a jump-instruction table function for the Target and
>> adds it to
>> + /// the tables.
>> + Function *insertEntry(Module &M, Function *Target);
>> +
>> + /// Checks to see if there is already a table for the given
>> FunctionType.
>> + bool hasTable(FunctionType *FunTy);
>> +
>> +private:
>> + /// The metadata used while a jump table is being built
>> + struct TableMeta {
>> + /// The number of this table
>> + unsigned TableNum;
>> +
>> + /// The current number of jump entries in the table.
>> + unsigned Count;
>> + };
>> +
>> + typedef DenseMap<FunctionType *, struct TableMeta> JumpMap;
>> +
>> + /// Maps the function into a subset of function types, depending
>> on the
>> + /// jump-instruction table style selected from JumpTableTypes in
>> + /// JumpInstrTables.cpp. The choice of mapping determines the
>> number of
>> + /// jump-instruction tables generated by this pass. E.g., the
>> simplest mapping
>> + /// converts every function type into void f(); so, all functions
>> end up in a
>> + /// single table.
>> + FunctionType *transformType(FunctionType *FunTy);
>> +
>> + /// The current state of functions and jump entries in the table(s).
>> + JumpMap Metadata;
>> +
>> + /// The ImmutablePass that stores information about the generated
>> tables.
>> + JumpInstrTableInfo *JITI;
>> +
>> + /// The total number of tables.
>> + unsigned TableCount;
>> +
>> + /// The type of tables to build.
>> + JumpTable::JumpTableType JTType;
>> +};
>> +
>> +/// Creates a JumpInstrTables pass for the given type of jump table.
>> +ModulePass *createJumpInstrTablesPass(JumpTable::JumpTableType JTT);
>> +}
>> +
>> +#endif /* LLVM_CODEGEN_JUMPINSTRTABLES_H */
>>
>> Modified: llvm/trunk/include/llvm/CodeGen/Passes.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/Passes.h?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/include/llvm/CodeGen/Passes.h (original)
>> +++ llvm/trunk/include/llvm/CodeGen/Passes.h Thu Jun 5 14:29:43 2014
>> @@ -588,6 +588,8 @@ namespace llvm {
>> /// the intrinsic for later emission to the StackMap.
>> extern char &StackMapLivenessID;
>> + /// createJumpInstrTables - This pass creates jump-instruction
>> tables.
>> + ModulePass *createJumpInstrTablesPass();
>> } // End llvm namespace
>> #endif
>>
>> Modified: llvm/trunk/include/llvm/IR/Attributes.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Attributes.h?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/include/llvm/IR/Attributes.h (original)
>> +++ llvm/trunk/include/llvm/IR/Attributes.h Thu Jun 5 14:29:43 2014
>> @@ -75,6 +75,7 @@ public:
>> Cold, ///< Marks function as being in a cold
>> path.
>> InlineHint, ///< Source said inlining was desirable
>> InReg, ///< Force argument to be passed in
>> register
>> + JumpTable, ///< Build jump-instruction tables and
>> replace refs.
>> MinSize, ///< Function must be optimized for size
>> first
>> Naked, ///< Naked function
>> Nest, ///< Nested function static chain
>>
>> Modified: llvm/trunk/include/llvm/InitializePasses.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/InitializePasses.h?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/include/llvm/InitializePasses.h (original)
>> +++ llvm/trunk/include/llvm/InitializePasses.h Thu Jun 5 14:29:43 2014
>> @@ -146,6 +146,8 @@ void initializeInstCountPass(PassRegistr
>> void initializeInstNamerPass(PassRegistry&);
>> void initializeInternalizePassPass(PassRegistry&);
>> void initializeIntervalPartitionPass(PassRegistry&);
>> +void initializeJumpInstrTableInfoPass(PassRegistry&);
>> +void initializeJumpInstrTablesPass(PassRegistry&);
>> void initializeJumpThreadingPass(PassRegistry&);
>> void initializeLCSSAPass(PassRegistry&);
>> void initializeLICMPass(PassRegistry&);
>>
>> Modified: llvm/trunk/include/llvm/LinkAllPasses.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/LinkAllPasses.h?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/include/llvm/LinkAllPasses.h (original)
>> +++ llvm/trunk/include/llvm/LinkAllPasses.h Thu Jun 5 14:29:43 2014
>> @@ -85,6 +85,8 @@ namespace {
>> (void) llvm::createIndVarSimplifyPass();
>> (void) llvm::createInstructionCombiningPass();
>> (void) llvm::createInternalizePass();
>> + (void) llvm::createJumpInstrTableInfoPass();
>> + (void) llvm::createJumpInstrTablesPass();
>> (void) llvm::createLCSSAPass();
>> (void) llvm::createLICMPass();
>> (void) llvm::createLazyValueInfoPass();
>>
>> Modified: llvm/trunk/include/llvm/Target/TargetInstrInfo.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/TargetInstrInfo.h?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/include/llvm/Target/TargetInstrInfo.h (original)
>> +++ llvm/trunk/include/llvm/Target/TargetInstrInfo.h Thu Jun 5
>> 14:29:43 2014
>> @@ -29,6 +29,7 @@ class MachineRegisterInfo;
>> class MDNode;
>> class MCInst;
>> class MCSchedModel;
>> +class MCSymbolRefExpr;
>> class SDNode;
>> class ScheduleHazardRecognizer;
>> class SelectionDAG;
>> @@ -321,6 +322,20 @@ public:
>> virtual void ReplaceTailWithBranchTo(MachineBasicBlock::iterator
>> Tail,
>> MachineBasicBlock *NewDest)
>> const;
>> + /// getUnconditionalBranch - Get an instruction that performs an
>> unconditional
>> + /// branch to the given symbol.
>> + virtual void
>> + getUnconditionalBranch(MCInst &MI,
>> + const MCSymbolRefExpr *BranchTarget) const {
>> + llvm_unreachable("Target didn't implement "
>> + "TargetInstrInfo::getUnconditionalBranch!");
>> + }
>> +
>> + /// getTrap - Get a machine trap instruction
>> + virtual void getTrap(MCInst &MI) const {
>> + llvm_unreachable("Target didn't implement
>> TargetInstrInfo::getTrap!");
>> + }
>> +
>> /// isLegalToSplitMBBAt - Return true if it's legal to split the
>> given basic
>> /// block at the specified instruction (i.e. instruction would be
>> the start
>> /// of a new basic block).
>>
>> Modified: llvm/trunk/include/llvm/Target/TargetOptions.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Target/TargetOptions.h?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/include/llvm/Target/TargetOptions.h (original)
>> +++ llvm/trunk/include/llvm/Target/TargetOptions.h Thu Jun 5
>> 14:29:43 2014
>> @@ -39,6 +39,17 @@ namespace llvm {
>> };
>> }
>> + namespace JumpTable {
>> + enum JumpTableType {
>> + Single, // Use a single table for all indirect
>> jumptable calls.
>> + Arity, // Use one table per number of function
>> parameters.
>> + Simplified, // Use one table per function type, with
>> types projected
>> + // into 4 types: pointer to non-function,
>> struct,
>> + // primitive, and function pointer.
>> + Full // Use one table per unique function type
>> + };
>> + }
>> +
>> class TargetOptions {
>> public:
>> TargetOptions()
>> @@ -54,7 +65,7 @@ namespace llvm {
>> CompressDebugSections(false), FunctionSections(false),
>> DataSections(false), TrapUnreachable(false),
>> TrapFuncName(""),
>> FloatABIType(FloatABI::Default),
>> - AllowFPOpFusion(FPOpFusion::Standard) {}
>> + AllowFPOpFusion(FPOpFusion::Standard),
>> JTType(JumpTable::Single) {}
>> /// PrintMachineCode - This flag is enabled when the
>> -print-machineinstrs
>> /// option is specified on the command line, and should enable
>> debugging
>> @@ -205,6 +216,10 @@ namespace llvm {
>> /// the value of this option.
>> FPOpFusion::FPOpFusionMode AllowFPOpFusion;
>> + /// JTType - This flag specifies the type of jump-instruction
>> table to
>> + /// create for functions that have the jumptable attribute.
>> + JumpTable::JumpTableType JTType;
>> +
>> /// Machine level options.
>> MCTargetOptions MCOptions;
>> };
>>
>> Modified: llvm/trunk/lib/Analysis/Analysis.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/Analysis.cpp?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/lib/Analysis/Analysis.cpp (original)
>> +++ llvm/trunk/lib/Analysis/Analysis.cpp Thu Jun 5 14:29:43 2014
>> @@ -48,6 +48,7 @@ void llvm::initializeAnalysis(PassRegist
>> initializeIVUsersPass(Registry);
>> initializeInstCountPass(Registry);
>> initializeIntervalPartitionPass(Registry);
>> + initializeJumpInstrTableInfoPass(Registry);
>> initializeLazyValueInfoPass(Registry);
>> initializeLibCallAliasAnalysisPass(Registry);
>> initializeLintPass(Registry);
>>
>> Modified: llvm/trunk/lib/Analysis/CMakeLists.txt
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/CMakeLists.txt?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/lib/Analysis/CMakeLists.txt (original)
>> +++ llvm/trunk/lib/Analysis/CMakeLists.txt Thu Jun 5 14:29:43 2014
>> @@ -25,6 +25,7 @@ add_llvm_library(LLVMAnalysis
>> InstructionSimplify.cpp
>> Interval.cpp
>> IntervalPartition.cpp
>> + JumpInstrTableInfo.cpp
>> LazyCallGraph.cpp
>> LazyValueInfo.cpp
>> LibCallAliasAnalysis.cpp
>>
>> Added: llvm/trunk/lib/Analysis/JumpInstrTableInfo.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/JumpInstrTableInfo.cpp?rev=210280&view=auto
>> ==============================================================================
>>
>> --- llvm/trunk/lib/Analysis/JumpInstrTableInfo.cpp (added)
>> +++ llvm/trunk/lib/Analysis/JumpInstrTableInfo.cpp Thu Jun 5
>> 14:29:43 2014
>> @@ -0,0 +1,40 @@
>> +//===-- JumpInstrTableInfo.cpp: Info for Jump-Instruction Tables
>> ----------===//
>> +//
>> +// This file is distributed under the University of Illinois Open
>> Source
>> +// License. See LICENSE.TXT for details.
>> +//
>> +//===----------------------------------------------------------------------===//
>>
>> +///
>> +/// \file
>> +/// \brief Information about jump-instruction tables that have been
>> created by
>> +/// JumpInstrTables pass.
>> +///
>> +//===----------------------------------------------------------------------===//
>>
>> +
>> +#define DEBUG_TYPE "jiti"
>> +
>> +#include "llvm/Analysis/JumpInstrTableInfo.h"
>> +#include "llvm/Analysis/Passes.h"
>> +#include "llvm/IR/Function.h"
>> +#include "llvm/IR/Type.h"
>> +
>> +using namespace llvm;
>> +
>> +INITIALIZE_PASS(JumpInstrTableInfo, "jump-instr-table-info",
>> + "Jump-Instruction Table Info", true, true)
>> +char JumpInstrTableInfo::ID = 0;
>> +
>> +ImmutablePass *llvm::createJumpInstrTableInfoPass() {
>> + return new JumpInstrTableInfo();
>> +}
>> +
>> +JumpInstrTableInfo::JumpInstrTableInfo() : ImmutablePass(ID),
>> Tables() {
>> + initializeJumpInstrTableInfoPass(*PassRegistry::getPassRegistry());
>> +}
>> +
>> +JumpInstrTableInfo::~JumpInstrTableInfo() {}
>> +
>> +void JumpInstrTableInfo::insertEntry(FunctionType *TableFunTy,
>> Function *Target,
>> + Function *Jump) {
>> + Tables[TableFunTy].push_back(JumpPair(Target, Jump));
>> +}
>>
>> Modified: llvm/trunk/lib/AsmParser/LLLexer.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLLexer.cpp?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/lib/AsmParser/LLLexer.cpp (original)
>> +++ llvm/trunk/lib/AsmParser/LLLexer.cpp Thu Jun 5 14:29:43 2014
>> @@ -583,6 +583,7 @@ lltok::Kind LLLexer::LexIdentifier() {
>> KEYWORD(cold);
>> KEYWORD(inlinehint);
>> KEYWORD(inreg);
>> + KEYWORD(jumptable);
>> KEYWORD(minsize);
>> KEYWORD(naked);
>> KEYWORD(nest);
>>
>> Modified: llvm/trunk/lib/AsmParser/LLParser.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLParser.cpp?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/lib/AsmParser/LLParser.cpp (original)
>> +++ llvm/trunk/lib/AsmParser/LLParser.cpp Thu Jun 5 14:29:43 2014
>> @@ -947,6 +947,7 @@ bool LLParser::ParseFnAttributeValuePair
>> case lltok::kw_builtin: B.addAttribute(Attribute::Builtin); break;
>> case lltok::kw_cold: B.addAttribute(Attribute::Cold); break;
>> case lltok::kw_inlinehint:
>> B.addAttribute(Attribute::InlineHint); break;
>> + case lltok::kw_jumptable: B.addAttribute(Attribute::JumpTable);
>> break;
>> case lltok::kw_minsize: B.addAttribute(Attribute::MinSize); break;
>> case lltok::kw_naked: B.addAttribute(Attribute::Naked); break;
>> case lltok::kw_nobuiltin: B.addAttribute(Attribute::NoBuiltin);
>> break;
>> @@ -1210,6 +1211,7 @@ bool LLParser::ParseOptionalParamAttrs(A
>> case lltok::kw_alwaysinline:
>> case lltok::kw_builtin:
>> case lltok::kw_inlinehint:
>> + case lltok::kw_jumptable:
>> case lltok::kw_minsize:
>> case lltok::kw_naked:
>> case lltok::kw_nobuiltin:
>> @@ -1271,6 +1273,7 @@ bool LLParser::ParseOptionalReturnAttrs(
>> case lltok::kw_builtin:
>> case lltok::kw_cold:
>> case lltok::kw_inlinehint:
>> + case lltok::kw_jumptable:
>> case lltok::kw_minsize:
>> case lltok::kw_naked:
>> case lltok::kw_nobuiltin:
>>
>> Modified: llvm/trunk/lib/AsmParser/LLToken.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLToken.h?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/lib/AsmParser/LLToken.h (original)
>> +++ llvm/trunk/lib/AsmParser/LLToken.h Thu Jun 5 14:29:43 2014
>> @@ -107,6 +107,7 @@ namespace lltok {
>> kw_cold,
>> kw_inlinehint,
>> kw_inreg,
>> + kw_jumptable,
>> kw_minsize,
>> kw_naked,
>> kw_nest,
>>
>> Modified: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp (original)
>> +++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp Thu Jun 5
>> 14:29:43 2014
>> @@ -549,6 +549,8 @@ static Attribute::AttrKind GetAttrFromCo
>> return Attribute::InlineHint;
>> case bitc::ATTR_KIND_IN_REG:
>> return Attribute::InReg;
>> + case bitc::ATTR_KIND_JUMP_TABLE:
>> + return Attribute::JumpTable;
>> case bitc::ATTR_KIND_MIN_SIZE:
>> return Attribute::MinSize;
>> case bitc::ATTR_KIND_NAKED:
>>
>> Modified: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp (original)
>> +++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp Thu Jun 5
>> 14:29:43 2014
>> @@ -177,6 +177,8 @@ static uint64_t getAttrKindEncoding(Attr
>> return bitc::ATTR_KIND_INLINE_HINT;
>> case Attribute::InReg:
>> return bitc::ATTR_KIND_IN_REG;
>> + case Attribute::JumpTable:
>> + return bitc::ATTR_KIND_JUMP_TABLE;
>> case Attribute::MinSize:
>> return bitc::ATTR_KIND_MIN_SIZE;
>> case Attribute::Naked:
>>
>> Modified: llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (original)
>> +++ llvm/trunk/lib/CodeGen/AsmPrinter/AsmPrinter.cpp Thu Jun 5
>> 14:29:43 2014
>> @@ -18,6 +18,7 @@
>> #include "llvm/ADT/SmallString.h"
>> #include "llvm/ADT/Statistic.h"
>> #include "llvm/Analysis/ConstantFolding.h"
>> +#include "llvm/Analysis/JumpInstrTableInfo.h"
>> #include "llvm/CodeGen/GCMetadataPrinter.h"
>> #include "llvm/CodeGen/MachineConstantPool.h"
>> #include "llvm/CodeGen/MachineFrameInfo.h"
>> @@ -889,6 +890,54 @@ bool AsmPrinter::doFinalization(Module &
>> EmitVisibility(Name, V, false);
>> }
>> + // Get information about jump-instruction tables to print.
>> + JumpInstrTableInfo *JITI =
>> getAnalysisIfAvailable<JumpInstrTableInfo>();
>> +
>> + if (JITI && !JITI->getTables().empty()) {
>> + unsigned Arch = Triple(getTargetTriple()).getArch();
>> + bool IsThumb = (Arch == Triple::thumb || Arch == Triple::thumbeb);
>> + MCInst TrapInst;
>> + TM.getInstrInfo()->getTrap(TrapInst);
>> + for (const auto &KV : JITI->getTables()) {
>> + uint64_t Count = 0;
>> + for (const auto &FunPair : KV.second) {
>> + // Emit the function labels to make this be a function entry
>> point.
>> + MCSymbol *FunSym =
>> + OutContext.GetOrCreateSymbol(FunPair.second->getName());
>> + OutStreamer.EmitSymbolAttribute(FunSym, MCSA_Global);
>> + // FIXME: JumpTableInstrInfo should store information about
>> the required
>> + // alignment of table entries and the size of the padding
>> instruction.
>> + EmitAlignment(3);
>> + if (IsThumb)
>> + OutStreamer.EmitThumbFunc(FunSym);
>> + if (MAI->hasDotTypeDotSizeDirective())
>> + OutStreamer.EmitSymbolAttribute(FunSym,
>> MCSA_ELF_TypeFunction);
>> + OutStreamer.EmitLabel(FunSym);
>> +
>> + // Emit the jump instruction to transfer control to the
>> original
>> + // function.
>> + MCInst JumpToFun;
>> + MCSymbol *TargetSymbol =
>> + OutContext.GetOrCreateSymbol(FunPair.first->getName());
>> + const MCSymbolRefExpr *TargetSymRef =
>> + MCSymbolRefExpr::Create(TargetSymbol,
>> MCSymbolRefExpr::VK_PLT,
>> + OutContext);
>> + TM.getInstrInfo()->getUnconditionalBranch(JumpToFun,
>> TargetSymRef);
>> + OutStreamer.EmitInstruction(JumpToFun, getSubtargetInfo());
>> + ++Count;
>> + }
>> +
>> + // Emit enough padding instructions to fill up to the next
>> power of two.
>> + // This assumes that the trap instruction takes 8 bytes or fewer.
>> + uint64_t Remaining = NextPowerOf2(Count) - Count;
>> + for (uint64_t C = 0; C < Remaining; ++C) {
>> + EmitAlignment(3);
>> + OutStreamer.EmitInstruction(TrapInst, getSubtargetInfo());
>> + }
>> +
>> + }
>> + }
>> +
>> // Emit module flags.
>> SmallVector<Module::ModuleFlagEntry, 8> ModuleFlags;
>> M.getModuleFlagsMetadata(ModuleFlags);
>>
>> Modified: llvm/trunk/lib/CodeGen/CMakeLists.txt
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/CMakeLists.txt?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/lib/CodeGen/CMakeLists.txt (original)
>> +++ llvm/trunk/lib/CodeGen/CMakeLists.txt Thu Jun 5 14:29:43 2014
>> @@ -27,6 +27,7 @@ add_llvm_library(LLVMCodeGen
>> InterferenceCache.cpp
>> IntrinsicLowering.cpp
>> JITCodeEmitter.cpp
>> + JumpInstrTables.cpp
>> LLVMTargetMachine.cpp
>> LatencyPriorityQueue.cpp
>> LexicalScopes.cpp
>>
>> Added: llvm/trunk/lib/CodeGen/JumpInstrTables.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/JumpInstrTables.cpp?rev=210280&view=auto
>> ==============================================================================
>>
>> --- llvm/trunk/lib/CodeGen/JumpInstrTables.cpp (added)
>> +++ llvm/trunk/lib/CodeGen/JumpInstrTables.cpp Thu Jun 5 14:29:43 2014
>> @@ -0,0 +1,301 @@
>> +//===-- JumpInstrTables.cpp: Jump-Instruction Tables
>> ----------------------===//
>> +//
>> +// This file is distributed under the University of Illinois Open
>> Source
>> +// License. See LICENSE.TXT for details.
>> +//
>> +//===----------------------------------------------------------------------===//
>>
>> +///
>> +/// \file
>> +/// \brief An implementation of jump-instruction tables.
>> +///
>> +//===----------------------------------------------------------------------===//
>>
>> +
>> +#define DEBUG_TYPE "jt"
>> +
>> +#include "llvm/CodeGen/JumpInstrTables.h"
>> +
>> +#include "llvm/ADT/Statistic.h"
>> +#include "llvm/Analysis/JumpInstrTableInfo.h"
>> +#include "llvm/CodeGen/Passes.h"
>> +#include "llvm/IR/Attributes.h"
>> +#include "llvm/IR/CallSite.h"
>> +#include "llvm/IR/Constants.h"
>> +#include "llvm/IR/DerivedTypes.h"
>> +#include "llvm/IR/Function.h"
>> +#include "llvm/IR/LLVMContext.h"
>> +#include "llvm/IR/Module.h"
>> +#include "llvm/IR/Operator.h"
>> +#include "llvm/IR/Type.h"
>> +#include "llvm/IR/Verifier.h"
>> +#include "llvm/Support/CommandLine.h"
>> +#include "llvm/Support/Debug.h"
>> +#include "llvm/Support/raw_ostream.h"
>> +
>> +#include <vector>
>> +
>> +using namespace llvm;
>> +
>> +char JumpInstrTables::ID = 0;
>> +
>> +INITIALIZE_PASS_BEGIN(JumpInstrTables, "jump-instr-tables",
>> + "Jump-Instruction Tables", true, true)
>> +INITIALIZE_PASS_DEPENDENCY(JumpInstrTableInfo);
>> +INITIALIZE_PASS_END(JumpInstrTables, "jump-instr-tables",
>> + "Jump-Instruction Tables", true, true)
>> +
>> +STATISTIC(NumJumpTables, "Number of indirect call tables generated");
>> +STATISTIC(NumFuncsInJumpTables, "Number of functions in the jump
>> tables");
>> +
>> +ModulePass *llvm::createJumpInstrTablesPass() {
>> + // The default implementation uses a single table for all functions.
>> + return new JumpInstrTables(JumpTable::Single);
>> +}
>> +
>> +ModulePass *llvm::createJumpInstrTablesPass(JumpTable::JumpTableType
>> JTT) {
>> + return new JumpInstrTables(JTT);
>> +}
>> +
>> +namespace {
>> +static const char jump_func_prefix[] = "__llvm_jump_instr_table_";
>> +static const char jump_section_prefix[] = ".jump.instr.table.text.";
>> +
>> +// Checks to see if a given CallSite is making an indirect call,
>> including
>> +// cases where the indirect call is made through a bitcast.
>> +bool isIndirectCall(CallSite &CS) {
>> + if (CS.getCalledFunction())
>> + return false;
>> +
>> + // Check the value to see if it is merely a bitcast of a function. In
>> + // this case, it will translate to a direct function call in the
>> resulting
>> + // assembly, so we won't treat it as an indirect call here.
>> + const Value *V = CS.getCalledValue();
>> + if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(V)) {
>> + return !(CE->isCast() && isa<Function>(CE->getOperand(0)));
>> + }
>> +
>> + // Otherwise, since we know it's a call, it must be an indirect call
>> + return true;
>> +}
>> +
>> +// Replaces Functions and GlobalAliases with a different Value.
>> +bool replaceGlobalValueIndirectUse(GlobalValue *GV, Value *V, Use *U) {
>> + User *Us = U->getUser();
>> + if (!Us)
>> + return false;
>> + if (Instruction *I = dyn_cast<Instruction>(Us)) {
>> + CallSite CS(I);
>> +
>> + // Don't do the replacement if this use is a direct call to this
>> function.
>> + // If the use is not the called value, then replace it.
>> + if (CS && (isIndirectCall(CS) || CS.isCallee(U))) {
>> + return false;
>> + }
>> +
>> + U->set(V);
>> + } else if (Constant *C = dyn_cast<Constant>(Us)) {
>> + // Don't replace calls to bitcasts of function symbols, since
>> they get
>> + // translated to direct calls.
>> + if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Us)) {
>> + if (CE->getOpcode() == Instruction::BitCast) {
>> + // This bitcast must have exactly one user.
>> + if (CE->user_begin() != CE->user_end()) {
>> + User *ParentUs = *CE->user_begin();
>> + if (CallInst *CI = dyn_cast<CallInst>(ParentUs)) {
>> + CallSite CS(CI);
>> + Use &CEU = *CE->use_begin();
>> + if (CS.isCallee(&CEU)) {
>> + return false;
>> + }
>> + }
>> + }
>> + }
>> + }
>> +
>> + // GlobalAlias doesn't support replaceUsesOfWithOnConstant. And
>> the verifier
>> + // requires alias to point to a defined function. So,
>> GlobalAlias is handled
>> + // as a separate case in runOnModule.
>> + if (!isa<GlobalAlias>(C))
>> + C->replaceUsesOfWithOnConstant(GV, V, U);
>> + } else {
>> + assert(false && "The Use of a Function symbol is neither an
>> instruction nor"
>> + " a constant");
>> + }
>> +
>> + return true;
>> +}
>> +
>> +// Replaces all replaceable address-taken uses of GV with a pointer
>> to a
>> +// jump-instruction table entry.
>> +void replaceValueWithFunction(GlobalValue *GV, Function *F) {
>> + // Go through all uses of this function and replace the uses of GV
>> with the
>> + // jump-table version of the function. Get the uses as a vector
>> before
>> + // replacing them, since replacing them changes the use list and
>> invalidates
>> + // the iterator otherwise.
>> + for (Value::use_iterator I = GV->use_begin(), E = GV->use_end(); I
>> != E;) {
>> + Use &U = *I++;
>> +
>> + // Replacement of constants replaces all instances in the
>> constant. So, some
>> + // uses might have already been handled by the time we reach
>> them here.
>> + if (U.get() == GV)
>> + replaceGlobalValueIndirectUse(GV, F, &U);
>> + }
>> +
>> + return;
>> +}
>> +} // end anonymous namespace
>> +
>> +JumpInstrTables::JumpInstrTables()
>> + : ModulePass(ID), Metadata(), JITI(nullptr), TableCount(0),
>> + JTType(JumpTable::Single) {
>> + initializeJumpInstrTablesPass(*PassRegistry::getPassRegistry());
>> +}
>> +
>> +JumpInstrTables::JumpInstrTables(JumpTable::JumpTableType JTT)
>> + : ModulePass(ID), Metadata(), JITI(nullptr), TableCount(0),
>> JTType(JTT) {
>> + initializeJumpInstrTablesPass(*PassRegistry::getPassRegistry());
>> +}
>> +
>> +JumpInstrTables::~JumpInstrTables() {}
>> +
>> +void JumpInstrTables::getAnalysisUsage(AnalysisUsage &AU) const {
>> + AU.addRequired<JumpInstrTableInfo>();
>> +}
>> +
>> +Function *JumpInstrTables::insertEntry(Module &M, Function *Target) {
>> + FunctionType *OrigFunTy = Target->getFunctionType();
>> + FunctionType *FunTy = transformType(OrigFunTy);
>> +
>> + JumpMap::iterator it = Metadata.find(FunTy);
>> + if (Metadata.end() == it) {
>> + struct TableMeta Meta;
>> + Meta.TableNum = TableCount;
>> + Meta.Count = 0;
>> + Metadata[FunTy] = Meta;
>> + it = Metadata.find(FunTy);
>> + ++NumJumpTables;
>> + ++TableCount;
>> + }
>> +
>> + it->second.Count++;
>> +
>> + std::string NewName(jump_func_prefix);
>> + NewName += (Twine(it->second.TableNum) + "_" +
>> Twine(it->second.Count)).str();
>> + Function *JumpFun =
>> + Function::Create(OrigFunTy, GlobalValue::ExternalLinkage,
>> NewName, &M);
>> + // The section for this table
>> + JumpFun->setSection((jump_section_prefix +
>> Twine(it->second.TableNum)).str());
>> + JITI->insertEntry(FunTy, Target, JumpFun);
>> +
>> + ++NumFuncsInJumpTables;
>> + return JumpFun;
>> +}
>> +
>> +bool JumpInstrTables::hasTable(FunctionType *FunTy) {
>> + FunctionType *TransTy = transformType(FunTy);
>> + return Metadata.end() != Metadata.find(TransTy);
>> +}
>> +
>> +FunctionType *JumpInstrTables::transformType(FunctionType *FunTy) {
>> + // Returning nullptr forces all types into the same table, since
>> all types map
>> + // to the same type
>> + Type *VoidPtrTy = Type::getInt8PtrTy(FunTy->getContext());
>> +
>> + // Ignore the return type.
>> + Type *RetTy = VoidPtrTy;
>> + bool IsVarArg = FunTy->isVarArg();
>> + std::vector<Type *> ParamTys(FunTy->getNumParams());
>> + FunctionType::param_iterator PI, PE;
>> + int i = 0;
>> +
>> + std::vector<Type *> EmptyParams;
>> + Type *Int32Ty = Type::getInt32Ty(FunTy->getContext());
>> + FunctionType *VoidFnTy = FunctionType::get(
>> + Type::getVoidTy(FunTy->getContext()), EmptyParams, false);
>> + switch (JTType) {
>> + case JumpTable::Single:
>> +
>> + return FunctionType::get(RetTy, EmptyParams, false);
>> + case JumpTable::Arity:
>> + // Transform all types to void* so that all functions with the
>> same arity
>> + // end up in the same table.
>> + for (PI = FunTy->param_begin(), PE = FunTy->param_end(); PI != PE;
>> + PI++, i++) {
>> + ParamTys[i] = VoidPtrTy;
>> + }
>> +
>> + return FunctionType::get(RetTy, ParamTys, IsVarArg);
>> + case JumpTable::Simplified:
>> + // Project all parameters types to one of 3 types: composite,
>> integer, and
>> + // function, matching the three subclasses of Type.
>> + for (PI = FunTy->param_begin(), PE = FunTy->param_end(); PI != PE;
>> + ++PI, ++i) {
>> + assert((isa<IntegerType>(*PI) || isa<FunctionType>(*PI) ||
>> + isa<CompositeType>(*PI)) &&
>> + "This type is not an Integer or a Composite or a
>> Function");
>> + if (isa<CompositeType>(*PI)) {
>> + ParamTys[i] = VoidPtrTy;
>> + } else if (isa<FunctionType>(*PI)) {
>> + ParamTys[i] = VoidFnTy;
>> + } else if (isa<IntegerType>(*PI)) {
>> + ParamTys[i] = Int32Ty;
>> + }
>> + }
>> +
>> + return FunctionType::get(RetTy, ParamTys, IsVarArg);
>> + case JumpTable::Full:
>> + // Don't transform this type at all.
>> + return FunTy;
>> + }
>> +
>> + return nullptr;
>> +}
>> +
>> +bool JumpInstrTables::runOnModule(Module &M) {
>> + // Make sure the module is well-formed, especially with respect to
>> jumptable.
>> + if (verifyModule(M))
>> + return false;
>> +
>> + JITI = &getAnalysis<JumpInstrTableInfo>();
>> +
>> + // Get the set of jumptable-annotated functions.
>> + DenseMap<Function *, Function *> Functions;
>> + for (Function &F : M) {
>> + if (F.hasFnAttribute(Attribute::JumpTable)) {
>> + assert(F.hasUnnamedAddr() &&
>> + "Attribute 'jumptable' requires 'unnamed_addr'");
>> + Functions[&F] = NULL;
>> + }
>> + }
>> +
>> + // Create the jump-table functions.
>> + for (auto &KV : Functions) {
>> + Function *F = KV.first;
>> + KV.second = insertEntry(M, F);
>> + }
>> +
>> + // GlobalAlias is a special case, because the target of an alias
>> statement
>> + // must be a defined function. So, instead of replacing a given
>> function in
>> + // the alias, we replace all uses of aliases that target jumptable
>> functions.
>> + // Note that there's no need to create these functions, since only
>> aliases
>> + // that target known jumptable functions are replaced, and there's
>> no way to
>> + // put the jumptable annotation on a global alias.
>> + DenseMap<GlobalAlias *, Function *> Aliases;
>> + for (GlobalAlias &GA : M.aliases()) {
>> + Constant *Aliasee = GA.getAliasee();
>> + if (Function *F = dyn_cast<Function>(Aliasee)) {
>> + auto it = Functions.find(F);
>> + if (it != Functions.end()) {
>> + Aliases[&GA] = it->second;
>> + }
>> + }
>> + }
>> +
>> + // Replace each address taken function with its jump-instruction
>> table entry.
>> + for (auto &KV : Functions)
>> + replaceValueWithFunction(KV.first, KV.second);
>> +
>> + for (auto &KV : Aliases)
>> + replaceValueWithFunction(KV.first, KV.second);
>> +
>> + return !Functions.empty();
>> +}
>>
>> Modified: llvm/trunk/lib/CodeGen/LLVMTargetMachine.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/LLVMTargetMachine.cpp?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/lib/CodeGen/LLVMTargetMachine.cpp (original)
>> +++ llvm/trunk/lib/CodeGen/LLVMTargetMachine.cpp Thu Jun 5 14:29:43
>> 2014
>> @@ -12,11 +12,15 @@
>> //===----------------------------------------------------------------------===//
>> #include "llvm/Target/TargetMachine.h"
>> +
>> +#include "llvm/Analysis/Passes.h"
>> #include "llvm/CodeGen/AsmPrinter.h"
>> +#include "llvm/CodeGen/JumpInstrTables.h"
>> #include "llvm/CodeGen/MachineFunctionAnalysis.h"
>> #include "llvm/CodeGen/MachineModuleInfo.h"
>> #include "llvm/CodeGen/Passes.h"
>> #include "llvm/IR/IRPrintingPasses.h"
>> +#include "llvm/IR/Verifier.h"
>> #include "llvm/MC/MCAsmInfo.h"
>> #include "llvm/MC/MCContext.h"
>> #include "llvm/MC/MCInstrInfo.h"
>> @@ -82,6 +86,7 @@ static MCContext *addPassesToGenerateCod
>> bool DisableVerify,
>> AnalysisID StartAfter,
>> AnalysisID StopAfter) {
>> +
>> // Add internal analysis passes from the target machine.
>> TM->addAnalysisPasses(PM);
>> @@ -136,6 +141,11 @@ bool LLVMTargetMachine::addPassesToEmitF
>> bool DisableVerify,
>> AnalysisID StartAfter,
>> AnalysisID StopAfter) {
>> + // Passes to handle jumptable function annotations. These can't be
>> handled at
>> + // JIT time, so we don't add them directly to
>> addPassesToGenerateCode.
>> + PM.add(createJumpInstrTableInfoPass());
>> + PM.add(createJumpInstrTablesPass(Options.JTType));
>> +
>> // Add common CodeGen passes.
>> MCContext *Context = addPassesToGenerateCode(this, PM,
>> DisableVerify,
>> StartAfter, StopAfter);
>>
>> Modified: llvm/trunk/lib/IR/Attributes.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Attributes.cpp?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/lib/IR/Attributes.cpp (original)
>> +++ llvm/trunk/lib/IR/Attributes.cpp Thu Jun 5 14:29:43 2014
>> @@ -173,6 +173,8 @@ std::string Attribute::getAsString(bool
>> return "inlinehint";
>> if (hasAttribute(Attribute::InReg))
>> return "inreg";
>> + if (hasAttribute(Attribute::JumpTable))
>> + return "jumptable";
>> if (hasAttribute(Attribute::MinSize))
>> return "minsize";
>> if (hasAttribute(Attribute::Naked))
>> @@ -395,6 +397,7 @@ uint64_t AttributeImpl::getAttrMask(Attr
>> case Attribute::OptimizeNone: return 1ULL << 42;
>> case Attribute::InAlloca: return 1ULL << 43;
>> case Attribute::NonNull: return 1ULL << 44;
>> + case Attribute::JumpTable: return 1ULL << 45;
>> }
>> llvm_unreachable("Unsupported attribute type");
>> }
>>
>> Modified: llvm/trunk/lib/IR/Verifier.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Verifier.cpp?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/lib/IR/Verifier.cpp (original)
>> +++ llvm/trunk/lib/IR/Verifier.cpp Thu Jun 5 14:29:43 2014
>> @@ -735,7 +735,8 @@ void Verifier::VerifyAttributeTypes(Attr
>> I->getKindAsEnum() == Attribute::Builtin ||
>> I->getKindAsEnum() == Attribute::NoBuiltin ||
>> I->getKindAsEnum() == Attribute::Cold ||
>> - I->getKindAsEnum() == Attribute::OptimizeNone) {
>> + I->getKindAsEnum() == Attribute::OptimizeNone ||
>> + I->getKindAsEnum() == Attribute::JumpTable) {
>> if (!isFunction) {
>> CheckFailed("Attribute '" + I->getAsString() +
>> "' only applies to functions!", V);
>> @@ -909,6 +910,14 @@ void Verifier::VerifyFunctionAttrs(Funct
>> Attribute::MinSize),
>> "Attributes 'minsize and optnone' are incompatible!", V);
>> }
>> +
>> + if (Attrs.hasAttribute(AttributeSet::FunctionIndex,
>> + Attribute::JumpTable)) {
>> + const GlobalValue *GV = cast<GlobalValue>(V);
>> + Assert1(GV->hasUnnamedAddr(),
>> + "Attribute 'jumptable' requires 'unnamed_addr'", V);
>> +
>> + }
>> }
>> void Verifier::VerifyBitcastType(const Value *V, Type *DestTy,
>> Type *SrcTy) {
>>
>> Modified: llvm/trunk/lib/LTO/LTOCodeGenerator.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/LTO/LTOCodeGenerator.cpp?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/lib/LTO/LTOCodeGenerator.cpp (original)
>> +++ llvm/trunk/lib/LTO/LTOCodeGenerator.cpp Thu Jun 5 14:29:43 2014
>> @@ -96,6 +96,7 @@ void LTOCodeGenerator::initializeLTOPass
>> initializeConstantMergePass(R);
>> initializeDAHPass(R);
>> initializeInstCombinerPass(R);
>> + initializeJumpInstrTablesPass(R);
>> initializeSimpleInlinerPass(R);
>> initializePruneEHPass(R);
>> initializeGlobalDCEPass(R);
>>
>> Modified: llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp (original)
>> +++ llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp Thu Jun 5
>> 14:29:43 2014
>> @@ -32,6 +32,7 @@
>> #include "llvm/IR/Function.h"
>> #include "llvm/IR/GlobalValue.h"
>> #include "llvm/MC/MCAsmInfo.h"
>> +#include "llvm/MC/MCExpr.h"
>> #include "llvm/Support/BranchProbability.h"
>> #include "llvm/Support/CommandLine.h"
>> #include "llvm/Support/Debug.h"
>> @@ -4358,6 +4359,29 @@ breakPartialRegDependency(MachineBasicBl
>> MI->addRegisterKilled(DReg, TRI, true);
>> }
>> +void ARMBaseInstrInfo::getUnconditionalBranch(
>> + MCInst &Branch, const MCSymbolRefExpr *BranchTarget) const {
>> + if (Subtarget.isThumb())
>> + Branch.setOpcode(ARM::tB);
>> + else if (Subtarget.isThumb2())
>> + Branch.setOpcode(ARM::t2B);
>> + else
>> + Branch.setOpcode(ARM::Bcc);
>> +
>> + Branch.addOperand(MCOperand::CreateExpr(BranchTarget));
>> + Branch.addOperand(MCOperand::CreateImm(ARMCC::AL));
>> + Branch.addOperand(MCOperand::CreateReg(0));
>> +}
>> +
>> +void ARMBaseInstrInfo::getTrap(MCInst &MI) const {
>> + if (Subtarget.isThumb())
>> + MI.setOpcode(ARM::tTRAP);
>> + else if (Subtarget.useNaClTrap())
>> + MI.setOpcode(ARM::TRAPNaCl);
>> + else
>> + MI.setOpcode(ARM::TRAP);
>> +}
>> +
>> bool ARMBaseInstrInfo::hasNOP() const {
>> return (Subtarget.getFeatureBits() & ARM::HasV6T2Ops) != 0;
>> }
>>
>> Modified: llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.h?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.h (original)
>> +++ llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.h Thu Jun 5 14:29:43
>> 2014
>> @@ -229,6 +229,13 @@ public:
>> const TargetRegisterInfo*)
>> const override;
>> void breakPartialRegDependency(MachineBasicBlock::iterator,
>> unsigned,
>> const TargetRegisterInfo *TRI)
>> const override;
>> +
>> + void
>> + getUnconditionalBranch(MCInst &Branch,
>> + const MCSymbolRefExpr *BranchTarget) const
>> override;
>> +
>> + void getTrap(MCInst &MI) const override;
>> +
>> /// Get the number of addresses by LDM or VLDM or zero for unknown.
>> unsigned getNumLDMAddresses(const MachineInstr *MI) const;
>>
>> Modified: llvm/trunk/lib/Target/X86/X86InstrInfo.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86InstrInfo.cpp?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/lib/Target/X86/X86InstrInfo.cpp (original)
>> +++ llvm/trunk/lib/Target/X86/X86InstrInfo.cpp Thu Jun 5 14:29:43 2014
>> @@ -28,6 +28,7 @@
>> #include "llvm/IR/DerivedTypes.h"
>> #include "llvm/IR/LLVMContext.h"
>> #include "llvm/MC/MCAsmInfo.h"
>> +#include "llvm/MC/MCExpr.h"
>> #include "llvm/MC/MCInst.h"
>> #include "llvm/Support/CommandLine.h"
>> #include "llvm/Support/Debug.h"
>> @@ -5299,6 +5300,16 @@ void X86InstrInfo::getNoopForMachoTarget
>> NopInst.setOpcode(X86::NOOP);
>> }
>> +void X86InstrInfo::getUnconditionalBranch(
>> + MCInst &Branch, const MCSymbolRefExpr *BranchTarget) const {
>> + Branch.setOpcode(X86::JMP_4);
>> + Branch.addOperand(MCOperand::CreateExpr(BranchTarget));
>> +}
>> +
>> +void X86InstrInfo::getTrap(MCInst &MI) const {
>> + MI.setOpcode(X86::TRAP);
>> +}
>> +
>> bool X86InstrInfo::isHighLatencyDef(int opc) const {
>> switch (opc) {
>> default: return false;
>>
>> Modified: llvm/trunk/lib/Target/X86/X86InstrInfo.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86InstrInfo.h?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/lib/Target/X86/X86InstrInfo.h (original)
>> +++ llvm/trunk/lib/Target/X86/X86InstrInfo.h Thu Jun 5 14:29:43 2014
>> @@ -396,6 +396,12 @@ public:
>> const
>> SmallVectorImpl<MachineOperand> &MOs,
>> unsigned Size, unsigned
>> Alignment) const;
>> + void
>> + getUnconditionalBranch(MCInst &Branch,
>> + const MCSymbolRefExpr *BranchTarget) const
>> override;
>> +
>> + void getTrap(MCInst &MI) const override;
>> +
>> bool isHighLatencyDef(int opc) const override;
>> bool hasHighOperandLatency(const InstrItineraryData *ItinData,
>>
>> Modified: llvm/trunk/lib/Transforms/IPO/IPO.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/IPO.cpp?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/lib/Transforms/IPO/IPO.cpp (original)
>> +++ llvm/trunk/lib/Transforms/IPO/IPO.cpp Thu Jun 5 14:29:43 2014
>> @@ -30,6 +30,7 @@ void llvm::initializeIPO(PassRegistry &R
>> initializeGlobalDCEPass(Registry);
>> initializeGlobalOptPass(Registry);
>> initializeIPCPPass(Registry);
>> + initializeJumpInstrTablesPass(Registry);
>> initializeAlwaysInlinerPass(Registry);
>> initializeSimpleInlinerPass(Registry);
>> initializeInternalizePassPass(Registry);
>>
>> Modified: llvm/trunk/test/Bitcode/attributes.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/attributes.ll?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/test/Bitcode/attributes.ll (original)
>> +++ llvm/trunk/test/Bitcode/attributes.ll Thu Jun 5 14:29:43 2014
>> @@ -203,7 +203,7 @@ define void @f34()
>> ; CHECK: define void @f34()
>> {
>> call void @nobuiltin() nobuiltin
>> -; CHECK: call void @nobuiltin() #24
>> +; CHECK: call void @nobuiltin() #25
>> ret void;
>> }
>> @@ -223,6 +223,12 @@ define nonnull i8* @f37(i8* nonnull %a)
>> ret i8* %a
>> }
>> +define void @f38() unnamed_addr jumptable {
>> +; CHECK: define void @f38() unnamed_addr #24
>> + call void bitcast (void (i8*)* @f36 to void ()*)()
>> + unreachable
>> +}
>> +
>> ; CHECK: attributes #0 = { noreturn }
>> ; CHECK: attributes #1 = { nounwind }
>> ; CHECK: attributes #2 = { readnone }
>> @@ -247,5 +253,5 @@ define nonnull i8* @f37(i8* nonnull %a)
>> ; CHECK: attributes #21 = { sspstrong }
>> ; CHECK: attributes #22 = { minsize }
>> ; CHECK: attributes #23 = { noinline optnone }
>> -; CHECK: attributes #24 = { nobuiltin }
>> -
>> +; CHECK: attributes #24 = { jumptable }
>> +; CHECK: attributes #25 = { nobuiltin }
>>
>> Added: llvm/trunk/test/CodeGen/ARM/jump_tables.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/jump_tables.ll?rev=210280&view=auto
>> ==============================================================================
>>
>> --- llvm/trunk/test/CodeGen/ARM/jump_tables.ll (added)
>> +++ llvm/trunk/test/CodeGen/ARM/jump_tables.ll Thu Jun 5 14:29:43 2014
>> @@ -0,0 +1,32 @@
>> +; RUN: llc <%s -march=arm -jump-table-type=single | FileCheck
>> --check-prefix=ARM %s
>> +; RUN: llc <%s -march=thumb -jump-table-type=single | FileCheck
>> --check-prefix=THUMB %s
>> +
>> +define void @indirect_fun() unnamed_addr jumptable {
>> + ret void
>> +}
>> +define void ()* @get_fun() {
>> + ret void ()* @indirect_fun
>> +
>> +; ARM: ldr r0, [[LABEL:.*]]
>> +; ARM: mov pc, lr
>> +; ARM: [[LABEL]]:
>> +; ARM: .long __llvm_jump_instr_table_0_1
>> +
>> +; THUMB: ldr r0, [[LABEL:.*]]
>> +; THUMB: bx lr
>> +; THUMB: [[LABEL]]:
>> +; THUMB: .long __llvm_jump_instr_table_0_1
>> +}
>> +
>> +; ARM: .globl __llvm_jump_instr_table_0_1
>> +; ARM: .align 3
>> +; ARM: .type __llvm_jump_instr_table_0_1,%function
>> +; ARM: __llvm_jump_instr_table_0_1:
>> +; ARM: b indirect_fun(PLT)
>> +
>> +; THUMB: .globl __llvm_jump_instr_table_0_1
>> +; THUMB: .align 3
>> +; THUMB: .thumb_func
>> +; THUMB: .type __llvm_jump_instr_table_0_1,%function
>> +; THUMB: __llvm_jump_instr_table_0_1:
>> +; THUMB: b indirect_fun(PLT)
>>
>> Modified: llvm/trunk/test/CodeGen/Generic/stop-after.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Generic/stop-after.ll?rev=210280&r1=210279&r2=210280&view=diff
>> ==============================================================================
>>
>> --- llvm/trunk/test/CodeGen/Generic/stop-after.ll (original)
>> +++ llvm/trunk/test/CodeGen/Generic/stop-after.ll Thu Jun 5 14:29:43
>> 2014
>> @@ -5,6 +5,6 @@
>> ; STOP: Loop Strength Reduction
>> ; STOP-NEXT: Machine Function Analysis
>> -; START: -machine-branch-prob -gc-lowering
>> +; START: -machine-branch-prob -jump-instr-tables -gc-lowering
>> ; START: FunctionPass Manager
>> ; START-NEXT: Lower Garbage Collection Instructions
>>
>> Added: llvm/trunk/test/CodeGen/X86/jump_table_alias.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/jump_table_alias.ll?rev=210280&view=auto
>> ==============================================================================
>>
>> --- llvm/trunk/test/CodeGen/X86/jump_table_alias.ll (added)
>> +++ llvm/trunk/test/CodeGen/X86/jump_table_alias.ll Thu Jun 5
>> 14:29:43 2014
>> @@ -0,0 +1,33 @@
>> +; RUN: llc <%s -jump-table-type=single | FileCheck %s
>> +target triple = "x86_64-unknown-linux-gnu"
>> +define i32 @f() unnamed_addr jumptable {
>> +entry:
>> + ret i32 0
>> +}
>> +
>> + at i = alias internal i32 ()* @f
>> + at j = alias i32 ()* @f
>> +
>> +define i32 @main(i32 %argc, i8** %argv) {
>> + %temp = alloca i32 ()*, align 8
>> + store i32 ()* @i, i32()** %temp, align 8
>> +; CHECK: movq $__llvm_jump_instr_table_0_1
>> + %1 = load i32 ()** %temp, align 8
>> +; CHECK: movl $__llvm_jump_instr_table_0_1
>> + %2 = call i32 ()* %1()
>> + %3 = call i32 ()* @i()
>> +; CHECK: callq i
>> + %4 = call i32 ()* @j()
>> +; CHECK: callq j
>> + ret i32 %3
>> +}
>> +
>> +; There should only be one table, even though there are two
>> GlobalAliases,
>> +; because they both alias the same value.
>> +
>> +; CHECK: .globl __llvm_jump_instr_table_0_1
>> +; CHECK: .align 8, 0x90
>> +; CHECK: .type __llvm_jump_instr_table_0_1, at function
>> +; CHECK: __llvm_jump_instr_table_0_1:
>> +; CHECK: jmp f at PLT
>> +
>>
>> Added: llvm/trunk/test/CodeGen/X86/jump_table_bitcast.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/jump_table_bitcast.ll?rev=210280&view=auto
>> ==============================================================================
>>
>> --- llvm/trunk/test/CodeGen/X86/jump_table_bitcast.ll (added)
>> +++ llvm/trunk/test/CodeGen/X86/jump_table_bitcast.ll Thu Jun 5
>> 14:29:43 2014
>> @@ -0,0 +1,46 @@
>> +; RUN: llc <%s -jump-table-type=single | FileCheck %s
>> +target triple = "x86_64-unknown-linux-gnu"
>> +define i32 @f() unnamed_addr jumptable {
>> + ret i32 0
>> +}
>> +
>> +define i32 @g(i8* %a) unnamed_addr jumptable {
>> + ret i32 0
>> +}
>> +
>> +define void @h(void ()* %func) unnamed_addr jumptable {
>> + ret void
>> +}
>> +
>> +define i32 @main() {
>> + %g = alloca i32 (...)*, align 8
>> + store i32 (...)* bitcast (i32 ()* @f to i32 (...)*), i32 (...)**
>> %g, align 8
>> +; CHECK: movq $__llvm_jump_instr_table_0_[[ENTRY:1|2|3]], (%rsp)
>> +; CHECK: movl $__llvm_jump_instr_table_0_[[ENTRY]], %ecx
>> + %1 = load i32 (...)** %g, align 8
>> + %call = call i32 (...)* %1()
>> + call void (void ()*)* @h(void ()* bitcast (void (void ()*)* @h to
>> void ()*))
>> +; CHECK: movl $__llvm_jump_instr_table_0_{{1|2|3}}, %edi
>> +; CHECK: callq h
>> +
>> + %a = call i32 (i32*)* bitcast (i32 (i8*)* @g to i32(i32*)*)(i32*
>> null)
>> +; CHECK: callq g
>> + ret i32 %a
>> +}
>> +
>> +; CHECK: .globl __llvm_jump_instr_table_0_1
>> +; CHECK: .align 8, 0x90
>> +; CHECK: .type __llvm_jump_instr_table_0_1, at function
>> +; CHECK: __llvm_jump_instr_table_0_1:
>> +; CHECK: jmp {{f|g|h}}@PLT
>> +; CHECK: .globl __llvm_jump_instr_table_0_2
>> +; CHECK: .align 8, 0x90
>> +; CHECK: .type __llvm_jump_instr_table_0_2, at function
>> +; CHECK: __llvm_jump_instr_table_0_2:
>> +; CHECK: jmp {{f|g|h}}@PLT
>> +; CHECK: .globl __llvm_jump_instr_table_0_3
>> +; CHECK: .align 8, 0x90
>> +; CHECK: .type __llvm_jump_instr_table_0_3, at function
>> +; CHECK: __llvm_jump_instr_table_0_3:
>> +; CHECK: jmp {{f|g|h}}@PLT
>> +
>>
>> Added: llvm/trunk/test/CodeGen/X86/jump_tables.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/jump_tables.ll?rev=210280&view=auto
>> ==============================================================================
>>
>> --- llvm/trunk/test/CodeGen/X86/jump_tables.ll (added)
>> +++ llvm/trunk/test/CodeGen/X86/jump_tables.ll Thu Jun 5 14:29:43 2014
>> @@ -0,0 +1,272 @@
>> +; RUN: llc <%s -jump-table-type=single | FileCheck
>> --check-prefix=SINGLE %s
>> +; RUN: llc <%s -jump-table-type=arity | FileCheck
>> --check-prefix=ARITY %s
>> +; RUN: llc <%s -jump-table-type=simplified | FileCheck
>> --check-prefix=SIMPL %s
>> +; RUN: llc <%s -jump-table-type=full | FileCheck --check-prefix=FULL %s
>> +
>> +target triple = "x86_64-unknown-linux-gnu"
>> +
>> +%struct.fun_struct = type { i32 (...)* }
>> +
>> +define void @indirect_fun() unnamed_addr jumptable {
>> + ret void
>> +}
>> +
>> +define void @indirect_fun_match() unnamed_addr jumptable {
>> + ret void
>> +}
>> +
>> +define i32 @indirect_fun_i32() unnamed_addr jumptable {
>> + ret i32 0
>> +}
>> +
>> +define i32 @indirect_fun_i32_1(i32 %a) unnamed_addr jumptable {
>> + ret i32 %a
>> +}
>> +
>> +define i32 @indirect_fun_i32_2(i32 %a, i32 %b) unnamed_addr jumptable {
>> + ret i32 %a
>> +}
>> +
>> +define i32* @indirect_fun_i32S_2(i32* %a, i32 %b) unnamed_addr
>> jumptable {
>> + ret i32* %a
>> +}
>> +
>> +define void @indirect_fun_struct(%struct.fun_struct %fs)
>> unnamed_addr jumptable {
>> + ret void
>> +}
>> +
>> +define void @indirect_fun_fun(i32 (...)* %fun, i32 %a) unnamed_addr
>> jumptable {
>> + ret void
>> +}
>> +
>> +define i32 @indirect_fun_fun_ret(i32 (...)* %fun, i32 %a)
>> unnamed_addr jumptable {
>> + ret i32 %a
>> +}
>> +
>> +define void @indirect_fun_array([19 x i8] %a) unnamed_addr jumptable {
>> + ret void
>> +}
>> +
>> +define void @indirect_fun_vec(<3 x i32> %a) unnamed_addr jumptable {
>> + ret void
>> +}
>> +
>> +define void @indirect_fun_vec_2(<4 x float> %a) unnamed_addr
>> jumptable {
>> + ret void
>> +}
>> +
>> +define i32 @m(void ()* %fun) {
>> + call void ()* %fun()
>> + ret i32 0
>> +}
>> +
>> +define void ()* @get_fun() {
>> + ret void ()* @indirect_fun
>> +; SINGLE: movl $__llvm_jump_instr_table_0_
>> +; ARITY: movl $__llvm_jump_instr_table_
>> +; SIMPL: movl $__llvm_jump_instr_table_
>> +; FULL: movl $__llvm_jump_instr_table_
>> +}
>> +
>> +define i32 @main(i32 %argc, i8** %argv) {
>> + %f = call void ()* ()* @get_fun()
>> + %a = call i32 @m(void ()* %f)
>> + ret i32 %a
>> +}
>> +
>> +; SINGLE-DAG: .globl __llvm_jump_instr_table_0_1
>> +; SINGLE-DAG: .align 8, 0x90
>> +; SINGLE-DAG: .type __llvm_jump_instr_table_0_1, at function
>> +; SINGLE-DAG: __llvm_jump_instr_table_0_1:
>> +; SINGLE-DAG: jmp indirect_fun_array at PLT
>> +; SINGLE-DAG: .globl __llvm_jump_instr_table_0_2
>> +; SINGLE-DAG: .align 8, 0x90
>> +; SINGLE-DAG: .type __llvm_jump_instr_table_0_2, at function
>> +; SINGLE-DAG: __llvm_jump_instr_table_0_2:
>> +; SINGLE-DAG: jmp indirect_fun_i32_2 at PLT
>> +; SINGLE-DAG: .globl __llvm_jump_instr_table_0_3
>> +; SINGLE-DAG: .align 8, 0x90
>> +; SINGLE-DAG: .type __llvm_jump_instr_table_0_3, at function
>> +; SINGLE-DAG: __llvm_jump_instr_table_0_3:
>> +; SINGLE-DAG: jmp indirect_fun_vec_2 at PLT
>> +; SINGLE-DAG: .globl __llvm_jump_instr_table_0_4
>> +; SINGLE-DAG: .align 8, 0x90
>> +; SINGLE-DAG: .type __llvm_jump_instr_table_0_4, at function
>> +; SINGLE-DAG: __llvm_jump_instr_table_0_4:
>> +; SINGLE-DAG: jmp indirect_fun_i32S_2 at PLT
>> +; SINGLE-DAG: .globl __llvm_jump_instr_table_0_5
>> +; SINGLE-DAG: .align 8, 0x90
>> +; SINGLE-DAG: .type __llvm_jump_instr_table_0_5, at function
>> +; SINGLE-DAG: __llvm_jump_instr_table_0_5:
>> +; SINGLE-DAG: jmp indirect_fun_struct at PLT
>> +; SINGLE-DAG: .globl __llvm_jump_instr_table_0_6
>> +; SINGLE-DAG: .align 8, 0x90
>> +; SINGLE-DAG: .type __llvm_jump_instr_table_0_6, at function
>> +; SINGLE-DAG: __llvm_jump_instr_table_0_6:
>> +; SINGLE-DAG: jmp indirect_fun_i32_1 at PLT
>> +; SINGLE-DAG: .globl __llvm_jump_instr_table_0_7
>> +; SINGLE-DAG: .align 8, 0x90
>> +; SINGLE-DAG: .type __llvm_jump_instr_table_0_7, at function
>> +; SINGLE-DAG: __llvm_jump_instr_table_0_7:
>> +; SINGLE-DAG: jmp indirect_fun_i32 at PLT
>> +; SINGLE-DAG: .globl __llvm_jump_instr_table_0_8
>> +; SINGLE-DAG: .align 8, 0x90
>> +; SINGLE-DAG: .type __llvm_jump_instr_table_0_8, at function
>> +; SINGLE-DAG: __llvm_jump_instr_table_0_8:
>> +; SINGLE-DAG: jmp indirect_fun_fun at PLT
>> +; SINGLE-DAG: .globl __llvm_jump_instr_table_0_9
>> +; SINGLE-DAG: .align 8, 0x90
>> +; SINGLE-DAG: .type __llvm_jump_instr_table_0_9, at function
>> +; SINGLE-DAG: __llvm_jump_instr_table_0_9:
>> +; SINGLE-DAG: jmp indirect_fun_fun_ret at PLT
>> +; SINGLE-DAG: .globl __llvm_jump_instr_table_0_10
>> +; SINGLE-DAG: .align 8, 0x90
>> +; SINGLE-DAG: .type __llvm_jump_instr_table_0_10, at function
>> +; SINGLE-DAG: __llvm_jump_instr_table_0_10:
>> +; SINGLE-DAG: jmp indirect_fun at PLT
>> +; SINGLE-DAG: .globl __llvm_jump_instr_table_0_11
>> +; SINGLE-DAG: .align 8, 0x90
>> +; SINGLE-DAG: .type __llvm_jump_instr_table_0_11, at function
>> +; SINGLE-DAG: __llvm_jump_instr_table_0_11:
>> +; SINGLE-DAG: jmp indirect_fun_match at PLT
>> +; SINGLE-DAG: .globl __llvm_jump_instr_table_0_12
>> +; SINGLE-DAG: .align 8, 0x90
>> +; SINGLE-DAG: .type __llvm_jump_instr_table_0_12, at function
>> +; SINGLE-DAG: __llvm_jump_instr_table_0_12:
>> +; SINGLE-DAG: jmp indirect_fun_vec at PLT
>> +; SINGLE-DAG: .align 8, 0x90
>> +; SINGLE-DAG: ud2
>> +; SINGLE-DAG: .align 8, 0x90
>> +; SINGLE-DAG: ud2
>> +; SINGLE-DAG: .align 8, 0x90
>> +; SINGLE-DAG: ud2
>> +; SINGLE-DAG: .align 8, 0x90
>> +; SINGLE-DAG: ud2
>> +
>> +
>> +; ARITY-DAG: .globl __llvm_jump_instr_table_2_1
>> +; ARITY-DAG: .align 8, 0x90
>> +; ARITY-DAG: .type __llvm_jump_instr_table_2_1, at function
>> +; ARITY-DAG: __llvm_jump_instr_table_2_1:
>> +; ARITY-DAG: jmp indirect_fun{{.*}}@PLT
>> +; ARITY-DAG: .align 8, 0x90
>> +; ARITY-DAG: ud2
>> +; ARITY-DAG: .globl __llvm_jump_instr_table_0_1
>> +; ARITY-DAG: .align 8, 0x90
>> +; ARITY-DAG: .type __llvm_jump_instr_table_0_1, at function
>> +; ARITY-DAG: __llvm_jump_instr_table_0_1:
>> +; ARITY-DAG: jmp indirect_fun{{.*}}@PLT
>> +; ARITY-DAG: .globl __llvm_jump_instr_table_1_1
>> +; ARITY-DAG: .align 8, 0x90
>> +; ARITY-DAG: .type __llvm_jump_instr_table_1_1, at function
>> +; ARITY-DAG: __llvm_jump_instr_table_1_1:
>> +; ARITY-DAG: jmp indirect_fun{{.*}}@PLT
>> +
>> +; SIMPL-DAG: .globl __llvm_jump_instr_table_2_1
>> +; SIMPL-DAG: .align 8, 0x90
>> +; SIMPL-DAG: .type __llvm_jump_instr_table_2_1, at function
>> +; SIMPL-DAG: __llvm_jump_instr_table_2_1:
>> +; SIMPL-DAG: jmp indirect_fun{{.*}}@PLT
>> +; SIMPL-DAG: .align 8, 0x90
>> +; SIMPL-DAG: ud2
>> +; SIMPL-DAG: .globl __llvm_jump_instr_table_0_1
>> +; SIMPL-DAG: .align 8, 0x90
>> +; SIMPL-DAG: .type __llvm_jump_instr_table_0_1, at function
>> +; SIMPL-DAG: __llvm_jump_instr_table_0_1:
>> +; SIMPL-DAG: jmp indirect_fun{{.*}}@PLT
>> +; SIMPL-DAG: .globl __llvm_jump_instr_table_1_1
>> +; SIMPL-DAG: .align 8, 0x90
>> +; SIMPL-DAG: .type __llvm_jump_instr_table_1_1, at function
>> +; SIMPL-DAG: __llvm_jump_instr_table_1_1:
>> +; SIMPL-DAG: jmp indirect_fun{{.*}}@PLT
>> +; SIMPL-DAG: .globl __llvm_jump_instr_table_3_1
>> +; SIMPL-DAG: .align 8, 0x90
>> +; SIMPL-DAG: .type __llvm_jump_instr_table_3_1, at function
>> +; SIMPL-DAG: __llvm_jump_instr_table_3_1:
>> +; SIMPL-DAG: jmp indirect_fun{{.*}}@PLT
>> +; SIMPL-DAG: .globl __llvm_jump_instr_table_4_1
>> +; SIMPL-DAG: .align 8, 0x90
>> +; SIMPL-DAG: .type __llvm_jump_instr_table_4_1, at function
>> +; SIMPL-DAG: __llvm_jump_instr_table_4_1:
>> +; SIMPL-DAG: jmp indirect_fun{{.*}}@PLT
>> +
>> +
>> +; FULL-DAG: .globl __llvm_jump_instr_table_10_1
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: .type __llvm_jump_instr_table_10_1, at function
>> +; FULL-DAG:__llvm_jump_instr_table_10_1:
>> +; FULL-DAG: jmp indirect_fun_i32_1 at PLT
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: ud2
>> +; FULL-DAG: .globl __llvm_jump_instr_table_9_1
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: .type __llvm_jump_instr_table_9_1, at function
>> +; FULL-DAG:__llvm_jump_instr_table_9_1:
>> +; FULL-DAG: jmp indirect_fun_i32_2 at PLT
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: ud2
>> +; FULL-DAG: .globl __llvm_jump_instr_table_7_1
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: .type __llvm_jump_instr_table_7_1, at function
>> +; FULL-DAG:__llvm_jump_instr_table_7_1:
>> +; FULL-DAG: jmp indirect_fun_i32S_2 at PLT
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: ud2
>> +; FULL-DAG: .globl __llvm_jump_instr_table_3_1
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: .type __llvm_jump_instr_table_3_1, at function
>> +; FULL-DAG:__llvm_jump_instr_table_3_1:
>> +; FULL-DAG: jmp indirect_fun_vec_2 at PLT
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: ud2
>> +; FULL-DAG: .globl __llvm_jump_instr_table_2_1
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: .type __llvm_jump_instr_table_2_1, at function
>> +; FULL-DAG:__llvm_jump_instr_table_2_1:
>> +; FULL-DAG: jmp indirect_fun at PLT
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: ud2
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: ud2
>> +; FULL-DAG: .globl __llvm_jump_instr_table_8_1
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: .type __llvm_jump_instr_table_8_1, at function
>> +; FULL-DAG:__llvm_jump_instr_table_8_1:
>> +; FULL-DAG: jmp indirect_fun_i32 at PLT
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: ud2
>> +; FULL-DAG: .globl __llvm_jump_instr_table_1_1
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: .type __llvm_jump_instr_table_1_1, at function
>> +; FULL-DAG:__llvm_jump_instr_table_1_1:
>> +; FULL-DAG: jmp indirect_fun_array at PLT
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: ud2
>> +; FULL-DAG: .globl __llvm_jump_instr_table_0_1
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: .type __llvm_jump_instr_table_0_1, at function
>> +; FULL-DAG:__llvm_jump_instr_table_0_1:
>> +; FULL-DAG: jmp indirect_fun_vec at PLT
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: ud2
>> +; FULL-DAG: .globl __llvm_jump_instr_table_6_1
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: .type __llvm_jump_instr_table_6_1, at function
>> +; FULL-DAG:__llvm_jump_instr_table_6_1:
>> +; FULL-DAG: jmp indirect_fun_struct at PLT
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: ud2
>> +; FULL-DAG: .globl __llvm_jump_instr_table_5_1
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: .type __llvm_jump_instr_table_5_1, at function
>> +; FULL-DAG:__llvm_jump_instr_table_5_1:
>> +; FULL-DAG: jmp indirect_fun_fun at PLT
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: ud2
>> +; FULL-DAG: .globl __llvm_jump_instr_table_4_1
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: .type __llvm_jump_instr_table_4_1, at function
>> +; FULL-DAG:__llvm_jump_instr_table_4_1:
>> +; FULL-DAG: jmp indirect_fun_fun_ret at PLT
>> +; FULL-DAG: .align 8, 0x90
>> +; FULL-DAG: ud2
>>
>> Added: llvm/trunk/test/Verifier/jumptable.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Verifier/jumptable.ll?rev=210280&view=auto
>> ==============================================================================
>>
>> --- llvm/trunk/test/Verifier/jumptable.ll (added)
>> +++ llvm/trunk/test/Verifier/jumptable.ll Thu Jun 5 14:29:43 2014
>> @@ -0,0 +1,9 @@
>> +; RUN: not llc <%s 2>&1 | FileCheck %s
>> +
>> +define i32 @f() jumptable {
>> + ret i32 0
>> +}
>> +
>> +; CHECK: Attribute 'jumptable' requires 'unnamed_addr'
>> +; CHECK: i32 ()* @f
>> +; CHECK: LLVM ERROR: Broken function found, compilation aborted!
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
--
http://www.nuanti.com
the browser experts
More information about the llvm-commits
mailing list