[RewriteStatepointsForGC] Fix a relocation bug w.r.t values defined by invoke instructions

RewriteStatepointsForGC pass emits an alloca for each GC pointer which will be relocated. It then inserts stores after def and all relocations, and inserts loads before each use as well. In the end, mem2reg is used to update IR with relocations in SSA form.

However, there is a problem with inserting stores for values defined by invoke instructions. The code didn't expect a def was a terminator instruction, and inserting instructions after these terminators resulted in malformed IR.

This patch fixes this problem by handling invoke instructions as a special case. If the def is an invoke instruction, the store will be inserted at the beginning of the normal destination block. Since return value from invoke instruction does not dominate the unwind destination block, no action is needed there.

Patch by: Chen Li
Differential Revision: http://reviews.llvm.org/D7923




git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@231183 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Philip Reames 2015-03-04 00:13:52 +00:00
parent e49da9aff1
commit 9f3ecd086a
2 changed files with 45 additions and 2 deletions

View File

@ -1593,8 +1593,18 @@ static void relocationViaAlloca(
// store must be inserted after load, otherwise store will be in alloca's
// use list and an extra load will be inserted before it
StoreInst *store = new StoreInst(def, alloca);
if (isa<Instruction>(def)) {
store->insertAfter(cast<Instruction>(def));
if (Instruction *inst = dyn_cast<Instruction>(def)) {
if (InvokeInst *invoke = dyn_cast<InvokeInst>(inst)) {
// InvokeInst is a TerminatorInst so the store need to be inserted
// into its normal destination block.
BasicBlock *normalDest = invoke->getNormalDest();
store->insertBefore(normalDest->getFirstNonPHI());
} else {
assert(!inst->isTerminator() &&
"The only TerminatorInst that can produce a value is "
"InvokeInst which is handled above.");
store->insertAfter(inst);
}
} else {
assert((isa<Argument>(def) || isa<GlobalVariable>(def) ||
(isa<Constant>(def) && cast<Constant>(def)->isNullValue())) &&

View File

@ -0,0 +1,33 @@
;; RUN: opt -rewrite-statepoints-for-gc -verify -S < %s | FileCheck %s
;; This test is to verify that RewriteStatepointsForGC correctly relocates values
;; defined by invoke instruction results.
declare i64* addrspace(1)* @non_gc_call()
declare void @gc_call()
declare i32* @fake_personality_function()
; Function Attrs: nounwind
define i64* addrspace(1)* @test() gc "statepoint-example" {
entry:
%obj = invoke i64* addrspace(1)* @non_gc_call()
to label %normal_dest unwind label %unwind_dest
unwind_dest:
%lpad = landingpad { i8*, i32 } personality i32* ()* @fake_personality_function
cleanup
resume { i8*, i32 } undef
normal_dest:
;; CHECK-LABEL: normal_dest:
;; CHECK-NEXT: gc.statepoint
;; CHECK-NEXT: %obj.relocated = call coldcc i64* addrspace(1)*
%safepoint_token = call i32 (void ()*, i32, i32, ...)* @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()* @gc_call, i32 0, i32 0, i32 5, i32 0, i32 -1, i32 0, i32 0, i32 0)
ret i64* addrspace(1)* %obj
}
declare i32 @llvm.experimental.gc.statepoint.p0f_isVoidf(void ()*, i32, i32, ...)