mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 04:30:23 +00:00
[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:
parent
e49da9aff1
commit
9f3ecd086a
@ -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())) &&
|
||||
|
@ -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, ...)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user