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:
parent
6c16f1042e
commit
ee178ad6c3
@ -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:
|
||||||
|
@ -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...
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
34
test/CodeGen/X86/deopt-intrinsic-cconv.ll
Normal file
34
test/CodeGen/X86/deopt-intrinsic-cconv.ll
Normal 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
|
@ -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
|
|
||||||
|
19
test/Transforms/Inline/deoptimize-intrinsic-cconv.ll
Normal file
19
test/Transforms/Inline/deoptimize-intrinsic-cconv.ll
Normal 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(...)
|
@ -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
|
|
||||||
}
|
|
||||||
|
@ -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
|
||||||
|
}
|
@ -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
|
|
||||||
}
|
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user