1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 03:02:36 +01:00

All llvm.deoptimize declarations must use the same calling convention

This new verifier rule lets us unambigously pick a calling convention
when creating a new declaration for
`@llvm.experimental.deoptimize.<ty>`.  It is also congruent with our
lowering strategy -- since all calls to `@llvm.experimental.deoptimize`
are lowered to calls to `__llvm_deoptimize`, it is reasonable to enforce
a unique calling convention.

Some of the tests that were breaking this verifier rule have had to be
split up into different .ll files.

The inliner was violating this rule as well, and has been fixed to avoid
producing invalid IR.

llvm-svn: 269261
This commit is contained in:
Sanjoy Das 2016-05-12 01:17:38 +00:00
parent 6c16f1042e
commit ee178ad6c3
10 changed files with 108 additions and 53 deletions

View File

@ -12339,6 +12339,9 @@ The inliner composes the ``"deopt"`` continuations of the caller into the
``"deopt"`` continuations present in the inlinee, and also updates calls to this ``"deopt"`` continuations present in the inlinee, and also updates calls to this
intrinsic to return directly from the frame of the function it inlined into. intrinsic to return directly from the frame of the function it inlined into.
All declarations of ``@llvm.experimental.deoptimize`` must share the
same calling convention.
.. _deoptimize_lowering: .. _deoptimize_lowering:
Lowering: Lowering:

View File

@ -243,6 +243,9 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {
/// Cache of constants visited in search of ConstantExprs. /// Cache of constants visited in search of ConstantExprs.
SmallPtrSet<const Constant *, 32> ConstantExprVisited; SmallPtrSet<const Constant *, 32> ConstantExprVisited;
/// Cache of declarations of the llvm.experimental.deoptimize.<ty> intrinsic.
SmallVector<const Function *, 4> DeoptimizeDeclarations;
// Verify that this GlobalValue is only used in this module. // Verify that this GlobalValue is only used in this module.
// This map is used to avoid visiting uses twice. We can arrive at a user // This map is used to avoid visiting uses twice. We can arrive at a user
// twice, if they have multiple operands. In particular for very large // twice, if they have multiple operands. In particular for very large
@ -322,8 +325,11 @@ public:
visitGlobalValue(F); visitGlobalValue(F);
// Check to make sure function prototypes are okay. // Check to make sure function prototypes are okay.
if (F.isDeclaration()) if (F.isDeclaration()) {
visitFunction(F); visitFunction(F);
if (F.getIntrinsicID() == Intrinsic::experimental_deoptimize)
DeoptimizeDeclarations.push_back(&F);
}
} }
// Now that we've visited every function, verify that we never asked to // Now that we've visited every function, verify that we never asked to
@ -346,6 +352,8 @@ public:
verifyCompileUnits(); verifyCompileUnits();
verifyDeoptimizeCallingConvs();
return !Broken; return !Broken;
} }
@ -470,6 +478,10 @@ private:
/// Module-level debug info verification... /// Module-level debug info verification...
void verifyCompileUnits(); void verifyCompileUnits();
/// Module-level verification that all @llvm.experimental.deoptimize
/// declarations share the same calling convention.
void verifyDeoptimizeCallingConvs();
}; };
} // End anonymous namespace } // End anonymous namespace
@ -4396,6 +4408,18 @@ void Verifier::verifyCompileUnits() {
CUVisited.clear(); CUVisited.clear();
} }
void Verifier::verifyDeoptimizeCallingConvs() {
if (DeoptimizeDeclarations.empty())
return;
const Function *First = DeoptimizeDeclarations[0];
for (auto *F : makeArrayRef(DeoptimizeDeclarations).slice(1))
Assert(First->getCallingConv() == F->getCallingConv(),
"All llvm.experimental.deoptimize declarations must have the same "
"calling convention",
First, F);
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Implement the public interfaces to this file... // Implement the public interfaces to this file...
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -1874,7 +1874,13 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI,
continue; continue;
} }
auto CallingConv = DeoptCall->getCallingConv(); // The calling convention on the deoptimize call itself may be bogus,
// since the code we're inlining may have undefined behavior (and may
// never actually execute at runtime); but all
// @llvm.experimental.deoptimize declarations have to have the same
// calling convention in a well-formed module.
auto CallingConv = DeoptCall->getCalledFunction()->getCallingConv();
NewDeoptIntrinsic->setCallingConv(CallingConv);
auto *CurBB = RI->getParent(); auto *CurBB = RI->getParent();
RI->eraseFromParent(); RI->eraseFromParent();

View File

