mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 03:02:36 +01:00
[EarlyCSE] Common gc.relocate calls.
gc.relocate intrinsic is special in that its second and third operands are not real values, but indices into relocate's parent statepoint list of GC pointers. To be CSE'd, they need special handling in `isEqual()` and `getHashCode()`. Reviewed By: reames Differential Revision: https://reviews.llvm.org/D80445
This commit is contained in:
parent
37450a7b9e
commit
bc1dd0f13a
@ -41,6 +41,7 @@
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/IR/PatternMatch.h"
|
||||
#include "llvm/IR/Statepoint.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/IR/Use.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
@ -456,6 +457,14 @@ template <> struct DenseMapInfo<CallValue> {
|
||||
|
||||
unsigned DenseMapInfo<CallValue>::getHashValue(CallValue Val) {
|
||||
Instruction *Inst = Val.Inst;
|
||||
|
||||
// gc.relocate is 'special' call: its second and third operands are
|
||||
// not real values, but indices into statepoint's argument list.
|
||||
// Get values they point to.
|
||||
if (const GCRelocateInst *GCR = dyn_cast<GCRelocateInst>(Inst))
|
||||
return hash_combine(GCR->getOpcode(), GCR->getOperand(0),
|
||||
GCR->getBasePtr(), GCR->getDerivedPtr());
|
||||
|
||||
// Hash all of the operands as pointers and mix in the opcode.
|
||||
return hash_combine(
|
||||
Inst->getOpcode(),
|
||||
@ -466,6 +475,14 @@ bool DenseMapInfo<CallValue>::isEqual(CallValue LHS, CallValue RHS) {
|
||||
Instruction *LHSI = LHS.Inst, *RHSI = RHS.Inst;
|
||||
if (LHS.isSentinel() || RHS.isSentinel())
|
||||
return LHSI == RHSI;
|
||||
|
||||
// See comment above in `getHashValue()`.
|
||||
if (const GCRelocateInst *GCR1 = dyn_cast<GCRelocateInst>(LHSI))
|
||||
if (const GCRelocateInst *GCR2 = dyn_cast<GCRelocateInst>(RHSI))
|
||||
return GCR1->getOperand(0) == GCR2->getOperand(0) &&
|
||||
GCR1->getBasePtr() == GCR2->getBasePtr() &&
|
||||
GCR1->getDerivedPtr() == GCR2->getDerivedPtr();
|
||||
|
||||
return LHSI->isIdenticalTo(RHSI);
|
||||
}
|
||||
|
||||
|
86
test/Transforms/EarlyCSE/gc_relocate.ll
Normal file
86
test/Transforms/EarlyCSE/gc_relocate.ll
Normal file
@ -0,0 +1,86 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt -early-cse -S < %s | FileCheck %s
|
||||
|
||||
declare void @func()
|
||||
declare i32 @"personality_function"()
|
||||
|
||||
define i1 @test_call(i32 addrspace(1)* %in) gc "statepoint-example" {
|
||||
; CHECK-LABEL: @test_call(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[SAFEPOINT_TOKEN:%.*]] = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0, i32 addrspace(1)* [[IN:%.*]], i32 addrspace(1)* [[IN]])
|
||||
; CHECK-NEXT: [[BASE:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[SAFEPOINT_TOKEN]], i32 7, i32 7)
|
||||
; CHECK-NEXT: [[SAFEPOINT_TOKEN2:%.*]] = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0, i32 addrspace(1)* [[BASE]], i32 addrspace(1)* [[BASE]])
|
||||
; CHECK-NEXT: br label [[NEXT:%.*]]
|
||||
; CHECK: next:
|
||||
; CHECK-NEXT: [[BASE_RELOC:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[SAFEPOINT_TOKEN2]], i32 7, i32 7)
|
||||
;
|
||||
entry:
|
||||
%safepoint_token = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0, i32 addrspace(1)* %in, i32 addrspace(1)* %in)
|
||||
%base = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 7, i32 7)
|
||||
%derived = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 7, i32 8)
|
||||
%safepoint_token2 = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0, i32 addrspace(1)* %base, i32 addrspace(1)* %derived)
|
||||
br label %next
|
||||
|
||||
next:
|
||||
%base_reloc = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token2, i32 7, i32 7)
|
||||
%derived_reloc = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token2, i32 7, i32 8)
|
||||
%cmp1 = icmp eq i32 addrspace(1)* %base_reloc, null
|
||||
%cmp2 = icmp eq i32 addrspace(1)* %derived_reloc, null
|
||||
%cmp = and i1 %cmp1, %cmp2
|
||||
ret i1 %cmp
|
||||
}
|
||||
|
||||
; Negative test: Check that relocates from different statepoints are not CSE'd
|
||||
define i1 @test_two_calls(i32 addrspace(1)* %in1, i32 addrspace(1)* %in2) gc "statepoint-example" {
|
||||
; CHECK-LABEL: @test_two_calls(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[SAFEPOINT_TOKEN:%.*]] = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0, i32 addrspace(1)* [[IN1:%.*]], i32 addrspace(1)* [[IN2:%.*]])
|
||||
; CHECK-NEXT: [[IN1_RELOC1:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[SAFEPOINT_TOKEN]], i32 7, i32 7)
|
||||
; CHECK-NEXT: [[IN2_RELOC1:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[SAFEPOINT_TOKEN]], i32 8, i32 8)
|
||||
; CHECK-NEXT: [[SAFEPOINT_TOKEN2:%.*]] = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0, i32 addrspace(1)* [[IN1_RELOC1]], i32 addrspace(1)* [[IN2_RELOC1]])
|
||||
; CHECK-NEXT: [[IN1_RELOC2:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[SAFEPOINT_TOKEN2]], i32 7, i32 7)
|
||||
; CHECK-NEXT: [[IN2_RELOC2:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[SAFEPOINT_TOKEN2]], i32 7, i32 8)
|
||||
;
|
||||
entry:
|
||||
%safepoint_token = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0, i32 addrspace(1)* %in1, i32 addrspace(1)* %in2)
|
||||
%in1.reloc1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 7, i32 7)
|
||||
%in2.reloc1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 8, i32 8)
|
||||
%safepoint_token2 = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0, i32 addrspace(1)* %in1.reloc1, i32 addrspace(1)* %in2.reloc1)
|
||||
%in1.reloc2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token2, i32 7, i32 7)
|
||||
%in2.reloc2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token2, i32 7, i32 8)
|
||||
%cmp1 = icmp eq i32 addrspace(1)* %in1.reloc2, null
|
||||
%cmp2 = icmp eq i32 addrspace(1)* %in2.reloc2, null
|
||||
%cmp = and i1 %cmp1, %cmp2
|
||||
ret i1 %cmp
|
||||
}
|
||||
|
||||
; Negative test: Check that relocates from normal and exceptional pathes are not be CSE'd
|
||||
define i32 addrspace(1)* @test_invoke(i32 addrspace(1)* %in) gc "statepoint-example" personality i32 ()* @"personality_function" {
|
||||
; CHECK-LABEL: @test_invoke(
|
||||
; CHECK-NEXT: [[SAFEPOINT_TOKEN:%.*]] = invoke token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0, i32 addrspace(1)* [[IN:%.*]])
|
||||
; CHECK-NEXT: to label [[INVOKE_NORMAL_DEST:%.*]] unwind label [[EXCEPTIONAL_RETURN:%.*]]
|
||||
; CHECK: invoke_normal_dest:
|
||||
; CHECK-NEXT: [[OUT:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[SAFEPOINT_TOKEN]], i32 7, i32 7)
|
||||
; CHECK-NEXT: ret i32 addrspace(1)* [[OUT]]
|
||||
; CHECK: exceptional_return:
|
||||
; CHECK-NEXT: [[LANDING_PAD:%.*]] = landingpad token
|
||||
; CHECK-NEXT: cleanup
|
||||
; CHECK-NEXT: [[OUT1:%.*]] = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token [[LANDING_PAD]], i32 7, i32 7)
|
||||
; CHECK-NEXT: ret i32 addrspace(1)* [[OUT1]]
|
||||
;
|
||||
%safepoint_token = invoke token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0, i32 addrspace(1)* %in)
|
||||
to label %invoke_normal_dest unwind label %exceptional_return
|
||||
|
||||
invoke_normal_dest:
|
||||
%out = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 7, i32 7)
|
||||
ret i32 addrspace(1)* %out
|
||||
|
||||
exceptional_return:
|
||||
%landing_pad = landingpad token
|
||||
cleanup
|
||||
%out1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %landing_pad, i32 7, i32 7)
|
||||
ret i32 addrspace(1)* %out1
|
||||
}
|
||||
|
||||
declare token @llvm.experimental.gc.statepoint.p0f_isVoidf(i64, i32, void ()*, i32, i32, ...)
|
||||
declare i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token, i32, i32)
|
Loading…
Reference in New Issue
Block a user