[llvm] r210280 - Add a new attribute called 'jumptable' that creates jump-instruction tables for functions marked with this attribute.

Tom Roeder tmroeder at google.com
Thu Jun 5 13:36:45 PDT 2014


After looking at this briefly, I remember the reason I didn't do this
to begin with: opt currently doesn't expose the -jump-instr-tables
pass, and that's because JumpInstrTables adds new functions to the
module and needs some way to keep the link between the newly generated
function and its associated jumptable function so that it can generate
the right jump instruction in AsmPrinter. This information is not
currently preserved in IR; it's stored in JumpInstrTableInfo, which is
later read by AsmPrinter.

JumpInstrTables currently happens at the beginning of CodeGen so that
its information never needs to be preserved in IR. In other words,
while this is an IR->IR transformation, it only makes sense to run it
in the context of CodeGen.

So, adding a testcase to make it run under opt would require moving
the pass out of CodeGen and probably also adding a way to preserve the
jumptable function -> generated function link in IR so that it makes
sense.

On Thu, Jun 5, 2014 at 12:58 PM, Tom Roeder <tmroeder at google.com> wrote:
> OK, will do
>
> On Thu, Jun 5, 2014 at 12:58 PM, Rafael EspĂ­ndola
> <rafael.espindola at gmail.com> wrote:
>> Since this is an IR->IR pass, can you add a testcase that runs just
>> the pass with opt?
>>
>> On 5 June 2014 15:29, Tom Roeder <tmroeder at google.com> 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




More information about the llvm-commits mailing list