summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
Diffstat (limited to 'llvm')
-rw-r--r--llvm/docs/LangRef.rst3
-rw-r--r--llvm/lib/IR/Verifier.cpp26
-rw-r--r--llvm/lib/Transforms/Utils/InlineFunction.cpp8
-rw-r--r--llvm/test/CodeGen/X86/deopt-intrinsic-cconv.ll34
-rw-r--r--llvm/test/CodeGen/X86/deopt-intrinsic.ll25
-rw-r--r--llvm/test/Transforms/Inline/deoptimize-intrinsic-cconv.ll19
-rw-r--r--llvm/test/Transforms/Inline/deoptimize-intrinsic.ll16
-rw-r--r--llvm/test/Transforms/RewriteStatepointsForGC/deopt-intrinsic-cconv.ll16
-rw-r--r--llvm/test/Transforms/RewriteStatepointsForGC/deopt-intrinsic.ll11
-rw-r--r--llvm/test/Verifier/deoptimize-intrinsic.ll3
10 files changed, 108 insertions, 53 deletions
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 39b119cfc8d..2fa6293744f 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -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
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:
Lowering:
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 5621962497a..1b36eb9bd68 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -243,6 +243,9 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {
/// Cache of constants visited in search of ConstantExprs.
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.
// 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
@@ -322,8 +325,11 @@ public:
visitGlobalValue(F);
// Check to make sure function prototypes are okay.
- if (F.isDeclaration())
+ if (F.isDeclaration()) {
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
@@ -346,6 +352,8 @@ public:
verifyCompileUnits();
+ verifyDeoptimizeCallingConvs();
+
return !Broken;
}
@@ -470,6 +478,10 @@ private:
/// Module-level debug info verification...
void verifyCompileUnits();
+
+ /// Module-level verification that all @llvm.experimental.deoptimize
+ /// declarations share the same calling convention.
+ void verifyDeoptimizeCallingConvs();
};
} // End anonymous namespace
@@ -4396,6 +4408,18 @@ void Verifier::verifyCompileUnits() {
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...
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp b/llvm/lib/Transforms/Utils/InlineFunction.cpp
index 5b0640c7237..c8d76f4d9e8 100644
--- a/llvm/lib/Transforms/Utils/InlineFunction.cpp
+++ b/llvm/lib/Transforms/Utils/InlineFunction.cpp
@@ -1874,7 +1874,13 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI,
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();
RI->eraseFromParent();
diff --git a/llvm/test/CodeGen/X86/deopt-intrinsic-cconv.ll b/llvm/test/CodeGen/X86/deopt-intrinsic-cconv.ll
new file mode 100644
index 00000000000..8e240f8901d
--- /dev/null
+++ b/llvm/test/CodeGen/X86/deopt-intrinsic-cconv.ll
@@ -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
diff --git a/llvm/test/CodeGen/X86/deopt-intrinsic.ll b/llvm/test/CodeGen/X86/deopt-intrinsic.ll
index 008075bfeae..ceed2d24882 100644
--- a/llvm/test/CodeGen/X86/deopt-intrinsic.ll
+++ b/llvm/test/CodeGen/X86/deopt-intrinsic.ll
@@ -7,7 +7,6 @@ target triple = "x86_64-apple-macosx10.11.0"
declare i32 @llvm.experimental.deoptimize.i32(...)
declare i8 @llvm.experimental.deoptimize.i8(...)
-declare webkit_jscc i64 @llvm.experimental.deoptimize.i64(...)
define i32 @caller_0() {
; CHECK-LABEL: _caller_0:
@@ -40,23 +39,6 @@ entry:
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-NEXT: Stack Maps: callsite 2882400015
; 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 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: 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
diff --git a/llvm/test/Transforms/Inline/deoptimize-intrinsic-cconv.ll b/llvm/test/Transforms/Inline/deoptimize-intrinsic-cconv.ll
new file mode 100644
index 00000000000..4e2c3fe4786
--- /dev/null
+++ b/llvm/test/Transforms/Inline/deoptimize-intrinsic-cconv.ll
@@ -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(...)
diff --git a/llvm/test/Transforms/Inline/deoptimize-intrinsic.ll b/llvm/test/Transforms/Inline/deoptimize-intrinsic.ll
index 98fbc68488e..848a9db0542 100644
--- a/llvm/test/Transforms/Inline/deoptimize-intrinsic.ll
+++ b/llvm/test/Transforms/Inline/deoptimize-intrinsic.ll
@@ -1,7 +1,7 @@
; RUN: opt -S -always-inline < %s | FileCheck %s
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 {
%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)
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
-}
diff --git a/llvm/test/Transforms/RewriteStatepointsForGC/deopt-intrinsic-cconv.ll b/llvm/test/Transforms/RewriteStatepointsForGC/deopt-intrinsic-cconv.ll
new file mode 100644
index 00000000000..b74c1963ddf
--- /dev/null
+++ b/llvm/test/Transforms/RewriteStatepointsForGC/deopt-intrinsic-cconv.ll
@@ -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
+}
diff --git a/llvm/test/Transforms/RewriteStatepointsForGC/deopt-intrinsic.ll b/llvm/test/Transforms/RewriteStatepointsForGC/deopt-intrinsic.ll
index 559dc9d6501..ef0e2bd61af 100644
--- a/llvm/test/Transforms/RewriteStatepointsForGC/deopt-intrinsic.ll
+++ b/llvm/test/Transforms/RewriteStatepointsForGC/deopt-intrinsic.ll
@@ -5,7 +5,6 @@ target triple = "x86_64-apple-macosx10.11.0"
declare i32 @llvm.experimental.deoptimize.i32(...)
declare void @llvm.experimental.deoptimize.isVoid(...)
-declare cc42 double @llvm.experimental.deoptimize.f64(...)
define i32 @caller_0(i32 addrspace(1)* %ptr) gc "statepoint-example" {
; CHECK-LABEL: @caller_0(
@@ -34,13 +33,3 @@ entry:
call void(...) @llvm.experimental.deoptimize.isVoid() [ "deopt"(i32 0, i32 addrspace(1)* %ptr) ]
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
-}
diff --git a/llvm/test/Verifier/deoptimize-intrinsic.ll b/llvm/test/Verifier/deoptimize-intrinsic.ll
index 81e4d3a8981..62c61d42b35 100644
--- a/llvm/test/Verifier/deoptimize-intrinsic.ll
+++ b/llvm/test/Verifier/deoptimize-intrinsic.ll
@@ -2,6 +2,7 @@
declare i8 @llvm.experimental.deoptimize.i8(...)
declare void @llvm.experimental.deoptimize.isVoid(...)
+declare cc40 void @llvm.experimental.deoptimize.double(...)
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
ret i8 0
}
+
+; CHECK: All llvm.experimental.deoptimize declarations must have the same calling convention
OpenPOWER on IntegriCloud