@ -0,0 +1,34 @@
; RUN: llc < %s | FileCheck %s
; RUN: llc -debug-only=stackmaps < %s 2>&1 | FileCheck --check-prefix=STACKMAPS %s
; REQUIRES: asserts
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.11.0"
declare webkit_jscc i64 @llvm.experimental.deoptimize.i64(...)
define i64 @caller_1() {
; CHECK-LABEL: _caller_1:
; CHECK-NEXT: {{.+cfi.+}}
; CHECK-NEXT: ##{{.+}}
; CHECK-NEXT: pushq %rax
; CHECK-NEXT: {{Ltmp[0-9]+}}:
; CHECK-NEXT: {{.+cfi.+}}
; CHECK-NEXT: movl $1140457472, (%rsp) ## imm = 0x43FA0000
; CHECK-NEXT: movl $42, %eax
; CHECK-NEXT: callq ___llvm_deoptimize
; CHECK-NEXT: {{Ltmp[0-9]+}}:
entry:
%v = call webkit_jscc i64(...) @llvm.experimental.deoptimize.i64(i32 42, float 500.0) [ "deopt"(i32 3) ]
ret i64 %v
}
; STACKMAPS: Stack Maps: callsites:
; STACKMAPS-NEXT: Stack Maps: callsite 2882400015
; STACKMAPS-NEXT: Stack Maps: has 4 locations
; STACKMAPS-NEXT: Stack Maps: Loc 0: Constant 12 [encoding: .byte 4, .byte 8, .short 0, .int 12]
; STACKMAPS-NEXT: Stack Maps: Loc 1: Constant 0 [encoding: .byte 4, .byte 8, .short 0, .int 0]
; STACKMAPS-NEXT: Stack Maps: Loc 2: Constant 1 [encoding: .byte 4, .byte 8, .short 0, .int 1]
; STACKMAPS-NEXT: Stack Maps: Loc 3: Constant 3 [encoding: .byte 4, .byte 8, .short 0, .int 3]
; STACKMAPS-NEXT: Stack Maps: has 0 live-out registers

View File

@ -7,7 +7,6 @@ target triple = "x86_64-apple-macosx10.11.0"
declare i32 @llvm.experimental.deoptimize.i32(...) declare i32 @llvm.experimental.deoptimize.i32(...)
declare i8 @llvm.experimental.deoptimize.i8(...) declare i8 @llvm.experimental.deoptimize.i8(...)
declare webkit_jscc i64 @llvm.experimental.deoptimize.i64(...)
define i32 @caller_0() { define i32 @caller_0() {
; CHECK-LABEL: _caller_0: ; CHECK-LABEL: _caller_0:
@ -40,23 +39,6 @@ entry:
ret i8 %v ret i8 %v
} }
define i64 @caller_2() {
; CHECK-LABEL: _caller_2:
; CHECK-NEXT: {{.+cfi.+}}
; CHECK-NEXT: ##{{.+}}
; CHECK-NEXT: pushq %rax
; CHECK-NEXT: {{Ltmp[0-9]+}}:
; CHECK-NEXT: {{.+cfi.+}}
; CHECK-NEXT: movl $1140457472, (%rsp) ## imm = 0x43FA0000
; CHECK-NEXT: movl $42, %eax
; CHECK-NEXT: callq ___llvm_deoptimize
; CHECK-NEXT: {{Ltmp[0-9]+}}:
entry:
%v = call webkit_jscc i64(...) @llvm.experimental.deoptimize.i64(i32 42, float 500.0) [ "deopt"(i32 3) ]
ret i64 %v
}
; STACKMAPS: Stack Maps: callsites: ; STACKMAPS: Stack Maps: callsites:
; STACKMAPS-NEXT: Stack Maps: callsite 2882400015 ; STACKMAPS-NEXT: Stack Maps: callsite 2882400015
; STACKMAPS-NEXT: Stack Maps: has 4 locations ; STACKMAPS-NEXT: Stack Maps: has 4 locations
@ -72,10 +54,3 @@ entry:
; STACKMAPS-NEXT: Stack Maps: Loc 2: Constant 1 [encoding: .byte 4, .byte 8, .short 0, .int 1] ; STACKMAPS-NEXT: Stack Maps: Loc 2: Constant 1 [encoding: .byte 4, .byte 8, .short 0, .int 1]
; STACKMAPS-NEXT: Stack Maps: Loc 3: Constant 1 [encoding: .byte 4, .byte 8, .short 0, .int 1] ; STACKMAPS-NEXT: Stack Maps: Loc 3: Constant 1 [encoding: .byte 4, .byte 8, .short 0, .int 1]
; STACKMAPS-NEXT: Stack Maps: has 0 live-out registers ; STACKMAPS-NEXT: Stack Maps: has 0 live-out registers
; STACKMAPS-NEXT: Stack Maps: callsite 2882400015
; STACKMAPS-NEXT: Stack Maps: has 4 locations
; STACKMAPS-NEXT: Stack Maps: Loc 0: Constant 12 [encoding: .byte 4, .byte 8, .short 0, .int 12]
; STACKMAPS-NEXT: Stack Maps: Loc 1: Constant 0 [encoding: .byte 4, .byte 8, .short 0, .int 0]
; STACKMAPS-NEXT: Stack Maps: Loc 2: Constant 1 [encoding: .byte 4, .byte 8, .short 0, .int 1]
; STACKMAPS-NEXT: Stack Maps: Loc 3: Constant 3 [encoding: .byte 4, .byte 8, .short 0, .int 3]
; STACKMAPS-NEXT: Stack Maps: has 0 live-out registers

