[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 12:29:44 PDT 2014
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!
More information about the llvm-commits
mailing list