Skip to content
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

Draft
wants to merge 1,802 commits into
base: main
Choose a base branch
from

Conversation

EricWF
Copy link
Member

@EricWF EricWF commented Jun 19, 2024

…e initial implementation

@@ -2776,6 +2797,53 @@ struct FieldDeclarator {
BitfieldSize(nullptr) {}
};

class ContractSpecifiers {
Copy link
Member Author

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.

@@ -15550,6 +15586,17 @@ class VoidExprEvaluator
case Builtin::BI__builtin_operator_delete:
return HandleOperatorDeleteCall(Info, E);

case Builtin::BI__builtin_contract_assert: {
Copy link
Member Author

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.

@@ -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: {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this as well.

Copy link

@cor3ntin cor3ntin left a 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"]

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?

enum { ResultNameDeclOffset = 0, ConditionOffset = 1, Count = 2 };

public:
// These types correspond to the three C++ 'await_suspend' return variants

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

haha :)

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;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That diag looks weird

Copy link
Member Author

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();

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

Comment on lines 4389 to 4460
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();
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that dead code?

Copy link
Member Author

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.

Comment on lines 2440 to 2442
// FIXME(EricWF): This seems really worg.
ParsedAttributes attrs(AttrFactory);
MaybeParseCXX11Attributes(attrs);

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

Comment on lines 2585 to 2590
def ContractAssert : Builtin {
let Spellings = ["__builtin_contract_assert"];
let Attributes = [NoThrow, Constexpr];

let Prototype = "void(bool)";
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dead code?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep.

Comment on lines 1678 to 1686

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">;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the ambition!

Copy link
Member Author

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.

Comment on lines +2110 to +2118
//===--------------------------------------------------------------------===//
// C++ Contracts
/*
ExceptionSpecificationType Parser::tryParseExceptionSpecification(
bool Delayed, SourceRange &SpecificationRange,
SmallVectorImpl<ParsedType> &DynamicExceptions,
SmallVectorImpl<SourceRange> &DynamicExceptionRanges,
ExprResult &NoexceptExpr, CachedTokens *&) {
*/

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"]

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?

Copy link
Member Author

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.

@EricWF
Copy link
Member Author

EricWF commented Jun 21, 2024

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)

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.

SourceLocation IdLoc = ConsumeToken();
(void)Id;
(void)IdLoc;
// FIXME(ericwf): Actually build the result name introducer
Copy link
Member Author

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?

vporpo and others added 24 commits July 3, 2024 12:04
…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.
…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>
}
```
HendrikHuebner and others added 11 commits July 6, 2024 09:24
… 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.
…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.
EricWF pushed a commit that referenced this pull request Jul 6, 2024
#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.
EricWF added 10 commits July 6, 2024 13:55
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.
EricWF pushed a commit that referenced this pull request Jul 9, 2024
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]>
EricWF pushed a commit that referenced this pull request Jul 9, 2024
…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.
EricWF pushed a commit that referenced this pull request Jul 16, 2024
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
```
EricWF pushed a commit that referenced this pull request Jul 26, 2024
…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
```
EricWF pushed a commit that referenced this pull request Aug 7, 2024
…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`
EricWF pushed a commit that referenced this pull request Aug 24, 2024
…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
```
EricWF pushed a commit that referenced this pull request Oct 2, 2024
…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
EricWF pushed a commit that referenced this pull request Oct 31, 2024
…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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.