View File

@ -0,0 +1,19 @@
; RUN: opt -S -always-inline < %s | FileCheck %s
declare cc42 i32 @llvm.experimental.deoptimize.i32(...)
define i32 @callee_with_coldcc() alwaysinline {
%v0 = call cc42 i32(...) @llvm.experimental.deoptimize.i32(i32 1) [ "deopt"() ]
ret i32 %v0
}
define void @caller_with_coldcc() {
; CHECK-LABEL: @caller_with_coldcc(
; CHECK-NEXT: call cc42 void (...) @llvm.experimental.deoptimize.isVoid(i32 1) [ "deopt"() ]
; CHECK-NEXT: ret void
%val = call i32 @callee_with_coldcc()
ret void
}
; CHECK: declare cc42 void @llvm.experimental.deoptimize.isVoid(...)

View File

@ -1,7 +1,7 @@
; RUN: opt -S -always-inline < %s | FileCheck %s ; RUN: opt -S -always-inline < %s | FileCheck %s
declare i8 @llvm.experimental.deoptimize.i8(...) declare i8 @llvm.experimental.deoptimize.i8(...)
declare cc42 i32 @llvm.experimental.deoptimize.i32(...) declare i32 @llvm.experimental.deoptimize.i32(...)
define i8 @callee(i1* %c) alwaysinline { define i8 @callee(i1* %c) alwaysinline {
%c0 = load volatile i1, i1* %c %c0 = load volatile i1, i1* %c
@ -121,17 +121,3 @@ define void @caller_with_stacksaverestore(i32 %n) {
call i8 @callee_with_dynamic_alloca(i32 %n) call i8 @callee_with_dynamic_alloca(i32 %n)
ret void ret void
} }
define i32 @callee_with_coldcc() alwaysinline {
%v0 = call cc42 i32(...) @llvm.experimental.deoptimize.i32(i32 1) [ "deopt"() ]
ret i32 %v0
}
define void @caller_with_coldcc() {
; CHECK-LABEL: @caller_with_coldcc(
; CHECK-NEXT: call cc42 void (...) @llvm.experimental.deoptimize.isVoid(i32 1) [ "deopt"() ]
; CHECK-NEXT: ret void
%val = call i32 @callee_with_coldcc()
ret void
}

View File

@ -0,0 +1,16 @@
; RUN: opt -rewrite-statepoints-for-gc -S < %s | FileCheck %s
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.11.0"
declare cc42 double @llvm.experimental.deoptimize.f64(...)
define double @caller_3() gc "statepoint-example" {
; CHECK-LABELL @caller_3(
; CHECK: call cc42 token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint
; CHECK: unreachable
entry:
%val = call cc42 double(...) @llvm.experimental.deoptimize.f64() [ "deopt"() ]
ret double %val
}

View File

@ -5,7 +5,6 @@ target triple = "x86_64-apple-macosx10.11.0"
declare i32 @llvm.experimental.deoptimize.i32(...) declare i32 @llvm.experimental.deoptimize.i32(...)
declare void @llvm.experimental.deoptimize.isVoid(...) declare void @llvm.experimental.deoptimize.isVoid(...)
declare cc42 double @llvm.experimental.deoptimize.f64(...)
define i32 @caller_0(i32 addrspace(1)* %ptr) gc "statepoint-example" { define i32 @caller_0(i32 addrspace(1)* %ptr) gc "statepoint-example" {
; CHECK-LABEL: @caller_0( ; CHECK-LABEL: @caller_0(
@ -34,13 +33,3 @@ entry:
call void(...) @llvm.experimental.deoptimize.isVoid() [ "deopt"(i32 0, i32 addrspace(1)* %ptr) ] call void(...) @llvm.experimental.deoptimize.isVoid() [ "deopt"(i32 0, i32 addrspace(1)* %ptr) ]
ret void ret void
} }
define double @caller_3() gc "statepoint-example" {
; CHECK-LABELL @caller_3(
; CHECK: call cc42 token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint
; CHECK: unreachable
entry:
%val = call cc42 double(...) @llvm.experimental.deoptimize.f64() [ "deopt"() ]
ret double %val
}

View File

@ -2,6 +2,7 @@
declare i8 @llvm.experimental.deoptimize.i8(...) declare i8 @llvm.experimental.deoptimize.i8(...)
declare void @llvm.experimental.deoptimize.isVoid(...) declare void @llvm.experimental.deoptimize.isVoid(...)
declare cc40 void @llvm.experimental.deoptimize.double(...)
declare void @unknown() declare void @unknown()
@ -40,3 +41,5 @@ entry:
; CHECK: calls to experimental_deoptimize must be followed by a return of the value computed by experimental_deoptimize ; CHECK: calls to experimental_deoptimize must be followed by a return of the value computed by experimental_deoptimize
ret i8 0 ret i8 0
} }
; CHECK: All llvm.experimental.deoptimize declarations must have the same calling convention