Skip to content

Commit 049993e

Browse files
NuriAmariNuri Amari
andauthored
[FunctionComparator] Differentiate instructions passing different MDStrings (llvm#69543)
Prior to this patch, differing metadata operands to two otherwise identical instructions was not enough to consider the instructions different in the eyes of the function comparator. This breaks LLVM virtual function elimination, among other features. In this patch, we handle the case where two associated operands are MDStrings of different value. This patch does not differentiate more complex metadata operands. --------- Co-authored-by: Nuri Amari <[email protected]>
1 parent d173ce4 commit 049993e

File tree

2 files changed

+73
-1
lines changed

2 files changed

+73
-1
lines changed

llvm/lib/Transforms/Utils/FunctionComparator.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,23 @@ int FunctionComparator::cmpAttrs(const AttributeList L,
160160
int FunctionComparator::cmpMetadata(const Metadata *L,
161161
const Metadata *R) const {
162162
// TODO: the following routine coerce the metadata contents into constants
163-
// before comparison.
163+
// or MDStrings before comparison.
164164
// It ignores any other cases, so that the metadata nodes are considered
165165
// equal even though this is not correct.
166166
// We should structurally compare the metadata nodes to be perfect here.
167+
168+
auto *MDStringL = dyn_cast<MDString>(L);
169+
auto *MDStringR = dyn_cast<MDString>(R);
170+
if (MDStringL && MDStringR) {
171+
if (MDStringL == MDStringR)
172+
return 0;
173+
return MDStringL->getString().compare(MDStringR->getString());
174+
}
175+
if (MDStringR)
176+
return -1;
177+
if (MDStringL)
178+
return 1;
179+
167180
auto *CL = dyn_cast<ConstantAsMetadata>(L);
168181
auto *CR = dyn_cast<ConstantAsMetadata>(R);
169182
if (CL == CR)
@@ -820,6 +833,21 @@ int FunctionComparator::cmpValues(const Value *L, const Value *R) const {
820833
if (ConstR)
821834
return -1;
822835

836+
const MetadataAsValue *MetadataValueL = dyn_cast<MetadataAsValue>(L);
837+
const MetadataAsValue *MetadataValueR = dyn_cast<MetadataAsValue>(R);
838+
if (MetadataValueL && MetadataValueR) {
839+
if (MetadataValueL == MetadataValueR)
840+
return 0;
841+
842+
return cmpMetadata(MetadataValueL->getMetadata(),
843+
MetadataValueR->getMetadata());
844+
}
845+
846+
if (MetadataValueL)
847+
return 1;
848+
if (MetadataValueR)
849+
return -1;
850+
823851
const InlineAsm *InlineAsmL = dyn_cast<InlineAsm>(L);
824852
const InlineAsm *InlineAsmR = dyn_cast<InlineAsm>(R);
825853

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3
2+
; RUN: opt -passes=mergefunc -S %s | FileCheck %s
3+
4+
; This test contains three identical functions, aside from the metadata
5+
; they pass to a function call. This test verifies that the function merger
6+
; pass is able to merge the two functions that are truly identical,
7+
; but the third that passes different metadata is preserved
8+
9+
declare { ptr, i1 } @llvm.type.checked.load(ptr, i32, metadata)
10+
11+
define i1 @merge_candidate_a(ptr %ptr, i32 %offset) {
12+
; CHECK-LABEL: define i1 @merge_candidate_a(
13+
; CHECK-SAME: ptr [[PTR:%.*]], i32 [[OFFSET:%.*]]) {
14+
; CHECK-NEXT: [[TMP1:%.*]] = call { ptr, i1 } @llvm.type.checked.load(ptr [[PTR]], i32 [[OFFSET]], metadata !"common_metadata")
15+
; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i1 } [[TMP1]], 1
16+
; CHECK-NEXT: ret i1 [[TMP2]]
17+
;
18+
%1 = call { ptr, i1 } @llvm.type.checked.load(ptr %ptr, i32 %offset, metadata !"common_metadata")
19+
%2 = extractvalue { ptr, i1 } %1, 1
20+
ret i1 %2
21+
}
22+
23+
define i1 @merge_candidate_c(ptr %ptr, i32 %offset) {
24+
; CHECK-LABEL: define i1 @merge_candidate_c(
25+
; CHECK-SAME: ptr [[PTR:%.*]], i32 [[OFFSET:%.*]]) {
26+
; CHECK-NEXT: [[TMP1:%.*]] = call { ptr, i1 } @llvm.type.checked.load(ptr [[PTR]], i32 [[OFFSET]], metadata !"different_metadata")
27+
; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { ptr, i1 } [[TMP1]], 1
28+
; CHECK-NEXT: ret i1 [[TMP2]]
29+
;
30+
%1 = call { ptr, i1 } @llvm.type.checked.load(ptr %ptr, i32 %offset, metadata !"different_metadata")
31+
%2 = extractvalue { ptr, i1 } %1, 1
32+
ret i1 %2
33+
}
34+
35+
define i1 @merge_candidate_b(ptr %ptr, i32 %offset) {
36+
; CHECK-LABEL: define i1 @merge_candidate_b(
37+
; CHECK-SAME: ptr [[TMP0:%.*]], i32 [[TMP1:%.*]]) {
38+
; CHECK-NEXT: [[TMP3:%.*]] = tail call i1 @merge_candidate_a(ptr [[TMP0]], i32 [[TMP1]])
39+
; CHECK-NEXT: ret i1 [[TMP3]]
40+
;
41+
%1 = call { ptr, i1 } @llvm.type.checked.load(ptr %ptr, i32 %offset, metadata !"common_metadata")
42+
%2 = extractvalue { ptr, i1 } %1, 1
43+
ret i1 %2
44+
}

0 commit comments

Comments
 (0)