[llvm] r286611 - [cfi] Implement cfi-icall using inline assembly.
Evgeniy Stepanov via llvm-commits
llvm-commits at lists.llvm.org
Fri Nov 11 10:49:09 PST 2016
Author: eugenis
Date: Fri Nov 11 12:49:09 2016
New Revision: 286611
URL: http://llvm.org/viewvc/llvm-project?rev=286611&view=rev
Log:
[cfi] Implement cfi-icall using inline assembly.
The current implementation is emitting a global constant that happens
to evaluate to the same bytes + relocation as a jump instruction on
X86. This does not work for PIE executables and shared libraries
though, because we end up with a wrong relocation type. And it has no
chance of working on ARM/AArch64 which use different relocation types
for jump instructions (R_ARM_JUMP24) that is never generated for
data.
This change replaces the constant with module-level inline assembly
followed by a hidden declaration of the jump table. Works fine for
ARM/AArch64, but has some drawbacks.
* Extra symbols are added to the static symbol table, which inflate
the size of the unstripped binary a little. Stripped binaries are not
affected. This happens because jump table declarations must be
external (because their body is in the inline asm).
* Original functions that were anonymous are now named
<original name>.cfi, and it affects symbolization sometimes. This is
necessary because the only user of these functions is the (inline
asm) jump table, so they had to be added to @llvm.used, which does
not allow unnamed functions.
Modified:
llvm/trunk/lib/Transforms/IPO/LowerTypeTests.cpp
llvm/trunk/test/Transforms/LowerTypeTests/function-disjoint.ll
llvm/trunk/test/Transforms/LowerTypeTests/function-ext.ll
llvm/trunk/test/Transforms/LowerTypeTests/function.ll
llvm/trunk/test/Transforms/LowerTypeTests/section.ll
Modified: llvm/trunk/lib/Transforms/IPO/LowerTypeTests.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/LowerTypeTests.cpp?rev=286611&r1=286610&r2=286611&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/LowerTypeTests.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/LowerTypeTests.cpp Fri Nov 11 12:49:09 2016
@@ -24,6 +24,7 @@
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Mangler.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
#include "llvm/Pass.h"
@@ -31,6 +32,7 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
using namespace llvm;
using namespace lowertypetests;
@@ -225,6 +227,8 @@ class LowerTypeTestsModule {
std::vector<ByteArrayInfo> ByteArrayInfos;
+ Mangler Mang;
+
BitSetInfo
buildBitSet(Metadata *TypeId,
const DenseMap<GlobalObject *, uint64_t> &GlobalLayout);
@@ -243,12 +247,13 @@ class LowerTypeTestsModule {
ArrayRef<GlobalVariable *> Globals);
unsigned getJumpTableEntrySize();
Type *getJumpTableEntryType();
- Constant *createJumpTableEntry(GlobalObject *Src, Function *Dest,
- unsigned Distance);
+ void createJumpTableEntry(raw_ostream &OS, Function *Dest, unsigned Distance);
+ void createJumpTableAlias(raw_ostream &OS, Function *Dest,
+ GlobalVariable *JumpTable, unsigned Distance);
void verifyTypeMDNode(GlobalObject *GO, MDNode *Type);
void buildBitSetsFromFunctions(ArrayRef<Metadata *> TypeIds,
ArrayRef<Function *> Functions);
- void buildBitSetsFromFunctionsX86(ArrayRef<Metadata *> TypeIds,
+ void buildBitSetsFromFunctionsNative(ArrayRef<Metadata *> TypeIds,
ArrayRef<Function *> Functions);
void buildBitSetsFromFunctionsWASM(ArrayRef<Metadata *> TypeIds,
ArrayRef<Function *> Functions);
@@ -627,53 +632,101 @@ void LowerTypeTestsModule::verifyTypeMDN
}
static const unsigned kX86JumpTableEntrySize = 8;
+static const unsigned kARMJumpTableEntrySize = 4;
unsigned LowerTypeTestsModule::getJumpTableEntrySize() {
- return kX86JumpTableEntrySize;
+ switch (Arch) {
+ case Triple::x86:
+ case Triple::x86_64:
+ return kX86JumpTableEntrySize;
+ case Triple::arm:
+ case Triple::aarch64:
+ return kARMJumpTableEntrySize;
+ default:
+ report_fatal_error("Unsupported architecture for jump tables");
+ }
+}
+
+static bool isValidAsmUnquotedName(StringRef Name) {
+ if (Name.empty())
+ return false;
+
+ for (char C : Name) {
+ if (!((C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z') ||
+ (C >= '0' && C <= '9') || C == '_' || C == '$' || C == '.' ||
+ C == '@'))
+ return false;
+ }
+
+ return true;
}
// Create a constant representing a jump table entry for the target. This
// consists of an instruction sequence containing a relative branch to Dest. The
// constant will be laid out at address Src+(Len*Distance) where Len is the
// target-specific jump table entry size.
-Constant *LowerTypeTestsModule::createJumpTableEntry(GlobalObject *Src,
- Function *Dest,
- unsigned Distance) {
- const unsigned kJmpPCRel32Code = 0xe9;
- const unsigned kInt3Code = 0xcc;
-
- ConstantInt *Jmp = ConstantInt::get(Int8Ty, kJmpPCRel32Code);
-
- // Build a constant representing the displacement between the constant's
- // address and Dest. This will resolve to a PC32 relocation referring to Dest.
- Constant *DestInt = ConstantExpr::getPtrToInt(Dest, IntPtrTy);
- Constant *SrcInt = ConstantExpr::getPtrToInt(Src, IntPtrTy);
- Constant *Disp = ConstantExpr::getSub(DestInt, SrcInt);
- ConstantInt *DispOffset =
- ConstantInt::get(IntPtrTy, Distance * kX86JumpTableEntrySize + 5);
- Constant *OffsetedDisp = ConstantExpr::getSub(Disp, DispOffset);
- OffsetedDisp = ConstantExpr::getTruncOrBitCast(OffsetedDisp, Int32Ty);
-
- ConstantInt *Int3 = ConstantInt::get(Int8Ty, kInt3Code);
-
- Constant *Fields[] = {
- Jmp, OffsetedDisp, Int3, Int3, Int3,
- };
- return ConstantStruct::getAnon(Fields, /*Packed=*/true);
+void LowerTypeTestsModule::createJumpTableEntry(raw_ostream &OS, Function *Dest,
+ unsigned Distance) {
+ // FIXME: replace IR Mangler with TargetLoweringObjectFile interface.
+ // A private instance of Mangler we use here can not deal with unnamed
+ // symbols, as it may create colliding labels. Thankfully(?), the use of
+ // inline asm requires us to give names to all affected functions anyway.
+ assert(Dest->hasName() && "jumptable targets can not be anonymous");
+ SmallString<16> Name;
+ Mang.getNameWithPrefix(Name, Dest, /* CannotUsePrivateLabel */ false);
+
+ if (!isValidAsmUnquotedName(Name)) {
+ // We are going to emit a function call as textual asm. Escaped strings
+ // in such expressions are not well supported.
+ report_fatal_error(
+ "CFI-ICall does not allow special characters in a function name.");
+ }
+
+ if (Arch == Triple::x86 || Arch == Triple::x86_64) {
+ OS << "jmp " << Name << "@plt\n";
+ OS << "int3\nint3\nint3\n";
+ } else if (Arch == Triple::arm || Arch == Triple::aarch64) {
+ OS << "b " << Name << "\n";
+ } else {
+ report_fatal_error("Unsupported architecture for jump tables");
+ }
+}
+
+void LowerTypeTestsModule::createJumpTableAlias(raw_ostream &OS, Function *Dest,
+ GlobalVariable *JumpTable,
+ unsigned Distance) {
+ assert(Dest->hasName() && "jumptable targets can not be anonymous");
+ SmallString<16> Name;
+ Mang.getNameWithPrefix(Name, Dest, /* CannotUsePrivateLabel */ false);
+
+ if (!isValidAsmUnquotedName(Name)) {
+ // We are going to emit a function alias as textual asm. Escaped strings
+ // in such expressions are not well supported.
+ report_fatal_error(
+ "CFI-ICall does not allow special characters in a function name.");
+ }
+
+ if (Dest->isWeakForLinker())
+ OS << ".weak " << Name << "\n";
+ else if (!Dest->hasLocalLinkage())
+ OS << ".globl " << Name << "\n";
+ OS << ".type " << Name << ", function\n";
+ OS << Name << " = " << JumpTable->getName() << " + "
+ << (getJumpTableEntrySize() * Distance) << "\n";
+ OS << ".size " << Name << ", " << getJumpTableEntrySize() << "\n";
}
Type *LowerTypeTestsModule::getJumpTableEntryType() {
- return StructType::get(M.getContext(),
- {Int8Ty, Int32Ty, Int8Ty, Int8Ty, Int8Ty},
- /*Packed=*/true);
+ return ArrayType::get(Int8Ty, getJumpTableEntrySize());
}
/// Given a disjoint set of type identifiers and functions, build the bit sets
/// and lower the llvm.type.test calls, architecture dependently.
void LowerTypeTestsModule::buildBitSetsFromFunctions(
ArrayRef<Metadata *> TypeIds, ArrayRef<Function *> Functions) {
- if (Arch == Triple::x86 || Arch == Triple::x86_64)
- buildBitSetsFromFunctionsX86(TypeIds, Functions);
+ if (Arch == Triple::x86 || Arch == Triple::x86_64 || Arch == Triple::arm ||
+ Arch == Triple::aarch64)
+ buildBitSetsFromFunctionsNative(TypeIds, Functions);
else if (Arch == Triple::wasm32 || Arch == Triple::wasm64)
buildBitSetsFromFunctionsWASM(TypeIds, Functions);
else
@@ -682,7 +735,7 @@ void LowerTypeTestsModule::buildBitSetsF
/// Given a disjoint set of type identifiers and functions, build a jump table
/// for the functions, build the bit sets and lower the llvm.type.test calls.
-void LowerTypeTestsModule::buildBitSetsFromFunctionsX86(
+void LowerTypeTestsModule::buildBitSetsFromFunctionsNative(
ArrayRef<Metadata *> TypeIds, ArrayRef<Function *> Functions) {
// Unlike the global bitset builder, the function bitset builder cannot
// re-arrange functions in a particular order and base its calculations on the
@@ -717,39 +770,35 @@ void LowerTypeTestsModule::buildBitSetsF
// mov h, %ecx
// ret
//
- // To create a jump table for these functions, we instruct the LLVM code
- // generator to output a jump table in the .text section. This is done by
- // representing the instructions in the jump table as an LLVM constant and
- // placing them in a global variable in the .text section. The end result will
- // (conceptually) look like this:
+ // We output the jump table as module-level inline asm string. The end result
+ // will (conceptually) look like this:
//
- // f:
- // jmp .Ltmp0 ; 5 bytes
+ // f = .cfi.jumptable
+ // g = .cfi.jumptable + 4
+ // h = .cfi.jumptable + 8
+ // .cfi.jumptable:
+ // jmp f.cfi ; 5 bytes
// int3 ; 1 byte
// int3 ; 1 byte
// int3 ; 1 byte
- //
- // g:
- // jmp .Ltmp1 ; 5 bytes
+ // jmp g.cfi ; 5 bytes
// int3 ; 1 byte
// int3 ; 1 byte
// int3 ; 1 byte
- //
- // h:
- // jmp .Ltmp2 ; 5 bytes
+ // jmp h.cfi ; 5 bytes
// int3 ; 1 byte
// int3 ; 1 byte
// int3 ; 1 byte
//
- // .Ltmp0:
+ // f.cfi:
// mov 0, %eax
// ret
//
- // .Ltmp1:
+ // g.cfi:
// mov 1, %eax
// ret
//
- // .Ltmp2:
+ // h.cfi:
// mov 2, %eax
// ret
//
@@ -763,6 +812,8 @@ void LowerTypeTestsModule::buildBitSetsF
// normal case the check can be carried out using the same kind of simple
// arithmetic that we normally use for globals.
+ // FIXME: find a better way to represent the jumptable in the IR.
+
assert(!Functions.empty());
// Build a simple layout based on the regular layout of jump tables.
@@ -774,45 +825,78 @@ void LowerTypeTestsModule::buildBitSetsF
// Create a constant to hold the jump table.
ArrayType *JumpTableType =
ArrayType::get(getJumpTableEntryType(), Functions.size());
- auto JumpTable = new GlobalVariable(M, JumpTableType,
- /*isConstant=*/true,
- GlobalValue::PrivateLinkage, nullptr);
- JumpTable->setSection(ObjectFormat == Triple::MachO
- ? "__TEXT,__text,regular,pure_instructions"
- : ".text");
+ auto JumpTable =
+ new GlobalVariable(M, JumpTableType,
+ /*isConstant=*/true, GlobalValue::ExternalLinkage,
+ nullptr, ".cfi.jumptable");
+ JumpTable->setVisibility(GlobalValue::HiddenVisibility);
lowerTypeTestCalls(TypeIds, JumpTable, GlobalLayout);
+ std::string AsmStr;
+ raw_string_ostream AsmOS(AsmStr);
+
// Build aliases pointing to offsets into the jump table, and replace
// references to the original functions with references to the aliases.
for (unsigned I = 0; I != Functions.size(); ++I) {
- Constant *CombinedGlobalElemPtr = ConstantExpr::getBitCast(
- ConstantExpr::getGetElementPtr(
- JumpTableType, JumpTable,
- ArrayRef<Constant *>{ConstantInt::get(IntPtrTy, 0),
- ConstantInt::get(IntPtrTy, I)}),
- Functions[I]->getType());
+ // Need a name for the asm label. Normally, unnamed functions get temporary
+ // asm labels in TargetLoweringObjectFile but we don't have access to that
+ // here.
+ if (!Functions[I]->hasName())
+ Functions[I]->setName("unnamed");
if (LinkerSubsectionsViaSymbols || Functions[I]->isDeclarationForLinker()) {
+ Constant *CombinedGlobalElemPtr = ConstantExpr::getBitCast(
+ ConstantExpr::getGetElementPtr(
+ JumpTableType, JumpTable,
+ ArrayRef<Constant *>{ConstantInt::get(IntPtrTy, 0),
+ ConstantInt::get(IntPtrTy, I)}),
+ Functions[I]->getType());
Functions[I]->replaceAllUsesWith(CombinedGlobalElemPtr);
+
+ if (Functions[I]->isWeakForLinker())
+ AsmOS << ".weak " << Functions[I]->getName() << "\n";
} else {
assert(Functions[I]->getType()->getAddressSpace() == 0);
- GlobalAlias *GAlias = GlobalAlias::create(Functions[I]->getValueType(), 0,
- Functions[I]->getLinkage(), "",
- CombinedGlobalElemPtr, &M);
- GAlias->setVisibility(Functions[I]->getVisibility());
- GAlias->takeName(Functions[I]);
- Functions[I]->replaceAllUsesWith(GAlias);
+
+ createJumpTableAlias(AsmOS, Functions[I], JumpTable, I);
+
+ Function *DeclAlias =
+ Function::Create(cast<FunctionType>(Functions[I]->getValueType()),
+ GlobalValue::ExternalLinkage, "", &M);
+ // Since the alias (DeclAlias) is actually a declaration, it can not have
+ // internal linkage. Compensate for that by giving it hidden visibility.
+ // With this we end up with a GOT relocation against a local symbol.
+ DeclAlias->setVisibility(Functions[I]->hasLocalLinkage()
+ ? GlobalValue::HiddenVisibility
+ : Functions[I]->getVisibility());
+ DeclAlias->takeName(Functions[I]);
+ // Unnamed functions can not be added to llvm.used.
+ Functions[I]->setName(DeclAlias->getName() + ".cfi");
+ Functions[I]->replaceAllUsesWith(DeclAlias);
}
if (!Functions[I]->isDeclarationForLinker())
- Functions[I]->setLinkage(GlobalValue::PrivateLinkage);
+ Functions[I]->setLinkage(GlobalValue::InternalLinkage);
}
- // Build and set the jump table's initializer.
- std::vector<Constant *> JumpTableEntries;
+ // Try to emit the jump table at the end of the text segment.
+ // Jump table must come after __cfi_check in the cross-dso mode.
+ // FIXME: this magic section name seems to do the trick.
+ AsmOS << ".section " << (ObjectFormat == Triple::MachO
+ ? "__TEXT,__text,regular,pure_instructions"
+ : ".text.cfi, \"ax\", @progbits")
+ << "\n";
+ // Align the whole table by entry size.
+ AsmOS << ".balign " << EntrySize << "\n";
+ AsmOS << JumpTable->getName() << ":\n";
for (unsigned I = 0; I != Functions.size(); ++I)
- JumpTableEntries.push_back(
- createJumpTableEntry(JumpTable, Functions[I], I));
- JumpTable->setInitializer(
- ConstantArray::get(JumpTableType, JumpTableEntries));
+ createJumpTableEntry(AsmOS, Functions[I], I);
+
+ M.appendModuleInlineAsm(AsmOS.str());
+
+ SmallVector<GlobalValue *, 16> Used;
+ Used.reserve(Functions.size());
+ for (auto *F : Functions)
+ Used.push_back(F);
+ appendToUsed(M, Used);
}
/// Assign a dummy layout using an incrementing counter, tag each function
Modified: llvm/trunk/test/Transforms/LowerTypeTests/function-disjoint.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/LowerTypeTests/function-disjoint.ll?rev=286611&r1=286610&r2=286611&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/LowerTypeTests/function-disjoint.ll (original)
+++ llvm/trunk/test/Transforms/LowerTypeTests/function-disjoint.ll Fri Nov 11 12:49:09 2016
@@ -5,21 +5,36 @@
target datalayout = "e-p:64:64"
-; X64: @[[JT0:.*]] = private constant [1 x <{ i8, i32, i8, i8, i8 }>] [<{ i8, i32, i8, i8, i8 }> <{ i8 -23, i32 trunc (i64 sub (i64 sub (i64 ptrtoint (void ()* @[[FNAME:.*]] to i64), i64 ptrtoint ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT0]] to i64)), i64 5) to i32), i8 -52, i8 -52, i8 -52 }>], section ".text"
-; X64: @[[JT1:.*]] = private constant [1 x <{ i8, i32, i8, i8, i8 }>] [<{ i8, i32, i8, i8, i8 }> <{ i8 -23, i32 trunc (i64 sub (i64 sub (i64 ptrtoint (void ()* @[[GNAME:.*]] to i64), i64 ptrtoint ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT1]] to i64)), i64 5) to i32), i8 -52, i8 -52, i8 -52 }>], section ".text"
+; X64: module asm "f = .cfi.jumptable + 0"
+
+; X64: module asm ".cfi.jumptable:"
+; X64-NEXT: module asm "jmp f.cfi at plt"
+; X64-NEXT: module asm "int3"
+; X64-NEXT: module asm "int3"
+; X64-NEXT: module asm "int3"
+
+; X64: module asm "g = .cfi.jumptable.1 + 0"
+
+; X64: module asm ".cfi.jumptable.1:"
+; X64-NEXT: module asm "jmp g.cfi at plt"
+; X64-NEXT: module asm "int3"
+; X64-NEXT: module asm "int3"
+; X64-NEXT: module asm "int3"
+
+
+; X64: @.cfi.jumptable = external hidden constant [1 x [8 x i8]]
+; X64: @.cfi.jumptable.1 = external hidden constant [1 x [8 x i8]]
+
; WASM32: private constant [0 x i8] zeroinitializer
@0 = private unnamed_addr constant [2 x void ()*] [void ()* @f, void ()* @g], align 16
-; X64: @f = alias void (), bitcast ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT0]] to void ()*)
-; X64: @g = alias void (), bitcast ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT1]] to void ()*)
-
-; X64: define private void @[[FNAME]]()
+; X64: define internal void @f.cfi()
; WASM32: define void @f() !type !{{[0-9]+}} !wasm.index ![[I0:[0-9]+]]
define void @f() !type !0 {
ret void
}
-; X64: define private void @[[GNAME]]()
+; X64: define internal void @g.cfi()
; WASM32: define void @g() !type !{{[0-9]+}} !wasm.index ![[I1:[0-9]+]]
define void @g() !type !1 {
ret void
@@ -31,15 +46,18 @@ define void @g() !type !1 {
declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone
define i1 @foo(i8* %p) {
- ; X64: icmp eq i64 {{.*}}, ptrtoint ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT0]] to i64)
+ ; X64: icmp eq i64 {{.*}}, ptrtoint ([1 x [8 x i8]]* @.cfi.jumptable to i64)
; WASM32: icmp eq i64 {{.*}}, 1
%x = call i1 @llvm.type.test(i8* %p, metadata !"typeid1")
- ; X64: icmp eq i64 {{.*}}, ptrtoint ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT1]] to i64)
+ ; X64: icmp eq i64 {{.*}}, ptrtoint ([1 x [8 x i8]]* @.cfi.jumptable.1 to i64)
; WASM32: icmp eq i64 {{.*}}, 2
%y = call i1 @llvm.type.test(i8* %p, metadata !"typeid2")
%z = add i1 %x, %y
ret i1 %z
}
+; X64: declare void @f()
+; X64: declare void @g()
+
; WASM32: ![[I0]] = !{i64 1}
-; WASM32: ![[I1]] = !{i64 2}
+; WASM32: ![[I1]] = !{i64 2}
\ No newline at end of file
Modified: llvm/trunk/test/Transforms/LowerTypeTests/function-ext.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/LowerTypeTests/function-ext.ll?rev=286611&r1=286610&r2=286611&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/LowerTypeTests/function-ext.ll (original)
+++ llvm/trunk/test/Transforms/LowerTypeTests/function-ext.ll Fri Nov 11 12:49:09 2016
@@ -4,14 +4,18 @@
; Tests that we correctly handle external references, including the case where
; all functions in a bitset are external references.
-; X64: @[[JT:.*]] = private constant [1 x <{ i8, i32, i8, i8, i8 }>] [<{ i8, i32, i8, i8, i8 }> <{ i8 -23, i32 trunc (i64 sub (i64 sub (i64 ptrtoint (void ()* @foo to i64), i64 ptrtoint ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64)), i64 5) to i32), i8 -52, i8 -52, i8 -52 }>], section ".text"
+; X64: module asm ".cfi.jumptable:"
+; X64-NEXT: module asm "jmp foo at plt"
+; X64-NOT: module asm "jmp {{.*}}@plt"
+
+; X64: @.cfi.jumptable = external hidden constant [1 x [8 x i8]]
; WASM32: private constant [0 x i8] zeroinitializer
; WASM32: declare !type !{{[0-9]+}} void @foo()
declare !type !0 void @foo()
define i1 @bar(i8* %ptr) {
- ; X64: icmp eq i64 {{.*}}, ptrtoint ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64)
+ ; X64: icmp eq i64 {{.*}}, ptrtoint ([1 x [8 x i8]]* @.cfi.jumptable to i64)
; WASM32: sub i64 {{.*}}, 0
; WASM32: icmp ult i64 {{.*}}, 1
%p = call i1 @llvm.type.test(i8* %ptr, metadata !"void")
Modified: llvm/trunk/test/Transforms/LowerTypeTests/function.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/LowerTypeTests/function.ll?rev=286611&r1=286610&r2=286611&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/LowerTypeTests/function.ll (original)
+++ llvm/trunk/test/Transforms/LowerTypeTests/function.ll Fri Nov 11 12:49:09 2016
@@ -1,26 +1,65 @@
-; RUN: opt -S -lowertypetests -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck --check-prefix=X64 %s
+; RUN: opt -S -lowertypetests -mtriple=i686-unknown-linux-gnu < %s | FileCheck --check-prefix=X86 %s
+; RUN: opt -S -lowertypetests -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck --check-prefix=X86 %s
+; RUN: opt -S -lowertypetests -mtriple=arm-unknown-linux-gnu < %s | FileCheck --check-prefix=ARM %s
+; RUN: opt -S -lowertypetests -mtriple=aarch64-unknown-linux-gnu < %s | FileCheck --check-prefix=ARM %s
; RUN: opt -S -lowertypetests -mtriple=wasm32-unknown-unknown < %s | FileCheck --check-prefix=WASM32 %s
; Tests that we correctly handle bitsets containing 2 or more functions.
target datalayout = "e-p:64:64"
-; X64: @[[JT:.*]] = private constant [2 x <{ i8, i32, i8, i8, i8 }>] [<{ i8, i32, i8, i8, i8 }> <{ i8 -23, i32 trunc (i64 sub (i64 sub (i64 ptrtoint (void ()* @[[FNAME:.*]] to i64), i64 ptrtoint ([2 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64)), i64 5) to i32), i8 -52, i8 -52, i8 -52 }>, <{ i8, i32, i8, i8, i8 }> <{ i8 -23, i32 trunc (i64 sub (i64 sub (i64 ptrtoint (void ()* @[[GNAME:.*]] to i64), i64 ptrtoint ([2 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64)), i64 13) to i32), i8 -52, i8 -52, i8 -52 }>], section ".text"
+; X86: module asm ".globl f"
+; X86-NEXT: module asm ".type f, function"
+; X86-NEXT: module asm "f = .cfi.jumptable + 0"
+; X86-NEXT: module asm ".size f, 8"
+; X86-NEXT: module asm ".type g, function"
+; X86-NEXT: module asm "g = .cfi.jumptable + 8"
+; X86-NEXT: module asm ".size g, 8"
+; X86-NEXT: module asm ".section .text.cfi, \22ax\22, @progbits"
+; X86-NEXT: module asm ".balign 8"
+; X86-NEXT: module asm ".cfi.jumptable:"
+; X86-NEXT: module asm "jmp f.cfi at plt"
+; X86-NEXT: module asm "int3"
+; X86-NEXT: module asm "int3"
+; X86-NEXT: module asm "int3"
+; X86-NEXT: module asm "jmp g.cfi at plt"
+; X86-NEXT: module asm "int3"
+; X86-NEXT: module asm "int3"
+; X86-NEXT: module asm "int3"
+
+; ARM: module asm ".globl f"
+; ARM-NEXT: module asm ".type f, function"
+; ARM-NEXT: module asm "f = .cfi.jumptable + 0"
+; ARM-NEXT: module asm ".size f, 4"
+; ARM-NEXT: module asm ".type g, function"
+; ARM-NEXT: module asm "g = .cfi.jumptable + 4"
+; ARM-NEXT: module asm ".size g, 4"
+; ARM-NEXT: module asm ".section .text.cfi, \22ax\22, @progbits"
+; ARM-NEXT: module asm ".balign 4"
+; ARM-NEXT: module asm ".cfi.jumptable:"
+; ARM-NEXT: module asm "b f.cfi"
+; ARM-NEXT: module asm "b g.cfi"
+
+; X86: @.cfi.jumptable = external hidden constant [2 x [8 x i8]]
+; ARM: @.cfi.jumptable = external hidden constant [2 x [4 x i8]]
+
; WASM32: private constant [0 x i8] zeroinitializer
@0 = private unnamed_addr constant [2 x void (...)*] [void (...)* bitcast (void ()* @f to void (...)*), void (...)* bitcast (void ()* @g to void (...)*)], align 16
-; X64: @f = alias void (), bitcast ([2 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to void ()*)
-; X64: @g = alias void (), bitcast (<{ i8, i32, i8, i8, i8 }>* getelementptr inbounds ([2 x <{ i8, i32, i8, i8, i8 }>], [2 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]], i64 0, i64 1) to void ()*)
+; X86: @llvm.used = appending global [2 x i8*] [i8* bitcast (void ()* @f.cfi to i8*), i8* bitcast (void ()* @g.cfi to i8*)], section "llvm.metadata"
+; ARM: @llvm.used = appending global [2 x i8*] [i8* bitcast (void ()* @f.cfi to i8*), i8* bitcast (void ()* @g.cfi to i8*)], section "llvm.metadata"
-; X64: define private void @[[FNAME]]()
+; X86: define internal void @f.cfi()
+; ARM: define internal void @f.cfi()
; WASM32: define void @f() !type !{{[0-9]+}} !wasm.index ![[I0:[0-9]+]]
define void @f() !type !0 {
ret void
}
-; X64: define private void @[[GNAME]]()
-; WASM32: define void @g() !type !{{[0-9]+}} !wasm.index ![[I1:[0-9]+]]
-define void @g() !type !0 {
+; X86: define internal void @g.cfi()
+; ARM: define internal void @g.cfi()
+; WASM32: define internal void @g() !type !{{[0-9]+}} !wasm.index ![[I1:[0-9]+]]
+define internal void @g() !type !0 {
ret void
}
@@ -29,12 +68,18 @@ define void @g() !type !0 {
declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone
define i1 @foo(i8* %p) {
- ; X64: sub i64 {{.*}}, ptrtoint ([2 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64)
+ ; X86: sub i64 {{.*}}, ptrtoint ([2 x [8 x i8]]* @.cfi.jumptable to i64)
+ ; ARM: sub i64 {{.*}}, ptrtoint ([2 x [4 x i8]]* @.cfi.jumptable to i64)
; WASM32: sub i64 {{.*}}, 1
; WASM32: icmp ult i64 {{.*}}, 2
%x = call i1 @llvm.type.test(i8* %p, metadata !"typeid1")
ret i1 %x
}
+; X86: declare void @f()
+; ARM: declare void @f()
+; X86: declare hidden void @g()
+; ARM: declare hidden void @g()
+
; WASM32: ![[I0]] = !{i64 1}
; WASM32: ![[I1]] = !{i64 2}
Modified: llvm/trunk/test/Transforms/LowerTypeTests/section.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/LowerTypeTests/section.ll?rev=286611&r1=286610&r2=286611&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/LowerTypeTests/section.ll (original)
+++ llvm/trunk/test/Transforms/LowerTypeTests/section.ll Fri Nov 11 12:49:09 2016
@@ -5,9 +5,11 @@
target triple = "x86_64-unknown-linux-gnu"
-; CHECK: @[[A:.*]] = private constant {{.*}} section ".text"
-; CHECK: @f = alias void (), bitcast ({{.*}}* @[[A]] to void ()*)
-; CHECK: define private void {{.*}} section "xxx"
+; CHECK: module asm ".section .text.cfi,
+; CHECK: module asm ".cfi.jumptable:"
+; CHECK-NEXT: module asm "jmp f.cfi at plt"
+
+; CHECK: define internal void @f.cfi() section "xxx"
define void @f() section "xxx" !type !0 {
entry:
More information about the llvm-commits
mailing list