-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add contracts representation and parsing. Much thanks to Peter for th… #3
base: main
Are you sure you want to change the base?
Conversation
@@ -2776,6 +2797,53 @@ struct FieldDeclarator { | |||
BitfieldSize(nullptr) {} | |||
}; | |||
|
|||
class ContractSpecifiers { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: Remove this, I actually haven't used it yet.
Though I haven't fixed the parsing yet.
clang/lib/AST/ExprConstant.cpp
Outdated
@@ -15550,6 +15586,17 @@ class VoidExprEvaluator | |||
case Builtin::BI__builtin_operator_delete: | |||
return HandleOperatorDeleteCall(Info, E); | |||
|
|||
case Builtin::BI__builtin_contract_assert: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FIXME: This also is unused and needs to be removed.
ContractStmts need to be handled differently.
clang/lib/CodeGen/CGBuiltin.cpp
Outdated
@@ -3359,6 +3359,11 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, | |||
Builder.CreateCall(FnAssume, ArgValue); | |||
return RValue::get(nullptr); | |||
} | |||
case Builtin::BI__builtin_contract_assert: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the next step would be to merge the 2 vectors of ContractStmts
everywhere, it's really not ergonomic and one ought to be enough (it's should be easy to either sort it , or filter it)
@@ -73,7 +73,7 @@ | |||
"-Wno-self-move", | |||
] | |||
|
|||
_allStandards = ["c++03", "c++11", "c++14", "c++17", "c++20", "c++23", "c++26"] | |||
_allStandards = ["c++03", "c++11", "c++14", "c++17", "c++20", "c++23", "c++26", "c++2c"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the difference between 2c and 26?
clang/include/clang/AST/StmtCXX.h
Outdated
enum { ResultNameDeclOffset = 0, ConditionOffset = 1, Count = 2 }; | ||
|
||
public: | ||
// These types correspond to the three C++ 'await_suspend' return variants |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
haha :)
clang/lib/Parse/ParseDeclCXX.cpp
Outdated
if (Tok.is(tok::identifier) && NextToken().is(tok::colon)) { | ||
if (CK != ContractKind::Post) { | ||
// Only post contracts can have a result name | ||
Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That diag looks weird
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it's wrong.
Actions.getASTContext().BoolTy); | ||
} | ||
|
||
T.consumeClose(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you want to keep that so that you know where the contract ends
clang/lib/Parse/ParseDeclCXX.cpp
Outdated
void Parser::ParsePostContract(Declarator &DeclaratorInfo) { | ||
ConsumeToken(); | ||
|
||
ParseScope ParamScope(this, Scope::DeclScope | | ||
Scope::FunctionDeclarationScope | | ||
Scope::FunctionPrototypeScope); | ||
|
||
DeclaratorChunk::FunctionTypeInfo FTI = DeclaratorInfo.getFunctionTypeInfo(); | ||
for (unsigned i = 0; i != FTI.NumParams; ++i) { | ||
ParmVarDecl *Param = cast<ParmVarDecl>(FTI.Params[i].Param); | ||
Actions.ActOnReenterCXXMethodParameter(getCurScope(), Param); | ||
} | ||
|
||
if (Tok.isNot(tok::l_paren)) { | ||
Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren; | ||
return; | ||
} | ||
ConsumeParen(); | ||
|
||
// Post contracts start with <identifier> colon <expression> | ||
// As we have to support the "auto f() post (r : r > 42) {...}" case, we cannot parse here | ||
// the return type is not guaranteed to be known until after the function body parses | ||
|
||
/* | ||
if (Tok.isNot(tok::identifier)) { | ||
Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; | ||
return; | ||
} | ||
|
||
ParsingDeclSpec DS(*this); | ||
|
||
ParsedTemplateInfo TemplateInfo; | ||
DeclSpecContext DSContext = getDeclSpecContextFromDeclaratorContext(DeclaratorContext::Block); | ||
ParseDeclarationSpecifiers(DS, TemplateInfo, AS_none, DSContext); | ||
|
||
ParsedAttributes LocalAttrs(AttrFactory); | ||
ParsingDeclarator D(*this, DS, LocalAttrs, DeclaratorContext::Block); | ||
|
||
D.setObjectType(getAsFunction().getReturnType()); | ||
IdentifierInfo *Id = Tok.getIdentifierInfo(); | ||
SourceLocation IdLoc = ConsumeToken(); | ||
D.setIdentifier(Id, IdLoc); | ||
|
||
Decl* ThisDecl = Actions.ActOnDeclarator(getCurScope(), D); | ||
Actions.ActOnUninitializedDecl(ThisDecl); | ||
Actions.FinalizeDeclaration(ThisDecl); | ||
D.complete(ThisDecl); | ||
if (Tok.isNot(tok::colon)) { | ||
Diag(Tok.getLocation(), diag::err_expected) << tok::colon; | ||
return; | ||
} | ||
|
||
ExprResult Expr = ParseExpression(); | ||
if (Expr.isInvalid()) { | ||
Diag(Tok.getLocation(), diag::err_invalid_pcs); | ||
return; | ||
} | ||
DeclaratorInfo.addPostContract(Expr.get()); | ||
*/ | ||
ExprResult Expr = ParseExpression(); | ||
if (Expr.isInvalid()) { | ||
Diag(Tok.getLocation(), diag::err_invalid_pcs); | ||
return; | ||
} | ||
// DeclaratorInfo.addPostContract(Expr.get()); | ||
|
||
if (Tok.isNot(tok::r_paren)) { | ||
Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren; | ||
return; | ||
} | ||
ConsumeParen(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that dead code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, but I still might want to reference it while building the result name introducer decl later.
clang/lib/Parse/ParseStmt.cpp
Outdated
// FIXME(EricWF): This seems really worg. | ||
ParsedAttributes attrs(AttrFactory); | ||
MaybeParseCXX11Attributes(attrs); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks fine to me? (except we never do anything with these attributes)
We might want to make ContractStmt an AttributedStmt
def ContractAssert : Builtin { | ||
let Spellings = ["__builtin_contract_assert"]; | ||
let Attributes = [NoThrow, Constexpr]; | ||
|
||
let Prototype = "void(bool)"; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dead code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep.
|
||
def fcontracts_impl_strategy : Joined<["-"], "fcontracts_strategy=">, | ||
HelpText<"Specify contract implementation strategy. The default value is 'callee'.">, | ||
Values<"0,1,2">, | ||
Visibility<[ClangOption, CC1Option]>, | ||
NormalizedValuesScope<"LangOptions::ContractImplStrategy">, | ||
NormalizedValues<["Callee", "Both", "Split"]>, | ||
MarshallingInfoEnum<LangOpts<"ContractStrategy">, "Callee">; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the ambition!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's all peter :-) I'm going to only emit callee side.
//===--------------------------------------------------------------------===// | ||
// C++ Contracts | ||
/* | ||
ExceptionSpecificationType Parser::tryParseExceptionSpecification( | ||
bool Delayed, SourceRange &SpecificationRange, | ||
SmallVectorImpl<ParsedType> &DynamicExceptions, | ||
SmallVectorImpl<SourceRange> &DynamicExceptionRanges, | ||
ExprResult &NoexceptExpr, CachedTokens *&) { | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Weird comment
@@ -73,7 +73,7 @@ | |||
"-Wno-self-move", | |||
] | |||
|
|||
_allStandards = ["c++03", "c++11", "c++14", "c++17", "c++20", "c++23", "c++26"] | |||
_allStandards = ["c++03", "c++11", "c++14", "c++17", "c++20", "c++23", "c++26", "c++2c"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the difference between 26 and 2c?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing, I thought I needed it, but I don't.
I think it's also needed to check that two declarations have equivalent contract specifications, since using two vectors removes the ordering of pre/post. |
clang/lib/Parse/ParseDeclCXX.cpp
Outdated
SourceLocation IdLoc = ConsumeToken(); | ||
(void)Id; | ||
(void)IdLoc; | ||
// FIXME(ericwf): Actually build the result name introducer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cor3ntin I'm struggling to get the return type out of the parser here. Thoughts?
…on, OpaqueInst (llvm#97343) A very basic implementation of sandboxir:: `Fuction` `Argument` `Constant` `Instruction` `OpaqueInst`
If the instruction is marked for deletion, better to drop all its operands and mark them for deletion too (if allowed). It allows to have more vectorizable patterns and generate less useless extractelement instructions. Reviewers: RKSimon Reviewed By: RKSimon Pull Request: llvm#97409
The new round-robin algorithm overrides the hash-based distribution of functions to modules. It achieves a more even number of functions per module when the number of functions is close to the number of requested modules. It's not in use by default and is available under a new flag.
zext does not allow converting vector shadow to scalar, so we must manually convert it prior to calling zext in materializeOneCheck, for which the 'ConvertedShadow' parameter isn't actually guaranteed to be scalar (1). Note that it is safe/no-op to call convertShadowToScalar on a shadow that is already scalar. In contrast, the storeOrigin function already converts the (potentially vector) shadow to scalar; we add a comment to note why it is load bearing. (1) In materializeInstructionChecks(): "// Disable combining in some cases. TrackOrigins checks each shadow to pick // correct origin. bool Combine = !MS.TrackOrigins; ... if (!Combine) { materializeOneCheck(IRB, ConvertedShadow, ShadowData.Origin); continue; }"
…s space when generating intrinsics (llvm#96836) This PR aims to factor in the allocation address space provided by an architectures data layout when generating the intrinsic instructions, this allows them to be lowered later with the address spaces in tow. This aligns the intrinsic creation with the LLVM IRBuilder's https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/IR/IRBuilder.h#L1053 This is also necessary for the below example to compile for OpenMP AMD GPU and not ICE the compiler in ISEL as AMD's stackrestore and stacksave are expected to have the appropriate allocation address space for AMD GPU. program main integer(4), allocatable :: test allocate(test) !$omp target map(tofrom:test) do i = 1, 10 test = test + 50 end do !$omp end target deallocate(test) end program The PR also fixes the issue I opened a while ago which hits the same error when compiling for AMDGPU: llvm#82368 Although, you have to have the appropriate GPU LIBC and Fortran offload runtime (both compiled for AMDGPU) added to the linker for the command or it will reach another ISEL error and ICE weirdly. But with the pre-requisites it works fine with this PR.
Added Demangle to Profile link components to fix shared build.
This reverts commit bbd52dd to fix a crash revealed in https://lab.llvm.org/buildbot/#/builders/4/builds/505
…lvm#97360) llvm#95482 is a reland of llvm#88024. llvm#95482 keeps indexing memory usage reasonable by using unordered_map and doesn't make other changes to originally reviewed code. While discussing possible ways to minimize indexing memory usage, Teresa asked whether I need `ExportSetTy` as a map or a set is sufficient. This PR implements the idea. It uses a set rather than a map to track exposed ValueInfos. Currently, `ExportLists` has two use cases, and neither needs to track a ValueInfo's import/export status. So using a set is sufficient and correct. 1) In both in-process and distributed ThinLTO, it's used to decide if a function or global variable is visible [1] from another module after importing creates additional cross-module references. * If a cross-module call edge is seen today, the callee must be visible to another module without keeping track of its export status already. For instance, this [2] is how callees of direct calls get exported. 2) For in-process ThinLTO [3], it's used to compute lto cache key. * The cache key computation already hashes [4] 'ImportList' , and 'ExportList' is determined by 'ImportList'. So it's fine to not track 'import type' for export list. [1] https://github.com/llvm/llvm-project/blob/66cd8ec4c08252ebc73c82e4883a8da247ed146b/llvm/lib/LTO/LTO.cpp#L1815-L1819 [2] https://github.com/llvm/llvm-project/blob/66cd8ec4c08252ebc73c82e4883a8da247ed146b/llvm/lib/LTO/LTO.cpp#L1783-L1794 [3] https://github.com/llvm/llvm-project/blob/66cd8ec4c08252ebc73c82e4883a8da247ed146b/llvm/lib/LTO/LTO.cpp#L1494-L1496 [4] https://github.com/llvm/llvm-project/blob/b76100e220591fab2bf0a4917b216439f7aa4b09/llvm/lib/LTO/LTO.cpp#L194-L222
…U. NFC We have an existing VT variable that should match N0.getValueType.
Add requires line to not test when the target architecture isn't supported. Technically we could make it a bit less restrictive, but want green builds.
The two options are discussed in a few comments around llvm#91280 (comment) * -Wa,--crel: error "-Wa,--allow-experimental-crel must be specified to use -Wa,--crel..." * -Wa,--allow-experimental-crel: no-op * -Wa,--crel,--allow-experimental-crel: enable CREL in the integrated assembler (llvm#91280) MIPS's little-endian n64 ABI messed up the `r_info` field in relocations. While this could be fixed with CREL, my intention is to avoid complication in assembler/linker. The implementation simply doesn't allow CREL for MIPS. Link: https://discourse.llvm.org/t/rfc-crel-a-compact-relocation-format-for-elf/77600 Pull Request: llvm#97378
- created integration tests for libc hdrgen - implemented sorting function names in yaml files through script
We only handled the easy LDS case before. Handle the other address spaces with the more complicated legality logic.
…#97329) Reordered Function class parameter "standards" to make more logical sense and to match the ordering in the add_function function. Deleted the yaml_combined folder and moved contained files to the yaml folder. Updated math.yaml file with the recently added math functions in spec.td
Refactors legacy ranges writers to create a writer for each instance of a DWO file. We now write out everything into .debug_ranges after the all the DWO files are processed. This also changes the order that ranges is written out in, as before we wrote out while in the main CU processing loop and we now iterate through the CU buckets created by partitionCUs, after the main processing loop.
…7489) Using the same range reduction as `sin`, `cos`, and `sincos`: 1) Reducing `x = k*pi/128 + u`, with `|u| <= pi/256`, and `u` is in double-double. 2) Approximate `tan(u)` using degree-9 Taylor polynomial. 3) Compute ``` tan(x) ~ (sin(k*pi/128) + tan(u) * cos(k*pi/128)) / (cos(k*pi/128) - tan(u) * sin(k*pi/128)) ``` using the fast double-double division algorithm in [the CORE-MATH project](https://gitlab.inria.fr/core-math/core-math/-/blob/master/src/binary64/tan/tan.c#L1855). 4) Perform relative-error Ziv's accuracy test 5) If the accuracy tests failed, we redo the computations using 128-bit precision `DyadicFloat`. Fixes llvm#96930
…nary operator& (llvm#97596) Currently, `TreeTransform::TransformCXXOperatorCallExpr` calls `TreeTransform::TransformAddressOfOperand` to transform the first operand of a `CXXOperatorCallExpr` when its `OverloadOperatorKind` is `OO_Amp` -- regardless of arity. This results in the first operand of binary `operator&` being incorrectly transformed as if it was the operand of the address of operator in cases such as the following: ``` struct A { int x; }; void operator&(A, A); template<typename T> struct B { int f() { return T::x & 1; // invalid reference to 'A::x' is not diagnosed because 'T::x' is incorrectly transformed as if it was the operand of unary operator& } }; template struct B<A>; ``` Prior to llvm#92318 we would build a `CXXDependentScopeMemberExpr` for `T::x` (as with most dependent qualified names that were not member qualified names). Since `TreeTransform::TransformAddressOfOperand` only differs from `TransformExpr` for `DependentScopeDeclRefExpr` and `UnresolvedLookupExpr` operands, `T::x` was transformed "correctly". Now that we build a `DependentScopeDeclRefExpr` for `T::x`, it is incorrectly transformed as if it was the operand of the address of operator and we fail to diagnose the invalid reference to a non-static data member. This patch fixes the issue by only calling `TreeTransform::TransformAddressOfOperand` for `CXXOperatorCallExpr`s with a single operand. This fixes llvm#97483.
The key was being dropped for external resources because they aren't present in the dialect resource name mapper.
…n leading / trailing dimensions." (llvm#97652) Reverts llvm#92934 because it breaks some lowering. To repro: `mlir-opt -test-vector-transfer-flatten-patterns ~/repro.mlir` ```mlir func.func @unit_dim_folding(%arg0: vector<1x1xf32>) -> vector<1x1xf32> { %cst = arith.constant dense<0.000000e+00> : vector<1x1xf32> %0 = arith.mulf %arg0, %cst : vector<1x1xf32> return %0 : vector<1x1xf32> } ```
Fixes: rdar://128092379
… rounding modes (llvm#97464) I also fixed a comment in sinpif.cpp in the first commit. Should this be included in this PR? All tests were passed, including the exhaustive test. CC: @lntue
Outlining these patterns has a significant impact on the overall stack frame size of llvm::UpgradeIntrinsicCall. This is helpful for scenarios where compilation threads are stack-constrained. The overall impact is low when using clang as the host compiler, but very pronounced when using MSVC 2022 with release builds. Clang: 1,624 -> 824 bytes MSVC: 23,560 -> 6,120 bytes
…lvm#97156) When `-fixup_chains`/`-init_offsets` is used, a different section, `__init_offsets` is synthesized from `__mod_init_func`. If there are any symbols defined inside `__mod_init_func`, they are added to the symbol table unconditionally while processing the input files. Later, when querying these symbols' addresses (when constructing the symtab or exports trie), we crash with a null deref, as there is no output section assigned to them. Just making the symbols point to `__init_offsets` is a bad idea, as the new section stores 32-bit integers instead of 64-bit pointers; accessing the symbols would not do what the programmer intended. We should entirely omit them from the output. This is what ld64 and ld-prime do. This patch uses the same mechanism as dead-stripping to mark these symbols as not needed in the output. There might be nicer fixes than the workaround, this is discussed in llvm#97155. Fixes llvm#79894 (comment) Fixes llvm#94716
…lvm#97744) GCC 14 has been released a while ago. We've updated the CI to use GCC 14 now. This removes any old annotations in the tests and updates the documentation to reflect the updated version requirements.
… ToT targetting Windows" This reverts commit cf1ded3.
…h Clang ToT targetting Windows" This reverts commit 10e1b93.
…ang ToT targetting Windows" This reverts commit 593f708.
This makes the test suite forward-compatible with future versions of macOS. Previously, the Lit features were built in a way that they would assume that any newer macOS version doesn't contain any version of LLVM, which doesn't make sense.
#3) (llvm#93315) The ThreadLocalCache implementation is used by the MLIRContext (among other things) to try to manage thread contention in the StorageUniquers. There is a bunch of fancy shared pointer/weak pointer setups that basically keeps everything alive across threads at the right time, but a huge bottleneck is the `weak_ptr::lock` call inside the `::get` method. This is because the `lock` method has to hit the atomic refcount several times, and this is bottlenecking performance across many threads. However, all this is doing is checking whether the storage is initialized. Importantly, when the `PerThreadInstance` goes out of scope, it does not remove all of its associated entries from the thread-local hash map (it contains dangling `PerThreadInstance *` keys). The `weak_ptr` also allows the thread local cache to synchronize with the `PerThreadInstance`'s destruction: 1. if `ThreadLocalCache` destructs, the `weak_ptr`s that reference its contained values are immediately invalidated 2. if `CacheType` destructs within a thread, any entries still live are removed from the owning `PerThreadInstance`, and it locks the `weak_ptr` first to ensure it's kept alive long enough for the removal. This PR changes the TLC entries to contain a `shared_ptr<ValueT*>` and a `weak_ptr<PerInstanceState>`. It gives the `PerInstanceState` entries a `weak_ptr<ValueT*>` on top of the `unique_ptr<ValueT>`. This enables `ThreadLocalCache::get` to check if the value is initialized by dereferencing the `shared_ptr<ValueT*>` and check if the contained pointer is null. When `PerInstanceState` destructs, the values inside the TLC are written to nullptr. The TLC uses the `weak_ptr<PerInstanceState>` to satisfy (2). (1) is no longer the case. When `ThreadLocalCache` begins destruction, the `weak_ptr<PerInstanceState>` are invalidated, but not the `shared_ptr<ValueT*>`. This is OK: because the overall object is being destroyed, `::get` cannot get called and because the `shared_ptr<PerInstanceState>` finishes destruction before freeing the pointer, it cannot get reallocated to another `ThreadLocalCache` during destruction. I.e. the values inside the TLC associated with a `PerInstanceState` cannot be read during destruction. The most important thing is to make sure destruction of the TLC doesn't race with the destructor of `PerInstanceState`. Because `PerInstanceState` carries `weak_ptr` references into the TLC, we guarantee to not have any use-after-frees.
…e initial implementation
The template stuff is a bit of a hack. I'm considering simply inserting the statements into the function body and letting the existing code handle the rest. Also add some cheaky diagnostics, fix a few name lookup bugs, and delete some old code.
There are also various experiements that need cleaning up, specifically around builtins and source location.
Some work on constification, but a bunch of experiment that still needs to be undone. The addition of -fclang-contract-groups=foo=<semantic>, which still needs better integrating with -fcontract-evaluation-semantic=. The [[clang::contract_group("foo.bar")]] stuff works really well. I'll be happy to try it in libc++. What still needs to be done includes: * Coming up with a proper descriptor/format for the compiler-stl interface. It seems to me we'll want the ABI to be able to evolve over time, and so we should pass a pointer to data + data descriptor of some kind so that the STL can parse version of the header from different compilers & versions. * Everything to do with parsing pre/post in inline member functions. * Contract redeclaration checking. * Constifying implicit this. * Code gen & constant evaluation for result names (and representation too). * Cleanup around experiments for source location & constification.
This test is currently flaky on a local Windows amd64 build. The reason is that it relies on the order of `process.threads` but this order is nondeterministic: If we print lldb's inputs and outputs while running, we can see that the breakpoints are always being set correctly, and always being hit: ```sh runCmd: breakpoint set -f "main.c" -l 2 output: Breakpoint 1: where = a.out`func_inner + 1 at main.c:2:9, address = 0x0000000140001001 runCmd: breakpoint set -f "main.c" -l 7 output: Breakpoint 2: where = a.out`main + 17 at main.c:7:5, address = 0x0000000140001021 runCmd: run output: Process 52328 launched: 'C:\workspace\llvm-project\llvm\build\lldb-test-build.noindex\functionalities\unwind\zeroth_frame\TestZerothFrame.test_dwarf\a.out' (x86_64) Process 52328 stopped * thread #1, stop reason = breakpoint 1.1 frame #0: 0x00007ff68f6b1001 a.out`func_inner at main.c:2:9 1 void func_inner() { -> 2 int a = 1; // Set breakpoint 1 here ^ 3 } 4 5 int main() { 6 func_inner(); 7 return 0; // Set breakpoint 2 here ``` However, sometimes the backtrace printed in this test shows that the process is stopped inside NtWaitForWorkViaWorkerFactory from `ntdll.dll`: ```sh Backtrace at the first breakpoint: frame #0: 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20 frame #1: 0x00007ffecc74585e ntdll.dll`RtlClearThreadWorkOnBehalfTicket + 862 frame #2: 0x00007ffecc3e257d kernel32.dll`BaseThreadInitThunk + 29 frame #3: 0x00007ffecc76af28 ntdll.dll`RtlUserThreadStart + 40 ``` When this happens, the test fails with an assertion error that the stopped thread's zeroth frame's current line number does not match the expected line number. This is because the test is looking at the wrong thread: `process.threads[0]`. If we print the list of threads each time the test is run, we notice that threads are sometimes in a different order, within `process.threads`: ```sh Thread 0: thread #4: tid = 0x9c38, 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20 Thread 1: thread #2: tid = 0xa950, 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20 Thread 2: thread #1: tid = 0xab18, 0x00007ff64bc81001 a.out`func_inner at main.c:2:9, stop reason = breakpoint 1.1 Thread 3: thread #3: tid = 0xc514, 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20 Thread 0: thread #3: tid = 0x018c, 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20 Thread 1: thread #1: tid = 0x85c8, 0x00007ff7130c1001 a.out`func_inner at main.c:2:9, stop reason = breakpoint 1.1 Thread 2: thread #2: tid = 0xf344, 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20 Thread 3: thread #4: tid = 0x6a50, 0x00007ffecc7b3bf4 ntdll.dll`NtWaitForWorkViaWorkerFactory + 20 ``` Use `self.thread()` to consistently select the correct thread, instead. Co-authored-by: kendal <[email protected]>
…izations of function templates to USRGenerator (llvm#98027) Given the following: ``` template<typename T> struct A { void f(int); // #1 template<typename U> void f(U); // #2 template<> void f<int>(int); // #3 }; ``` Clang will generate the same USR for `#1` and `#2`. This patch fixes the issue by including the template arguments of dependent class scope explicit specializations in their USRs.
This patch adds a frame recognizer for Clang's `__builtin_verbose_trap`, which behaves like a `__builtin_trap`, but emits a failure-reason string into debug-info in order for debuggers to display it to a user. The frame recognizer triggers when we encounter a frame with a function name that begins with `__clang_trap_msg`, which is the magic prefix Clang emits into debug-info for verbose traps. Once such frame is encountered we display the frame function name as the `Stop Reason` and display that frame to the user. Example output: ``` (lldb) run warning: a.out was compiled with optimization - stepping may behave oddly; variables may not be available. Process 35942 launched: 'a.out' (arm64) Process 35942 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = Misc.: Function is not implemented frame #1: 0x0000000100003fa4 a.out`main [inlined] Dummy::func(this=<unavailable>) at verbose_trap.cpp:3:5 [opt] 1 struct Dummy { 2 void func() { -> 3 __builtin_verbose_trap("Misc.", "Function is not implemented"); 4 } 5 }; 6 7 int main() { (lldb) bt * thread #1, queue = 'com.apple.main-thread', stop reason = Misc.: Function is not implemented frame #0: 0x0000000100003fa4 a.out`main [inlined] __clang_trap_msg$Misc.$Function is not implemented$ at verbose_trap.cpp:0 [opt] * frame #1: 0x0000000100003fa4 a.out`main [inlined] Dummy::func(this=<unavailable>) at verbose_trap.cpp:3:5 [opt] frame #2: 0x0000000100003fa4 a.out`main at verbose_trap.cpp:8:13 [opt] frame #3: 0x0000000189d518b4 dyld`start + 1988 ```
…linux (llvm#99613) Examples of the output: ARM: ``` # ./a.out AddressSanitizer:DEADLYSIGNAL ================================================================= ==122==ERROR: AddressSanitizer: SEGV on unknown address 0x0000007a (pc 0x76e13ac0 bp 0x7eb7fd00 sp 0x7eb7fcc8 T0) ==122==The signal is caused by a READ memory access. ==122==Hint: address points to the zero page. #0 0x76e13ac0 (/lib/libc.so.6+0x7cac0) #1 0x76dce680 in gsignal (/lib/libc.so.6+0x37680) #2 0x005c2250 (/root/a.out+0x145250) #3 0x76db982c (/lib/libc.so.6+0x2282c) #4 0x76db9918 in __libc_start_main (/lib/libc.so.6+0x22918) ==122==Register values: r0 = 0x00000000 r1 = 0x0000007a r2 = 0x0000000b r3 = 0x76d95020 r4 = 0x0000007a r5 = 0x00000001 r6 = 0x005dcc5c r7 = 0x0000010c r8 = 0x0000000b r9 = 0x76f9ece0 r10 = 0x00000000 r11 = 0x7eb7fd00 r12 = 0x76dce670 sp = 0x7eb7fcc8 lr = 0x76e13ab4 pc = 0x76e13ac0 AddressSanitizer can not provide additional info. SUMMARY: AddressSanitizer: SEGV (/lib/libc.so.6+0x7cac0) ==122==ABORTING ``` AArch64: ``` # ./a.out UndefinedBehaviorSanitizer:DEADLYSIGNAL ==99==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x000000000063 (pc 0x007fbbbc5860 bp 0x007fcfdcb700 sp 0x007fcfdcb700 T99) ==99==The signal is caused by a UNKNOWN memory access. ==99==Hint: address points to the zero page. #0 0x007fbbbc5860 (/lib64/libc.so.6+0x82860) #1 0x007fbbb81578 (/lib64/libc.so.6+0x3e578) #2 0x00556051152c (/root/a.out+0x3152c) #3 0x007fbbb6e268 (/lib64/libc.so.6+0x2b268) #4 0x007fbbb6e344 (/lib64/libc.so.6+0x2b344) #5 0x0055604e45ec (/root/a.out+0x45ec) ==99==Register values: x0 = 0x0000000000000000 x1 = 0x0000000000000063 x2 = 0x000000000000000b x3 = 0x0000007fbbb41440 x4 = 0x0000007fbbb41580 x5 = 0x3669288942d44cce x6 = 0x0000000000000000 x7 = 0x00000055605110b0 x8 = 0x0000000000000083 x9 = 0x0000000000000000 x10 = 0x0000000000000000 x11 = 0x0000000000000000 x12 = 0x0000007fbbdb3360 x13 = 0x0000000000010000 x14 = 0x0000000000000039 x15 = 0x00000000004113a0 x16 = 0x0000007fbbb81560 x17 = 0x0000005560540138 x18 = 0x000000006474e552 x19 = 0x0000000000000063 x20 = 0x0000000000000001 x21 = 0x000000000000000b x22 = 0x0000005560511510 x23 = 0x0000007fcfdcb918 x24 = 0x0000007fbbdb1b50 x25 = 0x0000000000000000 x26 = 0x0000007fbbdb2000 x27 = 0x000000556053f858 x28 = 0x0000000000000000 fp = 0x0000007fcfdcb700 lr = 0x0000007fbbbc584c sp = 0x0000007fcfdcb700 UndefinedBehaviorSanitizer can not provide additional info. SUMMARY: UndefinedBehaviorSanitizer: SEGV (/lib64/libc.so.6+0x82860) ==99==ABORTING ```
…llvm#96782) First commit's PR is llvm#96780 Combines the following instructions: `ushll r0, r0, #0` `shl r0, r0, #3` Into: `ushll r0, r0, #3`
…104523) Compilers and language runtimes often use helper functions that are fundamentally uninteresting when debugging anything but the compiler/runtime itself. This patch introduces a user-extensible mechanism that allows for these frames to be hidden from backtraces and automatically skipped over when navigating the stack with `up` and `down`. This does not affect the numbering of frames, so `f <N>` will still provide access to the hidden frames. The `bt` output will also print a hint that frames have been hidden. My primary motivation for this feature is to hide thunks in the Swift programming language, but I'm including an example recognizer for `std::function::operator()` that I wished for myself many times while debugging LLDB. rdar://126629381 Example output. (Yes, my proof-of-concept recognizer could hide even more frames if we had a method that returned the function name without the return type or I used something that isn't based off regex, but it's really only meant as an example). before: ``` (lldb) thread backtrace --filtered=false * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 * frame #0: 0x0000000100001f04 a.out`foo(x=1, y=1) at main.cpp:4:10 frame #1: 0x0000000100003a00 a.out`decltype(std::declval<int (*&)(int, int)>()(std::declval<int>(), std::declval<int>())) std::__1::__invoke[abi:se200000]<int (*&)(int, int), int, int>(__f=0x000000016fdff280, __args=0x000000016fdff224, __args=0x000000016fdff220) at invoke.h:149:25 frame #2: 0x000000010000399c a.out`int std::__1::__invoke_void_return_wrapper<int, false>::__call[abi:se200000]<int (*&)(int, int), int, int>(__args=0x000000016fdff280, __args=0x000000016fdff224, __args=0x000000016fdff220) at invoke.h:216:12 frame #3: 0x0000000100003968 a.out`std::__1::__function::__alloc_func<int (*)(int, int), std::__1::allocator<int (*)(int, int)>, int (int, int)>::operator()[abi:se200000](this=0x000000016fdff280, __arg=0x000000016fdff224, __arg=0x000000016fdff220) at function.h:171:12 frame #4: 0x00000001000026bc a.out`std::__1::__function::__func<int (*)(int, int), std::__1::allocator<int (*)(int, int)>, int (int, int)>::operator()(this=0x000000016fdff278, __arg=0x000000016fdff224, __arg=0x000000016fdff220) at function.h:313:10 frame #5: 0x0000000100003c38 a.out`std::__1::__function::__value_func<int (int, int)>::operator()[abi:se200000](this=0x000000016fdff278, __args=0x000000016fdff224, __args=0x000000016fdff220) const at function.h:430:12 frame #6: 0x0000000100002038 a.out`std::__1::function<int (int, int)>::operator()(this= Function = foo(int, int) , __arg=1, __arg=1) const at function.h:989:10 frame #7: 0x0000000100001f64 a.out`main(argc=1, argv=0x000000016fdff4f8) at main.cpp:9:10 frame llvm#8: 0x0000000183cdf154 dyld`start + 2476 (lldb) ``` after ``` (lldb) bt * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 * frame #0: 0x0000000100001f04 a.out`foo(x=1, y=1) at main.cpp:4:10 frame #1: 0x0000000100003a00 a.out`decltype(std::declval<int (*&)(int, int)>()(std::declval<int>(), std::declval<int>())) std::__1::__invoke[abi:se200000]<int (*&)(int, int), int, int>(__f=0x000000016fdff280, __args=0x000000016fdff224, __args=0x000000016fdff220) at invoke.h:149:25 frame #2: 0x000000010000399c a.out`int std::__1::__invoke_void_return_wrapper<int, false>::__call[abi:se200000]<int (*&)(int, int), int, int>(__args=0x000000016fdff280, __args=0x000000016fdff224, __args=0x000000016fdff220) at invoke.h:216:12 frame #6: 0x0000000100002038 a.out`std::__1::function<int (int, int)>::operator()(this= Function = foo(int, int) , __arg=1, __arg=1) const at function.h:989:10 frame #7: 0x0000000100001f64 a.out`main(argc=1, argv=0x000000016fdff4f8) at main.cpp:9:10 frame llvm#8: 0x0000000183cdf154 dyld`start + 2476 Note: Some frames were hidden by frame recognizers ```
…ext is not fully initialized (llvm#110481) As this comment around target initialization implies: ``` // This can be NULL if we don't know anything about the architecture or if // the target for an architecture isn't enabled in the llvm/clang that we // built ``` There are cases where we might fail to call `InitBuiltinTypes` when creating the backing `ASTContext` for a `TypeSystemClang`. If that happens, the builtins `QualType`s, e.g., `VoidPtrTy`/`IntTy`/etc., are not initialized and dereferencing them as we do in `GetBuiltinTypeForEncodingAndBitSize` (and other places) will lead to nullptr-dereferences. Example backtrace: ``` (lldb) run Assertion failed: (!isNull() && "Cannot retrieve a NULL type pointer"), function getCommonPtr, file Type.h, line 958. Process 2680 stopped * thread llvm#15, name = '<lldb.process.internal-state(pid=2712)>', stop reason = hit program assert frame #4: 0x000000010cdf3cdc liblldb.20.0.0git.dylib`DWARFASTParserClang::ExtractIntFromFormValue(lldb_private::CompilerType const&, lldb_private::plugin::dwarf::DWARFFormValue const&) const (.cold.1) + liblldb.20.0.0git.dylib`DWARFASTParserClang::ParseObjCMethod(lldb_private::ObjCLanguage::MethodName const&, lldb_private::plugin::dwarf::DWARFDIE const&, lldb_private::CompilerType, ParsedDWARFTypeAttributes , bool) (.cold.1): -> 0x10cdf3cdc <+0>: stp x29, x30, [sp, #-0x10]! 0x10cdf3ce0 <+4>: mov x29, sp 0x10cdf3ce4 <+8>: adrp x0, 545 0x10cdf3ce8 <+12>: add x0, x0, #0xa25 ; "ParseObjCMethod" Target 0: (lldb) stopped. (lldb) bt * thread llvm#15, name = '<lldb.process.internal-state(pid=2712)>', stop reason = hit program assert frame #0: 0x0000000180d08600 libsystem_kernel.dylib`__pthread_kill + 8 frame #1: 0x0000000180d40f50 libsystem_pthread.dylib`pthread_kill + 288 frame #2: 0x0000000180c4d908 libsystem_c.dylib`abort + 128 frame #3: 0x0000000180c4cc1c libsystem_c.dylib`__assert_rtn + 284 * frame #4: 0x000000010cdf3cdc liblldb.20.0.0git.dylib`DWARFASTParserClang::ExtractIntFromFormValue(lldb_private::CompilerType const&, lldb_private::plugin::dwarf::DWARFFormValue const&) const (.cold.1) + frame #5: 0x0000000109d30acc liblldb.20.0.0git.dylib`lldb_private::TypeSystemClang::GetBuiltinTypeForEncodingAndBitSize(lldb::Encoding, unsigned long) + 1188 frame #6: 0x0000000109aaaed4 liblldb.20.0.0git.dylib`DynamicLoaderMacOS::NotifyBreakpointHit(void*, lldb_private::StoppointCallbackContext*, unsigned long long, unsigned long long) + 384 ``` This patch adds a one-time user-visible warning for when we fail to initialize the AST to indicate that initialization went wrong for the given target. Additionally, we add checks for whether one of the `ASTContext` `QualType`s is invalid before dereferencing any builtin types. The warning would look as follows: ``` (lldb) target create "a.out" Current executable set to 'a.out' (arm64). (lldb) b main warning: Failed to initialize builtin ASTContext types for target 'some-unknown-triple'. Printing variables may behave unexpectedly. Breakpoint 1: where = a.out`main + 8 at stepping.cpp:5:14, address = 0x0000000100003f90 ``` rdar://134869779
…ates explicitly specialized for an implicitly instantiated class template specialization (llvm#113464) Consider the following: ``` template<typename T> struct A { template<typename U> struct B { static constexpr int x = 0; // #1 }; template<typename U> struct B<U*> { static constexpr int x = 1; // #2 }; }; template<> template<typename U> struct A<long>::B { static constexpr int x = 2; // #3 }; static_assert(A<short>::B<int>::y == 0); // uses #1 static_assert(A<short>::B<int*>::y == 1); // uses #2 static_assert(A<long>::B<int>::y == 2); // uses #3 static_assert(A<long>::B<int*>::y == 2); // uses #3 ``` According to [temp.spec.partial.member] p2: > If the primary member template is explicitly specialized for a given (implicit) specialization of the enclosing class template, the partial specializations of the member template are ignored for this specialization of the enclosing class template. If a partial specialization of the member template is explicitly specialized for a given (implicit) specialization of the enclosing class template, the primary member template and its other partial specializations are still considered for this specialization of the enclosing class template. The example above fails to compile because we currently don't implement [temp.spec.partial.member] p2. This patch implements the wording, fixing llvm#51051.
…e initial implementation