Skip to content

Commit d39300c

Browse files
authored
merge main into amd-staging (llvm#4013)
2 parents c40f6c6 + fdb1963 commit d39300c

File tree

118 files changed

+3198
-1056
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

118 files changed

+3198
-1056
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# This file defines a workflow that runs the libc++ benchmarks when a comment is added to the PR.
2+
#
3+
# The comment is of the form:
4+
#
5+
# /libcxx-bot benchmark <path-to-benchmarks-to-run>
6+
#
7+
# That will cause the specified benchmarks to be run on the PR and on the pull-request target, and
8+
# their results to be compared.
9+
10+
name: Benchmark libc++
11+
12+
permissions:
13+
contents: read
14+
15+
on:
16+
issue_comment:
17+
types:
18+
- created
19+
- edited
20+
21+
env:
22+
CC: clang-22
23+
CXX: clang++-22
24+
25+
jobs:
26+
run-benchmarks:
27+
permissions:
28+
pull-requests: write
29+
30+
if: >-
31+
github.event.issue.pull_request &&
32+
contains(github.event.comment.body, '/libcxx-bot benchmark')
33+
34+
runs-on: llvm-premerge-libcxx-next-runners # TODO: This should run on a dedicated set of machines
35+
steps:
36+
- uses: actions/setup-python@v6
37+
with:
38+
python-version: '3.10'
39+
40+
- name: Extract information from the PR
41+
id: vars
42+
run: |
43+
python3 -m venv .venv
44+
source .venv/bin/activate
45+
python -m pip install pygithub
46+
47+
cat <<EOF | python >> ${GITHUB_OUTPUT}
48+
import github
49+
repo = github.Github("${{ github.token }}").get_repo("${{ github.repository }}")
50+
pr = repo.get_pull(${{ github.event.issue.number }})
51+
print(f"pr_base={pr.base.sha}")
52+
print(f"pr_head={pr.head.sha}")
53+
EOF
54+
BENCHMARKS=$(echo "${{ github.event.comment.body }}" | sed -nE 's/\/libcxx-bot benchmark (.+)/\1/p')
55+
echo "benchmarks=${BENCHMARKS}" >> ${GITHUB_OUTPUT}
56+
57+
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
58+
with:
59+
ref: ${{ steps.vars.outputs.pr_head }}
60+
fetch-depth: 0
61+
fetch-tags: true # This job requires access to all the Git branches so it can diff against (usually) main
62+
path: repo # Avoid nuking the workspace, where we have the Python virtualenv
63+
64+
- name: Run baseline
65+
run: |
66+
source .venv/bin/activate && cd repo
67+
python -m pip install -r libcxx/utils/requirements.txt
68+
baseline_commit=$(git merge-base ${{ steps.vars.outputs.pr_base }} ${{ steps.vars.outputs.pr_head }})
69+
./libcxx/utils/test-at-commit --commit ${baseline_commit} -B build/baseline -- -sv -j1 --param optimization=speed ${{ steps.vars.outputs.benchmarks }}
70+
71+
- name: Run candidate
72+
run: |
73+
source .venv/bin/activate && cd repo
74+
./libcxx/utils/test-at-commit --commit ${{ steps.vars.outputs.pr_head }} -B build/candidate -- -sv -j1 --param optimization=speed ${{ steps.vars.outputs.benchmarks }}
75+
76+
- name: Compare baseline and candidate runs
77+
run: |
78+
source .venv/bin/activate && cd repo
79+
./libcxx/utils/compare-benchmarks <(./libcxx/utils/consolidate-benchmarks build/baseline) \
80+
<(./libcxx/utils/consolidate-benchmarks build/candidate) > results.txt
81+
82+
- name: Update comment with results
83+
run: |
84+
source .venv/bin/activate && cd repo
85+
cat <<EOF | python
86+
import github
87+
repo = github.Github("${{ github.token }}").get_repo("${{ github.repository }}")
88+
pr = repo.get_pull(${{ github.event.issue.number }})
89+
comment = pr.get_issue_comment(${{ github.event.comment.id }})
90+
with open('results.txt', 'r') as f:
91+
benchmark_results = f.read()
92+
93+
new_comment_text = f"""
94+
{comment.body}
95+
96+
<details>
97+
<summary>
98+
Benchmark results:
99+
</summary>
100+
101+
\`\`\`
102+
{benchmark_results}
103+
\`\`\`
104+
105+
</details>
106+
"""
107+
108+
comment.edit(new_comment_text)
109+
EOF

clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,13 @@ bool tryToFindPtrOrigin(
9191
continue;
9292
}
9393
if (auto *call = dyn_cast<CallExpr>(E)) {
94+
if (auto *Callee = call->getCalleeDecl()) {
95+
if (Callee->hasAttr<CFReturnsRetainedAttr>() ||
96+
Callee->hasAttr<NSReturnsRetainedAttr>()) {
97+
return callback(E, true);
98+
}
99+
}
100+
94101
if (auto *memberCall = dyn_cast<CXXMemberCallExpr>(call)) {
95102
if (auto *decl = memberCall->getMethodDecl()) {
96103
std::optional<bool> IsGetterOfRefCt = isGetterOfSafePtr(decl);
@@ -154,6 +161,24 @@ bool tryToFindPtrOrigin(
154161
Name == "NSClassFromString")
155162
return callback(E, true);
156163
}
164+
165+
// Sometimes, canonical type erroneously turns Ref<T> into T.
166+
// Workaround this problem by checking again if the original type was
167+
// a SubstTemplateTypeParmType of a safe smart pointer type (e.g. Ref).
168+
if (auto *CalleeDecl = call->getCalleeDecl()) {
169+
if (auto *FD = dyn_cast<FunctionDecl>(CalleeDecl)) {
170+
auto RetType = FD->getReturnType();
171+
if (auto *Subst = dyn_cast<SubstTemplateTypeParmType>(RetType)) {
172+
if (auto *SubstType = Subst->desugar().getTypePtr()) {
173+
if (auto *RD = dyn_cast<RecordType>(SubstType)) {
174+
if (auto *CXX = dyn_cast<CXXRecordDecl>(RD->getOriginalDecl()))
175+
if (isSafePtr(CXX))
176+
return callback(E, true);
177+
}
178+
}
179+
}
180+
}
181+
}
157182
}
158183
if (auto *ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(E)) {
159184
if (auto *Method = ObjCMsgExpr->getMethodDecl()) {

clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,10 @@ class TrivialFunctionAnalysisVisitor
666666
return IsFunctionTrivial(Callee);
667667
}
668668

669+
bool VisitGCCAsmStmt(const GCCAsmStmt *AS) {
670+
return AS->getAsmString() == "brk #0xc471";
671+
}
672+
669673
bool
670674
VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E) {
671675
// Non-type template paramter is compile time constant and trivial.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
2+
// expected-no-diagnostics
3+
4+
#include "mock-types.h"
5+
6+
struct Obj {
7+
void ref() const;
8+
void deref() const;
9+
10+
void someFunction();
11+
};
12+
13+
template<typename T> class Wrapper {
14+
public:
15+
T obj();
16+
};
17+
18+
static void foo(Wrapper<Ref<Obj>>&& wrapper)
19+
{
20+
wrapper.obj()->someFunction();
21+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %clang_analyze_cc1 -triple arm-darwin -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
2+
// expected-no-diagnostics
3+
4+
void crash()
5+
{
6+
__asm__ volatile ("brk #0xc471");
7+
__builtin_unreachable();
8+
}
9+
10+
class SomeObj {
11+
public:
12+
void ref();
13+
void deref();
14+
15+
void someWork() { crash(); }
16+
};
17+
18+
SomeObj* provide();
19+
20+
void doSomeWork() {
21+
provide()->someWork();
22+
}

clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,32 @@ void use_const_local() {
438438

439439
} // namespace const_global
440440

441+
namespace ns_retained_return_value {
442+
443+
NSString *provideNS() NS_RETURNS_RETAINED;
444+
CFDictionaryRef provideCF() CF_RETURNS_RETAINED;
445+
void consumeNS(NSString *);
446+
void consumeCF(CFDictionaryRef);
447+
448+
void foo() {
449+
consumeNS(provideNS());
450+
consumeCF(provideCF());
451+
}
452+
453+
struct Base {
454+
NSString *provideStr() NS_RETURNS_RETAINED;
455+
};
456+
457+
struct Derived : Base {
458+
void consumeStr(NSString *);
459+
460+
void foo() {
461+
consumeStr(provideStr());
462+
}
463+
};
464+
465+
} // namespace ns_retained_return_value
466+
441467
@interface TestObject : NSObject
442468
- (void)doWork:(NSString *)msg, ...;
443469
- (void)doWorkOnSelf;

clang/test/Analysis/Checkers/WebKit/unretained-local-vars.mm

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,21 @@ void use_const_local() {
408408

409409
} // namespace const_global
410410

411+
namespace ns_retained_return_value {
412+
413+
NSString *provideNS() NS_RETURNS_RETAINED;
414+
CFDictionaryRef provideCF() CF_RETURNS_RETAINED;
415+
void consumeNS(NSString *);
416+
void consumeCF(CFDictionaryRef);
417+
418+
unsigned foo() {
419+
auto *string = provideNS();
420+
auto *dictionary = provideCF();
421+
return string.length + CFDictionaryGetCount(dictionary);
422+
}
423+
424+
} // namespace ns_retained_return_value
425+
411426
bool doMoreWorkOpaque(OtherObj*);
412427
SomeObj* provide();
413428

libcxx/utils/test-at-commit

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ def main(argv):
7070

7171
with tempfile.TemporaryDirectory() as install_dir:
7272
# Build the library at the baseline
73-
build_cmd = [os.path.join(PARENT_DIR, 'build-at-commit'), '--install-dir', install_dir, '--commit', args.commit]
73+
build_cmd = [os.path.join(PARENT_DIR, 'build-at-commit'), '--git-repo', args.git_repo,
74+
'--install-dir', install_dir,
75+
'--commit', args.commit]
7476
build_cmd += ['--', '-DCMAKE_BUILD_TYPE=RelWithDebInfo']
7577
subprocess.check_call(build_cmd)
7678

lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ def __init__(
215215
self.terminated: bool = False
216216
self.events: List[Event] = []
217217
self.progress_events: List[Event] = []
218+
self.invalidated_event: Optional[Event] = None
218219
self.reverse_requests: List[Request] = []
219220
self.module_events: List[Dict] = []
220221
self.sequence: int = 1
@@ -440,6 +441,8 @@ def _handle_event(self, packet: Event) -> None:
440441
elif event == "capabilities" and body:
441442
# Update the capabilities with new ones from the event.
442443
self.capabilities.update(body["capabilities"])
444+
elif event == "invalidated":
445+
self.invalidated_event = packet
443446

444447
def _handle_reverse_request(self, request: Request) -> None:
445448
if request in self.reverse_requests:
@@ -1014,6 +1017,7 @@ def request_initialize(self, sourceInitFile=False):
10141017
"supportsVariableType": True,
10151018
"supportsStartDebuggingRequest": True,
10161019
"supportsProgressReporting": True,
1020+
"supportsInvalidatedEvent": True,
10171021
"$__lldb_sourceInitFile": sourceInitFile,
10181022
},
10191023
}

lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,13 @@ def verify_commands(self, flavor: str, output: str, commands: list[str]):
241241
f"Command '{flavor}' - '{cmd}' not found in output: {output}",
242242
)
243243

244+
def verify_invalidated_event(self, expected_areas):
245+
event = self.dap_server.invalidated_event
246+
self.dap_server.invalidated_event = None
247+
self.assertIsNotNone(event)
248+
areas = event["body"].get("areas", [])
249+
self.assertEqual(set(expected_areas), set(areas))
250+
244251
def get_dict_value(self, d: dict, key_path: list[str]) -> Any:
245252
"""Verify each key in the key_path array is in contained in each
246253
dictionary within "d". Assert if any key isn't in the
@@ -352,13 +359,20 @@ def get_local_as_int(self, name, threadId=None):
352359
else:
353360
return int(value)
354361

362+
def set_variable(self, varRef, name, value, id=None):
363+
"""Set a variable."""
364+
response = self.dap_server.request_setVariable(varRef, name, str(value), id=id)
365+
if response["success"]:
366+
self.verify_invalidated_event(["variables"])
367+
return response
368+
355369
def set_local(self, name, value, id=None):
356370
"""Set a top level local variable only."""
357-
return self.dap_server.request_setVariable(1, name, str(value), id=id)
371+
return self.set_variable(1, name, str(value), id=id)
358372

359373
def set_global(self, name, value, id=None):
360374
"""Set a top level global variable only."""
361-
return self.dap_server.request_setVariable(2, name, str(value), id=id)
375+
return self.set_variable(2, name, str(value), id=id)
362376

363377
def stepIn(
364378
self,
@@ -577,4 +591,6 @@ def writeMemory(self, memoryReference, data=None, offset=0, allowPartial=False):
577591
response = self.dap_server.request_writeMemory(
578592
memoryReference, encodedData, offset=offset, allowPartial=allowPartial
579593
)
594+
if response["success"]:
595+
self.verify_invalidated_event(["all"])
580596
return response

0 commit comments

Comments
 (0)